From 11c15229557cb489a5604f13e26a51099cc05314 Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 21 May 2025 18:11:11 +0100 Subject: [PATCH 01/39] 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 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 02/39] 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 db21837095f18a76d1fecb7d55547688a6b19647 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 19:35:21 -0400 Subject: [PATCH 03/39] 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 4c264c96ae30e45c503fbb24e452ea948c5229af Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 23 May 2025 17:26:39 +0000 Subject: [PATCH 04/39] Update `CmpResult` to use a pointer-sized return type As seen at [1], LLVM uses `long long` on LLP64 (to get a 64-bit integer matching pointer size) and `long` on everything else, with exceptions for AArch64 and AVR. Our current logic always uses an `i32`. This happens to work because LLVM uses 32-bit instructions to check the output on x86-64, but the GCC checks the full 64-bit register so garbage in the upper half leads to incorrect results. Update our return type to be `isize`, with exceptions for AArch64 and AVR. Fixes: https://github.com/rust-lang/compiler-builtins/issues/919 [1]: https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 --- .../builtins-test/benches/float_cmp.rs | 43 ++++++++++++------- .../builtins-test/src/bench.rs | 4 +- .../compiler-builtins/src/float/cmp.rs | 25 +++++++---- .../libm/src/math/support/mod.rs | 2 + 4 files changed, 48 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/builtins-test/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs index 42d6652397dcf..87a89efb5a4fe 100644 --- a/library/compiler-builtins/builtins-test/benches/float_cmp.rs +++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs @@ -1,12 +1,23 @@ #![cfg_attr(f128_enabled, feature(f128))] use builtins_test::float_bench; -use compiler_builtins::float::cmp; +use compiler_builtins::float::cmp::{self, CmpResult}; use criterion::{Criterion, criterion_main}; /// `gt` symbols are allowed to return differing results, they just get compared /// to 0. -fn gt_res_eq(a: i32, b: i32) -> bool { +fn gt_res_eq(mut a: CmpResult, mut b: CmpResult) -> bool { + // FIXME: Our CmpResult used to be `i32`, but GCC/LLVM expect `isize`. on 64-bit platforms, + // this means the top half of the word may be garbage if built with an old version of + // `compiler-builtins`, so add a hack around this. + // + // This can be removed once a version of `compiler-builtins` with the return type fix makes + // it upstream. + if size_of::() == 8 { + a = a as i32 as CmpResult; + b = b as i32 as CmpResult; + } + let a_lt_0 = a <= 0; let b_lt_0 = b <= 0; (a_lt_0 && b_lt_0) || (!a_lt_0 && !b_lt_0) @@ -14,14 +25,14 @@ fn gt_res_eq(a: i32, b: i32) -> bool { float_bench! { name: cmp_f32_gt, - sig: (a: f32, b: f32) -> i32, + sig: (a: f32, b: f32) -> CmpResult, crate_fn: cmp::__gtsf2, sys_fn: __gtsf2, sys_available: all(), output_eq: gt_res_eq, asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomiss {a}, {b}", @@ -36,7 +47,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:s}, {b:s}", "cset {ret:w}, gt", @@ -53,13 +64,13 @@ float_bench! { float_bench! { name: cmp_f32_unord, - sig: (a: f32, b: f32) -> i32, + sig: (a: f32, b: f32) -> CmpResult, crate_fn: cmp::__unordsf2, sys_fn: __unordsf2, sys_available: all(), asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomiss {a}, {b}", @@ -74,7 +85,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:s}, {b:s}", "cset {ret:w}, vs", @@ -91,14 +102,14 @@ float_bench! { float_bench! { name: cmp_f64_gt, - sig: (a: f64, b: f64) -> i32, + sig: (a: f64, b: f64) -> CmpResult, crate_fn: cmp::__gtdf2, sys_fn: __gtdf2, sys_available: all(), output_eq: gt_res_eq, asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomisd {a}, {b}", @@ -113,7 +124,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:d}, {b:d}", "cset {ret:w}, gt", @@ -130,13 +141,13 @@ float_bench! { float_bench! { name: cmp_f64_unord, - sig: (a: f64, b: f64) -> i32, + sig: (a: f64, b: f64) -> CmpResult, crate_fn: cmp::__unorddf2, sys_fn: __unorddf2, sys_available: all(), asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomisd {a}, {b}", @@ -151,7 +162,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:d}, {b:d}", "cset {ret:w}, vs", @@ -168,7 +179,7 @@ float_bench! { float_bench! { name: cmp_f128_gt, - sig: (a: f128, b: f128) -> i32, + sig: (a: f128, b: f128) -> CmpResult, crate_fn: cmp::__gttf2, crate_fn_ppc: cmp::__gtkf2, sys_fn: __gttf2, @@ -180,7 +191,7 @@ float_bench! { float_bench! { name: cmp_f128_unord, - sig: (a: f128, b: f128) -> i32, + sig: (a: f128, b: f128) -> CmpResult, crate_fn: cmp::__unordtf2, crate_fn_ppc: cmp::__unordkf2, sys_fn: __unordtf2, diff --git a/library/compiler-builtins/builtins-test/src/bench.rs b/library/compiler-builtins/builtins-test/src/bench.rs index 2348f6bc97379..0987185670ee3 100644 --- a/library/compiler-builtins/builtins-test/src/bench.rs +++ b/library/compiler-builtins/builtins-test/src/bench.rs @@ -358,8 +358,8 @@ 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!(int i8, i16, i32, i64, i128, isize); +impl_testio!(int u8, u16, u32, u64, u128, usize); impl_testio!((float, int)(f32, i32)); impl_testio!((float, int)(f64, i32)); #[cfg(f128_enabled)] diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index 296952821cb46..f1e54dc1c83d1 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -2,14 +2,23 @@ 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; +use crate::support::cfg_if; + +// Taken from LLVM config: +// https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 +cfg_if! { + if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { + // Aarch64 uses `int` rather than a pointer-sized value. + pub type CmpResult = i32; + } else if #[cfg(target_arch = "avr")] { + // AVR uses a single byte. + pub type CmpResult = i8; + } else { + // In compiler-rt, LLP64 ABIs use `long long` and everything else uses `long`. In effect, + // this means the return value is always pointer-sized. + pub type CmpResult = isize; + } +} #[derive(Clone, Copy)] enum Result { diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index a4f596ab8442f..2771cfd32c8b5 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -11,6 +11,8 @@ mod int_traits; #[allow(unused_imports)] pub use big::{i256, u256}; +#[allow(unused_imports)] +pub(crate) use cfg_if; pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; From c04f133858c3208525ae8fe47057fb157c18d606 Mon Sep 17 00:00:00 2001 From: Dario Damiani <154735680+D-Dario0@users.noreply.github.com> Date: Wed, 28 May 2025 20:48:05 +0200 Subject: [PATCH 05/39] Typo in README.md Link to Apache License changed from htps:// to https:// --- 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 349e892dfcf9c..77608db3d0d78 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -34,7 +34,7 @@ Usage is under the MIT license, available at ### Contribution Contributions are licensed under both the MIT license and the Apache License, -Version 2.0, available at . Unless +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. From 5978b8b875f6c53af9ca4c72f4ea5fcf74d55c84 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 May 2025 21:08:41 +0000 Subject: [PATCH 06/39] aarch64: Add a note saying why we use `frintx` rather than `frintn` --- library/compiler-builtins/libm/src/math/arch/aarch64.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64.rs index 020bb731cdc7a..8896804b50403 100644 --- a/library/compiler-builtins/libm/src/math/arch/aarch64.rs +++ b/library/compiler-builtins/libm/src/math/arch/aarch64.rs @@ -30,6 +30,12 @@ pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 { x } +// NB: `frintx` is technically the correct instruction for C's `rint`. However, in Rust (and LLVM +// by default), `rint` is identical to `roundeven` (no fpenv interaction) so we use the +// side-effect-free `frintn`. +// +// In general, C code that calls Rust's libm should assume that fpenv is ignored. + pub fn rint(mut x: f64) -> f64 { // SAFETY: `frintn` is available with neon and has no side effects. // From 2c9fb22f040094b4cb982c84254bb5d0589c38e8 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 28 May 2025 21:16:15 +0000 Subject: [PATCH 07/39] jsondoclint: Extract `Command`/`CommandKind` into its own file --- src/tools/jsondocck/src/directive.rs | 230 +++++++++++++++++++++++++++ src/tools/jsondocck/src/main.rs | 225 +------------------------- 2 files changed, 233 insertions(+), 222 deletions(-) create mode 100644 src/tools/jsondocck/src/directive.rs diff --git a/src/tools/jsondocck/src/directive.rs b/src/tools/jsondocck/src/directive.rs new file mode 100644 index 0000000000000..8617379ed270b --- /dev/null +++ b/src/tools/jsondocck/src/directive.rs @@ -0,0 +1,230 @@ +use std::borrow::Cow; +use serde_json::Value; +use crate::cache::Cache; + +#[derive(Debug)] +pub struct Command { + pub kind: CommandKind, + pub path: String, + pub lineno: usize, +} + +#[derive(Debug)] +pub enum CommandKind { + /// `//@ has ` + /// + /// Checks the path exists. + HasPath, + + /// `//@ has ` + /// + /// Check one thing at the path is equal to the value. + HasValue { value: String }, + + /// `//@ !has ` + /// + /// Checks the path doesn't exist. + HasNotPath, + + /// `//@ !has ` + /// + /// Checks the path exists, but doesn't have the given value. + HasNotValue { value: String }, + + /// `//@ is ` + /// + /// Check the path is the given value. + Is { value: String }, + + /// `//@ is ...` + /// + /// Check that the path matches to exactly every given value. + IsMany { values: Vec }, + + /// `//@ !is ` + /// + /// Check the path isn't the given value. + IsNot { value: String }, + + /// `//@ count ` + /// + /// Check the path has the expected number of matches. + CountIs { expected: usize }, + + /// `//@ set = ` + Set { variable: String }, +} + +impl CommandKind { + /// Returns both the kind and the path. + /// + /// Returns `None` if the command isn't from jsondocck (e.g. from compiletest). + pub fn parse<'a>( + command_name: &str, + negated: bool, + args: &'a [String], + ) -> Option<(Self, &'a str)> { + let kind = match (command_name, negated) { + ("count", false) => { + assert_eq!(args.len(), 2); + let expected = args[1].parse().expect("invalid number for `count`"); + Self::CountIs { expected } + } + + ("ismany", false) => { + // FIXME: Make this >= 3, and migrate len(values)==1 cases to @is + assert!(args.len() >= 2, "Not enough args to `ismany`"); + let values = args[1..].to_owned(); + Self::IsMany { values } + } + + ("is", false) => { + assert_eq!(args.len(), 2); + Self::Is { value: args[1].clone() } + } + ("is", true) => { + assert_eq!(args.len(), 2); + Self::IsNot { value: args[1].clone() } + } + + ("set", false) => { + assert_eq!(args.len(), 3); + assert_eq!(args[1], "="); + return Some((Self::Set { variable: args[0].clone() }, &args[2])); + } + + ("has", false) => match args { + [_path] => Self::HasPath, + [_path, value] => Self::HasValue { value: value.clone() }, + _ => panic!("`//@ has` must have 2 or 3 arguments, but got {args:?}"), + }, + ("has", true) => match args { + [_path] => Self::HasNotPath, + [_path, value] => Self::HasNotValue { value: value.clone() }, + _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"), + }, + + (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&command_name) => { + return None; + } + _ => { + panic!("Invalid command `//@ {}{command_name}`", if negated { "!" } else { "" }) + } + }; + + Some((kind, &args[0])) + } +} + +impl Command { + /// Performs the actual work of ensuring a command passes. + pub fn check(&self, cache: &mut Cache) -> Result<(), String> { + let matches = cache.select(&self.path); + match &self.kind { + CommandKind::HasPath => { + if matches.is_empty() { + return Err("matched to no values".to_owned()); + } + } + CommandKind::HasNotPath => { + if !matches.is_empty() { + return Err(format!("matched to {matches:?}, but wanted no matches")); + } + } + CommandKind::HasValue { value } => { + let want_value = string_to_value(value, cache); + if !matches.contains(&want_value.as_ref()) { + return Err(format!( + "matched to {matches:?}, which didn't contain {want_value:?}" + )); + } + } + CommandKind::HasNotValue { value } => { + let wantnt_value = string_to_value(value, cache); + if matches.contains(&wantnt_value.as_ref()) { + return Err(format!( + "matched to {matches:?}, which contains unwanted {wantnt_value:?}" + )); + } else if matches.is_empty() { + return Err(format!( + "got no matches, but expected some matched (not containing {wantnt_value:?}" + )); + } + } + + CommandKind::Is { value } => { + let want_value = string_to_value(value, cache); + let matched = get_one(&matches)?; + if matched != want_value.as_ref() { + return Err(format!("matched to {matched:?} but want {want_value:?}")); + } + } + CommandKind::IsNot { value } => { + let wantnt_value = string_to_value(value, cache); + let matched = get_one(&matches)?; + if matched == wantnt_value.as_ref() { + return Err(format!("got value {wantnt_value:?}, but want anything else")); + } + } + + CommandKind::IsMany { values } => { + // Serde json doesn't implement Ord or Hash for Value, so we must + // use a Vec here. While in theory that makes setwize equality + // O(n^2), in practice n will never be large enough to matter. + let expected_values = + values.iter().map(|v| string_to_value(v, cache)).collect::>(); + if expected_values.len() != matches.len() { + return Err(format!( + "Expected {} values, but matched to {} values ({:?})", + expected_values.len(), + matches.len(), + matches + )); + }; + for got_value in matches { + if !expected_values.iter().any(|exp| &**exp == got_value) { + return Err(format!("has match {got_value:?}, which was not expected",)); + } + } + } + CommandKind::CountIs { expected } => { + if *expected != matches.len() { + return Err(format!( + "matched to `{matches:?}` with length {}, but expected length {expected}", + matches.len(), + )); + } + } + CommandKind::Set { variable } => { + let value = get_one(&matches)?; + let r = cache.variables.insert(variable.to_owned(), value.clone()); + assert!(r.is_none(), "name collision: {variable:?} is duplicated"); + } + } + + Ok(()) + } +} + +fn get_one<'a>(matches: &[&'a Value]) -> Result<&'a Value, String> { + match matches { + [] => Err("matched to no values".to_owned()), + [matched] => Ok(matched), + _ => Err(format!("matched to multiple values {matches:?}, but want exactly 1")), + } +} + +// FIXME: This setup is temporary until we figure out how to improve this situation. +// See . +include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs")); + +fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { + if s.starts_with("$") { + Cow::Borrowed(&cache.variables.get(&s[1..]).unwrap_or_else(|| { + // FIXME(adotinthevoid): Show line number + panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables) + })) + } else { + Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s))) + } +} \ No newline at end of file diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 65ad38da98b08..80557b682430c 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -1,17 +1,17 @@ -use std::borrow::Cow; use std::process::ExitCode; use std::sync::LazyLock; use std::{env, fs}; use regex::{Regex, RegexBuilder}; -use serde_json::Value; mod cache; mod config; +mod directive; mod error; use cache::Cache; use config::parse_config; +use directive::{Command, CommandKind}; use error::CkError; fn main() -> ExitCode { @@ -25,7 +25,7 @@ fn main() -> ExitCode { }; for command in commands { - if let Err(message) = check_command(&command, &mut cache) { + if let Err(message) = command.check( &mut cache) { failed.push(CkError { command, message }); } } @@ -41,116 +41,6 @@ fn main() -> ExitCode { } } -#[derive(Debug)] -pub struct Command { - kind: CommandKind, - path: String, - lineno: usize, -} - -#[derive(Debug)] -enum CommandKind { - /// `//@ has ` - /// - /// Checks the path exists. - HasPath, - - /// `//@ has ` - /// - /// Check one thing at the path is equal to the value. - HasValue { value: String }, - - /// `//@ !has ` - /// - /// Checks the path doesn't exist. - HasNotPath, - - /// `//@ !has ` - /// - /// Checks the path exists, but doesn't have the given value. - HasNotValue { value: String }, - - /// `//@ is ` - /// - /// Check the path is the given value. - Is { value: String }, - - /// `//@ is ...` - /// - /// Check that the path matches to exactly every given value. - IsMany { values: Vec }, - - /// `//@ !is ` - /// - /// Check the path isn't the given value. - IsNot { value: String }, - - /// `//@ count ` - /// - /// Check the path has the expected number of matches. - CountIs { expected: usize }, - - /// `//@ set = ` - Set { variable: String }, -} - -impl CommandKind { - /// Returns both the kind and the path. - /// - /// Returns `None` if the command isn't from jsondocck (e.g. from compiletest). - fn parse<'a>(command_name: &str, negated: bool, args: &'a [String]) -> Option<(Self, &'a str)> { - let kind = match (command_name, negated) { - ("count", false) => { - assert_eq!(args.len(), 2); - let expected = args[1].parse().expect("invalid number for `count`"); - Self::CountIs { expected } - } - - ("ismany", false) => { - // FIXME: Make this >= 3, and migrate len(values)==1 cases to @is - assert!(args.len() >= 2, "Not enough args to `ismany`"); - let values = args[1..].to_owned(); - Self::IsMany { values } - } - - ("is", false) => { - assert_eq!(args.len(), 2); - Self::Is { value: args[1].clone() } - } - ("is", true) => { - assert_eq!(args.len(), 2); - Self::IsNot { value: args[1].clone() } - } - - ("set", false) => { - assert_eq!(args.len(), 3); - assert_eq!(args[1], "="); - return Some((Self::Set { variable: args[0].clone() }, &args[2])); - } - - ("has", false) => match args { - [_path] => Self::HasPath, - [_path, value] => Self::HasValue { value: value.clone() }, - _ => panic!("`//@ has` must have 2 or 3 arguments, but got {args:?}"), - }, - ("has", true) => match args { - [_path] => Self::HasNotPath, - [_path, value] => Self::HasNotValue { value: value.clone() }, - _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"), - }, - - (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&command_name) => { - return None; - } - _ => { - panic!("Invalid command `//@ {}{command_name}`", if negated { "!" } else { "" }) - } - }; - - Some((kind, &args[0])) - } -} - static LINE_PATTERN: LazyLock = LazyLock::new(|| { RegexBuilder::new( r#" @@ -183,10 +73,6 @@ fn print_err(msg: &str, lineno: usize) { eprintln!("Invalid command: {} on line {}", msg, lineno) } -// FIXME: This setup is temporary until we figure out how to improve this situation. -// See . -include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs")); - /// Get a list of commands from a file. fn get_commands(template: &str) -> Result, ()> { let mut commands = Vec::new(); @@ -222,108 +108,3 @@ fn get_commands(template: &str) -> Result, ()> { if !errors { Ok(commands) } else { Err(()) } } - -/// Performs the actual work of ensuring a command passes. -fn check_command(command: &Command, cache: &mut Cache) -> Result<(), String> { - let matches = cache.select(&command.path); - match &command.kind { - CommandKind::HasPath => { - if matches.is_empty() { - return Err("matched to no values".to_owned()); - } - } - CommandKind::HasNotPath => { - if !matches.is_empty() { - return Err(format!("matched to {matches:?}, but wanted no matches")); - } - } - CommandKind::HasValue { value } => { - let want_value = string_to_value(value, cache); - if !matches.contains(&want_value.as_ref()) { - return Err(format!("matched to {matches:?}, which didn't contain {want_value:?}")); - } - } - CommandKind::HasNotValue { value } => { - let wantnt_value = string_to_value(value, cache); - if matches.contains(&wantnt_value.as_ref()) { - return Err(format!( - "matched to {matches:?}, which contains unwanted {wantnt_value:?}" - )); - } else if matches.is_empty() { - return Err(format!( - "got no matches, but expected some matched (not containing {wantnt_value:?}" - )); - } - } - - CommandKind::Is { value } => { - let want_value = string_to_value(value, cache); - let matched = get_one(&matches)?; - if matched != want_value.as_ref() { - return Err(format!("matched to {matched:?} but want {want_value:?}")); - } - } - CommandKind::IsNot { value } => { - let wantnt_value = string_to_value(value, cache); - let matched = get_one(&matches)?; - if matched == wantnt_value.as_ref() { - return Err(format!("got value {wantnt_value:?}, but want anything else")); - } - } - - CommandKind::IsMany { values } => { - // Serde json doesn't implement Ord or Hash for Value, so we must - // use a Vec here. While in theory that makes setwize equality - // O(n^2), in practice n will never be large enough to matter. - let expected_values = - values.iter().map(|v| string_to_value(v, cache)).collect::>(); - if expected_values.len() != matches.len() { - return Err(format!( - "Expected {} values, but matched to {} values ({:?})", - expected_values.len(), - matches.len(), - matches - )); - }; - for got_value in matches { - if !expected_values.iter().any(|exp| &**exp == got_value) { - return Err(format!("has match {got_value:?}, which was not expected",)); - } - } - } - CommandKind::CountIs { expected } => { - if *expected != matches.len() { - return Err(format!( - "matched to `{matches:?}` with length {}, but expected length {expected}", - matches.len(), - )); - } - } - CommandKind::Set { variable } => { - let value = get_one(&matches)?; - let r = cache.variables.insert(variable.to_owned(), value.clone()); - assert!(r.is_none(), "name collision: {variable:?} is duplicated"); - } - } - - Ok(()) -} - -fn get_one<'a>(matches: &[&'a Value]) -> Result<&'a Value, String> { - match matches { - [] => Err("matched to no values".to_owned()), - [matched] => Ok(matched), - _ => Err(format!("matched to multiple values {matches:?}, but want exactly 1")), - } -} - -fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { - if s.starts_with("$") { - Cow::Borrowed(&cache.variables.get(&s[1..]).unwrap_or_else(|| { - // FIXME(adotinthevoid): Show line number - panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables) - })) - } else { - Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s))) - } -} From 851aa05aa0addf41507967952f1ac2d183751682 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 09:35:55 +0000 Subject: [PATCH 08/39] cleanup: Reuse `MinInt` and `Int` from `libm` in `compiler-builtins` Since the two crates are now in the same repo, it is easier to share code. Begin some deduplication with the integer traits. --- .../builtins-test/src/lib.rs | 78 ++++- .../compiler-builtins/src/float/add.rs | 22 +- .../compiler-builtins/src/float/conv.rs | 24 +- .../compiler-builtins/src/float/div.rs | 2 +- .../compiler-builtins/src/float/mul.rs | 2 +- .../compiler-builtins/src/float/traits.rs | 4 +- .../compiler-builtins/src/int/addsub.rs | 6 +- .../compiler-builtins/src/int/big.rs | 4 +- .../src/int/leading_zeros.rs | 64 ++-- .../src/int/trailing_zeros.rs | 25 +- .../compiler-builtins/src/int/traits.rs | 273 +----------------- .../libm/src/math/support/int_traits.rs | 9 + 12 files changed, 168 insertions(+), 345 deletions(-) diff --git a/library/compiler-builtins/builtins-test/src/lib.rs b/library/compiler-builtins/builtins-test/src/lib.rs index c596ac2138076..f1673133be27d 100644 --- a/library/compiler-builtins/builtins-test/src/lib.rs +++ b/library/compiler-builtins/builtins-test/src/lib.rs @@ -40,6 +40,75 @@ pub const N: u32 = if cfg!(target_arch = "x86_64") && !cfg!(debug_assertions) { 10_000 }; +/// Additional constants that determine how the integer gets fuzzed. +trait FuzzInt: MinInt { + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// 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(Self::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = Self::BITS.ilog2() 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)) + } + }; +} + +impl FuzzInt for I where I: MinInt {} + +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 +} + /// Random fuzzing step. When run several times, it results in excellent fuzzing entropy such as: /// 11110101010101011110111110011111 /// 10110101010100001011101011001010 @@ -92,10 +161,9 @@ fn fuzz_step(rng: &mut Xoshiro128StarStar, x: &mut I) { 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); + let mask_lo = (!$I::Unsigned::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 mask_hi = (!$I::Unsigned::ZERO).wrapping_shl($I::FUZZ_LENGTHS[i1 - i0] as u32); let $case = I::from_unsigned(mask_lo & mask_hi); $inner } @@ -107,7 +175,7 @@ macro_rules! edge_cases { /// edge cases, followed by a more random fuzzer that runs `n` times. pub fn fuzz(n: u32, mut f: F) where - ::UnsignedInt: Int, + ::Unsigned: Int, { // edge case tester. Calls `f` 210 times for u128. // zero gets skipped by the loop @@ -128,7 +196,7 @@ where /// The same as `fuzz`, except `f` has two inputs. pub fn fuzz_2(n: u32, f: F) where - ::UnsignedInt: Int, + ::Unsigned: Int, { // Check cases where the first and second inputs are zero. Both call `f` 210 times for `u128`. edge_cases!(I, case, { diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index 0426c9cc44fbb..43e3ae931ffa4 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int, MinInt}; +use crate::int::{CastFrom, CastInto, Int, MinInt}; /// Returns `a + b` fn add(a: F, b: F) -> F @@ -12,7 +12,7 @@ where let one = F::Int::ONE; let zero = F::Int::ZERO; - let bits = F::BITS.cast(); + let bits: F::Int = F::BITS.cast(); let significand_bits = F::SIG_BITS; let max_exponent = F::EXP_SAT; @@ -115,9 +115,10 @@ where let align = a_exponent.wrapping_sub(b_exponent).cast(); if align != MinInt::ZERO { if align < bits { - let sticky = - F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != MinInt::ZERO); - b_significand = (b_significand >> align.cast()) | sticky; + let sticky = F::Int::from_bool( + b_significand << u32::cast_from(bits.wrapping_sub(align)) != MinInt::ZERO, + ); + b_significand = (b_significand >> u32::cast_from(align)) | sticky; } else { b_significand = one; // sticky; b is known to be non-zero. } @@ -132,8 +133,8 @@ 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 << 3u32).leading_zeros() as i32; a_significand <<= shift; a_exponent -= shift; } @@ -159,9 +160,10 @@ 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()) != MinInt::ZERO); - a_significand = (a_significand >> shift.cast()) | sticky; + let sticky = F::Int::from_bool( + (a_significand << u32::cast_from(bits.wrapping_sub(shift))) != MinInt::ZERO, + ); + a_significand = (a_significand >> u32::cast_from(shift)) | sticky; a_exponent = 0; } diff --git a/library/compiler-builtins/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs index f5427a11390fc..9d732f2cdbc9e 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/conv.rs @@ -72,7 +72,7 @@ mod int_to_float { F: Float, I: Int, F::Int: CastFrom, - Conv: Fn(I::UnsignedInt) -> F::Int, + Conv: Fn(I::Unsigned) -> 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) @@ -313,10 +313,10 @@ intrinsics! { fn float_to_unsigned_int(f: F) -> U where F: Float, - U: Int, + U: Int, F::Int: CastInto, F::Int: CastFrom, - F::Int: CastInto, + F::Int: CastInto, u32: CastFrom, { float_to_int_inner::(f.to_bits(), |i: U| i, || U::MAX) @@ -327,8 +327,8 @@ fn float_to_signed_int(f: F) -> I where F: Float, I: Int + Neg, - I::UnsignedInt: Int, - F::Int: CastInto, + I::Unsigned: Int, + F::Int: CastInto, F::Int: CastFrom, u32: CastFrom, { @@ -355,27 +355,27 @@ where I: Int, FnFoo: FnOnce(I) -> I, FnOob: FnOnce() -> I, - I::UnsignedInt: Int, - F::Int: CastInto, + I::Unsigned: Int, + F::Int: CastInto, F::Int: CastFrom, u32: CastFrom, { let int_max_exp = F::EXP_BIAS + I::MAX.ilog2() + 1; - let foobar = F::EXP_BIAS + I::UnsignedInt::BITS - 1; + let foobar = F::EXP_BIAS + I::Unsigned::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::SIG_BITS { // >= 1, < integer max - let m_base = if I::UnsignedInt::BITS >= F::Int::BITS { - I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) + let m_base = if I::Unsigned::BITS >= F::Int::BITS { + I::Unsigned::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) } else { - I::UnsignedInt::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) + I::Unsigned::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; + let m: I::Unsigned = (I::Unsigned::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/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs index 5df637c7e0f9b..3e4f0e20d1056 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -370,7 +370,7 @@ where 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) + let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1u32) .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 diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs index 7f1f19d9bd7fb..c811f140670e6 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -143,7 +143,7 @@ where // 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(); + let shift: u32 = one.wrapping_sub(product_exponent.cast()).cast(); if shift >= bits { return F::from_bits(product_sign); } diff --git a/library/compiler-builtins/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/compiler-builtins/src/float/traits.rs index 8ccaa7bcbd78a..a30d20900b1c4 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/traits.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/traits.rs @@ -20,10 +20,10 @@ 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; diff --git a/library/compiler-builtins/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/compiler-builtins/src/int/addsub.rs index 1f84e8eb1e117..b2b21fc2c4401 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/addsub.rs @@ -22,7 +22,7 @@ impl UAddSub for u128 {} trait AddSub: Int where - ::UnsignedInt: UAddSub, + ::Unsigned: 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, + ::Unsigned: 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, + ::Unsigned: UAddSub, { fn subo(self, other: Self) -> (Self, bool) { let sum = AddSub::sub(self, other); diff --git a/library/compiler-builtins/compiler-builtins/src/int/big.rs b/library/compiler-builtins/compiler-builtins/src/int/big.rs index 1402efb8ed419..8e06009090c09 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/big.rs @@ -45,7 +45,7 @@ impl i256 { impl MinInt for u256 { type OtherSign = i256; - type UnsignedInt = u256; + type Unsigned = u256; const SIGNED: bool = false; const BITS: u32 = 256; @@ -58,7 +58,7 @@ impl MinInt for u256 { impl MinInt for i256 { type OtherSign = u256; - type UnsignedInt = u256; + type Unsigned = u256; const SIGNED: bool = false; const BITS: u32 = 256; 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 112f4d0361317..aa5cb39935ad8 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs @@ -9,11 +9,14 @@ pub use implementation::{leading_zeros_default, leading_zeros_riscv}; pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; mod implementation { - use crate::int::{CastInto, Int}; + use crate::int::{CastFrom, Int}; /// Returns the number of leading binary zeros in `x`. #[allow(dead_code)] - pub fn leading_zeros_default>(x: T) -> usize { + pub fn leading_zeros_default(x: I) -> usize + where + usize: CastFrom, + { // 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 @@ -23,44 +26,48 @@ mod implementation { // because it simplifies the final bisection step. let mut x = x; // the number of potential leading zeros - let mut z = T::BITS as usize; + let mut z = I::BITS as usize; // a temporary - let mut t: T; + let mut t: I; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { + const { assert!(I::BITS <= 64) }; + if I::BITS >= 64 { t = x >> 32; - if t != T::ZERO { + if t != I::ZERO { z -= 32; x = t; } } - if T::BITS >= 32 { + if I::BITS >= 32 { t = x >> 16; - if t != T::ZERO { + if t != I::ZERO { z -= 16; x = t; } } - const { assert!(T::BITS >= 16) }; + const { assert!(I::BITS >= 16) }; t = x >> 8; - if t != T::ZERO { + if t != I::ZERO { z -= 8; x = t; } t = x >> 4; - if t != T::ZERO { + if t != I::ZERO { z -= 4; x = t; } t = x >> 2; - if t != T::ZERO { + if t != I::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() } + if t != I::ZERO { + z - 2 + } else { + z - usize::cast_from(x) + } // We could potentially save a few cycles by using the LUT trick from // "https://embeddedgurus.com/state-space/2014/09/ @@ -82,10 +89,13 @@ mod implementation { /// Returns the number of leading binary zeros in `x`. #[allow(dead_code)] - pub fn leading_zeros_riscv>(x: T) -> usize { + pub fn leading_zeros_riscv(x: I) -> usize + where + usize: CastFrom, + { let mut x = x; // the number of potential leading zeros - let mut z = T::BITS; + let mut z = I::BITS; // a temporary let mut t: u32; @@ -97,11 +107,11 @@ mod implementation { // 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 { + const { assert!(I::BITS <= 64) }; + if I::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; + t = ((x >= (I::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; @@ -109,27 +119,27 @@ mod implementation { // leading zeros z -= t; } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; + if I::BITS >= 32 { + t = ((x >= (I::ONE << 16)) as u32) << 4; x >>= t; z -= t; } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; + const { assert!(I::BITS >= 16) }; + t = ((x >= (I::ONE << 8)) as u32) << 3; x >>= t; z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; + t = ((x >= (I::ONE << 4)) as u32) << 2; x >>= t; z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; + t = ((x >= (I::ONE << 2)) as u32) << 1; x >>= t; z -= t; - t = (x >= (T::ONE << 1)) as u32; + t = (x >= (I::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() + z as usize - usize::cast_from(x) } } 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 c45d6b1cfe8d8..8f63c22c8f734 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs @@ -4,33 +4,38 @@ pub use implementation::trailing_zeros; pub(crate) use implementation::trailing_zeros; mod implementation { - use crate::int::{CastInto, Int}; + use crate::int::{CastFrom, Int}; /// Returns number of trailing binary zeros in `x`. #[allow(dead_code)] - pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + pub fn trailing_zeros(x: I) -> usize + where + u32: CastFrom, + u16: CastFrom, + u8: CastFrom, + { 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 + const { assert!(I::BITS <= 64) }; + if I::BITS >= 64 { + r += ((u32::cast_from(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 + if I::BITS >= 32 { + t = ((u16::cast_from(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; + const { assert!(I::BITS >= 16) }; + t = ((u8::cast_from(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_lossy(); t = (((x & 0x0F) == 0) as u32) << 2; x >>= t; // x = [0 - 0xF] + higher garbage bits diff --git a/library/compiler-builtins/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/compiler-builtins/src/int/traits.rs index 152cb2eee2ee6..b474df366eb56 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/traits.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/traits.rs @@ -1,275 +1,4 @@ -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 `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. - 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); +pub use crate::support::{Int, MinInt}; /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. 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 3ec1faba170cb..fa9e06066d744 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -78,6 +78,7 @@ pub trait Int: fn unsigned(self) -> Self::Unsigned; fn from_unsigned(unsigned: Self::Unsigned) -> Self; fn abs(self) -> Self; + fn unsigned_abs(self) -> Self::Unsigned; fn from_bool(b: bool) -> Self; @@ -203,6 +204,10 @@ macro_rules! int_impl { unimplemented!() } + fn unsigned_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 { @@ -242,6 +247,10 @@ macro_rules! int_impl { self.abs() } + fn unsigned_abs(self) -> Self::Unsigned { + self.unsigned_abs() + } + fn from_unsigned(me: $uty) -> Self { me as $ity } From 877feef541542972f1bfeefe14624a17f23cef8d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 03:51:43 +0000 Subject: [PATCH 09/39] Reuse `libm`'s `Caat` and `CastFrom` in `compiler-builtins` --- .../compiler-builtins/src/float/add.rs | 2 +- .../compiler-builtins/src/float/conv.rs | 6 +-- .../compiler-builtins/src/float/div.rs | 2 +- .../compiler-builtins/src/float/mul.rs | 2 +- .../compiler-builtins/src/float/trunc.rs | 2 +- .../src/int/trailing_zeros.rs | 6 +-- .../compiler-builtins/src/int/traits.rs | 43 +------------------ .../libm/src/math/support/int_traits.rs | 5 +++ 8 files changed, 16 insertions(+), 52 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index 43e3ae931ffa4..0cc362f705b11 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -168,7 +168,7 @@ where } // Low three bits are round, guard, and sticky. - let a_significand_i32: i32 = a_significand.cast(); + let a_significand_i32: i32 = a_significand.cast_lossy(); let round_guard_sticky: i32 = a_significand_i32 & 0x7; // Shift the significand into place, and mask off the implicit bit. diff --git a/library/compiler-builtins/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs index 9d732f2cdbc9e..75ea7ce02424a 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/conv.rs @@ -74,7 +74,7 @@ mod int_to_float { F::Int: CastFrom, Conv: Fn(I::Unsigned) -> F::Int, { - let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1); + let sign_bit = F::Int::cast_from_lossy(i >> (I::BITS - 1)) << (F::BITS - 1); F::from_bits(conv(i.unsigned_abs()) | sign_bit) } @@ -166,7 +166,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::SIG_BITS - 1)).cast(); + let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast_lossy(); // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just // check if it is nonzero. @@ -371,7 +371,7 @@ where let m_base = if I::Unsigned::BITS >= F::Int::BITS { I::Unsigned::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) } else { - I::Unsigned::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) + I::Unsigned::cast_from_lossy(fbits >> (F::SIG_BITS - I::BITS + 1)) }; // Set the implicit 1-bit. diff --git a/library/compiler-builtins/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs index 3e4f0e20d1056..fc1fc085105a7 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -482,7 +482,7 @@ where 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_shl(significand_bits.wrapping_add(CastInto::::cast_lossy(res_exponent))) .wrapping_sub(ret.wrapping_mul(b_significand) << 1); ret }; diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs index c811f140670e6..dbed3095cda5d 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -143,7 +143,7 @@ where // 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: u32 = one.wrapping_sub(product_exponent.cast()).cast(); + let shift: u32 = one.wrapping_sub(product_exponent.cast_lossy()).cast(); if shift >= bits { return F::from_bits(product_sign); } diff --git a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs index ca8a0f368b563..93db5d8bbdeb1 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs @@ -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 >> sig_bits_delta).cast(); + abs_result = (a_abs >> sig_bits_delta).cast_lossy(); // 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; 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 8f63c22c8f734..1b0ae5b73ad24 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs @@ -20,18 +20,18 @@ mod implementation { const { assert!(I::BITS <= 64) }; if I::BITS >= 64 { - r += ((u32::cast_from(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + r += ((u32::cast_from_lossy(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 x >>= r; // remove 32 zero bits } if I::BITS >= 32 { - t = ((u16::cast_from(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + t = ((u16::cast_from_lossy(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!(I::BITS >= 16) }; - t = ((u8::cast_from(x) == 0) as u32) << 3; + t = ((u8::cast_from_lossy(x) == 0) as u32) << 3; x >>= t; // x = [0 - 0xFF] + higher garbage bits r += t; diff --git a/library/compiler-builtins/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/compiler-builtins/src/int/traits.rs index b474df366eb56..25b9718ad53fb 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/traits.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/traits.rs @@ -1,4 +1,4 @@ -pub use crate::support::{Int, MinInt}; +pub use crate::support::{CastFrom, CastInto, Int, MinInt}; /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. @@ -97,44 +97,3 @@ impl_h_int!( 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/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index fa9e06066d744..716af748a9fb8 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -374,14 +374,19 @@ impl_h_int!( /// Trait to express (possibly lossy) casting of integers pub trait CastInto: Copy { /// By default, casts should be exact. + #[track_caller] fn cast(self) -> T; /// Call for casts that are expected to truncate. + /// + /// In practice, this is exactly the same as `cast`; the main difference is to document intent + /// in code. `cast` may panic in debug mode. fn cast_lossy(self) -> T; } pub trait CastFrom: Copy { /// By default, casts should be exact. + #[track_caller] fn cast_from(value: T) -> Self; /// Call for casts that are expected to truncate. From 97c0bebdf7094434c0fb2f941d7136c9c3ade986 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 May 2025 18:15:41 +0000 Subject: [PATCH 10/39] Remove unneeded C symbols These are now provided by `compiler-builtins`, so there is no need to also build the C versions. This was detected by checking for duplicate symbols and not excluding weak symbols (like CI currently does). --- library/compiler-builtins/compiler-builtins/build.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 90d98ec7ce940..d37fdc5df507a 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -555,7 +555,6 @@ mod c { if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ - ("__comparetf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c"), ("__fe_raise_inexact", "fp_mode.c"), ]); @@ -570,11 +569,11 @@ mod c { } if target.arch == "mips64" { - sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); + sources.extend(&[("__fe_getround", "fp_mode.c")]); } if target.arch == "loongarch64" { - sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); + sources.extend(&[("__fe_getround", "fp_mode.c")]); } // Remove the assembly implementations that won't compile for the target From a63f4826cf2ccceeedff5fb19ba0cbffc1ef5d65 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 07:38:43 +0000 Subject: [PATCH 11/39] Replace the `nm` symbol check with a Rust implementation This should be less error-prone and adaptable than the `nm` version, and have better cross-platform support without needing LLVM `nm` installed. --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/ci/run.sh | 125 ++-------- .../crates/symbol-check/Cargo.toml | 13 + .../crates/symbol-check/src/main.rs | 231 ++++++++++++++++++ 4 files changed, 262 insertions(+), 108 deletions(-) create mode 100644 library/compiler-builtins/crates/symbol-check/Cargo.toml create mode 100644 library/compiler-builtins/crates/symbol-check/src/main.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b39ec8a25dac1..bc6b4bd29795e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -6,6 +6,7 @@ members = [ "crates/libm-macros", "crates/musl-math-sys", "crates/panic-handler", + "crates/symbol-check", "crates/util", "libm", "libm-test", diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 68d13c130bcce..cf3f7dfda1da2 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -47,87 +47,25 @@ else fi 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] -update_rlib_paths -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" --features c --release -cargo build -p compiler_builtins --target "$target" --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" --features no-f16-f128 --release - -PREFIX=${target//unknown-/}- -case "$target" in - armv7-*) - PREFIX=arm-linux-gnueabihf- - ;; - thumb*) - PREFIX=arm-none-eabi- - ;; - *86*-*) - PREFIX= - ;; -esac - -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)//')" -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 -update_rlib_paths -for rlib in "${rlib_paths[@]}"; do - set +x - echo "================================================================" - echo "checking $rlib for duplicate symbols" - echo "================================================================" - set -x - - duplicates_found=0 - - # NOTE On i586, It's normal that the get_pc_thunk symbol appears several - # times so ignore it - $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 -done - -rm -f "${rlib_paths[@]}" +# Ensure there are no duplicate symbols or references to `core` when +# `compiler-builtins` is built with various features. Symcheck invokes Cargo to +# build with the arguments we provide it, then validates the built artifacts. +symcheck=(cargo run -p symbol-check --release) +[[ "$target" = "wasm"* ]] && symcheck+=(--features wasm) +symcheck+=(-- build-and-check) + +"${symcheck[@]}" -p compiler_builtins --target "$target" +"${symcheck[@]}" -p compiler_builtins --target "$target" --release +"${symcheck[@]}" -p compiler_builtins --target "$target" --features c +"${symcheck[@]}" -p compiler_builtins --target "$target" --features c --release +"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-asm +"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-asm --release +"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 +"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 --release build_intrinsics_test() { - cargo build \ + # symcheck also checks the results of builtins-test-intrinsics + "${symcheck[@]}" \ --target "$target" --verbose \ --manifest-path builtins-test-intrinsics/Cargo.toml "$@" } @@ -143,35 +81,6 @@ build_intrinsics_test --features c --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 -for rlib in "${rlib_paths[@]}"; do - set +x - echo "================================================================" - echo "checking $rlib for references to core" - echo "================================================================" - 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_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_has_results" != 0 ]; then - echo "error: found unexpected references to core" - exit 1 - else - echo "success; no references to core found" - fi -done - # Test libm # Make sure a simple build works diff --git a/library/compiler-builtins/crates/symbol-check/Cargo.toml b/library/compiler-builtins/crates/symbol-check/Cargo.toml new file mode 100644 index 0000000000000..30969ee406ab4 --- /dev/null +++ b/library/compiler-builtins/crates/symbol-check/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "symbol-check" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +# FIXME: used as a git dependency since the latest release does not support wasm +object = { git = "https://github.com/gimli-rs/object.git", rev = "013fac75da56a684377af4151b8164b78c1790e0" } +serde_json = "1.0.140" + +[features] +wasm = ["object/wasm"] diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs new file mode 100644 index 0000000000000..104505438cc07 --- /dev/null +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -0,0 +1,231 @@ +//! Tool used by CI to inspect compiler-builtins archives and help ensure we won't run into any +//! linking errors. + +use std::collections::{BTreeMap, BTreeSet}; +use std::fs; +use std::io::{BufRead, BufReader}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; + +use object::read::archive::{ArchiveFile, ArchiveMember}; +use object::{Object, ObjectSymbol, Symbol, SymbolKind, SymbolScope, SymbolSection}; +use serde_json::Value; + +const CHECK_LIBRARIES: &[&str] = &["compiler_builtins", "builtins_test_intrinsics"]; +const CHECK_EXTENSIONS: &[Option<&str>] = &[Some("rlib"), Some("a"), Some("exe"), None]; + +const USAGE: &str = "Usage: + + symbol-check build-and-check CARGO_ARGS ... + +Cargo will get invoked with `CARGO_ARGS` and all output +`compiler_builtins*.rlib` files will be checked. +"; + +fn main() { + // Create a `&str` vec so we can match on it. + let args = std::env::args().collect::>(); + let args_ref = args.iter().map(String::as_str).collect::>(); + + match &args_ref[1..] { + ["build-and-check", rest @ ..] if !rest.is_empty() => { + let paths = exec_cargo_with_args(rest); + for path in paths { + println!("Checking {}", path.display()); + verify_no_duplicates(&path); + verify_core_symbols(&path); + } + } + _ => { + println!("{USAGE}"); + std::process::exit(1); + } + } +} + +/// Run `cargo build` with the provided additional arguments, collecting the list of created +/// libraries. +fn exec_cargo_with_args(args: &[&str]) -> Vec { + let mut cmd = Command::new("cargo") + .arg("build") + .arg("--message-format=json") + .args(args) + .stdout(Stdio::piped()) + .spawn() + .expect("failed to launch Cargo"); + + let stdout = cmd.stdout.take().unwrap(); + let reader = BufReader::new(stdout); + let mut check_files = Vec::new(); + + for line in reader.lines() { + let line = line.expect("failed to read line"); + println!("{line}"); // tee to stdout + + // Select only steps that create files + let j: Value = serde_json::from_str(&line).expect("failed to deserialize"); + if j["reason"] != "compiler-artifact" { + continue; + } + + // Find rlibs in the created file list that match our expected library names and + // extensions. + for fpath in j["filenames"].as_array().expect("filenames not an array") { + let path = fpath.as_str().expect("file name not a string"); + let path = PathBuf::from(path); + + if CHECK_EXTENSIONS.contains(&path.extension().map(|ex| ex.to_str().unwrap())) { + let fname = path.file_name().unwrap().to_str().unwrap(); + + if CHECK_LIBRARIES.iter().any(|lib| fname.contains(lib)) { + check_files.push(path); + } + } + } + } + + cmd.wait().expect("failed to wait on Cargo"); + + assert!(!check_files.is_empty(), "no compiler_builtins rlibs found"); + println!("Collected the following rlibs to check: {check_files:#?}"); + + check_files +} + +/// Information collected from `object`, for convenience. +#[expect(unused)] // only for printing +#[derive(Clone, Debug)] +struct SymInfo { + name: String, + kind: SymbolKind, + scope: SymbolScope, + section: SymbolSection, + is_undefined: bool, + is_global: bool, + is_local: bool, + is_weak: bool, + is_common: bool, + address: u64, + object: String, +} + +impl SymInfo { + fn new(sym: &Symbol, member: &ArchiveMember) -> Self { + Self { + name: sym.name().expect("missing name").to_owned(), + kind: sym.kind(), + scope: sym.scope(), + section: sym.section(), + is_undefined: sym.is_undefined(), + is_global: sym.is_global(), + is_local: sym.is_local(), + is_weak: sym.is_weak(), + is_common: sym.is_common(), + address: sym.address(), + object: String::from_utf8_lossy(member.name()).into_owned(), + } + } +} + +/// Ensure that the same global symbol isn't defined in multiple object files within an archive. +/// +/// Note that this will also locate cases where a symbol is weakly defined in more than one place. +/// Technically there are no linker errors that will come from this, but it keeps our binary more +/// straightforward and saves some distribution size. +fn verify_no_duplicates(path: &Path) { + let mut syms = BTreeMap::::new(); + let mut dups = Vec::new(); + let mut found_any = false; + + for_each_symbol(path, |symbol, member| { + // Only check defined globals + if !symbol.is_global() || symbol.is_undefined() { + return; + } + + let sym = SymInfo::new(&symbol, member); + + // x86-32 includes multiple copies of thunk symbols + if sym.name.starts_with("__x86.get_pc_thunk") { + return; + } + + // Windows has symbols for literal numeric constants, string literals, and MinGW pseudo- + // relocations. These are allowed to have repeated definitions. + let win_allowed_dup_pfx = ["__real@", "__xmm@", "??_C@_", ".refptr"]; + if win_allowed_dup_pfx + .iter() + .any(|pfx| sym.name.starts_with(pfx)) + { + return; + } + + match syms.get(&sym.name) { + Some(existing) => { + dups.push(sym); + dups.push(existing.clone()); + } + None => { + syms.insert(sym.name.clone(), sym); + } + } + + found_any = true; + }); + + assert!(found_any, "no symbols found"); + + if !dups.is_empty() { + dups.sort_unstable_by(|a, b| a.name.cmp(&b.name)); + panic!("found duplicate symbols: {dups:#?}"); + } + + println!(" success: no duplicate symbols found"); +} + +/// Ensure that there are no references to symbols from `core` that aren't also (somehow) defined. +fn verify_core_symbols(path: &Path) { + let mut defined = BTreeSet::new(); + let mut undefined = Vec::new(); + let mut has_symbols = false; + + for_each_symbol(path, |symbol, member| { + has_symbols = true; + + // Find only symbols from `core` + if !symbol.name().unwrap().contains("_ZN4core") { + return; + } + + let sym = SymInfo::new(&symbol, member); + if sym.is_undefined { + undefined.push(sym); + } else { + defined.insert(sym.name); + } + }); + + assert!(has_symbols, "no symbols found"); + + // Discard any symbols that are defined somewhere in the archive + undefined.retain(|sym| !defined.contains(&sym.name)); + + if !undefined.is_empty() { + undefined.sort_unstable_by(|a, b| a.name.cmp(&b.name)); + panic!("found undefined symbols from core: {undefined:#?}"); + } + + println!(" success: no undefined references to core found"); +} + +/// For a given archive path, do something with each symbol. +fn for_each_symbol(path: &Path, mut f: impl FnMut(Symbol, &ArchiveMember)) { + let data = fs::read(path).expect("reading file failed"); + let archive = ArchiveFile::parse(data.as_slice()).expect("archive parse failed"); + for member in archive.members() { + let member = member.expect("failed to access member"); + let obj_data = member.data(&*data).expect("failed to access object"); + let obj = object::File::parse(obj_data).expect("failed to parse object"); + obj.symbols().for_each(|sym| f(sym, &member)); + } +} From 8db9bd6a59c8c59b8d04ee647f071e81f79f6225 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 May 2025 19:59:16 +0000 Subject: [PATCH 12/39] Remove the now-unneeded llvm-tools-preview Since a working `nm` is no longer needed as part of CI, the rustup component can be removed. --- library/compiler-builtins/.github/workflows/main.yaml | 1 - library/compiler-builtins/crates/symbol-check/src/main.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index d13dd6b0f6462..567ad1205a5d3 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -119,7 +119,6 @@ jobs: rustup update "$channel" --no-self-update 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: diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index 104505438cc07..4e6417fdf9525 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -84,7 +84,7 @@ fn exec_cargo_with_args(args: &[&str]) -> Vec { } } - cmd.wait().expect("failed to wait on Cargo"); + assert!(cmd.wait().expect("failed to wait on Cargo").success()); assert!(!check_files.is_empty(), "no compiler_builtins rlibs found"); println!("Collected the following rlibs to check: {check_files:#?}"); From 151b1cb04777e1e9630045d52f14bc0e7adf5787 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 15:40:05 +0000 Subject: [PATCH 13/39] Change `compiler-builtins` to edition 2024 Do the same for `builtins-test-intrinsics`. Mostly this means updating `extern` to `unsafe extern`, and fixing a few new Clippy lints. --- .../builtins-test-intrinsics/Cargo.toml | 2 +- .../builtins-test-intrinsics/src/main.rs | 6 ++++-- .../builtins-test/tests/aeabi_memclr.rs | 3 ++- .../builtins-test/tests/aeabi_memcpy.rs | 3 ++- .../builtins-test/tests/aeabi_memset.rs | 3 ++- .../compiler-builtins/Cargo.toml | 2 +- .../compiler-builtins/src/arm.rs | 7 +++++-- .../src/int/specialized_div_rem/mod.rs | 16 ++++++++-------- .../compiler-builtins/src/macros.rs | 4 ++-- .../compiler-builtins/src/probestack.rs | 4 +++- 10 files changed, 30 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 6e10628a41b22..704de20c5ad64 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "builtins-test-intrinsics" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false license = "MIT OR Apache-2.0" diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index 1fa7b00916f77..96fe4a7385113 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -15,9 +15,10 @@ extern crate panic_handler; +// SAFETY: no definitions, only used for linking #[cfg(all(not(thumb), not(windows), not(target_arch = "wasm32")))] #[link(name = "c")] -extern "C" {} +unsafe 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 @@ -663,10 +664,11 @@ pub fn _start() -> ! { loop {} } +// SAFETY: no definitions, only used for linking #[cfg(windows)] #[link(name = "kernel32")] #[link(name = "msvcrt")] -extern "C" {} +unsafe extern "C" {} // ARM targets need these symbols #[unsafe(no_mangle)] diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs index bfd15a391aab2..0761feaffd9e2 100644 --- a/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs @@ -24,7 +24,8 @@ macro_rules! panic { }; } -extern "C" { +// SAFETY: defined in compiler-builtins +unsafe extern "aapcs" { fn __aeabi_memclr4(dest: *mut u8, n: usize); fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); } diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs index c892c5aba0f74..e76e712a246f1 100644 --- a/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs +++ b/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs @@ -22,7 +22,8 @@ macro_rules! panic { }; } -extern "C" { +// SAFETY: defined in compiler-builtins +unsafe extern "aapcs" { fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize); fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize); } diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs index 34ab3acc78c16..8f9f80f969ccb 100644 --- a/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs +++ b/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs @@ -24,7 +24,8 @@ macro_rules! panic { }; } -extern "C" { +// SAFETY: defined in compiler-builtins +unsafe extern "aapcs" { fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); } diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index d65a22152ef94..93eb3e01b3b8a 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/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 = "2021" +edition = "2024" description = "Compiler intrinsics used by the Rust compiler." links = "compiler-rt" diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index a9107e3cdfda4..a7d84e49b3493 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -1,13 +1,16 @@ #![cfg(not(feature = "no-asm"))] // Interfaces used by naked trampolines. -extern "C" { +// SAFETY: these are defined in compiler-builtins +unsafe 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; } -extern "aapcs" { +// SAFETY: these are defined in compiler-builtins +// FIXME(extern_custom), this isn't always the correct ABI +unsafe 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; 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 43f466e75ba4a..7841e4f33cd66 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 @@ -125,10 +125,10 @@ impl_normalization_shift!( /// 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); - } + if let Some(quo) = duo.checked_div(div) + && let Some(rem) = duo.checked_rem(div) + { + return (quo, rem); } zero_div_fn() } @@ -227,10 +227,10 @@ impl_asymmetric!( #[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); - } + if let Some(quo) = duo.checked_div(div) + && let Some(rem) = duo.checked_rem(div) + { + return (quo, rem); } zero_div_fn() } diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 22e0dd27f2f5a..203cd0949ac52 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -132,7 +132,7 @@ macro_rules! intrinsics { ) => ( #[cfg($name = "optimized-c")] pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - extern $abi { + unsafe extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; } unsafe { @@ -435,7 +435,7 @@ macro_rules! intrinsics { pub mod $name { #[unsafe(naked)] $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(not(feature = "mangled-names"), unsafe(no_mangle))] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* diff --git a/library/compiler-builtins/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs index 5b6abd21a1db3..c9070cf55c64a 100644 --- a/library/compiler-builtins/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/compiler-builtins/src/probestack.rs @@ -49,7 +49,9 @@ // We only define stack probing for these architectures today. #![cfg(any(target_arch = "x86_64", target_arch = "x86"))] -extern "C" { +// SAFETY: defined in this module. +// FIXME(extern_custom): the ABI is not correct. +unsafe extern "C" { pub fn __rust_probestack(); } From af16553893152ba74b0391b02c31f083c2f519b1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 16:07:54 +0000 Subject: [PATCH 14/39] symcheck: Print the command to make reproducing errors easier --- .../crates/symbol-check/src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index 4e6417fdf9525..d83cd318d6a95 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -46,15 +46,16 @@ fn main() { /// Run `cargo build` with the provided additional arguments, collecting the list of created /// libraries. fn exec_cargo_with_args(args: &[&str]) -> Vec { - let mut cmd = Command::new("cargo") - .arg("build") + let mut cmd = Command::new("cargo"); + cmd.arg("build") .arg("--message-format=json") .args(args) - .stdout(Stdio::piped()) - .spawn() - .expect("failed to launch Cargo"); + .stdout(Stdio::piped()); - let stdout = cmd.stdout.take().unwrap(); + println!("running: {cmd:?}"); + let mut child = cmd.spawn().expect("failed to launch Cargo"); + + let stdout = child.stdout.take().unwrap(); let reader = BufReader::new(stdout); let mut check_files = Vec::new(); @@ -84,7 +85,7 @@ fn exec_cargo_with_args(args: &[&str]) -> Vec { } } - assert!(cmd.wait().expect("failed to wait on Cargo").success()); + assert!(child.wait().expect("failed to wait on Cargo").success()); assert!(!check_files.is_empty(), "no compiler_builtins rlibs found"); println!("Collected the following rlibs to check: {check_files:#?}"); From 7db8cf1fea87dd42082ac6eeb405e609628ac6b1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 17:37:35 +0000 Subject: [PATCH 15/39] Add benchmarks for float parsing and printing As part of this, the u256 benchmarks are reorganized to a group. --- .../libm-test/benches/icount.rs | 100 +++++++++++++++--- 1 file changed, 83 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index da8c6bfd15a03..4bebbc41ccd87 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -1,9 +1,11 @@ //! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. +#![feature(f16)] +#![feature(f128)] use std::hint::black_box; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; -use libm::support::{HInt, u256}; +use libm::support::{HInt, Hexf, hf16, hf32, hf64, hf128, u256}; use libm_test::generate::spaced; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; @@ -109,11 +111,6 @@ fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { } } -library_benchmark_group!( - name = icount_bench_u128_widen_mul_group; - benchmarks = icount_bench_u128_widen_mul -); - #[library_benchmark] #[bench::linspace(setup_u256_add())] fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { @@ -122,11 +119,6 @@ fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { } } -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)>) { @@ -136,16 +128,90 @@ fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { } library_benchmark_group!( - name = icount_bench_u256_shr_group; - benchmarks = icount_bench_u256_shr + name = icount_bench_u128_group; + benchmarks = icount_bench_u128_widen_mul, icount_bench_u256_add, icount_bench_u256_shr +); + +#[library_benchmark] +#[bench::short("0x12.34p+8")] +#[bench::max("0x1.ffcp+15")] +fn icount_bench_hf16(s: &str) -> f16 { + black_box(hf16(s)) +} + +#[library_benchmark] +#[bench::short("0x12.34p+8")] +#[bench::max("0x1.fffffep+127")] +fn icount_bench_hf32(s: &str) -> f32 { + black_box(hf32(s)) +} + +#[library_benchmark] +#[bench::short("0x12.34p+8")] +#[bench::max("0x1.fffffffffffffp+1023")] +fn icount_bench_hf64(s: &str) -> f64 { + black_box(hf64(s)) +} + +#[library_benchmark] +#[bench::short("0x12.34p+8")] +#[bench::max("0x1.ffffffffffffffffffffffffffffp+16383")] +fn icount_bench_hf128(s: &str) -> f128 { + black_box(hf128(s)) +} + +library_benchmark_group!( + name = icount_bench_hf_parse_group; + benchmarks = + icount_bench_hf16, + icount_bench_hf32, + icount_bench_hf64, + icount_bench_hf128 +); + +#[library_benchmark] +#[bench::short(1.015625)] +#[bench::max(f16::MAX)] +fn icount_bench_print_hf16(x: f16) -> String { + black_box(Hexf(x).to_string()) +} + +#[library_benchmark] +#[bench::short(1.015625)] +#[bench::max(f32::MAX)] +fn icount_bench_print_hf32(x: f32) -> String { + black_box(Hexf(x).to_string()) +} + +#[library_benchmark] +#[bench::short(1.015625)] +#[bench::max(f64::MAX)] +fn icount_bench_print_hf64(x: f64) -> String { + black_box(Hexf(x).to_string()) +} + +#[library_benchmark] +#[bench::short(1.015625)] +#[bench::max(f128::MAX)] +fn icount_bench_print_hf128(x: f128) -> String { + black_box(Hexf(x).to_string()) +} + +library_benchmark_group!( + name = icount_bench_hf_print_group; + benchmarks = + icount_bench_print_hf16, + icount_bench_print_hf32, + icount_bench_print_hf64, + icount_bench_print_hf128 ); main!( library_benchmark_groups = - // u256-related benchmarks - icount_bench_u128_widen_mul_group, - icount_bench_u256_add_group, - icount_bench_u256_shr_group, + // Benchmarks not related to public libm math + icount_bench_u128_group, + icount_bench_hf_parse_group, + icount_bench_hf_print_group, // verify-apilist-start // verify-sorted-start icount_bench_acos_group, From c136fb7734716a078cd82a7364245128923eb7e4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 04:10:03 +0000 Subject: [PATCH 16/39] Run `builtins-test-intrinsics` when possible Currently we only build this, but it is possible to run the binary. Change the CI script to do so here. --- .../builtins-test-intrinsics/src/main.rs | 6 ++-- library/compiler-builtins/ci/run.sh | 30 ++++++++++++------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index 96fe4a7385113..66744a0817fe3 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -13,6 +13,8 @@ #![no_std] #![no_main] +// Ensure this `compiler_builtins` gets used, rather than the version injected from the sysroot. +extern crate compiler_builtins; extern crate panic_handler; // SAFETY: no definitions, only used for linking @@ -652,14 +654,14 @@ fn something_with_a_dtor(f: &dyn Fn()) { #[unsafe(no_mangle)] #[cfg(not(thumb))] -fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { run(); 0 } #[unsafe(no_mangle)] #[cfg(thumb)] -pub fn _start() -> ! { +extern "C" fn _start() -> ! { run(); loop {} } diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index cf3f7dfda1da2..27b9686eac644 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -63,23 +63,33 @@ symcheck+=(-- build-and-check) "${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 "${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 --release -build_intrinsics_test() { - # symcheck also checks the results of builtins-test-intrinsics - "${symcheck[@]}" \ +run_intrinsics_test() { + args=( --target "$target" --verbose \ - --manifest-path builtins-test-intrinsics/Cargo.toml "$@" + --manifest-path builtins-test-intrinsics/Cargo.toml + ) + args+=( "$@" ) + + # symcheck also checks the results of builtins-test-intrinsics + "${symcheck[@]}" "${args[@]}" + + # FIXME: we get access violations on Windows, our entrypoint may need to + # be tweaked. + if [ "${BUILD_ONLY:-}" != "1" ] && ! [[ "$target" = *"windows"* ]]; then + cargo run "${args[@]}" + fi } # 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 +run_intrinsics_test +run_intrinsics_test --release +run_intrinsics_test --features c +run_intrinsics_test --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations -CARGO_PROFILE_DEV_LTO=true build_intrinsics_test -CARGO_PROFILE_RELEASE_LTO=true build_intrinsics_test --release +CARGO_PROFILE_DEV_LTO=true run_intrinsics_test +CARGO_PROFILE_RELEASE_LTO=true run_intrinsics_test --release # Test libm From 3464b4b231e3e4a09e102696228fe950eb1672e5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 19:01:03 +0000 Subject: [PATCH 17/39] ci: Allow concurrency outside of pull requests When multiple merges to `master` happen before a CI run completes, the in-progress job is getting canceled. Fix this by using the commit sha for the group key if a pull request number is not available, rather than `github.ref` (which is always `refs/head/master` after merge). This should prevent jobs running on previous commits from getting cancelled, while still ensuring there is only ever one active run per pull request. --- library/compiler-builtins/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 567ad1205a5d3..de433d8c74d52 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -5,7 +5,7 @@ on: concurrency: # Make sure that new pushes cancel running jobs - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true env: From 9f84e9904fd2be7e6b2c339b16ac9c2e5da8778b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 18:06:43 +0000 Subject: [PATCH 18/39] Increase the benchmark rustc version to 2025-05-28 We may soon want to use some new nightly features in `compiler-builtins` and `libm`, specifically `cfg_target_has_reliable_f16_f128` which was added in the past few weeks. This will mean we need a newer toolchain for benchmarks to continue building. Bump to the current latest nightly so we are not blocked on this down the line. --- library/compiler-builtins/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index de433d8c74d52..8e89cb4729242 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -13,7 +13,7 @@ env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full - BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results + BENCHMARK_RUSTC: nightly-2025-05-28 # Pin the toolchain for reproducable results jobs: # Determine which tests should be run based on changed files. From 8edaa6e5c88e14df20b095016514d381c697e49a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 20:53:48 +0000 Subject: [PATCH 19/39] libm-test: Make `extensive` an attribute rather than a test type Currently we run logspace tests for extensive tests, but there isn't any reason we couldn't also run more kinds of tests more extensively (e.g. more edge cases, combine edge cases with logspace for multi-input functions, etc). As a first step toward making this possible, make `extensive` a new field in `CheckCtx`, and rename `QuickSpaced` to `Spaced`. --- .../libm-test/benches/icount.rs | 2 +- .../libm-test/examples/plot_domains.rs | 2 +- .../libm-test/src/run_cfg.rs | 74 ++++++++++++++----- .../libm-test/tests/compare_built_musl.rs | 2 +- .../libm-test/tests/multiprecision.rs | 2 +- .../libm-test/tests/z_extensive/run.rs | 3 +- 6 files changed, 60 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index 4bebbc41ccd87..a0928a29f9992 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -23,7 +23,7 @@ macro_rules! icount_benches { let mut ctx = CheckCtx::new( Op::IDENTIFIER, CheckBasis::None, - GeneratorKind::QuickSpaced + GeneratorKind::Spaced ); ctx.override_iterations(BENCH_ITER_ITEMS); let ret = spaced::get_test_cases::(&ctx).0.collect::>(); diff --git a/library/compiler-builtins/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm-test/examples/plot_domains.rs index 3563103b8cd7c..7331d454f2111 100644 --- a/library/compiler-builtins/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm-test/examples/plot_domains.rs @@ -55,7 +55,7 @@ where Op: MathOp, Op::RustArgs: SpacedInput, { - let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); + let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::Spaced); plot_one_generator( out_dir, &ctx, diff --git a/library/compiler-builtins/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs index 3345a01d2de79..90f81195c8560 100644 --- a/library/compiler-builtins/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm-test/src/run_cfg.rs @@ -22,13 +22,38 @@ static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { /// 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)] = &[ - (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 50), - (Identifier::Fmodf128, GeneratorKind::Extensive, 50), +const EXTREMELY_SLOW_TESTS: &[SlowTest] = &[ + SlowTest { + ident: Identifier::Fmodf128, + gen_kind: GeneratorKind::Spaced, + extensive: false, + reduce_factor: 50, + }, + SlowTest { + ident: Identifier::Fmodf128, + gen_kind: GeneratorKind::Spaced, + extensive: true, + reduce_factor: 50, + }, ]; +/// A pattern to match a `CheckCtx`, plus a factor to reduce by. +struct SlowTest { + ident: Identifier, + gen_kind: GeneratorKind, + extensive: bool, + reduce_factor: u64, +} + +impl SlowTest { + /// True if the test in `CheckCtx` should be reduced by `reduce_factor`. + fn matches_ctx(&self, ctx: &CheckCtx) -> bool { + self.ident == ctx.fn_ident + && self.gen_kind == ctx.gen_kind + && self.extensive == ctx.extensive + } +} + /// 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 @@ -54,6 +79,7 @@ pub struct CheckCtx { /// Source of truth for tests. pub basis: CheckBasis, pub gen_kind: GeneratorKind, + pub extensive: bool, /// If specified, this value will override the value returned by [`iteration_count`]. pub override_iterations: Option, } @@ -69,12 +95,19 @@ impl CheckCtx { base_name_str: fn_ident.base_name().as_str(), basis, gen_kind, + extensive: false, override_iterations: None, }; ret.ulp = crate::default_ulp(&ret); ret } + /// Configure that this is an extensive test. + pub fn extensive(mut self, extensive: bool) -> Self { + self.extensive = extensive; + self + } + /// The number of input arguments for this function. pub fn input_count(&self) -> usize { self.fn_ident.math_op().rust_sig.args.len() @@ -100,14 +133,17 @@ pub enum CheckBasis { /// and quantity. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum GeneratorKind { + /// Extremes, zeros, nonstandard numbers, etc. EdgeCases, - Extensive, - QuickSpaced, + /// Spaced by logarithm (floats) or linear (integers). + Spaced, + /// Test inputs from an RNG. Random, + /// A provided test case list. List, } -/// A list of all functions that should get extensive tests. +/// A list of all functions that should get extensive tests, as configured by environment variable. /// /// 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. @@ -216,17 +252,17 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let random_iter_count = domain_iter_count / 100; let mut total_iterations = match ctx.gen_kind { - GeneratorKind::QuickSpaced => domain_iter_count, + GeneratorKind::Spaced if ctx.extensive => extensive_max_iterations(), + GeneratorKind::Spaced => domain_iter_count, GeneratorKind::Random => random_iter_count, - GeneratorKind::Extensive => extensive_max_iterations(), GeneratorKind::EdgeCases | GeneratorKind::List => { unimplemented!("shoudn't need `iteration_count` for {:?}", ctx.gen_kind) } }; // Larger float types get more iterations. - if t_env.large_float_ty && ctx.gen_kind != GeneratorKind::Extensive { - if ctx.gen_kind == GeneratorKind::Extensive { + if t_env.large_float_ty { + if ctx.extensive { // Extensive already has a pretty high test count. total_iterations *= 2; } else { @@ -244,13 +280,13 @@ 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 + if let Some(slow) = EXTREMELY_SLOW_TESTS .iter() - .find(|(id, generator, _scale)| *id == ctx.fn_ident && *generator == ctx.gen_kind) + .find(|slow| slow.matches_ctx(ctx)) { // 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; + if !(ctx.extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) { + total_iterations /= slow.reduce_factor; } } @@ -279,7 +315,7 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let total = ntests.pow(t_env.input_count.try_into().unwrap()); let seed_msg = match ctx.gen_kind { - GeneratorKind::QuickSpaced | GeneratorKind::Extensive => String::new(), + GeneratorKind::Spaced => String::new(), GeneratorKind::Random => { format!( " using `{SEED_ENV}={}`", @@ -327,8 +363,8 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { let extensive_range = (-0xfff)..=0xfffff; match ctx.gen_kind { - GeneratorKind::Extensive => extensive_range, - GeneratorKind::QuickSpaced | GeneratorKind::Random => non_extensive_range, + _ if ctx.extensive => extensive_range, + GeneratorKind::Spaced | GeneratorKind::Random => non_extensive_range, GeneratorKind::EdgeCases => extensive_range, GeneratorKind::List => unimplemented!("shoudn't need range for {:?}", ctx.gen_kind), } 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 6ccbb6f4c51d5..86f3b8b711ea7 100644 --- a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs @@ -65,7 +65,7 @@ macro_rules! musl_tests { $(#[$attr])* fn [< musl_quickspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Spaced); let cases = spaced::get_test_cases::(&ctx).0; musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } diff --git a/library/compiler-builtins/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm-test/tests/multiprecision.rs index 80b2c78688ea7..60175ae615693 100644 --- a/library/compiler-builtins/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm-test/tests/multiprecision.rs @@ -55,7 +55,7 @@ macro_rules! mp_tests { $(#[$attr])* fn [< mp_quickspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Spaced); let cases = spaced::get_test_cases::(&ctx).0; mp_runner::(&ctx, cases); } 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 59c806ce73e24..f2ba6a4a0e3e6 100644 --- a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs @@ -17,7 +17,6 @@ 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() { @@ -77,7 +76,7 @@ where Op::RustArgs: SpacedInput + Send, { let test_name = format!("mp_extensive_{}", Op::NAME); - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GEN_KIND); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Spaced).extensive(true); let skip = skip_extensive_test(&ctx); let runner = move || { From 4d325e8b2cca0139370a809a76183a880db52b24 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 21:22:47 +0000 Subject: [PATCH 20/39] ci: Allow for multiple icount benchmarks in the same run We don't actually need this for now, but eventually it would be nice to run icount benchmarks on multiple targets. Start tagging artifact names with the architecture, and allow passing `--tag` to `ci-util.py` in order to retrieve the correct one. --- .../.github/workflows/main.yaml | 12 ++++++++++-- library/compiler-builtins/ci/bench-icount.sh | 16 ++++++++++++++-- library/compiler-builtins/ci/ci-util.py | 17 +++++++++++++---- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 8e89cb4729242..9f389d8b48579 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -195,8 +195,14 @@ jobs: benchmarks: name: Benchmarks - runs-on: ubuntu-24.04 timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-24.04 + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@master with: @@ -215,12 +221,14 @@ jobs: cargo binstall -y iai-callgrind-runner --version "$iai_version" sudo apt-get install valgrind - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} - name: Run icount benchmarks env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} - run: ./ci/bench-icount.sh + run: ./ci/bench-icount.sh ${{ matrix.target }} - name: Upload the benchmark baseline uses: actions/upload-artifact@v4 diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index 4d93e257a6cb0..5b6974fe42048 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -2,10 +2,21 @@ set -eux +target="${1:-}" + +if [ -z "$target" ]; then + host_target=$(rustc -vV | awk '/^host/ { print $2 }') + echo "Defaulted to host target $host_target" + target="$host_target" +fi + iai_home="iai-home" +# Use the arch as a tag to disambiguate artifacts +tag="$(echo "$target" | cut -d'-' -f1)" + # Download the baseline from master -./ci/ci-util.py locate-baseline --download --extract +./ci/ci-util.py locate-baseline --download --extract --tag "$tag" # Run benchmarks once function run_icount_benchmarks() { @@ -44,6 +55,7 @@ function run_icount_benchmarks() { # 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 + # Disregard regressions after merge ./ci/ci-util.py check-regressions --home "$iai_home" || true fi } @@ -53,6 +65,6 @@ 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}" +name="baseline-icount-$tag-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" echo "BASELINE_NAME=$name" >>"$GITHUB_ENV" tar cJf "$name.tar.xz" "$iai_home" diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py index d785b2e9e1d80..6c8b439805b44 100755 --- a/library/compiler-builtins/ci/ci-util.py +++ b/library/compiler-builtins/ci/ci-util.py @@ -28,11 +28,14 @@ Calculate a matrix of which functions had source change, print that as a JSON object. - locate-baseline [--download] [--extract] + locate-baseline [--download] [--extract] [--tag TAG] 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. + `--tag` can be specified to look for artifacts with a specific tag, such as + for a specific architecture. + Note that `--extract` will overwrite files in `iai-home`. check-regressions [--home iai-home] [--allow-pr-override pr_number] @@ -50,7 +53,7 @@ GIT = ["git", "-C", REPO_ROOT] DEFAULT_BRANCH = "master" WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts -ARTIFACT_GLOB = "baseline-icount*" +ARTIFACT_PREFIX = "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 @@ -278,6 +281,7 @@ def locate_baseline(flags: list[str]) -> None: download = False extract = False + tag = "" while len(flags) > 0: match flags[0]: @@ -285,6 +289,9 @@ def locate_baseline(flags: list[str]) -> None: download = True case "--extract": extract = True + case "--tag": + tag = flags[1] + flags = flags[1:] case _: eprint(USAGE) exit(1) @@ -333,8 +340,10 @@ def locate_baseline(flags: list[str]) -> None: eprint("skipping download step") return + artifact_glob = f"{ARTIFACT_PREFIX}{f"-{tag}" if tag else ""}*" + sp.run( - ["gh", "run", "download", str(job_id), f"--pattern={ARTIFACT_GLOB}"], + ["gh", "run", "download", str(job_id), f"--pattern={artifact_glob}"], check=False, ) @@ -344,7 +353,7 @@ def locate_baseline(flags: list[str]) -> None: # 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}") + candidate_baselines = glob(f"{artifact_glob}/{artifact_glob}") if len(candidate_baselines) == 0: eprint("no possible baseline directories found") return From 14db1b5b1c2b55dfa89c7b958e70efb936a33e7c Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 28 May 2025 21:22:21 +0000 Subject: [PATCH 21/39] jsondocck: command -> directive --- src/tools/jsondocck/src/config.rs | 2 +- src/tools/jsondocck/src/directive.rs | 44 +++++++++++++++------------- src/tools/jsondocck/src/error.rs | 4 +-- src/tools/jsondocck/src/main.rs | 30 +++++++++---------- 4 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/tools/jsondocck/src/config.rs b/src/tools/jsondocck/src/config.rs index 9b3ba3f3fbe39..6bef37c225973 100644 --- a/src/tools/jsondocck/src/config.rs +++ b/src/tools/jsondocck/src/config.rs @@ -4,7 +4,7 @@ use getopts::Options; pub struct Config { /// The directory documentation output was generated in pub doc_dir: String, - /// The file documentation was generated for, with docck commands to check + /// The file documentation was generated for, with docck directives to check pub template: String, } diff --git a/src/tools/jsondocck/src/directive.rs b/src/tools/jsondocck/src/directive.rs index 8617379ed270b..5269ffb469fa9 100644 --- a/src/tools/jsondocck/src/directive.rs +++ b/src/tools/jsondocck/src/directive.rs @@ -1,16 +1,18 @@ use std::borrow::Cow; + use serde_json::Value; + use crate::cache::Cache; #[derive(Debug)] -pub struct Command { - pub kind: CommandKind, +pub struct Directive { + pub kind: DirectiveKind, pub path: String, pub lineno: usize, } #[derive(Debug)] -pub enum CommandKind { +pub enum DirectiveKind { /// `//@ has ` /// /// Checks the path exists. @@ -55,16 +57,16 @@ pub enum CommandKind { Set { variable: String }, } -impl CommandKind { +impl DirectiveKind { /// Returns both the kind and the path. /// - /// Returns `None` if the command isn't from jsondocck (e.g. from compiletest). + /// Returns `None` if the directive isn't from jsondocck (e.g. from compiletest). pub fn parse<'a>( - command_name: &str, + directive_name: &str, negated: bool, args: &'a [String], ) -> Option<(Self, &'a str)> { - let kind = match (command_name, negated) { + let kind = match (directive_name, negated) { ("count", false) => { assert_eq!(args.len(), 2); let expected = args[1].parse().expect("invalid number for `count`"); @@ -104,11 +106,11 @@ impl CommandKind { _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"), }, - (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&command_name) => { + (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&directive_name) => { return None; } _ => { - panic!("Invalid command `//@ {}{command_name}`", if negated { "!" } else { "" }) + panic!("Invalid directive `//@ {}{directive_name}`", if negated { "!" } else { "" }) } }; @@ -116,22 +118,22 @@ impl CommandKind { } } -impl Command { - /// Performs the actual work of ensuring a command passes. +impl Directive { + /// Performs the actual work of ensuring a directive passes. pub fn check(&self, cache: &mut Cache) -> Result<(), String> { let matches = cache.select(&self.path); match &self.kind { - CommandKind::HasPath => { + DirectiveKind::HasPath => { if matches.is_empty() { return Err("matched to no values".to_owned()); } } - CommandKind::HasNotPath => { + DirectiveKind::HasNotPath => { if !matches.is_empty() { return Err(format!("matched to {matches:?}, but wanted no matches")); } } - CommandKind::HasValue { value } => { + DirectiveKind::HasValue { value } => { let want_value = string_to_value(value, cache); if !matches.contains(&want_value.as_ref()) { return Err(format!( @@ -139,7 +141,7 @@ impl Command { )); } } - CommandKind::HasNotValue { value } => { + DirectiveKind::HasNotValue { value } => { let wantnt_value = string_to_value(value, cache); if matches.contains(&wantnt_value.as_ref()) { return Err(format!( @@ -152,14 +154,14 @@ impl Command { } } - CommandKind::Is { value } => { + DirectiveKind::Is { value } => { let want_value = string_to_value(value, cache); let matched = get_one(&matches)?; if matched != want_value.as_ref() { return Err(format!("matched to {matched:?} but want {want_value:?}")); } } - CommandKind::IsNot { value } => { + DirectiveKind::IsNot { value } => { let wantnt_value = string_to_value(value, cache); let matched = get_one(&matches)?; if matched == wantnt_value.as_ref() { @@ -167,7 +169,7 @@ impl Command { } } - CommandKind::IsMany { values } => { + DirectiveKind::IsMany { values } => { // Serde json doesn't implement Ord or Hash for Value, so we must // use a Vec here. While in theory that makes setwize equality // O(n^2), in practice n will never be large enough to matter. @@ -187,7 +189,7 @@ impl Command { } } } - CommandKind::CountIs { expected } => { + DirectiveKind::CountIs { expected } => { if *expected != matches.len() { return Err(format!( "matched to `{matches:?}` with length {}, but expected length {expected}", @@ -195,7 +197,7 @@ impl Command { )); } } - CommandKind::Set { variable } => { + DirectiveKind::Set { variable } => { let value = get_one(&matches)?; let r = cache.variables.insert(variable.to_owned(), value.clone()); assert!(r.is_none(), "name collision: {variable:?} is duplicated"); @@ -227,4 +229,4 @@ fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { } else { Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s))) } -} \ No newline at end of file +} diff --git a/src/tools/jsondocck/src/error.rs b/src/tools/jsondocck/src/error.rs index 0a3e085b405ba..eb2932f780323 100644 --- a/src/tools/jsondocck/src/error.rs +++ b/src/tools/jsondocck/src/error.rs @@ -1,7 +1,7 @@ -use crate::Command; +use crate::Directive; #[derive(Debug)] pub struct CkError { pub message: String, - pub command: Command, + pub directive: Directive, } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 80557b682430c..d84be4d3a3a6f 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -11,7 +11,7 @@ mod error; use cache::Cache; use config::parse_config; -use directive::{Command, CommandKind}; +use directive::{Directive, DirectiveKind}; use error::CkError; fn main() -> ExitCode { @@ -19,14 +19,14 @@ fn main() -> ExitCode { let mut failed = Vec::new(); let mut cache = Cache::new(&config); - let Ok(commands) = get_commands(&config.template) else { + let Ok(directives) = get_directives(&config.template) else { eprintln!("Jsondocck failed for {}", &config.template); return ExitCode::FAILURE; }; - for command in commands { - if let Err(message) = command.check( &mut cache) { - failed.push(CkError { command, message }); + for directive in directives { + if let Err(message) = directive.check(&mut cache) { + failed.push(CkError { directive, message }); } } @@ -34,7 +34,7 @@ fn main() -> ExitCode { ExitCode::SUCCESS } else { for i in failed { - eprintln!("{}:{}, command failed", config.template, i.command.lineno); + eprintln!("{}:{}, directive failed", config.template, i.directive.lineno); eprintln!("{}", i.message) } ExitCode::FAILURE @@ -47,7 +47,7 @@ static LINE_PATTERN: LazyLock = LazyLock::new(|| { ^\s* //@\s+ (?P!?) - (?P[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*) + (?P[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*) (?P.*)$ "#, ) @@ -70,12 +70,12 @@ static DEPRECATED_LINE_PATTERN: LazyLock = LazyLock::new(|| { }); fn print_err(msg: &str, lineno: usize) { - eprintln!("Invalid command: {} on line {}", msg, lineno) + eprintln!("Invalid directive: {} on line {}", msg, lineno) } -/// Get a list of commands from a file. -fn get_commands(template: &str) -> Result, ()> { - let mut commands = Vec::new(); +/// Get a list of directives from a file. +fn get_directives(template: &str) -> Result, ()> { + let mut directives = Vec::new(); let mut errors = false; let file = fs::read_to_string(template).unwrap(); @@ -83,7 +83,7 @@ fn get_commands(template: &str) -> Result, ()> { let lineno = lineno + 1; if DEPRECATED_LINE_PATTERN.is_match(line) { - print_err("Deprecated command syntax, replace `// @` with `//@ `", lineno); + print_err("Deprecated directive syntax, replace `// @` with `//@ `", lineno); errors = true; continue; } @@ -101,10 +101,10 @@ fn get_commands(template: &str) -> Result, ()> { continue; }; - if let Some((kind, path)) = CommandKind::parse(&cap["cmd"], negated, &args) { - commands.push(Command { kind, lineno, path: path.to_owned() }) + if let Some((kind, path)) = DirectiveKind::parse(&cap["directive"], negated, &args) { + directives.push(Directive { kind, lineno, path: path.to_owned() }) } } - if !errors { Ok(commands) } else { Err(()) } + if !errors { Ok(directives) } else { Err(()) } } From 3c35505fe9c1a0f2c15c780709ed9812f8a332f0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 22:08:24 +0000 Subject: [PATCH 22/39] chore: release --- .../compiler-builtins/CHANGELOG.md | 15 +++++++++++++++ .../compiler-builtins/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index a7c01c463ca68..880e56c443e3e 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.160](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.159...compiler_builtins-v0.1.160) - 2025-05-29 + +### Other + +- Change `compiler-builtins` to edition 2024 +- Remove unneeded C symbols +- Reuse `libm`'s `Caat` and `CastFrom` in `compiler-builtins` +- Reuse `MinInt` and `Int` from `libm` in `compiler-builtins` +- Update `CmpResult` to use a pointer-sized return type +- Enable `__powitf2` on MSVC +- Fix `i256::MAX` +- Add a note saying why we use `frintx` rather than `frintn` +- Typo in README.md +- Clean up unused files + ## [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 diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 93eb3e01b3b8a..8ceef286f57e4 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.159" +version = "0.1.160" 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 c6df6a72d8f2463985b6b130673536e6d4cc7cbf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 1 Jun 2025 19:41:03 +0000 Subject: [PATCH 23/39] Fix new `dead_code` warnings from recent nightlies --- .../libm/src/math/support/float_traits.rs | 1 + .../libm/src/math/support/hex_float.rs | 207 +++++++++--------- .../libm/src/math/support/int_traits.rs | 1 + .../libm/src/math/support/macros.rs | 6 +- .../libm/src/math/support/mod.rs | 4 +- 5 files changed, 116 insertions(+), 103 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 4c866ef10bdd7..dd9f46209c11d 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -6,6 +6,7 @@ use super::int_traits::{CastFrom, Int, MinInt}; /// Trait for some basic operations on floats // #[allow(dead_code)] +#[allow(dead_code)] // Some constants are only used with tests pub trait Float: Copy + fmt::Debug 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 85569d98aef48..c8558b90053d1 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -1,8 +1,6 @@ //! Utilities for working with hex float formats. -use core::fmt; - -use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; +use super::{Round, Status, f32_from_bits, f64_from_bits}; /// Construct a 16-bit float from hex float representation (C-style) #[cfg(f16_enabled)] @@ -352,133 +350,143 @@ 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); +#[cfg(any(test, feature = "unstable-public-internals"))] +mod hex_fmt { + use core::fmt; -// 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, "-")?; - } + use crate::support::Float; - 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"); - } + /// Format a floating point number as its IEEE hex (`%a`) representation. + pub struct Hexf(pub F); - 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." - }; + // Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs + #[cfg(not(feature = "compiler-builtins"))] + pub(super) fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if x.is_sign_negative() { + write!(f, "-")?; + } - write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") -} + 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"); + } -#[cfg(feature = "compiler-builtins")] -fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() -} + 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." + }; -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt_any_hex(&self.0, f) + write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") + } + + #[cfg(feature = "compiler-builtins")] + pub(super) fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() + } + + impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt_any_hex(&self.0, f) + } } } } -} -impl fmt::LowerHex for Hexf<(F, F)> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + impl fmt::LowerHex for Hexf<(F, F)> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } } } } -} -impl fmt::LowerHex for Hexf<(F, i32)> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + impl fmt::LowerHex for Hexf<(F, i32)> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } } } } -} -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(&self.0, f) + impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(&self.0, f) + } } } } -} -impl fmt::Debug for Hexf -where - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) + impl fmt::Debug for Hexf + where + Hexf: fmt::LowerHex, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } } } } -} -impl fmt::Display for Hexf -where - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) + impl fmt::Display for Hexf + where + Hexf: fmt::LowerHex, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } } } } } +#[cfg(any(test, feature = "unstable-public-internals"))] +pub use hex_fmt::*; + #[cfg(test)] mod parse_tests { extern crate std; @@ -1064,6 +1072,7 @@ mod print_tests { use std::string::ToString; use super::*; + use crate::support::Float; #[test] #[cfg(f16_enabled)] 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 716af748a9fb8..9b29e2f4561d5 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -1,6 +1,7 @@ use core::{cmp, fmt, ops}; /// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] // Some constants are only used with tests pub trait MinInt: Copy + fmt::Debug diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 0b72db0e46e8b..2b8fd580a50e5 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -137,12 +137,12 @@ 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 = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value + // hack to get width from a value + let bits = $crate::support::Int::leading_zeros(l.to_bits() - l.to_bits()); assert!( - l.biteq(r), + $crate::support::Float::biteq(l, r), "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", format_args!($($tt)*), lb = l.to_bits(), diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 2771cfd32c8b5..2e7edd03c421e 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -17,6 +17,8 @@ pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; +#[cfg(any(test, feature = "unstable-public-internals"))] +pub use hex_float::Hexf; #[cfg(f16_enabled)] #[allow(unused_imports)] pub use hex_float::hf16; @@ -24,7 +26,7 @@ pub use hex_float::hf16; #[allow(unused_imports)] pub use hex_float::hf128; #[allow(unused_imports)] -pub use hex_float::{Hexf, hf32, hf64}; +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. From 0a7e59265a3432d6544b35d93120b66f45a67159 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 1 Jun 2025 19:22:42 +0000 Subject: [PATCH 24/39] Upgrade all dependencies to the latest available version In particular, this includes a fix to `iai-callgrind` that will allow us to simplify our benchmark runner. --- library/compiler-builtins/builtins-test/Cargo.toml | 8 ++++---- .../compiler-builtins/compiler-builtins/Cargo.toml | 4 ++-- .../crates/libm-macros/Cargo.toml | 4 ++-- .../crates/musl-math-sys/Cargo.toml | 2 +- library/compiler-builtins/libm-test/Cargo.toml | 14 +++++++------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 10978c0bb7ed0..c7742aa24275f 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -10,11 +10,11 @@ license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" # 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.6" +rand_xoshiro = "0.7" # To compare float builtins against -rustc_apfloat = "0.2.1" +rustc_apfloat = "0.2.2" # Really a dev dependency, but dev dependencies can't be optional -iai-callgrind = { version = "0.14.0", optional = true } +iai-callgrind = { version = "0.14.1", optional = true } [dependencies.compiler_builtins] path = "../compiler-builtins" @@ -22,7 +22,7 @@ default-features = false features = ["unstable-public-internals"] [dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +criterion = { version = "0.6.0", 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] diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 8ceef286f57e4..6bee8da68a0a2 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -19,10 +19,10 @@ 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.1", optional = true, package = "rustc-std-workspace-core" } [build-dependencies] -cc = { optional = true, version = "1.0" } +cc = { optional = true, version = "1.2" } [dev-dependencies] panic-handler = { path = "../crates/panic-handler" } diff --git a/library/compiler-builtins/crates/libm-macros/Cargo.toml b/library/compiler-builtins/crates/libm-macros/Cargo.toml index 3929854f08e65..6bbf47784ff91 100644 --- a/library/compiler-builtins/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/crates/libm-macros/Cargo.toml @@ -10,9 +10,9 @@ proc-macro = true [dependencies] heck = "0.5.0" -proc-macro2 = "1.0.94" +proc-macro2 = "1.0.95" quote = "1.0.40" -syn = { version = "2.0.100", features = ["full", "extra-traits", "visit-mut"] } +syn = { version = "2.0.101", features = ["full", "extra-traits", "visit-mut"] } [lints.rust] # Values used during testing diff --git a/library/compiler-builtins/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml index d3fb147e526aa..3b88117343b62 100644 --- a/library/compiler-builtins/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml @@ -11,4 +11,4 @@ license = "MIT OR Apache-2.0" libm = { path = "../../libm" } [build-dependencies] -cc = "1.2.16" +cc = "1.2.25" diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 7a306e735577e..01b45716b7a21 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -28,28 +28,28 @@ icount = ["dep:iai-callgrind"] short-benchmarks = [] [dependencies] -anyhow = "1.0.97" +anyhow = "1.0.98" # 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 } +gmp-mpfr-sys = { version = "1.6.5", optional = true, default-features = false } +iai-callgrind = { version = "0.14.1", optional = true } indicatif = { version = "0.17.11", default-features = false } 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 = "0.9.1" 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"] } +getrandom = { version = "0.3.3", features = ["wasm_js"] } [build-dependencies] -rand = { version = "0.9.0", optional = true } +rand = { version = "0.9.1", optional = true } [dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +criterion = { version = "0.6.0", default-features = false, features = ["cargo_bench_support"] } libtest-mimic = "0.8.1" [[bench]] From e83ca863412a950f19fbc4e8fc632f19107dd0a2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 2 Jun 2025 16:10:49 +0000 Subject: [PATCH 25/39] cleanup: Use `x.biteq(y)` rather than `x.to_bits() == y.to_bits()` --- library/compiler-builtins/libm-test/src/precision.rs | 2 +- .../compiler-builtins/libm-test/src/test_traits.rs | 5 +---- .../libm/src/math/generic/fmaximum.rs | 2 +- .../libm/src/math/generic/fmaximum_num.rs | 11 +++++------ .../libm/src/math/generic/fminimum.rs | 2 +- .../libm/src/math/generic/fminimum_num.rs | 11 +++++------ 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index f5fb5f6707b08..f6cdd015a593c 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -381,7 +381,7 @@ fn unop_common( } // abs and copysign require signaling NaNs to be propagated, so verify bit equality. - if actual.to_bits() == expected.to_bits() { + if actual.biteq(expected) { return CheckAction::Custom(Ok(())); } else { return CheckAction::Custom(Err(anyhow::anyhow!("NaNs have different bitpatterns"))); diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index dbb97016153c7..2af6af60ba270 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -328,10 +328,7 @@ 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.biteq(expected), "mismatched NaN bitpatterns"); } // By default, NaNs have nothing special to check. return Ok(()); diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index 4b6295bc0c6bc..898828b80c7ff 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -17,7 +17,7 @@ pub fn fmaximum(x: F, y: F) -> F { x } else if y.is_nan() { y - } else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) { + } else if x > y || (y.biteq(F::NEG_ZERO) && x.is_sign_positive()) { x } else { y 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 2e97ff6d36905..05df6cbd4643e 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -15,12 +15,11 @@ use crate::support::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()) { - y - } else { - x - }; + let res = if x.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { + y + } else { + x + }; // Canonicalize res * F::ONE diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index 9dc0b64be3f2c..8592ac5460ef0 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -17,7 +17,7 @@ pub fn fminimum(x: F, y: F) -> F { x } else if y.is_nan() { y - } else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + } else if x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { x } else { y 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 40db8b18957bc..6777bbf87721b 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -15,12 +15,11 @@ use crate::support::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()) { - x - } else { - y - }; + let res = if y.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { + x + } else { + y + }; // Canonicalize res * F::ONE From ba7cdb681468ef7617bfa5a2bde7e3fb3d79a2be Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 1 Jun 2025 19:52:57 +0000 Subject: [PATCH 26/39] ci: Refactor benchmark regression checks iai-callgrind now correctly exits with error if regressions were found [1], so we no longer need to check for regressions manually. Remove this check and instead exit based on the exit status of the benchmark run. [1] https://github.com/iai-callgrind/iai-callgrind/issues/337 --- library/compiler-builtins/ci/bench-icount.sh | 19 ++--- library/compiler-builtins/ci/ci-util.py | 84 +++++--------------- 2 files changed, 29 insertions(+), 74 deletions(-) diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index 5b6974fe42048..5724955fe3672 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -46,17 +46,18 @@ function run_icount_benchmarks() { shift done - # Run iai-callgrind benchmarks - cargo bench "${cargo_args[@]}" -- "${iai_args[@]}" + # Run iai-callgrind benchmarks. Do this in a subshell with `&& true` to + # capture rather than exit on error. + (cargo bench "${cargo_args[@]}" -- "${iai_args[@]}") && true + exit_code="$?" - # 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 - 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 + if [ "$exit_code" -eq 0 ]; then + echo "Benchmarks completed with no regressions" + elif [ -z "${PR_NUMBER:-}" ]; then # Disregard regressions after merge - ./ci/ci-util.py check-regressions --home "$iai_home" || true + echo "Benchmarks completed with regressions; ignoring (not in a PR)" + else + ./ci/ci-util.py handle-banch-regressions "$PR_NUMBER" fi } diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py index 6c8b439805b44..3437d304f48c5 100755 --- a/library/compiler-builtins/ci/ci-util.py +++ b/library/compiler-builtins/ci/ci-util.py @@ -11,7 +11,7 @@ import subprocess as sp import sys from dataclasses import dataclass -from glob import glob, iglob +from glob import glob from inspect import cleandoc from os import getenv from pathlib import Path @@ -38,14 +38,10 @@ Note that `--extract` will overwrite files in `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`. + handle-bench-regressions PR_NUMBER + Exit with success if the pull request contains a line starting with + `ci: allow-regressions`, indicating that regressions in benchmarks should + be accepted. Otherwise, exit 1. """ ) @@ -365,64 +361,22 @@ def locate_baseline(flags: list[str]) -> None: eprint("baseline extracted successfully") -def check_iai_regressions(args: list[str]): - """Find regressions in iai summary.json files, exit with failure if any are - found. - """ - - iai_home_str = "iai-home" - pr_number = None - - while len(args) > 0: - match args: - case ["--home", home, *rest]: - iai_home_str = 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_str) - - found_summaries = False - 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: - summary = json.load(f) - - summary_regs = [] - run = summary["callgrind_summary"]["callgrind_run"] - fname = summary["function_name"] - id = summary["id"] - name_entry = {"name": f"{fname}.{id}"} - - for segment in run["segments"]: - summary_regs.extend(segment["regressions"]) +def handle_bench_regressions(args: list[str]): + """Exit with error unless the PR message contains an ignore directive.""" - 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) + match args: + case [pr_number]: + pr_number = pr_number + case _: + eprint(USAGE) + exit(1) - if len(regressions) == 0: - eprint("No regressions found") + pr = PrInfo.load(pr_number) + if pr.contains_directive(REGRESSION_DIRECTIVE): + eprint("PR allows regressions") return - eprint("Found regressions:", json.dumps(regressions, indent=4)) - - if pr_number is not None: - pr = PrInfo.load(pr_number) - if pr.contains_directive(REGRESSION_DIRECTIVE): - eprint("PR allows regressions, returning") - return - + eprint("Regressions were found; benchmark failed") exit(1) @@ -433,8 +387,8 @@ def main(): ctx.emit_workflow_output() case ["locate-baseline", *flags]: locate_baseline(flags) - case ["check-regressions", *args]: - check_iai_regressions(args) + case ["handle-bench-regressions", *args]: + handle_bench_regressions(args) case ["--help" | "-h"]: print(USAGE) exit() From 57786431746f495f4205e26ee1badd142a380fff Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 2 Jun 2025 20:20:23 +0000 Subject: [PATCH 27/39] libm-test: Fix unintentional skips in `binop_common` `binop_common` emits a `SKIP` that is intended to apply only to `copysign`, but is instead applying to all binary operators. Correct the general case but leave the currently-failing `maximum_num` tests as a FIXME, to be resolved separately in [1]. Also simplify skip logic and NaN checking, and add a few more `copysign` checks. [1]: https://github.com/rust-lang/compiler-builtins/pull/939 --- .../libm-test/src/generate/edge_cases.rs | 1 + .../libm-test/src/precision.rs | 15 +++++++++----- .../libm-test/src/test_traits.rs | 20 +++++++++++++------ .../libm/src/math/copysign.rs | 10 +++++++++- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs index 2fb0746388c15..4e4a782a16988 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -51,6 +51,7 @@ where // Check some special values that aren't included in the above ranges values.push(Op::FTy::NAN); + values.push(Op::FTy::NEG_NAN); values.extend(Op::FTy::consts().iter()); // Check around the maximum subnormal value diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index f6cdd015a593c..32825b15d4761 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -444,13 +444,18 @@ fn binop_common( expected: F2, ctx: &CheckCtx, ) -> 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 + // MPFR only has one NaN bitpattern; skip tests in cases where the first argument would take + // the sign of a NaN second argument. The default NaN checks cover other cases. + if ctx.base_name == BaseName::Copysign && ctx.basis == CheckBasis::Mpfr && input.1.is_nan() { + return SKIP; + } + + // FIXME(#939): this should not be skipped, there is a bug in our implementationi. + if ctx.base_name == BaseName::FmaximumNum + && ctx.basis == CheckBasis::Mpfr && ((input.0.is_nan() && actual.is_nan() && expected.is_nan()) || input.1.is_nan()) { - return SKIP; + return XFAIL_NOCHECK; } /* FIXME(#439): our fmin and fmax do not compare signed zeros */ diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index 2af6af60ba270..278274d917b35 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -312,12 +312,9 @@ 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 => (), + // Forbid overrides if the items came from an explicit list + _ if ctx.gen_kind == GeneratorKind::List => (), CheckAction::AssertSuccess => (), CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg), CheckAction::Custom(res) => return res, @@ -327,9 +324,20 @@ where // Check when both are NaNs if actual.is_nan() && expected.is_nan() { - if require_biteq && ctx.basis == CheckBasis::None { + // Don't assert NaN bitwise equality if: + // + // * Testing against MPFR (there is a single NaN representation) + // * Testing against Musl except for explicit tests (Musl does some NaN quieting) + // + // In these cases, just the check that actual and expected are both NaNs is + // sufficient. + let skip_nan_biteq = ctx.basis == CheckBasis::Mpfr + || (ctx.basis == CheckBasis::Musl && ctx.gen_kind != GeneratorKind::List); + + if !skip_nan_biteq { ensure!(actual.biteq(expected), "mismatched NaN bitpatterns"); } + // By default, NaNs have nothing special to check. return Ok(()); } else if actual.is_nan() || expected.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index d2a86e7fd545f..d093d61072732 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -59,9 +59,17 @@ mod tests { // 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::ONE), F::NAN); + assert_biteq!(f(F::NAN, F::NEG_ONE), F::NEG_NAN); assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN); + assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NEG_NAN, F::ONE), F::NAN); + assert_biteq!(f(F::NEG_NAN, F::NEG_ONE), F::NEG_NAN); assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN); + assert_biteq!(f(F::ONE, F::NAN), F::ONE); + assert_biteq!(f(F::ONE, F::NEG_NAN), F::NEG_ONE); + assert_biteq!(f(F::NEG_ONE, F::NAN), F::ONE); + assert_biteq!(f(F::NEG_ONE, F::NEG_NAN), F::NEG_ONE); } #[test] From 763663ad56672b0f0635ad25c0c1a52e7773e0b9 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Tue, 3 Jun 2025 21:17:33 +0000 Subject: [PATCH 28/39] rustdoc-json-type: Depend on `serde` and `serde_derive` seperately Before this commit, serde_derive is built before serde. But serde does not depend on serde_derive, so that is not needed. Instead, build serde and serde_derive in parallel. This speeds up compilation for users depending on rustdoc-json-types out of tree. Imports: https://www.github.com/rust-lang/rustdoc-types/pull/49 Co-authored-by: Martin Nordholts --- Cargo.lock | 1 + src/rustdoc-json-types/Cargo.toml | 3 ++- src/rustdoc-json-types/lib.rs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43f5f40925b66..164617c909fea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4673,6 +4673,7 @@ dependencies = [ "bincode", "rustc-hash 2.1.1", "serde", + "serde_derive", "serde_json", ] diff --git a/src/rustdoc-json-types/Cargo.toml b/src/rustdoc-json-types/Cargo.toml index 14ff1d0881639..a38d34ef0e7d9 100644 --- a/src/rustdoc-json-types/Cargo.toml +++ b/src/rustdoc-json-types/Cargo.toml @@ -10,7 +10,8 @@ path = "lib.rs" default = ["rustc-hash"] [dependencies] -serde = { version = "1.0", features = ["derive"] } +serde = "1.0" +serde_derive = "1.0" rustc-hash = { version = "2.0", optional = true } [dev-dependencies] diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index f1c375bd2fe1c..8a3ab6f864072 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -21,7 +21,7 @@ use std::path::PathBuf; #[cfg(feature = "rustc-hash")] use rustc_hash::FxHashMap as HashMap; -use serde::{Deserialize, Serialize}; +use serde_derive::{Deserialize, Serialize}; pub type FxHashMap = HashMap; // re-export for use in src/librustdoc From 28231d95fc43ca11e40e3d701c42881d0ca7314c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 4 Jun 2025 06:26:56 +0000 Subject: [PATCH 29/39] Replace some `Option` with `Span` and use DUMMY_SP instead of None --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 4 +-- compiler/rustc_borrowck/src/type_check/mod.rs | 22 +++++------- .../rustc_borrowck/src/universal_regions.rs | 8 ++--- compiler/rustc_codegen_cranelift/src/base.rs | 16 ++++----- .../src/intrinsics/llvm.rs | 2 +- .../src/intrinsics/llvm_aarch64.rs | 2 +- .../src/intrinsics/llvm_x86.rs | 2 +- .../src/intrinsics/mod.rs | 6 ++-- .../rustc_codegen_cranelift/src/main_shim.rs | 4 +-- compiler/rustc_codegen_cranelift/src/num.rs | 2 +- .../rustc_codegen_cranelift/src/unsize.rs | 2 +- compiler/rustc_codegen_ssa/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/common.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 9 ++--- compiler/rustc_codegen_ssa/src/size_of_val.rs | 3 +- .../rustc_const_eval/src/check_consts/ops.rs | 6 +--- .../src/check_consts/qualifs.rs | 4 +-- .../src/const_eval/machine.rs | 2 +- .../rustc_const_eval/src/interpret/operand.rs | 3 +- .../src/util/caller_location.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 2 +- .../rustc_hir_analysis/src/check/intrinsic.rs | 8 ++--- .../rustc_hir_analysis/src/check/wfcheck.rs | 20 +++++------ .../src/coherence/builtin.rs | 10 +++--- .../src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_hir_typeck/src/check.rs | 4 +-- compiler/rustc_hir_typeck/src/closure.rs | 6 ++-- compiler/rustc_hir_typeck/src/coercion.rs | 5 ++- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 6 ++-- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 5 ++- .../src/fn_ctxt/suggestions.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 8 ++--- compiler/rustc_hir_typeck/src/upvar.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 5 +-- compiler/rustc_middle/src/error.rs | 2 +- .../rustc_middle/src/middle/lang_items.rs | 2 +- compiler/rustc_middle/src/mir/statement.rs | 2 +- compiler/rustc_middle/src/ty/adjustment.rs | 4 +-- compiler/rustc_middle/src/ty/context.rs | 8 ++--- compiler/rustc_middle/src/ty/instance.rs | 6 ++-- compiler/rustc_middle/src/ty/sty.rs | 14 ++++---- .../src/builder/expr/as_rvalue.rs | 2 +- .../rustc_mir_build/src/builder/expr/into.rs | 2 +- .../src/builder/matches/test.rs | 4 +-- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/mod.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 7 ++-- compiler/rustc_mir_transform/src/coroutine.rs | 31 +++++++++-------- .../rustc_mir_transform/src/coroutine/drop.rs | 23 ++++++------- .../rustc_mir_transform/src/elaborate_drop.rs | 13 +++---- compiler/rustc_mir_transform/src/shim.rs | 2 +- .../src/shim/async_destructor_ctor.rs | 12 +++---- compiler/rustc_mir_transform/src/validate.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 4 +-- compiler/rustc_monomorphize/src/lib.rs | 2 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 8 ++--- .../src/error_reporting/infer/mod.rs | 4 +-- .../src/error_reporting/traits/call_kind.rs | 6 ++-- .../src/error_reporting/traits/suggestions.rs | 6 ++-- compiler/rustc_trait_selection/src/infer.rs | 8 ++--- .../src/traits/effects.rs | 4 +-- .../rustc_trait_selection/src/traits/misc.rs | 4 +-- .../src/traits/project.rs | 34 +++++++++++-------- .../src/traits/select/confirmation.rs | 28 ++++++++------- .../rustc_trait_selection/src/traits/wf.rs | 4 +-- compiler/rustc_ty_utils/src/abi.rs | 13 +++---- compiler/rustc_ty_utils/src/common_traits.rs | 3 +- .../rustc_ty_utils/src/structural_match.rs | 3 +- compiler/rustc_ty_utils/src/ty.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- src/tools/miri/src/shims/panic.rs | 2 +- .../lang-item-generic-requirements.rs | 3 +- .../lang-item-generic-requirements.stderr | 8 +++-- 77 files changed, 241 insertions(+), 243 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f41627e479ff2..ca110719a729f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -732,7 +732,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, args: Option<&'hir hir::GenericArgs<'hir>>, ) -> &'hir hir::Path<'hir> { - let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_id = self.tcx.require_lang_item(lang_item, span); let def_kind = self.tcx.def_kind(def_id); let res = Res::Def(def_kind, def_id); self.arena.alloc(hir::Path { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 3b7d31b1b13bd..e9c18d1761f9d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -263,7 +263,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // something that already has `Fn`-like bounds (or is a closure), so we can't // restrict anyways. } else { - let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); + let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, span); self.suggest_adding_bounds(&mut err, ty, copy_did, span); } @@ -1915,7 +1915,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let local_ty = self.body.local_decls[place.local].ty; let typeck_results = tcx.typeck(self.mir_def_id()); - let clone = tcx.require_lang_item(LangItem::Clone, Some(body.span)); + let clone = tcx.require_lang_item(LangItem::Clone, body.span); for expr in expr_finder.clones { if let hir::ExprKind::MethodCall(_, rcvr, _, span) = expr.kind && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 4f5baeff7c320..4f75dd7e99287 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -688,7 +688,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self.unsized_feature_enabled() { let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), + tcx.require_lang_item(LangItem::Sized, self.last_span), [place_ty], ); self.prove_trait_ref( @@ -1010,7 +1010,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let ty = place.ty(self.body, tcx).ty; let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Copy, Some(span)), + tcx.require_lang_item(LangItem::Copy, span), [ty], ); @@ -1025,11 +1025,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [ty]); self.prove_trait_ref( trait_ref, @@ -1041,11 +1038,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} Rvalue::ShallowInitBox(_operand, ty) => { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [*ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [*ty]); self.prove_trait_ref( trait_ref, @@ -1222,7 +1216,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let &ty = ty; let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)), + tcx.require_lang_item(LangItem::CoerceUnsized, span), [op.ty(self.body, tcx), ty], ); @@ -1811,7 +1805,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), + tcx.require_lang_item(LangItem::Copy, self.last_span), [place_ty.ty], ); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index c11e14d214c42..846299711be38 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -544,10 +544,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // (as it's created inside the body itself, not passed in from outside). if let DefiningTy::FnDef(def_id, _) = defining_ty { if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { - let va_list_did = self.infcx.tcx.require_lang_item( - LangItem::VaList, - Some(self.infcx.tcx.def_span(self.mir_def)), - ); + let va_list_did = self + .infcx + .tcx + .require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def)); let reg_vid = self .infcx diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 4617304105a5b..0b641ba64b7a4 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -380,7 +380,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicBoundsCheck, &[index, len, location], *unwind, - Some(source_info.span), + source_info.span, ); } AssertKind::MisalignedPointerDereference { ref required, ref found } => { @@ -393,7 +393,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicMisalignedPointerDereference, &[required, found, location], *unwind, - Some(source_info.span), + source_info.span, ); } AssertKind::NullPointerDereference => { @@ -404,7 +404,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicNullPointerDereference, &[location], *unwind, - Some(source_info.span), + source_info.span, ) } _ => { @@ -415,7 +415,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { msg.panic_function(), &[location], *unwind, - Some(source_info.span), + source_info.span, ); } } @@ -531,7 +531,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { ); } TerminatorKind::UnwindTerminate(reason) => { - codegen_unwind_terminate(fx, Some(source_info.span), *reason); + codegen_unwind_terminate(fx, source_info.span, *reason); } TerminatorKind::UnwindResume => { // FIXME implement unwinding @@ -1074,7 +1074,7 @@ pub(crate) fn codegen_operand<'tcx>( pub(crate) fn codegen_panic_nounwind<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, - span: Option, + span: Span, ) { let msg_ptr = fx.anonymous_str(msg_str); let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); @@ -1091,7 +1091,7 @@ pub(crate) fn codegen_panic_nounwind<'tcx>( pub(crate) fn codegen_unwind_terminate<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - span: Option, + span: Span, reason: UnwindTerminateReason, ) { codegen_panic_inner(fx, reason.lang_item(), &[], UnwindAction::Unreachable, span); @@ -1102,7 +1102,7 @@ fn codegen_panic_inner<'tcx>( lang_item: rustc_hir::LangItem, args: &[Value], _unwind: UnwindAction, - span: Option, + span: Span, ) { fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 2e02e85a997d5..99a5518d0b688 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -71,7 +71,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( 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); + crate::base::codegen_panic_nounwind(fx, &msg, span); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs index d22483cf17764..c22f2a7b8734a 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs @@ -512,7 +512,7 @@ pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( 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); + crate::base::codegen_panic_nounwind(fx, &msg, fx.mir.span); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 3d67913a8fff1..615f6c47d902f 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -1321,7 +1321,7 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( 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); + crate::base::codegen_panic_nounwind(fx, &msg, span); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 0de23e55e8174..27a5df8b1520a 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -785,7 +785,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } }) }); - crate::base::codegen_panic_nounwind(fx, &msg_str, Some(source_info.span)); + crate::base::codegen_panic_nounwind(fx, &msg_str, source_info.span); return Ok(()); } } @@ -884,7 +884,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic_nounwind( fx, "128bit atomics not yet supported", - None, + source_info.span, ); return Ok(()); } else { @@ -919,7 +919,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic_nounwind( fx, "128bit atomics not yet supported", - None, + source_info.span, ); return Ok(()); } else { diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 6eef97c14dd28..bf756860b6499 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -101,7 +101,7 @@ pub(crate) fn maybe_create_entry_wrapper( let call_inst = bcx.ins().call(main_func_ref, &[]); let call_results = bcx.func.dfg.inst_results(call_inst).to_owned(); - let termination_trait = tcx.require_lang_item(LangItem::Termination, None); + let termination_trait = tcx.require_lang_item(LangItem::Termination, DUMMY_SP); let report = tcx .associated_items(termination_trait) .find_by_ident_and_kind( @@ -136,7 +136,7 @@ pub(crate) fn maybe_create_entry_wrapper( } } else { // Regular main fn invoked via start lang item. - let start_def_id = tcx.require_lang_item(LangItem::Start, None); + let start_def_id = tcx.require_lang_item(LangItem::Start, DUMMY_SP); let start_instance = Instance::expect_resolve( tcx, ty::TypingEnv::fully_monomorphized(), diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index f53045df6e799..95d44dfb6d950 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -54,7 +54,7 @@ fn codegen_three_way_compare<'tcx>( let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs); let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs); let val = fx.bcx.ins().isub(gt, lt); - CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(Some(fx.mir.span)))) + CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(fx.mir.span))) } fn codegen_compare_bin_op<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index f8bbb21492015..662546e499988 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -240,7 +240,7 @@ pub(crate) fn size_and_align_of<'tcx>( }) }); - codegen_panic_nounwind(fx, &msg_str, None); + codegen_panic_nounwind(fx, &msg_str, fx.mir.span); fx.bcx.switch_to_block(next_block); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f7863fe4ae264..c2d6a26de0fd0 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -561,7 +561,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let EntryFnType::Main { sigpipe } = entry_type; let (start_fn, start_ty, args, instance) = { - let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); + let start_def_id = cx.tcx().require_lang_item(LangItem::Start, DUMMY_SP); let start_instance = ty::Instance::expect_resolve( cx.tcx(), cx.typing_env(), diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index ef0d565333e4b..48565e0b4de47 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -110,7 +110,7 @@ mod temp_stable_hash_impls { pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &Bx, - span: Option, + span: Span, li: LangItem, ) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) { let tcx = bx.tcx(); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1baab62ae43ac..bfc367f7a4db2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -783,7 +783,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; - let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), lang_item); + let (fn_abi, llfn, instance) = common::build_langcall(bx, span, lang_item); // Codegen the actual panic invoke/call. let merging_succ = @@ -803,7 +803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(bx, terminator.source_info); // Obtain the panic entry point. - let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), reason.lang_item()); + let (fn_abi, llfn, instance) = common::build_langcall(bx, span, reason.lang_item()); // Codegen the actual panic invoke/call. let merging_succ = helper.do_call( @@ -871,7 +871,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Obtain the panic entry point. let (fn_abi, llfn, instance) = - common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind); + common::build_langcall(bx, source_info.span, LangItem::PanicNounwind); // Codegen the actual panic invoke/call. Some(helper.do_call( @@ -1830,7 +1830,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span)); - let (fn_abi, fn_ptr, instance) = common::build_langcall(&bx, None, reason.lang_item()); + let (fn_abi, fn_ptr, instance) = + common::build_langcall(&bx, self.mir.span, reason.lang_item()); if is_call_from_compiler_builtins_to_upstream_monomorphization(bx.tcx(), instance) { bx.abort(); } else { diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index ac2366340fb79..577012151e49f 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -5,6 +5,7 @@ use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty}; +use rustc_span::DUMMY_SP; use tracing::{debug, trace}; use crate::common::IntPredicate; @@ -62,7 +63,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Obtain the panic entry point. let (fn_abi, llfn, _instance) = - common::build_langcall(bx, None, LangItem::PanicNounwind); + common::build_langcall(bx, DUMMY_SP, LangItem::PanicNounwind); // Generate the call. Cannot use `do_call` since we don't have a MIR terminator so we // can't create a `TerminationCodegenHelper`. (But we are in good company, this code is diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index d701646719ad9..9c30dbff99eb3 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -345,11 +345,7 @@ fn build_error_for_const_call<'tcx>( non_or_conditionally, }); - note_trait_if_possible( - &mut err, - self_ty, - tcx.require_lang_item(LangItem::Deref, Some(span)), - ); + note_trait_if_possible(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, span)); err } _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::FmtArgumentsNew) => { diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index dfcd1969a73d1..c1a37ab6a83f3 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -99,7 +99,7 @@ impl Qualif for HasMutInterior { // requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error. // Instead we invoke an obligation context manually, and provide the opaque type inference settings // that allow the trait solver to just error out instead of cycling. - let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span)); + let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, cx.body.span); // FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR // typeck results without causing query cycles, we should use this here instead of defining // opaque types. @@ -180,7 +180,7 @@ impl Qualif for NeedsNonConstDrop { // that the components of this type are also `~const Destruct`. This // amounts to verifying that there are no values in this ADT that may have // a non-const drop. - let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span)); + let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, cx.body.span); let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(Obligation::new( diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 3922b33ea8421..a68dcf2998866 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -249,7 +249,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { return Err(ConstEvalErrKind::Panic { msg, file, line, col }).into(); } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. - let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); + let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, self.tcx.span); let new_instance = ty::Instance::expect_resolve( *self.tcx, self.typing_env(), diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 39755169e6cae..77667ba823a7b 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug, ty}; +use rustc_span::DUMMY_SP; use tracing::trace; use super::{ @@ -307,7 +308,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self { // Can use any typing env, since `Ordering` is always monomorphic. - let ty = tcx.ty_ordering_enum(None); + let ty = tcx.ty_ordering_enum(DUMMY_SP); let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap(); Self::from_scalar(Scalar::Int(c.into()), layout) diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index e926040e9ba15..9575bd4366188 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -30,7 +30,7 @@ fn alloc_caller_location<'tcx>( // Allocate memory for `CallerLocation` struct. let loc_ty = ecx .tcx - .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, None)) + .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, ecx.tcx.span)) .instantiate(*ecx.tcx, ecx.tcx.mk_args(&[ecx.tcx.lifetimes.re_erased.into()])); let loc_layout = ecx.layout_of(loc_ty).unwrap(); let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 846eacce9e10b..77f6204d595c6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -97,7 +97,7 @@ fn allowed_union_or_unsafe_field<'tcx>( let def_id = tcx .lang_items() .get(LangItem::BikeshedGuaranteedNoDrop) - .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, Some(span))); + .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, span)); let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) else { tcx.dcx().span_delayed_bug(span, "could not normalize field type"); return true; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 09610a2f3ec6d..234520c158311 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -180,7 +180,7 @@ pub(crate) fn check_intrinsic_type( ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv), ]); let mk_va_list_ty = |mutbl| { - let did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let did = tcx.require_lang_item(LangItem::VaList, span); let region = ty::Region::new_bound( tcx, ty::INNERMOST, @@ -442,9 +442,7 @@ pub(crate) fn check_intrinsic_type( sym::bswap | sym::bitreverse => (1, 0, vec![param(0)], param(0)), - sym::three_way_compare => { - (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(span))) - } + sym::three_way_compare => (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(span)), sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { (1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool])) @@ -520,7 +518,7 @@ pub(crate) fn check_intrinsic_type( sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( - tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), + tcx.require_lang_item(hir::LangItem::DiscriminantKind, span), ); let discriminant_def_id = assoc_items[0]; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b764b714fe17e..6b6ec7914c9b4 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -969,7 +969,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::UnsizedConstParamTy, Some(hir_ty.span)), + tcx.require_lang_item(LangItem::UnsizedConstParamTy, hir_ty.span), ); Ok(()) }) @@ -983,7 +983,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)), + tcx.require_lang_item(LangItem::ConstParamTy, hir_ty.span), ); Ok(()) }) @@ -1232,7 +1232,7 @@ fn check_type_defn<'tcx>( ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::Sized, Some(hir_ty.span)), + tcx.require_lang_item(LangItem::Sized, hir_ty.span), ); } @@ -1356,7 +1356,7 @@ fn check_static_item( ), wfcx.param_env, item_ty, - tcx.require_lang_item(LangItem::Sized, Some(ty_span)), + tcx.require_lang_item(LangItem::Sized, ty_span), ); } @@ -1375,7 +1375,7 @@ fn check_static_item( ), wfcx.param_env, item_ty, - tcx.require_lang_item(LangItem::Sync, Some(ty_span)), + tcx.require_lang_item(LangItem::Sync, ty_span), ); } Ok(()) @@ -1401,7 +1401,7 @@ fn check_const_item( ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::Sized, None), + tcx.require_lang_item(LangItem::Sized, ty_span), ); check_where_clauses(wfcx, item_span, def_id); @@ -1725,13 +1725,13 @@ fn check_fn_or_method<'tcx>( ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall), wfcx.param_env, *ty, - tcx.require_lang_item(hir::LangItem::Tuple, Some(span)), + tcx.require_lang_item(hir::LangItem::Tuple, span), ); wfcx.register_bound( ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall), wfcx.param_env, *ty, - tcx.require_lang_item(hir::LangItem::Sized, Some(span)), + tcx.require_lang_item(hir::LangItem::Sized, span), ); } else { tcx.dcx().span_err( @@ -1776,7 +1776,7 @@ fn check_sized_if_body<'tcx>( ObligationCause::new(span, def_id, code), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::Sized, Some(span)), + tcx.require_lang_item(LangItem::Sized, span), ); } } @@ -2013,7 +2013,7 @@ fn receiver_is_valid<'tcx>( // deref chain implement `LegacyReceiver`. if arbitrary_self_types_enabled.is_none() { let legacy_receiver_trait_def_id = - tcx.require_lang_item(LangItem::LegacyReceiver, Some(span)); + tcx.require_lang_item(LangItem::LegacyReceiver, span); if !legacy_receiver_is_implemented( wfcx, legacy_receiver_trait_def_id, diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index b92d1d7104f0a..4779f4fb702b7 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -225,7 +225,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() // redundant errors for `DispatchFromDyn`. This is best effort, though. let mut res = Ok(()); tcx.for_each_relevant_impl( - tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)), + tcx.require_lang_item(LangItem::CoerceUnsized, span), source, |impl_def_id| { res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id)); @@ -379,8 +379,8 @@ pub(crate) fn coerce_unsized_info<'tcx>( let span = tcx.def_span(impl_did); let trait_name = "CoerceUnsized"; - let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); - let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span)); + let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span); + let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span); let source = tcx.type_of(impl_did).instantiate_identity(); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity(); @@ -591,7 +591,7 @@ fn infringing_fields_error<'tcx>( impl_did: LocalDefId, impl_span: Span, ) -> ErrorGuaranteed { - let trait_did = tcx.require_lang_item(lang_item, Some(impl_span)); + let trait_did = tcx.require_lang_item(lang_item, impl_span); let trait_name = tcx.def_path_str(trait_did); @@ -748,7 +748,7 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err ObligationCause::misc(impl_span, checker.impl_def_id), param_env, nontrivial_field_ty, - tcx.require_lang_item(LangItem::PointerLike, Some(impl_span)), + tcx.require_lang_item(LangItem::PointerLike, impl_span), ); // FIXME(dyn-star): We should regionck this implementation. if ocx.select_all_or_error().is_empty() { 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 2a37a8bdbd47d..4c65d0d051021 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2590,7 +2590,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .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)); + let def_id = tcx.require_lang_item(lang_item, span); let (args, _) = self.lower_generic_args_of_path( span, def_id, diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f555d116c52db..d173fe7c2c26a 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -508,7 +508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(ty) = fn_sig.inputs().last().copied() { self.register_bound( ty, - self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)), + self.tcx.require_lang_item(hir::LangItem::Tuple, sp), self.cause(sp, ObligationCauseCode::RustCall), ); self.require_type_is_sized(ty, sp, ObligationCauseCode::RustCall); diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 99103f14d6823..ac42eebf08c0d 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -57,7 +57,7 @@ pub(super) fn check_fn<'a, 'tcx>( // (as it's created inside the body itself, not passed in from outside). let maybe_va_list = fn_sig.c_variadic.then(|| { let span = body.params.last().unwrap().span; - let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let va_list_did = tcx.require_lang_item(LangItem::VaList, span); let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); tcx.type_of(va_list_did).instantiate(tcx, &[region.into()]) @@ -178,7 +178,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_> tcx.dcx().span_err(span, "should have no const parameters"); } - let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, Some(span)); + let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, span); // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` let panic_info_ty = tcx.type_of(panic_info_did).instantiate( diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index cd3746be1d156..459c0498d500b 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -142,13 +142,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_adt( tcx, - tcx.adt_def( - tcx.require_lang_item(hir::LangItem::Poll, Some(expr_span)), - ), + tcx.adt_def(tcx.require_lang_item(hir::LangItem::Poll, expr_span)), tcx.mk_args(&[Ty::new_adt( tcx, tcx.adt_def( - tcx.require_lang_item(hir::LangItem::Option, Some(expr_span)), + tcx.require_lang_item(hir::LangItem::Option, expr_span), ), tcx.mk_args(&[yield_ty.into()]), ) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ddc80fab2ce18..d9fa56fefeb21 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -760,8 +760,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.param_env, ty::TraitRef::new( self.tcx, - self.tcx - .require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)), + self.tcx.require_lang_item(hir::LangItem::PointerLike, self.cause.span), [a], ), ), @@ -1969,7 +1968,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.param_env, ty::TraitRef::new( fcx.tcx, - fcx.tcx.require_lang_item(hir::LangItem::Sized, None), + fcx.tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP), [sig.output()], ), )) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 082ddac7e5ae2..b17d5977e067b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1407,7 +1407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let lhs_deref_ty_is_sized = self .infcx .type_implements_trait( - self.tcx.require_lang_item(LangItem::Sized, None), + self.tcx.require_lang_item(LangItem::Sized, span), [lhs_deref_ty], self.param_env, ) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 362c7d8efac08..8a90e768d7002 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -409,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { code: traits::ObligationCauseCode<'tcx>, ) { if !ty.references_error() { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, span); self.require_type_meets(ty, span, code, lang_item); } } @@ -443,7 +443,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Nothing else is required here. } else { // We can't be sure, let's required full `Sized`. - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, span); self.require_type_meets(ty, span, ObligationCauseCode::Misc, lang_item); } } @@ -732,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, hir_id: HirId, ) -> (Res, Ty<'tcx>) { - let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_id = self.tcx.require_lang_item(lang_item, span); let def_kind = self.tcx.def_kind(def_id); let item_ty = if let DefKind::Variant = def_kind { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 59aba6fae5e45..95c7f251c884c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -165,7 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => traits::IsConstable::No, }; - let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); + let lang_item = self.tcx.require_lang_item(LangItem::Copy, element.span); let code = traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span, @@ -1680,8 +1680,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast::LitKind::CStr(_, _) => Ty::new_imm_ref( tcx, tcx.lifetimes.re_static, - tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span))) - .skip_binder(), + tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, lit.span)).skip_binder(), ), ast::LitKind::Err(guar) => Ty::new_error(tcx, guar), } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1c3bc338d85b2..66af085cfd48d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2679,7 +2679,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut sugg_sp = sp; if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind { let clone_trait = - self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span)); + self.tcx.require_lang_item(LangItem::Clone, segment.ident.span); if args.is_empty() && self .typeck_results diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 17d48184dd971..432eeae8016cc 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -796,7 +796,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if *negated { self.register_bound( ty, - self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)), + self.tcx.require_lang_item(LangItem::Neg, lt.span), ObligationCause::dummy_with_span(lt.span), ); } @@ -2553,13 +2553,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; self.register_bound( source_ty, - tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)), + tcx.require_lang_item(hir::LangItem::DerefPure, span), self.misc(span), ); // The expected type for the deref pat's inner pattern is `::Target`. let target_ty = Ty::new_projection( tcx, - tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)), + tcx.require_lang_item(hir::LangItem::DerefTarget, span), [source_ty], ); let target_ty = self.normalize(span, target_ty); @@ -2580,7 +2580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for mutably_derefed_ty in derefed_tys { self.register_bound( mutably_derefed_ty, - self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)), + self.tcx.require_lang_item(hir::LangItem::DerefMut, span), self.misc(span), ); } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4b2e87f5674a6..5b5253c7e7e21 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1560,7 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let is_drop_defined_for_ty = |ty: Ty<'tcx>| { - let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span)); + let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, closure_span); self.infcx .type_implements_trait(drop_trait, [ty], self.tcx.param_env(closure_def_id)) .must_apply_modulo_regions() diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 47b80135bae94..69e9f8e1b2cb7 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -39,7 +39,7 @@ pub use rustc_session::lint::builtin::*; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; -use rustc_span::{BytePos, Ident, InnerSpan, Span, Symbol, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Ident, InnerSpan, Span, Symbol, kw, sym}; use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -635,7 +635,8 @@ fn type_implements_negative_copy_modulo_regions<'tcx>( typing_env: ty::TypingEnv<'tcx>, ) -> bool { let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); - let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, DUMMY_SP), [ty]); let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative }; let obligation = traits::Obligation { cause: traits::ObligationCause::dummy(), diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index bd315577efb5e..6c6b12fed674f 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -95,7 +95,7 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence { #[diag(middle_requires_lang_item)] pub(crate) struct RequiresLangItem { #[primary_span] - pub span: Option, + pub span: Span, pub name: Symbol, } diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 0f92c1910f1bb..93264f02cc259 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -17,7 +17,7 @@ use crate::ty::{self, TyCtxt}; impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. - pub fn require_lang_item(self, lang_item: LangItem, span: Option) -> DefId { + pub fn require_lang_item(self, lang_item: LangItem, span: Span) -> DefId { self.lang_items().get(lang_item).unwrap_or_else(|| { self.dcx().emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() }); }) diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 06e41e64fdc7d..d98b40f0fcf13 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -835,7 +835,7 @@ impl<'tcx> BinOp { &BinOp::Cmp => { // these should be integer-like types of the same size. assert_eq!(lhs_ty, rhs_ty); - tcx.ty_ordering_enum(None) + tcx.ty_ordering_enum(DUMMY_SP) } } } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index a61a6c571a2cd..3bacdfe5ac880 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -128,8 +128,8 @@ impl OverloadedDeref { /// for this overloaded deref's mutability. pub fn method_call<'tcx>(&self, tcx: TyCtxt<'tcx>) -> DefId { let trait_def_id = match self.mutbl { - hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None), - hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None), + hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, self.span), + hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, self.span), }; tcx.associated_items(trait_def_id) .in_definition_order() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 57b20a1bba606..0b1e9852d2a90 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -458,7 +458,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId { - self.require_lang_item(trait_lang_item_to_lang_item(lang_item), None) + self.require_lang_item(trait_lang_item_to_lang_item(lang_item), DUMMY_SP) } fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool { @@ -1710,7 +1710,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Gets a `Ty` representing the [`LangItem::OrderingEnum`] #[track_caller] - pub fn ty_ordering_enum(self, span: Option) -> Ty<'tcx> { + pub fn ty_ordering_enum(self, span: Span) -> Ty<'tcx> { let ordering_enum = self.require_lang_item(hir::LangItem::OrderingEnum, span); self.type_of(ordering_enum).no_bound_vars().unwrap() } @@ -2253,7 +2253,7 @@ impl<'tcx> TyCtxt<'tcx> { Ty::new_imm_ref( self, self.lifetimes.re_static, - self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) + self.type_of(self.require_lang_item(LangItem::PanicLocation, DUMMY_SP)) .instantiate(self, self.mk_args(&[self.lifetimes.re_static.into()])), ) } @@ -2712,7 +2712,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given a `ty`, return whether it's an `impl Future<...>`. pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool { let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false }; - let future_trait = self.require_lang_item(LangItem::Future, None); + let future_trait = self.require_lang_item(LangItem::Future, DUMMY_SP); self.explicit_item_self_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 0d99a1b51499a..5ba4e5446e9d4 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -786,7 +786,7 @@ impl<'tcx> Instance<'tcx> { } pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); + let def_id = tcx.require_lang_item(LangItem::DropInPlace, DUMMY_SP); let args = tcx.mk_args(&[ty.into()]); Instance::expect_resolve( tcx, @@ -798,7 +798,7 @@ impl<'tcx> Instance<'tcx> { } pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); + let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, DUMMY_SP); let args = tcx.mk_args(&[ty.into()]); Instance::expect_resolve( tcx, @@ -824,7 +824,7 @@ impl<'tcx> Instance<'tcx> { closure_did: DefId, args: ty::GenericArgsRef<'tcx>, ) -> Instance<'tcx> { - let fn_once = tcx.require_lang_item(LangItem::FnOnce, None); + let fn_once = tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP); let call_once = tcx .associated_items(fn_once) .in_definition_order() diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 404674c359ed8..cbf545c01c589 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -593,7 +593,7 @@ impl<'tcx> Ty<'tcx> { ty: Ty<'tcx>, mutbl: ty::Mutability, ) -> Ty<'tcx> { - let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None)); + let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, DUMMY_SP)); Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()])) } @@ -857,19 +857,19 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_box(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = tcx.require_lang_item(LangItem::OwnedBox, None); + let def_id = tcx.require_lang_item(LangItem::OwnedBox, DUMMY_SP); Ty::new_generic_adt(tcx, def_id, ty) } #[inline] pub fn new_maybe_uninit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); + let def_id = tcx.require_lang_item(LangItem::MaybeUninit, DUMMY_SP); Ty::new_generic_adt(tcx, def_id, ty) } /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes. pub fn new_task_context(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - let context_did = tcx.require_lang_item(LangItem::Context, None); + let context_did = tcx.require_lang_item(LangItem::Context, DUMMY_SP); let context_adt_ref = tcx.adt_def(context_did); let context_args = tcx.mk_args(&[tcx.lifetimes.re_erased.into()]); let context_ty = Ty::new_adt(tcx, context_adt_ref, context_args); @@ -1549,7 +1549,7 @@ impl<'tcx> Ty<'tcx> { ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => { let assoc_items = tcx.associated_item_def_ids( - tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), + tcx.require_lang_item(hir::LangItem::DiscriminantKind, DUMMY_SP), ); Ty::new_projection_from_args(tcx, assoc_items[0], tcx.mk_args(&[self.into()])) } @@ -1629,7 +1629,7 @@ impl<'tcx> Ty<'tcx> { ty::Str | ty::Slice(_) => Ok(tcx.types.usize), ty::Dynamic(_, _, ty::Dyn) => { - let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, DUMMY_SP); Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()])) } @@ -1683,7 +1683,7 @@ impl<'tcx> Ty<'tcx> { match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) { Ok(metadata_ty) => metadata_ty, Err(tail_ty) => { - let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, DUMMY_SP); Ty::new_projection(tcx, metadata_def_id, [tail_ty]) } } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 5a97b08db28d6..b23bc089cd43e 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // malloc some memory of suitable size and align: let exchange_malloc = Operand::function_handle( tcx, - tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)), + tcx.require_lang_item(LangItem::ExchangeMalloc, expr_span), [], expr_span, ); diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index a9a07997410c0..2074fbce0aef0 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -307,7 +307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) { // Convert `expr.use` to a call like `Clone::clone(&expr)` let success = this.cfg.start_new_block(); - let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None); + let clone_trait = this.tcx.require_lang_item(LangItem::Clone, span); let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0]; let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span); let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty); diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 210b9cce581fd..a4609a6053ea5 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -364,7 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let borrow_kind = super::util::ref_pat_borrow_kind(mutability); let source_info = self.source_info(span); let re_erased = self.tcx.lifetimes.re_erased; - let trait_item = self.tcx.require_lang_item(trait_item, None); + let trait_item = self.tcx.require_lang_item(trait_item, span); let method = trait_method(self.tcx, trait_item, method, [ty]); let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span); // `let ref_src = &src_place;` @@ -437,7 +437,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { val: Operand<'tcx>, ) { let str_ty = self.tcx.types.str_; - let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); + let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, source_info.span); let method = trait_method(self.tcx, eq_def_id, sym::eq, [str_ty, str_ty]); let bool_ty = self.tcx.types.bool; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 226dc920a496c..03448933fa9bd 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -220,7 +220,7 @@ impl<'tcx> ThirBuildCx<'tcx> { }); // kind = Pin { __pointer: pointer } - let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span)); + let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, span); let args = self.tcx.mk_args(&[new_pin_target.into()]); let kind = ExprKind::Adt(Box::new(AdtExpr { adt_def: self.tcx.adt_def(pin_did), diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 8c817605847aa..24d4136c64237 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -189,7 +189,7 @@ impl<'tcx> ThirBuildCx<'tcx> { // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). let ty = if fn_decl.c_variadic && index == fn_decl.inputs.len() { - let va_list_did = self.tcx.require_lang_item(LangItem::VaList, Some(param.span)); + let va_list_did = self.tcx.require_lang_item(LangItem::VaList, param.span); self.tcx .type_of(va_list_did) 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 84a0190a7fa19..003ad17086128 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 @@ -15,7 +15,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{mir, span_bug}; use rustc_span::def_id::DefId; -use rustc_span::{Span, sym}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use tracing::{debug, instrument, trace}; @@ -480,8 +480,9 @@ fn type_has_partial_eq_impl<'tcx>( // (If there isn't, then we can safely issue a hard // error, because that's never worked, due to compiler // using `PartialEq::eq` in this scenario in the past.) - let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, None); - let structural_partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::StructuralPeq, None); + let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, DUMMY_SP); + let structural_partial_eq_trait_id = + tcx.require_lang_item(hir::LangItem::StructuralPeq, DUMMY_SP); let partial_eq_obligation = Obligation::new( tcx, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index cddb2f8477858..d5d0d56f52880 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -225,7 +225,7 @@ impl<'tcx> TransformVisitor<'tcx> { CoroutineKind::Coroutine(_) => span_bug!(body.span, "`Coroutine`s cannot be fused"), // `gen` continues return `None` CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { - let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); + let option_def_id = self.tcx.require_lang_item(LangItem::Option, body.span); make_aggregate_adt( option_def_id, VariantIdx::ZERO, @@ -242,7 +242,7 @@ impl<'tcx> TransformVisitor<'tcx> { span: source_info.span, const_: Const::Unevaluated( UnevaluatedConst::new( - self.tcx.require_lang_item(LangItem::AsyncGenFinished, None), + self.tcx.require_lang_item(LangItem::AsyncGenFinished, body.span), self.tcx.mk_args(&[yield_ty.into()]), ), self.old_yield_ty, @@ -282,7 +282,7 @@ impl<'tcx> TransformVisitor<'tcx> { const ONE: VariantIdx = VariantIdx::from_usize(1); let rvalue = match self.coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { - let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, None); + let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, source_info.span); let args = self.tcx.mk_args(&[self.old_ret_ty.into()]); let (variant_idx, operands) = if is_return { (ZERO, IndexVec::from_raw(vec![val])) // Poll::Ready(val) @@ -292,7 +292,7 @@ impl<'tcx> TransformVisitor<'tcx> { make_aggregate_adt(poll_def_id, variant_idx, args, operands) } CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { - let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); + let option_def_id = self.tcx.require_lang_item(LangItem::Option, source_info.span); let args = self.tcx.mk_args(&[self.old_yield_ty.into()]); let (variant_idx, operands) = if is_return { (ZERO, IndexVec::new()) // None @@ -310,7 +310,10 @@ impl<'tcx> TransformVisitor<'tcx> { span: source_info.span, const_: Const::Unevaluated( UnevaluatedConst::new( - self.tcx.require_lang_item(LangItem::AsyncGenFinished, None), + self.tcx.require_lang_item( + LangItem::AsyncGenFinished, + source_info.span, + ), self.tcx.mk_args(&[yield_ty.into()]), ), self.old_yield_ty, @@ -323,7 +326,7 @@ impl<'tcx> TransformVisitor<'tcx> { } CoroutineKind::Coroutine(_) => { let coroutine_state_def_id = - self.tcx.require_lang_item(LangItem::CoroutineState, None); + self.tcx.require_lang_item(LangItem::CoroutineState, source_info.span); let args = self.tcx.mk_args(&[self.old_yield_ty.into(), self.old_ret_ty.into()]); let variant_idx = if is_return { ONE // CoroutineState::Complete(val) @@ -496,7 +499,7 @@ fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Bo fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let ref_coroutine_ty = body.local_decls.raw[1].ty; - let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span)); + let pin_did = tcx.require_lang_item(LangItem::Pin, body.span); let pin_adt_ref = tcx.adt_def(pin_did); let args = tcx.mk_args(&[ref_coroutine_ty.into()]); let pin_ref_coroutine_ty = Ty::new_adt(tcx, pin_adt_ref, args); @@ -557,7 +560,7 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> Ty // replace the type of the `resume` argument replace_resume_ty_local(tcx, body, CTX_ARG, context_mut_ref); - let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None); + let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, body.span); for bb in body.basic_blocks.indices() { let bb_data = &body[bb]; @@ -618,7 +621,7 @@ fn replace_resume_ty_local<'tcx>( #[cfg(debug_assertions)] { if let ty::Adt(resume_ty_adt, _) = local_ty.kind() { - let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, body.span)); assert_eq!(*resume_ty_adt, expected_adt); } else { panic!("expected `ResumeTy`, found `{:?}`", local_ty); @@ -1095,7 +1098,7 @@ fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Statement<'tcx> { // Poll::Ready(()) - let poll_def_id = tcx.require_lang_item(LangItem::Poll, None); + let poll_def_id = tcx.require_lang_item(LangItem::Poll, source_info.span); let args = tcx.mk_args(&[tcx.types.unit.into()]); let val = Operand::Constant(Box::new(ConstOperand { span: source_info.span, @@ -1437,7 +1440,7 @@ fn check_field_tys_sized<'tcx>( ), param_env, field_ty.ty, - tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)), + tcx.require_lang_item(hir::LangItem::Sized, field_ty.source_info.span), ); } @@ -1473,14 +1476,14 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let new_ret_ty = match coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { // Compute Poll - let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_did = tcx.require_lang_item(LangItem::Poll, body.span); let poll_adt_ref = tcx.adt_def(poll_did); let poll_args = tcx.mk_args(&[old_ret_ty.into()]); Ty::new_adt(tcx, poll_adt_ref, poll_args) } CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { // Compute Option - let option_did = tcx.require_lang_item(LangItem::Option, None); + let option_did = tcx.require_lang_item(LangItem::Option, body.span); let option_adt_ref = tcx.adt_def(option_did); let option_args = tcx.mk_args(&[old_yield_ty.into()]); Ty::new_adt(tcx, option_adt_ref, option_args) @@ -1491,7 +1494,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { } CoroutineKind::Coroutine(_) => { // Compute CoroutineState - let state_did = tcx.require_lang_item(LangItem::CoroutineState, None); + let state_did = tcx.require_lang_item(LangItem::CoroutineState, body.span); let state_adt_ref = tcx.adt_def(state_did); let state_args = tcx.mk_args(&[old_yield_ty.into(), old_ret_ty.into()]); Ty::new_adt(tcx, state_adt_ref, state_args) diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 6b266da5a69e5..0d189c00d5d73 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -42,7 +42,7 @@ fn build_poll_call<'tcx>( context_ref_place: &Place<'tcx>, unwind: UnwindAction, ) -> BasicBlock { - let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, None); + let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, DUMMY_SP); let poll_fn = Ty::new_fn_def(tcx, poll_fn, [fut_ty]); let poll_fn = Operand::Constant(Box::new(ConstOperand { span: DUMMY_SP, @@ -77,11 +77,8 @@ fn build_pin_fut<'tcx>( let fut_ty = fut_place.ty(&body.local_decls, tcx).ty; let fut_ref_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fut_ty); let fut_ref_place = Place::from(body.local_decls.push(LocalDecl::new(fut_ref_ty, span))); - let pin_fut_new_unchecked_fn = Ty::new_fn_def( - tcx, - tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)), - [fut_ref_ty], - ); + let pin_fut_new_unchecked_fn = + Ty::new_fn_def(tcx, tcx.require_lang_item(LangItem::PinNewUnchecked, span), [fut_ref_ty]); let fut_pin_ty = pin_fut_new_unchecked_fn.fn_sig(tcx).output().skip_binder(); let fut_pin_place = Place::from(body.local_decls.push(LocalDecl::new(fut_pin_ty, span))); let pin_fut_new_unchecked_fn = Operand::Constant(Box::new(ConstOperand { @@ -143,13 +140,15 @@ fn build_poll_switch<'tcx>( let Discr { val: poll_ready_discr, ty: poll_discr_ty } = poll_enum .discriminant_for_variant( tcx, - poll_enum_adt.variant_index_with_id(tcx.require_lang_item(LangItem::PollReady, None)), + poll_enum_adt + .variant_index_with_id(tcx.require_lang_item(LangItem::PollReady, DUMMY_SP)), ) .unwrap(); let poll_pending_discr = poll_enum .discriminant_for_variant( tcx, - poll_enum_adt.variant_index_with_id(tcx.require_lang_item(LangItem::PollPending, None)), + poll_enum_adt + .variant_index_with_id(tcx.require_lang_item(LangItem::PollPending, DUMMY_SP)), ) .unwrap() .val; @@ -317,7 +316,7 @@ pub(super) fn expand_async_drops<'tcx>( // ready => *continue_bb|drop_bb* // Compute Poll<> (aka Poll with void return) - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, body.span)); let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); let poll_decl = LocalDecl::new(poll_enum, body.span); let poll_unit_place = Place::from(body.local_decls.push(poll_decl)); @@ -573,7 +572,7 @@ pub(super) fn create_coroutine_drop_shim<'tcx>( // Update the body's def to become the drop glue. let coroutine_instance = body.source.instance; - let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None); + let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, body.span); let drop_instance = InstanceKind::DropGlue(drop_in_place, Some(coroutine_ty)); // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible @@ -644,7 +643,7 @@ pub(super) fn create_coroutine_drop_shim_async<'tcx>( } // Replace the return variable: Poll to Poll<()> - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, body.span)); let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info); @@ -695,7 +694,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>( let source_info = SourceInfo::outermost(body.span); // Replace the return variable: Poll to Poll<()> - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, body.span)); let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info); diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index c15d7d6f732c9..3a5e2620b149c 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -235,11 +235,8 @@ where let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only { // Resolving obj.() - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::AsyncDrop, Some(span)), - [drop_ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::AsyncDrop, span), [drop_ty]); let (drop_trait, trait_args) = match tcx.codegen_select_candidate( ty::TypingEnv::fully_monomorphized().as_query_input(trait_ref), ) { @@ -292,7 +289,7 @@ where (sig.output(), drop_fn_def_id, trait_args) } else { // Resolving async_drop_in_place function for drop_ty - let drop_fn_def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, Some(span)); + let drop_fn_def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, span); let trait_args = tcx.mk_args(&[drop_ty.into()]); let sig = tcx.fn_sig(drop_fn_def_id).instantiate(tcx, trait_args); let sig = tcx.instantiate_bound_regions_with_erased(sig); @@ -319,7 +316,7 @@ where // pin_obj_place preparation let pin_obj_new_unchecked_fn = Ty::new_fn_def( tcx, - tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)), + tcx.require_lang_item(LangItem::PinNewUnchecked, span), [GenericArg::from(obj_ref_ty)], ); let pin_obj_ty = pin_obj_new_unchecked_fn.fn_sig(tcx).output().no_bound_vars().unwrap(); @@ -937,7 +934,7 @@ where fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { debug!("destructor_call_block_sync({:?}, {:?})", self, succ); let tcx = self.tcx(); - let drop_trait = tcx.require_lang_item(LangItem::Drop, None); + let drop_trait = tcx.require_lang_item(LangItem::Drop, DUMMY_SP); let drop_fn = tcx.associated_item_def_ids(drop_trait)[0]; let ty = self.place_ty(self.place); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 9688ac8ed2e27..6d45bbc6e16e2 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -98,7 +98,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } ty::InstanceKind::ClosureOnceShim { call_once: _, track_caller: _ } => { - let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); + let fn_mut = tcx.require_lang_item(LangItem::FnMut, DUMMY_SP); let call_mut = tcx .associated_items(fn_mut) .in_definition_order() 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 fbc8ee9b06c03..fd7b7362cd9da 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -64,7 +64,7 @@ pub(super) fn build_async_drop_shim<'tcx>( let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env); let needs_sync_drop = !needs_async_drop && drop_ty.needs_drop(tcx, typing_env); - let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP)); let resume_ty = Ty::new_adt(tcx, resume_adt, ty::List::empty()); let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig( @@ -220,7 +220,7 @@ fn build_adrop_for_coroutine_shim<'tcx>( body.source.instance = instance; body.phase = MirPhase::Runtime(RuntimePhase::Initial); body.var_debug_info.clear(); - let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, Some(span))); + let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span)); let args = tcx.mk_args(&[proxy_ref.into()]); let pin_proxy_ref = Ty::new_adt(tcx, pin_adt_ref, args); @@ -308,10 +308,10 @@ fn build_adrop_for_adrop_shim<'tcx>( let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty); // ret_ty = `Poll<()>` - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, span)); let ret_ty = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); // env_ty = `Pin<&mut proxy_ty>` - let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None)); + let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span)); let env_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[proxy_ref.into()])); // sig = `fn (Pin<&mut proxy_ty>, &mut Context) -> Poll<()>` let sig = tcx.mk_fn_sig( @@ -376,7 +376,7 @@ fn build_adrop_for_adrop_shim<'tcx>( let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()])); let cor_pin_place = Place::from(locals.push(LocalDecl::new(cor_pin_ty, span))); - let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)); + let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span); // call Pin::new_unchecked(&mut impl_cor) blocks.push(BasicBlockData { statements, @@ -396,7 +396,7 @@ fn build_adrop_for_adrop_shim<'tcx>( }); // When dropping async drop coroutine, we continue its execution: // we call impl::poll (impl_layout, ctx) - let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, None); + let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span); let resume_ctx = Place::from(Local::new(2)); blocks.push(BasicBlockData { statements: vec![], diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index c8aa7588d03ab..fd91508cc1148 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1253,7 +1253,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.tcx, self.tcx.require_lang_item( LangItem::CoerceUnsized, - Some(self.body.source_info(location).span), + self.body.source_info(location).span, ), [op_ty, *target_type], )) { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1ee977a5457e2..173030e0326e8 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -781,7 +781,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let tcx = self.tcx; let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| { - let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source))); + let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, source)); if tcx.should_codegen_locally(instance) { this.used_items.push(create_fn_mono_item(tcx, instance, source)); } @@ -921,7 +921,7 @@ fn visit_instance_use<'tcx>( // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any // of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to // codegen a call to that function without generating code for the function itself. - let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None); + let def_id = tcx.require_lang_item(LangItem::PanicNounwind, source); let panic_instance = Instance::mono(tcx, def_id); if tcx.should_codegen_locally(panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 5c66017bc6113..05683940cba4f 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -29,7 +29,7 @@ fn custom_coerce_unsize_info<'tcx>( ) -> Result { let trait_ref = ty::TraitRef::new( tcx.tcx, - tcx.require_lang_item(LangItem::CoerceUnsized, Some(tcx.span)), + tcx.require_lang_item(LangItem::CoerceUnsized, tcx.span), [source_ty, target_ty], ); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index d2917478e4e43..c69991f3fb208 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UintTy, }; use rustc_span::def_id::DefId; -use rustc_span::sym; +use rustc_span::{DUMMY_SP, sym}; use rustc_trait_selection::traits; use tracing::{debug, instrument}; @@ -414,7 +414,7 @@ pub(crate) fn transform_instance<'tcx>( } ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() { hir::CoroutineKind::Coroutine(..) => ( - tcx.require_lang_item(LangItem::Coroutine, None), + tcx.require_lang_item(LangItem::Coroutine, DUMMY_SP), Some(instance.args.as_coroutine().resume_ty()), ), hir::CoroutineKind::Desugared(desugaring, _) => { @@ -423,11 +423,11 @@ pub(crate) fn transform_instance<'tcx>( hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator, hir::CoroutineDesugaring::Gen => LangItem::Iterator, }; - (tcx.require_lang_item(lang_item, None), None) + (tcx.require_lang_item(lang_item, DUMMY_SP), None) } }, ty::CoroutineClosure(..) => ( - tcx.require_lang_item(LangItem::FnOnce, None), + tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP), Some( tcx.instantiate_bound_regions_with_erased( instance.args.as_coroutine_closure().coroutine_closure_sig(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 8e2137da6552d..2c16672d78641 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -73,7 +73,7 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{BytePos, DesugaringKind, Pos, Span, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -194,7 +194,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => return None, }; - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + let future_trait = self.tcx.require_lang_item(LangItem::Future, DUMMY_SP); let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; self.tcx diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs index d8b405e904c06..8a67e4ccd456f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs @@ -6,7 +6,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, lang_items}; use rustc_middle::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv}; -use rustc_span::{DesugaringKind, Ident, Span, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, sym}; use tracing::debug; use crate::traits::specialization_graph; @@ -31,9 +31,9 @@ impl CallDesugaringKind { pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId { match self { Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(), - Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, None), + Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, DUMMY_SP), Self::QuestionBranch | Self::TryBlockFromOutput => { - tcx.require_lang_item(LangItem::Try, None) + tcx.require_lang_item(LangItem::Try, DUMMY_SP) } Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(), 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 c4f1f7d712a7c..4d66ee8d38bd7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -955,7 +955,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return false; }; - let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None); + let clone_trait = self.tcx.require_lang_item(LangItem::Clone, obligation.cause.span); let has_clone = |ty| { self.type_implements_trait(clone_trait, [ty], obligation.param_env) .must_apply_modulo_regions() @@ -3625,7 +3625,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) { - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + let future_trait = self.tcx.require_lang_item(LangItem::Future, span); let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); let impls_future = self.type_implements_trait( @@ -4139,7 +4139,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let pred = ty::Binder::dummy(ty::TraitPredicate { trait_ref: ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Clone, Some(span)), + tcx.require_lang_item(LangItem::Clone, span), [*ty], ), polarity: ty::PredicatePolarity::Positive, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 0dab3adadb033..0118321befbb2 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -38,7 +38,7 @@ impl<'tcx> InferCtxt<'tcx> { return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty); } - let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None); + let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP); // This can get called from typeck (by euv), and `moves_by_default` // rightly refuses to work with inference variables, but @@ -49,7 +49,7 @@ impl<'tcx> InferCtxt<'tcx> { fn type_is_clone_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); - let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, None); + let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id) } @@ -59,12 +59,12 @@ impl<'tcx> InferCtxt<'tcx> { ty: Ty<'tcx>, ) -> bool { let ty = self.resolve_vars_if_possible(ty); - let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None); + let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id) } fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index cc5861b5a1f59..e77d9e32cb98c 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -248,7 +248,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( obligation: &HostEffectObligation<'tcx>, ) -> Result>, EvaluationFailure> { let tcx = selcx.tcx(); - let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, None); + let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, obligation.cause.span); let self_ty = obligation.predicate.self_ty(); let const_conditions = match *self_ty.kind() { @@ -267,7 +267,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution), // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold. Some(hir::Constness::Const) => { - let drop_def_id = tcx.require_lang_item(LangItem::Drop, None); + let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span); let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]); const_conditions.push(drop_trait_ref); } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index a4b6f330b9d78..393f458bea273 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -157,7 +157,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( parent_cause.clone(), param_env, inner_ty, - tcx.require_lang_item(lang_item, Some(parent_cause.span)), + tcx.require_lang_item(lang_item, parent_cause.span), ); let errors = ocx.select_all_or_error(); @@ -193,7 +193,7 @@ pub fn all_fields_implement_trait<'tcx>( parent_cause: ObligationCause<'tcx>, lang_item: LangItem, ) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> { - let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span)); + let trait_def_id = tcx.require_lang_item(lang_item, parent_cause.span); let mut infringing = Vec::new(); for variant in adt.variants() { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index ed0f34b5aa915..6dd80551980f7 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1117,7 +1117,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( selcx.tcx(), selcx.tcx().require_lang_item( LangItem::Sized, - Some(obligation.cause.span), + obligation.cause.span, ), [self_ty], ), @@ -1317,7 +1317,7 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); - let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, None); + let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, obligation.cause.span); let (trait_ref, yield_ty, return_ty) = super::util::coroutine_trait_ref_and_outputs( tcx, @@ -1375,7 +1375,7 @@ fn confirm_future_candidate<'cx, 'tcx>( debug!(?obligation, ?coroutine_sig, ?obligations, "confirm_future_candidate"); let tcx = selcx.tcx(); - let fut_def_id = tcx.require_lang_item(LangItem::Future, None); + let fut_def_id = tcx.require_lang_item(LangItem::Future, obligation.cause.span); let (trait_ref, return_ty) = super::util::future_trait_ref_and_outputs( tcx, @@ -1421,7 +1421,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>( debug!(?obligation, ?gen_sig, ?obligations, "confirm_iterator_candidate"); let tcx = selcx.tcx(); - let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None); + let iter_def_id = tcx.require_lang_item(LangItem::Iterator, obligation.cause.span); let (trait_ref, yield_ty) = super::util::iterator_trait_ref_and_outputs( tcx, @@ -1467,7 +1467,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>( debug!(?obligation, ?gen_sig, ?obligations, "confirm_async_iterator_candidate"); let tcx = selcx.tcx(); - let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, None); + let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, obligation.cause.span); let (trait_ref, yield_ty) = super::util::async_iterator_trait_ref_and_outputs( tcx, @@ -1511,12 +1511,13 @@ fn confirm_builtin_candidate<'cx, 'tcx>( let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); let args = tcx.mk_args(&[self_ty.into()]); let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { - let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); + let discriminant_def_id = + tcx.require_lang_item(LangItem::Discriminant, obligation.cause.span); assert_eq!(discriminant_def_id, item_def_id); (self_ty.discriminant_ty(tcx).into(), PredicateObligations::new()) } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { - let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, obligation.cause.span); assert_eq!(metadata_def_id, item_def_id); let mut obligations = PredicateObligations::new(); @@ -1538,7 +1539,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( // exist. Instead, `Pointee` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), + tcx.require_lang_item(LangItem::Sized, obligation.cause.span), [self_ty], ); obligations.push(obligation.with(tcx, sized_predicate)); @@ -1620,7 +1621,7 @@ fn confirm_closure_candidate<'cx, 'tcx>( ) } else { let upvars_projection_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); + tcx.require_lang_item(LangItem::AsyncFnKindUpvars, obligation.cause.span); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, @@ -1681,8 +1682,9 @@ fn confirm_callable_candidate<'cx, 'tcx>( debug!(?obligation, ?fn_sig, "confirm_callable_candidate"); - let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None); - let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None); + let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, obligation.cause.span); + let fn_once_output_def_id = + tcx.require_lang_item(LangItem::FnOnceOutput, obligation.cause.span); let predicate = super::util::closure_trait_ref_and_return_type( tcx, @@ -1740,8 +1742,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( args.coroutine_captures_by_ref_ty(), ) } else { - let upvars_projection_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); + let upvars_projection_def_id = tcx + .require_lang_item(LangItem::AsyncFnKindUpvars, obligation.cause.span); // When we don't know the closure kind (and therefore also the closure's upvars, // which are computed at the same time), we must delay the computation of the // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait @@ -1798,7 +1800,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { - let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); + let future_output_def_id = + tcx.require_lang_item(LangItem::FutureOutput, obligation.cause.span); Ty::new_projection(tcx, future_output_def_id, [sig.output()]) } name => bug!("no such associated type: {name}"), @@ -1831,7 +1834,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { - let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); + let future_output_def_id = + tcx.require_lang_item(LangItem::FutureOutput, obligation.cause.span); Ty::new_projection(tcx, future_output_def_id, [sig.output()]) } name => bug!("no such associated type: {name}"), diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index c9169127e0b90..7acf0f990d1b3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -318,7 +318,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let make_freeze_obl = |ty| { let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Freeze, None), + tcx.require_lang_item(LangItem::Freeze, obligation.cause.span), [ty::GenericArg::from(ty)], ); Obligation::with_depth( @@ -657,7 +657,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); let tr = ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)), + self.tcx().require_lang_item(LangItem::Sized, cause.span), [output_ty], ); nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr)); @@ -877,14 +877,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); // We must additionally check that the return type impls `Future + Sized`. - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = + tcx.require_lang_item(LangItem::Future, obligation.cause.span); nested.push(obligation.with( tcx, sig.output().map_bound(|output_ty| { ty::TraitRef::new(tcx, future_trait_def_id, [output_ty]) }), )); - let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let sized_trait_def_id = + tcx.require_lang_item(LangItem::Sized, obligation.cause.span); nested.push(obligation.with( tcx, sig.output().map_bound(|output_ty| { @@ -906,13 +908,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); // We must additionally check that the return type impls `Future + Sized`. - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = + tcx.require_lang_item(LangItem::Future, obligation.cause.span); let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); nested.push(obligation.with( tcx, ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]), )); - let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let sized_trait_def_id = + tcx.require_lang_item(LangItem::Sized, obligation.cause.span); nested.push(obligation.with( tcx, sig.output().map_bound(|output_ty| { @@ -946,10 +950,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item( - LangItem::AsyncFnKindHelper, - Some(obligation.cause.span), - ), + self.tcx() + .require_lang_item(LangItem::AsyncFnKindHelper, obligation.cause.span), [kind_ty, Ty::from_closure_kind(self.tcx(), goal_kind)], ), )); @@ -1165,7 +1167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We can only make objects from sized types. let tr = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), + tcx.require_lang_item(LangItem::Sized, obligation.cause.span), [source], ); nested.push(predicate_to_obligation(tr.upcast(tcx))); @@ -1359,7 +1361,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self_ty.map_bound(|ty| { ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Copy, Some(obligation.cause.span)), + tcx.require_lang_item(LangItem::Copy, obligation.cause.span), [ty], ) }), @@ -1411,7 +1413,7 @@ fn pointer_like_goal_for_rpitit<'tcx>( ty::Binder::bind_with_vars( ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::PointerLike, Some(cause.span)), + tcx.require_lang_item(LangItem::PointerLike, cause.span), [Ty::new_projection_from_args(tcx, rpitit_item, args)], ), tcx.mk_bound_variable_kinds(&bound_vars), diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 3018dad8e0916..416865e861ea8 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -541,7 +541,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let cause = self.cause(cause); let trait_ref = ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)), + self.tcx().require_lang_item(LangItem::Sized, cause.span), [subty], ); self.out.push(traits::Obligation::with_depth( @@ -895,7 +895,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.tcx(), self.tcx().require_lang_item( LangItem::BikeshedGuaranteedNoDrop, - Some(self.span), + self.span, ), [ty], ) diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 83d7416b03efa..bb5187e4f5c8c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; +use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; use rustc_target::callconv::{ AbiMap, ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, FnAbi, PassMode, @@ -124,7 +125,7 @@ fn fn_sig_for_fn_abi<'tcx>( let env_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty); - let pin_did = tcx.require_lang_item(LangItem::Pin, None); + let pin_did = tcx.require_lang_item(LangItem::Pin, DUMMY_SP); let pin_adt_ref = tcx.adt_def(pin_did); let pin_args = tcx.mk_args(&[env_ty.into()]); let env_ty = match coroutine_kind { @@ -149,7 +150,7 @@ fn fn_sig_for_fn_abi<'tcx>( // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll` assert_eq!(sig.yield_ty, tcx.types.unit); - let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_did = tcx.require_lang_item(LangItem::Poll, DUMMY_SP); let poll_adt_ref = tcx.adt_def(poll_did); let poll_args = tcx.mk_args(&[sig.return_ty.into()]); let ret_ty = Ty::new_adt(tcx, poll_adt_ref, poll_args); @@ -160,7 +161,7 @@ fn fn_sig_for_fn_abi<'tcx>( { if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() { let expected_adt = - tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP)); assert_eq!(*resume_ty_adt, expected_adt); } else { panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty); @@ -172,7 +173,7 @@ fn fn_sig_for_fn_abi<'tcx>( } hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => { // The signature should be `Iterator::next(_) -> Option` - let option_did = tcx.require_lang_item(LangItem::Option, None); + let option_did = tcx.require_lang_item(LangItem::Option, DUMMY_SP); let option_adt_ref = tcx.adt_def(option_did); let option_args = tcx.mk_args(&[sig.yield_ty.into()]); let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args); @@ -196,7 +197,7 @@ fn fn_sig_for_fn_abi<'tcx>( { if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() { let expected_adt = - tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP)); assert_eq!(*resume_ty_adt, expected_adt); } else { panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty); @@ -208,7 +209,7 @@ fn fn_sig_for_fn_abi<'tcx>( } hir::CoroutineKind::Coroutine(_) => { // The signature should be `Coroutine::resume(_, Resume) -> CoroutineState` - let state_did = tcx.require_lang_item(LangItem::CoroutineState, None); + let state_did = tcx.require_lang_item(LangItem::CoroutineState, DUMMY_SP); let state_adt_ref = tcx.adt_def(state_did); let state_args = tcx.mk_args(&[sig.yield_ty.into(), sig.return_ty.into()]); let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_args); diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index bb2c4172b0877..7219f40710e08 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -4,6 +4,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { @@ -42,7 +43,7 @@ fn is_item_raw<'tcx>( item: LangItem, ) -> bool { let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(query.typing_env); - let trait_def_id = tcx.require_lang_item(item, None); + let trait_def_id = tcx.require_lang_item(item, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, query.value, trait_def_id) } diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 0b4efab1d9c44..e900264a76c7e 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -16,8 +16,7 @@ fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { let ocx = ObligationCtxt::new(infcx); // require `#[derive(PartialEq)]` - let structural_peq_def_id = - infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span)); + let structural_peq_def_id = infcx.tcx.require_lang_item(LangItem::StructuralPeq, cause.span); ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id); // We deliberately skip *reporting* fulfillment errors (via diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 330aaa25d1350..e39fd6b947b47 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -104,7 +104,7 @@ fn adt_sized_constraint<'tcx>( // perf hack: if there is a `constraint_ty: Sized` bound, then we know // that the type is sized and do not need to check it on the impl. - let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, DUMMY_SP); let predicates = tcx.predicates_of(def.did()).predicates; if predicates.iter().any(|(p, _)| { p.as_trait_clause().is_some_and(|trait_pred| { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9e46d0b47e91b..4030bd4586688 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1277,7 +1277,7 @@ impl GenericBound { } fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound { - let did = cx.tcx.require_lang_item(LangItem::Sized, None); + let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP); let empty = ty::Binder::dummy(ty::GenericArgs::empty()); let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); 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 5b4ec12cbece6..8e16f943e9fc3 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 @@ -439,7 +439,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> tcx, ObligationCause::dummy_with_span(body.span), param_env, - TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]), + TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, body.span), [ty]), ); let mut selcx = SelectionContext::new(&infcx); diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 549d859a6e1e8..a6bce8301491f 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -247,7 +247,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => { // Call the lang item associated with this message. - let fn_item = this.tcx.require_lang_item(msg.panic_function(), None); + let fn_item = this.tcx.require_lang_item(msg.panic_function(), this.tcx.span); let instance = ty::Instance::mono(this.tcx.tcx, fn_item); this.call_function( instance, diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs index 7676b5557d22b..25a4ff283ba6a 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.rs +++ b/tests/ui/lang-items/lang-item-generic-requirements.rs @@ -48,6 +48,7 @@ fn ice() { // Use index let arr = [0; 5]; + //~^ ERROR requires `copy` lang_item let _ = arr[2]; //~^ ERROR cannot index into a value of type `[{integer}; 5]` @@ -61,5 +62,3 @@ fn ice() { // use `start` fn main() {} - -//~? ERROR requires `copy` lang_item diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr index 409fa05d6371a..c82bdb00fd1a3 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.stderr +++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr @@ -77,13 +77,13 @@ LL | r + a; | {integer} error[E0608]: cannot index into a value of type `[{integer}; 5]` - --> $DIR/lang-item-generic-requirements.rs:51:16 + --> $DIR/lang-item-generic-requirements.rs:52:16 | LL | let _ = arr[2]; | ^^^ error[E0308]: mismatched types - --> $DIR/lang-item-generic-requirements.rs:58:17 + --> $DIR/lang-item-generic-requirements.rs:59:17 | LL | let _: () = Foo; | -- ^^^ expected `()`, found `Foo` @@ -91,6 +91,10 @@ LL | let _: () = Foo; | expected due to this error: requires `copy` lang_item + --> $DIR/lang-item-generic-requirements.rs:50:16 + | +LL | let arr = [0; 5]; + | ^ error: aborting due to 12 previous errors From 9091a94ff042d501b627f6244444f472a32fc972 Mon Sep 17 00:00:00 2001 From: smpdt <206221751+smpdt@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:00:20 -0400 Subject: [PATCH 30/39] bootstrap: Fix file permissions when dereferencing symlinks --- src/bootstrap/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index cfb968f79ba1d..07772b8932d9d 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1795,11 +1795,12 @@ Executed at: {executed_at}"#, let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)); let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos())); } - let metadata = t!(src.symlink_metadata(), format!("src = {}", src.display())); + let mut metadata = t!(src.symlink_metadata(), format!("src = {}", src.display())); let mut src = src.to_path_buf(); if metadata.file_type().is_symlink() { if dereference_symlinks { src = t!(fs::canonicalize(src)); + metadata = t!(fs::metadata(&src), format!("target = {}", src.display())); } else { let link = t!(fs::read_link(src)); t!(self.symlink_file(link, dst)); From 06ab34e51604ae09d56b42cb4576a87dd44db5be Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 3 Jun 2025 20:59:42 +0500 Subject: [PATCH 31/39] cleaned up some tests --- tests/ui/char.rs | 13 ---- tests/ui/class-cast-to-trait.rs | 54 ----------------- tests/ui/class-cast-to-trait.stderr | 9 --- tests/ui/class-method-missing.rs | 21 ------- tests/ui/class-method-missing.stderr | 12 ---- tests/ui/cleanup-rvalue-for-scope.rs | 60 ------------------- .../ui/drop/for-expr-temporary-drop-scope.rs | 33 ++++++++++ .../enum-drop-cast-error.rs} | 4 ++ .../enum-drop-cast-error.stderr} | 2 +- tests/ui/privacy/trait-object-method-error.rs | 20 +++++++ .../privacy/trait-object-method-error.stderr | 15 +++++ tests/ui/traits/trait-impl-missing-method.rs | 13 ++++ .../traits/trait-impl-missing-method.stderr | 12 ++++ 13 files changed, 98 insertions(+), 170 deletions(-) delete mode 100644 tests/ui/char.rs delete mode 100644 tests/ui/class-cast-to-trait.rs delete mode 100644 tests/ui/class-cast-to-trait.stderr delete mode 100644 tests/ui/class-method-missing.rs delete mode 100644 tests/ui/class-method-missing.stderr delete mode 100644 tests/ui/cleanup-rvalue-for-scope.rs create mode 100644 tests/ui/drop/for-expr-temporary-drop-scope.rs rename tests/ui/{cenum_impl_drop_cast.rs => enum/enum-drop-cast-error.rs} (61%) rename tests/ui/{cenum_impl_drop_cast.stderr => enum/enum-drop-cast-error.stderr} (81%) create mode 100644 tests/ui/privacy/trait-object-method-error.rs create mode 100644 tests/ui/privacy/trait-object-method-error.stderr create mode 100644 tests/ui/traits/trait-impl-missing-method.rs create mode 100644 tests/ui/traits/trait-impl-missing-method.stderr diff --git a/tests/ui/char.rs b/tests/ui/char.rs deleted file mode 100644 index a7842f16fa7a6..0000000000000 --- a/tests/ui/char.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -pub fn main() { - let c: char = 'x'; - let d: char = 'x'; - assert_eq!(c, 'x'); - assert_eq!('x', c); - assert_eq!(c, c); - assert_eq!(c, d); - assert_eq!(d, c); - assert_eq!(d, 'x'); - assert_eq!('x', d); -} diff --git a/tests/ui/class-cast-to-trait.rs b/tests/ui/class-cast-to-trait.rs deleted file mode 100644 index ca98e4c90031f..0000000000000 --- a/tests/ui/class-cast-to-trait.rs +++ /dev/null @@ -1,54 +0,0 @@ -trait Noisy { - fn speak(&mut self); -} - -struct Cat { - meows : usize, - - how_hungry : isize, - name : String, -} - -impl Cat { - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } -} - -impl Noisy for Cat { - fn speak(&mut self) { self.meow(); } - -} - -impl Cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> Cat { - Cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - - - -fn main() { - let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; - nyan.eat(); //~ ERROR no method named `eat` found -} diff --git a/tests/ui/class-cast-to-trait.stderr b/tests/ui/class-cast-to-trait.stderr deleted file mode 100644 index 4ea0f41c3ed93..0000000000000 --- a/tests/ui/class-cast-to-trait.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0599]: no method named `eat` found for struct `Box` in the current scope - --> $DIR/class-cast-to-trait.rs:53:8 - | -LL | nyan.eat(); - | ^^^ method not found in `Box` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/class-method-missing.rs b/tests/ui/class-method-missing.rs deleted file mode 100644 index 5dc18328f31ed..0000000000000 --- a/tests/ui/class-method-missing.rs +++ /dev/null @@ -1,21 +0,0 @@ -trait Animal { - fn eat(&self); -} - -struct Cat { - meows: usize, -} - -impl Animal for Cat { - //~^ ERROR not all trait items implemented, missing: `eat` -} - -fn cat(in_x : usize) -> Cat { - Cat { - meows: in_x - } -} - -fn main() { - let nyan = cat(0); -} diff --git a/tests/ui/class-method-missing.stderr b/tests/ui/class-method-missing.stderr deleted file mode 100644 index 42bd22e18a198..0000000000000 --- a/tests/ui/class-method-missing.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0046]: not all trait items implemented, missing: `eat` - --> $DIR/class-method-missing.rs:9:1 - | -LL | fn eat(&self); - | -------------- `eat` from trait -... -LL | impl Animal for Cat { - | ^^^^^^^^^^^^^^^^^^^ missing `eat` in implementation - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/cleanup-rvalue-for-scope.rs b/tests/ui/cleanup-rvalue-for-scope.rs deleted file mode 100644 index 8f5ee8723fd66..0000000000000 --- a/tests/ui/cleanup-rvalue-for-scope.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ run-pass - -#![allow(non_snake_case)] -#![allow(dead_code)] -#![allow(unused_variables)] -// Test that the lifetime of rvalues in for loops is extended -// to the for loop itself. -static mut FLAGS: u64 = 0; - -struct Box { f: T } -struct AddFlags { bits: u64 } - -fn AddFlags(bits: u64) -> AddFlags { - AddFlags { bits: bits } -} - -fn arg(exp: u64, _x: &AddFlags) { - check_flags(exp); -} - -fn pass(v: T) -> T { - v -} - -fn check_flags(exp: u64) { - unsafe { - let x = FLAGS; - FLAGS = 0; - println!("flags {}, expected {}", x, exp); - assert_eq!(x, exp); - } -} - -impl AddFlags { - fn check_flags(&self, exp: u64) -> &AddFlags { - check_flags(exp); - self - } - - fn bits(&self) -> u64 { - self.bits - } -} - -impl Drop for AddFlags { - fn drop(&mut self) { - unsafe { - FLAGS = FLAGS + self.bits; - } - } -} - -pub fn main() { - // The array containing [AddFlags] should not be dropped until - // after the for loop: - for x in &[AddFlags(1)] { - check_flags(0); - } - check_flags(1); -} diff --git a/tests/ui/drop/for-expr-temporary-drop-scope.rs b/tests/ui/drop/for-expr-temporary-drop-scope.rs new file mode 100644 index 0000000000000..c6f80842ee636 --- /dev/null +++ b/tests/ui/drop/for-expr-temporary-drop-scope.rs @@ -0,0 +1,33 @@ +//! Check that temporaries in the for into-iterable expr are not dropped +//! until the end of the for expr. + +//@ run-pass + +static mut FLAGS: u64 = 0; + +struct AddFlags { + bits: u64, +} + +impl Drop for AddFlags { + fn drop(&mut self) { + unsafe { + FLAGS += self.bits; + } + } +} + +fn check_flags(expected: u64) { + unsafe { + let actual = FLAGS; + FLAGS = 0; + assert_eq!(actual, expected, "flags {}, expected {}", actual, expected); + } +} + +fn main() { + for _ in &[AddFlags { bits: 1 }] { + check_flags(0); + } + check_flags(1); +} diff --git a/tests/ui/cenum_impl_drop_cast.rs b/tests/ui/enum/enum-drop-cast-error.rs similarity index 61% rename from tests/ui/cenum_impl_drop_cast.rs rename to tests/ui/enum/enum-drop-cast-error.rs index f681434dd86ac..36101573624d1 100644 --- a/tests/ui/cenum_impl_drop_cast.rs +++ b/tests/ui/enum/enum-drop-cast-error.rs @@ -1,3 +1,7 @@ +//! Check that trying to cast an enum with a Drop impl to an integer is rejected. +//! +//! Issue: + enum E { A = 0, } diff --git a/tests/ui/cenum_impl_drop_cast.stderr b/tests/ui/enum/enum-drop-cast-error.stderr similarity index 81% rename from tests/ui/cenum_impl_drop_cast.stderr rename to tests/ui/enum/enum-drop-cast-error.stderr index 35c69f4b4b785..b58abbd39d38e 100644 --- a/tests/ui/cenum_impl_drop_cast.stderr +++ b/tests/ui/enum/enum-drop-cast-error.stderr @@ -1,5 +1,5 @@ error: cannot cast enum `E` into integer `u32` because it implements `Drop` - --> $DIR/cenum_impl_drop_cast.rs:13:13 + --> $DIR/enum-drop-cast-error.rs:17:13 | LL | let i = e as u32; | ^^^^^^^^ diff --git a/tests/ui/privacy/trait-object-method-error.rs b/tests/ui/privacy/trait-object-method-error.rs new file mode 100644 index 0000000000000..f0214dc636138 --- /dev/null +++ b/tests/ui/privacy/trait-object-method-error.rs @@ -0,0 +1,20 @@ +//! Trait objects only allow access to methods defined in the trait. + +trait MyTrait { + fn trait_method(&mut self); +} + +struct ImplType; + +impl MyTrait for ImplType { + fn trait_method(&mut self) {} +} + +impl ImplType { + fn struct_impl_method(&mut self) {} +} + +fn main() { + let obj: Box = Box::new(ImplType); + obj.struct_impl_method(); //~ ERROR no method named `struct_impl_method` found +} diff --git a/tests/ui/privacy/trait-object-method-error.stderr b/tests/ui/privacy/trait-object-method-error.stderr new file mode 100644 index 0000000000000..40dde8fc47e1b --- /dev/null +++ b/tests/ui/privacy/trait-object-method-error.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `struct_impl_method` found for struct `Box` in the current scope + --> $DIR/trait-object-method-error.rs:19:9 + | +LL | obj.struct_impl_method(); + | ^^^^^^^^^^^^^^^^^^ + | +help: there is a method `trait_method` with a similar name + | +LL - obj.struct_impl_method(); +LL + obj.trait_method(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/traits/trait-impl-missing-method.rs b/tests/ui/traits/trait-impl-missing-method.rs new file mode 100644 index 0000000000000..1f03a332c4a2c --- /dev/null +++ b/tests/ui/traits/trait-impl-missing-method.rs @@ -0,0 +1,13 @@ +//! Trait impls must define all required methods. + +trait MyTrait { + fn trait_method(&self); +} + +struct ImplType; + +impl MyTrait for ImplType {} //~ ERROR not all trait items implemented, missing: `trait_method` + +fn main() { + let _ = ImplType; +} diff --git a/tests/ui/traits/trait-impl-missing-method.stderr b/tests/ui/traits/trait-impl-missing-method.stderr new file mode 100644 index 0000000000000..ae11c3665eed0 --- /dev/null +++ b/tests/ui/traits/trait-impl-missing-method.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `trait_method` + --> $DIR/trait-impl-missing-method.rs:9:1 + | +LL | fn trait_method(&self); + | ----------------------- `trait_method` from trait +... +LL | impl MyTrait for ImplType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `trait_method` in implementation + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. From 64172481da44e0dd6a705afcea22b58b45b42c5a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 4 Jun 2025 08:12:54 +0000 Subject: [PATCH 32/39] Report the actual item that evaluation failed for --- compiler/rustc_const_eval/src/const_eval/eval_queries.rs | 5 +++-- tests/ui/consts/miri_unleashed/assoc_const.stderr | 2 +- tests/ui/consts/uninhabited-const-issue-61744.rs | 1 + tests/ui/consts/uninhabited-const-issue-61744.stderr | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) 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 01625b91353b7..2556e57a58f33 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -454,11 +454,12 @@ fn report_eval_error<'tcx>( // FIXME(oli-obk): figure out how to use structured diagnostics again. diag.code(E0080); diag.span_label(span, crate::fluent_generated::const_eval_error); - diag.arg("instance", instance); - diag.arg("error_kind", kind); for frame in frames { diag.subdiagnostic(frame); } + // Add after the frame rendering above, as it adds its own `instance` args. + diag.arg("instance", instance); + diag.arg("error_kind", kind); }, ) } diff --git a/tests/ui/consts/miri_unleashed/assoc_const.stderr b/tests/ui/consts/miri_unleashed/assoc_const.stderr index b6dcb86f360fd..e843615bd6de7 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const.stderr +++ b/tests/ui/consts/miri_unleashed/assoc_const.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/assoc_const.rs:12:31 | LL | const F: u32 = (U::X, 42).1; - | ^ evaluation of `drop_in_place::> - shim(Some(Vec))` failed here + | ^ evaluation of `, std::string::String>>::F` failed here | note: inside `drop_in_place::<(Vec, u32)> - shim(Some((Vec, u32)))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/uninhabited-const-issue-61744.rs b/tests/ui/consts/uninhabited-const-issue-61744.rs index d33f9c268a51f..698245b5cb8ce 100644 --- a/tests/ui/consts/uninhabited-const-issue-61744.rs +++ b/tests/ui/consts/uninhabited-const-issue-61744.rs @@ -11,6 +11,7 @@ pub const unsafe fn hint_unreachable() -> ! { trait Const { const CONSTANT: i32 = unsafe { fake_type() }; //~ ERROR reached the configured maximum number of stack frames + //~^ NOTE evaluation of `::CONSTANT` failed here } impl Const for T {} diff --git a/tests/ui/consts/uninhabited-const-issue-61744.stderr b/tests/ui/consts/uninhabited-const-issue-61744.stderr index 3c5b5196aebf8..f13f6126e9444 100644 --- a/tests/ui/consts/uninhabited-const-issue-61744.stderr +++ b/tests/ui/consts/uninhabited-const-issue-61744.stderr @@ -2,7 +2,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/uninhabited-const-issue-61744.rs:13:36 | LL | const CONSTANT: i32 = unsafe { fake_type() }; - | ^^^^^^^^^^^ evaluation of `fake_type::` failed here + | ^^^^^^^^^^^ evaluation of `::CONSTANT` failed here | note: inside `fake_type::` --> $DIR/uninhabited-const-issue-61744.rs:5:5 From 55f59fb0e329d0815a06d51dd469d774eb455cba Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 4 Jun 2025 15:51:36 +0000 Subject: [PATCH 33/39] Fix parsing of frontmatters with inner hyphens --- compiler/rustc_lexer/src/lib.rs | 4 +++- tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs | 10 ++++++++++ tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs create mode 100644 tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 2374f38825099..ece3f9107b003 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -545,11 +545,12 @@ impl Cursor<'_> { let mut s = self.as_str(); let mut found = false; + let mut size = 0; while let Some(closing) = s.find(&"-".repeat(length_opening as usize)) { let preceding_chars_start = s[..closing].rfind("\n").map_or(0, |i| i + 1); if s[preceding_chars_start..closing].chars().all(is_whitespace) { // candidate found - self.bump_bytes(closing); + self.bump_bytes(size + closing); // in case like // ---cargo // --- blahblah @@ -562,6 +563,7 @@ impl Cursor<'_> { break; } else { s = &s[closing + length_opening as usize..]; + size += closing + length_opening as usize; } } diff --git a/tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs b/tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs new file mode 100644 index 0000000000000..985b1cfe9884f --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs @@ -0,0 +1,10 @@ +--- +x ---🚧️ +--- + +// Regression test for #141483 +//@check-pass + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs b/tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs new file mode 100644 index 0000000000000..3d5fb4538720b --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs @@ -0,0 +1,11 @@ +--- +x ---y +--- + +// Test that hypens are allowed inside frontmatters if there is some +// non-whitespace character preceding them. +//@check-pass + +#![feature(frontmatter)] + +fn main() {} From e1e3cc24a22d0951e802b413b00bfd104ea22c7e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 4 Jun 2025 08:20:08 +0000 Subject: [PATCH 34/39] Replace the musl submodule with a download script The submodule was causing issues in rust-lang/rust, so eliminiate it here. `build-musl` is also removed from `libm-test`'s default features so the crate doesn't need to be built by default. --- .../.github/workflows/main.yaml | 22 +++++++++---------- library/compiler-builtins/.gitignore | 3 +++ library/compiler-builtins/.gitmodules | 4 ---- library/compiler-builtins/ci/update-musl.sh | 15 +++++++++++++ .../crates/musl-math-sys/build.rs | 2 +- .../crates/musl-math-sys/musl | 1 - .../compiler-builtins/libm-test/Cargo.toml | 2 +- 7 files changed, 30 insertions(+), 19 deletions(-) delete mode 100644 library/compiler-builtins/.gitmodules create mode 100755 library/compiler-builtins/ci/update-musl.sh delete mode 160000 library/compiler-builtins/crates/musl-math-sys/musl diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 9f389d8b48579..95b0962b08241 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -108,8 +108,6 @@ jobs: - name: Print runner information run: uname -a - uses: actions/checkout@v4 - with: - submodules: true - name: Install Rust (rustup) shell: bash run: | @@ -146,6 +144,10 @@ jobs: shell: bash - run: echo "RUST_COMPILER_RT_ROOT=$(realpath ./compiler-rt)" >> "$GITHUB_ENV" shell: bash + + - name: Download musl source + run: ./ci/update-musl.sh + shell: bash - name: Verify API list if: matrix.os == 'ubuntu-24.04' @@ -182,8 +184,6 @@ jobs: 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: | @@ -191,6 +191,8 @@ jobs: rustup default nightly rustup component add clippy - uses: Swatinem/rust-cache@v2 + - name: Download musl source + run: ./ci/update-musl.sh - run: cargo clippy --workspace --all-targets benchmarks: @@ -205,8 +207,6 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@master - with: - submodules: true - uses: taiki-e/install-action@cargo-binstall - name: Set up dependencies @@ -223,6 +223,8 @@ jobs: - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} + - name: Download musl source + run: ./ci/update-musl.sh - name: Run icount benchmarks env: @@ -256,8 +258,6 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 - with: - submodules: true - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly shell: bash @@ -292,8 +292,6 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 - with: - submodules: true - name: Install stable `rustfmt` run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - run: cargo fmt -- --check @@ -317,13 +315,13 @@ jobs: 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: download musl source + run: ./ci/update-musl.sh - name: Run extensive tests run: ./ci/run-extensive.sh - name: Print test logs if available diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore index 5287a6c72be41..f12b871c2f783 100644 --- a/library/compiler-builtins/.gitignore +++ b/library/compiler-builtins/.gitignore @@ -14,3 +14,6 @@ iai-home *.bk *.rs.bk .#* + +# Manually managed +crates/musl-math-sys/musl diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules deleted file mode 100644 index 792ed9ab21f06..0000000000000 --- a/library/compiler-builtins/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[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/ci/update-musl.sh b/library/compiler-builtins/ci/update-musl.sh new file mode 100755 index 0000000000000..b71cf5778300c --- /dev/null +++ b/library/compiler-builtins/ci/update-musl.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Download musl to a repository for `musl-math-sys` + +set -eux + +url=git://git.musl-libc.org/musl +ref=c47ad25ea3b484e10326f933e927c0bc8cded3da +dst=crates/musl-math-sys/musl + +if ! [ -d "$dst" ]; then + git clone "$url" "$dst" --single-branch --depth=1000 +fi + +git -C "$dst" fetch "$url" --depth=1 +git -C "$dst" checkout "$ref" diff --git a/library/compiler-builtins/crates/musl-math-sys/build.rs b/library/compiler-builtins/crates/musl-math-sys/build.rs index b00dbc73e2800..59e42f2d2e67f 100644 --- a/library/compiler-builtins/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/crates/musl-math-sys/build.rs @@ -120,7 +120,7 @@ fn build_musl_math(cfg: &Config) { let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); assert!( math.exists(), - "musl source not found. Is the submodule up to date?" + "musl source not found. You may need to run `./ci/update-musl.sh`." ); let source_map = find_math_source(&math, cfg); diff --git a/library/compiler-builtins/crates/musl-math-sys/musl b/library/compiler-builtins/crates/musl-math-sys/musl deleted file mode 160000 index c47ad25ea3b48..0000000000000 --- a/library/compiler-builtins/crates/musl-math-sys/musl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c47ad25ea3b484e10326f933e927c0bc8cded3da diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 01b45716b7a21..05fcc3234e00b 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -6,7 +6,7 @@ publish = false license = "MIT OR Apache-2.0" [features] -default = ["build-mpfr", "build-musl", "unstable-float"] +default = ["build-mpfr", "unstable-float"] # Propagated from libm because this affects which functions we test. unstable-float = ["libm/unstable-float", "rug?/nightly-float"] From f67ca0fe37eb7de1a6ed748a926122f177ed6472 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 May 2025 14:45:14 +0000 Subject: [PATCH 35/39] Add an empty rust-version file This will be used by `josh` tooling. --- library/compiler-builtins/rust-version | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 library/compiler-builtins/rust-version diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version new file mode 100644 index 0000000000000..e69de29bb2d1d From 3353a891e328715673f7687b3ccc7f90c52d1dca Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 18 May 2025 17:30:58 +0000 Subject: [PATCH 36/39] Add tooling for `josh` syncs Create a crate that handles pulling from and pushing to rust-lang/rust. This can be invoked with the following: $ cargo run -p josh-sync -- rustc-pull $ RUSTC_GIT=/path/to/rust/checkout cargo run -p josh-sync -- rustc-push --- library/compiler-builtins/Cargo.toml | 1 + .../crates/josh-sync/Cargo.toml | 7 + .../crates/josh-sync/src/main.rs | 45 +++ .../crates/josh-sync/src/sync.rs | 371 ++++++++++++++++++ 4 files changed, 424 insertions(+) create mode 100644 library/compiler-builtins/crates/josh-sync/Cargo.toml create mode 100644 library/compiler-builtins/crates/josh-sync/src/main.rs create mode 100644 library/compiler-builtins/crates/josh-sync/src/sync.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index bc6b4bd29795e..fb638f2fb379f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" members = [ "builtins-test", "compiler-builtins", + "crates/josh-sync", "crates/libm-macros", "crates/musl-math-sys", "crates/panic-handler", diff --git a/library/compiler-builtins/crates/josh-sync/Cargo.toml b/library/compiler-builtins/crates/josh-sync/Cargo.toml new file mode 100644 index 0000000000000..1f3bb376d6d91 --- /dev/null +++ b/library/compiler-builtins/crates/josh-sync/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "josh-sync" +edition = "2024" +publish = false + +[dependencies] +directories = "6.0.0" diff --git a/library/compiler-builtins/crates/josh-sync/src/main.rs b/library/compiler-builtins/crates/josh-sync/src/main.rs new file mode 100644 index 0000000000000..7f0b11900337b --- /dev/null +++ b/library/compiler-builtins/crates/josh-sync/src/main.rs @@ -0,0 +1,45 @@ +use std::io::{Read, Write}; +use std::process::exit; +use std::{env, io}; + +use crate::sync::{GitSync, Josh}; + +mod sync; + +const USAGE: &str = r#"Utility for synchroniing compiler-builtins with rust-lang/rust + +Usage: + + josh-sync rustc-pull + + Pull from rust-lang/rust to compiler-builtins. Creates a commit + updating the version file, followed by a merge commit. + + josh-sync rustc-push GITHUB_USERNAME [BRANCH] + + Create a branch off of rust-lang/rust updating compiler-builtins. +"#; + +fn main() { + let sync = GitSync::from_current_dir(); + + // Collect args, then recollect as str refs so we can match on them + let args: Vec<_> = env::args().collect(); + let args: Vec<&str> = args.iter().map(String::as_str).collect(); + + match args.as_slice()[1..] { + ["rustc-pull"] => sync.rustc_pull(None), + ["rustc-push", github_user, branch] => sync.rustc_push(github_user, Some(branch)), + ["rustc-push", github_user] => sync.rustc_push(github_user, None), + ["start-josh"] => { + let _josh = Josh::start(); + println!("press enter to stop"); + io::stdout().flush().unwrap(); + let _ = io::stdin().read(&mut [0u8]).unwrap(); + } + _ => { + println!("{USAGE}"); + exit(1); + } + } +} diff --git a/library/compiler-builtins/crates/josh-sync/src/sync.rs b/library/compiler-builtins/crates/josh-sync/src/sync.rs new file mode 100644 index 0000000000000..003cf187d8301 --- /dev/null +++ b/library/compiler-builtins/crates/josh-sync/src/sync.rs @@ -0,0 +1,371 @@ +use std::net::{SocketAddr, TcpStream}; +use std::process::{Command, Stdio, exit}; +use std::time::Duration; +use std::{env, fs, process, thread}; + +const JOSH_PORT: u16 = 42042; +const DEFAULT_PR_BRANCH: &str = "update-builtins"; + +pub struct GitSync { + upstream_repo: String, + upstream_ref: String, + upstream_url: String, + josh_filter: String, + josh_url_base: String, +} + +/// This code was adapted from the miri repository, via the rustc-dev-guide +/// () +impl GitSync { + pub fn from_current_dir() -> Self { + let upstream_repo = + env::var("UPSTREAM_ORG").unwrap_or_else(|_| "rust-lang".to_owned()) + "/rust"; + + Self { + upstream_url: format!("https://github.com/{upstream_repo}"), + upstream_repo, + upstream_ref: env::var("UPSTREAM_REF").unwrap_or_else(|_| "HEAD".to_owned()), + josh_filter: ":/library/compiler-builtins".to_owned(), + josh_url_base: format!("http://localhost:{JOSH_PORT}"), + } + } + + /// Pull from rust-lang/rust to compiler-builtins. + pub fn rustc_pull(&self, commit: Option) { + let Self { + upstream_ref, + upstream_url, + upstream_repo, + .. + } = self; + + let new_upstream_base = commit.unwrap_or_else(|| { + let out = check_output(["git", "ls-remote", upstream_url, upstream_ref]); + out.split_whitespace() + .next() + .unwrap_or_else(|| panic!("could not split output: '{out}'")) + .to_owned() + }); + + ensure_clean(); + + // Make sure josh is running. + let _josh = Josh::start(); + let josh_url_filtered = self.josh_url( + &self.upstream_repo, + Some(&new_upstream_base), + Some(&self.josh_filter), + ); + + let previous_upstream_base = fs::read_to_string("rust-version") + .expect("failed to read `rust-version`") + .trim() + .to_string(); + assert_ne!(previous_upstream_base, new_upstream_base, "nothing to pull"); + + let orig_head = check_output(["git", "rev-parse", "HEAD"]); + println!("original upstream base: {previous_upstream_base}"); + println!("new upstream base: {new_upstream_base}"); + println!("original HEAD: {orig_head}"); + + // Fetch the latest upstream HEAD so we can get a summary. Use the Josh URL for caching. + run([ + "git", + "fetch", + &self.josh_url(&self.upstream_repo, Some(&new_upstream_base), Some(":/")), + &new_upstream_base, + "--depth=1", + ]); + let new_summary = check_output(["git", "log", "-1", "--format=%h %s", &new_upstream_base]); + + // Update rust-version file. As a separate commit, since making it part of + // the merge has confused the heck out of josh in the past. + // We pass `--no-verify` to avoid running git hooks. + // We do this before the merge so that if there are merge conflicts, we have + // the right rust-version file while resolving them. + fs::write("rust-version", format!("{new_upstream_base}\n")) + .expect("failed to write rust-version"); + + let prep_message = format!( + "Update the upstream Rust version\n\n\ + To prepare for merging from {upstream_repo}, set the version file to:\n\n \ + {new_summary}\n\ + ", + ); + run([ + "git", + "commit", + "rust-version", + "--no-verify", + "-m", + &prep_message, + ]); + + // Fetch given rustc commit. + run(["git", "fetch", &josh_url_filtered]); + let incoming_ref = check_output(["git", "rev-parse", "FETCH_HEAD"]); + println!("incoming ref: {incoming_ref}"); + + let merge_message = format!( + "Merge ref '{upstream_head_short}{filter}' from {upstream_url}\n\n\ + Pull recent changes from {upstream_repo} via Josh.\n\n\ + Upstream ref: {new_upstream_base}\n\ + Filtered ref: {incoming_ref}\n\ + ", + upstream_head_short = &new_upstream_base[..12], + filter = self.josh_filter + ); + + // This should not add any new root commits. So count those before and after merging. + let num_roots = || -> u32 { + let out = check_output(["git", "rev-list", "HEAD", "--max-parents=0", "--count"]); + out.trim() + .parse::() + .unwrap_or_else(|e| panic!("failed to parse `{out}`: {e}")) + }; + let num_roots_before = num_roots(); + + let pre_merge_sha = check_output(["git", "rev-parse", "HEAD"]); + println!("pre-merge HEAD: {pre_merge_sha}"); + + // Merge the fetched commit. + run([ + "git", + "merge", + "FETCH_HEAD", + "--no-verify", + "--no-ff", + "-m", + &merge_message, + ]); + + let current_sha = check_output(["git", "rev-parse", "HEAD"]); + if current_sha == pre_merge_sha { + run(["git", "reset", "--hard", &orig_head]); + eprintln!( + "No merge was performed, no changes to pull were found. \ + Rolled back the preparation commit." + ); + exit(1); + } + + // Check that the number of roots did not increase. + assert_eq!( + num_roots(), + num_roots_before, + "Josh created a new root commit. This is probably not the history you want." + ); + } + + /// Construct an update to rust-lang/rust from compiler-builtins. + pub fn rustc_push(&self, github_user: &str, branch: Option<&str>) { + let Self { + josh_filter, + upstream_url, + .. + } = self; + + let branch = branch.unwrap_or(DEFAULT_PR_BRANCH); + let josh_url = self.josh_url(&format!("{github_user}/rust"), None, Some(josh_filter)); + let user_upstream_url = format!("git@github.com:{github_user}/rust.git"); + + let Ok(rustc_git) = env::var("RUSTC_GIT") else { + panic!("the RUSTC_GIT environment variable must be set to a rust-lang/rust checkout") + }; + + ensure_clean(); + let base = fs::read_to_string("rust-version") + .expect("failed to read `rust-version`") + .trim() + .to_string(); + + // Make sure josh is running. + let _josh = Josh::start(); + + // Prepare the branch. Pushing works much better if we use as base exactly + // the commit that we pulled from last time, so we use the `rust-version` + // file to find out which commit that would be. + println!("Preparing {github_user}/rust (base: {base})..."); + + if Command::new("git") + .args(["-C", &rustc_git, "fetch", &user_upstream_url, branch]) + .output() // capture output + .expect("could not run fetch") + .status + .success() + { + panic!( + "The branch '{branch}' seems to already exist in '{user_upstream_url}'. \ + Please delete it and try again." + ); + } + + run(["git", "-C", &rustc_git, "fetch", upstream_url, &base]); + + run_cfg("git", |c| { + c.args([ + "-C", + &rustc_git, + "push", + &user_upstream_url, + &format!("{base}:refs/heads/{branch}"), + ]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) // silence the "create GitHub PR" message + }); + println!("pushed PR branch"); + + // Do the actual push. + println!("Pushing changes..."); + run(["git", "push", &josh_url, &format!("HEAD:{branch}")]); + println!(); + + // Do a round-trip check to make sure the push worked as expected. + run(["git", "fetch", &josh_url, branch]); + + let head = check_output(["git", "rev-parse", "HEAD"]); + let fetch_head = check_output(["git", "rev-parse", "FETCH_HEAD"]); + assert_eq!( + head, fetch_head, + "Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\ + Expected {head}, got {fetch_head}." + ); + println!( + "Confirmed that the push round-trips back to compiler-builtins properly. Please \ + create a rustc PR:" + ); + // Open PR with `subtree update` title to silence the `no-merges` triagebot check + println!( + " {upstream_url}/compare/{github_user}:{branch}?quick_pull=1\ + &title=Update%20the%20%60compiler-builtins%60%20subtree\ + &body=Update%20the%20Josh%20subtree%20to%20https%3A%2F%2Fgithub.com%2Frust-lang%2F\ + compiler-builtins%2Fcommit%2F{head_short}.%0A%0Ar%3F%20%40ghost", + head_short = &head[..12], + ); + } + + /// Construct a url to the local Josh server with (optionally) + fn josh_url(&self, repo: &str, rev: Option<&str>, filter: Option<&str>) -> String { + format!( + "{base}/{repo}.git{at}{rev}{filter}{filt_git}", + base = self.josh_url_base, + at = if rev.is_some() { "@" } else { "" }, + rev = rev.unwrap_or_default(), + filter = filter.unwrap_or_default(), + filt_git = if filter.is_some() { ".git" } else { "" } + ) + } +} + +/// Fail if there are files that need to be checked in. +fn ensure_clean() { + let read = check_output(["git", "status", "--untracked-files=no", "--porcelain"]); + assert!( + read.is_empty(), + "working directory must be clean before performing rustc pull" + ); +} + +/* Helpers for running commands with logged invocations */ + +/// Run a command from an array, passing its output through. +fn run<'a, Args: AsRef<[&'a str]>>(l: Args) { + let l = l.as_ref(); + run_cfg(l[0], |c| c.args(&l[1..])); +} + +/// Run a command from an array, collecting its output. +fn check_output<'a, Args: AsRef<[&'a str]>>(l: Args) -> String { + let l = l.as_ref(); + check_output_cfg(l[0], |c| c.args(&l[1..])) +} + +/// [`run`] with configuration. +fn run_cfg(prog: &str, f: impl FnOnce(&mut Command) -> &mut Command) { + // self.read(l.as_ref()); + check_output_cfg(prog, |c| f(c.stdout(Stdio::inherit()))); +} + +/// [`read`] with configuration. All shell helpers print the command and pass stderr. +fn check_output_cfg(prog: &str, f: impl FnOnce(&mut Command) -> &mut Command) -> String { + let mut cmd = Command::new(prog); + cmd.stderr(Stdio::inherit()); + f(&mut cmd); + eprintln!("+ {cmd:?}"); + let out = cmd.output().expect("command failed"); + assert!(out.status.success()); + String::from_utf8(out.stdout.trim_ascii().to_vec()).expect("non-UTF8 output") +} + +/// Create a wrapper that stops Josh on drop. +pub struct Josh(process::Child); + +impl Josh { + pub fn start() -> Self { + // Determine cache directory. + let user_dirs = + directories::ProjectDirs::from("org", "rust-lang", "rustc-compiler-builtins-josh") + .unwrap(); + let local_dir = user_dirs.cache_dir().to_owned(); + + // Start josh, silencing its output. + #[expect(clippy::zombie_processes, reason = "clippy can't handle the loop")] + let josh = process::Command::new("josh-proxy") + .arg("--local") + .arg(local_dir) + .args([ + "--remote=https://github.com", + &format!("--port={JOSH_PORT}"), + "--no-background", + ]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("failed to start josh-proxy, make sure it is installed"); + + // Wait until the port is open. We try every 10ms until 1s passed. + for _ in 0..100 { + // This will generally fail immediately when the port is still closed. + let addr = SocketAddr::from(([127, 0, 0, 1], JOSH_PORT)); + let josh_ready = TcpStream::connect_timeout(&addr, Duration::from_millis(1)); + + if josh_ready.is_ok() { + println!("josh up and running"); + return Josh(josh); + } + + // Not ready yet. + thread::sleep(Duration::from_millis(10)); + } + panic!("Even after waiting for 1s, josh-proxy is still not available.") + } +} + +impl Drop for Josh { + fn drop(&mut self) { + if cfg!(unix) { + // Try to gracefully shut it down. + Command::new("kill") + .args(["-s", "INT", &self.0.id().to_string()]) + .output() + .expect("failed to SIGINT josh-proxy"); + // Sadly there is no "wait with timeout"... so we just give it some time to finish. + thread::sleep(Duration::from_millis(100)); + // Now hopefully it is gone. + if self + .0 + .try_wait() + .expect("failed to wait for josh-proxy") + .is_some() + { + return; + } + } + // If that didn't work (or we're not on Unix), kill it hard. + eprintln!( + "I have to kill josh-proxy the hard way, let's hope this does not \ + break anything." + ); + self.0.kill().expect("failed to SIGKILL josh-proxy"); + } +} From eb45e57afe52ba549a3929b58dc9060541bf0a20 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 4 Jun 2025 18:10:07 +0000 Subject: [PATCH 37/39] Update the upstream Rust version To prepare for merging from rust-lang/rust, set the version file to: df8102fe5f Auto merge of #142002 - onur-ozkan:follow-ups2, r=jieyouxu --- library/compiler-builtins/rust-version | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index e69de29bb2d1d..e05aaa0573cab 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -0,0 +1 @@ +df8102fe5f24f28a918660b0cd918d7331c3896e From ab453db3c4e7a49d0ed3811c12ae658cf578f78b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 4 Jun 2025 21:17:51 +0000 Subject: [PATCH 38/39] `panic-handler`: Remove the `no_core` feature This was introduced before `#[panic_handler]` was stable, but should no longer be needed. Additionally, we only need it for `builtins-test-intrinsics`, not as a dependency of `compiler-builtins`. --- .../compiler-builtins/builtins-test-intrinsics/Cargo.toml | 2 +- library/compiler-builtins/compiler-builtins/Cargo.toml | 3 --- library/compiler-builtins/crates/panic-handler/src/lib.rs | 7 ++----- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 704de20c5ad64..064b7cad2f64b 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -6,7 +6,7 @@ publish = false license = "MIT OR Apache-2.0" [dependencies] -compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"]} +compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"] } panic-handler = { path = "../crates/panic-handler" } [features] diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 6bee8da68a0a2..11ee919543841 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -24,9 +24,6 @@ core = { version = "1.0.1", optional = true, package = "rustc-std-workspace-core [build-dependencies] cc = { optional = true, version = "1.2" } -[dev-dependencies] -panic-handler = { path = "../crates/panic-handler" } - [features] default = ["compiler-builtins"] diff --git a/library/compiler-builtins/crates/panic-handler/src/lib.rs b/library/compiler-builtins/crates/panic-handler/src/lib.rs index 673e005224bd0..f4d7c839740b5 100644 --- a/library/compiler-builtins/crates/panic-handler/src/lib.rs +++ b/library/compiler-builtins/crates/panic-handler/src/lib.rs @@ -1,11 +1,8 @@ //! This is needed for tests on targets that require a `#[panic_handler]` function -#![feature(no_core)] -#![no_core] - -extern crate core; +#![no_std] #[panic_handler] -fn panic(_: &core::panic::PanicInfo) -> ! { +fn panic(_: &core::panic::PanicInfo<'_>) -> ! { loop {} } From 91ad4bf08784916edfb4e498c3749bed76b0686a Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Thu, 5 Jun 2025 11:33:38 +0000 Subject: [PATCH 39/39] jsondocck: Explain what `KNOWN_DIRECTIVE_NAMES` is doing --- src/tools/jsondocck/src/directive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/jsondocck/src/directive.rs b/src/tools/jsondocck/src/directive.rs index 5269ffb469fa9..fdb2fa6dbbe01 100644 --- a/src/tools/jsondocck/src/directive.rs +++ b/src/tools/jsondocck/src/directive.rs @@ -105,7 +105,7 @@ impl DirectiveKind { [_path, value] => Self::HasNotValue { value: value.clone() }, _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"), }, - + // Ignore compiletest directives, like //@ edition (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&directive_name) => { return None; }