From 59e5920e298d7690d455b13adf31b11485b25dcd Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Wed, 5 Mar 2025 15:28:38 -0800 Subject: [PATCH 001/222] Reject test executables when not supported by target Currently, compiling tests for SOLID produces an ICE, because SOLID does not support executables. --- compiler/rustc_session/src/output.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index b37a80274c0c..2b7420cb1b27 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -177,6 +177,13 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec Date: Wed, 26 Mar 2025 11:27:52 +0800 Subject: [PATCH 002/222] Add ui test cast-array-issue-138836 Signed-off-by: xizheyin --- tests/ui/cast/cast-array-issue-138836.rs | 5 +++++ tests/ui/cast/cast-array-issue-138836.stderr | 12 ++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/ui/cast/cast-array-issue-138836.rs create mode 100644 tests/ui/cast/cast-array-issue-138836.stderr diff --git a/tests/ui/cast/cast-array-issue-138836.rs b/tests/ui/cast/cast-array-issue-138836.rs new file mode 100644 index 000000000000..6fd65d5878ac --- /dev/null +++ b/tests/ui/cast/cast-array-issue-138836.rs @@ -0,0 +1,5 @@ +fn main() { + let a: [u8; 3] = [1,2,3]; + let b = &a; + let c = b as *const [u32; 3]; //~ ERROR mismatched types [E0308] +} diff --git a/tests/ui/cast/cast-array-issue-138836.stderr b/tests/ui/cast/cast-array-issue-138836.stderr new file mode 100644 index 000000000000..fe20d429a498 --- /dev/null +++ b/tests/ui/cast/cast-array-issue-138836.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/cast-array-issue-138836.rs:4:13 + | +LL | let c = b as *const [u32; 3]; + | ^^^^^^^^^^^^^^^^^^^^ expected `[u8; 3]`, found `[u32; 3]` + | + = note: expected array `[u8; 3]` + found array `[u32; 3]` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From a34c42fefabc774af2d8b2c5a5a100c0697d2ba9 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Wed, 26 Mar 2025 11:31:58 +0800 Subject: [PATCH 003/222] Expect an array when expected and acutal types are both arrays during cast Signed-off-by: xizheyin --- compiler/rustc_hir_typeck/src/cast.rs | 37 ++++++++++---------- tests/ui/cast/cast-array-issue-138836.rs | 2 +- tests/ui/cast/cast-array-issue-138836.stderr | 9 ++--- tests/ui/consts/const-cast-wrong-type.rs | 2 +- tests/ui/consts/const-cast-wrong-type.stderr | 6 ++-- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 8f5fddd19d7f..b19d9efe2c6f 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -1042,30 +1042,31 @@ impl<'a, 'tcx> CastCheck<'tcx> { m_cast: ty::TypeAndMut<'tcx>, ) -> Result> { // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const - if m_expr.mutbl >= m_cast.mutbl { - if let ty::Array(ety, _) = m_expr.ty.kind() { - // Due to the limitations of LLVM global constants, - // region pointers end up pointing at copies of - // vector elements instead of the original values. - // To allow raw pointers to work correctly, we - // need to special-case obtaining a raw pointer - // from a region pointer to a vector. + if m_expr.mutbl >= m_cast.mutbl + && let ty::Array(ety, _) = m_expr.ty.kind() + && fcx.can_eq(fcx.param_env, *ety, m_cast.ty) + { + // Due to the limitations of LLVM global constants, + // region pointers end up pointing at copies of + // vector elements instead of the original values. + // To allow raw pointers to work correctly, we + // need to special-case obtaining a raw pointer + // from a region pointer to a vector. - // Coerce to a raw pointer so that we generate RawPtr in MIR. - let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl); - fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) - .unwrap_or_else(|_| { - bug!( + // Coerce to a raw pointer so that we generate RawPtr in MIR. + let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl); + fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) + .unwrap_or_else(|_| { + bug!( "could not cast from reference to array to pointer to array ({:?} to {:?})", self.expr_ty, array_ptr_type, ) - }); + }); - // this will report a type mismatch if needed - fcx.demand_eqtype(self.span, *ety, m_cast.ty); - return Ok(CastKind::ArrayPtrCast); - } + // this will report a type mismatch if needed + fcx.demand_eqtype(self.span, *ety, m_cast.ty); + return Ok(CastKind::ArrayPtrCast); } Err(CastError::IllegalCast) diff --git a/tests/ui/cast/cast-array-issue-138836.rs b/tests/ui/cast/cast-array-issue-138836.rs index 6fd65d5878ac..3f8098e76fd2 100644 --- a/tests/ui/cast/cast-array-issue-138836.rs +++ b/tests/ui/cast/cast-array-issue-138836.rs @@ -1,5 +1,5 @@ fn main() { let a: [u8; 3] = [1,2,3]; let b = &a; - let c = b as *const [u32; 3]; //~ ERROR mismatched types [E0308] + let c = b as *const [u32; 3]; //~ ERROR casting `&[u8; 3]` as `*const [u32; 3]` is invalid } diff --git a/tests/ui/cast/cast-array-issue-138836.stderr b/tests/ui/cast/cast-array-issue-138836.stderr index fe20d429a498..309474c29f93 100644 --- a/tests/ui/cast/cast-array-issue-138836.stderr +++ b/tests/ui/cast/cast-array-issue-138836.stderr @@ -1,12 +1,9 @@ -error[E0308]: mismatched types +error[E0606]: casting `&[u8; 3]` as `*const [u32; 3]` is invalid --> $DIR/cast-array-issue-138836.rs:4:13 | LL | let c = b as *const [u32; 3]; - | ^^^^^^^^^^^^^^^^^^^^ expected `[u8; 3]`, found `[u32; 3]` - | - = note: expected array `[u8; 3]` - found array `[u32; 3]` + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/consts/const-cast-wrong-type.rs b/tests/ui/consts/const-cast-wrong-type.rs index 6e055a2bcd34..9936a660936b 100644 --- a/tests/ui/consts/const-cast-wrong-type.rs +++ b/tests/ui/consts/const-cast-wrong-type.rs @@ -1,5 +1,5 @@ const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8]; -const b: *const i8 = &a as *const i8; //~ ERROR mismatched types +const b: *const i8 = &a as *const i8; //~ ERROR casting `&[u8; 3]` as `*const i8` is invalid fn main() { } diff --git a/tests/ui/consts/const-cast-wrong-type.stderr b/tests/ui/consts/const-cast-wrong-type.stderr index 44361f15d8a9..0730bac22354 100644 --- a/tests/ui/consts/const-cast-wrong-type.stderr +++ b/tests/ui/consts/const-cast-wrong-type.stderr @@ -1,9 +1,9 @@ -error[E0308]: mismatched types +error[E0606]: casting `&[u8; 3]` as `*const i8` is invalid --> $DIR/const-cast-wrong-type.rs:2:22 | LL | const b: *const i8 = &a as *const i8; - | ^^^^^^^^^^^^^^^ expected `u8`, found `i8` + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0606`. From 3a4dd1b7b279435b4289b9b9a45db6647f1d3f9c Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 29 Mar 2025 13:08:18 +0100 Subject: [PATCH 004/222] std: make `cmath` functions safe --- library/std/src/f128.rs | 32 +++++----- library/std/src/f16.rs | 32 +++++----- library/std/src/f32.rs | 34 +++++----- library/std/src/f64.rs | 34 +++++----- library/std/src/sys/cmath.rs | 118 +++++++++++++++++------------------ 5 files changed, 125 insertions(+), 125 deletions(-) diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index ede219690511..217528fdf1c1 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -666,7 +666,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cbrt(self) -> f128 { - unsafe { cmath::cbrtf128(self) } + cmath::cbrtf128(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -703,7 +703,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn hypot(self, other: f128) -> f128 { - unsafe { cmath::hypotf128(self, other) } + cmath::hypotf128(self, other) } /// Computes the sine of a number (in radians). @@ -789,7 +789,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tan(self) -> f128 { - unsafe { cmath::tanf128(self) } + cmath::tanf128(self) } /// Computes the arcsine of a number. Return value is in radians in @@ -824,7 +824,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn asin(self) -> f128 { - unsafe { cmath::asinf128(self) } + cmath::asinf128(self) } /// Computes the arccosine of a number. Return value is in radians in @@ -859,7 +859,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn acos(self) -> f128 { - unsafe { cmath::acosf128(self) } + cmath::acosf128(self) } /// Computes the arctangent of a number. Return value is in radians in the @@ -893,7 +893,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan(self) -> f128 { - unsafe { cmath::atanf128(self) } + cmath::atanf128(self) } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -939,7 +939,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan2(self, other: f128) -> f128 { - unsafe { cmath::atan2f128(self, other) } + cmath::atan2f128(self, other) } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -1008,7 +1008,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp_m1(self) -> f128 { - unsafe { cmath::expm1f128(self) } + cmath::expm1f128(self) } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -1055,7 +1055,7 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] pub fn ln_1p(self) -> f128 { - unsafe { cmath::log1pf128(self) } + cmath::log1pf128(self) } /// Hyperbolic sine function. @@ -1090,7 +1090,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sinh(self) -> f128 { - unsafe { cmath::sinhf128(self) } + cmath::sinhf128(self) } /// Hyperbolic cosine function. @@ -1125,7 +1125,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cosh(self) -> f128 { - unsafe { cmath::coshf128(self) } + cmath::coshf128(self) } /// Hyperbolic tangent function. @@ -1160,7 +1160,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tanh(self) -> f128 { - unsafe { cmath::tanhf128(self) } + cmath::tanhf128(self) } /// Inverse hyperbolic sine function. @@ -1289,7 +1289,7 @@ impl f128 { // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn gamma(self) -> f128 { - unsafe { cmath::tgammaf128(self) } + cmath::tgammaf128(self) } /// Natural logarithm of the absolute value of the gamma function @@ -1325,7 +1325,7 @@ impl f128 { #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_gamma(self) -> (f128, i32) { let mut signgamp: i32 = 0; - let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) }; + let x = cmath::lgammaf128_r(self, &mut signgamp); (x, signgamp) } @@ -1365,7 +1365,7 @@ impl f128 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f128 { - unsafe { cmath::erff128(self) } + cmath::erff128(self) } /// Complementary error function. @@ -1398,6 +1398,6 @@ impl f128 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f128 { - unsafe { cmath::erfcf128(self) } + cmath::erfcf128(self) } } diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index 286993d736b9..4dadcbb51855 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -665,7 +665,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cbrt(self) -> f16 { - (unsafe { cmath::cbrtf(self as f32) }) as f16 + cmath::cbrtf(self as f32) as f16 } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -701,7 +701,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn hypot(self, other: f16) -> f16 { - (unsafe { cmath::hypotf(self as f32, other as f32) }) as f16 + cmath::hypotf(self as f32, other as f32) as f16 } /// Computes the sine of a number (in radians). @@ -787,7 +787,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tan(self) -> f16 { - (unsafe { cmath::tanf(self as f32) }) as f16 + cmath::tanf(self as f32) as f16 } /// Computes the arcsine of a number. Return value is in radians in @@ -822,7 +822,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn asin(self) -> f16 { - (unsafe { cmath::asinf(self as f32) }) as f16 + cmath::asinf(self as f32) as f16 } /// Computes the arccosine of a number. Return value is in radians in @@ -857,7 +857,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn acos(self) -> f16 { - (unsafe { cmath::acosf(self as f32) }) as f16 + cmath::acosf(self as f32) as f16 } /// Computes the arctangent of a number. Return value is in radians in the @@ -891,7 +891,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan(self) -> f16 { - (unsafe { cmath::atanf(self as f32) }) as f16 + cmath::atanf(self as f32) as f16 } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -937,7 +937,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan2(self, other: f16) -> f16 { - (unsafe { cmath::atan2f(self as f32, other as f32) }) as f16 + cmath::atan2f(self as f32, other as f32) as f16 } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -1006,7 +1006,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp_m1(self) -> f16 { - (unsafe { cmath::expm1f(self as f32) }) as f16 + cmath::expm1f(self as f32) as f16 } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -1053,7 +1053,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_1p(self) -> f16 { - (unsafe { cmath::log1pf(self as f32) }) as f16 + cmath::log1pf(self as f32) as f16 } /// Hyperbolic sine function. @@ -1088,7 +1088,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sinh(self) -> f16 { - (unsafe { cmath::sinhf(self as f32) }) as f16 + cmath::sinhf(self as f32) as f16 } /// Hyperbolic cosine function. @@ -1123,7 +1123,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cosh(self) -> f16 { - (unsafe { cmath::coshf(self as f32) }) as f16 + cmath::coshf(self as f32) as f16 } /// Hyperbolic tangent function. @@ -1158,7 +1158,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tanh(self) -> f16 { - (unsafe { cmath::tanhf(self as f32) }) as f16 + cmath::tanhf(self as f32) as f16 } /// Inverse hyperbolic sine function. @@ -1287,7 +1287,7 @@ impl f16 { // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn gamma(self) -> f16 { - (unsafe { cmath::tgammaf(self as f32) }) as f16 + cmath::tgammaf(self as f32) as f16 } /// Natural logarithm of the absolute value of the gamma function @@ -1323,7 +1323,7 @@ impl f16 { #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_gamma(self) -> (f16, i32) { let mut signgamp: i32 = 0; - let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16; + let x = cmath::lgammaf_r(self as f32, &mut signgamp) as f16; (x, signgamp) } @@ -1363,7 +1363,7 @@ impl f16 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f16 { - (unsafe { cmath::erff(self as f32) }) as f16 + cmath::erff(self as f32) as f16 } /// Complementary error function. @@ -1396,6 +1396,6 @@ impl f16 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f16 { - (unsafe { cmath::erfcf(self as f32) }) as f16 + cmath::erfcf(self as f32) as f16 } } diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 980e7f7793af..baf7002f3803 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -599,7 +599,7 @@ impl f32 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f32) -> f32 { - unsafe { cmath::fdimf(self, other) } + cmath::fdimf(self, other) } /// Returns the cube root of a number. @@ -626,7 +626,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f32 { - unsafe { cmath::cbrtf(self) } + cmath::cbrtf(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -657,7 +657,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn hypot(self, other: f32) -> f32 { - unsafe { cmath::hypotf(self, other) } + cmath::hypotf(self, other) } /// Computes the sine of a number (in radians). @@ -730,7 +730,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tan(self) -> f32 { - unsafe { cmath::tanf(self) } + cmath::tanf(self) } /// Computes the arcsine of a number. Return value is in radians in @@ -760,7 +760,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asin(self) -> f32 { - unsafe { cmath::asinf(self) } + cmath::asinf(self) } /// Computes the arccosine of a number. Return value is in radians in @@ -790,7 +790,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acos(self) -> f32 { - unsafe { cmath::acosf(self) } + cmath::acosf(self) } /// Computes the arctangent of a number. Return value is in radians in the @@ -819,7 +819,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan(self) -> f32 { - unsafe { cmath::atanf(self) } + cmath::atanf(self) } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -860,7 +860,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan2(self, other: f32) -> f32 { - unsafe { cmath::atan2f(self, other) } + cmath::atan2f(self, other) } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -919,7 +919,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp_m1(self) -> f32 { - unsafe { cmath::expm1f(self) } + cmath::expm1f(self) } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -957,7 +957,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln_1p(self) -> f32 { - unsafe { cmath::log1pf(self) } + cmath::log1pf(self) } /// Hyperbolic sine function. @@ -987,7 +987,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sinh(self) -> f32 { - unsafe { cmath::sinhf(self) } + cmath::sinhf(self) } /// Hyperbolic cosine function. @@ -1017,7 +1017,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cosh(self) -> f32 { - unsafe { cmath::coshf(self) } + cmath::coshf(self) } /// Hyperbolic tangent function. @@ -1047,7 +1047,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tanh(self) -> f32 { - unsafe { cmath::tanhf(self) } + cmath::tanhf(self) } /// Inverse hyperbolic sine function. @@ -1158,7 +1158,7 @@ impl f32 { #[unstable(feature = "float_gamma", issue = "99842")] #[inline] pub fn gamma(self) -> f32 { - unsafe { cmath::tgammaf(self) } + cmath::tgammaf(self) } /// Natural logarithm of the absolute value of the gamma function @@ -1188,7 +1188,7 @@ impl f32 { #[inline] pub fn ln_gamma(self) -> (f32, i32) { let mut signgamp: i32 = 0; - let x = unsafe { cmath::lgammaf_r(self, &mut signgamp) }; + let x = cmath::lgammaf_r(self, &mut signgamp); (x, signgamp) } @@ -1224,7 +1224,7 @@ impl f32 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f32 { - unsafe { cmath::erff(self) } + cmath::erff(self) } /// Complementary error function. @@ -1253,6 +1253,6 @@ impl f32 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f32 { - unsafe { cmath::erfcf(self) } + cmath::erfcf(self) } } diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 2aaab3ffc835..84fd9bfb7b68 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -599,7 +599,7 @@ impl f64 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f64) -> f64 { - unsafe { cmath::fdim(self, other) } + cmath::fdim(self, other) } /// Returns the cube root of a number. @@ -626,7 +626,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f64 { - unsafe { cmath::cbrt(self) } + cmath::cbrt(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -657,7 +657,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn hypot(self, other: f64) -> f64 { - unsafe { cmath::hypot(self, other) } + cmath::hypot(self, other) } /// Computes the sine of a number (in radians). @@ -730,7 +730,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tan(self) -> f64 { - unsafe { cmath::tan(self) } + cmath::tan(self) } /// Computes the arcsine of a number. Return value is in radians in @@ -760,7 +760,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asin(self) -> f64 { - unsafe { cmath::asin(self) } + cmath::asin(self) } /// Computes the arccosine of a number. Return value is in radians in @@ -790,7 +790,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acos(self) -> f64 { - unsafe { cmath::acos(self) } + cmath::acos(self) } /// Computes the arctangent of a number. Return value is in radians in the @@ -819,7 +819,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan(self) -> f64 { - unsafe { cmath::atan(self) } + cmath::atan(self) } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -860,7 +860,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan2(self, other: f64) -> f64 { - unsafe { cmath::atan2(self, other) } + cmath::atan2(self, other) } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -919,7 +919,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp_m1(self) -> f64 { - unsafe { cmath::expm1(self) } + cmath::expm1(self) } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -957,7 +957,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln_1p(self) -> f64 { - unsafe { cmath::log1p(self) } + cmath::log1p(self) } /// Hyperbolic sine function. @@ -987,7 +987,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sinh(self) -> f64 { - unsafe { cmath::sinh(self) } + cmath::sinh(self) } /// Hyperbolic cosine function. @@ -1017,7 +1017,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cosh(self) -> f64 { - unsafe { cmath::cosh(self) } + cmath::cosh(self) } /// Hyperbolic tangent function. @@ -1047,7 +1047,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tanh(self) -> f64 { - unsafe { cmath::tanh(self) } + cmath::tanh(self) } /// Inverse hyperbolic sine function. @@ -1158,7 +1158,7 @@ impl f64 { #[unstable(feature = "float_gamma", issue = "99842")] #[inline] pub fn gamma(self) -> f64 { - unsafe { cmath::tgamma(self) } + cmath::tgamma(self) } /// Natural logarithm of the absolute value of the gamma function @@ -1188,7 +1188,7 @@ impl f64 { #[inline] pub fn ln_gamma(self) -> (f64, i32) { let mut signgamp: i32 = 0; - let x = unsafe { cmath::lgamma_r(self, &mut signgamp) }; + let x = cmath::lgamma_r(self, &mut signgamp); (x, signgamp) } @@ -1224,7 +1224,7 @@ impl f64 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f64 { - unsafe { cmath::erf(self) } + cmath::erf(self) } /// Complementary error function. @@ -1253,6 +1253,6 @@ impl f64 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f64 { - unsafe { cmath::erfc(self) } + cmath::erfc(self) } } diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs index c9969b4e376e..668fd9285340 100644 --- a/library/std/src/sys/cmath.rs +++ b/library/std/src/sys/cmath.rs @@ -3,70 +3,70 @@ // These symbols are all defined by `libm`, // or by `compiler-builtins` on unsupported platforms. unsafe extern "C" { - pub fn acos(n: f64) -> f64; - pub fn asin(n: f64) -> f64; - pub fn atan(n: f64) -> f64; - pub fn atan2(a: f64, b: f64) -> f64; - pub fn cbrt(n: f64) -> f64; - pub fn cbrtf(n: f32) -> f32; - pub fn cosh(n: f64) -> f64; - pub fn expm1(n: f64) -> f64; - pub fn expm1f(n: f32) -> f32; - pub fn fdim(a: f64, b: f64) -> f64; - pub fn fdimf(a: f32, b: f32) -> f32; + pub safe fn acos(n: f64) -> f64; + pub safe fn asin(n: f64) -> f64; + pub safe fn atan(n: f64) -> f64; + pub safe fn atan2(a: f64, b: f64) -> f64; + pub safe fn cbrt(n: f64) -> f64; + pub safe fn cbrtf(n: f32) -> f32; + pub safe fn cosh(n: f64) -> f64; + pub safe fn expm1(n: f64) -> f64; + pub safe fn expm1f(n: f32) -> f32; + pub safe fn fdim(a: f64, b: f64) -> f64; + pub safe fn fdimf(a: f32, b: f32) -> f32; #[cfg_attr(target_env = "msvc", link_name = "_hypot")] - pub fn hypot(x: f64, y: f64) -> f64; + pub safe fn hypot(x: f64, y: f64) -> f64; #[cfg_attr(target_env = "msvc", link_name = "_hypotf")] - pub fn hypotf(x: f32, y: f32) -> f32; - pub fn log1p(n: f64) -> f64; - pub fn log1pf(n: f32) -> f32; - pub fn sinh(n: f64) -> f64; - pub fn tan(n: f64) -> f64; - pub fn tanh(n: f64) -> f64; - pub fn tgamma(n: f64) -> f64; - pub fn tgammaf(n: f32) -> f32; - pub fn lgamma_r(n: f64, s: &mut i32) -> f64; + pub safe fn hypotf(x: f32, y: f32) -> f32; + pub safe fn log1p(n: f64) -> f64; + pub safe fn log1pf(n: f32) -> f32; + pub safe fn sinh(n: f64) -> f64; + pub safe fn tan(n: f64) -> f64; + pub safe fn tanh(n: f64) -> f64; + pub safe fn tgamma(n: f64) -> f64; + pub safe fn tgammaf(n: f32) -> f32; + pub safe fn lgamma_r(n: f64, s: &mut i32) -> f64; #[cfg(not(target_os = "aix"))] - pub fn lgammaf_r(n: f32, s: &mut i32) -> f32; - pub fn erf(n: f64) -> f64; - pub fn erff(n: f32) -> f32; - pub fn erfc(n: f64) -> f64; - pub fn erfcf(n: f32) -> f32; + pub safe fn lgammaf_r(n: f32, s: &mut i32) -> f32; + pub safe fn erf(n: f64) -> f64; + pub safe fn erff(n: f32) -> f32; + pub safe fn erfc(n: f64) -> f64; + pub safe fn erfcf(n: f32) -> f32; - pub fn acosf128(n: f128) -> f128; - pub fn asinf128(n: f128) -> f128; - pub fn atanf128(n: f128) -> f128; - pub fn atan2f128(a: f128, b: f128) -> f128; - pub fn cbrtf128(n: f128) -> f128; - pub fn coshf128(n: f128) -> f128; - pub fn expm1f128(n: f128) -> f128; - pub fn hypotf128(x: f128, y: f128) -> f128; - pub fn log1pf128(n: f128) -> f128; - pub fn sinhf128(n: f128) -> f128; - pub fn tanf128(n: f128) -> f128; - pub fn tanhf128(n: f128) -> f128; - pub fn tgammaf128(n: f128) -> f128; - pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128; - pub fn erff128(n: f128) -> f128; - pub fn erfcf128(n: f128) -> f128; + pub safe fn acosf128(n: f128) -> f128; + pub safe fn asinf128(n: f128) -> f128; + pub safe fn atanf128(n: f128) -> f128; + pub safe fn atan2f128(a: f128, b: f128) -> f128; + pub safe fn cbrtf128(n: f128) -> f128; + pub safe fn coshf128(n: f128) -> f128; + pub safe fn expm1f128(n: f128) -> f128; + pub safe fn hypotf128(x: f128, y: f128) -> f128; + pub safe fn log1pf128(n: f128) -> f128; + pub safe fn sinhf128(n: f128) -> f128; + pub safe fn tanf128(n: f128) -> f128; + pub safe fn tanhf128(n: f128) -> f128; + pub safe fn tgammaf128(n: f128) -> f128; + pub safe fn lgammaf128_r(n: f128, s: &mut i32) -> f128; + pub safe fn erff128(n: f128) -> f128; + pub safe fn erfcf128(n: f128) -> f128; cfg_if::cfg_if! { if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] { - pub fn acosf(n: f32) -> f32; - pub fn asinf(n: f32) -> f32; - pub fn atan2f(a: f32, b: f32) -> f32; - pub fn atanf(n: f32) -> f32; - pub fn coshf(n: f32) -> f32; - pub fn sinhf(n: f32) -> f32; - pub fn tanf(n: f32) -> f32; - pub fn tanhf(n: f32) -> f32; + pub safe fn acosf(n: f32) -> f32; + pub safe fn asinf(n: f32) -> f32; + pub safe fn atan2f(a: f32, b: f32) -> f32; + pub safe fn atanf(n: f32) -> f32; + pub safe fn coshf(n: f32) -> f32; + pub safe fn sinhf(n: f32) -> f32; + pub safe fn tanf(n: f32) -> f32; + pub safe fn tanhf(n: f32) -> f32; }} } // On AIX, we don't have lgammaf_r only the f64 version, so we can // use the f64 version lgamma_r #[cfg(target_os = "aix")] -pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 { +pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 { lgamma_r(n.into(), s) as f32 } @@ -76,42 +76,42 @@ pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 { cfg_if::cfg_if! { if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] { #[inline] - pub unsafe fn acosf(n: f32) -> f32 { + pub fn acosf(n: f32) -> f32 { f64::acos(n as f64) as f32 } #[inline] - pub unsafe fn asinf(n: f32) -> f32 { + pub fn asinf(n: f32) -> f32 { f64::asin(n as f64) as f32 } #[inline] - pub unsafe fn atan2f(n: f32, b: f32) -> f32 { + pub fn atan2f(n: f32, b: f32) -> f32 { f64::atan2(n as f64, b as f64) as f32 } #[inline] - pub unsafe fn atanf(n: f32) -> f32 { + pub fn atanf(n: f32) -> f32 { f64::atan(n as f64) as f32 } #[inline] - pub unsafe fn coshf(n: f32) -> f32 { + pub fn coshf(n: f32) -> f32 { f64::cosh(n as f64) as f32 } #[inline] - pub unsafe fn sinhf(n: f32) -> f32 { + pub fn sinhf(n: f32) -> f32 { f64::sinh(n as f64) as f32 } #[inline] - pub unsafe fn tanf(n: f32) -> f32 { + pub fn tanf(n: f32) -> f32 { f64::tan(n as f64) as f32 } #[inline] - pub unsafe fn tanhf(n: f32) -> f32 { + pub fn tanhf(n: f32) -> f32 { f64::tanh(n as f64) as f32 } }} From 18c787f48f08352ad5167b99920c395e3d703f62 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 30 Mar 2025 04:21:20 +0000 Subject: [PATCH 005/222] Fix up partial res of segment in primitive resolution hack --- compiler/rustc_resolve/src/late.rs | 5 +++++ tests/ui/resolve/auxiliary/empty.rs | 1 + tests/ui/resolve/prim-crate-partial-res.rs | 8 ++++++++ tests/ui/resolve/prim-crate-partial-res.stderr | 17 +++++++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 tests/ui/resolve/auxiliary/empty.rs create mode 100644 tests/ui/resolve/prim-crate-partial-res.rs create mode 100644 tests/ui/resolve/prim-crate-partial-res.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0d23ae501f04..606d25c558a1 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4598,6 +4598,11 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } }; + // Fix up partial res of segment from `resolve_path` call. + if let Some(id) = path[0].id { + self.r.partial_res_map.insert(id, PartialRes::new(Res::PrimTy(prim))); + } + PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1) } PathResult::Module(ModuleOrUniformRoot::Module(module)) => { diff --git a/tests/ui/resolve/auxiliary/empty.rs b/tests/ui/resolve/auxiliary/empty.rs new file mode 100644 index 000000000000..bd9ec079d80d --- /dev/null +++ b/tests/ui/resolve/auxiliary/empty.rs @@ -0,0 +1 @@ +// Intentionally empty. diff --git a/tests/ui/resolve/prim-crate-partial-res.rs b/tests/ui/resolve/prim-crate-partial-res.rs new file mode 100644 index 000000000000..955f4fa2aee7 --- /dev/null +++ b/tests/ui/resolve/prim-crate-partial-res.rs @@ -0,0 +1,8 @@ +//@ aux-build: empty.rs + +extern crate empty as usize; + +fn foo() -> usize<()> { 0 } +//~^ ERROR type arguments are not allowed on builtin type `usize` + +fn main() {} diff --git a/tests/ui/resolve/prim-crate-partial-res.stderr b/tests/ui/resolve/prim-crate-partial-res.stderr new file mode 100644 index 000000000000..d10d37c9f1b0 --- /dev/null +++ b/tests/ui/resolve/prim-crate-partial-res.stderr @@ -0,0 +1,17 @@ +error[E0109]: type arguments are not allowed on builtin type `usize` + --> $DIR/prim-crate-partial-res.rs:5:19 + | +LL | fn foo() -> usize<()> { 0 } + | ----- ^^ type argument not allowed + | | + | not allowed on builtin type `usize` + | +help: primitive type `usize` doesn't have generic parameters + | +LL - fn foo() -> usize<()> { 0 } +LL + fn foo() -> usize { 0 } + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0109`. From 19648ce5cd12b11889eccacac50c70ca8ac78fee Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 23 Mar 2025 18:45:08 -0700 Subject: [PATCH 006/222] codegen test for non-memcmp array comparison --- tests/codegen/array-cmp.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/codegen/array-cmp.rs b/tests/codegen/array-cmp.rs index 2565a385b61b..f9b7be898828 100644 --- a/tests/codegen/array-cmp.rs +++ b/tests/codegen/array-cmp.rs @@ -17,3 +17,15 @@ pub fn compare() -> bool { [0x00, 0x00, 0x48, 0x41] } } + +// CHECK-LABEL: @array_of_tuple_le +// CHECK: call{{.+}}i8 @llvm.scmp.i8.i16 +// CHECK: call{{.+}}i8 @llvm.ucmp.i8.i16 +// CHECK: call{{.+}}i8 @llvm.scmp.i8.i16 +// CHECK: call{{.+}}i8 @llvm.ucmp.i8.i16 +// CHECK: %[[RET:.+]] = icmp slt i8 {{.+}}, 1 +// CHECK: ret i8 %[[RET]] +#[no_mangle] +pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool { + a <= b +} From 54bb849affcbede09ab1327c6cd996e5c5948cdd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 28 Mar 2025 22:31:20 +0300 Subject: [PATCH 007/222] hygiene: Rename semi-transparent to semi-opaque The former is just too long, see the examples in `hygiene.rs` --- .../src/attributes/transparency.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 6 +-- compiler/rustc_span/src/hygiene.rs | 47 +++++++++---------- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + tests/ui/hygiene/rustc-macro-transparency.rs | 12 ++--- .../hygiene/rustc-macro-transparency.stderr | 12 ++--- tests/ui/hygiene/unpretty-debug.stdout | 2 +- tests/ui/proc-macro/meta-macro-hygiene.stdout | 6 +-- .../nonterminal-token-hygiene.stdout | 4 +- 11 files changed, 48 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ad83a1f7af80..ce42b0507ed5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -20,7 +20,7 @@ impl SingleAttributeParser for TransparencyParser { fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { match args.name_value().and_then(|nv| nv.value_as_str()) { Some(sym::transparent) => Some(Transparency::Transparent), - Some(sym::semitransparent) => Some(Transparency::SemiTransparent), + Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque), Some(sym::opaque) => Some(Transparency::Opaque), Some(other) => { cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`")); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 1e33e2e9393f..a8f0da736c63 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -752,7 +752,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( rustc_macro_transparency, Normal, - template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing, + template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing, EncodeCrossCrate::Yes, "used internally for testing macro hygiene", ), rustc_attr!( diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 612e091770f0..1eac3f848b62 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1998,16 +1998,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { result, result.map(|r| r.expn_data()) ); - // Then find the last semi-transparent mark from the end if it exists. + // Then find the last semi-opaque mark from the end if it exists. for (mark, transparency) in iter { - if transparency == Transparency::SemiTransparent { + if transparency == Transparency::SemiOpaque { result = Some(mark); } else { break; } } debug!( - "resolve_crate_root: found semi-transparent mark {:?} {:?}", + "resolve_crate_root: found semi-opaque mark {:?} {:?}", result, result.map(|r| r.expn_data()) ); diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index e7a8dee27f56..c2e7cb457755 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -66,10 +66,10 @@ pub struct SyntaxContextData { outer_expn: ExpnId, outer_transparency: Transparency, parent: SyntaxContext, - /// This context, but with all transparent and semi-transparent expansions filtered away. + /// This context, but with all transparent and semi-opaque expansions filtered away. opaque: SyntaxContext, /// This context, but with all transparent expansions filtered away. - opaque_and_semitransparent: SyntaxContext, + opaque_and_semiopaque: SyntaxContext, /// Name of the crate to which `$crate` with this context would resolve. dollar_crate_name: Symbol, } @@ -78,14 +78,14 @@ impl SyntaxContextData { fn new( (parent, outer_expn, outer_transparency): SyntaxContextKey, opaque: SyntaxContext, - opaque_and_semitransparent: SyntaxContext, + opaque_and_semiopaque: SyntaxContext, ) -> SyntaxContextData { SyntaxContextData { outer_expn, outer_transparency, parent, opaque, - opaque_and_semitransparent, + opaque_and_semiopaque, dollar_crate_name: kw::DollarCrate, } } @@ -96,7 +96,7 @@ impl SyntaxContextData { outer_transparency: Transparency::Opaque, parent: SyntaxContext::root(), opaque: SyntaxContext::root(), - opaque_and_semitransparent: SyntaxContext::root(), + opaque_and_semiopaque: SyntaxContext::root(), dollar_crate_name: kw::DollarCrate, } } @@ -207,13 +207,13 @@ pub enum Transparency { /// Identifier produced by a transparent expansion is always resolved at call-site. /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this. Transparent, - /// Identifier produced by a semi-transparent expansion may be resolved + /// Identifier produced by a semi-opaque expansion may be resolved /// either at call-site or at definition-site. /// If it's a local variable, label or `$crate` then it's resolved at def-site. /// Otherwise it's resolved at call-site. /// `macro_rules` macros behave like this, built-in macros currently behave like this too, /// but that's an implementation detail. - SemiTransparent, + SemiOpaque, /// Identifier produced by an opaque expansion is always resolved at definition-site. /// Def-site spans in procedural macros, identifiers from `macro` by default use this. Opaque, @@ -221,7 +221,7 @@ pub enum Transparency { impl Transparency { pub fn fallback(macro_rules: bool) -> Self { - if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque } + if macro_rules { Transparency::SemiOpaque } else { Transparency::Opaque } } } @@ -469,7 +469,7 @@ impl HygieneData { fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext { debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); - self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent + self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque } fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { @@ -562,7 +562,7 @@ impl HygieneData { } let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt(); - let mut call_site_ctxt = if transparency == Transparency::SemiTransparent { + let mut call_site_ctxt = if transparency == Transparency::SemiOpaque { self.normalize_to_macros_2_0(call_site_ctxt) } else { self.normalize_to_macro_rules(call_site_ctxt) @@ -608,33 +608,32 @@ impl HygieneData { self.syntax_context_data.push(SyntaxContextData::decode_placeholder()); self.syntax_context_map.insert(key, ctxt); - // Opaque and semi-transparent versions of the parent. Note that they may be equal to the + // Opaque and semi-opaque versions of the parent. Note that they may be equal to the // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques, - // and `parent_opaque_and_semitransparent` == `parent` if the expn contains only opaques - // and semi-transparents. + // and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques. let parent_opaque = self.syntax_context_data[parent.0 as usize].opaque; - let parent_opaque_and_semitransparent = - self.syntax_context_data[parent.0 as usize].opaque_and_semitransparent; + let parent_opaque_and_semiopaque = + self.syntax_context_data[parent.0 as usize].opaque_and_semiopaque; - // Evaluate opaque and semi-transparent versions of the new syntax context. - let (opaque, opaque_and_semitransparent) = match transparency { - Transparency::Transparent => (parent_opaque, parent_opaque_and_semitransparent), - Transparency::SemiTransparent => ( + // Evaluate opaque and semi-opaque versions of the new syntax context. + let (opaque, opaque_and_semiopaque) = match transparency { + Transparency::Transparent => (parent_opaque, parent_opaque_and_semiopaque), + Transparency::SemiOpaque => ( parent_opaque, - // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. - self.alloc_ctxt(parent_opaque_and_semitransparent, expn_id, transparency), + // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques. + self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency), ), Transparency::Opaque => ( // Will be the same as `ctxt` if the expn chain contains only opaques. self.alloc_ctxt(parent_opaque, expn_id, transparency), - // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents. - self.alloc_ctxt(parent_opaque_and_semitransparent, expn_id, transparency), + // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques. + self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency), ), }; // Fill the full data, now that we have it. self.syntax_context_data[ctxt.as_u32() as usize] = - SyntaxContextData::new(key, opaque, opaque_and_semitransparent); + SyntaxContextData::new(key, opaque, opaque_and_semiopaque); ctxt } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9e6ba2e1b9ce..625ece787b90 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1112,7 +1112,7 @@ impl Span { /// Equivalent of `Span::mixed_site` from the proc macro API, /// except that the location is taken from the `self` span. pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span { - self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent) + self.with_ctxt_from_mark(expn_id, Transparency::SemiOpaque) } /// Produces a span with the same location as `self` and context produced by a macro with the diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 47dd80c432ea..02f89c527e63 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1871,6 +1871,7 @@ symbols! { select_unpredictable, self_in_typedefs, self_struct_ctor, + semiopaque, semitransparent, sha2, sha3, diff --git a/tests/ui/hygiene/rustc-macro-transparency.rs b/tests/ui/hygiene/rustc-macro-transparency.rs index 5f36993af2f3..1a78a7543cfd 100644 --- a/tests/ui/hygiene/rustc-macro-transparency.rs +++ b/tests/ui/hygiene/rustc-macro-transparency.rs @@ -6,9 +6,9 @@ macro transparent() { let transparent = 0; } #[rustc_macro_transparency = "semitransparent"] -macro semitransparent() { - struct SemiTransparent; - let semitransparent = 0; +macro semiopaque() { + struct SemiOpaque; + let semiopaque = 0; } #[rustc_macro_transparency = "opaque"] macro opaque() { @@ -18,14 +18,14 @@ macro opaque() { fn main() { transparent!(); - semitransparent!(); + semiopaque!(); opaque!(); Transparent; // OK - SemiTransparent; // OK + SemiOpaque; // OK Opaque; //~ ERROR cannot find value `Opaque` in this scope transparent; // OK - semitransparent; //~ ERROR expected value, found macro `semitransparent` + semiopaque; //~ ERROR expected value, found macro `semiopaque` opaque; //~ ERROR expected value, found macro `opaque` } diff --git a/tests/ui/hygiene/rustc-macro-transparency.stderr b/tests/ui/hygiene/rustc-macro-transparency.stderr index 1d2a1e124986..1bea8a0ee4f3 100644 --- a/tests/ui/hygiene/rustc-macro-transparency.stderr +++ b/tests/ui/hygiene/rustc-macro-transparency.stderr @@ -4,17 +4,17 @@ error[E0425]: cannot find value `Opaque` in this scope LL | Opaque; | ^^^^^^ not found in this scope -error[E0423]: expected value, found macro `semitransparent` +error[E0423]: expected value, found macro `semiopaque` --> $DIR/rustc-macro-transparency.rs:29:5 | -LL | struct SemiTransparent; - | ----------------------- similarly named unit struct `SemiTransparent` defined here +LL | struct SemiOpaque; + | ------------------ similarly named unit struct `SemiOpaque` defined here ... -LL | semitransparent; - | ^^^^^^^^^^^^^^^ +LL | semiopaque; + | ^^^^^^^^^^ | | | not a value - | help: a unit struct with a similar name exists: `SemiTransparent` + | help: a unit struct with a similar name exists (notice the capitalization): `SemiOpaque` error[E0423]: expected value, found macro `opaque` --> $DIR/rustc-macro-transparency.rs:30:5 diff --git a/tests/ui/hygiene/unpretty-debug.stdout b/tests/ui/hygiene/unpretty-debug.stdout index e475cfac2fc1..f35bd7a7cb2c 100644 --- a/tests/ui/hygiene/unpretty-debug.stdout +++ b/tests/ui/hygiene/unpretty-debug.stdout @@ -24,5 +24,5 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) -#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiTransparent) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque) */ diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index 1ee7179e84c0..1734b9afe92e 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -60,11 +60,11 @@ SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) #1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) #2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) -#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) +#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque) #4: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) #5: parent: #3, outer_mark: (crate0::{{expn3}}, Transparent) -#6: parent: #0, outer_mark: (crate0::{{expn3}}, SemiTransparent) +#6: parent: #0, outer_mark: (crate0::{{expn3}}, SemiOpaque) #7: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) #8: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent) -#9: parent: #4, outer_mark: (crate0::{{expn4}}, SemiTransparent) +#9: parent: #4, outer_mark: (crate0::{{expn4}}, SemiOpaque) */ diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 6fd6cb474693..0f1b19ffdeab 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -82,10 +82,10 @@ SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) #1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) #2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) -#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) +#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque) #4: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) #5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) #6: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) #7: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent) -#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) +#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiOpaque) */ From bb495d6d3e6dae294f08162097bd85f904e9f90b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Apr 2024 20:18:13 +1000 Subject: [PATCH 008/222] Remove `NtBlock`, `Nonterminal`, and `TokenKind::Interpolated`. `NtBlock` is the last remaining variant of `Nonterminal`, so once it is gone then `Nonterminal` can be removed as well. --- compiler/rustc_ast/src/ast_traits.rs | 14 -- compiler/rustc_ast/src/mut_visit.rs | 40 +----- compiler/rustc_ast/src/token.rs | 127 +++--------------- compiler/rustc_ast/src/tokenstream.rs | 26 +--- compiler/rustc_ast_pretty/src/pprust/mod.rs | 6 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 12 +- compiler/rustc_attr_parsing/src/parser.rs | 20 +-- compiler/rustc_builtin_macros/src/cfg_eval.rs | 6 +- compiler/rustc_expand/src/config.rs | 8 +- compiler/rustc_expand/src/mbe/diagnostics.rs | 4 +- compiler/rustc_expand/src/mbe/transcribe.rs | 19 ++- .../rustc_expand/src/proc_macro_server.rs | 9 -- compiler/rustc_parse/src/parser/expr.rs | 38 +++--- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_parse/src/parser/mod.rs | 33 +---- .../rustc_parse/src/parser/nonterminal.rs | 120 ++++++----------- compiler/rustc_parse/src/parser/stmt.rs | 10 +- tests/ui/macros/macro-as-fn-body.rs | 2 +- 18 files changed, 108 insertions(+), 388 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index c9e2e9911ef0..7f98e7ba8a61 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -6,7 +6,6 @@ use std::fmt; use std::marker::PhantomData; use crate::ptr::P; -use crate::token::Nonterminal; use crate::tokenstream::LazyAttrTokenStream; use crate::{ Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField, @@ -206,19 +205,6 @@ impl HasTokens for Attribute { } } -impl HasTokens for Nonterminal { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - match self { - Nonterminal::NtBlock(block) => block.tokens(), - } - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - match self { - Nonterminal::NtBlock(block) => block.tokens_mut(), - } - } -} - /// A trait for AST nodes having (or not having) attributes. pub trait HasAttrs { /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f7d13acdfc40..3d4fa546984a 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -843,9 +843,9 @@ fn visit_lazy_tts(vis: &mut T, lazy_tts: &mut Option(vis: &mut T, t: &mut Token) { let Token { kind, span } = t; @@ -863,45 +863,11 @@ pub fn visit_token(vis: &mut T, t: &mut Token) { token::NtLifetime(ident, _is_raw) => { vis.visit_ident(ident); } - token::Interpolated(nt) => { - let nt = Arc::make_mut(nt); - visit_nonterminal(vis, nt); - } _ => {} } vis.visit_span(span); } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -/// Applies the visitor to elements of interpolated nodes. -// -// N.B., this can occur only when applying a visitor to partially expanded -// code, where parsed pieces have gotten implanted ito *other* macro -// invocations. This is relevant for macro hygiene, but possibly not elsewhere. -// -// One problem here occurs because the types for flat_map_item, flat_map_stmt, -// etc., allow the visitor to return *multiple* items; this is a problem for the -// nodes here, because they insist on having exactly one piece. One solution -// would be to mangle the MutVisitor trait to include one-to-many and -// one-to-one versions of these entry points, but that would probably confuse a -// lot of people and help very few. Instead, I'm just going to put in dynamic -// checks. I think the performance impact of this will be pretty much -// nonexistent. The danger is that someone will apply a `MutVisitor` to a -// partially expanded node, and will be confused by the fact that their -// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt` -// nodes. Hopefully they'll wind up reading this comment, and doing something -// appropriate. -// -// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to -// contain multiple items, but decided against it when I looked at -// `parse_item_or_view_item` and tried to figure out what I would do with -// multiple items there.... -fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { - match nt { - token::NtBlock(block) => vis.visit_block(block), - } -} - // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_defaultness(vis: &mut T, defaultness: &mut Defaultness) { match defaultness { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index d57a369eebf2..de80bb47aff2 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -1,13 +1,10 @@ use std::borrow::Cow; use std::fmt; -use std::sync::Arc; pub use LitKind::*; -pub use Nonterminal::*; pub use NtExprKind::*; pub use NtPatKind::*; pub use TokenKind::*; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym}; @@ -16,7 +13,6 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym}; use rustc_span::{Ident, Symbol}; use crate::ast; -use crate::ptr::P; use crate::util::case::Case; #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -35,8 +31,8 @@ pub enum InvisibleOrigin { // `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro. ProcMacro, - // Converted from `TokenKind::Interpolated` in - // `TokenStream::flatten_token`. Treated similarly to `ProcMacro`. + // Converted from `TokenKind::NtLifetime` in `TokenStream::flatten_token`. + // Treated similarly to `ProcMacro`. FlattenToken, } @@ -337,9 +333,7 @@ impl From for bool { } } -// SAFETY: due to the `Clone` impl below, all fields of all variants other than -// `Interpolated` must impl `Copy`. -#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ /// `=` @@ -468,21 +462,6 @@ pub enum TokenKind { /// the `lifetime` metavariable in the macro's RHS. NtLifetime(Ident, IdentIsRaw), - /// An embedded AST node, as produced by a macro. This only exists for - /// historical reasons. We'd like to get rid of it, for multiple reasons. - /// - It's conceptually very strange. Saying a token can contain an AST - /// node is like saying, in natural language, that a word can contain a - /// sentence. - /// - It requires special handling in a bunch of places in the parser. - /// - It prevents `Token` from implementing `Copy`. - /// It adds complexity and likely slows things down. Please don't add new - /// occurrences of this token kind! - /// - /// The span in the surrounding `Token` is that of the metavariable in the - /// macro's RHS. The span within the Nonterminal is that of the fragment - /// passed to the macro at the call site. - Interpolated(Arc), - /// A doc comment token. /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc) /// similarly to symbols in string literal tokens. @@ -492,19 +471,6 @@ pub enum TokenKind { Eof, } -impl Clone for TokenKind { - fn clone(&self) -> Self { - // `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So - // for all other variants, this implementation of `clone` is just like - // a copy. This is faster than the `derive(Clone)` version which has a - // separate path for every variant. - match self { - Interpolated(nt) => Interpolated(Arc::clone(nt)), - _ => unsafe { std::ptr::read(self) }, - } - } -} - #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Token { pub kind: TokenKind, @@ -600,7 +566,7 @@ impl Token { | FatArrow | Pound | Dollar | Question | SingleQuote => true, OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false, + | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false, } } @@ -631,7 +597,6 @@ impl Token { PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Block | MetaVarKind::Expr { .. } | @@ -703,7 +668,6 @@ impl Token { match self.kind { OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal, ))) => true, @@ -831,31 +795,20 @@ impl Token { /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_metavar_expr(&self) -> bool { - #[allow(irrefutable_let_patterns)] // FIXME: temporary - if let Interpolated(nt) = &self.kind - && let NtBlock(_) = &**nt - { - true - } else if matches!( + matches!( self.is_metavar_seq(), - Some(MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path) - ) { - true - } else { - matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) - } + Some( + MetaVarKind::Expr { .. } + | MetaVarKind::Literal + | MetaVarKind::Path + | MetaVarKind::Block + ) + ) } - /// Is the token an interpolated block (`$b:block`)? - pub fn is_whole_block(&self) -> bool { - #[allow(irrefutable_let_patterns)] // FIXME: temporary - if let Interpolated(nt) = &self.kind - && let NtBlock(..) = &**nt - { - return true; - } - - false + /// Are we at a block from a metavar (`$b:block`)? + pub fn is_metavar_block(&self) -> bool { + matches!(self.is_metavar_seq(), Some(MetaVarKind::Block)) } /// Returns `true` if the token is either the `mut` or `const` keyword. @@ -1024,7 +977,7 @@ impl Token { | PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..) - | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof, + | Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof, _, ) => { return None; @@ -1063,12 +1016,6 @@ pub enum NtExprKind { Expr2021 { inferred: bool }, } -#[derive(Clone, Encodable, Decodable)] -/// For interpolation during macro expansion. -pub enum Nonterminal { - NtBlock(P), -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NonterminalKind { Item, @@ -1152,47 +1099,6 @@ impl fmt::Display for NonterminalKind { } } -impl Nonterminal { - pub fn use_span(&self) -> Span { - match self { - NtBlock(block) => block.span, - } - } - - pub fn descr(&self) -> &'static str { - match self { - NtBlock(..) => "block", - } - } -} - -impl PartialEq for Nonterminal { - fn eq(&self, _rhs: &Self) -> bool { - // FIXME: Assume that all nonterminals are not equal, we can't compare them - // correctly based on data from AST. This will prevent them from matching each other - // in macros. The comparison will become possible only when each nonterminal has an - // attached token stream from which it was parsed. - false - } -} - -impl fmt::Debug for Nonterminal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - NtBlock(..) => f.pad("NtBlock(..)"), - } - } -} - -impl HashStable for Nonterminal -where - CTX: crate::HashStableContext, -{ - fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) { - panic!("interpolated tokens should not be present in the HIR") - } -} - // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { @@ -1202,7 +1108,6 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(Lit, 12); static_assert_size!(LitKind, 2); - static_assert_size!(Nonterminal, 8); static_assert_size!(Token, 24); static_assert_size!(TokenKind, 16); // tidy-alphabetical-end diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index fb331e74aeb8..3b457303cac1 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -25,7 +25,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym}; use crate::ast::AttrStyle; use crate::ast_traits::{HasAttrs, HasTokens}; -use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind}; +use crate::token::{self, Delimiter, InvisibleOrigin, Token, TokenKind}; use crate::{AttrVec, Attribute}; /// Part of a `TokenStream`. @@ -305,11 +305,6 @@ pub struct AttrsTarget { } /// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s. -/// -/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s -/// instead of a representation of the abstract syntax tree. -/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for -/// backwards compatibility. #[derive(Clone, Debug, Default, Encodable, Decodable)] pub struct TokenStream(pub(crate) Arc>); @@ -476,12 +471,6 @@ impl TokenStream { TokenStream::new(tts) } - pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { - match nt { - Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - } - } - fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree { match token.kind { token::NtIdent(ident, is_raw) => { @@ -493,12 +482,6 @@ impl TokenStream { Delimiter::Invisible(InvisibleOrigin::FlattenToken), TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), ), - token::Interpolated(ref nt) => TokenTree::Delimited( - DelimSpan::from_single(token.span), - DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible(InvisibleOrigin::FlattenToken), - TokenStream::from_nonterminal_ast(&nt).flattened(), - ), _ => TokenTree::Token(token.clone(), spacing), } } @@ -516,10 +499,9 @@ impl TokenStream { pub fn flattened(&self) -> TokenStream { fn can_skip(stream: &TokenStream) -> bool { stream.iter().all(|tree| match tree { - TokenTree::Token(token, _) => !matches!( - token.kind, - token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..) - ), + TokenTree::Token(token, _) => { + !matches!(token.kind, token::NtIdent(..) | token::NtLifetime(..)) + } TokenTree::Delimited(.., inner) => can_skip(inner), }) } diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 97cb6e52d562..551506f2aef8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -5,14 +5,10 @@ pub mod state; use std::borrow::Cow; use rustc_ast as ast; -use rustc_ast::token::{Nonterminal, Token, TokenKind}; +use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate}; -pub fn nonterminal_to_string(nt: &Nonterminal) -> String { - State::new().nonterminal_to_string(nt) -} - /// Print the token kind precisely, without converting `$crate` into its respective crate name. pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> { State::new().token_kind_to_string(tok) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3dbfc191f8f5..64a0a2ed97de 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use rustc_ast::attr::AttrIdGenerator; use rustc_ast::ptr::P; -use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; @@ -876,14 +876,6 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } } - fn nonterminal_to_string(&self, nt: &Nonterminal) -> String { - // We extract the token stream from the AST fragment and pretty print - // it, rather than using AST pretty printing, because `Nonterminal` is - // slated for removal in #124141. (This method will also then be - // removed.) - self.tts_to_string(&TokenStream::from_nonterminal_ast(nt)) - } - /// Print the token kind precisely, without converting `$crate` into its respective crate name. fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> { self.token_kind_to_string_ext(tok, None) @@ -976,8 +968,6 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere doc_comment_to_string(comment_kind, attr_style, data).into() } token::Eof => "".into(), - - token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(), } } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a8a1460591cf..384fae59873f 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -485,25 +485,7 @@ impl<'a> MetaItemListParserContext<'a> { } // or a path. - let path = - if let Some(TokenTree::Token(Token { kind: token::Interpolated(_), span, .. }, _)) = - self.inside_delimiters.peek() - { - self.inside_delimiters.next(); - // We go into this path if an expr ended up in an attribute that - // expansion did not turn into a literal. Say, `#[repr(align(macro!()))]` - // where the macro didn't expand to a literal. An error is already given - // for this at this point, and then we do continue. This makes this path - // reachable... - let e = self.dcx.span_delayed_bug( - *span, - "expr in place where literal is expected (builtin attr parsing)", - ); - - return Some(MetaItemOrLitParser::Err(*span, e)); - } else { - self.next_path()? - }; + let path = self.next_path()?; // Paths can be followed by: // - `(more meta items)` (another list) diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index b3ba90731184..ea0bbd0e31ad 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -92,11 +92,11 @@ impl CfgEval<'_> { // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization // process is lossless, so this process is invisible to proc-macros. - // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`) + // 'Flatten' all nonterminals (i.e. `TokenKind::Nt{Ident,Lifetime}`) // to `None`-delimited groups containing the corresponding tokens. This // is normally delayed until the proc-macro server actually needs to - // provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier, - // so that we can handle cases like: + // provide tokens to a proc-macro. We do this earlier, so that we can + // handle cases like: // // ```rust // #[cfg_eval] #[cfg] $item diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index bcc2703c39b3..27924544de52 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -238,13 +238,7 @@ impl<'a> StripUnconfigured<'a> { Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)) } AttrTokenTree::Token( - Token { - kind: - TokenKind::NtIdent(..) - | TokenKind::NtLifetime(..) - | TokenKind::Interpolated(..), - .. - }, + Token { kind: TokenKind::NtIdent(..) | TokenKind::NtLifetime(..), .. }, _, ) => { panic!("Nonterminal should have been flattened: {:?}", tree); diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index e60a9e83184f..30961a2b4044 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -66,9 +66,7 @@ pub(super) fn failed_to_match_macro( } if let MatcherLoc::Token { token: expected_token } = &remaining_matcher - && (matches!(expected_token.kind, TokenKind::Interpolated(_)) - || matches!(token.kind, TokenKind::Interpolated(_)) - || matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))) + && (matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))) || matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))) { err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens"); diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 6e47ed6eb67c..79a5c7ea31be 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -1,5 +1,4 @@ use std::mem; -use std::sync::Arc; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{ @@ -307,7 +306,9 @@ pub(super) fn transcribe<'a>( let tt = match cur_matched { MatchedSingle(ParseNtResult::Tt(tt)) => { // `tt`s are emitted into the output stream directly as "raw tokens", - // without wrapping them into groups. + // without wrapping them into groups. Other variables are emitted into + // the output stream as groups with `Delimiter::Invisible` to maintain + // parsing priorities. maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker) } MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { @@ -325,6 +326,11 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Item(item)) => { mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item)) } + MatchedSingle(ParseNtResult::Block(block)) => mk_delimited( + block.span, + MetaVarKind::Block, + TokenStream::from_ast(block), + ), MatchedSingle(ParseNtResult::Stmt(stmt)) => { let stream = if let StmtKind::Empty = stmt.kind { // FIXME: Properly collect tokens for empty statements. @@ -385,15 +391,6 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Vis(vis)) => { mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis)) } - MatchedSingle(ParseNtResult::Nt(nt)) => { - // Other variables are emitted into the output stream as groups with - // `Delimiter::Invisible` to maintain parsing priorities. - // `Interpolated` is currently used for such groups in rustc parser. - marker.visit_span(&mut sp); - let use_span = nt.use_span(); - with_metavar_spans(|mspans| mspans.insert(use_span, sp)); - TokenTree::token_alone(token::Interpolated(Arc::clone(nt)), sp) - } MatchedSeq(..) => { // We were unable to descend far enough. This is an error. return Err(dcx.create_err(VarStillRepeating { span: sp, ident })); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index ee6306e39610..2706a5eb3d7f 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -309,15 +309,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec { - let stream = TokenStream::from_nonterminal_ast(&nt); - trees.push(TokenTree::Group(Group { - delimiter: pm::Delimiter::None, - stream: Some(stream), - span: DelimSpan::from_single(span), - })) - } - OpenDelim(..) | CloseDelim(..) => unreachable!(), Eof => unreachable!(), } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e1e6b93abf35..83df18ae2867 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -637,9 +637,7 @@ impl<'a> Parser<'a> { /// Returns the span of expr if it was not interpolated, or the span of the interpolated token. fn interpolated_or_expr_span(&self, expr: &Expr) -> Span { match self.prev_token.kind { - TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => { - self.prev_token.span - } + TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) => self.prev_token.span, TokenKind::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { // `expr.span` is the interpolated span, because invisible open // and close delims both get marked with the same span, one @@ -1386,15 +1384,7 @@ impl<'a> Parser<'a> { maybe_recover_from_interpolated_ty_qpath!(self, true); let span = self.token.span; - if let token::Interpolated(nt) = &self.token.kind { - match &**nt { - token::NtBlock(block) => { - let block = block.clone(); - self.bump(); - return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); - } - }; - } else if let Some(expr) = self.eat_metavar_seq_with_matcher( + if let Some(expr) = self.eat_metavar_seq_with_matcher( |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }), |this| { // Force collection (as opposed to just `parse_expr`) is required to avoid the @@ -1415,9 +1405,13 @@ impl<'a> Parser<'a> { self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) { return Ok(lit); - } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| { - this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type)) - }) { + } else if let Some(block) = + self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) + { + return Ok(self.mk_expr(span, ExprKind::Block(block, None))); + } else if let Some(path) = + self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type)) + { return Ok(self.mk_expr(span, ExprKind::Path(None, path))); } @@ -1671,7 +1665,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(exp!(Loop)) { self.parse_expr_loop(label, lo) } else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace)) - || self.token.is_whole_block() + || self.token.is_metavar_block() { self.parse_expr_block(label, lo, BlockCheckMode::Default) } else if !ate_colon @@ -2349,7 +2343,7 @@ impl<'a> Parser<'a> { } } - if self.token.is_whole_block() { + if self.token.is_metavar_block() { self.dcx().emit_err(errors::InvalidBlockMacroSegment { span: self.token.span, context: lo.to(self.token.span), @@ -2472,7 +2466,7 @@ impl<'a> Parser<'a> { if self.may_recover() && self.token.can_begin_expr() && !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace)) - && !self.token.is_whole_block() + && !self.token.is_metavar_block() { let snapshot = self.create_snapshot_for_diagnostic(); let restrictions = @@ -3519,7 +3513,7 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Catch]) && self - .look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + .look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) } @@ -3530,7 +3524,7 @@ impl<'a> Parser<'a> { fn is_try_block(&self) -> bool { self.token.is_keyword(kw::Try) && self - .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) && self.token_uninterpolated_span().at_least_rust_2018() } @@ -3564,12 +3558,12 @@ impl<'a> Parser<'a> { // `async move {` self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use]) && self.look_ahead(lookahead + 2, |t| { - *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() + *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block() }) ) || ( // `async {` self.look_ahead(lookahead + 1, |t| { - *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() + *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block() }) )) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a8208e4717bd..83c0bceb20a4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2543,7 +2543,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; *sig_hi = self.prev_token.span; (AttrVec::new(), None) - } else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() { + } else if self.check(exp!(OpenBrace)) || self.token.is_metavar_block() { self.parse_block_common(self.token.span, BlockCheckMode::Default, None) .map(|(attrs, body)| (attrs, Some(body)))? } else if self.token == token::Eq { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 392a1c1057ab..bb9393b8918b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -13,7 +13,6 @@ mod ty; use std::assert_matches::debug_assert_matches; use std::ops::Range; -use std::sync::Arc; use std::{fmt, mem, slice}; use attr_wrapper::{AttrWrapper, UsePreAttrPos}; @@ -24,8 +23,8 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtExprKind, NtPatKind, - Token, TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, + TokenKind, }; use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree}; use rustc_ast::util::case::Case; @@ -98,21 +97,6 @@ pub enum ForceCollect { No, } -#[macro_export] -macro_rules! maybe_whole { - ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { - #[allow(irrefutable_let_patterns)] // FIXME: temporary - if let token::Interpolated(nt) = &$p.token.kind - && let token::$constructor(x) = &**nt - { - #[allow(unused_mut)] - let mut $x = x.clone(); - $p.bump(); - return Ok($e); - } - }; -} - /// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`. #[macro_export] macro_rules! maybe_recover_from_interpolated_ty_qpath { @@ -459,7 +443,6 @@ pub fn token_descr(token: &Token) -> String { (Some(TokenDescription::MetaVar(kind)), _) => format!("`{kind}` metavariable"), (None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"), (None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"), - (None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()), (None, _) => format!("`{s}`"), } } @@ -828,8 +811,10 @@ impl<'a> Parser<'a> { fn check_inline_const(&self, dist: usize) -> bool { self.is_keyword_ahead(dist, &[kw::Const]) && self.look_ahead(dist + 1, |t| match &t.kind { - token::Interpolated(nt) => matches!(&**nt, token::NtBlock(..)), token::OpenDelim(Delimiter::Brace) => true, + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Block, + ))) => true, _ => false, }) } @@ -1375,7 +1360,7 @@ impl<'a> Parser<'a> { // Avoid const blocks and const closures to be parsed as const items if (self.check_const_closure() == is_closure) && !self - .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) && self.eat_keyword_case(exp!(Const), case) { Const::Yes(self.prev_token_uninterpolated_span()) @@ -1732,7 +1717,6 @@ impl<'a> Parser<'a> { pub fn token_uninterpolated_span(&self) -> Span { match &self.token.kind { token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span, - token::Interpolated(nt) => nt.use_span(), token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { self.look_ahead(1, |t| t.span) } @@ -1744,7 +1728,6 @@ impl<'a> Parser<'a> { pub fn prev_token_uninterpolated_span(&self) -> Span { match &self.prev_token.kind { token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span, - token::Interpolated(nt) => nt.use_span(), token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { self.look_ahead(0, |t| t.span) } @@ -1801,6 +1784,7 @@ pub enum ParseNtResult { Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), Item(P), + Block(P), Stmt(P), Pat(P, NtPatKind), Expr(P, NtExprKind), @@ -1809,7 +1793,4 @@ pub enum ParseNtResult { Meta(P), Path(P), Vis(P), - - /// This variant will eventually be removed, along with `Token::Interpolate`. - Nt(Arc), } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index b4e540d670d1..576de7766849 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,14 +1,7 @@ -use std::sync::Arc; - -use rustc_ast::HasTokens; use rustc_ast::ptr::P; -use rustc_ast::token::Nonterminal::*; use rustc_ast::token::NtExprKind::*; use rustc_ast::token::NtPatKind::*; -use rustc_ast::token::{ - self, Delimiter, InvisibleOrigin, MetaVarKind, Nonterminal, NonterminalKind, Token, -}; -use rustc_ast_pretty::pprust; +use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, NonterminalKind, Token}; use rustc_errors::PResult; use rustc_span::{Ident, kw}; @@ -45,13 +38,6 @@ impl<'a> Parser<'a> { } } - /// Old variant of `may_be_ident`. Being phased out. - fn nt_may_be_ident(nt: &Nonterminal) -> bool { - match nt { - NtBlock(_) => false, - } - } - match kind { // `expr_2021` and earlier NonterminalKind::Expr(Expr2021 { .. }) => { @@ -83,16 +69,12 @@ impl<'a> Parser<'a> { | token::Ident(..) | token::NtIdent(..) | token::NtLifetime(..) - | token::Interpolated(_) | token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true, _ => token.can_begin_type(), }, NonterminalKind::Block => match &token.kind { token::OpenDelim(Delimiter::Brace) => true, token::NtLifetime(..) => true, - token::Interpolated(nt) => match &**nt { - NtBlock(_) => true, - }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block | MetaVarKind::Stmt @@ -112,7 +94,6 @@ impl<'a> Parser<'a> { }, NonterminalKind::Path | NonterminalKind::Meta => match &token.kind { token::PathSep | token::Ident(..) | token::NtIdent(..) => true, - token::Interpolated(nt) => nt_may_be_ident(nt), token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => { may_be_ident(*kind) } @@ -136,62 +117,52 @@ impl<'a> Parser<'a> { // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, // which requires having captured tokens available. Since we cannot determine // in advance whether or not a proc-macro will be (transitively) invoked, - // we always capture tokens for any `Nonterminal` which needs them. - let mut nt = match kind { + // we always capture tokens for any nonterminal that needs them. + match kind { // Note that TT is treated differently to all the others. - NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())), + NonterminalKind::TT => Ok(ParseNtResult::Tt(self.parse_token_tree())), NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { - Some(item) => return Ok(ParseNtResult::Item(item)), - None => { - return Err(self - .dcx() - .create_err(UnexpectedNonterminal::Item(self.token.span))); - } + Some(item) => Ok(ParseNtResult::Item(item)), + None => Err(self.dcx().create_err(UnexpectedNonterminal::Item(self.token.span))), }, NonterminalKind::Block => { // While a block *expression* may have attributes (e.g. `#[my_attr] { ... }`), // the ':block' matcher does not support them - NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) + Ok(ParseNtResult::Block(self.collect_tokens_no_attrs(|this| this.parse_block())?)) } NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { - Some(stmt) => return Ok(ParseNtResult::Stmt(P(stmt))), + Some(stmt) => Ok(ParseNtResult::Stmt(P(stmt))), None => { - return Err(self - .dcx() - .create_err(UnexpectedNonterminal::Statement(self.token.span))); + Err(self.dcx().create_err(UnexpectedNonterminal::Statement(self.token.span))) } }, - NonterminalKind::Pat(pat_kind) => { - return Ok(ParseNtResult::Pat( - self.collect_tokens_no_attrs(|this| match pat_kind { - PatParam { .. } => this.parse_pat_no_top_alt(None, None), - PatWithOr => this.parse_pat_no_top_guard( - None, - RecoverComma::No, - RecoverColon::No, - CommaRecoveryMode::EitherTupleOrPipe, - ), - })?, - pat_kind, - )); - } + NonterminalKind::Pat(pat_kind) => Ok(ParseNtResult::Pat( + self.collect_tokens_no_attrs(|this| match pat_kind { + PatParam { .. } => this.parse_pat_no_top_alt(None, None), + PatWithOr => this.parse_pat_no_top_guard( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + ), + })?, + pat_kind, + )), NonterminalKind::Expr(expr_kind) => { - return Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind)); + Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind)) } NonterminalKind::Literal => { // The `:literal` matcher does not support attributes. - return Ok(ParseNtResult::Literal( + Ok(ParseNtResult::Literal( self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?, - )); + )) } - NonterminalKind::Ty => { - return Ok(ParseNtResult::Ty( - self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, - )); - } - // this could be handled like a token, since it is one + NonterminalKind::Ty => Ok(ParseNtResult::Ty( + self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, + )), + // This could be handled like a token, since it is one. NonterminalKind::Ident => { - return if let Some((ident, is_raw)) = get_macro_ident(&self.token) { + if let Some((ident, is_raw)) = get_macro_ident(&self.token) { self.bump(); Ok(ParseNtResult::Ident(ident, is_raw)) } else { @@ -199,25 +170,22 @@ impl<'a> Parser<'a> { span: self.token.span, token: self.token.clone(), })) - }; - } - NonterminalKind::Path => { - return Ok(ParseNtResult::Path(P( - self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))? - ))); + } } + NonterminalKind::Path => Ok(ParseNtResult::Path(P( + self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))? + ))), NonterminalKind::Meta => { - return Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))); + Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))) } NonterminalKind::Vis => { - return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| { - this.parse_visibility(FollowedByType::Yes) - })?))); + Ok(ParseNtResult::Vis(P(self + .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))) } NonterminalKind::Lifetime => { // We want to keep `'keyword` parsing, just like `keyword` is still // an ident for nonterminal purposes. - return if let Some((ident, is_raw)) = self.token.lifetime() { + if let Some((ident, is_raw)) = self.token.lifetime() { self.bump(); Ok(ParseNtResult::Lifetime(ident, is_raw)) } else { @@ -225,21 +193,9 @@ impl<'a> Parser<'a> { span: self.token.span, token: self.token.clone(), })) - }; + } } - }; - - // If tokens are supported at all, they should be collected. - if matches!(nt.tokens_mut(), Some(None)) { - panic!( - "Missing tokens for nt {:?} at {:?}: {:?}", - nt, - nt.use_span(), - pprust::nonterminal_to_string(&nt) - ); } - - Ok(ParseNtResult::Nt(Arc::new(nt))) } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 97cd4d2117f8..953bc3030126 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -23,8 +23,8 @@ use super::{ AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode, Trailing, UsePreAttrPos, }; -use crate::errors::MalformedLoopLabel; -use crate::{errors, exp, maybe_whole}; +use crate::errors::{self, MalformedLoopLabel}; +use crate::exp; impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. @@ -681,7 +681,9 @@ impl<'a> Parser<'a> { blk_mode: BlockCheckMode, loop_header: Option, ) -> PResult<'a, (AttrVec, P)> { - maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block)); + if let Some(block) = self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) { + return Ok((AttrVec::new(), block)); + } let maybe_ident = self.prev_token.clone(); self.maybe_recover_unexpected_block_label(loop_header); @@ -896,7 +898,7 @@ impl<'a> Parser<'a> { { if self.token == token::Colon && self.look_ahead(1, |token| { - token.is_whole_block() + token.is_metavar_block() || matches!( token.kind, token::Ident( diff --git a/tests/ui/macros/macro-as-fn-body.rs b/tests/ui/macros/macro-as-fn-body.rs index e0542edc2a52..188c7f7f728c 100644 --- a/tests/ui/macros/macro-as-fn-body.rs +++ b/tests/ui/macros/macro-as-fn-body.rs @@ -1,7 +1,7 @@ // //@ run-pass // -// Description - ensure Interpolated blocks can act as valid function bodies +// Description - ensure block metavariables can act as valid function bodies // Covered cases: free functions, struct methods, and default trait functions macro_rules! def_fn { From 027251ff7da03a6c190bfb1e1756a23085e3ff35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 2 Apr 2025 07:02:25 +0200 Subject: [PATCH 009/222] Use a session counter to make anon dep nodes unique --- .../rustc_query_system/src/dep_graph/graph.rs | 9 ++------- .../src/dep_graph/serialized.rs | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 127dcd825da5..abd6120bf9df 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1167,8 +1167,7 @@ pub(super) struct CurrentDepGraph { /// ID from the previous session. In order to side-step this problem, we make /// sure that anonymous `NodeId`s allocated in different sessions don't overlap. /// This is implemented by mixing a session-key into the ID fingerprint of - /// each anon node. The session-key is just a random number generated when - /// the `DepGraph` is created. + /// each anon node. The session-key is a hash of the number of previous sessions. anon_id_seed: Fingerprint, /// These are simple counters that are for profiling and @@ -1186,12 +1185,8 @@ impl CurrentDepGraph { record_stats: bool, previous: Arc, ) -> Self { - use std::time::{SystemTime, UNIX_EPOCH}; - - let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - let nanos = duration.as_nanos(); let mut stable_hasher = StableHasher::new(); - nanos.hash(&mut stable_hasher); + previous.session_count().hash(&mut stable_hasher); let anon_id_seed = stable_hasher.finish(); #[cfg(debug_assertions)] diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 7750d6d1fef4..9a639ede662c 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -92,6 +92,9 @@ pub struct SerializedDepGraph { /// Stores a map from fingerprints to nodes per dep node kind. /// This is the reciprocal of `nodes`. index: Vec>, + /// The number of previous compilation sessions. This is used to generate + /// unique anon dep nodes per session. + session_count: u64, } impl SerializedDepGraph { @@ -146,6 +149,11 @@ impl SerializedDepGraph { pub fn node_count(&self) -> usize { self.nodes.len() } + + #[inline] + pub fn session_count(&self) -> u64 { + self.session_count + } } /// A packed representation of an edge's start index and byte width. @@ -252,6 +260,8 @@ impl SerializedDepGraph { .map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default())) .collect(); + let session_count = d.read_u64(); + for (idx, node) in nodes.iter_enumerated() { if index[node.kind.as_usize()].insert(node.hash, idx).is_some() { // Side effect nodes can have duplicates @@ -273,6 +283,7 @@ impl SerializedDepGraph { edge_list_indices, edge_list_data, index, + session_count, }) } } @@ -601,7 +612,7 @@ impl EncoderState { stats: _, kind_stats, marker: _, - previous: _, + previous, } = self; let node_count = total_node_count.try_into().unwrap(); @@ -612,6 +623,8 @@ impl EncoderState { count.encode(&mut encoder); } + previous.session_count.checked_add(1).unwrap().encode(&mut encoder); + debug!(?node_count, ?edge_count); debug!("position: {:?}", encoder.position()); IntEncodedWithFixedSize(node_count).encode(&mut encoder); From 4d8f7577b5f2f7c72d1e258c07b882d0afcf0956 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 16 May 2024 09:22:37 +1000 Subject: [PATCH 010/222] Impl `Copy` for `Token` and `TokenKind`. --- compiler/rustc_ast/src/token.rs | 4 ++-- compiler/rustc_ast/src/tokenstream.rs | 2 +- compiler/rustc_expand/src/mbe/diagnostics.rs | 2 +- compiler/rustc_expand/src/mbe/macro_parser.rs | 4 ++-- compiler/rustc_expand/src/mbe/macro_rules.rs | 8 ++++---- compiler/rustc_expand/src/mbe/quoted.rs | 4 ++-- compiler/rustc_expand/src/mbe/transcribe.rs | 4 ++-- .../rustc_parse/src/lexer/unicode_chars.rs | 2 +- .../rustc_parse/src/parser/attr_wrapper.rs | 4 ++-- .../rustc_parse/src/parser/diagnostics.rs | 10 +++++----- compiler/rustc_parse/src/parser/expr.rs | 20 +++++++++---------- compiler/rustc_parse/src/parser/item.rs | 5 ++--- compiler/rustc_parse/src/parser/mod.rs | 8 ++++---- .../rustc_parse/src/parser/nonterminal.rs | 4 ++-- compiler/rustc_parse/src/parser/pat.rs | 6 +++--- compiler/rustc_parse/src/parser/path.rs | 4 ++-- compiler/rustc_parse/src/parser/stmt.rs | 2 +- compiler/rustc_parse/src/parser/tests.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 4 ++-- src/tools/rustfmt/src/macros.rs | 14 ++++++------- 20 files changed, 56 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index de80bb47aff2..9d56cc83ac8c 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -333,7 +333,7 @@ impl From for bool { } } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ /// `=` @@ -471,7 +471,7 @@ pub enum TokenKind { Eof, } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Token { pub kind: TokenKind, pub span: Span, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 3b457303cac1..8260842fb879 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -482,7 +482,7 @@ impl TokenStream { Delimiter::Invisible(InvisibleOrigin::FlattenToken), TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), ), - _ => TokenTree::Token(token.clone(), spacing), + _ => TokenTree::Token(*token, spacing), } } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 30961a2b4044..b663e959744f 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -160,7 +160,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match .is_none_or(|failure| failure.is_better_position(*approx_position)) { self.best_failure = Some(BestFailure { - token: token.clone(), + token: *token, position_in_tokenstream: *approx_position, msg, remaining_matcher: self diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index d709fd792817..0065f83eb4ee 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -179,7 +179,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec { for tt in tts { match tt { TokenTree::Token(token) => { - locs.push(MatcherLoc::Token { token: token.clone() }); + locs.push(MatcherLoc::Token { token: *token }); } TokenTree::Delimited(span, _, delimited) => { let open_token = Token::new(token::OpenDelim(delimited.delim), span.open); @@ -648,7 +648,7 @@ impl TtParser { // There are no possible next positions AND we aren't waiting for the black-box // parser: syntax error. return Failure(T::build_failure( - parser.token.clone(), + parser.token, parser.approx_token_stream_pos(), "no rules expected this token in macro call", )); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 77ec598e62a1..7ddd64d81d5a 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -778,7 +778,7 @@ impl<'tt> FirstSets<'tt> { // token could be the separator token itself. if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) { - first.add_one_maybe(TtHandle::from_token(sep.clone())); + first.add_one_maybe(TtHandle::from_token(*sep)); } // Reverse scan: Sequence comes before `first`. @@ -841,7 +841,7 @@ impl<'tt> FirstSets<'tt> { // If the sequence contents can be empty, then the first // token could be the separator token itself. if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) { - first.add_one_maybe(TtHandle::from_token(sep.clone())); + first.add_one_maybe(TtHandle::from_token(*sep)); } assert!(first.maybe_empty); @@ -917,7 +917,7 @@ impl<'tt> Clone for TtHandle<'tt> { // This variant *must* contain a `mbe::TokenTree::Token`, and not // any other variant of `mbe::TokenTree`. TtHandle::Token(mbe::TokenTree::Token(tok)) => { - TtHandle::Token(mbe::TokenTree::Token(tok.clone())) + TtHandle::Token(mbe::TokenTree::Token(*tok)) } _ => unreachable!(), @@ -1093,7 +1093,7 @@ fn check_matcher_core<'tt>( let mut new; let my_suffix = if let Some(sep) = &seq_rep.separator { new = suffix_first.clone(); - new.add_one_maybe(TtHandle::from_token(sep.clone())); + new.add_one_maybe(TtHandle::from_token(*sep)); &new } else { &suffix_first diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 0ea53627fe78..3f0372599565 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -283,7 +283,7 @@ fn parse_tree<'a>( } // `tree` is an arbitrary token. Keep it. - tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token.clone()), + tokenstream::TokenTree::Token(token, _) => TokenTree::Token(*token), // `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to // descend into the delimited set and further parse it. @@ -321,7 +321,7 @@ fn parse_kleene_op( match iter.next() { Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(token) { Some(op) => Ok(Ok((op, token.span))), - None => Ok(Err(token.clone())), + None => Ok(Err(*token)), }, tree => Err(tree.map_or(span, tokenstream::TokenTree::span)), } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 79a5c7ea31be..39186319b1cc 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -164,7 +164,7 @@ pub(super) fn transcribe<'a>( if repeat_idx < repeat_len { frame.idx = 0; if let Some(sep) = sep { - result.push(TokenTree::Token(sep.clone(), Spacing::Alone)); + result.push(TokenTree::Token(*sep, Spacing::Alone)); } continue; } @@ -438,7 +438,7 @@ pub(super) fn transcribe<'a>( // Nothing much to do here. Just push the token to the result, being careful to // preserve syntax context. mbe::TokenTree::Token(token) => { - let mut token = token.clone(); + let mut token = *token; mut_visit::visit_token(&mut marker, &mut token); let tt = TokenTree::Token(token, Spacing::Alone); result.push(tt); diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index ff03b42484b4..2bfa1ea4e058 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -376,7 +376,7 @@ pub(super) fn check_for_substitution( ascii_name, }) }; - (token.clone(), sugg) + (*token, sugg) } /// Extract string if found at current position with given delimiters diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index cff998fa1379..f1bd6a227309 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -120,7 +120,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // produce an empty `TokenStream` if no calls were made, and omit the // final token otherwise. let mut cursor_snapshot = self.cursor_snapshot.clone(); - let tokens = iter::once(FlatToken::Token(self.start_token.clone())) + let tokens = iter::once(FlatToken::Token(self.start_token)) .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next()))) .take(self.num_calls as usize); @@ -186,7 +186,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { impl<'a> Parser<'a> { pub(super) fn collect_pos(&self) -> CollectPos { CollectPos { - start_token: (self.token.clone(), self.token_spacing), + start_token: (self.token, self.token_spacing), cursor_snapshot: self.token_cursor.clone(), start_pos: self.num_bump_calls, } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ef044fe9d638..bb63e91aecfa 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -322,7 +322,7 @@ impl<'a> Parser<'a> { let mut recovered_ident = None; // we take this here so that the correct original token is retained in // the diagnostic, regardless of eager recovery. - let bad_token = self.token.clone(); + let bad_token = self.token; // suggest prepending a keyword in identifier position with `r#` let suggest_raw = if let Some((ident, IdentIsRaw::No)) = self.token.ident() @@ -382,7 +382,7 @@ impl<'a> Parser<'a> { // if the previous token is a valid keyword // that might use a generic, then suggest a correct // generic placement (later on) - let maybe_keyword = self.prev_token.clone(); + let maybe_keyword = self.prev_token; if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) { // if we have a valid keyword, attempt to parse generics // also obtain the keywords symbol @@ -530,7 +530,7 @@ impl<'a> Parser<'a> { // let y = 42; let guar = self.dcx().emit_err(ExpectedSemi { span: self.token.span, - token: self.token.clone(), + token: self.token, unexpected_token_label: None, sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span), }); @@ -555,7 +555,7 @@ impl<'a> Parser<'a> { let span = self.prev_token.span.shrink_to_hi(); let guar = self.dcx().emit_err(ExpectedSemi { span, - token: self.token.clone(), + token: self.token, unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); @@ -801,7 +801,7 @@ impl<'a> Parser<'a> { let span = self.prev_token.span.shrink_to_hi(); let mut err = self.dcx().create_err(ExpectedSemi { span, - token: self.token.clone(), + token: self.token, unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 83df18ae2867..c4ba62a7a4c4 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -344,7 +344,7 @@ impl<'a> Parser<'a> { fn error_found_expr_would_be_stmt(&self, lhs: &Expr) { self.dcx().emit_err(errors::FoundExprWouldBeStmt { span: self.token.span, - token: self.token.clone(), + token: self.token, suggestion: ExprParenthesesNeeded::surrounding(lhs.span), }); } @@ -417,7 +417,7 @@ impl<'a> Parser<'a> { cur_op_span: Span, ) -> PResult<'a, P> { let rhs = if self.is_at_start_of_range_notation_rhs() { - let maybe_lt = self.token.clone(); + let maybe_lt = self.token; let attrs = self.parse_outer_attributes()?; Some( self.parse_expr_assoc_with(Bound::Excluded(prec), attrs) @@ -611,7 +611,7 @@ impl<'a> Parser<'a> { /// Recover on `not expr` in favor of `!expr`. fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { - let negated_token = self.look_ahead(1, |t| t.clone()); + let negated_token = self.look_ahead(1, |t| *t); let sub_diag = if negated_token.is_numeric_lit() { errors::NotAsNegationOperatorSub::SuggestNotBitwise @@ -1606,7 +1606,7 @@ impl<'a> Parser<'a> { } fn parse_expr_path_start(&mut self) -> PResult<'a, P> { - let maybe_eq_tok = self.prev_token.clone(); + let maybe_eq_tok = self.prev_token; let (qself, path) = if self.eat_lt() { let lt_span = self.prev_token.span; let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| { @@ -2067,7 +2067,7 @@ impl<'a> Parser<'a> { &mut self, mk_lit_char: impl FnOnce(Symbol, Span) -> L, ) -> PResult<'a, L> { - let token = self.token.clone(); + let token = self.token; let err = |self_: &Self| { let msg = format!("unexpected token: {}", super::token_descr(&token)); self_.dcx().struct_span_err(token.span, msg) @@ -2368,7 +2368,7 @@ impl<'a> Parser<'a> { fn parse_expr_closure(&mut self) -> PResult<'a, P> { let lo = self.token.span; - let before = self.prev_token.clone(); + let before = self.prev_token; let binder = if self.check_keyword(exp!(For)) { let lo = self.token.span; let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?; @@ -2400,8 +2400,8 @@ impl<'a> Parser<'a> { FnRetTy::Default(_) => { let restrictions = self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET; - let prev = self.prev_token.clone(); - let token = self.token.clone(); + let prev = self.prev_token; + let token = self.token; let attrs = self.parse_outer_attributes()?; match self.parse_expr_res(restrictions, attrs) { Ok((expr, _)) => expr, @@ -2648,7 +2648,7 @@ impl<'a> Parser<'a> { } } else { let attrs = self.parse_outer_attributes()?; // For recovery. - let maybe_fatarrow = self.token.clone(); + let maybe_fatarrow = self.token; let block = if self.check(exp!(OpenBrace)) { self.parse_block()? } else if let Some(block) = recover_block_from_condition(self) { @@ -3856,7 +3856,7 @@ impl<'a> Parser<'a> { return Err(this.dcx().create_err(errors::ExpectedStructField { span: this.look_ahead(1, |t| t.span), ident_span: this.token.span, - token: this.look_ahead(1, |t| t.clone()), + token: this.look_ahead(1, |t| *t), })); } let (ident, expr) = if is_shorthand { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 83c0bceb20a4..73dc5c17a204 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1739,8 +1739,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; body } else { - let err = - errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone()); + let err = errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token); return Err(self.dcx().create_err(err)); }; @@ -2310,7 +2309,7 @@ impl<'a> Parser<'a> { || self.token.is_keyword(kw::Union)) && self.look_ahead(1, |t| t.is_ident()) { - let kw_token = self.token.clone(); + let kw_token = self.token; let kw_str = pprust::token_to_string(&kw_token); let item = self.parse_item(ForceCollect::No)?; let mut item = item.unwrap().span; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index bb9393b8918b..d7525a0d716d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -326,12 +326,12 @@ impl TokenCursor { // below can be removed. if let Some(tree) = self.curr.curr() { match tree { - &TokenTree::Token(ref token, spacing) => { + &TokenTree::Token(token, spacing) => { debug_assert!(!matches!( token.kind, token::OpenDelim(_) | token::CloseDelim(_) )); - let res = (token.clone(), spacing); + let res = (token, spacing); self.curr.bump(); return res; } @@ -1490,7 +1490,7 @@ impl<'a> Parser<'a> { _ => { let prev_spacing = self.token_spacing; self.bump(); - TokenTree::Token(self.prev_token.clone(), prev_spacing) + TokenTree::Token(self.prev_token, prev_spacing) } } } @@ -1676,7 +1676,7 @@ impl<'a> Parser<'a> { dbg_fmt.field("prev_token", &self.prev_token); let mut tokens = vec![]; for i in 0..lookahead { - let tok = self.look_ahead(i, |tok| tok.kind.clone()); + let tok = self.look_ahead(i, |tok| tok.kind); let is_eof = tok == TokenKind::Eof; tokens.push(tok); if is_eof { diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 576de7766849..b6e89cd7fa46 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -168,7 +168,7 @@ impl<'a> Parser<'a> { } else { Err(self.dcx().create_err(UnexpectedNonterminal::Ident { span: self.token.span, - token: self.token.clone(), + token: self.token, })) } } @@ -191,7 +191,7 @@ impl<'a> Parser<'a> { } else { Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime { span: self.token.span, - token: self.token.clone(), + token: self.token, })) } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 9612f71b2af9..d5f469f9aa9e 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -363,7 +363,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(TrailingVertNotAllowed { span: self.token.span, start: lo, - token: self.token.clone(), + token: self.token, note_double_vert: matches!(self.token.kind, token::OrOr), }); self.bump(); @@ -1519,8 +1519,8 @@ impl<'a> Parser<'a> { etc = PatFieldsRest::Rest; let mut etc_sp = self.token.span; if first_etc_and_maybe_comma_span.is_none() { - if let Some(comma_tok) = self - .look_ahead(1, |t| if *t == token::Comma { Some(t.clone()) } else { None }) + if let Some(comma_tok) = + self.look_ahead(1, |&t| if t == token::Comma { Some(t) } else { None }) { let nw_span = self .psess diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9c6830c36727..30fb96c6ea90 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -393,8 +393,8 @@ impl<'a> Parser<'a> { } else { // `(T, U) -> R` - let prev_token_before_parsing = self.prev_token.clone(); - let token_before_parsing = self.token.clone(); + let prev_token_before_parsing = self.prev_token; + let token_before_parsing = self.token; let mut snapshot = None; if self.may_recover() && prev_token_before_parsing == token::PathSep diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 953bc3030126..824e930aa88a 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -685,7 +685,7 @@ impl<'a> Parser<'a> { return Ok((AttrVec::new(), block)); } - let maybe_ident = self.prev_token.clone(); + let maybe_ident = self.prev_token; self.maybe_recover_unexpected_block_label(loop_header); if !self.eat(exp!(OpenBrace)) { return self.error_block_no_opening_brace(); diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 49ae6cb9b726..2f958f4d4927 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -2554,7 +2554,7 @@ fn look(p: &Parser<'_>, dist: usize, kind: rustc_ast::token::TokenKind) { // Do the `assert_eq` outside the closure so that `track_caller` works. // (`#![feature(closure_track_caller)]` + `#[track_caller]` on the closure // doesn't give the line number in the test below if the assertion fails.) - let tok = p.look_ahead(dist, |tok| tok.clone()); + let tok = p.look_ahead(dist, |tok| *tok); assert_eq!(kind, tok.kind); } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 93705da22c45..d0cff42a2091 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -547,7 +547,7 @@ impl<'a> Parser<'a> { // Recovery mutbl = Mutability::Mut; - let (dyn_tok, dyn_tok_sp) = (self.token.clone(), self.token_spacing); + let (dyn_tok, dyn_tok_sp) = (self.token, self.token_spacing); self.bump(); self.bump_with((dyn_tok, dyn_tok_sp)); } @@ -886,7 +886,7 @@ impl<'a> Parser<'a> { /// ``` fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { let lo = self.token.span; - let leading_token = self.prev_token.clone(); + let leading_token = self.prev_token; let has_parens = self.eat(exp!(OpenParen)); let bound = if self.token.is_lifetime() { diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index ddf3d2ce96af..1e16aace3041 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -858,18 +858,18 @@ impl MacroArgParser { }; self.result.push(ParsedMacroArg { - kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()), + kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok), }); Some(()) } - fn update_buffer(&mut self, t: &Token) { + fn update_buffer(&mut self, t: Token) { if self.buf.is_empty() { - self.start_tok = t.clone(); + self.start_tok = t; } else { let needs_space = match next_space(&self.last_tok.kind) { - SpaceState::Ident => ident_like(t), - SpaceState::Punctuation => !ident_like(t), + SpaceState::Ident => ident_like(&t), + SpaceState::Punctuation => !ident_like(&t), SpaceState::Always => true, SpaceState::Never => false, }; @@ -878,7 +878,7 @@ impl MacroArgParser { } } - self.buf.push_str(&pprust::token_to_string(t)); + self.buf.push_str(&pprust::token_to_string(&t)); } fn need_space_prefix(&self) -> bool { @@ -937,7 +937,7 @@ impl MacroArgParser { ) if self.is_meta_var => { self.add_meta_variable(&mut iter)?; } - TokenTree::Token(ref t, _) => self.update_buffer(t), + &TokenTree::Token(t, _) => self.update_buffer(t), &TokenTree::Delimited(_dspan, _spacing, delimited, ref tts) => { if !self.buf.is_empty() { if next_space(&self.last_tok.kind) == SpaceState::Always { From 4c0cbaeb9e799362dd081ff8514f75e23ab8c2f5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 4 Jul 2024 10:16:51 +1000 Subject: [PATCH 011/222] Remove `TokenStream::flattened` and `InvisibleOrigin::FlattenToken`. They are no longer needed. This does slightly worsen the error message for a single test, but that test contains code that is so badly broken that I'm not worried about it. --- compiler/rustc_ast/src/token.rs | 8 +--- compiler/rustc_ast/src/tokenstream.rs | 44 +------------------ compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 10 ++--- compiler/rustc_expand/src/config.rs | 6 --- tests/ui/macros/syntax-error-recovery.rs | 4 +- tests/ui/macros/syntax-error-recovery.stderr | 6 +-- 8 files changed, 12 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 9d56cc83ac8c..055481f5d878 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -30,10 +30,6 @@ pub enum InvisibleOrigin { // Converted from `proc_macro::Delimiter` in // `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro. ProcMacro, - - // Converted from `TokenKind::NtLifetime` in `TokenStream::flatten_token`. - // Treated similarly to `ProcMacro`. - FlattenToken, } impl PartialEq for InvisibleOrigin { @@ -130,9 +126,7 @@ impl Delimiter { match self { Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false, Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false, - Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => { - true - } + Delimiter::Invisible(InvisibleOrigin::ProcMacro) => true, } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 8260842fb879..43d25d180750 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -25,7 +25,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym}; use crate::ast::AttrStyle; use crate::ast_traits::{HasAttrs, HasTokens}; -use crate::token::{self, Delimiter, InvisibleOrigin, Token, TokenKind}; +use crate::token::{self, Delimiter, Token, TokenKind}; use crate::{AttrVec, Attribute}; /// Part of a `TokenStream`. @@ -471,48 +471,6 @@ impl TokenStream { TokenStream::new(tts) } - fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree { - match token.kind { - token::NtIdent(ident, is_raw) => { - TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing) - } - token::NtLifetime(ident, is_raw) => TokenTree::Delimited( - DelimSpan::from_single(token.span), - DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible(InvisibleOrigin::FlattenToken), - TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), - ), - _ => TokenTree::Token(*token, spacing), - } - } - - fn flatten_token_tree(tree: &TokenTree) -> TokenTree { - match tree { - TokenTree::Token(token, spacing) => TokenStream::flatten_token(token, *spacing), - TokenTree::Delimited(span, spacing, delim, tts) => { - TokenTree::Delimited(*span, *spacing, *delim, tts.flattened()) - } - } - } - - #[must_use] - pub fn flattened(&self) -> TokenStream { - fn can_skip(stream: &TokenStream) -> bool { - stream.iter().all(|tree| match tree { - TokenTree::Token(token, _) => { - !matches!(token.kind, token::NtIdent(..) | token::NtLifetime(..)) - } - TokenTree::Delimited(.., inner) => can_skip(inner), - }) - } - - if can_skip(self) { - return self.clone(); - } - - self.iter().map(|tree| TokenStream::flatten_token_tree(tree)).collect() - } - // If `vec` is not empty, try to glue `tt` onto its last token. The return // value indicates if gluing took place. fn try_glue_to_last(vec: &mut Vec, tt: &TokenTree) -> bool { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d5d6dcd8d631..4fbd62864a1b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -917,7 +917,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs { - DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() } + DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.clone() } } /// Lower an associated item constraint. diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index a68d4578b40f..3bf03f84ce8f 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -320,7 +320,7 @@ impl<'sess> AttributeParser<'sess> { ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs { dspan: args.dspan, delim: args.delim, - tokens: args.tokens.flattened(), + tokens: args.tokens.clone(), }), // This is an inert key-value attribute - it will never be visible to macros // after it gets lowered to HIR. Therefore, we can extract literals to handle diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index ea0bbd0e31ad..da01e3e9607b 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -92,11 +92,7 @@ impl CfgEval<'_> { // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization // process is lossless, so this process is invisible to proc-macros. - // 'Flatten' all nonterminals (i.e. `TokenKind::Nt{Ident,Lifetime}`) - // to `None`-delimited groups containing the corresponding tokens. This - // is normally delayed until the proc-macro server actually needs to - // provide tokens to a proc-macro. We do this earlier, so that we can - // handle cases like: + // Interesting cases: // // ```rust // #[cfg_eval] #[cfg] $item @@ -104,8 +100,8 @@ impl CfgEval<'_> { // // where `$item` is `#[cfg_attr] struct Foo {}`. We want to make // sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest - // way to do this is to do a single parse of a stream without any nonterminals. - let orig_tokens = annotatable.to_tokens().flattened(); + // way to do this is to do a single parse of the token stream. + let orig_tokens = annotatable.to_tokens(); // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 27924544de52..c70e259b2cd8 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -237,12 +237,6 @@ impl<'a> StripUnconfigured<'a> { inner = self.configure_tokens(&inner); Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)) } - AttrTokenTree::Token( - Token { kind: TokenKind::NtIdent(..) | TokenKind::NtLifetime(..), .. }, - _, - ) => { - panic!("Nonterminal should have been flattened: {:?}", tree); - } AttrTokenTree::Token( Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. }, _, diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs index 6cf9d54e8263..e1681ea32a2e 100644 --- a/tests/ui/macros/syntax-error-recovery.rs +++ b/tests/ui/macros/syntax-error-recovery.rs @@ -5,14 +5,14 @@ macro_rules! values { $( #[$attr] $token $($inner)? = $value, + //~^ ERROR expected one of `!` or `::`, found `` )* } }; } -//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable +//~^^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable //~| ERROR macro expansion ignores `ty` metavariable and any tokens following values!(STRING(1) as (String) => cfg(test),); -//~^ ERROR expected one of `!` or `::`, found `` fn main() {} diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr index 61758fb9d7dc..a2059aa1aa80 100644 --- a/tests/ui/macros/syntax-error-recovery.stderr +++ b/tests/ui/macros/syntax-error-recovery.stderr @@ -22,10 +22,10 @@ LL | values!(STRING(1) as (String) => cfg(test),); = note: the usage of `values!` is likely invalid in item context error: expected one of `!` or `::`, found `` - --> $DIR/syntax-error-recovery.rs:15:9 + --> $DIR/syntax-error-recovery.rs:7:17 | -LL | values!(STRING(1) as (String) => cfg(test),); - | ^^^^^^ expected one of `!` or `::` +LL | $token $($inner)? = $value, + | ^^^^^^ expected one of `!` or `::` error: aborting due to 3 previous errors From 1830245a224c523f86ad3c62be76be3f336a9fb0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Apr 2025 16:25:27 +1100 Subject: [PATCH 012/222] Remove `recursion_limit` increases. These are no longer needed now that `Nonterminal` is gone. --- compiler/rustc_ast/src/lib.rs | 1 - compiler/rustc_ast_lowering/src/lib.rs | 1 - compiler/rustc_attr_parsing/src/lib.rs | 1 - compiler/rustc_borrowck/src/lib.rs | 1 - compiler/rustc_builtin_macros/src/lib.rs | 1 - compiler/rustc_codegen_ssa/src/lib.rs | 1 - compiler/rustc_const_eval/src/lib.rs | 1 - compiler/rustc_driver/src/lib.rs | 1 - compiler/rustc_driver_impl/src/lib.rs | 1 - compiler/rustc_hir/src/lib.rs | 1 - compiler/rustc_hir_analysis/src/lib.rs | 1 - compiler/rustc_hir_typeck/src/lib.rs | 1 - compiler/rustc_incremental/src/lib.rs | 1 - compiler/rustc_lint/src/lib.rs | 1 - compiler/rustc_metadata/src/lib.rs | 1 - compiler/rustc_middle/src/lib.rs | 1 - compiler/rustc_mir_build/src/lib.rs | 1 - compiler/rustc_mir_dataflow/src/lib.rs | 1 - compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_monomorphize/src/lib.rs | 1 - compiler/rustc_parse/src/lib.rs | 1 - compiler/rustc_passes/src/lib.rs | 1 - compiler/rustc_privacy/src/lib.rs | 1 - compiler/rustc_query_impl/src/lib.rs | 1 - compiler/rustc_sanitizers/src/lib.rs | 1 - compiler/rustc_smir/src/lib.rs | 1 - compiler/rustc_symbol_mangling/src/lib.rs | 1 - compiler/rustc_transmute/src/lib.rs | 1 - compiler/rustc_ty_utils/src/lib.rs | 1 - 29 files changed, 29 deletions(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index da510e4967db..294c6c9ba7a5 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4fbd62864a1b..17cac88aacbe 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,7 +32,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index a7465847e18b..249e71ef70dc 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -77,7 +77,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(let_chains)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 84b7b8c6a2de..4a4a99aa154e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,7 +2,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 606e85577f7e..bcd40f980e64 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,7 +5,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index d26d6edf3149..a49f82a2bca5 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -2,7 +2,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index e03849c32f94..da52d60ae59f 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 381309f83b2c..a03834c519d5 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -3,7 +3,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 37755e7d61db..d3d435b01e99 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -7,7 +7,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(decl_macro)] diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 4a839d405718..84d369f1eddb 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,7 +4,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(closure_track_caller)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index e7ecd727a852..e1ad8124aea7 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,7 +59,6 @@ This API is completely unstable and subject to change. #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 4968998fd512..263fb84206e0 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index dabfb6a90cad..299ee4876389 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -2,7 +2,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![deny(missing_docs)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 25878c7ac814..7b05b4d26d32 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -21,7 +21,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 028d5c8b6099..3b44c44fcb94 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(coroutines)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 1e6178144c92..8fe2cc7101ba 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,7 +29,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index a25697ba086d..8e96d46dac27 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -3,7 +3,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 82c57ef5678d..a0efc623b8e7 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_patterns)] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 205d388f4fb5..739cee5d7f4c 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 5dbae50c499f..8f6914f3d724 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(file_buffered)] #![feature(if_let_guard)] diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 79939aab7fc2..2edc8c83017d 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -4,7 +4,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 6f6115af96c8..93ff0f66d695 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(let_chains)] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 643b82f47530..c7bab828659a 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 30a9e718d236..3c329dd0a0e8 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -3,7 +3,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(unused_parens)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(min_specialization)] diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs index c4a9cab24d07..e4792563e71e 100644 --- a/compiler/rustc_sanitizers/src/lib.rs +++ b/compiler/rustc_sanitizers/src/lib.rs @@ -4,7 +4,6 @@ //! compiler. // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(let_chains)] // tidy-alphabetical-end diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index eaba14bbf30f..9f8888753061 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -9,7 +9,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::usage_of_ty_tykind)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c9b15151a2cb..cc33974cc627 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -89,7 +89,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(let_chains)] diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 7d800e49ff45..00928137d297 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(never_type)] // tidy-alphabetical-end diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 143b7d538801..35cc6f398565 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] From 4a8d35709e301d983412b42b26dad6eb5c869951 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 2 Apr 2025 19:14:27 +0000 Subject: [PATCH 013/222] Revert "Disable `f16` on Aarch64 without `neon`" The LLVM issue [1] was resolved and the fix was synced to rust-lang/rust in [2]. This reverts commit c51b229140c885cac757a405a328a07e90d5bca9. [1]: https://github.com/llvm/llvm-project/issues/129394 [2]: https://github.com/rust-lang/rust/pull/138695 --- library/std/build.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index d76d07a89f4e..40a56d4930d3 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -12,11 +12,6 @@ fn main() { .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set") .parse() .unwrap(); - let target_features: Vec<_> = env::var("CARGO_CFG_TARGET_FEATURE") - .unwrap_or_default() - .split(",") - .map(ToOwned::to_owned) - .collect(); let is_miri = env::var_os("CARGO_CFG_MIRI").is_some(); println!("cargo:rustc-check-cfg=cfg(netbsd10)"); @@ -108,8 +103,6 @@ fn main() { ("s390x", _) => false, // Unsupported ("arm64ec", _) => false, - // LLVM crash - ("aarch64", _) if !target_features.iter().any(|f| f == "neon") => false, // MinGW ABI bugs ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // Infinite recursion From 984c51f6a1d93fa244829f488d2945e7fc06b880 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 18 Mar 2025 01:01:15 +0000 Subject: [PATCH 014/222] Stabilize `cfg_boolean_literals` --- .../rustc_attr_parsing/src/attributes/cfg.rs | 15 ------- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/unstable.rs | 2 - .../language-features/cfg-boolean-literals.md | 22 ---------- .../crates/ide-db/src/generated/lints.rs | 29 ------------- tests/rustdoc-ui/cfg-boolean-literal.rs | 1 - tests/rustdoc-ui/doc-cfg-unstable.rs | 4 -- tests/rustdoc-ui/doc-cfg-unstable.stderr | 14 +----- tests/ui/cfg/true-false.rs | 1 - .../feature-gate-cfg-boolean-literals.rs | 10 ----- .../feature-gate-cfg-boolean-literals.stderr | 43 ------------------- tests/ui/lint/inert-attr-macro.rs | 1 - tests/ui/lint/inert-attr-macro.stderr | 14 +++--- tests/ui/proc-macro/cfg-attr-trace.rs | 1 - tests/ui/proc-macro/cfg-attr-trace.stdout | 30 ++++++------- 15 files changed, 26 insertions(+), 163 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/cfg-boolean-literals.md delete mode 100644 tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs delete mode 100644 tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 0d6d521b40c6..48297b2ebd8c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -7,7 +7,6 @@ use rustc_session::config::ExpectedValues; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::feature_err; -use rustc_span::symbol::kw; use rustc_span::{Span, Symbol, sym}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -89,20 +88,6 @@ pub fn eval_condition( let cfg = match cfg { MetaItemInner::MetaItem(meta_item) => meta_item, MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { - if let Some(features) = features { - // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true` - // and `true`, and we want to keep the former working without feature gate - gate_cfg( - &( - if *b { kw::True } else { kw::False }, - sym::cfg_boolean_literals, - |features: &Features| features.cfg_boolean_literals(), - ), - cfg.span(), - sess, - features, - ); - } return *b; } _ => { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 88e6593572bc..a9ef7c3f9f18 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -95,6 +95,8 @@ declare_features! ( (accepted, c_unwind, "1.81.0", Some(74990)), /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. (accepted, cfg_attr_multi, "1.33.0", Some(54881)), + /// Allows the use of `#[cfg()]`. + (accepted, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)), /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests. (accepted, cfg_doctest, "1.40.0", Some(62210)), /// Enables `#[cfg(panic = "...")]` config key. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 87b88bb4223e..6ead07ac0ffb 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -391,8 +391,6 @@ declare_features! ( (unstable, async_trait_bounds, "1.85.0", Some(62290)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), - /// Allows the use of `#[cfg()]`. - (unstable, cfg_boolean_literals, "1.83.0", Some(131204)), /// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled. (unstable, cfg_contract_checks, "1.86.0", Some(128044)), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. diff --git a/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md b/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md deleted file mode 100644 index ad795ff9d9b2..000000000000 --- a/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md +++ /dev/null @@ -1,22 +0,0 @@ -# `cfg_boolean_literals` - -The tracking issue for this feature is: [#131204] - -[#131204]: https://github.com/rust-lang/rust/issues/131204 - ------------------------- - -The `cfg_boolean_literals` feature makes it possible to use the `true`/`false` -literal as cfg predicate. They always evaluate to true/false respectively. - -## Examples - -```rust -#![feature(cfg_boolean_literals)] - -#[cfg(true)] -const A: i32 = 5; - -#[cfg(all(false))] -const A: i32 = 58 * 89; -``` diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 0a7a7d1fb241..706d04484f6f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -3789,35 +3789,6 @@ The tracking issue for this feature is: [#64797] [#64797]: https://github.com/rust-lang/rust/issues/64797 ------------------------ -"##, - default_severity: Severity::Allow, - warn_since: None, - deny_since: None, - }, - Lint { - label: "cfg_boolean_literals", - description: r##"# `cfg_boolean_literals` - -The tracking issue for this feature is: [#131204] - -[#131204]: https://github.com/rust-lang/rust/issues/131204 - ------------------------- - -The `cfg_boolean_literals` feature makes it possible to use the `true`/`false` -literal as cfg predicate. They always evaluate to true/false respectively. - -## Examples - -```rust -#![feature(cfg_boolean_literals)] - -#[cfg(true)] -const A: i32 = 5; - -#[cfg(all(false))] -const A: i32 = 58 * 89; -``` "##, default_severity: Severity::Allow, warn_since: None, diff --git a/tests/rustdoc-ui/cfg-boolean-literal.rs b/tests/rustdoc-ui/cfg-boolean-literal.rs index 4d4e599bfeef..74808d066c71 100644 --- a/tests/rustdoc-ui/cfg-boolean-literal.rs +++ b/tests/rustdoc-ui/cfg-boolean-literal.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(cfg_boolean_literals)] #![feature(doc_cfg)] #[doc(cfg(false))] diff --git a/tests/rustdoc-ui/doc-cfg-unstable.rs b/tests/rustdoc-ui/doc-cfg-unstable.rs index 14c2e83ec854..b77c3654497d 100644 --- a/tests/rustdoc-ui/doc-cfg-unstable.rs +++ b/tests/rustdoc-ui/doc-cfg-unstable.rs @@ -1,10 +1,6 @@ // #138113: rustdoc didn't gate unstable predicates inside `doc(cfg(..))` #![feature(doc_cfg)] -// `cfg_boolean_literals` -#[doc(cfg(false))] //~ ERROR `cfg(false)` is experimental and subject to change -pub fn cfg_boolean_literals() {} - // `cfg_version` #[doc(cfg(sanitize = "thread"))] //~ ERROR `cfg(sanitize)` is experimental and subject to change pub fn cfg_sanitize() {} diff --git a/tests/rustdoc-ui/doc-cfg-unstable.stderr b/tests/rustdoc-ui/doc-cfg-unstable.stderr index 54de3b178edb..9651c5f1a0b0 100644 --- a/tests/rustdoc-ui/doc-cfg-unstable.stderr +++ b/tests/rustdoc-ui/doc-cfg-unstable.stderr @@ -1,15 +1,5 @@ -error[E0658]: `cfg(false)` is experimental and subject to change - --> $DIR/doc-cfg-unstable.rs:5:11 - | -LL | #[doc(cfg(false))] - | ^^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: `cfg(sanitize)` is experimental and subject to change - --> $DIR/doc-cfg-unstable.rs:9:11 + --> $DIR/doc-cfg-unstable.rs:5:11 | LL | #[doc(cfg(sanitize = "thread"))] | ^^^^^^^^^^^^^^^^^^^ @@ -18,6 +8,6 @@ LL | #[doc(cfg(sanitize = "thread"))] = help: add `#![feature(cfg_sanitize)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/cfg/true-false.rs b/tests/ui/cfg/true-false.rs index 03d96fbafecb..0bd1cf427faf 100644 --- a/tests/ui/cfg/true-false.rs +++ b/tests/ui/cfg/true-false.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(link_cfg)] -#![feature(cfg_boolean_literals)] #[cfg(true)] fn foo() -> bool { diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs deleted file mode 100644 index 6784b4450490..000000000000 --- a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[cfg(true)] //~ ERROR `cfg(true)` is experimental -fn foo() {} - -#[cfg_attr(true, cfg(false))] //~ ERROR `cfg(true)` is experimental -//~^ ERROR `cfg(false)` is experimental -fn foo() {} - -fn main() { - cfg!(false); //~ ERROR `cfg(false)` is experimental -} diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr deleted file mode 100644 index 64491464f1d4..000000000000 --- a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0658]: `cfg(true)` is experimental and subject to change - --> $DIR/feature-gate-cfg-boolean-literals.rs:1:7 - | -LL | #[cfg(true)] - | ^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(true)` is experimental and subject to change - --> $DIR/feature-gate-cfg-boolean-literals.rs:4:12 - | -LL | #[cfg_attr(true, cfg(false))] - | ^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(false)` is experimental and subject to change - --> $DIR/feature-gate-cfg-boolean-literals.rs:4:22 - | -LL | #[cfg_attr(true, cfg(false))] - | ^^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(false)` is experimental and subject to change - --> $DIR/feature-gate-cfg-boolean-literals.rs:9:10 - | -LL | cfg!(false); - | ^^^^^ - | - = note: see issue #131204 for more information - = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/inert-attr-macro.rs b/tests/ui/lint/inert-attr-macro.rs index 5d4133d6c774..f2d50e30aecc 100644 --- a/tests/ui/lint/inert-attr-macro.rs +++ b/tests/ui/lint/inert-attr-macro.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(cfg_boolean_literals)] #![warn(unused)] macro_rules! foo { diff --git a/tests/ui/lint/inert-attr-macro.stderr b/tests/ui/lint/inert-attr-macro.stderr index b85b0319e712..5ccb4ffe7929 100644 --- a/tests/ui/lint/inert-attr-macro.stderr +++ b/tests/ui/lint/inert-attr-macro.stderr @@ -1,41 +1,41 @@ warning: unused attribute `inline` - --> $DIR/inert-attr-macro.rs:11:5 + --> $DIR/inert-attr-macro.rs:10:5 | LL | #[inline] foo!(); | ^^^^^^^^^ | note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:11:15 + --> $DIR/inert-attr-macro.rs:10:15 | LL | #[inline] foo!(); | ^^^ note: the lint level is defined here - --> $DIR/inert-attr-macro.rs:4:9 + --> $DIR/inert-attr-macro.rs:3:9 | LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]` warning: unused attribute `allow` - --> $DIR/inert-attr-macro.rs:15:5 + --> $DIR/inert-attr-macro.rs:14:5 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^^^^^^^^^^^^^^^^ | note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:15:34 + --> $DIR/inert-attr-macro.rs:14:34 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^ warning: unused attribute `inline` - --> $DIR/inert-attr-macro.rs:15:24 + --> $DIR/inert-attr-macro.rs:14:24 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^^^^^^^ | note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:15:34 + --> $DIR/inert-attr-macro.rs:14:34 | LL | #[allow(warnings)] #[inline] foo!(); | ^^^ diff --git a/tests/ui/proc-macro/cfg-attr-trace.rs b/tests/ui/proc-macro/cfg-attr-trace.rs index 140dd10a7e04..412c65bed1d8 100644 --- a/tests/ui/proc-macro/cfg-attr-trace.rs +++ b/tests/ui/proc-macro/cfg-attr-trace.rs @@ -3,7 +3,6 @@ //@ check-pass //@ proc-macro: test-macros.rs -#![feature(cfg_boolean_literals)] #![feature(cfg_eval)] #[macro_use] diff --git a/tests/ui/proc-macro/cfg-attr-trace.stdout b/tests/ui/proc-macro/cfg-attr-trace.stdout index 52f9ff4e05c5..33bcfe5d69b7 100644 --- a/tests/ui/proc-macro/cfg-attr-trace.stdout +++ b/tests/ui/proc-macro/cfg-attr-trace.stdout @@ -4,75 +4,75 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: #0 bytes(305..306), + span: #0 bytes(271..272), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "test_macros", - span: #0 bytes(322..333), + span: #0 bytes(288..299), }, Punct { ch: ':', spacing: Joint, - span: #0 bytes(333..334), + span: #0 bytes(299..300), }, Punct { ch: ':', spacing: Alone, - span: #0 bytes(334..335), + span: #0 bytes(300..301), }, Ident { ident: "print_attr", - span: #0 bytes(335..345), + span: #0 bytes(301..311), }, ], - span: #0 bytes(306..347), + span: #0 bytes(272..313), }, Ident { ident: "struct", - span: #0 bytes(348..354), + span: #0 bytes(314..320), }, Ident { ident: "S", - span: #0 bytes(355..356), + span: #0 bytes(321..322), }, Punct { ch: ';', spacing: Alone, - span: #0 bytes(356..357), + span: #0 bytes(322..323), }, ] PRINT-ATTR INPUT (DISPLAY): struct S; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #0 bytes(348..354), + span: #0 bytes(314..320), }, Ident { ident: "S", - span: #0 bytes(355..356), + span: #0 bytes(321..322), }, Punct { ch: ';', spacing: Alone, - span: #0 bytes(356..357), + span: #0 bytes(322..323), }, ] PRINT-ATTR INPUT (DISPLAY): struct Z; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #0 bytes(411..417), + span: #0 bytes(377..383), }, Ident { ident: "Z", - span: #0 bytes(418..419), + span: #0 bytes(384..385), }, Punct { ch: ';', spacing: Alone, - span: #0 bytes(419..420), + span: #0 bytes(385..386), }, ] From d83f4153251ad3e85e975fa3e613378eba913c0b Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 18 Mar 2025 13:06:25 +0000 Subject: [PATCH 015/222] Add more tests for `cfg_boolean_literals` --- tests/ui/cfg/both-true-false.rs | 14 ++++++++++++++ tests/ui/cfg/both-true-false.stderr | 9 +++++++++ tests/ui/cfg/cmdline-false.rs | 9 +++++++++ tests/ui/cfg/cmdline-false.stderr | 9 +++++++++ 4 files changed, 41 insertions(+) create mode 100644 tests/ui/cfg/both-true-false.rs create mode 100644 tests/ui/cfg/both-true-false.stderr create mode 100644 tests/ui/cfg/cmdline-false.rs create mode 100644 tests/ui/cfg/cmdline-false.stderr diff --git a/tests/ui/cfg/both-true-false.rs b/tests/ui/cfg/both-true-false.rs new file mode 100644 index 000000000000..5fca8f654ad8 --- /dev/null +++ b/tests/ui/cfg/both-true-false.rs @@ -0,0 +1,14 @@ +/// Test that placing a `cfg(true)` and `cfg(false)` on the same item result in +//. it being disabled.` + +#[cfg(false)] +#[cfg(true)] +fn foo() {} + +#[cfg(true)] +#[cfg(false)] +fn foo() {} + +fn main() { + foo(); //~ ERROR cannot find function `foo` in this scope +} diff --git a/tests/ui/cfg/both-true-false.stderr b/tests/ui/cfg/both-true-false.stderr new file mode 100644 index 000000000000..1526cc2b707b --- /dev/null +++ b/tests/ui/cfg/both-true-false.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find function `foo` in this scope + --> $DIR/both-true-false.rs:13:5 + | +LL | foo(); + | ^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/cfg/cmdline-false.rs b/tests/ui/cfg/cmdline-false.rs new file mode 100644 index 000000000000..d4b7d3bbfdca --- /dev/null +++ b/tests/ui/cfg/cmdline-false.rs @@ -0,0 +1,9 @@ +/// Test that `--cfg false` doesn't cause `cfg(false)` to evaluate to `true` +//@ compile-flags: --cfg false + +#[cfg(false)] +fn foo() {} + +fn main() { + foo(); //~ ERROR cannot find function `foo` in this scope +} diff --git a/tests/ui/cfg/cmdline-false.stderr b/tests/ui/cfg/cmdline-false.stderr new file mode 100644 index 000000000000..5f57c754c403 --- /dev/null +++ b/tests/ui/cfg/cmdline-false.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find function `foo` in this scope + --> $DIR/cmdline-false.rs:8:5 + | +LL | foo(); + | ^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. From 303c1b45c29f8bb186a9a95cb56643d1aef773fa Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sat, 29 Mar 2025 17:24:03 +0000 Subject: [PATCH 016/222] Use `cfg(false)` in UI tests --- tests/pretty/ast-stmt-expr-attr.rs | 2 +- tests/pretty/enum-variant-vis.rs | 2 +- tests/pretty/if-attr.rs | 8 +- tests/pretty/nested-item-vis-defaultness.rs | 6 +- .../associated-types/associated-type-macro.rs | 2 +- .../ui/async-await/feature-async-for-loop.rs | 2 +- tests/ui/async-await/no-unsafe-async.rs | 4 +- tests/ui/attributes/z-crate-attr/cfg-false.rs | 4 +- tests/ui/auto-traits/pre-cfg.rs | 2 +- tests/ui/cfg/auxiliary/cfg_false_lib.rs | 4 +- .../auxiliary/cfg_false_lib_no_std_after.rs | 4 +- .../auxiliary/cfg_false_lib_no_std_before.rs | 4 +- tests/ui/cfg/auxiliary/cfged_out.rs | 4 +- tests/ui/cfg/cfg-false-feature.rs | 4 +- tests/ui/cfg/cfg-macros-notfoo.rs | 2 +- tests/ui/cfg/cfg-match-arm.rs | 2 +- tests/ui/cfg/cfg-stmt-recovery.rs | 2 +- tests/ui/cfg/cfg-stmt-recovery.stderr | 6 +- tests/ui/cfg/cfg_stmt_expr.rs | 30 ++-- tests/ui/cfg/conditional-compile.rs | 36 ++--- tests/ui/cfg/diagnostics-cross-crate.stderr | 4 +- tests/ui/cfg/diagnostics-reexport.rs | 10 +- tests/ui/cfg/diagnostics-reexport.stderr | 8 +- tests/ui/cfg/diagnostics-same-crate.rs | 4 +- tests/ui/cfg/diagnostics-same-crate.stderr | 8 +- tests/ui/check-cfg/allow-same-level.rs | 2 +- tests/ui/check-cfg/allow-same-level.stderr | 8 +- tests/ui/check-cfg/allow-top-level.rs | 2 +- tests/ui/check-cfg/allow-upper-level.rs | 2 +- .../cfg-generic-params.rs | 16 +- .../cfg-generic-params.stderr | 6 +- .../conditional-compilation/cfg-in-crate-1.rs | 2 +- .../cfg-in-crate-1.stderr | 2 +- .../cfg-non-opt-expr.rs | 6 +- .../cfg-non-opt-expr.stderr | 6 +- .../module_with_cfg.rs | 2 +- ...nst-extern-fns-dont-need-fn-specifier-2.rs | 2 +- ...const-extern-fns-dont-need-fn-specifier.rs | 2 +- .../explicit-paths-signature-pass.rs | 2 +- tests/ui/expr/if/attrs/bad-cfg.rs | 2 +- tests/ui/expr/if/attrs/bad-cfg.stderr | 2 +- tests/ui/expr/if/attrs/cfg-false-if-attr.rs | 14 +- tests/ui/expr/if/attrs/else-attrs.rs | 6 +- tests/ui/expr/if/attrs/gate-whole-expr.rs | 2 +- tests/ui/expr/if/attrs/let-chains-attr.rs | 2 +- .../feature-gates/feature-gate-coroutines.rs | 2 +- .../feature-gate-deref_patterns.rs | 2 +- .../feature-gates/feature-gate-gen_blocks.rs | 2 +- .../feature-gate-guard-patterns.rs | 2 +- .../ui/feature-gates/feature-gate-mut-ref.rs | 4 +- .../feature-gate-never_patterns.rs | 8 +- .../feature-gate-postfix_match.rs | 2 +- .../feature-gate-yeet_expr-in-cfg.rs | 4 +- .../soft-syntax-gates-with-errors.rs | 6 +- .../soft-syntax-gates-without-errors.rs | 6 +- .../stmt_expr_attrs_no_feature.rs | 24 +-- tests/ui/filter-block-view-items.rs | 2 +- ...nge-pats-inclusive-dotdotdot-bad-syntax.rs | 2 +- .../half-open-range-pats-inclusive-no-end.rs | 2 +- ...lf-open-range-pats-ref-ambiguous-interp.rs | 2 +- .../half-open-range-pats-syntactic-pass.rs | 2 +- tests/ui/inner-attrs-on-impl.rs | 4 +- tests/ui/issues/issue-11004.rs | 2 +- tests/ui/issues/issue-11085.rs | 8 +- tests/ui/issues/issue-16819.rs | 2 +- tests/ui/lexer/error-stage.rs | 2 +- .../link-attr-validation-late.rs | 2 +- .../link-attr-validation-late.stderr | 2 +- .../ui/lint/unused/unused-attr-macro-rules.rs | 2 +- tests/ui/macros/lint-trailing-macro-call.rs | 2 +- .../ui/macros/lint-trailing-macro-call.stderr | 4 +- tests/ui/macros/macro-attributes.rs | 2 +- tests/ui/macros/macro-inner-attributes.rs | 2 +- tests/ui/macros/macro-outer-attributes.rs | 2 +- tests/ui/macros/macro-outer-attributes.stderr | 2 +- tests/ui/macros/macro-with-attrs2.rs | 2 +- tests/ui/nested-cfg-attrs.rs | 2 +- .../ui/or-patterns/fn-param-wrap-parens.fixed | 2 +- tests/ui/or-patterns/fn-param-wrap-parens.rs | 2 +- .../or-patterns/or-patterns-syntactic-pass.rs | 2 +- .../ui/or-patterns/remove-leading-vert.fixed | 4 +- tests/ui/or-patterns/remove-leading-vert.rs | 4 +- .../assoc-const-underscore-syntactic-pass.rs | 2 +- .../assoc/assoc-static-syntactic-fail.rs | 6 +- .../attribute/attr-stmt-expr-attr-bad.rs | 90 +++++------ .../attribute/attr-stmt-expr-attr-bad.stderr | 150 +++++++++--------- .../multiple-tail-expr-behind-cfg.rs | 2 +- .../multiple-tail-expr-behind-cfg.stderr | 4 +- ...from-trailing-outer-attribute-in-body-2.rs | 2 +- ...-trailing-outer-attribute-in-body-2.stderr | 2 +- ...ints-before-generic-args-syntactic-pass.rs | 2 +- tests/ui/parser/default-on-wrong-item-kind.rs | 8 +- tests/ui/parser/extern-abi-syntactic.rs | 6 +- tests/ui/parser/extern-crate-async.rs | 4 +- .../parser/fn-body-optional-syntactic-pass.rs | 2 +- tests/ui/parser/fn-header-syntactic-pass.rs | 2 +- .../ui/parser/foreign-const-syntactic-fail.rs | 2 +- .../parser/foreign-static-syntactic-pass.rs | 2 +- tests/ui/parser/foreign-ty-syntactic-pass.rs | 2 +- tests/ui/parser/impl-item-const-pass.rs | 2 +- tests/ui/parser/impl-item-fn-no-body-pass.rs | 2 +- .../ui/parser/impl-item-type-no-body-pass.rs | 2 +- .../issue-65041-empty-vis-matcher-in-enum.rs | 2 +- .../issue-65041-empty-vis-matcher-in-trait.rs | 2 +- .../item-free-const-no-body-syntactic-pass.rs | 2 +- ...item-free-static-no-body-syntactic-pass.rs | 2 +- .../item-free-type-bounds-syntactic-pass.rs | 2 +- .../recover/recover-assoc-const-constraint.rs | 2 +- .../recover/recover-assoc-eq-missing-term.rs | 2 +- .../recover-assoc-lifetime-constraint.rs | 2 +- tests/ui/parser/self-param-syntactic-pass.rs | 10 +- .../stripped-nested-outline-mod-pass.rs | 2 +- .../trait-item-with-defaultness-pass.rs | 2 +- .../ui/parser/variadic-ffi-syntactic-pass.rs | 22 +-- ...d-type-ascription-syntactically-invalid.rs | 6 +- .../wild-before-at-syntactically-rejected.rs | 2 +- tests/ui/pattern/rest-pat-syntactic.rs | 2 +- tests/ui/proc-macro/attribute-after-derive.rs | 4 +- .../proc-macro/attribute-after-derive.stdout | 12 +- tests/ui/proc-macro/cfg-eval-fail.rs | 2 +- tests/ui/proc-macro/cfg-eval-fail.stderr | 2 +- tests/ui/proc-macro/cfg-eval-inner.rs | 2 +- tests/ui/proc-macro/cfg-eval.rs | 6 +- .../ui/proc-macro/derive-cfg-nested-tokens.rs | 2 +- .../derive-cfg-nested-tokens.stdout | 4 +- tests/ui/proc-macro/expand-to-derive.rs | 4 +- tests/ui/proc-macro/issue-75930-derive-cfg.rs | 26 +-- .../proc-macro/issue-75930-derive-cfg.stdout | 90 +++++------ tests/ui/proc-macro/nested-derive-cfg.rs | 4 +- .../rfc-2294-if-let-guard/feature-gate.rs | 2 +- tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs | 2 +- .../disallowed-positions.rs | 8 +- .../rfc-2497-if-let-chains/feature-gate.rs | 2 +- .../feature-gate.stderr | 2 +- .../invalid-let-in-a-valid-let-context.rs | 10 +- .../attr-without-param.rs | 6 +- .../specialization/issue-63716-parse-async.rs | 2 +- tests/ui/suggestions/const-no-type.rs | 6 +- .../type-ascription-and-other-error.rs | 2 +- tests/ui/wasm/wasm-import-module.rs | 2 +- tests/ui/wasm/wasm-import-module.stderr | 2 +- 141 files changed, 470 insertions(+), 470 deletions(-) diff --git a/tests/pretty/ast-stmt-expr-attr.rs b/tests/pretty/ast-stmt-expr-attr.rs index fd7272a1b1fd..4ca60465b54c 100644 --- a/tests/pretty/ast-stmt-expr-attr.rs +++ b/tests/pretty/ast-stmt-expr-attr.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { let _ = #[attr] []; let _ = #[attr] [0]; diff --git a/tests/pretty/enum-variant-vis.rs b/tests/pretty/enum-variant-vis.rs index 3397e7dc8e28..5b9f7e037595 100644 --- a/tests/pretty/enum-variant-vis.rs +++ b/tests/pretty/enum-variant-vis.rs @@ -4,5 +4,5 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] enum Foo { pub V, } diff --git a/tests/pretty/if-attr.rs b/tests/pretty/if-attr.rs index 89d6130f6592..8b343a83a1c5 100644 --- a/tests/pretty/if-attr.rs +++ b/tests/pretty/if-attr.rs @@ -1,6 +1,6 @@ //@ pp-exact -#[cfg(FALSE)] +#[cfg(false)] fn simple_attr() { #[attr] @@ -10,21 +10,21 @@ fn simple_attr() { if true {} } -#[cfg(FALSE)] +#[cfg(false)] fn if_else_chain() { #[first_attr] if true {} else if false {} else {} } -#[cfg(FALSE)] +#[cfg(false)] fn if_let() { #[attr] if let Some(_) = Some(true) {} } -#[cfg(FALSE)] +#[cfg(false)] fn let_attr_if() { let _ = #[attr] if let _ = 0 {}; let _ = #[attr] if true {}; diff --git a/tests/pretty/nested-item-vis-defaultness.rs b/tests/pretty/nested-item-vis-defaultness.rs index 1e971fcf07a5..68f56a1be450 100644 --- a/tests/pretty/nested-item-vis-defaultness.rs +++ b/tests/pretty/nested-item-vis-defaultness.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" { static X: u8; type X; @@ -14,7 +14,7 @@ extern "C" { pub fn foo(); } -#[cfg(FALSE)] +#[cfg(false)] trait T { const X: u8; type X; @@ -30,7 +30,7 @@ trait T { pub default fn foo(); } -#[cfg(FALSE)] +#[cfg(false)] impl T for S { const X: u8; type X; diff --git a/tests/ui/associated-types/associated-type-macro.rs b/tests/ui/associated-types/associated-type-macro.rs index 22b5bca40103..8586dc172764 100644 --- a/tests/ui/associated-types/associated-type-macro.rs +++ b/tests/ui/associated-types/associated-type-macro.rs @@ -1,4 +1,4 @@ fn main() { - #[cfg(FALSE)] + #[cfg(false)] <() as module>::mac!(); //~ ERROR macros cannot use qualified paths } diff --git a/tests/ui/async-await/feature-async-for-loop.rs b/tests/ui/async-await/feature-async-for-loop.rs index 67817cbfa5f3..22d32907e0e7 100644 --- a/tests/ui/async-await/feature-async-for-loop.rs +++ b/tests/ui/async-await/feature-async-for-loop.rs @@ -11,7 +11,7 @@ fn f() { }; } -#[cfg(FALSE)] +#[cfg(false)] fn g() { let _ = async { for await _i in core::async_iter::from_iter(0..3) { diff --git a/tests/ui/async-await/no-unsafe-async.rs b/tests/ui/async-await/no-unsafe-async.rs index e58d878c3db0..cc7e89e16cb2 100644 --- a/tests/ui/async-await/no-unsafe-async.rs +++ b/tests/ui/async-await/no-unsafe-async.rs @@ -3,11 +3,11 @@ struct S; impl S { - #[cfg(FALSE)] + #[cfg(false)] unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async` } -#[cfg(FALSE)] +#[cfg(false)] unsafe async fn f() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async` fn main() {} diff --git a/tests/ui/attributes/z-crate-attr/cfg-false.rs b/tests/ui/attributes/z-crate-attr/cfg-false.rs index db37cfdd0863..5e5662c74385 100644 --- a/tests/ui/attributes/z-crate-attr/cfg-false.rs +++ b/tests/ui/attributes/z-crate-attr/cfg-false.rs @@ -1,5 +1,5 @@ -// Ensure that `-Z crate-attr=cfg(FALSE)` can comment out the whole crate -//@ compile-flags: --crate-type=lib -Zcrate-attr=cfg(FALSE) +// Ensure that `-Z crate-attr=cfg(false)` can comment out the whole crate +//@ compile-flags: --crate-type=lib -Zcrate-attr=cfg(false) //@ check-pass // NOTE: duplicate items are load-bearing diff --git a/tests/ui/auto-traits/pre-cfg.rs b/tests/ui/auto-traits/pre-cfg.rs index e806686f965c..4820a5353580 100644 --- a/tests/ui/auto-traits/pre-cfg.rs +++ b/tests/ui/auto-traits/pre-cfg.rs @@ -1,6 +1,6 @@ //@ check-pass -#[cfg(FALSE)] +#[cfg(false)] auto trait Foo {} //~^ WARN `auto` traits are unstable //~| WARN unstable syntax can change at any point in the future, causing a hard error! diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib.rs b/tests/ui/cfg/auxiliary/cfg_false_lib.rs index 6c2dbb44d2a4..d1768e69b0d5 100644 --- a/tests/ui/cfg/auxiliary/cfg_false_lib.rs +++ b/tests/ui/cfg/auxiliary/cfg_false_lib.rs @@ -1,4 +1,4 @@ -// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`. +// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`. // This crate has no such attribute, therefore this crate does link to libstd. -#![cfg(FALSE)] +#![cfg(false)] diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs index 3cfa6c510d02..cd3170f3fb33 100644 --- a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs +++ b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs @@ -1,5 +1,5 @@ -// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`. +// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`. // Therefore this crate does link to libstd. -#![cfg(FALSE)] +#![cfg(false)] #![no_std] diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs index a5c14be4c29d..ce4e1690996b 100644 --- a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs +++ b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs @@ -1,8 +1,8 @@ -// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`. +// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`. // Therefore this crate doesn't link to libstd. //@ no-prefer-dynamic #![no_std] #![crate_type = "lib"] -#![cfg(FALSE)] +#![cfg(false)] diff --git a/tests/ui/cfg/auxiliary/cfged_out.rs b/tests/ui/cfg/auxiliary/cfged_out.rs index f6a9089cf29d..564280b24f59 100644 --- a/tests/ui/cfg/auxiliary/cfged_out.rs +++ b/tests/ui/cfg/auxiliary/cfged_out.rs @@ -1,8 +1,8 @@ pub mod inner { - #[cfg(FALSE)] + #[cfg(false)] pub fn uwu() {} - #[cfg(FALSE)] + #[cfg(false)] pub mod doesnt_exist { pub fn hello() {} } diff --git a/tests/ui/cfg/cfg-false-feature.rs b/tests/ui/cfg/cfg-false-feature.rs index 716b18492c73..f66e4722440c 100644 --- a/tests/ui/cfg/cfg-false-feature.rs +++ b/tests/ui/cfg/cfg-false-feature.rs @@ -1,10 +1,10 @@ -// Features above `cfg(FALSE)` are in effect in a fully unconfigured crate (issue #104633). +// Features above `cfg(false)` are in effect in a fully unconfigured crate (issue #104633). //@ check-pass //@ compile-flags: --crate-type lib #![feature(decl_macro)] -#![cfg(FALSE)] +#![cfg(false)] #![feature(box_patterns)] macro mac() {} // OK diff --git a/tests/ui/cfg/cfg-macros-notfoo.rs b/tests/ui/cfg/cfg-macros-notfoo.rs index 9feb06be73e9..c25cf1c39bf5 100644 --- a/tests/ui/cfg/cfg-macros-notfoo.rs +++ b/tests/ui/cfg/cfg-macros-notfoo.rs @@ -3,7 +3,7 @@ // check that cfg correctly chooses between the macro impls (see also // cfg-macros-foo.rs) -#[cfg(FALSE)] +#[cfg(false)] #[macro_use] mod foo { macro_rules! bar { diff --git a/tests/ui/cfg/cfg-match-arm.rs b/tests/ui/cfg/cfg-match-arm.rs index f6cd52c475cf..cb5bf0ab0653 100644 --- a/tests/ui/cfg/cfg-match-arm.rs +++ b/tests/ui/cfg/cfg-match-arm.rs @@ -11,7 +11,7 @@ fn foo(f: Foo) { Foo::Bar => {}, #[cfg(not(FALSE))] Foo::Baz => {}, - #[cfg(FALSE)] + #[cfg(false)] Basdfwe => {} } } diff --git a/tests/ui/cfg/cfg-stmt-recovery.rs b/tests/ui/cfg/cfg-stmt-recovery.rs index 2e0839d2a153..f0f9a649165b 100644 --- a/tests/ui/cfg/cfg-stmt-recovery.rs +++ b/tests/ui/cfg/cfg-stmt-recovery.rs @@ -6,7 +6,7 @@ #[cfg_eval] fn main() { #[cfg_eval] - let _ = #[cfg(FALSE)] 0; + let _ = #[cfg(false)] 0; //~^ ERROR removing an expression is not supported in this position //~| ERROR expected expression, found `;` //~| ERROR removing an expression is not supported in this position diff --git a/tests/ui/cfg/cfg-stmt-recovery.stderr b/tests/ui/cfg/cfg-stmt-recovery.stderr index cb15e21fac69..e34da72afd93 100644 --- a/tests/ui/cfg/cfg-stmt-recovery.stderr +++ b/tests/ui/cfg/cfg-stmt-recovery.stderr @@ -1,19 +1,19 @@ error: removing an expression is not supported in this position --> $DIR/cfg-stmt-recovery.rs:9:13 | -LL | let _ = #[cfg(FALSE)] 0; +LL | let _ = #[cfg(false)] 0; | ^^^^^^^^^^^^^ error: expected expression, found `;` --> $DIR/cfg-stmt-recovery.rs:9:28 | -LL | let _ = #[cfg(FALSE)] 0; +LL | let _ = #[cfg(false)] 0; | ^ expected expression error: removing an expression is not supported in this position --> $DIR/cfg-stmt-recovery.rs:9:13 | -LL | let _ = #[cfg(FALSE)] 0; +LL | let _ = #[cfg(false)] 0; | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/cfg/cfg_stmt_expr.rs b/tests/ui/cfg/cfg_stmt_expr.rs index 9245f6d97576..361b159a354f 100644 --- a/tests/ui/cfg/cfg_stmt_expr.rs +++ b/tests/ui/cfg/cfg_stmt_expr.rs @@ -7,47 +7,47 @@ fn main() { let a = 413; - #[cfg(FALSE)] + #[cfg(false)] let a = (); assert_eq!(a, 413); let mut b = 612; - #[cfg(FALSE)] + #[cfg(false)] { b = 1111; } assert_eq!(b, 612); - #[cfg(FALSE)] + #[cfg(false)] undefined_fn(); - #[cfg(FALSE)] + #[cfg(false)] undefined_macro!(); - #[cfg(FALSE)] + #[cfg(false)] undefined_macro![]; - #[cfg(FALSE)] + #[cfg(false)] undefined_macro!{}; // pretty printer bug... - // #[cfg(FALSE)] + // #[cfg(false)] // undefined_macro!{} - let () = (#[cfg(FALSE)] 341,); // Should this also work on parens? - let t = (1, #[cfg(FALSE)] 3, 4); + let () = (#[cfg(false)] 341,); // Should this also work on parens? + let t = (1, #[cfg(false)] 3, 4); assert_eq!(t, (1, 4)); let f = |_: u32, _: u32| (); - f(2, 1, #[cfg(FALSE)] 6); + f(2, 1, #[cfg(false)] 6); - let _: u32 = a.clone(#[cfg(FALSE)] undefined); + let _: u32 = a.clone(#[cfg(false)] undefined); - let _: [(); 0] = [#[cfg(FALSE)] 126]; - let t = [#[cfg(FALSE)] 1, 2, 6]; + let _: [(); 0] = [#[cfg(false)] 126]; + let t = [#[cfg(false)] 1, 2, 6]; assert_eq!(t, [2, 6]); { let r; - #[cfg(FALSE)] + #[cfg(false)] (r = 5); #[cfg(not(FALSE))] (r = 10); @@ -75,7 +75,7 @@ fn main() { 612 }); - assert_eq!((#[cfg(FALSE)] 1, #[cfg(not(FALSE))] 2), (2,)); + assert_eq!((#[cfg(false)] 1, #[cfg(not(FALSE))] 2), (2,)); assert_eq!(n, 612); // check that lints work diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs index dff280054d65..0739e877bfd1 100644 --- a/tests/ui/cfg/conditional-compile.rs +++ b/tests/ui/cfg/conditional-compile.rs @@ -6,16 +6,16 @@ // Crate use statements -#[cfg(FALSE)] +#[cfg(false)] use flippity; -#[cfg(FALSE)] +#[cfg(false)] static b: bool = false; static b: bool = true; mod rustrt { - #[cfg(FALSE)] + #[cfg(false)] extern "C" { // This symbol doesn't exist and would be a link error if this // module was codegened @@ -25,12 +25,12 @@ mod rustrt { extern "C" {} } -#[cfg(FALSE)] +#[cfg(false)] type t = isize; type t = bool; -#[cfg(FALSE)] +#[cfg(false)] enum tg { foo, } @@ -39,12 +39,12 @@ enum tg { bar, } -#[cfg(FALSE)] +#[cfg(false)] struct r { i: isize, } -#[cfg(FALSE)] +#[cfg(false)] fn r(i: isize) -> r { r { i: i } } @@ -57,7 +57,7 @@ fn r(i: isize) -> r { r { i: i } } -#[cfg(FALSE)] +#[cfg(false)] mod m { // This needs to parse but would fail in typeck. Since it's not in // the current config it should not be typechecked. @@ -69,7 +69,7 @@ mod m { mod m { // Submodules have slightly different code paths than the top-level // module, so let's make sure this jazz works here as well - #[cfg(FALSE)] + #[cfg(false)] pub fn f() {} pub fn f() {} @@ -77,7 +77,7 @@ mod m { // Since the FALSE configuration isn't defined main will just be // parsed, but nothing further will be done with it -#[cfg(FALSE)] +#[cfg(false)] pub fn main() { panic!() } @@ -93,14 +93,14 @@ pub fn main() { } fn test_in_fn_ctxt() { - #[cfg(FALSE)] + #[cfg(false)] fn f() { panic!() } fn f() {} f(); - #[cfg(FALSE)] + #[cfg(false)] static i: isize = 0; static i: isize = 1; assert_eq!(i, 1); @@ -109,7 +109,7 @@ fn test_in_fn_ctxt() { mod test_foreign_items { pub mod rustrt { extern "C" { - #[cfg(FALSE)] + #[cfg(false)] pub fn write() -> String; pub fn write() -> String; } @@ -117,7 +117,7 @@ mod test_foreign_items { } mod test_use_statements { - #[cfg(FALSE)] + #[cfg(false)] use flippity_foo; } @@ -127,24 +127,24 @@ mod test_methods { } impl Fooable for Foo { - #[cfg(FALSE)] + #[cfg(false)] fn what(&self) {} fn what(&self) {} - #[cfg(FALSE)] + #[cfg(false)] fn the(&self) {} fn the(&self) {} } trait Fooable { - #[cfg(FALSE)] + #[cfg(false)] fn what(&self); fn what(&self); - #[cfg(FALSE)] + #[cfg(false)] fn the(&self); fn the(&self); diff --git a/tests/ui/cfg/diagnostics-cross-crate.stderr b/tests/ui/cfg/diagnostics-cross-crate.stderr index 07ad4e3272d1..3e32a856e954 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.stderr +++ b/tests/ui/cfg/diagnostics-cross-crate.stderr @@ -12,7 +12,7 @@ LL | pub mod doesnt_exist { note: the item is gated here --> $DIR/auxiliary/cfged_out.rs:5:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in crate `cfged_out` @@ -35,7 +35,7 @@ LL | pub fn uwu() {} note: the item is gated here --> $DIR/auxiliary/cfged_out.rs:2:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `meow` in module `cfged_out::inner::right` diff --git a/tests/ui/cfg/diagnostics-reexport.rs b/tests/ui/cfg/diagnostics-reexport.rs index 9ae7d931fcb8..56fac5622382 100644 --- a/tests/ui/cfg/diagnostics-reexport.rs +++ b/tests/ui/cfg/diagnostics-reexport.rs @@ -1,10 +1,10 @@ pub mod inner { - #[cfg(FALSE)] + #[cfg(false)] mod gone { pub fn uwu() {} } - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub use super::uwu; //~^ NOTE found an item that was configured out } @@ -14,7 +14,7 @@ pub use a::x; //~| NOTE no `x` in `a` mod a { - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub fn x() {} //~^ NOTE found an item that was configured out } @@ -25,10 +25,10 @@ pub use b::{x, y}; //~| NOTE no `y` in `b` mod b { - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub fn x() {} //~^ NOTE found an item that was configured out - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub fn y() {} //~^ NOTE found an item that was configured out } diff --git a/tests/ui/cfg/diagnostics-reexport.stderr b/tests/ui/cfg/diagnostics-reexport.stderr index 737202fdf9ad..95dc4fac945e 100644 --- a/tests/ui/cfg/diagnostics-reexport.stderr +++ b/tests/ui/cfg/diagnostics-reexport.stderr @@ -12,7 +12,7 @@ LL | pub fn x() {} note: the item is gated here --> $DIR/diagnostics-reexport.rs:17:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0432]: unresolved imports `b::x`, `b::y` @@ -31,7 +31,7 @@ LL | pub fn x() {} note: the item is gated here --> $DIR/diagnostics-reexport.rs:28:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ note: found an item that was configured out --> $DIR/diagnostics-reexport.rs:32:12 @@ -41,7 +41,7 @@ LL | pub fn y() {} note: the item is gated here --> $DIR/diagnostics-reexport.rs:31:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in module `inner` @@ -58,7 +58,7 @@ LL | pub use super::uwu; note: the item is gated here --> $DIR/diagnostics-reexport.rs:7:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/cfg/diagnostics-same-crate.rs b/tests/ui/cfg/diagnostics-same-crate.rs index d6f8dd21a922..9153f20b2964 100644 --- a/tests/ui/cfg/diagnostics-same-crate.rs +++ b/tests/ui/cfg/diagnostics-same-crate.rs @@ -1,11 +1,11 @@ #![allow(unexpected_cfgs)] // since we want to recognize them as unexpected pub mod inner { - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here pub fn uwu() {} //~^ NOTE found an item that was configured out - #[cfg(FALSE)] //~ NOTE the item is gated here + #[cfg(false)] //~ NOTE the item is gated here //~^ NOTE the item is gated here //~| NOTE the item is gated here pub mod doesnt_exist { diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index dd0d10c6567e..75a1bc39a013 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -12,7 +12,7 @@ LL | pub mod doesnt_exist { note: the item is gated here --> $DIR/diagnostics-same-crate.rs:8:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0432]: unresolved import `super::inner::doesnt_exist` @@ -29,7 +29,7 @@ LL | pub mod doesnt_exist { note: the item is gated here --> $DIR/diagnostics-same-crate.rs:8:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` @@ -46,7 +46,7 @@ LL | pub mod doesnt_exist { note: the item is gated here --> $DIR/diagnostics-same-crate.rs:8:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in module `inner` @@ -63,7 +63,7 @@ LL | pub fn uwu() {} note: the item is gated here --> $DIR/diagnostics-same-crate.rs:4:5 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ^^^^^^^^^^^^^ error[E0425]: cannot find function `meow` in module `inner::right` diff --git a/tests/ui/check-cfg/allow-same-level.rs b/tests/ui/check-cfg/allow-same-level.rs index 8260b57bad4d..3f673cb88447 100644 --- a/tests/ui/check-cfg/allow-same-level.rs +++ b/tests/ui/check-cfg/allow-same-level.rs @@ -12,7 +12,7 @@ //@ compile-flags: --check-cfg=cfg() --cfg=unknown_but_active_cfg #[allow(unexpected_cfgs)] -#[cfg(FALSE)] +#[cfg(unknown_and_inactive_cfg)] //~^ WARNING unexpected `cfg` condition name fn bar() {} diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr index a705cd4e5f01..cfff03048b53 100644 --- a/tests/ui/check-cfg/allow-same-level.stderr +++ b/tests/ui/check-cfg/allow-same-level.stderr @@ -1,10 +1,10 @@ -warning: unexpected `cfg` condition name: `FALSE` +warning: unexpected `cfg` condition name: `unknown_and_inactive_cfg` --> $DIR/allow-same-level.rs:15:7 | -LL | #[cfg(FALSE)] - | ^^^^^ +LL | #[cfg(unknown_and_inactive_cfg)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: to expect this configuration use `--check-cfg=cfg(FALSE)` + = help: to expect this configuration use `--check-cfg=cfg(unknown_and_inactive_cfg)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/allow-top-level.rs b/tests/ui/check-cfg/allow-top-level.rs index cf94ed5da428..7ccecd2360e8 100644 --- a/tests/ui/check-cfg/allow-top-level.rs +++ b/tests/ui/check-cfg/allow-top-level.rs @@ -6,7 +6,7 @@ #![allow(unexpected_cfgs)] -#[cfg(FALSE)] +#[cfg(false)] fn bar() {} fn foo() { diff --git a/tests/ui/check-cfg/allow-upper-level.rs b/tests/ui/check-cfg/allow-upper-level.rs index 2e6664c30d39..657a4768f952 100644 --- a/tests/ui/check-cfg/allow-upper-level.rs +++ b/tests/ui/check-cfg/allow-upper-level.rs @@ -6,7 +6,7 @@ #[allow(unexpected_cfgs)] mod aa { - #[cfg(FALSE)] + #[cfg(false)] fn bar() {} } diff --git a/tests/ui/conditional-compilation/cfg-generic-params.rs b/tests/ui/conditional-compilation/cfg-generic-params.rs index 4bb8f8ae94f6..6480a0f24794 100644 --- a/tests/ui/conditional-compilation/cfg-generic-params.rs +++ b/tests/ui/conditional-compilation/cfg-generic-params.rs @@ -1,18 +1,18 @@ //@ compile-flags:--cfg yes --check-cfg=cfg(yes,no) -fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(FALSE)] T>() {} -fn f_ty<#[cfg(FALSE)] 'a: 'a, #[cfg(yes)] T>() {} +fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(false)] T>() {} +fn f_ty<#[cfg(false)] 'a: 'a, #[cfg(yes)] T>() {} -type FnGood = for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> fn(); // OK -type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn(); +type FnGood = for<#[cfg(yes)] 'a, #[cfg(false)] T> fn(); // OK +type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn(); //~^ ERROR only lifetime parameters can be used in this context -type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> Copy; // OK -type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy; +type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(false)] T> Copy; // OK +type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy; //~^ ERROR only lifetime parameters can be used in this context -struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> u8: Copy; // OK -struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy; +struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(false)] T> u8: Copy; // OK +struct WhereBad where for<#[cfg(false)] 'a, #[cfg(yes)] T> u8: Copy; //~^ ERROR only lifetime parameters can be used in this context fn f_lt_no<#[cfg_attr(FALSE, unknown)] 'a>() {} // OK diff --git a/tests/ui/conditional-compilation/cfg-generic-params.stderr b/tests/ui/conditional-compilation/cfg-generic-params.stderr index 563616be36bc..bae75dd0deb0 100644 --- a/tests/ui/conditional-compilation/cfg-generic-params.stderr +++ b/tests/ui/conditional-compilation/cfg-generic-params.stderr @@ -31,7 +31,7 @@ LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; error[E0658]: only lifetime parameters can be used in this context --> $DIR/cfg-generic-params.rs:7:48 | -LL | type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn(); +LL | type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn(); | ^ | = note: see issue #108185 for more information @@ -41,7 +41,7 @@ LL | type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn(); error[E0658]: only lifetime parameters can be used in this context --> $DIR/cfg-generic-params.rs:11:54 | -LL | type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy; +LL | type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy; | ^ | = note: see issue #108185 for more information @@ -51,7 +51,7 @@ LL | type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy; error[E0658]: only lifetime parameters can be used in this context --> $DIR/cfg-generic-params.rs:15:57 | -LL | struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy; +LL | struct WhereBad where for<#[cfg(false)] 'a, #[cfg(yes)] T> u8: Copy; | ^ | = note: see issue #108185 for more information diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.rs b/tests/ui/conditional-compilation/cfg-in-crate-1.rs index a1faa2397a33..b9efa32babef 100644 --- a/tests/ui/conditional-compilation/cfg-in-crate-1.rs +++ b/tests/ui/conditional-compilation/cfg-in-crate-1.rs @@ -1 +1 @@ -#![cfg(FALSE)] //~ ERROR `main` function not found in crate `cfg_in_crate_1` +#![cfg(false)] //~ ERROR `main` function not found in crate `cfg_in_crate_1` diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr index 126e10cf0402..352baf33091b 100644 --- a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr +++ b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr @@ -1,7 +1,7 @@ error[E0601]: `main` function not found in crate `cfg_in_crate_1` --> $DIR/cfg-in-crate-1.rs:1:15 | -LL | #![cfg(FALSE)] +LL | #![cfg(false)] | ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs` error: aborting due to 1 previous error diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs index ae85f38e645e..cae07ae0ced1 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs @@ -2,10 +2,10 @@ #![feature(custom_test_frameworks)] fn main() { - let _ = #[cfg(FALSE)] (); + let _ = #[cfg(false)] (); //~^ ERROR removing an expression is not supported in this position - let _ = 1 + 2 + #[cfg(FALSE)] 3; + let _ = 1 + 2 + #[cfg(false)] 3; //~^ ERROR removing an expression is not supported in this position - let _ = [1, 2, 3][#[cfg(FALSE)] 1]; + let _ = [1, 2, 3][#[cfg(false)] 1]; //~^ ERROR removing an expression is not supported in this position } diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr index 06eaa59efdd7..bd1bfeb06c7a 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr @@ -1,19 +1,19 @@ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:5:13 | -LL | let _ = #[cfg(FALSE)] (); +LL | let _ = #[cfg(false)] (); | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:7:21 | -LL | let _ = 1 + 2 + #[cfg(FALSE)] 3; +LL | let _ = 1 + 2 + #[cfg(false)] 3; | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:9:23 | -LL | let _ = [1, 2, 3][#[cfg(FALSE)] 1]; +LL | let _ = [1, 2, 3][#[cfg(false)] 1]; | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/conditional-compilation/module_with_cfg.rs b/tests/ui/conditional-compilation/module_with_cfg.rs index 778379fa6ea7..29eb6d43aa79 100644 --- a/tests/ui/conditional-compilation/module_with_cfg.rs +++ b/tests/ui/conditional-compilation/module_with_cfg.rs @@ -1,3 +1,3 @@ //@ ignore-test (auxiliary, used by other tests) -#![cfg_attr(all(), cfg(FALSE))] +#![cfg_attr(all(), cfg(false))] diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs index 7ced24808bf6..50728970be2c 100644 --- a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs +++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs @@ -1,6 +1,6 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn container() { const unsafe WhereIsFerris Now() {} //~^ ERROR expected one of `extern` or `fn` diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs index 6f575d055a29..20e79ca200bb 100644 --- a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs +++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs @@ -1,6 +1,6 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn container() { const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } //~^ ERROR expected `fn` diff --git a/tests/ui/delegation/explicit-paths-signature-pass.rs b/tests/ui/delegation/explicit-paths-signature-pass.rs index 8c16ad92393c..11bc8a70db0e 100644 --- a/tests/ui/delegation/explicit-paths-signature-pass.rs +++ b/tests/ui/delegation/explicit-paths-signature-pass.rs @@ -6,7 +6,7 @@ mod to_reuse { use crate::S; - pub fn foo<'a>(#[cfg(FALSE)] a: u8, _b: &'a S) -> u32 { + pub fn foo<'a>(#[cfg(false)] a: u8, _b: &'a S) -> u32 { 1 } } diff --git a/tests/ui/expr/if/attrs/bad-cfg.rs b/tests/ui/expr/if/attrs/bad-cfg.rs index 3f84929a00e4..6e7f4b007a92 100644 --- a/tests/ui/expr/if/attrs/bad-cfg.rs +++ b/tests/ui/expr/if/attrs/bad-cfg.rs @@ -1,5 +1,5 @@ #![feature(stmt_expr_attributes)] fn main() { - let _ = #[cfg(FALSE)] if true {}; //~ ERROR removing an expression + let _ = #[cfg(false)] if true {}; //~ ERROR removing an expression } diff --git a/tests/ui/expr/if/attrs/bad-cfg.stderr b/tests/ui/expr/if/attrs/bad-cfg.stderr index ca0eced267d6..d12f5eeaf5fa 100644 --- a/tests/ui/expr/if/attrs/bad-cfg.stderr +++ b/tests/ui/expr/if/attrs/bad-cfg.stderr @@ -1,7 +1,7 @@ error: removing an expression is not supported in this position --> $DIR/bad-cfg.rs:4:13 | -LL | let _ = #[cfg(FALSE)] if true {}; +LL | let _ = #[cfg(false)] if true {}; | ^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs index c139b347d998..e6c83b86cb77 100644 --- a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs +++ b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs @@ -1,12 +1,12 @@ //@ check-pass -#[cfg(FALSE)] +#[cfg(false)] fn simple_attr() { #[attr] if true {} #[allow_warnings] if true {} } -#[cfg(FALSE)] +#[cfg(false)] fn if_else_chain() { #[first_attr] if true { } else if false { @@ -14,20 +14,20 @@ fn if_else_chain() { } } -#[cfg(FALSE)] +#[cfg(false)] fn if_let() { #[attr] if let Some(_) = Some(true) {} } fn bar() { - #[cfg(FALSE)] + #[cfg(false)] if true { - let x: () = true; // Should not error due to the #[cfg(FALSE)] + let x: () = true; // Should not error due to the #[cfg(false)] } - #[cfg_attr(not(FALSE), cfg(FALSE))] + #[cfg_attr(not(FALSE), cfg(false))] if true { - let a: () = true; // Should not error due to the applied #[cfg(FALSE)] + let a: () = true; // Should not error due to the applied #[cfg(false)] } } diff --git a/tests/ui/expr/if/attrs/else-attrs.rs b/tests/ui/expr/if/attrs/else-attrs.rs index 85da7cf6bb8c..4010d9d6132b 100644 --- a/tests/ui/expr/if/attrs/else-attrs.rs +++ b/tests/ui/expr/if/attrs/else-attrs.rs @@ -1,11 +1,11 @@ -#[cfg(FALSE)] +#[cfg(false)] fn if_else_parse_error() { if true { } #[attr] else if false { //~ ERROR expected } } -#[cfg(FALSE)] +#[cfg(false)] fn else_attr_ifparse_error() { if true { } else #[attr] if false { //~ ERROR outer attributes are not allowed @@ -13,7 +13,7 @@ fn else_attr_ifparse_error() { } } -#[cfg(FALSE)] +#[cfg(false)] fn else_parse_error() { if true { } else if false { diff --git a/tests/ui/expr/if/attrs/gate-whole-expr.rs b/tests/ui/expr/if/attrs/gate-whole-expr.rs index bab01592c247..885909016b5e 100644 --- a/tests/ui/expr/if/attrs/gate-whole-expr.rs +++ b/tests/ui/expr/if/attrs/gate-whole-expr.rs @@ -3,7 +3,7 @@ fn main() { let x = 1; - #[cfg(FALSE)] + #[cfg(false)] if false { x = 2; } else if true { diff --git a/tests/ui/expr/if/attrs/let-chains-attr.rs b/tests/ui/expr/if/attrs/let-chains-attr.rs index b3dbd53e5798..2cf1b169f069 100644 --- a/tests/ui/expr/if/attrs/let-chains-attr.rs +++ b/tests/ui/expr/if/attrs/let-chains-attr.rs @@ -2,7 +2,7 @@ #![feature(let_chains)] -#[cfg(FALSE)] +#[cfg(false)] fn foo() { #[attr] if let Some(_) = Some(true) && let Ok(_) = Ok(1) { diff --git a/tests/ui/feature-gates/feature-gate-coroutines.rs b/tests/ui/feature-gates/feature-gate-coroutines.rs index f20dc56f1229..b37a61d9105f 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.rs +++ b/tests/ui/feature-gates/feature-gate-coroutines.rs @@ -12,7 +12,7 @@ fn main() { //~^^ ERROR `yield` can only be used } -#[cfg(FALSE)] +#[cfg(false)] fn foo() { // Ok in 2024 edition yield; //~ ERROR yield syntax is experimental diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.rs b/tests/ui/feature-gates/feature-gate-deref_patterns.rs index b43001f2d53f..53b4301f10c0 100644 --- a/tests/ui/feature-gates/feature-gate-deref_patterns.rs +++ b/tests/ui/feature-gates/feature-gate-deref_patterns.rs @@ -4,6 +4,6 @@ fn main() { println!("x: {}", x); // `box` syntax is allowed to be cfg-ed out for historical reasons (#65742). - #[cfg(FALSE)] + #[cfg(false)] let box _x = Box::new('c'); } diff --git a/tests/ui/feature-gates/feature-gate-gen_blocks.rs b/tests/ui/feature-gates/feature-gate-gen_blocks.rs index 01fd922b0e99..989daf471bcb 100644 --- a/tests/ui/feature-gates/feature-gate-gen_blocks.rs +++ b/tests/ui/feature-gates/feature-gate-gen_blocks.rs @@ -17,7 +17,7 @@ fn test_async_gen() { fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn foo() { gen {}; //[e2024]~^ ERROR: gen blocks are experimental diff --git a/tests/ui/feature-gates/feature-gate-guard-patterns.rs b/tests/ui/feature-gates/feature-gate-guard-patterns.rs index 52ed89e668b1..74fb5817081c 100644 --- a/tests/ui/feature-gates/feature-gate-guard-patterns.rs +++ b/tests/ui/feature-gates/feature-gate-guard-patterns.rs @@ -30,7 +30,7 @@ fn other_guards_dont() { while let (x if guard(x)) = 0 {} //~^ ERROR: guard patterns are experimental - #[cfg(FALSE)] + #[cfg(false)] while let (x if guard(x)) = 0 {} //~^ ERROR: guard patterns are experimental } diff --git a/tests/ui/feature-gates/feature-gate-mut-ref.rs b/tests/ui/feature-gates/feature-gate-mut-ref.rs index 806b25de66ff..752ae35d8a9a 100644 --- a/tests/ui/feature-gates/feature-gate-mut-ref.rs +++ b/tests/ui/feature-gates/feature-gate-mut-ref.rs @@ -6,8 +6,8 @@ fn main() { let mut ref mut z = 14; //~ ERROR [E0658] z = &mut 15; - #[cfg(FALSE)] + #[cfg(false)] let mut ref x = 10; //~ ERROR [E0658] - #[cfg(FALSE)] + #[cfg(false)] let mut ref mut y = 10; //~ ERROR [E0658] } diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.rs b/tests/ui/feature-gates/feature-gate-never_patterns.rs index d23405ada2d4..2cb0b5a6679d 100644 --- a/tests/ui/feature-gates/feature-gate-never_patterns.rs +++ b/tests/ui/feature-gates/feature-gate-never_patterns.rs @@ -15,12 +15,12 @@ fn main() { //~^ ERROR `!` patterns are experimental } // Check that the gate operates even behind `cfg`. - #[cfg(FALSE)] + #[cfg(false)] match *ptr { ! //~^ ERROR `!` patterns are experimental } - #[cfg(FALSE)] + #[cfg(false)] match *ptr { ! => {} //~^ ERROR `!` patterns are experimental @@ -60,13 +60,13 @@ fn main() { // Check that the gate operates even behind `cfg`. match Some(0) { None => {} - #[cfg(FALSE)] + #[cfg(false)] Some(_) //~^ ERROR `match` arm with no body } match Some(0) { _ => {} - #[cfg(FALSE)] + #[cfg(false)] Some(_) if false //~^ ERROR `match` arm with no body } diff --git a/tests/ui/feature-gates/feature-gate-postfix_match.rs b/tests/ui/feature-gates/feature-gate-postfix_match.rs index dce7e81a9ae4..2226816e5ea7 100644 --- a/tests/ui/feature-gates/feature-gate-postfix_match.rs +++ b/tests/ui/feature-gates/feature-gate-postfix_match.rs @@ -9,7 +9,7 @@ fn main() { }; // Test that the gate works behind a cfg - #[cfg(FALSE)] + #[cfg(false)] val.match { //~ ERROR postfix match is experimental Some(42) => "the answer to life, the universe, and everything", _ => "might be the answer to something" diff --git a/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs b/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs index 33fda822baad..bacbbc57c2c9 100644 --- a/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs +++ b/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs @@ -1,7 +1,7 @@ //@ compile-flags: --edition 2021 pub fn demo() -> Option { - #[cfg(FALSE)] + #[cfg(false)] { do yeet //~ ERROR `do yeet` expression is experimental } @@ -9,7 +9,7 @@ pub fn demo() -> Option { Some(1) } -#[cfg(FALSE)] +#[cfg(false)] pub fn alternative() -> Result<(), String> { do yeet "hello"; //~ ERROR `do yeet` expression is experimental } diff --git a/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs b/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs index 2aa2ed34020c..87629a5bcce7 100644 --- a/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs +++ b/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs @@ -5,7 +5,7 @@ macro a() {} //~^ ERROR: `macro` is experimental -#[cfg(FALSE)] +#[cfg(false)] macro b() {} macro_rules! identity { @@ -17,13 +17,13 @@ identity! { //~^ ERROR: `macro` is experimental } -#[cfg(FALSE)] +#[cfg(false)] identity! { macro d() {} // No error } identity! { - #[cfg(FALSE)] + #[cfg(false)] macro e() {} } diff --git a/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs b/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs index 056c8fb04f45..72d0bf1ccd52 100644 --- a/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs +++ b/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs @@ -2,7 +2,7 @@ // This file is used to test the behavior of the early-pass syntax warnings. // If macro syntax is stabilized, replace with a different unstable syntax. -#[cfg(FALSE)] +#[cfg(false)] macro b() {} //~^ WARN: `macro` is experimental //~| WARN: unstable syntax @@ -11,13 +11,13 @@ macro_rules! identity { ($($x:tt)*) => ($($x)*); } -#[cfg(FALSE)] +#[cfg(false)] identity! { macro d() {} // No error } identity! { - #[cfg(FALSE)] + #[cfg(false)] macro e() {} //~^ WARN: `macro` is experimental //~| WARN: unstable syntax diff --git a/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs index a160a9bb082d..4523afa7c4bd 100644 --- a/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs +++ b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs @@ -25,7 +25,7 @@ fn main() { // Check that cfg works right -#[cfg(FALSE)] +#[cfg(false)] fn c() { #[rustc_dummy] 5; @@ -37,7 +37,7 @@ fn j() { 5; } -#[cfg_attr(not(FALSE), cfg(FALSE))] +#[cfg_attr(not(FALSE), cfg(false))] fn d() { #[rustc_dummy] 8; @@ -57,7 +57,7 @@ macro_rules! item_mac { #[rustc_dummy] 42; - #[cfg(FALSE)] + #[cfg(false)] fn f() { #[rustc_dummy] 5; @@ -69,7 +69,7 @@ macro_rules! item_mac { 5; } - #[cfg_attr(not(FALSE), cfg(FALSE))] + #[cfg_attr(not(FALSE), cfg(false))] fn g() { #[rustc_dummy] 8; @@ -90,42 +90,42 @@ item_mac!(e); // check that the gate visitor works right: extern "C" { - #[cfg(FALSE)] + #[cfg(false)] fn x(a: [u8; #[rustc_dummy] 5]); fn y(a: [u8; #[rustc_dummy] 5]); //~ ERROR attributes on expressions are experimental } struct Foo; impl Foo { - #[cfg(FALSE)] + #[cfg(false)] const X: u8 = #[rustc_dummy] 5; const Y: u8 = #[rustc_dummy] 5; //~ ERROR attributes on expressions are experimental } trait Bar { - #[cfg(FALSE)] + #[cfg(false)] const X: [u8; #[rustc_dummy] 5]; const Y: [u8; #[rustc_dummy] 5]; //~ ERROR attributes on expressions are experimental } struct Joyce { - #[cfg(FALSE)] + #[cfg(false)] field: [u8; #[rustc_dummy] 5], field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } struct Walky( - #[cfg(FALSE)] [u8; #[rustc_dummy] 5], + #[cfg(false)] [u8; #[rustc_dummy] 5], [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ); enum Mike { Happy( - #[cfg(FALSE)] [u8; #[rustc_dummy] 5], + #[cfg(false)] [u8; #[rustc_dummy] 5], [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ), Angry { - #[cfg(FALSE)] + #[cfg(false)] field: [u8; #[rustc_dummy] 5], field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } @@ -133,7 +133,7 @@ enum Mike { fn pat() { match 5 { - #[cfg(FALSE)] + #[cfg(false)] 5 => #[rustc_dummy] (), 6 => #[rustc_dummy] (), //~ ERROR attributes on expressions are experimental _ => (), diff --git a/tests/ui/filter-block-view-items.rs b/tests/ui/filter-block-view-items.rs index 975ab19ddf25..cb599c272647 100644 --- a/tests/ui/filter-block-view-items.rs +++ b/tests/ui/filter-block-view-items.rs @@ -3,5 +3,5 @@ pub fn main() { // Make sure that this view item is filtered out because otherwise it would // trigger a compilation error - #[cfg(FALSE)] use bar as foo; + #[cfg(false)] use bar as foo; } diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs index 33506a5c444a..01f4340b14ad 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs @@ -9,7 +9,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { match scrutinee { ...X => {} //~ ERROR range-to patterns with `...` are not allowed diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs index 2f1ec6589721..24eb99347329 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs @@ -3,7 +3,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn foo() { if let 0... = 1 {} //~ ERROR inclusive range with no end if let 0..= = 1 {} //~ ERROR inclusive range with no end diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs index 2d63fe078561..6b33ead3f87d 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs @@ -1,6 +1,6 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { match &0 { &0.. | _ => {} diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs index 4e3fffbef2de..02699e76ad29 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { match scrutinee { X.. | 0.. | 'a'.. | 0.0f32.. => {} diff --git a/tests/ui/inner-attrs-on-impl.rs b/tests/ui/inner-attrs-on-impl.rs index 75f406232e20..1dce1cdd261a 100644 --- a/tests/ui/inner-attrs-on-impl.rs +++ b/tests/ui/inner-attrs-on-impl.rs @@ -3,7 +3,7 @@ struct Foo; impl Foo { - #![cfg(FALSE)] + #![cfg(false)] fn method(&self) -> bool { false } } @@ -12,7 +12,7 @@ impl Foo { #![cfg(not(FALSE))] // check that we don't eat attributes too eagerly. - #[cfg(FALSE)] + #[cfg(false)] fn method(&self) -> bool { false } fn method(&self) -> bool { true } diff --git a/tests/ui/issues/issue-11004.rs b/tests/ui/issues/issue-11004.rs index 09d5476dbe60..7292843c86a9 100644 --- a/tests/ui/issues/issue-11004.rs +++ b/tests/ui/issues/issue-11004.rs @@ -9,7 +9,7 @@ unsafe fn access(n:*mut A) -> (i32, f64) { (x, y) } -#[cfg(FALSE)] +#[cfg(false)] unsafe fn access(n:*mut A) -> (i32, f64) { let x : i32 = (*n).x; let y : f64 = (*n).y; diff --git a/tests/ui/issues/issue-11085.rs b/tests/ui/issues/issue-11085.rs index d0703b063954..c3f13199b308 100644 --- a/tests/ui/issues/issue-11085.rs +++ b/tests/ui/issues/issue-11085.rs @@ -3,7 +3,7 @@ #![allow(dead_code)] struct Foo { - #[cfg(FALSE)] + #[cfg(false)] bar: baz, foo: isize, } @@ -15,18 +15,18 @@ struct Foo2 { enum Bar1 { Bar1_1, - #[cfg(FALSE)] + #[cfg(false)] Bar1_2(NotAType), } enum Bar2 { - #[cfg(FALSE)] + #[cfg(false)] Bar2_1(NotAType), } enum Bar3 { Bar3_1 { - #[cfg(FALSE)] + #[cfg(false)] foo: isize, bar: isize, } diff --git a/tests/ui/issues/issue-16819.rs b/tests/ui/issues/issue-16819.rs index e2b109091777..2805c82acfb2 100644 --- a/tests/ui/issues/issue-16819.rs +++ b/tests/ui/issues/issue-16819.rs @@ -3,7 +3,7 @@ // `#[cfg]` on struct field permits empty unusable struct struct S { - #[cfg(FALSE)] + #[cfg(false)] a: int, } diff --git a/tests/ui/lexer/error-stage.rs b/tests/ui/lexer/error-stage.rs index c8d88f745a1f..f0ccb886d0d2 100644 --- a/tests/ui/lexer/error-stage.rs +++ b/tests/ui/lexer/error-stage.rs @@ -59,7 +59,7 @@ const _: () = sink! { // The invalid literals used to cause errors, but this was changed by #102944. // Except for `0b010.0f32`, because it's a lexer error. -#[cfg(FALSE)] +#[cfg(false)] fn configured_out() { "string"any_suffix; // OK 10u123; // OK diff --git a/tests/ui/link-native-libs/link-attr-validation-late.rs b/tests/ui/link-native-libs/link-attr-validation-late.rs index 34f720dd2d3c..4eeb8ba4884f 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.rs +++ b/tests/ui/link-native-libs/link-attr-validation-late.rs @@ -9,7 +9,7 @@ extern "C" {} #[link(name = "foo", name = "bar")] //~ ERROR multiple `name` arguments #[link(name = "...", kind = "dylib", kind = "bar")] //~ ERROR multiple `kind` arguments #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] //~ ERROR multiple `modifiers` arguments -#[link(name = "...", cfg(FALSE), cfg(FALSE))] //~ ERROR multiple `cfg` arguments +#[link(name = "...", cfg(false), cfg(false))] //~ ERROR multiple `cfg` arguments #[link(wasm_import_module = "foo", wasm_import_module = "bar")] //~ ERROR multiple `wasm_import_module` arguments extern "C" {} diff --git a/tests/ui/link-native-libs/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr index 1ad5fbaf7de8..f3989c09360f 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr @@ -31,7 +31,7 @@ LL | #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] error: multiple `cfg` arguments in a single `#[link]` attribute --> $DIR/link-attr-validation-late.rs:12:34 | -LL | #[link(name = "...", cfg(FALSE), cfg(FALSE))] +LL | #[link(name = "...", cfg(false), cfg(false))] | ^^^^^^^^^^ error: multiple `wasm_import_module` arguments in a single `#[link]` attribute diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.rs b/tests/ui/lint/unused/unused-attr-macro-rules.rs index c0fc280ab1a7..7a8a1bb1ae52 100644 --- a/tests/ui/lint/unused/unused-attr-macro-rules.rs +++ b/tests/ui/lint/unused/unused-attr-macro-rules.rs @@ -17,7 +17,7 @@ macro_rules! foo2 { () => {}; } -#[cfg(FALSE)] +#[cfg(false)] macro_rules! foo { () => {}; } diff --git a/tests/ui/macros/lint-trailing-macro-call.rs b/tests/ui/macros/lint-trailing-macro-call.rs index 66dce057d0f5..78b861f1df17 100644 --- a/tests/ui/macros/lint-trailing-macro-call.rs +++ b/tests/ui/macros/lint-trailing-macro-call.rs @@ -6,7 +6,7 @@ macro_rules! expand_it { () => { - #[cfg(FALSE)] 25; //~ WARN trailing semicolon in macro + #[cfg(false)] 25; //~ WARN trailing semicolon in macro //~| WARN this was previously } } diff --git a/tests/ui/macros/lint-trailing-macro-call.stderr b/tests/ui/macros/lint-trailing-macro-call.stderr index 13cecc3a31d2..223b85e112ed 100644 --- a/tests/ui/macros/lint-trailing-macro-call.stderr +++ b/tests/ui/macros/lint-trailing-macro-call.stderr @@ -1,7 +1,7 @@ warning: trailing semicolon in macro used in expression position --> $DIR/lint-trailing-macro-call.rs:9:25 | -LL | #[cfg(FALSE)] 25; +LL | #[cfg(false)] 25; | ^ ... LL | expand_it!() @@ -20,7 +20,7 @@ Future incompatibility report: Future breakage diagnostic: warning: trailing semicolon in macro used in expression position --> $DIR/lint-trailing-macro-call.rs:9:25 | -LL | #[cfg(FALSE)] 25; +LL | #[cfg(false)] 25; | ^ ... LL | expand_it!() diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs index 832907907669..976d2cbcccdb 100644 --- a/tests/ui/macros/macro-attributes.rs +++ b/tests/ui/macros/macro-attributes.rs @@ -9,7 +9,7 @@ macro_rules! compiles_fine { // check that the attributes are recognised by requiring this // to be removed to avoid a compile error - #[cfg(FALSE)] + #[cfg(false)] static MISTYPED: () = "foo"; } } diff --git a/tests/ui/macros/macro-inner-attributes.rs b/tests/ui/macros/macro-inner-attributes.rs index a1eb7cd15c4c..1a832ca9b0c4 100644 --- a/tests/ui/macros/macro-inner-attributes.rs +++ b/tests/ui/macros/macro-inner-attributes.rs @@ -5,7 +5,7 @@ macro_rules! test { ($nm:ident, $i:item) => (mod $nm { #![$a] $i }); } test!(a, - #[cfg(FALSE)], + #[cfg(false)], pub fn bar() { }); test!(b, diff --git a/tests/ui/macros/macro-outer-attributes.rs b/tests/ui/macros/macro-outer-attributes.rs index 8c79683f49a9..5b41cf9fd29d 100644 --- a/tests/ui/macros/macro-outer-attributes.rs +++ b/tests/ui/macros/macro-outer-attributes.rs @@ -5,7 +5,7 @@ macro_rules! test { ($nm:ident, $i:item) => (mod $nm { #[$a] $i }); } test!(a, - #[cfg(FALSE)], + #[cfg(false)], pub fn bar() { }); test!(b, diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr index a8809f3fcff6..a894c90f4c32 100644 --- a/tests/ui/macros/macro-outer-attributes.stderr +++ b/tests/ui/macros/macro-outer-attributes.stderr @@ -16,7 +16,7 @@ LL | $i:item) => (mod $nm { #[$a] $i }); } | ^^^^^ LL | LL | / test!(a, -LL | | #[cfg(FALSE)], +LL | | #[cfg(false)], LL | | pub fn bar() { }); | |_______________________- in this macro invocation = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/macros/macro-with-attrs2.rs b/tests/ui/macros/macro-with-attrs2.rs index 37188e45ad3b..7d0bf9114253 100644 --- a/tests/ui/macros/macro-with-attrs2.rs +++ b/tests/ui/macros/macro-with-attrs2.rs @@ -1,6 +1,6 @@ //@ run-pass -#[cfg(FALSE)] +#[cfg(false)] macro_rules! foo { () => (1) } #[cfg(not(FALSE))] diff --git a/tests/ui/nested-cfg-attrs.rs b/tests/ui/nested-cfg-attrs.rs index 0af28fc3d8ec..941807a84310 100644 --- a/tests/ui/nested-cfg-attrs.rs +++ b/tests/ui/nested-cfg-attrs.rs @@ -1,4 +1,4 @@ -#[cfg_attr(all(), cfg_attr(all(), cfg(FALSE)))] +#[cfg_attr(all(), cfg_attr(all(), cfg(false)))] fn f() {} fn main() { f() } //~ ERROR cannot find function `f` in this scope diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.fixed b/tests/ui/or-patterns/fn-param-wrap-parens.fixed index 7b0bbd04d978..fbf60069c7d4 100644 --- a/tests/ui/or-patterns/fn-param-wrap-parens.fixed +++ b/tests/ui/or-patterns/fn-param-wrap-parens.fixed @@ -9,5 +9,5 @@ fn main() {} enum E { A, B } use E::*; -#[cfg(FALSE)] +#[cfg(false)] fn fun1((A | B): E) {} //~ ERROR top-level or-patterns are not allowed diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.rs b/tests/ui/or-patterns/fn-param-wrap-parens.rs index dadbb8a906a7..d796f998e97c 100644 --- a/tests/ui/or-patterns/fn-param-wrap-parens.rs +++ b/tests/ui/or-patterns/fn-param-wrap-parens.rs @@ -9,5 +9,5 @@ fn main() {} enum E { A, B } use E::*; -#[cfg(FALSE)] +#[cfg(false)] fn fun1(A | B: E) {} //~ ERROR top-level or-patterns are not allowed diff --git a/tests/ui/or-patterns/or-patterns-syntactic-pass.rs b/tests/ui/or-patterns/or-patterns-syntactic-pass.rs index 6a8d0a5adb49..6fd5840e801a 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-pass.rs +++ b/tests/ui/or-patterns/or-patterns-syntactic-pass.rs @@ -18,7 +18,7 @@ accept_pat!([p | q]); // Non-macro tests: -#[cfg(FALSE)] +#[cfg(false)] fn or_patterns() { // Top level of `let`: let (| A | B); diff --git a/tests/ui/or-patterns/remove-leading-vert.fixed b/tests/ui/or-patterns/remove-leading-vert.fixed index 3ec815c84684..136ca5765b7e 100644 --- a/tests/ui/or-patterns/remove-leading-vert.fixed +++ b/tests/ui/or-patterns/remove-leading-vert.fixed @@ -6,7 +6,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn leading() { fn fun1( A: E) {} //~ ERROR top-level or-patterns are not allowed fn fun2( A: E) {} //~ ERROR unexpected `||` before function parameter @@ -21,7 +21,7 @@ fn leading() { let NS { f: | A }: NS; //~ ERROR unexpected token `||` in pattern } -#[cfg(FALSE)] +#[cfg(false)] fn trailing() { let ( A ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern let (a ,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern diff --git a/tests/ui/or-patterns/remove-leading-vert.rs b/tests/ui/or-patterns/remove-leading-vert.rs index 2aeeb0e979f6..d9e9c9fe4d2f 100644 --- a/tests/ui/or-patterns/remove-leading-vert.rs +++ b/tests/ui/or-patterns/remove-leading-vert.rs @@ -6,7 +6,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn leading() { fn fun1( | A: E) {} //~ ERROR top-level or-patterns are not allowed fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter @@ -21,7 +21,7 @@ fn leading() { let NS { f: || A }: NS; //~ ERROR unexpected token `||` in pattern } -#[cfg(FALSE)] +#[cfg(false)] fn trailing() { let ( A | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern let (a |,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern diff --git a/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs b/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs index 6c0453791916..63c567b2d033 100644 --- a/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs +++ b/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] const _: () = { pub trait A { const _: () = (); diff --git a/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs b/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs index 492f2ea16ef5..e875d733bd62 100644 --- a/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs +++ b/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl S { static IA: u8 = 0; //~ ERROR associated `static` items are not allowed static IB: u8; //~ ERROR associated `static` items are not allowed @@ -12,7 +12,7 @@ impl S { //~^ ERROR a static item cannot be `default` } -#[cfg(FALSE)] +#[cfg(false)] trait T { static TA: u8 = 0; //~ ERROR associated `static` items are not allowed static TB: u8; //~ ERROR associated `static` items are not allowed @@ -22,7 +22,7 @@ trait T { //~^ ERROR a static item cannot be `default` } -#[cfg(FALSE)] +#[cfg(false)] impl T for S { static TA: u8 = 0; //~ ERROR associated `static` items are not allowed static TB: u8; //~ ERROR associated `static` items are not allowed diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs index 26761a1d2544..1380974538a5 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs @@ -1,108 +1,108 @@ fn main() {} -#[cfg(FALSE)] fn e() { let _ = [#[attr]]; } +#[cfg(false)] fn e() { let _ = [#[attr]]; } //~^ ERROR expected expression, found `]` -#[cfg(FALSE)] fn e() { let _ = foo#[attr](); } +#[cfg(false)] fn e() { let _ = foo#[attr](); } //~^ ERROR expected one of -#[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } +#[cfg(false)] fn e() { let _ = foo(#![attr]); } //~^ ERROR an inner attribute is not permitted in this context //~| ERROR an inner attribute is not permitted in this context //~| ERROR expected expression, found `)` -#[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); } +#[cfg(false)] fn e() { let _ = x.foo(#![attr]); } //~^ ERROR an inner attribute is not permitted in this context //~| ERROR expected expression, found `)` -#[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; } +#[cfg(false)] fn e() { let _ = 0 + #![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = !#![attr] 0; } +#[cfg(false)] fn e() { let _ = !#![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = -#![attr] 0; } +#[cfg(false)] fn e() { let _ = -#![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; } +#[cfg(false)] fn e() { let _ = x #![attr] as Y; } //~^ ERROR expected one of -#[cfg(FALSE)] fn e() { let _ = || #![attr] foo; } +#[cfg(false)] fn e() { let _ = || #![attr] foo; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; } +#[cfg(false)] fn e() { let _ = move || #![attr] foo; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; } +#[cfg(false)] fn e() { let _ = || #![attr] {foo}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; } +#[cfg(false)] fn e() { let _ = move || #![attr] {foo}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = #[attr] ..#[attr] 0; } +#[cfg(false)] fn e() { let _ = #[attr] ..#[attr] 0; } //~^ ERROR attributes are not allowed on range expressions starting with `..` -#[cfg(FALSE)] fn e() { let _ = #[attr] ..; } +#[cfg(false)] fn e() { let _ = #[attr] ..; } //~^ ERROR attributes are not allowed on range expressions starting with `..` -#[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; } +#[cfg(false)] fn e() { let _ = #[attr] &#![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } +#[cfg(false)] fn e() { let _ = #[attr] &mut #![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } +#[cfg(false)] fn e() { let _ = if 0 #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } +#[cfg(false)] fn e() { let _ = if 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; } +#[cfg(false)] fn e() { let _ = if 0 {} #[attr] else {}; } //~^ ERROR expected one of -#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } +#[cfg(false)] fn e() { let _ = if 0 {} else #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } +#[cfg(false)] fn e() { let _ = if 0 {} else {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } +#[cfg(false)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } +#[cfg(false)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } +#[cfg(false)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } //~^ ERROR expected one of -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } //~^ ERROR outer attributes are not allowed on `if` -#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } +#[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; } +#[cfg(false)] fn s() { #[attr] #![attr] let _ = 0; } //~^ ERROR an inner attribute is not permitted following an outer attribute -#[cfg(FALSE)] fn s() { #[attr] #![attr] 0; } +#[cfg(false)] fn s() { #[attr] #![attr] 0; } //~^ ERROR an inner attribute is not permitted following an outer attribute -#[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } +#[cfg(false)] fn s() { #[attr] #![attr] foo!(); } //~^ ERROR an inner attribute is not permitted following an outer attribute -#[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } +#[cfg(false)] fn s() { #[attr] #![attr] foo![]; } //~^ ERROR an inner attribute is not permitted following an outer attribute -#[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } +#[cfg(false)] fn s() { #[attr] #![attr] foo!{}; } //~^ ERROR an inner attribute is not permitted following an outer attribute // FIXME: Allow attributes in pattern constexprs? // note: requires parens in patterns to allow disambiguation -#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } +#[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } } //~^ ERROR inclusive range with no end //~| ERROR expected one of `=>`, `if`, or `|`, found `#` -#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } +#[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } } //~^ ERROR inclusive range with no end //~| ERROR expected one of `=>`, `if`, or `|`, found `#` -#[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } } +#[cfg(false)] fn e() { match 0 { 0..=-#[attr] 10 => () } } //~^ ERROR unexpected token: `#` -#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } +#[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } } //~^ ERROR inclusive range with no end //~| ERROR expected one of `=>`, `if`, or `|`, found `#` -#[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } +#[cfg(false)] fn e() { let _ = x.#![attr]foo(); } //~^ ERROR unexpected token: `#` //~| ERROR expected one of `.` -#[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } +#[cfg(false)] fn e() { let _ = x.#[attr]foo(); } //~^ ERROR unexpected token: `#` //~| ERROR expected one of `.` // make sure we don't catch this bug again... -#[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } } +#[cfg(false)] fn e() { { fn foo() { #[attr]; } } } //~^ ERROR expected statement after outer attribute -#[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } } +#[cfg(false)] fn e() { { fn foo() { #[attr] } } } //~^ ERROR expected statement after outer attribute diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr index bd860841b806..5d94a8dcbdb8 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr @@ -1,19 +1,19 @@ error: expected expression, found `]` --> $DIR/attr-stmt-expr-attr-bad.rs:3:40 | -LL | #[cfg(FALSE)] fn e() { let _ = [#[attr]]; } +LL | #[cfg(false)] fn e() { let _ = [#[attr]]; } | ^ expected expression error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:5:35 | -LL | #[cfg(FALSE)] fn e() { let _ = foo#[attr](); } +LL | #[cfg(false)] fn e() { let _ = foo#[attr](); } | ^ expected one of 8 possible tokens error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:7:36 | -LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = foo(#![attr]); } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -22,7 +22,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:7:36 | -LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = foo(#![attr]); } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -32,13 +32,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } error: expected expression, found `)` --> $DIR/attr-stmt-expr-attr-bad.rs:7:44 | -LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = foo(#![attr]); } | ^ expected expression error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:11:38 | -LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = x.foo(#![attr]); } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -47,13 +47,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); } error: expected expression, found `)` --> $DIR/attr-stmt-expr-attr-bad.rs:11:46 | -LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); } +LL | #[cfg(false)] fn e() { let _ = x.foo(#![attr]); } | ^ expected expression error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:14:36 | -LL | #[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = 0 + #![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -62,7 +62,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:16:33 | -LL | #[cfg(FALSE)] fn e() { let _ = !#![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = !#![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -71,7 +71,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = !#![attr] 0; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:18:33 | -LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = -#![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -80,13 +80,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; } error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:20:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; } +LL | #[cfg(false)] fn e() { let _ = x #![attr] as Y; } | ^ expected one of 8 possible tokens error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:22:35 | -LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] foo; } +LL | #[cfg(false)] fn e() { let _ = || #![attr] foo; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -95,7 +95,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] foo; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:24:40 | -LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; } +LL | #[cfg(false)] fn e() { let _ = move || #![attr] foo; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -104,7 +104,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:26:35 | -LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; } +LL | #[cfg(false)] fn e() { let _ = || #![attr] {foo}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -113,7 +113,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:28:40 | -LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; } +LL | #[cfg(false)] fn e() { let _ = move || #![attr] {foo}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -122,19 +122,19 @@ LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; } error: attributes are not allowed on range expressions starting with `..` --> $DIR/attr-stmt-expr-attr-bad.rs:30:40 | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..#[attr] 0; } +LL | #[cfg(false)] fn e() { let _ = #[attr] ..#[attr] 0; } | ^^ error: attributes are not allowed on range expressions starting with `..` --> $DIR/attr-stmt-expr-attr-bad.rs:32:40 | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..; } +LL | #[cfg(false)] fn e() { let _ = #[attr] ..; } | ^^ error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:34:41 | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = #[attr] &#![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -143,7 +143,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; } error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:36:45 | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } +LL | #[cfg(false)] fn e() { let _ = #[attr] &mut #![attr] 0; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -152,21 +152,21 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:38:37 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `if` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if 0 #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if 0 {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:40:38 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -175,27 +175,27 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:42:40 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:44:45 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] {}; } | ---- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `else` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else {}; } +LL - #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if 0 {} else {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:46:46 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -204,35 +204,35 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:48:45 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } | ---- ^^^^^^^ ------- the attributes are attached to this branch | | | the branch belongs to this `else` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } +LL + #[cfg(false)] fn e() { let _ = if 0 {} else if 0 {}; } | error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:50:50 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `if` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if 0 {} else if 0 {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:52:51 | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -241,21 +241,21 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:54:45 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `if` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if let _ = 0 #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:56:46 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -264,27 +264,27 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:58:48 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:60:53 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } | ---- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `else` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {}; } +LL - #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {} else {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:62:54 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -293,35 +293,35 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:64:53 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } | ---- ^^^^^^^ --------------- the attributes are attached to this branch | | | the branch belongs to this `else` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } +LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } | error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:66:66 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch | | | the branch belongs to this `if` | help: remove the attributes | -LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } -LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } +LL - #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } +LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:68:67 | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } +LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files @@ -330,7 +330,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]} error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:71:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; } +LL | #[cfg(false)] fn s() { #[attr] #![attr] let _ = 0; } | ------- ^^^^^^^^ not permitted following an outer attribute | | | previous outer attribute @@ -341,7 +341,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; } error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:73:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; } +LL | #[cfg(false)] fn s() { #[attr] #![attr] 0; } | ------- ^^^^^^^^ not permitted following an outer attribute | | | previous outer attribute @@ -352,7 +352,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; } error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:75:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } +LL | #[cfg(false)] fn s() { #[attr] #![attr] foo!(); } | ------- ^^^^^^^^ ------- the inner attribute doesn't annotate this item macro invocation | | | | | not permitted following an outer attribute @@ -363,7 +363,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:77:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } +LL | #[cfg(false)] fn s() { #[attr] #![attr] foo![]; } | ------- ^^^^^^^^ ------- the inner attribute doesn't annotate this item macro invocation | | | | | not permitted following an outer attribute @@ -374,7 +374,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:79:32 | -LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } +LL | #[cfg(false)] fn s() { #[attr] #![attr] foo!{}; } | ------- ^^^^^^^^ ------ the inner attribute doesn't annotate this item macro invocation | | | | | not permitted following an outer attribute @@ -385,100 +385,100 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:85:35 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } } | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) help: use `..` instead | -LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } -LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] 10 => () } } +LL - #[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } } +LL + #[cfg(false)] fn e() { match 0 { 0..#[attr] 10 => () } } | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:85:38 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } } | ^ expected one of `=>`, `if`, or `|` error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:88:35 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } } | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) help: use `..` instead | -LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } -LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] -10 => () } } +LL - #[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } } +LL + #[cfg(false)] fn e() { match 0 { 0..#[attr] -10 => () } } | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:88:38 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } } | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` --> $DIR/attr-stmt-expr-attr-bad.rs:91:39 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=-#[attr] 10 => () } } | ^ error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:93:35 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } } | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) help: use `..` instead | -LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } -LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] FOO => () } } +LL - #[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } } +LL + #[cfg(false)] fn e() { match 0 { 0..#[attr] FOO => () } } | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:93:38 | -LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } +LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } } | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` --> $DIR/attr-stmt-expr-attr-bad.rs:97:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } +LL | #[cfg(false)] fn e() { let _ = x.#![attr]foo(); } | ^ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:97:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } +LL | #[cfg(false)] fn e() { let _ = x.#![attr]foo(); } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: unexpected token: `#` --> $DIR/attr-stmt-expr-attr-bad.rs:100:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } +LL | #[cfg(false)] fn e() { let _ = x.#[attr]foo(); } | ^ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:100:34 | -LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } +LL | #[cfg(false)] fn e() { let _ = x.#[attr]foo(); } | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: expected statement after outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:105:37 | -LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } } +LL | #[cfg(false)] fn e() { { fn foo() { #[attr]; } } } | ^^^^^^^ error: expected statement after outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:107:37 | -LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } } +LL | #[cfg(false)] fn e() { { fn foo() { #[attr] } } } | ^^^^^^^ error: aborting due to 53 previous errors diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs index 33671df94928..371f19d48726 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs @@ -1,7 +1,7 @@ #![feature(stmt_expr_attributes)] fn foo() -> String { - #[cfg(FALSE)] + #[cfg(false)] [1, 2, 3].iter().map(|c| c.to_string()).collect::() //~ ERROR expected `;`, found `#` #[cfg(not(FALSE))] String::new() diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr index 6266718162f8..3a97a14b3c30 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr @@ -1,7 +1,7 @@ error: expected `;`, found `#` --> $DIR/multiple-tail-expr-behind-cfg.rs:5:64 | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | ------------- only `;` terminated statements or tail expressions are allowed after this attribute LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::() | ^ expected `;` here @@ -18,7 +18,7 @@ LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::() } | + + help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)` | -LL ~ if cfg!(FALSE) { +LL ~ if cfg!(false) { LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::() LL ~ } else if cfg!(not(FALSE)) { LL ~ String::new() diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs index e2a62922bcc5..1cd3f13d7b67 100644 --- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs @@ -5,7 +5,7 @@ macro_rules! the_macro { #[cfg()] $foo //~ ERROR expected `;`, found `#` - #[cfg(FALSE)] + #[cfg(false)] $bar }; } diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr index fa4409f73fa5..41e7b5ab759d 100644 --- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr @@ -6,7 +6,7 @@ LL | #[cfg()] LL | $foo | ^ expected `;` here LL | -LL | #[cfg(FALSE)] +LL | #[cfg(false)] | - unexpected token ... LL | the_macro!( (); (); ); diff --git a/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs b/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs index ed3ffed2f802..acc58a47fbcf 100644 --- a/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs +++ b/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs @@ -1,6 +1,6 @@ //@ check-pass -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { foo::(); foo::(); diff --git a/tests/ui/parser/default-on-wrong-item-kind.rs b/tests/ui/parser/default-on-wrong-item-kind.rs index 98a95cfa35a9..da990a4b4212 100644 --- a/tests/ui/parser/default-on-wrong-item-kind.rs +++ b/tests/ui/parser/default-on-wrong-item-kind.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] mod free_items { default extern crate foo; //~ ERROR an extern crate cannot be `default` default use foo; //~ ERROR a `use` import cannot be `default` @@ -28,7 +28,7 @@ mod free_items { default macro_rules! foo {} //~ ERROR a macro definition cannot be `default` } -#[cfg(FALSE)] +#[cfg(false)] extern "C" { default extern crate foo; //~ ERROR an extern crate cannot be `default` //~^ ERROR extern crate is not supported in `extern` blocks @@ -65,7 +65,7 @@ extern "C" { //~^ ERROR macro definition is not supported in `extern` blocks } -#[cfg(FALSE)] +#[cfg(false)] impl S { default extern crate foo; //~ ERROR an extern crate cannot be `default` //~^ ERROR extern crate is not supported in `trait`s or `impl`s @@ -102,7 +102,7 @@ impl S { //~^ ERROR macro definition is not supported in `trait`s or `impl`s } -#[cfg(FALSE)] +#[cfg(false)] trait T { default extern crate foo; //~ ERROR an extern crate cannot be `default` //~^ ERROR extern crate is not supported in `trait`s or `impl`s diff --git a/tests/ui/parser/extern-abi-syntactic.rs b/tests/ui/parser/extern-abi-syntactic.rs index d3e2ba0e2d3f..28565a3f4bef 100644 --- a/tests/ui/parser/extern-abi-syntactic.rs +++ b/tests/ui/parser/extern-abi-syntactic.rs @@ -5,13 +5,13 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "some_abi_that_we_are_sure_does_not_exist_semantically" fn foo() {} -#[cfg(FALSE)] +#[cfg(false)] extern "some_abi_that_we_are_sure_does_not_exist_semantically" { fn foo(); } -#[cfg(FALSE)] +#[cfg(false)] type T = extern "some_abi_that_we_are_sure_does_not_exist_semantically" fn(); diff --git a/tests/ui/parser/extern-crate-async.rs b/tests/ui/parser/extern-crate-async.rs index 7c7769075b65..529e0f1ab5cb 100644 --- a/tests/ui/parser/extern-crate-async.rs +++ b/tests/ui/parser/extern-crate-async.rs @@ -5,8 +5,8 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern crate async; -#[cfg(FALSE)] +#[cfg(false)] extern crate async as something_else; diff --git a/tests/ui/parser/fn-body-optional-syntactic-pass.rs b/tests/ui/parser/fn-body-optional-syntactic-pass.rs index 140471dfc774..762247e63e99 100644 --- a/tests/ui/parser/fn-body-optional-syntactic-pass.rs +++ b/tests/ui/parser/fn-body-optional-syntactic-pass.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { fn f(); fn f() {} diff --git a/tests/ui/parser/fn-header-syntactic-pass.rs b/tests/ui/parser/fn-header-syntactic-pass.rs index 065ded31b073..1e15886e5645 100644 --- a/tests/ui/parser/fn-header-syntactic-pass.rs +++ b/tests/ui/parser/fn-header-syntactic-pass.rs @@ -5,7 +5,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { async fn f(); unsafe fn f(); diff --git a/tests/ui/parser/foreign-const-syntactic-fail.rs b/tests/ui/parser/foreign-const-syntactic-fail.rs index a6e77f846638..fc3cd0b3430d 100644 --- a/tests/ui/parser/foreign-const-syntactic-fail.rs +++ b/tests/ui/parser/foreign-const-syntactic-fail.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" { const A: isize; //~ ERROR extern items cannot be `const` const B: isize = 42; //~ ERROR extern items cannot be `const` diff --git a/tests/ui/parser/foreign-static-syntactic-pass.rs b/tests/ui/parser/foreign-static-syntactic-pass.rs index a76b9bab4911..d7c21c672ab6 100644 --- a/tests/ui/parser/foreign-static-syntactic-pass.rs +++ b/tests/ui/parser/foreign-static-syntactic-pass.rs @@ -4,7 +4,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" { static X: u8; static mut Y: u8; diff --git a/tests/ui/parser/foreign-ty-syntactic-pass.rs b/tests/ui/parser/foreign-ty-syntactic-pass.rs index 50bb68cd83be..337276852010 100644 --- a/tests/ui/parser/foreign-ty-syntactic-pass.rs +++ b/tests/ui/parser/foreign-ty-syntactic-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" { type A: Ord; type A<'a> where 'a: 'static; diff --git a/tests/ui/parser/impl-item-const-pass.rs b/tests/ui/parser/impl-item-const-pass.rs index 8ebdf633b5b9..6ca4cd9cd930 100644 --- a/tests/ui/parser/impl-item-const-pass.rs +++ b/tests/ui/parser/impl-item-const-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl X { const Y: u8; } diff --git a/tests/ui/parser/impl-item-fn-no-body-pass.rs b/tests/ui/parser/impl-item-fn-no-body-pass.rs index 5a593fe1d124..b8269fc42708 100644 --- a/tests/ui/parser/impl-item-fn-no-body-pass.rs +++ b/tests/ui/parser/impl-item-fn-no-body-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl X { fn f(); } diff --git a/tests/ui/parser/impl-item-type-no-body-pass.rs b/tests/ui/parser/impl-item-type-no-body-pass.rs index 039825bcc538..979b5f765960 100644 --- a/tests/ui/parser/impl-item-type-no-body-pass.rs +++ b/tests/ui/parser/impl-item-type-no-body-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl X { type Y; type Z: Ord; diff --git a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs index 4fa803bb318e..13bb9351bb69 100644 --- a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs +++ b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs @@ -20,7 +20,7 @@ macro_rules! mac_variant { mac_variant!(MARKER); // We also accept visibilities on variants syntactically but not semantically. -#[cfg(FALSE)] +#[cfg(false)] enum E { pub U, pub(crate) T(u8), diff --git a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs index cd474db63b71..55e69cd14d6b 100644 --- a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs +++ b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs @@ -20,7 +20,7 @@ trait Alpha { } // We also accept visibilities on items in traits syntactically but not semantically. -#[cfg(FALSE)] +#[cfg(false)] trait Foo { pub fn bar(); pub(crate) type baz; diff --git a/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs b/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs index 4edbee54de67..0b9229860bf8 100644 --- a/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs +++ b/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs @@ -4,5 +4,5 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] const X: u8; diff --git a/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs b/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs index df5192645e11..8dae4338ee7e 100644 --- a/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs +++ b/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs @@ -4,5 +4,5 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] static X: u8; diff --git a/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs b/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs index 80de3cfc668d..8603dc3eaf86 100644 --- a/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs +++ b/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { type A: Ord; type B: Ord = u8; diff --git a/tests/ui/parser/recover/recover-assoc-const-constraint.rs b/tests/ui/parser/recover/recover-assoc-const-constraint.rs index 1453e6cb5cd7..d938b4ccaca7 100644 --- a/tests/ui/parser/recover/recover-assoc-const-constraint.rs +++ b/tests/ui/parser/recover/recover-assoc-const-constraint.rs @@ -1,4 +1,4 @@ -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { bar::(); //~^ ERROR associated const equality is incomplete diff --git a/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs b/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs index 4b42c44dc64e..73b4e22cab6f 100644 --- a/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs +++ b/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs @@ -1,4 +1,4 @@ -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { bar::(); //~ ERROR missing type to the right of `=` } diff --git a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs index cb65f80b0890..30bac49e63a5 100644 --- a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs +++ b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs @@ -1,4 +1,4 @@ -#[cfg(FALSE)] +#[cfg(false)] fn syntax() { bar::(); //~ ERROR lifetimes are not permitted in this context } diff --git a/tests/ui/parser/self-param-syntactic-pass.rs b/tests/ui/parser/self-param-syntactic-pass.rs index c7fdc5297164..331e652f9c57 100644 --- a/tests/ui/parser/self-param-syntactic-pass.rs +++ b/tests/ui/parser/self-param-syntactic-pass.rs @@ -5,7 +5,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn free() { fn f(self) {} fn f(mut self) {} @@ -17,7 +17,7 @@ fn free() { fn f(mut self: u8) {} } -#[cfg(FALSE)] +#[cfg(false)] extern "C" { fn f(self); fn f(mut self); @@ -29,7 +29,7 @@ extern "C" { fn f(mut self: u8); } -#[cfg(FALSE)] +#[cfg(false)] trait X { fn f(self) {} fn f(mut self) {} @@ -41,7 +41,7 @@ trait X { fn f(mut self: u8) {} } -#[cfg(FALSE)] +#[cfg(false)] impl X for Y { fn f(self) {} fn f(mut self) {} @@ -53,7 +53,7 @@ impl X for Y { fn f(mut self: u8) {} } -#[cfg(FALSE)] +#[cfg(false)] impl X for Y { type X = fn(self); type X = fn(mut self); diff --git a/tests/ui/parser/stripped-nested-outline-mod-pass.rs b/tests/ui/parser/stripped-nested-outline-mod-pass.rs index 8909d8ae0eb6..166a60f257a3 100644 --- a/tests/ui/parser/stripped-nested-outline-mod-pass.rs +++ b/tests/ui/parser/stripped-nested-outline-mod-pass.rs @@ -5,7 +5,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] mod foo { mod bar { mod baz; // This was an error before. diff --git a/tests/ui/parser/trait-item-with-defaultness-pass.rs b/tests/ui/parser/trait-item-with-defaultness-pass.rs index c636342f6ca4..164d0b13b539 100644 --- a/tests/ui/parser/trait-item-with-defaultness-pass.rs +++ b/tests/ui/parser/trait-item-with-defaultness-pass.rs @@ -2,7 +2,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] trait X { default const A: u8; default const B: u8 = 0; diff --git a/tests/ui/parser/variadic-ffi-syntactic-pass.rs b/tests/ui/parser/variadic-ffi-syntactic-pass.rs index da81f1362160..ebe0b6c2dd25 100644 --- a/tests/ui/parser/variadic-ffi-syntactic-pass.rs +++ b/tests/ui/parser/variadic-ffi-syntactic-pass.rs @@ -2,31 +2,31 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn f1_1(x: isize, ...) {} -#[cfg(FALSE)] +#[cfg(false)] fn f1_2(...) {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" fn f2_1(x: isize, ...) {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" fn f2_2(...) {} -#[cfg(FALSE)] +#[cfg(false)] extern "C" fn f2_3(..., x: isize) {} -#[cfg(FALSE)] +#[cfg(false)] extern fn f3_1(x: isize, ...) {} -#[cfg(FALSE)] +#[cfg(false)] extern fn f3_2(...) {} -#[cfg(FALSE)] +#[cfg(false)] extern fn f3_3(..., x: isize) {} -#[cfg(FALSE)] +#[cfg(false)] extern { fn e_f1(...); fn e_f2(..., x: isize); @@ -34,7 +34,7 @@ extern { struct X; -#[cfg(FALSE)] +#[cfg(false)] impl X { fn i_f1(x: isize, ...) {} fn i_f2(...) {} @@ -42,7 +42,7 @@ impl X { fn i_f4(..., x: isize, ...) {} } -#[cfg(FALSE)] +#[cfg(false)] trait T { fn t_f1(x: isize, ...) {} fn t_f2(x: isize, ...); diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs index 01a978d55574..9582d2729a89 100644 --- a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs +++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs @@ -13,19 +13,19 @@ fn _ok() { fn _f(_a @ _b: u8) {} // OK. } -#[cfg(FALSE)] +#[cfg(false)] fn case_1() { let a: u8 @ b = 0; //~^ ERROR expected one of `!` } -#[cfg(FALSE)] +#[cfg(false)] fn case_2() { let a @ (b: u8); //~^ ERROR expected one of `)` } -#[cfg(FALSE)] +#[cfg(false)] fn case_3() { let a: T1 @ Outer(b: T2); //~^ ERROR expected one of `!` diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs index 50ac0ef27834..c3994d35c421 100644 --- a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs +++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs @@ -3,7 +3,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] fn wild_before_at_is_bad_syntax() { let _ @ a = 0; //~^ ERROR pattern on wrong side of `@` diff --git a/tests/ui/pattern/rest-pat-syntactic.rs b/tests/ui/pattern/rest-pat-syntactic.rs index 1de29e69b054..59c687bb5a8d 100644 --- a/tests/ui/pattern/rest-pat-syntactic.rs +++ b/tests/ui/pattern/rest-pat-syntactic.rs @@ -11,7 +11,7 @@ macro_rules! accept_pat { accept_pat!(..); -#[cfg(FALSE)] +#[cfg(false)] fn rest_patterns() { // Top level: fn foo(..: u8) {} diff --git a/tests/ui/proc-macro/attribute-after-derive.rs b/tests/ui/proc-macro/attribute-after-derive.rs index f2e2eb12a195..382ef1f6ddfd 100644 --- a/tests/ui/proc-macro/attribute-after-derive.rs +++ b/tests/ui/proc-macro/attribute-after-derive.rs @@ -14,14 +14,14 @@ extern crate test_macros; #[print_attr] #[derive(Print)] struct AttributeDerive { - #[cfg(FALSE)] + #[cfg(false)] field: u8, } #[derive(Print)] #[print_attr] struct DeriveAttribute { - #[cfg(FALSE)] + #[cfg(false)] field: u8, } diff --git a/tests/ui/proc-macro/attribute-after-derive.stdout b/tests/ui/proc-macro/attribute-after-derive.stdout index 6d9531df8caf..bc0fc6dc1af1 100644 --- a/tests/ui/proc-macro/attribute-after-derive.stdout +++ b/tests/ui/proc-macro/attribute-after-derive.stdout @@ -1,5 +1,5 @@ -PRINT-ATTR INPUT (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(FALSE)] field: u8, } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(FALSE)] field : u8, } +PRINT-ATTR INPUT (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(false)] field: u8, } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(false)] field : u8, } PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', @@ -53,7 +53,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0), }, ], @@ -131,8 +131,8 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field: u8, } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field : u8, } +PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(false)] field: u8, } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct DeriveAttribute { #[cfg(false)] field : u8, } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -161,7 +161,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/attribute-after-derive.rs:24:11: 24:16 (#0), }, ], diff --git a/tests/ui/proc-macro/cfg-eval-fail.rs b/tests/ui/proc-macro/cfg-eval-fail.rs index a259aa2e6ec0..a94dcd283781 100644 --- a/tests/ui/proc-macro/cfg-eval-fail.rs +++ b/tests/ui/proc-macro/cfg-eval-fail.rs @@ -2,6 +2,6 @@ #![feature(stmt_expr_attributes)] fn main() { - let _ = #[cfg_eval] #[cfg(FALSE)] 0; + let _ = #[cfg_eval] #[cfg(false)] 0; //~^ ERROR removing an expression is not supported in this position } diff --git a/tests/ui/proc-macro/cfg-eval-fail.stderr b/tests/ui/proc-macro/cfg-eval-fail.stderr index 945ad46bf33c..7f21e4646b1c 100644 --- a/tests/ui/proc-macro/cfg-eval-fail.stderr +++ b/tests/ui/proc-macro/cfg-eval-fail.stderr @@ -1,7 +1,7 @@ error: removing an expression is not supported in this position --> $DIR/cfg-eval-fail.rs:5:25 | -LL | let _ = #[cfg_eval] #[cfg(FALSE)] 0; +LL | let _ = #[cfg_eval] #[cfg(false)] 0; | ^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/cfg-eval-inner.rs b/tests/ui/proc-macro/cfg-eval-inner.rs index 7493f3ea5236..dc4efd6ba15f 100644 --- a/tests/ui/proc-macro/cfg-eval-inner.rs +++ b/tests/ui/proc-macro/cfg-eval-inner.rs @@ -32,7 +32,7 @@ impl Foo<[u8; { #![cfg_attr(not(FALSE), rustc_dummy(evaluated_attr))] fn bar() { - #[cfg(FALSE)] let a = 1; + #[cfg(false)] let a = 1; } } diff --git a/tests/ui/proc-macro/cfg-eval.rs b/tests/ui/proc-macro/cfg-eval.rs index 1d9b4f23ea5c..ddf370805960 100644 --- a/tests/ui/proc-macro/cfg-eval.rs +++ b/tests/ui/proc-macro/cfg-eval.rs @@ -15,7 +15,7 @@ extern crate test_macros; #[cfg_eval] #[print_attr] struct S1 { - #[cfg(FALSE)] + #[cfg(false)] field_false: u8, #[cfg(all(/*true*/))] #[cfg_attr(FALSE, unknown_attr)] @@ -24,7 +24,7 @@ struct S1 { } #[cfg_eval] -#[cfg(FALSE)] +#[cfg(false)] struct S2 {} fn main() { @@ -33,5 +33,5 @@ fn main() { // expression. `#[cfg]` is not supported inside parenthesized expressions, so this will // produce an error when attribute collection runs. let _ = #[cfg_eval] #[print_attr] #[cfg_attr(not(FALSE), rustc_dummy)] - (#[cfg(FALSE)] 0, #[cfg(all(/*true*/))] 1,); + (#[cfg(false)] 0, #[cfg(all(/*true*/))] 1,); } diff --git a/tests/ui/proc-macro/derive-cfg-nested-tokens.rs b/tests/ui/proc-macro/derive-cfg-nested-tokens.rs index 7d4e8d8373d6..ec6aba0d1ea3 100644 --- a/tests/ui/proc-macro/derive-cfg-nested-tokens.rs +++ b/tests/ui/proc-macro/derive-cfg-nested-tokens.rs @@ -15,7 +15,7 @@ struct S { // - on eagerly configured `S` (from `impl Copy`), only 11 should be printed // - on non-configured `S` (from `struct S`), both 10 and 11 should be printed field: [u8; #[print_attr] { - #[cfg(FALSE)] { 10 } + #[cfg(false)] { 10 } #[cfg(not(FALSE))] { 11 } }], } diff --git a/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout b/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout index 05bf21ee8f9b..9dbddc95902d 100644 --- a/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout +++ b/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout @@ -54,7 +54,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: #0 bytes(452..523), }, ] -PRINT-ATTR INPUT (DISPLAY): { #[cfg(FALSE)] { 10 } #[cfg(not(FALSE))] { 11 } } +PRINT-ATTR INPUT (DISPLAY): { #[cfg(false)] { 10 } #[cfg(not(FALSE))] { 11 } } PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Brace, @@ -75,7 +75,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: #0 bytes(468..473), }, ], diff --git a/tests/ui/proc-macro/expand-to-derive.rs b/tests/ui/proc-macro/expand-to-derive.rs index 0e38e471980b..05c8e3262431 100644 --- a/tests/ui/proc-macro/expand-to-derive.rs +++ b/tests/ui/proc-macro/expand-to-derive.rs @@ -14,7 +14,7 @@ macro_rules! expand_to_derive { ($item:item) => { #[derive(Print)] struct Foo { - #[cfg(FALSE)] removed: bool, + #[cfg(false)] removed: bool, field: [bool; { $item 0 @@ -26,7 +26,7 @@ macro_rules! expand_to_derive { expand_to_derive! { #[cfg_attr(not(FALSE), rustc_dummy)] struct Inner { - #[cfg(FALSE)] removed_inner_field: bool, + #[cfg(false)] removed_inner_field: bool, other_inner_field: u8, } } diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.rs b/tests/ui/proc-macro/issue-75930-derive-cfg.rs index 376a8ea42783..f0851b31e9cb 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.rs +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.rs @@ -31,7 +31,7 @@ extern crate test_macros; // // It is because of this code from below: // ``` -// struct Foo<#[cfg(FALSE)] A, B> +// struct Foo<#[cfg(false)] A, B> // ``` // When the token stream is formed during parsing, `<` is followed immediately // by `#`, which is punctuation, so it is marked `Joint`. But before being @@ -51,22 +51,22 @@ extern crate test_macros; #[print_attr] #[derive(Print)] #[print_helper(b)] -struct Foo<#[cfg(FALSE)] A, B> { - #[cfg(FALSE)] first: String, +struct Foo<#[cfg(false)] A, B> { + #[cfg(false)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: bool, third: [u8; { - #[cfg(FALSE)] struct Bar; + #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner; - #[cfg(FALSE)] let a = 25; + #[cfg(false)] let a = 25; match true { - #[cfg(FALSE)] true => {}, + #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} }; #[print_helper(should_be_removed)] fn removed_fn() { - #![cfg(FALSE)] + #![cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { @@ -76,22 +76,22 @@ struct Foo<#[cfg(FALSE)] A, B> { enum TupleEnum { Foo( - #[cfg(FALSE)] u8, - #[cfg(FALSE)] bool, + #[cfg(false)] u8, + #[cfg(false)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8 + #[cfg(false)] String, u8 ) } struct TupleStruct( - #[cfg(FALSE)] String, + #[cfg(false)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, + #[cfg(false)] bool, u8 ); fn plain_removed_fn() { - #![cfg_attr(not(FALSE), cfg(FALSE))] + #![cfg_attr(not(FALSE), cfg(false))] } 0 diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout index 4dcf2b717d8a..549621fdca31 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -1,73 +1,73 @@ PRINT-ATTR INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] -struct Foo<#[cfg(FALSE)] A, B> +struct Foo<#[cfg(false)] A, B> { - #[cfg(FALSE)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: + #[cfg(false)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: bool, third: [u8; { - #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner; - #[cfg(FALSE)] let a = 25; match true + #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner; + #[cfg(false)] let a = 25; match true { - #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] + #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} }; #[print_helper(should_be_removed)] fn removed_fn() - { #![cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() + { #![cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { #![cfg(not(FALSE))] let my_val = true; } enum TupleEnum { - Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8) + Foo(#[cfg(false)] u8, #[cfg(false)] bool, #[cfg(not(FALSE))] i32, + #[cfg(false)] String, u8) } struct - TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, u8); fn plain_removed_fn() - { #![cfg_attr(not(FALSE), cfg(FALSE))] } 0 + TupleStruct(#[cfg(false)] String, #[cfg(not(FALSE))] i32, + #[cfg(false)] bool, u8); fn plain_removed_fn() + { #![cfg_attr(not(FALSE), cfg(false))] } 0 }], #[print_helper(d)] fourth: B } PRINT-ATTR RE-COLLECTED (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] -struct Foo <#[cfg(FALSE)] A, B > +struct Foo <#[cfg(false)] A, B > { - #[cfg(FALSE)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: + #[cfg(false)] first: String, #[cfg_attr(FALSE, deny(warnings))] second: bool, third: [u8; { - #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner; - #[cfg(FALSE)] let a = 25; match true + #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner; + #[cfg(false)] let a = 25; match true { - #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] + #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} }; #[print_helper(should_be_removed)] fn removed_fn() - { #![cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() + { #![cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { #![cfg(not(FALSE))] let my_val = true; } enum TupleEnum { - Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8) + Foo(#[cfg(false)] u8, #[cfg(false)] bool, #[cfg(not(FALSE))] i32, + #[cfg(false)] String, u8) } struct - TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, u8); fn plain_removed_fn() - { #![cfg_attr(not(FALSE), cfg(FALSE))] } 0 + TupleStruct(#[cfg(false)] String, #[cfg(not(FALSE))] i32, + #[cfg(false)] bool, u8); fn plain_removed_fn() + { #![cfg_attr(not(FALSE), cfg(false))] } 0 }], #[print_helper(d)] fourth: B } PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] -struct Foo <#[cfg(FALSE)] A, B > +struct Foo <#[cfg(false)] A, B > { - #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : + #[cfg(false)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : bool, third : [u8; { - #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner; - #[cfg(FALSE)] let a = 25; match true + #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner; + #[cfg(false)] let a = 25; match true { - #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] + #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} }; #[print_helper(should_be_removed)] fn removed_fn() - { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() + { #! [cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { #! [cfg(not(FALSE))] let my_val = true; } enum TupleEnum { - Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8) + Foo(#[cfg(false)] u8, #[cfg(false)] bool, #[cfg(not(FALSE))] i32, + #[cfg(false)] String, u8) } struct - TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, u8); fn plain_removed_fn() - { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0 + TupleStruct(#[cfg(false)] String, #[cfg(not(FALSE))] i32, + #[cfg(false)] bool, u8); fn plain_removed_fn() + { #! [cfg_attr(not(FALSE), cfg(false))] } 0 }], #[print_helper(d)] fourth : B } PRINT-ATTR INPUT (DEBUG): TokenStream [ @@ -200,7 +200,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:54:18: 54:23 (#0), }, ], @@ -246,7 +246,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:55:11: 55:16 (#0), }, ], @@ -375,7 +375,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:20 (#0), }, ], @@ -461,7 +461,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:20 (#0), }, ], @@ -521,7 +521,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:62:19: 62:24 (#0), }, ], @@ -721,7 +721,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:69:20: 69:25 (#0), }, ], @@ -908,7 +908,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:79:23: 79:28 (#0), }, ], @@ -942,7 +942,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:80:23: 80:28 (#0), }, ], @@ -1020,7 +1020,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:82:23: 82:28 (#0), }, ], @@ -1075,7 +1075,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:87:19: 87:24 (#0), }, ], @@ -1153,7 +1153,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:89:19: 89:24 (#0), }, ], @@ -1246,7 +1246,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "FALSE", + ident: "false", span: $DIR/issue-75930-derive-cfg.rs:94:41: 94:46 (#0), }, ], diff --git a/tests/ui/proc-macro/nested-derive-cfg.rs b/tests/ui/proc-macro/nested-derive-cfg.rs index bd8f231ac2c2..b3dcfb7c3966 100644 --- a/tests/ui/proc-macro/nested-derive-cfg.rs +++ b/tests/ui/proc-macro/nested-derive-cfg.rs @@ -10,10 +10,10 @@ extern crate test_macros; #[derive(Print)] struct Foo { - #[cfg(FALSE)] removed: bool, + #[cfg(false)] removed: bool, my_array: [bool; { struct Inner { - #[cfg(FALSE)] removed_inner_field: u8, + #[cfg(false)] removed_inner_field: u8, non_removed_inner_field: usize } 0 diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs index 110c03d0e549..983fe87451f2 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -64,7 +64,7 @@ fn _macros() { //~^ ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement match () { - #[cfg(FALSE)] + #[cfg(false)] () if let 0 = 1 => {} //~^ ERROR `if let` guards are experimental _ => {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs index f12824db9c00..0e71a9d24c97 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs @@ -3,7 +3,7 @@ #![feature(if_let_guard)] #![feature(let_chains)] -#[cfg(FALSE)] +#[cfg(false)] fn un_cfged() { match () { () if let 0 = 1 => {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs index 99f99c2be72d..0b0abe6ec175 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs @@ -340,12 +340,12 @@ fn outside_if_and_while_expr() { //~| ERROR expected expression, found `let` statement { - #[cfg(FALSE)] + #[cfg(false)] let x = true && let y = 1; //~^ ERROR expected expression, found `let` statement } - #[cfg(FALSE)] + #[cfg(false)] { [1, 2, 3][let _ = ()] //~^ ERROR expected expression, found `let` statement @@ -436,11 +436,11 @@ fn with_parenthesis() { //[no_feature]~^ ERROR `let` expressions in this position are unstable } - #[cfg(FALSE)] + #[cfg(false)] let x = (true && let y = 1); //~^ ERROR expected expression, found `let` statement - #[cfg(FALSE)] + #[cfg(false)] { ([1, 2, 3][let _ = ()]) //~^ ERROR expected expression, found `let` statement diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs index 2087fc42cf10..dad02b7f1063 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs @@ -51,7 +51,7 @@ fn _macros() { while $e {} } } - #[cfg(FALSE)] (let 0 = 1); + #[cfg(false)] (let 0 = 1); //~^ ERROR expected expression, found `let` statement use_expr!(let 0 = 1); //~^ ERROR no rules expected keyword `let` diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr index 7c874ae78a8a..b9dac472dca1 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr @@ -1,7 +1,7 @@ error: expected expression, found `let` statement --> $DIR/feature-gate.rs:54:20 | -LL | #[cfg(FALSE)] (let 0 = 1); +LL | #[cfg(false)] (let 0 = 1); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs index dce1c19ff339..ae525aed4148 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs @@ -3,12 +3,12 @@ fn main() { let _opt = Some(1i32); - #[cfg(FALSE)] + #[cfg(false)] { let _ = &&let Some(x) = Some(42); //~^ ERROR expected expression, found `let` statement } - #[cfg(FALSE)] + #[cfg(false)] { if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 { //~^ ERROR expected expression, found `let` statement @@ -18,7 +18,7 @@ fn main() { } } - #[cfg(FALSE)] + #[cfg(false)] { if let Some(elem) = _opt && { [1, 2, 3][let _ = ()]; @@ -28,7 +28,7 @@ fn main() { } } - #[cfg(FALSE)] + #[cfg(false)] { if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 { //~^ ERROR expected expression, found `let` statement @@ -36,7 +36,7 @@ fn main() { true } } - #[cfg(FALSE)] + #[cfg(false)] { if let a = 1 && { let x = let y = 1; diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs index eeb2191bab46..c0f17570673c 100644 --- a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs +++ b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs @@ -1,14 +1,14 @@ -#[cfg(FALSE)] +#[cfg(false)] impl S { fn f(#[attr]) {} //~ ERROR expected parameter name, found `)` } -#[cfg(FALSE)] +#[cfg(false)] impl T for S { fn f(#[attr]) {} //~ ERROR expected parameter name, found `)` } -#[cfg(FALSE)] +#[cfg(false)] trait T { fn f(#[attr]); //~ ERROR expected argument name, found `)` } diff --git a/tests/ui/specialization/issue-63716-parse-async.rs b/tests/ui/specialization/issue-63716-parse-async.rs index 3314b4e20f90..00c0b291a1ad 100644 --- a/tests/ui/specialization/issue-63716-parse-async.rs +++ b/tests/ui/specialization/issue-63716-parse-async.rs @@ -8,7 +8,7 @@ fn main() {} -#[cfg(FALSE)] +#[cfg(false)] impl Foo for Bar { default async fn baz() {} } diff --git a/tests/ui/suggestions/const-no-type.rs b/tests/ui/suggestions/const-no-type.rs index c6fdcdadbeaf..b72ace95213c 100644 --- a/tests/ui/suggestions/const-no-type.rs +++ b/tests/ui/suggestions/const-no-type.rs @@ -10,19 +10,19 @@ fn main() {} // These will not reach typeck: -#[cfg(FALSE)] +#[cfg(false)] const C2 = 42; //~^ ERROR missing type for `const` item //~| HELP provide a type for the item //~| SUGGESTION : -#[cfg(FALSE)] +#[cfg(false)] static S2 = "abc"; //~^ ERROR missing type for `static` item //~| HELP provide a type for the item //~| SUGGESTION : -#[cfg(FALSE)] +#[cfg(false)] static mut SM2 = "abc"; //~^ ERROR missing type for `static mut` item //~| HELP provide a type for the item diff --git a/tests/ui/suggestions/type-ascription-and-other-error.rs b/tests/ui/suggestions/type-ascription-and-other-error.rs index 99ab2f3c858b..da985b53aef6 100644 --- a/tests/ui/suggestions/type-ascription-and-other-error.rs +++ b/tests/ui/suggestions/type-ascription-and-other-error.rs @@ -1,6 +1,6 @@ fn main() { not rust; //~ ERROR let _ = 0: i32; // (error hidden by existing error) - #[cfg(FALSE)] + #[cfg(false)] let _ = 0: i32; // (warning hidden by existing error) } diff --git a/tests/ui/wasm/wasm-import-module.rs b/tests/ui/wasm/wasm-import-module.rs index bff08847d37d..2b3bca9a411b 100644 --- a/tests/ui/wasm/wasm-import-module.rs +++ b/tests/ui/wasm/wasm-import-module.rs @@ -15,7 +15,7 @@ extern "C" {} #[link(wasm_import_module = "foo", kind = "dylib")] //~ ERROR: `wasm_import_module` is incompatible with other arguments extern "C" {} -#[link(wasm_import_module = "foo", cfg(FALSE))] //~ ERROR: `wasm_import_module` is incompatible with other arguments +#[link(wasm_import_module = "foo", cfg(false))] //~ ERROR: `wasm_import_module` is incompatible with other arguments extern "C" {} fn main() {} diff --git a/tests/ui/wasm/wasm-import-module.stderr b/tests/ui/wasm/wasm-import-module.stderr index e792c33e91a9..84f437941a79 100644 --- a/tests/ui/wasm/wasm-import-module.stderr +++ b/tests/ui/wasm/wasm-import-module.stderr @@ -31,7 +31,7 @@ LL | #[link(wasm_import_module = "foo", kind = "dylib")] error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes --> $DIR/wasm-import-module.rs:18:8 | -LL | #[link(wasm_import_module = "foo", cfg(FALSE))] +LL | #[link(wasm_import_module = "foo", cfg(false))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors From 8b12153e3557318900675a0ab3fe1581ecf9d9e2 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 4 Apr 2025 16:41:40 +0000 Subject: [PATCH 017/222] Update windows-bindgen to 0.61.0 --- Cargo.lock | 6 +- .../std/src/sys/fs/windows/remove_dir_all.rs | 2 +- library/std/src/sys/pal/windows/c.rs | 4 +- .../std/src/sys/pal/windows/c/bindings.txt | 4 +- .../std/src/sys/pal/windows/c/windows_sys.rs | 303 ++++++++++++++++-- src/tools/generate-windows-sys/Cargo.toml | 2 +- 6 files changed, 290 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96526f7e9e7d..2ba12ea8030e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6066,11 +6066,13 @@ dependencies = [ [[package]] name = "windows-bindgen" -version = "0.59.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7fb600834d7e868f6e5bb748a86101427330fafbf9485c331b9d5f562d54a5" +checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90" dependencies = [ "rayon", + "serde", + "serde_json", ] [[package]] diff --git a/library/std/src/sys/fs/windows/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs index f51eced84164..b213c49bcb00 100644 --- a/library/std/src/sys/fs/windows/remove_dir_all.rs +++ b/library/std/src/sys/fs/windows/remove_dir_all.rs @@ -95,7 +95,7 @@ fn open_link_no_reparse( ObjectName: &mut path_str, RootDirectory: parent.as_raw_handle(), Attributes: ATTRIBUTES.load(Ordering::Relaxed), - ..c::OBJECT_ATTRIBUTES::default() + ..c::OBJECT_ATTRIBUTES::with_length() }; let share = c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE; let options = c::FILE_OPEN_REPARSE_POINT | options; diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 004cbee52f62..ac1c5e9932e1 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -44,8 +44,8 @@ impl UNICODE_STRING { } } -impl Default for OBJECT_ATTRIBUTES { - fn default() -> Self { +impl OBJECT_ATTRIBUTES { + pub fn with_length() -> Self { Self { Length: size_of::() as _, RootDirectory: ptr::null_mut(), diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index e2c216332796..d5fbb453c6f9 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -1,7 +1,8 @@ --out windows_sys.rs --flat --sys ---no-core +--no-deps +--link windows_targets --filter !INVALID_HANDLE_VALUE ABOVE_NORMAL_PRIORITY_CLASS @@ -19,7 +20,6 @@ ALL_PROCESSOR_GROUPS ARM64_NT_NEON128 BELOW_NORMAL_PRIORITY_CLASS bind -BOOL BY_HANDLE_FILE_INFORMATION CALLBACK_CHUNK_FINISHED CALLBACK_STREAM_SWITCH diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 1d0e89f5d0f0..eb2914b86447 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -1,4 +1,4 @@ -// Bindings generated by `windows-bindgen` 0.59.0 +// Bindings generated by `windows-bindgen` 0.61.0 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] @@ -141,7 +141,7 @@ windows_targets::link!("ws2_32.dll" "system" fn setsockopt(s : SOCKET, level : i windows_targets::link!("ws2_32.dll" "system" fn shutdown(s : SOCKET, how : WINSOCK_SHUTDOWN_HOW) -> i32); pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct ACL { pub AclRevision: u8, pub Sbz1: u8, @@ -162,6 +162,11 @@ pub struct ADDRINFOA { pub ai_addr: *mut SOCKADDR, pub ai_next: *mut ADDRINFOA, } +impl Default for ADDRINFOA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const AF_INET: ADDRESS_FAMILY = 2u16; pub const AF_INET6: ADDRESS_FAMILY = 23u16; pub const AF_UNIX: u16 = 1u16; @@ -176,8 +181,13 @@ pub union ARM64_NT_NEON128 { pub H: [u16; 8], pub B: [u8; 16], } +impl Default for ARM64_NT_NEON128 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct ARM64_NT_NEON128_0 { pub Low: u64, pub High: i64, @@ -185,7 +195,7 @@ pub struct ARM64_NT_NEON128_0 { pub const BELOW_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 16384u32; pub type BOOL = i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct BY_HANDLE_FILE_INFORMATION { pub dwFileAttributes: u32, pub ftCreationTime: FILETIME, @@ -206,9 +216,14 @@ pub type COMPARESTRING_RESULT = i32; pub struct CONDITION_VARIABLE { pub Ptr: *mut core::ffi::c_void, } +impl Default for CONDITION_VARIABLE { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type CONSOLE_MODE = u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct CONSOLE_READCONSOLE_CONTROL { pub nLength: u32, pub nInitialChars: u32, @@ -245,6 +260,12 @@ pub struct CONTEXT { pub SegSs: u32, pub ExtendedRegisters: [u8; 512], } +#[cfg(target_arch = "x86")] +impl Default for CONTEXT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -296,6 +317,12 @@ pub struct CONTEXT { pub LastExceptionToRip: u64, pub LastExceptionFromRip: u64, } +#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for CONTEXT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -303,6 +330,12 @@ pub union CONTEXT_0 { pub FltSave: XSAVE_FORMAT, pub Anonymous: CONTEXT_0_0, } +#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for CONTEXT_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -326,6 +359,12 @@ pub struct CONTEXT_0_0 { pub Xmm14: M128A, pub Xmm15: M128A, } +#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for CONTEXT_0_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "aarch64")] #[derive(Clone, Copy)] @@ -343,6 +382,12 @@ pub struct CONTEXT { pub Wcr: [u32; 2], pub Wvr: [u64; 2], } +#[cfg(target_arch = "aarch64")] +impl Default for CONTEXT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "aarch64")] #[derive(Clone, Copy)] @@ -350,9 +395,15 @@ pub union CONTEXT_0 { pub Anonymous: CONTEXT_0_0, pub X: [u64; 31], } +#[cfg(target_arch = "aarch64")] +impl Default for CONTEXT_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "aarch64")] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct CONTEXT_0_0 { pub X0: u64, pub X1: u64, @@ -2305,6 +2356,11 @@ pub struct EXCEPTION_POINTERS { pub ExceptionRecord: *mut EXCEPTION_RECORD, pub ContextRecord: *mut CONTEXT, } +impl Default for EXCEPTION_POINTERS { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct EXCEPTION_RECORD { @@ -2315,6 +2371,11 @@ pub struct EXCEPTION_RECORD { pub NumberParameters: u32, pub ExceptionInformation: [usize; 15], } +impl Default for EXCEPTION_RECORD { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _; pub const EXTENDED_STARTUPINFO_PRESENT: PROCESS_CREATION_FLAGS = 524288u32; pub const E_NOTIMPL: HRESULT = 0x80004001_u32 as _; @@ -2333,8 +2394,13 @@ pub struct FD_SET { pub fd_count: u32, pub fd_array: [SOCKET; 64], } +impl Default for FD_SET { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILETIME { pub dwLowDateTime: u32, pub dwHighDateTime: u32, @@ -2343,7 +2409,7 @@ pub type FILE_ACCESS_RIGHTS = u32; pub const FILE_ADD_FILE: FILE_ACCESS_RIGHTS = 2u32; pub const FILE_ADD_SUBDIRECTORY: FILE_ACCESS_RIGHTS = 4u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_ALLOCATION_INFO { pub AllocationSize: i64, } @@ -2369,7 +2435,7 @@ pub const FILE_ATTRIBUTE_REPARSE_POINT: FILE_FLAGS_AND_ATTRIBUTES = 1024u32; pub const FILE_ATTRIBUTE_SPARSE_FILE: FILE_FLAGS_AND_ATTRIBUTES = 512u32; pub const FILE_ATTRIBUTE_SYSTEM: FILE_FLAGS_AND_ATTRIBUTES = 4u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_ATTRIBUTE_TAG_INFO { pub FileAttributes: u32, pub ReparseTag: u32, @@ -2378,7 +2444,7 @@ pub const FILE_ATTRIBUTE_TEMPORARY: FILE_FLAGS_AND_ATTRIBUTES = 256u32; pub const FILE_ATTRIBUTE_UNPINNED: FILE_FLAGS_AND_ATTRIBUTES = 1048576u32; pub const FILE_ATTRIBUTE_VIRTUAL: FILE_FLAGS_AND_ATTRIBUTES = 65536u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_BASIC_INFO { pub CreationTime: i64, pub LastAccessTime: i64, @@ -2405,19 +2471,19 @@ pub const FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE: FILE_DISPOSITION_INFO pub const FILE_DISPOSITION_FLAG_ON_CLOSE: FILE_DISPOSITION_INFO_EX_FLAGS = 8u32; pub const FILE_DISPOSITION_FLAG_POSIX_SEMANTICS: FILE_DISPOSITION_INFO_EX_FLAGS = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_DISPOSITION_INFO { pub DeleteFile: bool, } #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_DISPOSITION_INFO_EX { pub Flags: FILE_DISPOSITION_INFO_EX_FLAGS, } pub type FILE_DISPOSITION_INFO_EX_FLAGS = u32; pub const FILE_END: SET_FILE_POINTER_MOVE_METHOD = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_END_OF_FILE_INFO { pub EndOfFile: i64, } @@ -2457,9 +2523,14 @@ pub struct FILE_ID_BOTH_DIR_INFO { pub FileId: i64, pub FileName: [u16; 1], } +impl Default for FILE_ID_BOTH_DIR_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type FILE_INFO_BY_HANDLE_CLASS = i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_IO_PRIORITY_HINT_INFO { pub PriorityHint: PRIORITY_HINT, } @@ -2494,12 +2565,22 @@ pub struct FILE_RENAME_INFO { pub FileNameLength: u32, pub FileName: [u16; 1], } +impl Default for FILE_RENAME_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union FILE_RENAME_INFO_0 { pub ReplaceIfExists: bool, pub Flags: u32, } +impl Default for FILE_RENAME_INFO_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const FILE_RESERVE_OPFILTER: NTCREATEFILE_CREATE_OPTIONS = 1048576u32; pub const FILE_SEQUENTIAL_ONLY: NTCREATEFILE_CREATE_OPTIONS = 4u32; pub const FILE_SESSION_AWARE: NTCREATEFILE_CREATE_OPTIONS = 262144u32; @@ -2509,7 +2590,7 @@ pub const FILE_SHARE_NONE: FILE_SHARE_MODE = 0u32; pub const FILE_SHARE_READ: FILE_SHARE_MODE = 1u32; pub const FILE_SHARE_WRITE: FILE_SHARE_MODE = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_STANDARD_INFO { pub AllocationSize: i64, pub EndOfFile: i64, @@ -2549,6 +2630,12 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Spare0: u32, } +#[cfg(target_arch = "x86")] +impl Default for FLOATING_SAVE_AREA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -2563,6 +2650,12 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Cr0NpxState: u32, } +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for FLOATING_SAVE_AREA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: FORMAT_MESSAGE_OPTIONS = 256u32; pub const FORMAT_MESSAGE_ARGUMENT_ARRAY: FORMAT_MESSAGE_OPTIONS = 8192u32; pub const FORMAT_MESSAGE_FROM_HMODULE: FORMAT_MESSAGE_OPTIONS = 2048u32; @@ -2639,12 +2732,22 @@ pub const IDLE_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 64u32; pub struct IN6_ADDR { pub u: IN6_ADDR_0, } +impl Default for IN6_ADDR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union IN6_ADDR_0 { pub Byte: [u8; 16], pub Word: [u16; 8], } +impl Default for IN6_ADDR_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const INFINITE: u32 = 4294967295u32; pub const INHERIT_CALLER_PRIORITY: PROCESS_CREATION_FLAGS = 131072u32; pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32; @@ -2653,6 +2756,11 @@ pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32; pub union INIT_ONCE { pub Ptr: *mut core::ffi::c_void, } +impl Default for INIT_ONCE { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const INIT_ONCE_INIT_FAILED: u32 = 4u32; pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32; pub const INVALID_SOCKET: SOCKET = -1i32 as _; @@ -2661,6 +2769,11 @@ pub const INVALID_SOCKET: SOCKET = -1i32 as _; pub struct IN_ADDR { pub S_un: IN_ADDR_0, } +impl Default for IN_ADDR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union IN_ADDR_0 { @@ -2668,8 +2781,13 @@ pub union IN_ADDR_0 { pub S_un_w: IN_ADDR_0_1, pub S_addr: u32, } +impl Default for IN_ADDR_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct IN_ADDR_0_0 { pub s_b1: u8, pub s_b2: u8, @@ -2677,7 +2795,7 @@ pub struct IN_ADDR_0_0 { pub s_b4: u8, } #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct IN_ADDR_0_1 { pub s_w1: u16, pub s_w2: u16, @@ -2690,12 +2808,22 @@ pub struct IO_STATUS_BLOCK { pub Anonymous: IO_STATUS_BLOCK_0, pub Information: usize, } +impl Default for IO_STATUS_BLOCK { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union IO_STATUS_BLOCK_0 { pub Status: NTSTATUS, pub Pointer: *mut core::ffi::c_void, } +impl Default for IO_STATUS_BLOCK_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type IPPROTO = i32; pub const IPPROTO_AH: IPPROTO = 51i32; pub const IPPROTO_CBT: IPPROTO = 7i32; @@ -2742,6 +2870,11 @@ pub struct IPV6_MREQ { pub ipv6mr_multiaddr: IN6_ADDR, pub ipv6mr_interface: u32, } +impl Default for IPV6_MREQ { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const IPV6_MULTICAST_LOOP: i32 = 11i32; pub const IPV6_V6ONLY: i32 = 27i32; pub const IP_ADD_MEMBERSHIP: i32 = 12i32; @@ -2752,11 +2885,16 @@ pub struct IP_MREQ { pub imr_multiaddr: IN_ADDR, pub imr_interface: IN_ADDR, } +impl Default for IP_MREQ { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const IP_MULTICAST_LOOP: i32 = 11i32; pub const IP_MULTICAST_TTL: i32 = 10i32; pub const IP_TTL: i32 = 4i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct LINGER { pub l_onoff: u16, pub l_linger: u16, @@ -2797,7 +2935,7 @@ pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = Option< ), >; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct M128A { pub Low: u64, pub High: i64, @@ -2838,6 +2976,11 @@ pub struct OBJECT_ATTRIBUTES { pub SecurityDescriptor: *const SECURITY_DESCRIPTOR, pub SecurityQualityOfService: *const SECURITY_QUALITY_OF_SERVICE, } +impl Default for OBJECT_ATTRIBUTES { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type OBJECT_ATTRIBUTE_FLAGS = u32; pub const OBJ_DONT_REPARSE: OBJECT_ATTRIBUTE_FLAGS = 4096u32; pub const OPEN_ALWAYS: FILE_CREATION_DISPOSITION = 4u32; @@ -2850,14 +2993,24 @@ pub struct OVERLAPPED { pub Anonymous: OVERLAPPED_0, pub hEvent: HANDLE, } +impl Default for OVERLAPPED { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union OVERLAPPED_0 { pub Anonymous: OVERLAPPED_0_0, pub Pointer: *mut core::ffi::c_void, } +impl Default for OVERLAPPED_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct OVERLAPPED_0_0 { pub Offset: u32, pub OffsetHigh: u32, @@ -2895,6 +3048,11 @@ pub struct PROCESS_INFORMATION { pub dwProcessId: u32, pub dwThreadId: u32, } +impl Default for PROCESS_INFORMATION { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const PROCESS_MODE_BACKGROUND_BEGIN: PROCESS_CREATION_FLAGS = 1048576u32; pub const PROCESS_MODE_BACKGROUND_END: PROCESS_CREATION_FLAGS = 2097152u32; pub const PROFILE_KERNEL: PROCESS_CREATION_FLAGS = 536870912u32; @@ -2926,6 +3084,11 @@ pub struct SECURITY_ATTRIBUTES { pub lpSecurityDescriptor: *mut core::ffi::c_void, pub bInheritHandle: BOOL, } +impl Default for SECURITY_ATTRIBUTES { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const SECURITY_CONTEXT_TRACKING: FILE_FLAGS_AND_ATTRIBUTES = 262144u32; pub const SECURITY_DELEGATION: FILE_FLAGS_AND_ATTRIBUTES = 196608u32; #[repr(C)] @@ -2939,13 +3102,18 @@ pub struct SECURITY_DESCRIPTOR { pub Sacl: *mut ACL, pub Dacl: *mut ACL, } +impl Default for SECURITY_DESCRIPTOR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type SECURITY_DESCRIPTOR_CONTROL = u16; pub const SECURITY_EFFECTIVE_ONLY: FILE_FLAGS_AND_ATTRIBUTES = 524288u32; pub const SECURITY_IDENTIFICATION: FILE_FLAGS_AND_ATTRIBUTES = 65536u32; pub const SECURITY_IMPERSONATION: FILE_FLAGS_AND_ATTRIBUTES = 131072u32; pub type SECURITY_IMPERSONATION_LEVEL = i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct SECURITY_QUALITY_OF_SERVICE { pub Length: u32, pub ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, @@ -2962,6 +3130,11 @@ pub struct SOCKADDR { pub sa_family: ADDRESS_FAMILY, pub sa_data: [i8; 14], } +impl Default for SOCKADDR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct SOCKADDR_STORAGE { @@ -2970,12 +3143,22 @@ pub struct SOCKADDR_STORAGE { pub __ss_align: i64, pub __ss_pad2: [i8; 112], } +impl Default for SOCKADDR_STORAGE { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct SOCKADDR_UN { pub sun_family: ADDRESS_FAMILY, pub sun_path: [i8; 108], } +impl Default for SOCKADDR_UN { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type SOCKET = usize; pub const SOCKET_ERROR: i32 = -1i32; pub const SOCK_DGRAM: WINSOCK_SOCKET_TYPE = 2i32; @@ -2995,6 +3178,11 @@ pub const SPECIFIC_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 65535u32; pub struct SRWLOCK { pub Ptr: *mut core::ffi::c_void, } +impl Default for SRWLOCK { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const STACK_SIZE_PARAM_IS_A_RESERVATION: THREAD_CREATION_FLAGS = 65536u32; pub const STANDARD_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 2031616u32; pub const STANDARD_RIGHTS_EXECUTE: FILE_ACCESS_RIGHTS = 131072u32; @@ -3021,6 +3209,11 @@ pub struct STARTUPINFOEXW { pub StartupInfo: STARTUPINFOW, pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, } +impl Default for STARTUPINFOEXW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct STARTUPINFOW { @@ -3043,6 +3236,11 @@ pub struct STARTUPINFOW { pub hStdOutput: HANDLE, pub hStdError: HANDLE, } +impl Default for STARTUPINFOW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type STARTUPINFOW_FLAGS = u32; pub const STATUS_DELETE_PENDING: NTSTATUS = 0xC0000056_u32 as _; pub const STATUS_DIRECTORY_NOT_EMPTY: NTSTATUS = 0xC0000101_u32 as _; @@ -3078,14 +3276,24 @@ pub struct SYSTEM_INFO { pub wProcessorLevel: u16, pub wProcessorRevision: u16, } +impl Default for SYSTEM_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union SYSTEM_INFO_0 { pub dwOemId: u32, pub Anonymous: SYSTEM_INFO_0_0, } +impl Default for SYSTEM_INFO_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct SYSTEM_INFO_0_0 { pub wProcessorArchitecture: PROCESSOR_ARCHITECTURE, pub wReserved: u16, @@ -3097,7 +3305,7 @@ pub type THREAD_CREATION_FLAGS = u32; pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32; pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct TIMEVAL { pub tv_sec: i32, pub tv_usec: i32, @@ -3134,6 +3342,11 @@ pub struct UNICODE_STRING { pub MaximumLength: u16, pub Buffer: PWSTR, } +impl Default for UNICODE_STRING { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const VOLUME_NAME_DOS: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const VOLUME_NAME_GUID: GETFINALPATHNAMEBYHANDLE_FLAGS = 1u32; pub const VOLUME_NAME_NONE: GETFINALPATHNAMEBYHANDLE_FLAGS = 4u32; @@ -3160,6 +3373,11 @@ pub struct WIN32_FIND_DATAW { pub cFileName: [u16; 260], pub cAlternateFileName: [u16; 14], } +impl Default for WIN32_FIND_DATAW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type WINSOCK_SHUTDOWN_HOW = i32; pub type WINSOCK_SOCKET_TYPE = i32; pub const WRITE_DAC: FILE_ACCESS_RIGHTS = 262144u32; @@ -3171,6 +3389,11 @@ pub struct WSABUF { pub len: u32, pub buf: PSTR, } +impl Default for WSABUF { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "x86")] #[derive(Clone, Copy)] @@ -3183,6 +3406,12 @@ pub struct WSADATA { pub iMaxUdpDg: u16, pub lpVendorInfo: PSTR, } +#[cfg(target_arch = "x86")] +impl Default for WSADATA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -3195,6 +3424,12 @@ pub struct WSADATA { pub szDescription: [i8; 257], pub szSystemStatus: [i8; 129], } +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for WSADATA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const WSAEACCES: WSA_ERROR = 10013i32; pub const WSAEADDRINUSE: WSA_ERROR = 10048i32; pub const WSAEADDRNOTAVAIL: WSA_ERROR = 10049i32; @@ -3255,6 +3490,11 @@ pub struct WSAPROTOCOLCHAIN { pub ChainLen: i32, pub ChainEntries: [u32; 7], } +impl Default for WSAPROTOCOLCHAIN { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct WSAPROTOCOL_INFOW { @@ -3279,6 +3519,11 @@ pub struct WSAPROTOCOL_INFOW { pub dwProviderReserved: u32, pub szProtocol: [u16; 256], } +impl Default for WSAPROTOCOL_INFOW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const WSASERVICE_NOT_FOUND: WSA_ERROR = 10108i32; pub const WSASYSCALLFAILURE: WSA_ERROR = 10107i32; pub const WSASYSNOTREADY: WSA_ERROR = 10091i32; @@ -3348,6 +3593,12 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 8], pub Reserved4: [u8; 224], } +#[cfg(target_arch = "x86")] +impl Default for XSAVE_FORMAT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -3369,6 +3620,12 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 16], pub Reserved4: [u8; 96], } +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for XSAVE_FORMAT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[cfg(target_arch = "arm")] #[repr(C)] diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml index f5c0e56bb3c2..152cd504abd1 100644 --- a/src/tools/generate-windows-sys/Cargo.toml +++ b/src/tools/generate-windows-sys/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies.windows-bindgen] -version = "0.59.0" +version = "0.61.0" From 6dfbe7c986d55a5a48f625d37d4576092e5638eb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 4 Apr 2025 21:36:03 +0000 Subject: [PATCH 018/222] Detect and provide suggestion for `&raw EXPR` --- compiler/rustc_ast/src/ast.rs | 11 ++ .../rustc_parse/src/parser/diagnostics.rs | 21 ++++ compiler/rustc_parse/src/parser/expr.rs | 12 ++ compiler/rustc_parse/src/parser/stmt.rs | 6 +- tests/ui/parser/recover/raw-no-const-mut.rs | 31 +++++ .../ui/parser/recover/raw-no-const-mut.stderr | 109 ++++++++++++++++++ 6 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 tests/ui/parser/recover/raw-no-const-mut.rs create mode 100644 tests/ui/parser/recover/raw-no-const-mut.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 33c20602dfd2..77b181974823 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -120,6 +120,17 @@ impl Path { Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None } } + pub fn is_ident(&self, name: Symbol) -> bool { + if let [segment] = self.segments.as_ref() + && segment.args.is_none() + && segment.ident.name == name + { + true + } else { + false + } + } + pub fn is_global(&self) -> bool { self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ef044fe9d638..2f026a77a0fb 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -609,6 +609,8 @@ impl<'a> Parser<'a> { // FIXME: translation requires list formatting (for `expect`) let mut err = self.dcx().struct_span_err(self.token.span, msg_exp); + self.label_expected_raw_ref(&mut err); + // Look for usages of '=>' where '>=' was probably intended if self.token == token::FatArrow && expected.iter().any(|tok| matches!(tok, TokenType::Operator | TokenType::Le)) @@ -750,6 +752,25 @@ impl<'a> Parser<'a> { Err(err) } + /// Adds a label when `&raw EXPR` was written instead of `&raw const EXPR`/`&raw mut EXPR`. + /// + /// Given that not all parser diagnostics flow through `expected_one_of_not_found`, this + /// label may need added to other diagnostics emission paths as needed. + pub(super) fn label_expected_raw_ref(&mut self, err: &mut Diag<'_>) { + if self.prev_token.is_keyword(kw::Raw) + && self.expected_token_types.contains(TokenType::KwMut) + && self.expected_token_types.contains(TokenType::KwConst) + && self.token.can_begin_expr() + { + err.span_suggestions( + self.prev_token.span.shrink_to_hi(), + "`&raw` must be followed by `const` or `mut` to be a raw reference expression", + [" const".to_string(), " mut".to_string()], + Applicability::MaybeIncorrect, + ); + } + } + /// Checks if the current token or the previous token are misspelled keywords /// and adds a helpful suggestion. fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e1e6b93abf35..8ae660cb780f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -829,6 +829,18 @@ impl<'a> Parser<'a> { if let Some(lt) = lifetime { self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span)); } + + // Add expected tokens if we parsed `&raw` as an expression. + // This will make sure we see "expected `const`, `mut`", and + // guides recovery in case we write `&raw expr`. + if borrow_kind == ast::BorrowKind::Ref + && mutbl == ast::Mutability::Not + && matches!(&expr.kind, ExprKind::Path(None, p) if p.is_ident(kw::Raw)) + { + self.expected_token_types.insert(TokenType::KwMut); + self.expected_token_types.insert(TokenType::KwConst); + } + Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr))) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 2cd09aa8959c..040de133c927 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -516,7 +516,11 @@ impl<'a> Parser<'a> { let prev = self.prev_token.span; let sp = self.token.span; let mut e = self.dcx().struct_span_err(sp, msg); - let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; + self.label_expected_raw_ref(&mut e); + + let do_not_suggest_help = self.token.is_keyword(kw::In) + || self.token == token::Colon + || self.prev_token.is_keyword(kw::Raw); // Check to see if the user has written something like // diff --git a/tests/ui/parser/recover/raw-no-const-mut.rs b/tests/ui/parser/recover/raw-no-const-mut.rs new file mode 100644 index 000000000000..d0ae69cc3084 --- /dev/null +++ b/tests/ui/parser/recover/raw-no-const-mut.rs @@ -0,0 +1,31 @@ +fn a() { + let x = &raw 1; + //~^ ERROR expected one of +} + +fn b() { + [&raw const 1, &raw 2] + //~^ ERROR expected one of + //~| ERROR cannot find value `raw` in this scope + //~| ERROR cannot take address of a temporary +} + +fn c() { + if x == &raw z {} + //~^ ERROR expected `{` +} + +fn d() { + f(&raw 2); + //~^ ERROR expected one of + //~| ERROR cannot find value `raw` in this scope + //~| ERROR cannot find function `f` in this scope +} + +fn e() { + let x; + x = &raw 1; + //~^ ERROR expected one of +} + +fn main() {} diff --git a/tests/ui/parser/recover/raw-no-const-mut.stderr b/tests/ui/parser/recover/raw-no-const-mut.stderr new file mode 100644 index 000000000000..65032c807953 --- /dev/null +++ b/tests/ui/parser/recover/raw-no-const-mut.stderr @@ -0,0 +1,109 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `const`, `else`, `mut`, `{`, or an operator, found `1` + --> $DIR/raw-no-const-mut.rs:2:18 + | +LL | let x = &raw 1; + | ^ expected one of 10 possible tokens + | +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | let x = &raw const 1; + | +++++ +LL | let x = &raw mut 1; + | +++ + +error: expected one of `!`, `,`, `.`, `::`, `?`, `]`, `const`, `mut`, `{`, or an operator, found `2` + --> $DIR/raw-no-const-mut.rs:7:25 + | +LL | [&raw const 1, &raw 2] + | ^ expected one of 10 possible tokens + | +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | [&raw const 1, &raw const 2] + | +++++ +LL | [&raw const 1, &raw mut 2] + | +++ +help: missing `,` + | +LL | [&raw const 1, &raw, 2] + | + + +error: expected `{`, found `z` + --> $DIR/raw-no-const-mut.rs:14:18 + | +LL | if x == &raw z {} + | ^ expected `{` + | +note: the `if` expression is missing a block after this condition + --> $DIR/raw-no-const-mut.rs:14:8 + | +LL | if x == &raw z {} + | ^^^^^^^^^ +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | if x == &raw const z {} + | +++++ +LL | if x == &raw mut z {} + | +++ + +error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `const`, `mut`, `{`, or an operator, found `2` + --> $DIR/raw-no-const-mut.rs:19:12 + | +LL | f(&raw 2); + | ^ expected one of 10 possible tokens + | +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | f(&raw const 2); + | +++++ +LL | f(&raw mut 2); + | +++ +help: missing `,` + | +LL | f(&raw, 2); + | + + +error: expected one of `!`, `.`, `::`, `;`, `?`, `const`, `mut`, `{`, `}`, or an operator, found `1` + --> $DIR/raw-no-const-mut.rs:27:14 + | +LL | x = &raw 1; + | ^ expected one of 10 possible tokens + | +help: `&raw` must be followed by `const` or `mut` to be a raw reference expression + | +LL | x = &raw const 1; + | +++++ +LL | x = &raw mut 1; + | +++ + +error[E0425]: cannot find value `raw` in this scope + --> $DIR/raw-no-const-mut.rs:7:21 + | +LL | [&raw const 1, &raw 2] + | ^^^ not found in this scope + +error[E0425]: cannot find value `raw` in this scope + --> $DIR/raw-no-const-mut.rs:19:8 + | +LL | f(&raw 2); + | ^^^ not found in this scope + +error[E0745]: cannot take address of a temporary + --> $DIR/raw-no-const-mut.rs:7:17 + | +LL | [&raw const 1, &raw 2] + | ^ temporary value + +error[E0425]: cannot find function `f` in this scope + --> $DIR/raw-no-const-mut.rs:19:5 + | +LL | fn a() { + | ------ similarly named function `a` defined here +... +LL | f(&raw 2); + | ^ help: a function with a similar name exists: `a` + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0425, E0745. +For more information about an error, try `rustc --explain E0425`. From 41fcdab3b5549ed93c87409bcf0b526a39d8b31c Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 3 Apr 2025 13:28:10 +0000 Subject: [PATCH 019/222] Switch `time` to `jiff` for time formatting in ICE dumps --- Cargo.lock | 54 +--------------------- compiler/rustc_driver_impl/Cargo.toml | 2 +- compiler/rustc_driver_impl/src/lib.rs | 13 ++---- src/bootstrap/src/utils/proc_macro_deps.rs | 2 - src/tools/tidy/src/deps.rs | 9 ++-- 5 files changed, 8 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96526f7e9e7d..3c96e195191c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -890,15 +890,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "deranged" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" -dependencies = [ - "powerfmt", -] - [[package]] name = "derive-where" version = "1.2.7" @@ -2385,12 +2376,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - [[package]] name = "num-integer" version = "0.1.46" @@ -2768,12 +2753,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" version = "0.2.21" @@ -3572,6 +3551,7 @@ name = "rustc_driver_impl" version = "0.0.0" dependencies = [ "ctrlc", + "jiff", "libc", "rustc_abi", "rustc_ast", @@ -3618,7 +3598,6 @@ dependencies = [ "rustc_ty_utils", "serde_json", "shlex", - "time", "tracing", "windows 0.59.0", ] @@ -5311,37 +5290,6 @@ dependencies = [ "libc", ] -[[package]] -name = "time" -version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" - -[[package]] -name = "time-macros" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinystr" version = "0.7.6" diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index de643355f5f4..c823d11126e2 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" edition = "2024" [dependencies] +jiff = { version = "0.2.5", default-features = false, features = ["std"] } # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } @@ -50,7 +51,6 @@ rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } serde_json = "1.0.59" shlex = "1.0" -time = { version = "0.3.36", default-features = false, features = ["alloc", "formatting", "macros"] } tracing = { version = "0.1.35" } # tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index f1dc4bb795e5..75478d9fdea3 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -30,7 +30,7 @@ use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; use std::sync::OnceLock; use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::{Instant, SystemTime}; +use std::time::Instant; use std::{env, str}; use rustc_ast as ast; @@ -66,8 +66,6 @@ use rustc_session::{EarlyDiagCtxt, Session, config, filesearch}; use rustc_span::FileName; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTuple}; -use time::OffsetDateTime; -use time::macros::format_description; use tracing::trace; #[allow(unused_macros)] @@ -1304,13 +1302,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option Date: Wed, 26 Mar 2025 00:38:28 -0700 Subject: [PATCH 020/222] std: Fix build for NuttX targets Fix std build for all NuttX targets. It is the single largest set of failures on . Although, ESP-IDF also requires these same gates, there are other issues for those targets. This can verified be running `x check library/std --target=` for all NuttX targets. --- library/std/src/sys/fd/unix.rs | 2 ++ library/std/src/sys/net/connection/socket/unix.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index 2042ea2c73d0..13fefb4031d0 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -71,9 +71,11 @@ const fn max_iov() -> usize { target_os = "android", target_os = "dragonfly", target_os = "emscripten", + target_os = "espidf", target_os = "freebsd", target_os = "linux", target_os = "netbsd", + target_os = "nuttx", target_os = "nto", target_os = "openbsd", target_os = "horizon", diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index bbe1e038dccf..b35d5d2aa841 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -1,5 +1,6 @@ use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t}; +#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; From 15e1a6676cdaac8442959990806d33a40949aaca Mon Sep 17 00:00:00 2001 From: Eduard Stefes Date: Mon, 31 Mar 2025 09:39:28 +0200 Subject: [PATCH 021/222] Use -C target-cpu=z13 on s390x vector test The default s390x cpu(z10) does not have vector support. Setting target-cpu at least to z13 enables vectorisation for s390x architecture and makes the tests pass. --- tests/codegen/dont-shuffle-bswaps.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/codegen/dont-shuffle-bswaps.rs b/tests/codegen/dont-shuffle-bswaps.rs index e100474f606f..c1dab2bc2953 100644 --- a/tests/codegen/dont-shuffle-bswaps.rs +++ b/tests/codegen/dont-shuffle-bswaps.rs @@ -1,8 +1,11 @@ -//@ revisions: OPT2 OPT3 +//@ revisions: OPT2 OPT3 OPT3_S390X //@[OPT2] compile-flags: -Copt-level=2 //@[OPT3] compile-flags: -C opt-level=3 // some targets don't do the opt we are looking for //@[OPT3] only-64bit +//@[OPT3] ignore-s390x +//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13 +//@[OPT3_S390X] only-s390x #![crate_type = "lib"] #![no_std] @@ -17,6 +20,10 @@ // OPT3-NEXT: call <8 x i16> @llvm.bswap // OPT3-NEXT: store <8 x i16> // OPT3-NEXT: ret void +// OPT3_S390X: load <8 x i16> +// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap +// OPT3_S390X-NEXT: store <8 x i16> +// OPT3_S390X-NEXT: ret void #[no_mangle] pub fn convert(value: [u16; 8]) -> [u8; 16] { #[cfg(target_endian = "little")] From b9754f9e7bfe2d8eed780962b550a25a87118ce4 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Tue, 25 Feb 2025 13:24:07 -0800 Subject: [PATCH 022/222] Enable contracts for const functions Use `const_eval_select!()` macro to enable contract checking only at runtime. The existing contract logic relies on closures, which are not supported in constant functions. This commit also removes one level of indirection for ensures clauses, however, it currently has a spurious warning message when the bottom of the function is unreachable. --- compiler/rustc_ast_lowering/src/expr.rs | 13 +++-- compiler/rustc_hir/src/lang_items.rs | 2 + .../rustc_hir_analysis/src/check/intrinsic.rs | 12 ++-- library/core/src/contracts.rs | 13 ++--- library/core/src/intrinsics/mod.rs | 47 ++++++++++++++-- library/core/src/lib.rs | 1 - .../contract-attributes-nest.chk_pass.stderr | 13 ++++- .../ui/contracts/contract-attributes-nest.rs | 1 + ...act-attributes-nest.unchk_fail_post.stderr | 13 ++++- ...ract-attributes-nest.unchk_fail_pre.stderr | 13 ++++- ...contract-attributes-nest.unchk_pass.stderr | 13 ++++- .../contract-const-fn.all_pass.stderr | 11 ++++ tests/ui/contracts/contract-const-fn.rs | 56 +++++++++++++++++++ ...contract-const-fn.runtime_fail_post.stderr | 11 ++++ .../contract-const-fn.runtime_fail_pre.stderr | 11 ++++ .../contract-ast-extensions-nest.rs | 1 + .../internal_machinery/contract-intrinsics.rs | 6 +- .../internal_machinery/contract-lang-items.rs | 4 +- 18 files changed, 206 insertions(+), 35 deletions(-) create mode 100644 tests/ui/contracts/contract-const-fn.all_pass.stderr create mode 100644 tests/ui/contracts/contract-const-fn.rs create mode 100644 tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr create mode 100644 tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 80bb1e8fc414..0b7a76304311 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -397,12 +397,17 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, expr: &'hir hir::Expr<'hir>, span: Span, - check_ident: Ident, - check_hir_id: HirId, + cond_ident: Ident, + cond_hir_id: HirId, ) -> &'hir hir::Expr<'hir> { - let checker_fn = self.expr_ident(span, check_ident, check_hir_id); + let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id); let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None); - self.expr_call(span, checker_fn, std::slice::from_ref(expr)) + let call_expr = self.expr_call_lang_item_fn_mut( + span, + hir::LangItem::ContractCheckEnsures, + arena_vec![self; *expr, *cond_fn], + ); + self.arena.alloc(call_expr) } pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 90fab01ba2d4..fd15d0543179 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -439,6 +439,8 @@ language_item_table! { DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None; DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None; DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None; + + ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None; } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 42d785c8dd0f..290e47b42b56 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -232,15 +232,11 @@ pub fn check_intrinsic_type( }; (n_tps, 0, 0, inputs, output, hir::Safety::Unsafe) } else if intrinsic_name == sym::contract_check_ensures { - // contract_check_ensures::<'a, Ret, C>(&'a Ret, C) - // where C: impl Fn(&'a Ret) -> bool, + // contract_check_ensures::(Ret, C) -> Ret + // where C: for<'a> Fn(&'a Ret) -> bool, // - // so: two type params, one lifetime param, 0 const params, two inputs, no return - - let p = generics.param_at(0, tcx); - let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data()); - let ref_ret = Ty::new_imm_ref(tcx, r, param(1)); - (2, 1, 0, vec![ref_ret, param(2)], tcx.types.unit, hir::Safety::Safe) + // so: two type params, 0 lifetime param, 0 const params, two inputs, no return + (2, 0, 0, vec![param(0), param(1)], param(0), hir::Safety::Safe) } else { let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); let (n_tps, n_cts, inputs, output) = match intrinsic_name { diff --git a/library/core/src/contracts.rs b/library/core/src/contracts.rs index 8b79a3a7eba8..829226420181 100644 --- a/library/core/src/contracts.rs +++ b/library/core/src/contracts.rs @@ -5,16 +5,15 @@ pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_require /// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }` /// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }` /// (including the implicit return of the tail expression, if any). +/// +/// This call helps with type inference for the predicate. #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] +#[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_build_check_ensures"] #[track_caller] -pub fn build_check_ensures(cond: C) -> impl (Fn(Ret) -> Ret) + Copy +pub const fn build_check_ensures(cond: C) -> C where - C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static, + C: Fn(&Ret) -> bool + Copy + 'static, { - #[track_caller] - move |ret| { - crate::intrinsics::contract_check_ensures(&ret, cond); - ret - } + cond } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 81e59a1f349e..8812cb66526b 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3450,20 +3450,55 @@ pub const fn contract_checks() -> bool { /// /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. -#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] +/// +/// Note that this function is a no-op during constant evaluation. +#[unstable(feature = "contracts_internals", issue = "128044")] +#[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_check_requires"] #[rustc_intrinsic] -pub fn contract_check_requires bool>(cond: C) { - if contract_checks() && !cond() { - // Emit no unwind panic in case this was a safety requirement. - crate::panicking::panic_nounwind("failed requires check"); - } +pub const fn contract_check_requires bool + Copy>(cond: C) { + const_eval_select!( + @capture[C: Fn() -> bool + Copy] { cond: C } : + if const { + // Do nothing + } else { + if contract_checks() && !cond() { + // Emit no unwind panic in case this was a safety requirement. + crate::panicking::panic_nounwind("failed requires check"); + } + } + ) } /// Check if the post-condition `cond` has been met. /// /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. +/// +/// Note that this function is a no-op during constant evaluation. +#[cfg(not(bootstrap))] +#[unstable(feature = "contracts_internals", issue = "128044")] +#[rustc_const_unstable(feature = "contracts", issue = "128044")] +#[lang = "contract_check_ensures"] +#[rustc_intrinsic] +pub const fn contract_check_ensures bool + Copy>(ret: Ret, cond: C) -> Ret { + const_eval_select!( + @capture[Ret, C: Fn(&Ret) -> bool + Copy] { ret: Ret, cond: C } -> Ret : + if const { + // Do nothing + ret + } else { + if contract_checks() && !cond(&ret) { + // Emit no unwind panic in case this was a safety requirement. + crate::panicking::panic_nounwind("failed ensures check"); + } + ret + } + ) +} + +/// This is the old version of contract_check_ensures kept here for bootstrap only. +#[cfg(bootstrap)] #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[rustc_intrinsic] pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index dc06aa4c38d5..8c68e57897cb 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -101,7 +101,6 @@ #![feature(bstr)] #![feature(bstr_internals)] #![feature(cfg_match)] -#![feature(closure_track_caller)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(core_intrinsics)] diff --git a/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr b/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr index 9ca95b8bb01a..e7c42ad98a57 100644 --- a/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr +++ b/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr @@ -7,5 +7,16 @@ LL | #![feature(contracts)] = note: see issue #128044 for more information = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +warning: unreachable expression + --> $DIR/contract-attributes-nest.rs:23:1 + | +LL | #[core::contracts::ensures(|ret| *ret > 100)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression +... +LL | return x.baz + 50; + | ----------------- any code following this expression is unreachable + | + = note: `#[warn(unreachable_code)]` on by default + +warning: 2 warnings emitted diff --git a/tests/ui/contracts/contract-attributes-nest.rs b/tests/ui/contracts/contract-attributes-nest.rs index e1e61b88f282..7c35e54c18bc 100644 --- a/tests/ui/contracts/contract-attributes-nest.rs +++ b/tests/ui/contracts/contract-attributes-nest.rs @@ -21,6 +21,7 @@ #[core::contracts::requires(x.baz > 0)] #[core::contracts::ensures(|ret| *ret > 100)] +//~^ WARN unreachable expression [unreachable_code] fn nest(x: Baz) -> i32 { loop { diff --git a/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr b/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr index 9ca95b8bb01a..e7c42ad98a57 100644 --- a/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr +++ b/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr @@ -7,5 +7,16 @@ LL | #![feature(contracts)] = note: see issue #128044 for more information = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +warning: unreachable expression + --> $DIR/contract-attributes-nest.rs:23:1 + | +LL | #[core::contracts::ensures(|ret| *ret > 100)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression +... +LL | return x.baz + 50; + | ----------------- any code following this expression is unreachable + | + = note: `#[warn(unreachable_code)]` on by default + +warning: 2 warnings emitted diff --git a/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr b/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr index 9ca95b8bb01a..e7c42ad98a57 100644 --- a/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr +++ b/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr @@ -7,5 +7,16 @@ LL | #![feature(contracts)] = note: see issue #128044 for more information = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +warning: unreachable expression + --> $DIR/contract-attributes-nest.rs:23:1 + | +LL | #[core::contracts::ensures(|ret| *ret > 100)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression +... +LL | return x.baz + 50; + | ----------------- any code following this expression is unreachable + | + = note: `#[warn(unreachable_code)]` on by default + +warning: 2 warnings emitted diff --git a/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr b/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr index 9ca95b8bb01a..e7c42ad98a57 100644 --- a/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr +++ b/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr @@ -7,5 +7,16 @@ LL | #![feature(contracts)] = note: see issue #128044 for more information = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +warning: unreachable expression + --> $DIR/contract-attributes-nest.rs:23:1 + | +LL | #[core::contracts::ensures(|ret| *ret > 100)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression +... +LL | return x.baz + 50; + | ----------------- any code following this expression is unreachable + | + = note: `#[warn(unreachable_code)]` on by default + +warning: 2 warnings emitted diff --git a/tests/ui/contracts/contract-const-fn.all_pass.stderr b/tests/ui/contracts/contract-const-fn.all_pass.stderr new file mode 100644 index 000000000000..e5b1df655823 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.all_pass.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contract-const-fn.rs:17:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/contract-const-fn.rs b/tests/ui/contracts/contract-const-fn.rs new file mode 100644 index 000000000000..733a06ae5709 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.rs @@ -0,0 +1,56 @@ +//! Check if we can annotate a constant function with contracts. +//! +//! The contract is only checked at runtime, and it will not fail if evaluated statically. +//! This is an existing limitation due to the existing architecture and the lack of constant +//! closures. +//! +//@ revisions: all_pass runtime_fail_pre runtime_fail_post +// +//@ [all_pass] run-pass +// +//@ [runtime_fail_pre] run-fail +//@ [runtime_fail_post] run-fail +// +//@ [all_pass] compile-flags: -Zcontract-checks=yes +//@ [runtime_fail_pre] compile-flags: -Zcontract-checks=yes +//@ [runtime_fail_post] compile-flags: -Zcontract-checks=yes +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; +use core::contracts::*; + +#[requires(x < 100)] +const fn less_than_100(x: u8) -> u8 { + x +} + +// This is wrong on purpose. +#[ensures(|ret| *ret)] +const fn always_true(b: bool) -> bool { + b +} + +const ZERO: u8 = less_than_100(0); +// This is no-op because the contract cannot be checked at compilation time. +const TWO_HUNDRED: u8 = less_than_100(200); + +/// Example from . +#[ensures(move |ret: &u32| *ret > x)] +const fn broken_sum(x: u32, y: u32) -> u32 { + x + y +} + +fn main() { + assert_eq!(ZERO, 0); + assert_eq!(TWO_HUNDRED, 200); + assert_eq!(broken_sum(0, 1), 1); + assert_eq!(always_true(true), true); + + #[cfg(runtime_fail_post)] + let _ok = always_true(false); + + // Runtime check should fail. + #[cfg(runtime_fail_pre)] + let _200 = less_than_100(200); +} diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr new file mode 100644 index 000000000000..e5b1df655823 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contract-const-fn.rs:17:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr new file mode 100644 index 000000000000..e5b1df655823 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contract-const-fn.rs:17:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs index 6d8cd3949eed..7f9c3fe28cef 100644 --- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs +++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs @@ -21,6 +21,7 @@ fn nest(x: Baz) -> i32 contract_requires(|| x.baz > 0) contract_ensures(|ret| *ret > 100) + //~^ WARN unreachable expression [unreachable_code] { loop { return x.baz + 50; diff --git a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs index ae692afd146f..f94dfbde75fb 100644 --- a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs +++ b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs @@ -26,11 +26,11 @@ fn main() { #[cfg(any(default, unchk_pass, chk_fail_requires))] core::intrinsics::contract_check_requires(|| false); - let doubles_to_two = { let old = 2; move |ret| ret + ret == old }; + let doubles_to_two = { let old = 2; move |ret: &u32 | ret + ret == old }; // Always pass - core::intrinsics::contract_check_ensures(&1, doubles_to_two); + core::intrinsics::contract_check_ensures(1, doubles_to_two); // Fail if enabled #[cfg(any(default, unchk_pass, chk_fail_ensures))] - core::intrinsics::contract_check_ensures(&2, doubles_to_two); + core::intrinsics::contract_check_ensures(2, doubles_to_two); } diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs index e91bbed294d1..26042cf688fd 100644 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs +++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs @@ -15,14 +15,14 @@ #![feature(contracts)] // to access core::contracts //~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #![feature(contracts_internals)] // to access check_requires lang item - +#![feature(core_intrinsics)] fn foo(x: Baz) -> i32 { let injected_checker = { core::contracts::build_check_ensures(|ret| *ret > 100) }; let ret = x.baz + 50; - injected_checker(ret) + core::intrinsics::contract_check_ensures(ret, injected_checker) } struct Baz { baz: i32 } From 8866af388497e9ed3254147c015379d5d6cdb054 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 26 Mar 2025 19:44:53 +0100 Subject: [PATCH 023/222] Add `naked_functions_rustic_abi` feature gate --- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_lint/src/lib.rs | 5 +++ compiler/rustc_lint_defs/src/builtin.rs | 34 ------------------- compiler/rustc_passes/messages.ftl | 3 -- compiler/rustc_passes/src/check_attr.rs | 15 ++++++++ compiler/rustc_passes/src/errors.rs | 4 --- compiler/rustc_passes/src/naked_functions.rs | 33 ++++-------------- compiler/rustc_span/src/symbol.rs | 1 + tests/ui/asm/naked-functions-rustic-abi.rs | 27 +++++++++++++++ tests/ui/asm/naked-functions-testattrs.rs | 9 +++-- tests/ui/asm/naked-functions-testattrs.stderr | 8 ++--- tests/ui/asm/naked-functions.rs | 12 ------- tests/ui/asm/naked-functions.stderr | 22 +++--------- ...feature-gate-naked_functions_rustic_abi.rs | 26 ++++++++++++++ ...ure-gate-naked_functions_rustic_abi.stderr | 33 ++++++++++++++++++ .../undefined_naked_function_abi.rs | 5 +++ .../undefined_naked_function_abi.stderr | 10 ++++++ 17 files changed, 142 insertions(+), 107 deletions(-) create mode 100644 tests/ui/asm/naked-functions-rustic-abi.rs create mode 100644 tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs create mode 100644 tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr create mode 100644 tests/ui/lint/removed-lints/undefined_naked_function_abi.rs create mode 100644 tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 72468dd4714d..e0af871d3fd4 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -566,6 +566,8 @@ declare_features! ( (incomplete, mut_ref, "1.79.0", Some(123076)), /// Allows using `#[naked]` on functions. (unstable, naked_functions, "1.9.0", Some(90957)), + /// Allows using `#[naked]` on `extern "Rust"` functions. + (unstable, naked_functions_rustic_abi, "CURRENT_RUSTC_VERSION", Some(138997)), /// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions. (unstable, naked_functions_target_feature, "1.86.0", Some(138568)), /// Allows specifying the as-needed link modifier diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c38a75400181..1863ba8f8fb6 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -604,6 +604,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see issue #127323 \ for more information", ); + store.register_removed( + "undefined_naked_function_abi", + "converted into hard error, see PR #139001 \ + for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8a761a0a0969..b25d2a30681c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -110,7 +110,6 @@ declare_lint_pass! { UNCONDITIONAL_PANIC, UNCONDITIONAL_RECURSION, UNCOVERED_PARAM_IN_PROJECTION, - UNDEFINED_NAKED_FUNCTION_ABI, UNEXPECTED_CFGS, UNFULFILLED_LINT_EXPECTATIONS, UNINHABITED_STATIC, @@ -2830,39 +2829,6 @@ declare_lint! { "detects deprecation attributes with no effect", } -declare_lint! { - /// The `undefined_naked_function_abi` lint detects naked function definitions that - /// either do not specify an ABI or specify the Rust ABI. - /// - /// ### Example - /// - /// ```rust - /// #![feature(asm_experimental_arch, naked_functions)] - /// - /// use std::arch::naked_asm; - /// - /// #[naked] - /// pub fn default_abi() -> u32 { - /// unsafe { naked_asm!(""); } - /// } - /// - /// #[naked] - /// pub extern "Rust" fn rust_abi() -> u32 { - /// unsafe { naked_asm!(""); } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The Rust ABI is currently undefined. Therefore, naked functions should - /// specify a non-Rust ABI. - pub UNDEFINED_NAKED_FUNCTION_ABI, - Warn, - "undefined naked function ABI" -} - declare_lint! { /// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used. /// diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 06398dd4f725..18cbbad92b6c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -738,9 +738,6 @@ passes_trait_impl_const_stable = passes_transparent_incompatible = transparent {$target} cannot have other repr hints -passes_undefined_naked_function_abi = - Rust ABI is unsupported in naked functions - passes_unknown_external_lang_item = unknown external lang item: `{$lang_item}` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9238c73cdb11..50ce20641293 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -607,6 +607,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { + let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); + let abi = fn_sig.header.abi; + if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() { + feature_err( + &self.tcx.sess, + sym::naked_functions_rustic_abi, + fn_sig.span, + format!( + "`#[naked]` is currently unstable on `extern \"{}\"` functions", + abi.as_str() + ), + ) + .emit(); + } + for other_attr in attrs { // this covers "sugared doc comments" of the form `/// ...` // it does not cover `#[doc = "..."]`, which is handled below diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 0ee17430aab8..536cb96bf466 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1197,10 +1197,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> { pub cf_type: &'a str, } -#[derive(LintDiagnostic)] -#[diag(passes_undefined_naked_function_abi)] -pub(crate) struct UndefinedNakedFunctionAbi; - #[derive(Diagnostic)] #[diag(passes_no_patterns)] pub(crate) struct NoPatterns { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index d35aedf9a564..3c9f8b72c363 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,6 +1,5 @@ //! Checks validity of naked functions. -use rustc_abi::ExternAbi; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; @@ -10,12 +9,11 @@ use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; use rustc_span::{Span, sym}; use crate::errors::{ NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, - ParamsNotAllowed, UndefinedNakedFunctionAbi, + ParamsNotAllowed, }; pub(crate) fn provide(providers: &mut Providers) { @@ -29,26 +27,21 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { continue; } - let (fn_header, body_id) = match tcx.hir_node_by_def_id(def_id) { + let body = match tcx.hir_node_by_def_id(def_id) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn { sig, body: body_id, .. }, - .. + kind: hir::ItemKind::Fn { body: body_id, .. }, .. }) | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), + kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)), .. }) | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(sig, body_id), - .. - }) => (sig.header, *body_id), + kind: hir::ImplItemKind::Fn(_, body_id), .. + }) => tcx.hir_body(*body_id), _ => continue, }; - let body = tcx.hir_body(body_id); - if tcx.has_attr(def_id, sym::naked) { - check_abi(tcx, def_id, fn_header.abi); check_no_patterns(tcx, body.params); check_no_parameters_use(tcx, body); check_asm(tcx, def_id, body); @@ -60,20 +53,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { } } -/// Checks that function uses non-Rust ABI. -fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: ExternAbi) { - if abi == ExternAbi::Rust { - let hir_id = tcx.local_def_id_to_hir_id(def_id); - let span = tcx.def_span(def_id); - tcx.emit_node_span_lint( - UNDEFINED_NAKED_FUNCTION_ABI, - hir_id, - span, - UndefinedNakedFunctionAbi, - ); - } -} - /// Checks that parameters don't use patterns. Mirrors the checks for function declarations. fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { for param in params { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3e4742439655..5906b242dda6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1387,6 +1387,7 @@ symbols! { naked, naked_asm, naked_functions, + naked_functions_rustic_abi, naked_functions_target_feature, name, names, diff --git a/tests/ui/asm/naked-functions-rustic-abi.rs b/tests/ui/asm/naked-functions-rustic-abi.rs new file mode 100644 index 000000000000..b654d38ccc1a --- /dev/null +++ b/tests/ui/asm/naked-functions-rustic-abi.rs @@ -0,0 +1,27 @@ +//@ revisions: x86_64 aarch64 +// +//@[aarch64] only-aarch64 +//@[x86_64] only-x86_64 +// +//@ build-pass +//@ needs-asm-support + +#![feature(naked_functions, naked_functions_rustic_abi, rust_cold_cc)] +#![crate_type = "lib"] + +use std::arch::{asm, naked_asm}; + +#[naked] +pub unsafe fn rust_implicit() { + naked_asm!("ret"); +} + +#[naked] +pub unsafe extern "Rust" fn rust_explicit() { + naked_asm!("ret"); +} + +#[naked] +pub unsafe extern "rust-cold" fn rust_cold() { + naked_asm!("ret"); +} diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs index 7e373270e9fc..ad31876a77a5 100644 --- a/tests/ui/asm/naked-functions-testattrs.rs +++ b/tests/ui/asm/naked-functions-testattrs.rs @@ -1,7 +1,6 @@ //@ needs-asm-support //@ compile-flags: --test -#![allow(undefined_naked_function_abi)] #![feature(naked_functions)] #![feature(test)] #![crate_type = "lib"] @@ -11,7 +10,7 @@ use std::arch::naked_asm; #[test] #[naked] //~^ ERROR [E0736] -fn test_naked() { +extern "C" fn test_naked() { unsafe { naked_asm!("") }; } @@ -19,7 +18,7 @@ fn test_naked() { #[test] #[naked] //~^ ERROR [E0736] -fn test_naked_should_panic() { +extern "C" fn test_naked_should_panic() { unsafe { naked_asm!("") }; } @@ -27,13 +26,13 @@ fn test_naked_should_panic() { #[test] #[naked] //~^ ERROR [E0736] -fn test_naked_ignore() { +extern "C" fn test_naked_ignore() { unsafe { naked_asm!("") }; } #[bench] #[naked] //~^ ERROR [E0736] -fn bench_naked() { +extern "C" fn bench_naked() { unsafe { naked_asm!("") }; } diff --git a/tests/ui/asm/naked-functions-testattrs.stderr b/tests/ui/asm/naked-functions-testattrs.stderr index 4dabe41964a5..0f0bb91b9541 100644 --- a/tests/ui/asm/naked-functions-testattrs.stderr +++ b/tests/ui/asm/naked-functions-testattrs.stderr @@ -1,5 +1,5 @@ error[E0736]: cannot use `#[naked]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:12:1 + --> $DIR/naked-functions-testattrs.rs:11:1 | LL | #[test] | ------- function marked with testing attribute here @@ -7,7 +7,7 @@ LL | #[naked] | ^^^^^^^^ `#[naked]` is incompatible with testing attributes error[E0736]: cannot use `#[naked]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:20:1 + --> $DIR/naked-functions-testattrs.rs:19:1 | LL | #[test] | ------- function marked with testing attribute here @@ -15,7 +15,7 @@ LL | #[naked] | ^^^^^^^^ `#[naked]` is incompatible with testing attributes error[E0736]: cannot use `#[naked]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:28:1 + --> $DIR/naked-functions-testattrs.rs:27:1 | LL | #[test] | ------- function marked with testing attribute here @@ -23,7 +23,7 @@ LL | #[naked] | ^^^^^^^^ `#[naked]` is incompatible with testing attributes error[E0736]: cannot use `#[naked]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:35:1 + --> $DIR/naked-functions-testattrs.rs:34:1 | LL | #[bench] | -------- function marked with testing attribute here diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 3d4d414539c1..5bf2e2a3abd0 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -122,18 +122,6 @@ unsafe extern "C" fn invalid_may_unwind() { //~^ ERROR the `may_unwind` option cannot be used with `naked_asm!` } -#[naked] -pub unsafe fn default_abi() { - //~^ WARN Rust ABI is unsupported in naked functions - naked_asm!(""); -} - -#[naked] -pub unsafe fn rust_abi() { - //~^ WARN Rust ABI is unsupported in naked functions - naked_asm!(""); -} - #[naked] pub extern "C" fn valid_a() -> T { unsafe { diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 0898f3620f24..0a55bb9cd837 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -53,19 +53,19 @@ LL | naked_asm!("", options(may_unwind)); | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly error: this is a user specified error - --> $DIR/naked-functions.rs:169:5 + --> $DIR/naked-functions.rs:157:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:175:5 + --> $DIR/naked-functions.rs:163:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:182:16 + --> $DIR/naked-functions.rs:170:16 | LL | naked_asm!(invalid_syntax) | ^^^^^^^^^^^^^^ @@ -175,20 +175,6 @@ LL | LL | *&y | --- not allowed in naked functions -warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:126:1 - | -LL | pub unsafe fn default_abi() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(undefined_naked_function_abi)]` on by default - -warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:132:1 - | -LL | pub unsafe fn rust_abi() { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 25 previous errors; 2 warnings emitted +error: aborting due to 25 previous errors For more information about this error, try `rustc --explain E0787`. diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs new file mode 100644 index 000000000000..c91d83399441 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs @@ -0,0 +1,26 @@ +//@ needs-asm-support +//@ only-x86_64 + +#![feature(naked_functions, rust_cold_cc)] + +use std::arch::naked_asm; + +#[naked] +pub unsafe fn rust_implicit() { + //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions + naked_asm!("ret"); +} + +#[naked] +pub unsafe extern "Rust" fn rust_explicit() { + //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions + naked_asm!("ret"); +} + +#[naked] +pub unsafe extern "rust-cold" fn rust_cold() { + //~^ ERROR `#[naked]` is currently unstable on `extern "rust-cold"` functions + naked_asm!("ret"); +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr new file mode 100644 index 000000000000..ba45e15ec86b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr @@ -0,0 +1,33 @@ +error[E0658]: `#[naked]` is currently unstable on `extern "Rust"` functions + --> $DIR/feature-gate-naked_functions_rustic_abi.rs:9:1 + | +LL | pub unsafe fn rust_implicit() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #138997 for more information + = help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[naked]` is currently unstable on `extern "Rust"` functions + --> $DIR/feature-gate-naked_functions_rustic_abi.rs:15:1 + | +LL | pub unsafe extern "Rust" fn rust_explicit() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #138997 for more information + = help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[naked]` is currently unstable on `extern "rust-cold"` functions + --> $DIR/feature-gate-naked_functions_rustic_abi.rs:21:1 + | +LL | pub unsafe extern "rust-cold" fn rust_cold() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #138997 for more information + = help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/removed-lints/undefined_naked_function_abi.rs b/tests/ui/lint/removed-lints/undefined_naked_function_abi.rs new file mode 100644 index 000000000000..cf3ac66ac86d --- /dev/null +++ b/tests/ui/lint/removed-lints/undefined_naked_function_abi.rs @@ -0,0 +1,5 @@ +//@ check-pass + +#![deny(undefined_naked_function_abi)] +//~^ WARN lint `undefined_naked_function_abi` has been removed +fn main() {} diff --git a/tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr b/tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr new file mode 100644 index 000000000000..5a546688beb5 --- /dev/null +++ b/tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr @@ -0,0 +1,10 @@ +warning: lint `undefined_naked_function_abi` has been removed: converted into hard error, see PR #139001 for more information + --> $DIR/undefined_naked_function_abi.rs:3:9 + | +LL | #![deny(undefined_naked_function_abi)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(renamed_and_removed_lints)]` on by default + +warning: 1 warning emitted + From 44d1d86124e7229a59a13899a14e468fee9dc923 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 8 Apr 2025 13:26:22 +1000 Subject: [PATCH 024/222] libtest: Pass the test's panic payload as Option instead of Result Passing a `Result<(), &dyn Any>` to `calc_result` requires awkward code at both call sites, for no real benefit. It's much easier to just pass the payload as `Option<&dyn Any>`. No functional change, except that the owned payload is dropped slightly later. --- library/test/src/lib.rs | 14 ++++++-------- library/test/src/test_result.rs | 21 ++++++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 7ada3f269a00..acaf026c679b 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -666,10 +666,11 @@ fn run_test_in_process( io::set_output_capture(None); - let test_result = match result { - Ok(()) => calc_result(&desc, Ok(()), time_opts.as_ref(), exec_time.as_ref()), - Err(e) => calc_result(&desc, Err(e.as_ref()), time_opts.as_ref(), exec_time.as_ref()), - }; + // Determine whether the test passed or failed, by comparing its panic + // payload (if any) with its `ShouldPanic` value, and by checking for + // fatal timeout. + let test_result = + calc_result(&desc, result.err().as_deref(), time_opts.as_ref(), exec_time.as_ref()); let stdout = data.lock().unwrap_or_else(|e| e.into_inner()).to_vec(); let message = CompletedTest::new(id, desc, test_result, exec_time, stdout); monitor_ch.send(message).unwrap(); @@ -741,10 +742,7 @@ fn spawn_test_subprocess( fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) -> ! { let builtin_panic_hook = panic::take_hook(); let record_result = Arc::new(move |panic_info: Option<&'_ PanicHookInfo<'_>>| { - let test_result = match panic_info { - Some(info) => calc_result(&desc, Err(info.payload()), None, None), - None => calc_result(&desc, Ok(()), None, None), - }; + let test_result = calc_result(&desc, panic_info.map(|info| info.payload()), None, None); // We don't support serializing TrFailedMsg, so just // print the message out to stderr. diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index 73dcc2e2a0cc..959cd730fa43 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -39,15 +39,18 @@ pub enum TestResult { /// Creates a `TestResult` depending on the raw result of test execution /// and associated data. -pub(crate) fn calc_result<'a>( +pub(crate) fn calc_result( desc: &TestDesc, - task_result: Result<(), &'a (dyn Any + 'static + Send)>, + panic_payload: Option<&(dyn Any + Send)>, time_opts: Option<&time::TestTimeOptions>, exec_time: Option<&time::TestExecTime>, ) -> TestResult { - let result = match (&desc.should_panic, task_result) { - (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk, - (&ShouldPanic::YesWithMessage(msg), Err(err)) => { + let result = match (desc.should_panic, panic_payload) { + // The test did or didn't panic, as expected. + (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestResult::TrOk, + + // Check the actual panic message against the expected message. + (ShouldPanic::YesWithMessage(msg), Some(err)) => { let maybe_panic_str = err .downcast_ref::() .map(|e| &**e) @@ -71,10 +74,14 @@ pub(crate) fn calc_result<'a>( )) } } - (&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => { + + // The test should have panicked, but didn't panic. + (ShouldPanic::Yes, None) | (ShouldPanic::YesWithMessage(_), None) => { TestResult::TrFailedMsg("test did not panic as expected".to_string()) } - _ => TestResult::TrFailed, + + // The test should not have panicked, but did panic. + (ShouldPanic::No, Some(_)) => TestResult::TrFailed, }; // If test is already failed (or allowed to fail), do not change the result. From 3feac59b794acf326c0efebaabd500e47fc65ba9 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Mon, 7 Apr 2025 17:42:08 -0700 Subject: [PATCH 025/222] Fix unreachable expression warning Invert the order that we pass the arguments to the `contract_check_ensures` function to avoid the warning when the tail of the function is unreachable. Note that the call itself is also unreachable, but we have already handled that case by ignoring unreachable call for contract calls. --- compiler/rustc_ast_lowering/src/expr.rs | 3 +-- compiler/rustc_ast_lowering/src/item.rs | 9 ++++++++- .../rustc_hir_analysis/src/check/intrinsic.rs | 2 +- library/core/src/contracts.rs | 15 ++++++++++----- library/core/src/intrinsics/mod.rs | 11 +++++++++-- .../contract-attributes-nest.chk_pass.stderr | 13 +------------ tests/ui/contracts/contract-attributes-nest.rs | 1 - ...ontract-attributes-nest.unchk_fail_post.stderr | 13 +------------ ...contract-attributes-nest.unchk_fail_pre.stderr | 13 +------------ .../contract-attributes-nest.unchk_pass.stderr | 13 +------------ .../contract-captures-via-closure-noncopy.stderr | 1 + .../contract-ast-extensions-nest.rs | 1 - .../internal_machinery/contract-intrinsics.rs | 4 ++-- .../internal_machinery/contract-lang-items.rs | 2 +- .../internal_machinery/internal-feature-gating.rs | 2 +- .../internal-feature-gating.stderr | 2 +- 16 files changed, 39 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0b7a76304311..c3f57e111830 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -401,11 +401,10 @@ impl<'hir> LoweringContext<'_, 'hir> { cond_hir_id: HirId, ) -> &'hir hir::Expr<'hir> { let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id); - let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None); let call_expr = self.expr_call_lang_item_fn_mut( span, hir::LangItem::ContractCheckEnsures, - arena_vec![self; *expr, *cond_fn], + arena_vec![self; *cond_fn, *expr], ); self.arena.alloc(call_expr) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 28f596ac0926..c89112fc5a37 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1209,8 +1209,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let precond = if let Some(req) = &contract.requires { // Lower the precondition check intrinsic. let lowered_req = this.lower_expr_mut(&req); + let req_span = this.mark_span_with_reason( + DesugaringKind::Contract, + lowered_req.span, + None, + ); let precond = this.expr_call_lang_item_fn_mut( - req.span, + req_span, hir::LangItem::ContractCheckRequires, &*arena_vec![this; lowered_req], ); @@ -1220,6 +1225,8 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let (postcond, body) = if let Some(ens) = &contract.ensures { let ens_span = this.lower_span(ens.span); + let ens_span = + this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None); // Set up the postcondition `let` statement. let check_ident: Ident = Ident::from_str_and_span("__ensures_checker", ens_span); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 290e47b42b56..e54fa89328cd 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -236,7 +236,7 @@ pub fn check_intrinsic_type( // where C: for<'a> Fn(&'a Ret) -> bool, // // so: two type params, 0 lifetime param, 0 const params, two inputs, no return - (2, 0, 0, vec![param(0), param(1)], param(0), hir::Safety::Safe) + (2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe) } else { let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); let (n_tps, n_cts, inputs, output) = match intrinsic_name { diff --git a/library/core/src/contracts.rs b/library/core/src/contracts.rs index 829226420181..53f459debabc 100644 --- a/library/core/src/contracts.rs +++ b/library/core/src/contracts.rs @@ -2,15 +2,20 @@ pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires}; -/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }` -/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }` -/// (including the implicit return of the tail expression, if any). +/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute. /// -/// This call helps with type inference for the predicate. +/// This is an existing hack to allow users to omit the type of the return value in their ensures +/// attribute. +/// +/// Ideally, rustc should be able to generate the type annotation. +/// The existing lowering logic makes it rather hard to add the explicit type annotation, +/// while the function call is fairly straight forward. #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] +// Similar to `contract_check_requires`, we need to use the user-facing +// `contracts` feature rather than the perma-unstable `contracts_internals`. +// Const-checking doesn't honor allow internal unstable logic used by contract expansion. #[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_build_check_ensures"] -#[track_caller] pub const fn build_check_ensures(cond: C) -> C where C: Fn(&Ret) -> bool + Copy + 'static, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 8812cb66526b..90f686a67288 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3453,6 +3453,10 @@ pub const fn contract_checks() -> bool { /// /// Note that this function is a no-op during constant evaluation. #[unstable(feature = "contracts_internals", issue = "128044")] +// Calls to this function get inserted by an AST expansion pass, which uses the equivalent of +// `#[allow_internal_unstable]` to allow using `contracts_internals` functions. Const-checking +// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing +// `contracts` feature rather than the perma-unstable `contracts_internals` #[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_check_requires"] #[rustc_intrinsic] @@ -3478,12 +3482,15 @@ pub const fn contract_check_requires bool + Copy>(cond: C) { /// Note that this function is a no-op during constant evaluation. #[cfg(not(bootstrap))] #[unstable(feature = "contracts_internals", issue = "128044")] +// Similar to `contract_check_requires`, we need to use the user-facing +// `contracts` feature rather than the perma-unstable `contracts_internals`. +// Const-checking doesn't honor allow internal unstable logic used by contract expansion. #[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_check_ensures"] #[rustc_intrinsic] -pub const fn contract_check_ensures bool + Copy>(ret: Ret, cond: C) -> Ret { +pub const fn contract_check_ensures bool + Copy, Ret>(cond: C, ret: Ret) -> Ret { const_eval_select!( - @capture[Ret, C: Fn(&Ret) -> bool + Copy] { ret: Ret, cond: C } -> Ret : + @capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret : if const { // Do nothing ret diff --git a/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr b/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr index e7c42ad98a57..9ca95b8bb01a 100644 --- a/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr +++ b/tests/ui/contracts/contract-attributes-nest.chk_pass.stderr @@ -7,16 +7,5 @@ LL | #![feature(contracts)] = note: see issue #128044 for more information = note: `#[warn(incomplete_features)]` on by default -warning: unreachable expression - --> $DIR/contract-attributes-nest.rs:23:1 - | -LL | #[core::contracts::ensures(|ret| *ret > 100)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression -... -LL | return x.baz + 50; - | ----------------- any code following this expression is unreachable - | - = note: `#[warn(unreachable_code)]` on by default - -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/contracts/contract-attributes-nest.rs b/tests/ui/contracts/contract-attributes-nest.rs index 7c35e54c18bc..e1e61b88f282 100644 --- a/tests/ui/contracts/contract-attributes-nest.rs +++ b/tests/ui/contracts/contract-attributes-nest.rs @@ -21,7 +21,6 @@ #[core::contracts::requires(x.baz > 0)] #[core::contracts::ensures(|ret| *ret > 100)] -//~^ WARN unreachable expression [unreachable_code] fn nest(x: Baz) -> i32 { loop { diff --git a/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr b/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr index e7c42ad98a57..9ca95b8bb01a 100644 --- a/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr +++ b/tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr @@ -7,16 +7,5 @@ LL | #![feature(contracts)] = note: see issue #128044 for more information = note: `#[warn(incomplete_features)]` on by default -warning: unreachable expression - --> $DIR/contract-attributes-nest.rs:23:1 - | -LL | #[core::contracts::ensures(|ret| *ret > 100)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression -... -LL | return x.baz + 50; - | ----------------- any code following this expression is unreachable - | - = note: `#[warn(unreachable_code)]` on by default - -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr b/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr index e7c42ad98a57..9ca95b8bb01a 100644 --- a/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr +++ b/tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr @@ -7,16 +7,5 @@ LL | #![feature(contracts)] = note: see issue #128044 for more information = note: `#[warn(incomplete_features)]` on by default -warning: unreachable expression - --> $DIR/contract-attributes-nest.rs:23:1 - | -LL | #[core::contracts::ensures(|ret| *ret > 100)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression -... -LL | return x.baz + 50; - | ----------------- any code following this expression is unreachable - | - = note: `#[warn(unreachable_code)]` on by default - -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr b/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr index e7c42ad98a57..9ca95b8bb01a 100644 --- a/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr +++ b/tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr @@ -7,16 +7,5 @@ LL | #![feature(contracts)] = note: see issue #128044 for more information = note: `#[warn(incomplete_features)]` on by default -warning: unreachable expression - --> $DIR/contract-attributes-nest.rs:23:1 - | -LL | #[core::contracts::ensures(|ret| *ret > 100)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression -... -LL | return x.baz + 50; - | ----------------- any code following this expression is unreachable - | - = note: `#[warn(unreachable_code)]` on by default - -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr index 4a47671fee19..b6f2e014e0a8 100644 --- a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr +++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr @@ -16,6 +16,7 @@ LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz | | within this `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}` | | this tail expression is of type `{closure@contract-captures-via-closure-noncopy.rs:12:42}` | unsatisfied trait bound + | required by a bound introduced by this call | = help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}`, the trait `std::marker::Copy` is not implemented for `Baz` note: required because it's used within this closure diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs index 7f9c3fe28cef..6d8cd3949eed 100644 --- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs +++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs @@ -21,7 +21,6 @@ fn nest(x: Baz) -> i32 contract_requires(|| x.baz > 0) contract_ensures(|ret| *ret > 100) - //~^ WARN unreachable expression [unreachable_code] { loop { return x.baz + 50; diff --git a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs index f94dfbde75fb..c62b8cca75ab 100644 --- a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs +++ b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs @@ -28,9 +28,9 @@ fn main() { let doubles_to_two = { let old = 2; move |ret: &u32 | ret + ret == old }; // Always pass - core::intrinsics::contract_check_ensures(1, doubles_to_two); + core::intrinsics::contract_check_ensures(doubles_to_two, 1); // Fail if enabled #[cfg(any(default, unchk_pass, chk_fail_ensures))] - core::intrinsics::contract_check_ensures(2, doubles_to_two); + core::intrinsics::contract_check_ensures(doubles_to_two, 2); } diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs index 26042cf688fd..73c591945310 100644 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs +++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs @@ -22,7 +22,7 @@ fn foo(x: Baz) -> i32 { }; let ret = x.baz + 50; - core::intrinsics::contract_check_ensures(ret, injected_checker) + core::intrinsics::contract_check_ensures(injected_checker, ret) } struct Baz { baz: i32 } diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs index 1b76eef6780f..6e5a7a3f9500 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs @@ -6,7 +6,7 @@ fn main() { //~^ ERROR use of unstable library feature `contracts_internals` core::intrinsics::contract_check_requires(|| true); //~^ ERROR use of unstable library feature `contracts_internals` - core::intrinsics::contract_check_ensures(&1, |_|true); + core::intrinsics::contract_check_ensures( |_|true, &1); //~^ ERROR use of unstable library feature `contracts_internals` core::contracts::build_check_ensures(|_: &()| true); diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr index 7302694a7874..1e39bd62e245 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr @@ -41,7 +41,7 @@ LL | core::intrinsics::contract_check_requires(|| true); error[E0658]: use of unstable library feature `contracts_internals` --> $DIR/internal-feature-gating.rs:9:5 | -LL | core::intrinsics::contract_check_ensures(&1, |_|true); +LL | core::intrinsics::contract_check_ensures( |_|true, &1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #128044 for more information From 72d17bfebbf5463dac1a7eb71c513b151b523e1f Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 18 Mar 2025 03:06:17 +0000 Subject: [PATCH 026/222] re-use sized fast path There's an existing fast path for the `type_op_prove_predicate` predicate, checking for trivially `Sized` types, which can be re-used when evaluating obligations within queries. This should improve performance, particularly in anticipation of new sizedness traits being added which can take advantage of this. --- compiler/rustc_middle/src/ty/sty.rs | 14 +++++++------- .../src/traits/fulfill.rs | 6 +++++- .../rustc_trait_selection/src/traits/mod.rs | 4 ++-- .../traits/query/type_op/prove_predicate.rs | 13 ++----------- .../src/traits/select/mod.rs | 8 +++++++- .../rustc_trait_selection/src/traits/util.rs | 19 +++++++++++++++++++ compiler/rustc_traits/src/codegen.rs | 11 +++++++++-- .../rustc_traits/src/evaluate_obligation.rs | 5 +++++ tests/ui/closures/issue-78720.rs | 1 + tests/ui/closures/issue-78720.stderr | 16 +++++++++++----- tests/ui/codegen/overflow-during-mono.rs | 2 +- tests/ui/codegen/overflow-during-mono.stderr | 2 +- 12 files changed, 70 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 27ee363f1c14..e17088799465 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1872,14 +1872,14 @@ impl<'tcx> Ty<'tcx> { /// Fast path helper for testing if a type is `Sized`. /// - /// Returning true means the type is known to be sized. Returning - /// `false` means nothing -- could be sized, might not be. + /// Returning true means the type is known to implement `Sized`. Returning `false` means + /// nothing -- could be sized, might not be. /// - /// Note that we could never rely on the fact that a type such as `[_]` is - /// trivially `!Sized` because we could be in a type environment with a - /// bound such as `[_]: Copy`. A function with such a bound obviously never - /// can be called, but that doesn't mean it shouldn't typecheck. This is why - /// this method doesn't return `Option`. + /// Note that we could never rely on the fact that a type such as `[_]` is trivially `!Sized` + /// because we could be in a type environment with a bound such as `[_]: Copy`. A function with + /// such a bound obviously never can be called, but that doesn't mean it shouldn't typecheck. + /// This is why this method doesn't return `Option`. + #[instrument(skip(tcx), level = "debug")] pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e98a240a53f5..1b76d48e4310 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -24,10 +24,10 @@ use super::{ }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; -use crate::traits::EvaluateConstErr; use crate::traits::normalize::normalize_with_depth_to; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{EvaluateConstErr, sizedness_fast_path}; pub(crate) type PendingPredicateObligations<'tcx> = ThinVec>; @@ -335,6 +335,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx; + if sizedness_fast_path(infcx.tcx, obligation.predicate) { + return ProcessResult::Changed(thin_vec::thin_vec![]); + } + if obligation.predicate.has_aliases() { let mut obligations = PredicateObligations::new(); let predicate = normalize_with_depth_to( diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index de337710b5ef..f2713b98f0a2 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,8 +65,8 @@ pub use self::specialize::{ pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::{ BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final, - supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices, - with_replaced_escaping_bound_vars, + sizedness_fast_path, supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, + upcast_choices, with_replaced_escaping_bound_vars, }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::outlives::env::OutlivesEnvironment; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 4f9e2e79d624..87fc532adaf6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -1,4 +1,3 @@ -use rustc_hir::LangItem; use rustc_infer::traits::Obligation; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; @@ -7,7 +6,7 @@ use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; use rustc_span::Span; use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse}; -use crate::traits::ObligationCtxt; +use crate::traits::{ObligationCtxt, sizedness_fast_path}; impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { type QueryResponse = (); @@ -16,15 +15,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>, ) -> Option { - // Proving Sized, very often on "obviously sized" types like - // `&T`, accounts for about 60% percentage of the predicates - // we have to prove. No need to canonicalize and all that for - // such cases. - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = - key.value.predicate.kind().skip_binder() - && tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) - && trait_ref.self_ty().is_trivially_sized(tcx) - { + if sizedness_fast_path(tcx, key.value.predicate) { return Some(()); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 56ff46e89e70..4d88a23250a7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -49,7 +49,9 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; -use crate::traits::{EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects}; +use crate::traits::{ + EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects, sizedness_fast_path, +}; mod _match; mod candidate_assembly; @@ -603,6 +605,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } + if sizedness_fast_path(self.tcx(), obligation.predicate) { + return Ok(EvaluatedToOk); + } + ensure_sufficient_stack(|| { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 9f20cd7eacb4..035fd38c48aa 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,6 +1,7 @@ use std::collections::{BTreeMap, VecDeque}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_hir::LangItem; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; pub use rustc_infer::traits::util::*; @@ -504,3 +505,21 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { } } } + +pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool { + // Proving `Sized` very often on "obviously sized" types like `&T`, accounts for about 60% + // percentage of the predicates we have to prove. No need to canonicalize and all that for + // such cases. + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = + predicate.kind().skip_binder() + { + if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) + && trait_ref.self_ty().is_trivially_sized(tcx) + { + debug!("fast path -- trivial sizedness"); + return true; + } + } + + false +} diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 4a889abfc28f..88f02d16c7d5 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -6,11 +6,11 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; -use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, Upcast}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, - Unimplemented, + Unimplemented, sizedness_fast_path, }; use tracing::debug; @@ -34,6 +34,13 @@ pub(crate) fn codegen_select_candidate<'tcx>( let (infcx, param_env) = tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env); let mut selcx = SelectionContext::new(&infcx); + if sizedness_fast_path(tcx, trait_ref.upcast(tcx)) { + return Ok(&*tcx.arena.alloc(ImplSource::Builtin( + ty::solve::BuiltinImplSource::Trivial, + Default::default(), + ))); + } + let obligation_cause = ObligationCause::dummy(); let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index c9ad096c6e9d..7771db855d70 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -5,6 +5,7 @@ use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; use rustc_trait_selection::traits::{ EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, + sizedness_fast_path, }; use tracing::debug; @@ -23,6 +24,10 @@ fn evaluate_obligation<'tcx>( debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; + if sizedness_fast_path(tcx, predicate) { + return Ok(EvaluationResult::EvaluatedToOk); + } + let mut selcx = SelectionContext::with_query_mode(infcx, TraitQueryMode::Canonical); let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate); diff --git a/tests/ui/closures/issue-78720.rs b/tests/ui/closures/issue-78720.rs index 81af030fe556..a615cdf26902 100644 --- a/tests/ui/closures/issue-78720.rs +++ b/tests/ui/closures/issue-78720.rs @@ -1,5 +1,6 @@ fn server() -> impl { //~^ ERROR at least one trait must be specified + //~^^ ERROR type annotations needed ().map2(|| "") } diff --git a/tests/ui/closures/issue-78720.stderr b/tests/ui/closures/issue-78720.stderr index 90672cd83d7c..3e95fab441ad 100644 --- a/tests/ui/closures/issue-78720.stderr +++ b/tests/ui/closures/issue-78720.stderr @@ -5,7 +5,7 @@ LL | fn server() -> impl { | ^^^^ error[E0412]: cannot find type `F` in this scope - --> $DIR/issue-78720.rs:13:12 + --> $DIR/issue-78720.rs:14:12 | LL | _func: F, | ^ @@ -22,8 +22,14 @@ help: you might be missing a type parameter LL | struct Map2 { | +++ +error[E0282]: type annotations needed + --> $DIR/issue-78720.rs:1:16 + | +LL | fn server() -> impl { + | ^^^^ cannot infer type + error[E0308]: mismatched types - --> $DIR/issue-78720.rs:7:39 + --> $DIR/issue-78720.rs:8:39 | LL | fn map2(self, f: F) -> Map2 {} | ^^ expected `Map2`, found `()` @@ -32,7 +38,7 @@ LL | fn map2(self, f: F) -> Map2 {} found unit type `()` error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/issue-78720.rs:7:16 + --> $DIR/issue-78720.rs:8:16 | LL | fn map2(self, f: F) -> Map2 {} | ^^^^ doesn't have a size known at compile-time @@ -47,7 +53,7 @@ help: function arguments must have a statically known size, borrowed types alway LL | fn map2(&self, f: F) -> Map2 {} | + -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0277, E0308, E0412. +Some errors have detailed explanations: E0277, E0282, E0308, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs index 83a8b6b3ef6a..a9045840173e 100644 --- a/tests/ui/codegen/overflow-during-mono.rs +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -1,4 +1,4 @@ -//~ ERROR overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` +//~ ERROR overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: FnMut(&'a _)` //@ build-fail #![recursion_limit = "32"] diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr index f7a3e2df3dba..74d98fde285b 100644 --- a/tests/ui/codegen/overflow-during-mono.stderr +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` +error[E0275]: overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: FnMut(&'a _)` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`) = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` From f20efc4c61a0d5deaf86988565a0214733ff0e6b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Apr 2025 09:49:24 +0000 Subject: [PATCH 027/222] Handle `UnsafePointer` coercions in one place --- compiler/rustc_hir_typeck/src/coercion.rs | 58 +++++++++-------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index f1571cf4c831..c19e0a057401 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -247,7 +247,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::FnPtr(a_sig_tys, a_hdr) => { // We permit coercion of fn pointers to drop the // unsafe qualifier. - self.coerce_from_fn_pointer(a, a_sig_tys.with(a_hdr), b) + self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b) } ty::Closure(closure_def_id_a, args_a) => { // Non-capturing closures are coercible to @@ -813,18 +813,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }) } - fn coerce_from_safe_fn( + fn coerce_from_safe_fn( &self, - a: Ty<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>, b: Ty<'tcx>, - to_unsafe: F, - normal: G, - ) -> CoerceResult<'tcx> - where - F: FnOnce(Ty<'tcx>) -> Vec>, - G: FnOnce(Ty<'tcx>) -> Vec>, - { + adjustment: Option, + ) -> CoerceResult<'tcx> { self.commit_if_ok(|snapshot| { let outer_universe = self.infcx.universe(); @@ -833,9 +827,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { && hdr_b.safety.is_unsafe() { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - self.unify_and(unsafe_a, b, to_unsafe) + self.unify_and(unsafe_a, b, |target| match adjustment { + Some(kind) => vec![ + Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }, + Adjustment { + kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer), + target, + }, + ], + None => simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer))(target), + }) } else { - self.unify_and(a, b, normal) + let a = Ty::new_fn_ptr(self.tcx, fn_ty_a); + self.unify_and(a, b, |target| match adjustment { + None => vec![], + Some(kind) => vec![Adjustment { kind, target }], + }) }; // FIXME(#73154): This is a hack. Currently LUB can generate @@ -852,7 +859,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fn coerce_from_fn_pointer( &self, - a: Ty<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { @@ -861,15 +867,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { //! let b = self.shallow_resolve(b); - debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); + debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer"); - self.coerce_from_safe_fn( - a, - fn_ty_a, - b, - simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)), - identity, - ) + self.coerce_from_safe_fn(fn_ty_a, b, None) } fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { @@ -916,24 +916,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.at(&self.cause, self.param_env).normalize(a_sig); obligations.extend(o1); - let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig); let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn( - a_fn_pointer, a_sig, b, - |unsafe_ty| { - vec![ - Adjustment { - kind: Adjust::Pointer(PointerCoercion::ReifyFnPointer), - target: a_fn_pointer, - }, - Adjustment { - kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer), - target: unsafe_ty, - }, - ] - }, - simple(Adjust::Pointer(PointerCoercion::ReifyFnPointer)), + Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)), )?; obligations.extend(o2); From 697768a6645468e2a67a2df3c022b32d450a7f06 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Apr 2025 12:46:08 +0000 Subject: [PATCH 028/222] Simplify some `unify_and` calls --- compiler/rustc_hir_typeck/src/coercion.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index c19e0a057401..9e1a4703b995 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -191,7 +191,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // we have no information about the source type. This will always // ultimately fall back to some form of subtyping. if a.is_ty_var() { - return self.coerce_from_inference_variable(a, b, identity); + return self.coerce_from_inference_variable(a, b); } // Consider coercing the subtype to a DST @@ -265,12 +265,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// Coercing *from* an inference variable. In this case, we have no information /// about the source type, so we can't really do a true coercion and we always /// fall back to subtyping (`unify_and`). - fn coerce_from_inference_variable( - &self, - a: Ty<'tcx>, - b: Ty<'tcx>, - make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec>, - ) -> CoerceResult<'tcx> { + fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b); assert!(a.is_ty_var() && self.shallow_resolve(a) == a); assert!(self.shallow_resolve(b) == b); @@ -298,12 +293,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { "coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}", target_ty, obligations ); - let adjustments = make_adjustments(target_ty); - InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations }) + success(vec![], target_ty, obligations) } else { // One unresolved type variable: just apply subtyping, we may be able // to do something useful. - self.unify_and(a, b, make_adjustments) + self.unify_and(a, b, identity) } } @@ -708,7 +702,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { && let ty::Dynamic(b_data, _, ty::DynStar) = b.kind() && a_data.principal_def_id() == b_data.principal_def_id() { - return self.unify_and(a, b, |_| vec![]); + return self.unify_and(a, b, identity); } // Check the obligations of the cast -- for example, when casting @@ -808,9 +802,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // To complete the reborrow, we need to make sure we can unify the inner types, and if so we // add the adjustments. - self.unify_and(a, b, |_inner_ty| { - vec![Adjustment { kind: Adjust::ReborrowPin(mut_b), target: b }] - }) + self.unify_and(a, b, simple(Adjust::ReborrowPin(mut_b))) } fn coerce_from_safe_fn( From 804b6c963688a78f041bab93247c3cf0c78d7f2b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Apr 2025 12:57:43 +0000 Subject: [PATCH 029/222] Rename `unify` to `unify_raw` --- compiler/rustc_hir_typeck/src/coercion.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9e1a4703b995..44b966e610ed 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -131,7 +131,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never } } - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { + fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|_| { let at = self.at(&self.cause, self.fcx.param_env); @@ -166,7 +166,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { where F: FnOnce(Ty<'tcx>) -> Vec>, { - self.unify(a, b) + self.unify_raw(a, b) .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations)) } @@ -431,7 +431,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { referent_ty, mutbl_b, // [1] above ); - match self.unify(derefd_ty_a, b) { + match self.unify_raw(derefd_ty_a, b) { Ok(ok) => { found = Some(ok); break; @@ -1096,9 +1096,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); // We don't ever need two-phase here since we throw out the result of the coercion. let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); - coerce - .autoderef(DUMMY_SP, expr_ty) - .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps)) + coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| { + self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps) + }) } /// Given a type, this function will calculate and return the type given From 34258d62cd61c7cca7d1b957724717cd7df6c2ec Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Apr 2025 12:58:33 +0000 Subject: [PATCH 030/222] Add a dedicated function for the common `unify_and(identity)` case --- compiler/rustc_hir_typeck/src/coercion.rs | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 44b966e610ed..80592ea53d98 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -103,11 +103,6 @@ fn coerce_mutbls<'tcx>( if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) } } -/// Do not require any adjustments, i.e. coerce `x -> x`. -fn identity(_: Ty<'_>) -> Vec> { - vec![] -} - fn simple<'tcx>(kind: Adjust) -> impl FnOnce(Ty<'tcx>) -> Vec> { move |target| vec![Adjustment { kind, target }] } @@ -161,6 +156,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }) } + /// Unify two types (using sub or lub). + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + self.unify_raw(a, b) + .and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations)) + } + /// Unify two types (using sub or lub) and produce a specific coercion. fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx> where @@ -183,7 +184,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new()); } else { // Otherwise the only coercion we can do is unification. - return self.unify_and(a, b, identity); + return self.unify(a, b); } } @@ -257,7 +258,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify_and(a, b, identity) + self.unify(a, b) } } } @@ -297,7 +298,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } else { // One unresolved type variable: just apply subtyping, we may be able // to do something useful. - self.unify_and(a, b, identity) + self.unify(a, b) } } @@ -325,7 +326,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { coerce_mutbls(mt_a.mutbl, mutbl_b)?; (r_a, mt_a) } - _ => return self.unify_and(a, b, identity), + _ => return self.unify(a, b), }; let span = self.cause.span; @@ -702,7 +703,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { && let ty::Dynamic(b_data, _, ty::DynStar) = b.kind() && a_data.principal_def_id() == b_data.principal_def_id() { - return self.unify_and(a, b, identity); + return self.unify(a, b); } // Check the obligations of the cast -- for example, when casting @@ -917,7 +918,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { obligations.extend(o2); Ok(InferOk { value, obligations }) } - _ => self.unify_and(a, b, identity), + _ => self.unify(a, b), } } @@ -964,7 +965,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))), ) } - _ => self.unify_and(a, b, identity), + _ => self.unify(a, b), } } @@ -979,7 +980,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let (is_ref, mt_a) = match *a.kind() { ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }), - _ => return self.unify_and(a, b, identity), + _ => return self.unify(a, b), }; coerce_mutbls(mt_a.mutbl, mutbl_b)?; @@ -998,7 +999,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } else if mt_a.mutbl != mutbl_b { self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer))) } else { - self.unify_and(a_raw, b, identity) + self.unify(a_raw, b) } } } From 3528a65dd75c9f0ace6aa8dd8ce75e2ce97027b0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Apr 2025 13:03:45 +0000 Subject: [PATCH 031/222] Deduplicate `target` type setting in `unify_and` callbacks --- compiler/rustc_hir_typeck/src/coercion.rs | 90 +++++++++++++---------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 80592ea53d98..4f95d20251f2 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -103,10 +103,6 @@ fn coerce_mutbls<'tcx>( if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) } } -fn simple<'tcx>(kind: Adjust) -> impl FnOnce(Ty<'tcx>) -> Vec> { - move |target| vec![Adjustment { kind, target }] -} - /// This always returns `Ok(...)`. fn success<'tcx>( adj: Vec>, @@ -163,12 +159,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } /// Unify two types (using sub or lub) and produce a specific coercion. - fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx> - where - F: FnOnce(Ty<'tcx>) -> Vec>, - { - self.unify_raw(a, b) - .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations)) + fn unify_and( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + mut adjustments: Vec>, + final_adjustment: Adjust, + ) -> CoerceResult<'tcx> { + self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| { + adjustments.push(Adjustment { target: ty, kind: final_adjustment }); + success(adjustments, ty, obligations) + }) } #[instrument(skip(self))] @@ -181,7 +182,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Coercing from `!` to any type is allowed: if a.is_never() { if self.coerce_never { - return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new()); + return success( + vec![Adjustment { kind: Adjust::NeverToAny, target: b }], + b, + PredicateObligations::new(), + ); } else { // Otherwise the only coercion we can do is unification. return self.unify(a, b); @@ -574,13 +579,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // We only have the latter, so we use an inference variable // for the former and let type inference do the rest. let coerce_target = self.next_ty_var(self.cause.span); - let mut coercion = self.unify_and(coerce_target, target, |target| { - let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target }; + let mut coercion = self.unify_and( + coerce_target, + target, match reborrow { - None => vec![unsize], - Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize], - } - })?; + None => vec![], + Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone()], + }, + Adjust::Pointer(PointerCoercion::Unsize), + )?; let mut selcx = traits::SelectionContext::new(self); @@ -803,7 +810,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // To complete the reborrow, we need to make sure we can unify the inner types, and if so we // add the adjustments. - self.unify_and(a, b, simple(Adjust::ReborrowPin(mut_b))) + self.unify_and(a, b, vec![], Adjust::ReborrowPin(mut_b)) } fn coerce_from_safe_fn( @@ -820,22 +827,24 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { && hdr_b.safety.is_unsafe() { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - self.unify_and(unsafe_a, b, |target| match adjustment { - Some(kind) => vec![ - Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }, - Adjustment { - kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer), - target, - }, - ], - None => simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer))(target), - }) + let adjustments = match adjustment { + Some(kind) => { + vec![Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }] + } + None => vec![], + }; + self.unify_and( + unsafe_a, + b, + adjustments, + Adjust::Pointer(PointerCoercion::UnsafeFnPointer), + ) } else { let a = Ty::new_fn_ptr(self.tcx, fn_ty_a); - self.unify_and(a, b, |target| match adjustment { - None => vec![], - Some(kind) => vec![Adjustment { kind, target }], - }) + match adjustment { + Some(adjust) => self.unify_and(a, b, vec![], adjust), + None => self.unify(a, b), + } }; // FIXME(#73154): This is a hack. Currently LUB can generate @@ -962,7 +971,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.unify_and( pointer_ty, b, - simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))), + vec![], + Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)), ) } _ => self.unify(a, b), @@ -990,14 +1000,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. if is_ref { - self.unify_and(a_raw, b, |target| { - vec![ - Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }, - Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target }, - ] - }) + self.unify_and( + a_raw, + b, + vec![Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }], + Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), + ) } else if mt_a.mutbl != mutbl_b { - self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer))) + self.unify_and(a_raw, b, vec![], Adjust::Pointer(PointerCoercion::MutToConstPointer)) } else { self.unify(a_raw, b) } From 77116881a857ca49ff11c7c3b35c86305864ab45 Mon Sep 17 00:00:00 2001 From: oyvindln Date: Wed, 9 Apr 2025 23:45:46 +0200 Subject: [PATCH 032/222] update miniz_oxide to 0.8.8 0.8.7 can trigger a panic when debug assertions are enabled when used via flate2 in some cases --- Cargo.lock | 6 +++--- library/Cargo.lock | 4 ++-- src/ci/citool/Cargo.lock | 4 ++-- src/tools/miri/test_dependencies/Cargo.lock | 4 ++-- src/tools/rustbook/Cargo.lock | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf519e039260..68ad21bbeba7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1221,7 +1221,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.7", + "miniz_oxide 0.8.8", ] [[package]] @@ -2291,9 +2291,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] diff --git a/library/Cargo.lock b/library/Cargo.lock index ad634e9f794a..75584d2a77b7 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", "compiler_builtins", diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index 800eaae07665..2fe219f368b9 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -563,9 +563,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock index 24a8efc873d6..276c518e74f3 100644 --- a/src/tools/miri/test_dependencies/Cargo.lock +++ b/src/tools/miri/test_dependencies/Cargo.lock @@ -156,9 +156,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 09bbbd61de50..e0939afc09bb 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -981,9 +981,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] From 673012faf7085d426d6598b8e445ad8630921723 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 10 Apr 2025 07:12:12 +0000 Subject: [PATCH 033/222] Some performance shenanigans --- compiler/rustc_hir_typeck/src/coercion.rs | 69 +++++++++++++---------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 4f95d20251f2..ec198c252975 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -163,12 +163,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { &self, a: Ty<'tcx>, b: Ty<'tcx>, - mut adjustments: Vec>, + adjustments: impl IntoIterator>, final_adjustment: Adjust, ) -> CoerceResult<'tcx> { self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| { - adjustments.push(Adjustment { target: ty, kind: final_adjustment }); - success(adjustments, ty, obligations) + success( + adjustments + .into_iter() + .chain(std::iter::once(Adjustment { target: ty, kind: final_adjustment })) + .collect(), + ty, + obligations, + ) }) } @@ -579,15 +585,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // We only have the latter, so we use an inference variable // for the former and let type inference do the rest. let coerce_target = self.next_ty_var(self.cause.span); - let mut coercion = self.unify_and( - coerce_target, - target, - match reborrow { - None => vec![], - Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone()], - }, - Adjust::Pointer(PointerCoercion::Unsize), - )?; + + let mut coercion = match reborrow { + None => { + self.unify_and(coerce_target, target, [], Adjust::Pointer(PointerCoercion::Unsize))? + } + Some((ref deref, ref autoref)) => self.unify_and( + coerce_target, + target, + [deref.clone(), autoref.clone()], + Adjust::Pointer(PointerCoercion::Unsize), + )?, + }; let mut selcx = traits::SelectionContext::new(self); @@ -810,7 +819,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // To complete the reborrow, we need to make sure we can unify the inner types, and if so we // add the adjustments. - self.unify_and(a, b, vec![], Adjust::ReborrowPin(mut_b)) + self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b)) } fn coerce_from_safe_fn( @@ -827,22 +836,24 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { && hdr_b.safety.is_unsafe() { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - let adjustments = match adjustment { - Some(kind) => { - vec![Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }] - } - None => vec![], - }; - self.unify_and( - unsafe_a, - b, - adjustments, - Adjust::Pointer(PointerCoercion::UnsafeFnPointer), - ) + match adjustment { + Some(kind) => self.unify_and( + unsafe_a, + b, + [Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }], + Adjust::Pointer(PointerCoercion::UnsafeFnPointer), + ), + None => self.unify_and( + unsafe_a, + b, + [], + Adjust::Pointer(PointerCoercion::UnsafeFnPointer), + ), + } } else { let a = Ty::new_fn_ptr(self.tcx, fn_ty_a); match adjustment { - Some(adjust) => self.unify_and(a, b, vec![], adjust), + Some(adjust) => self.unify_and(a, b, [], adjust), None => self.unify(a, b), } }; @@ -971,7 +982,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.unify_and( pointer_ty, b, - vec![], + [], Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)), ) } @@ -1003,11 +1014,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.unify_and( a_raw, b, - vec![Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }], + [Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }], Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), ) } else if mt_a.mutbl != mutbl_b { - self.unify_and(a_raw, b, vec![], Adjust::Pointer(PointerCoercion::MutToConstPointer)) + self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer)) } else { self.unify(a_raw, b) } From f80b12129ea8a58464a685abefd1f36819d3dd7b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 10 Apr 2025 08:15:03 +0000 Subject: [PATCH 034/222] Avoid some more duplication --- compiler/rustc_hir_typeck/src/coercion.rs | 38 ++++++++--------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ec198c252975..fd899425f62d 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -586,17 +586,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // for the former and let type inference do the rest. let coerce_target = self.next_ty_var(self.cause.span); - let mut coercion = match reborrow { - None => { - self.unify_and(coerce_target, target, [], Adjust::Pointer(PointerCoercion::Unsize))? - } - Some((ref deref, ref autoref)) => self.unify_and( - coerce_target, - target, - [deref.clone(), autoref.clone()], - Adjust::Pointer(PointerCoercion::Unsize), - )?, - }; + let mut coercion = self.unify_and( + coerce_target, + target, + reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]), + Adjust::Pointer(PointerCoercion::Unsize), + )?; let mut selcx = traits::SelectionContext::new(self); @@ -836,20 +831,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { && hdr_b.safety.is_unsafe() { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - match adjustment { - Some(kind) => self.unify_and( - unsafe_a, - b, - [Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }], - Adjust::Pointer(PointerCoercion::UnsafeFnPointer), - ), - None => self.unify_and( - unsafe_a, - b, - [], - Adjust::Pointer(PointerCoercion::UnsafeFnPointer), - ), - } + self.unify_and( + unsafe_a, + b, + adjustment + .map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }), + Adjust::Pointer(PointerCoercion::UnsafeFnPointer), + ) } else { let a = Ty::new_fn_ptr(self.tcx, fn_ty_a); match adjustment { From ac4014bd2004811851caea3e81c22cbed7b92aa5 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 22 Jan 2025 16:05:26 -0800 Subject: [PATCH 035/222] Add minimal x86_64-lynx-lynxos178 support. It's possible to build no_std programs with this compiler. > A tier 3 target must have a designated developer or developers (the "target maintainers") on record to be CCed when issues arise regarding the target. (The mechanism to track and CC such developers may evolve over time.) Tim Newsome (@tnewsome-lynx) will be the designated developer for x86_64-lynx-lynxos178 support. > Targets must use naming consistent with any existing targets; for instance, a target for the same CPU or OS as an existing Rust target should use the same name for that CPU or OS. Targets should normally use the same names and naming conventions as used elsewhere in the broader ecosystem beyond Rust (such as in other toolchains), unless they have a very good reason to diverge. Changing the name of a target can be highly disruptive, especially once the target reaches a higher tier, so getting the name right is important even for a tier 3 target. I believe the target is named appropriately. > Target names should not introduce undue confusion or ambiguity unless absolutely necessary to maintain ecosystem compatibility. For example, if the name of the target makes people extremely likely to form incorrect beliefs about what it targets, the name should be changed or augmented to disambiguate it. The target name is not confusing. > If possible, use only letters, numbers, dashes and underscores for the name. Periods (.) are known to cause issues in Cargo. Done. > Tier 3 targets may have unusual requirements to build or use, but must not create legal issues or impose onerous legal terms for the Rust project or for Rust developers or users. > The target must not introduce license incompatibilities. > Anything added to the Rust repository must be under the standard Rust license (MIT OR Apache-2.0). All this new code is licensed under the Apache-2.0 license. > The target must not cause the Rust tools or libraries built for any other host (even when supporting cross-compilation to the target) to depend on any new dependency less permissive than the Rust licensing policy. This applies whether the dependency is a Rust crate that would require adding new license exceptions (as specified by the tidy tool in the rust-lang/rust repository), or whether the dependency is a native library or binary. In other words, the introduction of the target must not cause a user installing or running a version of Rust or the Rust tools to be subject to any new license requirements. Done. > Compiling, linking, and emitting functional binaries, libraries, or other code for the target (whether hosted on the target itself or cross-compiling from another target) must not depend on proprietary (non-FOSS) libraries. Host tools built for the target itself may depend on the ordinary runtime libraries supplied by the platform and commonly used by other applications built for the target, but those libraries must not be required for code generation for the target; cross-compilation to the target must not require such libraries at all. For instance, rustc built for the target may depend on a common proprietary C runtime library or console output library, but must not depend on a proprietary code generation library or code optimization library. Rust's license permits such combinations, but the Rust project has no interest in maintaining such combinations within the scope of Rust itself, even at tier 3. I think we're in the clear here. We do link against some static libraries that are proprietary (like libm and libc), but those are not used to generate code. E.g. the VxWorks target requires `wr-c++` to be installed, which is not publically available. > "onerous" here is an intentionally subjective term. At a minimum, "onerous" legal/licensing terms include but are not limited to: non-disclosure requirements, non-compete requirements, contributor license agreements (CLAs) or equivalent, "non-commercial"/"research-only"/etc terms, requirements conditional on the employer or employment of any particular Rust developers, revocable terms, any requirements that create liability for the Rust project or its developers or users, or any requirements that adversely affect the livelihood or prospects of the Rust project or its developers or users. Our intention is to allow anyone with access to LynxOS CDK to use Rust for it. > Neither this policy nor any decisions made regarding targets shall create any binding agreement or estoppel by any party. If any member of an approving Rust team serves as one of the maintainers of a target, or has any legal or employment requirement (explicit or implicit) that might affect their decisions regarding a target, they must recuse themselves from any approval decisions regarding the target's tier status, though they may otherwise participate in discussions. > This requirement does not prevent part or all of this policy from being cited in an explicit contract or work agreement (e.g. to implement or maintain support for a target). This requirement exists to ensure that a developer or team responsible for reviewing and approving a target does not face any legal threats or obligations that would prevent them from freely exercising their judgment in such approval, even if such judgment involves subjective matters or goes beyond the letter of these requirements. No problem. > Tier 3 targets should attempt to implement as much of the standard libraries as possible and appropriate (core for most targets, alloc for targets that can support dynamic memory allocation, std for targets with an operating system or equivalent layer of system-provided functionality), but may leave some code unimplemented (either unavailable or stubbed out as appropriate), whether because the target makes it impossible to implement or challenging to implement. The authors of pull requests are not obligated to avoid calling any portions of the standard library on the basis of a tier 3 target not implementing those portions. With this first PR, only core is supported. I am working on support for the std library and intend to submit that once all the tests are passing. > The target must provide documentation for the Rust community explaining how to build for the target, using cross-compilation if possible. If the target supports running binaries, or running tests (even if they do not pass), the documentation must explain how to run such binaries or tests for the target, using emulation if possible or dedicated hardware if necessary. This is documented in `src/doc/rustc/src/platform-support/lynxos_178.md`. > Tier 3 targets must not impose burden on the authors of pull requests, or other developers in the community, to maintain the target. In particular, do not post comments (automated or manual) on a PR that derail or suggest a block on the PR based on a tier 3 target. Do not send automated messages or notifications (via any medium, including via @) to a PR author or others involved with a PR regarding a tier 3 target, unless they have opted into such messages. > Backlinks such as those generated by the issue/PR tracker when linking to an issue or PR are not considered a violation of this policy, within reason. However, such messages (even on a separate repository) must not generate notifications to anyone involved with a PR who has not requested such notifications. Understood. > Patches adding or updating tier 3 targets must not break any existing tier 2 or tier 1 target, and must not knowingly break another tier 3 target without approval of either the compiler team or the maintainers of the other tier 3 target. > In particular, this may come up when working on closely related targets, such as variations of the same architecture with different features. Avoid introducing unconditional uses of features that another variation of the target may not have; use conditional compilation or runtime detection, as appropriate, to let each target run code supported by that target. As far as I know this change does not affect any other targets. > Tier 3 targets must be able to produce assembly using at least one of rustc's supported backends from any host target. (Having support in a fork of the backend is not sufficient, it must be upstream.) Many targets produce assembly for x86_64 so that also works for LynxOS-178. --- .../rustc_target/src/spec/base/lynxos178.rs | 31 ++++++++ compiler/rustc_target/src/spec/base/mod.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 1 + .../src/spec/targets/x86_64_lynx_lynxos178.rs | 34 ++++++++ src/bootstrap/src/core/sanity.rs | 1 + src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + .../rustc/src/platform-support/lynxos178.md | 77 +++++++++++++++++++ tests/assembly/targets/targets-elf.rs | 3 + tests/ui/check-cfg/well-known-values.stderr | 4 +- 10 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_target/src/spec/base/lynxos178.rs create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs create mode 100644 src/doc/rustc/src/platform-support/lynxos178.md diff --git a/compiler/rustc_target/src/spec/base/lynxos178.rs b/compiler/rustc_target/src/spec/base/lynxos178.rs new file mode 100644 index 000000000000..b9434ff5faaf --- /dev/null +++ b/compiler/rustc_target/src/spec/base/lynxos178.rs @@ -0,0 +1,31 @@ +use std::borrow::Cow; + +use crate::spec::{ + PanicStrategy, RelocModel, RelroLevel, SplitDebuginfo, StackProbeType, TargetOptions, cvs, +}; + +pub(crate) fn opts() -> TargetOptions { + TargetOptions { + os: "lynxos178".into(), + dynamic_linking: false, + families: cvs!["unix"], + position_independent_executables: false, + static_position_independent_executables: false, + relro_level: RelroLevel::Full, + has_thread_local: false, + crt_static_respected: true, + panic_strategy: PanicStrategy::Abort, + linker: Some(Cow::Borrowed("x86_64-lynx-lynxos178-gcc")), + no_default_libraries: false, + eh_frame_header: false, // GNU ld (GNU Binutils) 2.37.50 does not support --eh-frame-hdr + max_atomic_width: Some(64), + supported_split_debuginfo: Cow::Borrowed(&[ + SplitDebuginfo::Packed, + SplitDebuginfo::Unpacked, + SplitDebuginfo::Off, + ]), + relocation_model: RelocModel::Static, + stack_probes: StackProbeType::Inline, + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index 71b6528c2dd1..b368d93f0072 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -19,6 +19,7 @@ pub(crate) mod linux_musl; pub(crate) mod linux_ohos; pub(crate) mod linux_uclibc; pub(crate) mod linux_wasm; +pub(crate) mod lynxos178; pub(crate) mod msvc; pub(crate) mod netbsd; pub(crate) mod nto_qnx; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 64171fcc7ab3..3c769dad630a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2078,6 +2078,7 @@ supported_targets! { ("riscv32imafc-unknown-nuttx-elf", riscv32imafc_unknown_nuttx_elf), ("riscv64imac-unknown-nuttx-elf", riscv64imac_unknown_nuttx_elf), ("riscv64gc-unknown-nuttx-elf", riscv64gc_unknown_nuttx_elf), + ("x86_64-lynx-lynxos178", x86_64_lynx_lynxos178), ("x86_64-pc-cygwin", x86_64_pc_cygwin), } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs b/compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs new file mode 100644 index 000000000000..654ae7c9c5be --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs @@ -0,0 +1,34 @@ +use crate::spec::{SanitizerSet, StackProbeType, Target, base}; + +pub(crate) fn target() -> Target { + let mut base = base::lynxos178::opts(); + base.cpu = "x86-64".into(); + base.plt_by_default = false; + base.max_atomic_width = Some(64); + base.stack_probes = StackProbeType::Inline; + base.static_position_independent_executables = false; + base.supported_sanitizers = SanitizerSet::ADDRESS + | SanitizerSet::CFI + | SanitizerSet::KCFI + | SanitizerSet::DATAFLOW + | SanitizerSet::LEAK + | SanitizerSet::MEMORY + | SanitizerSet::SAFESTACK + | SanitizerSet::THREAD; + base.supports_xray = true; + + Target { + llvm_target: "x86_64-unknown-unknown-gnu".into(), + metadata: crate::spec::TargetMetadata { + description: Some("LynxOS-178".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: "x86_64".into(), + options: base, + } +} diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 891340add908..9e4a72bc9c37 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,6 +34,7 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined + "x86_64-lynx-lynxos178", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 9bb64adfa786..cf41f5b86a85 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -78,6 +78,7 @@ - [illumos](platform-support/illumos.md) - [loongarch\*-unknown-linux-\*](platform-support/loongarch-linux.md) - [loongarch\*-unknown-none\*](platform-support/loongarch-none.md) + - [\*-lynxos178-\*](platform-support/lynxos178.md) - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md) - [m68k-unknown-none-elf](platform-support/m68k-unknown-none-elf.md) - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 4149b4cb9202..9870e5011ebf 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -407,6 +407,7 @@ target | std | host | notes [`wasm32-wali-linux-musl`](platform-support/wasm32-wali-linux.md) | ? | | WebAssembly with [WALI](https://github.com/arjunr2/WALI) [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator +[`x86_64-lynx-lynxos178`](platform-support/lynxos178.md) | | | x86_64 LynxOS-178 [`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ✓ | | 64-bit x86 Cygwin | [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | [`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) | diff --git a/src/doc/rustc/src/platform-support/lynxos178.md b/src/doc/rustc/src/platform-support/lynxos178.md new file mode 100644 index 000000000000..6463f95a0b8e --- /dev/null +++ b/src/doc/rustc/src/platform-support/lynxos178.md @@ -0,0 +1,77 @@ +# `*-lynxos178-*` + +**Tier: 3** + +Targets for the LynxOS-178 operating system. + +[LynxOS-178](https://www.lynx.com/products/lynxos-178-do-178c-certified-posix-rtos) +is a commercial RTOS designed for safety-critical real-time systems. It is +developed by Lynx Software Technologies as part of the +[MOSA.ic](https://www.lynx.com/solutions/safe-and-secure-operating-environment) +product suite. + +Target triples available: +- `x86_64-lynx-lynxos178` + +## Target maintainers + +- Renat Fatykhov, https://github.com/rfatykhov-lynx + +## Requirements + +To build Rust programs for LynxOS-178, you must first have LYNX MOSA.ic +installed on the build machine. + +This target supports only cross-compilation, from the same hosts supported by +the Lynx CDK. + +Currently only `no_std` programs are supported. Work to support `std` is in +progress. + +## Building the target + +You can build Rust with support for x86_64-lynx-lynxos178 by adding that +to the `target` list in `config.toml`, and then running `./x build --target +x86_64-lynx-lynxos178 compiler`. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will need to build Rust with the target enabled (see "Building +the target" above). + +Before executing `cargo`, you must configure the environment to build LynxOS-178 +binaries by running `source setup.sh` from the los178 directory. + +If your program/crates contain procedural macros, Rust must be able to build +binaries for the host as well. The host gcc is hidden by sourcing setup.sh. To +deal with this, add the following to your project's `.cargo/config.toml`: +```toml +[target.x86_64-unknown-linux-gnu] +linker = "lynx-host-gcc" +``` +(If necessary substitute your host target triple for x86_64-unknown-linux-gnu.) + +To point `cargo` at the correct rustc binary, set the RUSTC environment +variable. + +The core library should be usable. You can try by building it as part of your +project: +```bash +cargo +nightly build -Z build-std=core --target x86_64-lynx-lynxos178 +``` + +## Testing + +Binaries built with rust can be provided to a LynxOS-178 instance on its file +system, where they can be executed. Rust binaries tend to be large, so it may +be necessary to strip them first. + +It is possible to run the Rust testsuite by providing a test runner that takes +the test binary and executes it under LynxOS-178. Most (all?) tests won't run +without std support though, which is not yet supported. + +## Cross-compilation toolchains and C code + +LYNX MOSA.ic comes with all the tools required to cross-compile C code for +LynxOS-178. diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 8f2fef0e9c91..325559111949 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -571,6 +571,9 @@ //@ revisions: x86_64_linux_android //@ [x86_64_linux_android] compile-flags: --target x86_64-linux-android //@ [x86_64_linux_android] needs-llvm-components: x86 +//@ revisions: x86_64_lynx_lynxos178 +//@ [x86_64_lynx_lynxos178] compile-flags: --target x86_64-lynx-lynxos178 +//@ [x86_64_lynx_lynxos178] needs-llvm-components: x86 //@ revisions: x86_64_pc_nto_qnx710 //@ [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710 //@ [x86_64_pc_nto_qnx710] needs-llvm-components: x86 diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 4636b6945d06..7cda6c2eaa52 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -201,7 +201,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -274,7 +274,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: 28 warnings emitted From 95ad6dfeab798a612908f768ea6df0ddb000f643 Mon Sep 17 00:00:00 2001 From: Makai Date: Thu, 10 Apr 2025 20:12:26 +0800 Subject: [PATCH 036/222] add `span_extend_to_prev_char_before()` to `SourceMap` --- compiler/rustc_span/src/source_map.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 6fdf8e46fec6..0273bb040f43 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -633,6 +633,24 @@ impl SourceMap { sp } + /// Extends the given `Span` to just before the previous occurrence of `c`. Return the same span + /// if an error occurred while retrieving the code snippet. + pub fn span_extend_to_prev_char_before( + &self, + sp: Span, + c: char, + accept_newlines: bool, + ) -> Span { + if let Ok(prev_source) = self.span_to_prev_source(sp) { + let prev_source = prev_source.rsplit(c).next().unwrap_or(""); + if accept_newlines || !prev_source.contains('\n') { + return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32 - 1_u32)); + } + } + + sp + } + /// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by /// whitespace. Returns None if the pattern could not be found or if an error occurred while /// retrieving the code snippet. From f9f2acac1f7335ccb5129f97c963ac937b121b49 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 10 Apr 2025 13:55:52 +0000 Subject: [PATCH 037/222] cfi: do not transmute function pointers in formatting code --- library/core/src/fmt/mod.rs | 2 +- library/core/src/fmt/rt.rs | 45 +++++++++++++++++++------------------ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 7ca390941bcd..580f95eddce7 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -7,7 +7,7 @@ use crate::char::{EscapeDebugExtArgs, MAX_LEN_UTF8}; use crate::marker::PhantomData; use crate::num::fmt as numfmt; use crate::ops::Deref; -use crate::{iter, mem, result, str}; +use crate::{iter, result, str}; mod builders; #[cfg(not(no_fp_fmt_parse))] diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 0459674303d1..05e024b134d1 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -65,61 +65,67 @@ pub struct Argument<'a> { ty: ArgumentType<'a>, } -#[rustc_diagnostic_item = "ArgumentMethods"] -impl Argument<'_> { - #[inline] - const fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { +macro_rules! argument_new { + ($t:ty, $x:expr, $f:expr) => { Argument { // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { - value: NonNull::from_ref(x).cast(), + value: NonNull::<$t>::from_ref($x).cast(), // SAFETY: function pointers always have the same layout. - formatter: unsafe { mem::transmute(f) }, + formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| { + let func = $f; + // SAFETY: This is the same type as the `value` field. + let r = unsafe { ptr.cast::<$t>().as_ref() }; + (func)(r, fmt) + }, _lifetime: PhantomData, }, } - } + }; +} +#[rustc_diagnostic_item = "ArgumentMethods"] +impl Argument<'_> { #[inline] pub fn new_display(x: &T) -> Argument<'_> { - Self::new(x, Display::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_debug(x: &T) -> Argument<'_> { - Self::new(x, Debug::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_debug_noop(x: &T) -> Argument<'_> { - Self::new(x, |_, _| Ok(())) + argument_new!(T, x, |_: &T, _| Ok(())) } #[inline] pub fn new_octal(x: &T) -> Argument<'_> { - Self::new(x, Octal::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_lower_hex(x: &T) -> Argument<'_> { - Self::new(x, LowerHex::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_upper_hex(x: &T) -> Argument<'_> { - Self::new(x, UpperHex::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_pointer(x: &T) -> Argument<'_> { - Self::new(x, Pointer::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_binary(x: &T) -> Argument<'_> { - Self::new(x, Binary::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_lower_exp(x: &T) -> Argument<'_> { - Self::new(x, LowerExp::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_upper_exp(x: &T) -> Argument<'_> { - Self::new(x, UpperExp::fmt) + argument_new!(T, x, ::fmt) } #[inline] #[track_caller] @@ -135,11 +141,6 @@ impl Argument<'_> { /// # Safety /// /// This argument must actually be a placeholder argument. - /// - // FIXME: Transmuting formatter in new and indirectly branching to/calling - // it here is an explicit CFI violation. - #[allow(inline_no_sanitize)] - #[no_sanitize(cfi, kcfi)] #[inline] pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self.ty { From 997ec4982b6be6c4d2bffe7dcb0df420d78482de Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 10 Apr 2025 14:32:59 +0000 Subject: [PATCH 038/222] Update code coverage map --- tests/coverage/closure.cov-map | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 2d784ba09b60..640f98956840 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -140,19 +140,17 @@ Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 -Function name: closure::main::{closure#18} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] +Function name: closure::main::{closure#18} (unused) +Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 25, 13) to (start + 2, 28) -- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) -- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) - = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14) -Highest counter ID seen: c1 +- Code(Zero) at (prev + 25, 13) to (start + 2, 28) +- Code(Zero) at (prev + 2, 29) to (start + 2, 18) +- Code(Zero) at (prev + 2, 17) to (start + 0, 18) +- Code(Zero) at (prev + 1, 17) to (start + 1, 14) +Highest counter ID seen: (none) Function name: closure::main::{closure#19} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] From 250a1aa7a6d583db8882333c1875f3ececdccc3b Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Wed, 5 Mar 2025 09:24:09 +0000 Subject: [PATCH 039/222] make `AllTypes::print` return `impl fmt::Display` --- src/librustdoc/html/render/context.rs | 10 +--- src/librustdoc/html/render/mod.rs | 73 ++++++++++++++------------- src/librustdoc/html/render/tests.rs | 3 +- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index e2d1f58a37ec..596ac665fc31 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -650,15 +650,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { bar.render_into(&mut sidebar).unwrap(); - let v = layout::render( - &shared.layout, - &page, - sidebar, - BufDisplay(|buf: &mut String| { - all.print(buf); - }), - &shared.style_files, - ); + let v = layout::render(&shared.layout, &page, sidebar, all.print(), &shared.style_files); shared.fs.write(final_file, v)?; // if to avoid writing help, settings files to doc root unless we're on the final invocation diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 21c823f49d15..aacb854d5da1 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -439,44 +439,49 @@ impl AllTypes { sections } - fn print(&self, f: &mut String) { - fn print_entries(f: &mut String, e: &FxIndexSet, kind: ItemSection) { - if !e.is_empty() { - let mut e: Vec<&ItemEntry> = e.iter().collect(); - e.sort(); - write_str( - f, - format_args!( - "

{title}

    ", - id = kind.id(), - title = kind.name(), - ), - ); - - for s in e.iter() { - write_str(f, format_args!("
  • {}
  • ", s.print())); + fn print(&self) -> impl fmt::Display { + fn print_entries(e: &FxIndexSet, kind: ItemSection) -> impl fmt::Display { + fmt::from_fn(move |f| { + if e.is_empty() { + return Ok(()); } - f.push_str("
"); - } + let mut e: Vec<&ItemEntry> = e.iter().collect(); + e.sort(); + write!( + f, + "

{title}

    ", + id = kind.id(), + title = kind.name(), + )?; + + for s in e.iter() { + write!(f, "
  • {}
  • ", s.print())?; + } + + f.write_str("
") + }) } - f.push_str("

List of all items

"); - // Note: print_entries does not escape the title, because we know the current set of titles - // doesn't require escaping. - print_entries(f, &self.structs, ItemSection::Structs); - print_entries(f, &self.enums, ItemSection::Enums); - print_entries(f, &self.unions, ItemSection::Unions); - print_entries(f, &self.primitives, ItemSection::PrimitiveTypes); - print_entries(f, &self.traits, ItemSection::Traits); - print_entries(f, &self.macros, ItemSection::Macros); - print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros); - print_entries(f, &self.derive_macros, ItemSection::DeriveMacros); - print_entries(f, &self.functions, ItemSection::Functions); - print_entries(f, &self.type_aliases, ItemSection::TypeAliases); - print_entries(f, &self.trait_aliases, ItemSection::TraitAliases); - print_entries(f, &self.statics, ItemSection::Statics); - print_entries(f, &self.constants, ItemSection::Constants); + fmt::from_fn(|f| { + f.write_str("

List of all items

")?; + // Note: print_entries does not escape the title, because we know the current set of titles + // doesn't require escaping. + print_entries(&self.structs, ItemSection::Structs).fmt(f)?; + print_entries(&self.enums, ItemSection::Enums).fmt(f)?; + print_entries(&self.unions, ItemSection::Unions).fmt(f)?; + print_entries(&self.primitives, ItemSection::PrimitiveTypes).fmt(f)?; + print_entries(&self.traits, ItemSection::Traits).fmt(f)?; + print_entries(&self.macros, ItemSection::Macros).fmt(f)?; + print_entries(&self.attribute_macros, ItemSection::AttributeMacros).fmt(f)?; + print_entries(&self.derive_macros, ItemSection::DeriveMacros).fmt(f)?; + print_entries(&self.functions, ItemSection::Functions).fmt(f)?; + print_entries(&self.type_aliases, ItemSection::TypeAliases).fmt(f)?; + print_entries(&self.trait_aliases, ItemSection::TraitAliases).fmt(f)?; + print_entries(&self.statics, ItemSection::Statics).fmt(f)?; + print_entries(&self.constants, ItemSection::Constants).fmt(f)?; + Ok(()) + }) } } diff --git a/src/librustdoc/html/render/tests.rs b/src/librustdoc/html/render/tests.rs index 657cd3c82aae..327a30887b1d 100644 --- a/src/librustdoc/html/render/tests.rs +++ b/src/librustdoc/html/render/tests.rs @@ -47,8 +47,7 @@ fn test_all_types_prints_header_once() { // Regression test for #82477 let all_types = AllTypes::new(); - let mut buffer = String::new(); - all_types.print(&mut buffer); + let buffer = all_types.print().to_string(); assert_eq!(1, buffer.matches("List of all items").count()); } From 642995cf1c25d13b7857f1a36cf609654c29c6dc Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Thu, 13 Mar 2025 06:20:23 +0000 Subject: [PATCH 040/222] make `link_tooltip` return `impl fmt::Display` --- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/html/format.rs | 55 ++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 06e75fe1764e..c67f81c77f3c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -517,7 +517,7 @@ impl Item { Some(RenderedLink { original_text: s.clone(), new_text: link_text.clone(), - tooltip: link_tooltip(*id, fragment, cx), + tooltip: link_tooltip(*id, fragment, cx).to_string(), href, }) } else { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 41e9a5a66516..4998c671b61e 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -11,6 +11,7 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::fmt::{self, Display, Write}; use std::iter::{self, once}; +use std::slice; use itertools::Either; use rustc_abi::ExternAbi; @@ -650,33 +651,35 @@ pub(crate) fn href_relative_parts<'fqp>( } } -pub(crate) fn link_tooltip(did: DefId, fragment: &Option, cx: &Context<'_>) -> String { - let cache = cx.cache(); - let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did)) - else { - return String::new(); - }; - let mut buf = String::new(); - let fqp = if *shortty == ItemType::Primitive { - // primitives are documented in a crate, but not actually part of it - &fqp[fqp.len() - 1..] - } else { - fqp - }; - if let &Some(UrlFragment::Item(id)) = fragment { - write_str(&mut buf, format_args!("{} ", cx.tcx().def_descr(id))); - for component in fqp { - write_str(&mut buf, format_args!("{component}::")); +pub(crate) fn link_tooltip( + did: DefId, + fragment: &Option, + cx: &Context<'_>, +) -> impl fmt::Display { + fmt::from_fn(move |f| { + let cache = cx.cache(); + let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did)) + else { + return Ok(()); + }; + let fqp = if *shortty == ItemType::Primitive { + // primitives are documented in a crate, but not actually part of it + slice::from_ref(fqp.last().unwrap()) + } else { + fqp + }; + if let &Some(UrlFragment::Item(id)) = fragment { + write!(f, "{} ", cx.tcx().def_descr(id))?; + for component in fqp { + write!(f, "{component}::")?; + } + write!(f, "{}", cx.tcx().item_name(id))?; + } else if !fqp.is_empty() { + write!(f, "{shortty} ")?; + fqp.iter().joined("::", f)?; } - write_str(&mut buf, format_args!("{}", cx.tcx().item_name(id))); - } else if !fqp.is_empty() { - let mut fqp_it = fqp.iter(); - write_str(&mut buf, format_args!("{shortty} {}", fqp_it.next().unwrap())); - for component in fqp_it { - write_str(&mut buf, format_args!("::{component}")); - } - } - buf + Ok(()) + }) } /// Used to render a [`clean::Path`]. From f7640d5468208b1e58913b58e164718c628d51cc Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Thu, 13 Mar 2025 12:41:47 +0000 Subject: [PATCH 041/222] make `doc_impl_item` and `render_default_items` receive `impl fmt::Write` --- src/librustdoc/html/render/mod.rs | 234 ++++++++++++++---------------- 1 file changed, 108 insertions(+), 126 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index aacb854d5da1..511a9316aff3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -47,6 +47,7 @@ use std::path::PathBuf; use std::{fs, str}; use askama::Template; +use itertools::Either; use rustc_attr_parsing::{ ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince, }; @@ -1644,8 +1645,8 @@ fn render_impl( // `containing_item` is used for rendering stability info. If the parent is a trait impl, // `containing_item` will the grandparent, since trait impls can't have stability attached. fn doc_impl_item( - boring: &mut String, - interesting: &mut String, + boring: impl fmt::Write, + interesting: impl fmt::Write, cx: &Context<'_>, item: &clean::Item, parent: &clean::Item, @@ -1654,7 +1655,7 @@ fn render_impl( is_default_item: bool, trait_: Option<&clean::Trait>, rendering_params: ImplRenderingParameters, - ) { + ) -> fmt::Result { let item_type = item.type_(); let name = item.name.as_ref().unwrap(); @@ -1729,15 +1730,16 @@ fn render_impl( ); } } - let w = if short_documented && trait_.is_some() { interesting } else { boring }; + let mut w = if short_documented && trait_.is_some() { + Either::Left(interesting) + } else { + Either::Right(boring) + }; let toggled = !doc_buffer.is_empty(); if toggled { let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; - write_str( - w, - format_args!("
"), - ); + write!(w, "
")?; } match &item.kind { clean::MethodItem(..) | clean::RequiredMethodItem(_) => { @@ -1752,172 +1754,151 @@ fn render_impl( .find(|item| item.name.map(|n| n == *name).unwrap_or(false)) }) .map(|item| format!("{}.{name}", item.type_())); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode) + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - render_assoc_item( - item, - link.anchor(source_id.as_ref().unwrap_or(&id)), - ItemType::Impl, - cx, - render_mode, - ), + "

{}

", + render_assoc_item( + item, + link.anchor(source_id.as_ref().unwrap_or(&id)), + ItemType::Impl, + cx, + render_mode, ), - ); + )?; } } clean::RequiredAssocConstItem(generics, ty) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode) + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - assoc_const( - item, - generics, - ty, - AssocConstValue::None, - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ) + "

{}

", + assoc_const( + item, + generics, + ty, + AssocConstValue::None, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, ), - ); + )?; } clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode), + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - assoc_const( - item, - &ci.generics, - &ci.type_, - match item.kind { - clean::ProvidedAssocConstItem(_) => - AssocConstValue::TraitDefault(&ci.kind), - clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind), - _ => unreachable!(), - }, - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ) + "

{}

", + assoc_const( + item, + &ci.generics, + &ci.type_, + match item.kind { + clean::ProvidedAssocConstItem(_) => + AssocConstValue::TraitDefault(&ci.kind), + clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind), + _ => unreachable!(), + }, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, ), - ); + )?; } clean::RequiredAssocTypeItem(generics, bounds) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode), + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - assoc_type( - item, - generics, - bounds, - None, - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ) + "

{}

", + assoc_type( + item, + generics, + bounds, + None, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, ), - ); + )?; } clean::AssocTypeItem(tydef, _bounds) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); - write_str( + write!( w, - format_args!( - "
\ + "
\ {}", - render_rightside(cx, item, render_mode) - ), - ); + render_rightside(cx, item, render_mode), + )?; if trait_.is_some() { // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + write!(w, "§")?; } - write_str( + write!( w, - format_args!( - "

{}

", - assoc_type( - item, - &tydef.generics, - &[], // intentionally leaving out bounds - Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)), - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ) + "

{}

", + assoc_type( + item, + &tydef.generics, + &[], // intentionally leaving out bounds + Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)), + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, ), - ); + )?; } - clean::StrippedItem(..) => return, + clean::StrippedItem(..) => return Ok(()), _ => panic!("can't make docs for trait item with name {:?}", item.name), } - w.push_str(&info_buffer); + w.write_str(&info_buffer)?; if toggled { - w.push_str("
"); - w.push_str(&doc_buffer); - w.push_str("
"); + write!(w, "
{doc_buffer}
")?; } + Ok(()) } let mut impl_items = String::new(); @@ -1960,7 +1941,7 @@ fn render_impl( false, trait_, rendering_params, - ); + )?; } _ => {} } @@ -1978,7 +1959,7 @@ fn render_impl( false, trait_, rendering_params, - ); + )?; } for method in methods { doc_impl_item( @@ -1992,20 +1973,20 @@ fn render_impl( false, trait_, rendering_params, - ); + )?; } } fn render_default_items( - boring: &mut String, - interesting: &mut String, + mut boring: impl fmt::Write, + mut interesting: impl fmt::Write, cx: &Context<'_>, t: &clean::Trait, i: &clean::Impl, parent: &clean::Item, render_mode: RenderMode, rendering_params: ImplRenderingParameters, - ) { + ) -> fmt::Result { for trait_item in &t.items { // Skip over any default trait items that are impossible to reference // (e.g. if it has a `Self: Sized` bound on an unsized type). @@ -2025,8 +2006,8 @@ fn render_impl( let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods); doc_impl_item( - boring, - interesting, + &mut boring, + &mut interesting, cx, trait_item, parent, @@ -2035,8 +2016,9 @@ fn render_impl( true, Some(t), rendering_params, - ); + )?; } + Ok(()) } // If we've implemented a trait, then also emit documentation for all @@ -2056,7 +2038,7 @@ fn render_impl( &i.impl_item, render_mode, rendering_params, - ); + )?; } } if render_mode == RenderMode::Normal { From 8dd1cbbdad2ba128c8237714665ef25b86e9945d Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Thu, 13 Mar 2025 13:34:00 +0000 Subject: [PATCH 042/222] lazify `render_assoc_items_inner` --- src/librustdoc/html/render/mod.rs | 91 ++++++++++++++++++------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 511a9316aff3..94171ad6de80 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -40,6 +40,7 @@ mod span_map; mod type_layout; mod write_shared; +use std::borrow::Cow; use std::collections::VecDeque; use std::fmt::{self, Display as _, Write}; use std::iter::Peekable; @@ -99,6 +100,19 @@ enum AssocItemRender<'a> { DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, } +impl AssocItemRender<'_> { + fn render_mode(&self) -> RenderMode { + match self { + Self::All => RenderMode::Normal, + &Self::DerefFor { deref_mut_, .. } => RenderMode::ForDeref { mut_: deref_mut_ }, + } + } + + fn class(&self) -> Option<&'static str> { + if let Self::DerefFor { .. } = self { Some("impl-items") } else { None } + } +} + /// For different handling of associated items from the Deref target of a type rather than the type /// itself. #[derive(Copy, Clone, PartialEq)] @@ -1211,7 +1225,7 @@ impl<'a> AssocItemLink<'a> { } fn write_section_heading( - title: &str, + title: impl fmt::Display, id: &str, extra_class: Option<&str>, extra: impl fmt::Display, @@ -1231,7 +1245,7 @@ fn write_section_heading( }) } -fn write_impl_section_heading(title: &str, id: &str) -> impl fmt::Display { +fn write_impl_section_heading(title: impl fmt::Display, id: &str) -> impl fmt::Display { write_section_heading(title, id, None, "") } @@ -1308,20 +1322,17 @@ fn render_assoc_items_inner( let (mut non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { - let mut close_tags = >::with_capacity(1); - let mut tmp_buf = String::new(); - let (render_mode, id, class_html) = match what { - AssocItemRender::All => { - write_str( - &mut tmp_buf, - format_args!( - "{}", - write_impl_section_heading("Implementations", "implementations") - ), - ); - (RenderMode::Normal, "implementations-list".to_owned(), "") - } - AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { + let render_mode = what.render_mode(); + let class_html = what + .class() + .map(|class| fmt::from_fn(move |f| write!(f, r#" class="{class}""#))) + .maybe_display(); + let (section_heading, id) = match what { + AssocItemRender::All => ( + Either::Left(write_impl_section_heading("Implementations", "implementations")), + Cow::Borrowed("implementations-list"), + ), + AssocItemRender::DerefFor { trait_, type_, .. } => { let id = cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx)))); // the `impls.get` above only looks at the outermost type, @@ -1335,25 +1346,27 @@ fn render_assoc_items_inner( type_.is_doc_subtype_of(&impl_.inner_impl().for_, &cx.shared.cache) }); let derived_id = cx.derive_id(&id); - close_tags.push(""); - write_str( - &mut tmp_buf, - format_args!( - "
{}", - write_impl_section_heading( - &format!( - "Methods from {trait_}<Target = {type_}>", - trait_ = trait_.print(cx), - type_ = type_.print(cx), - ), - &id, - ) - ), - ); if let Some(def_id) = type_.def_id(cx.cache()) { - cx.deref_id_map.borrow_mut().insert(def_id, id); + cx.deref_id_map.borrow_mut().insert(def_id, id.clone()); } - (RenderMode::ForDeref { mut_: deref_mut_ }, derived_id, r#" class="impl-items""#) + ( + Either::Right(fmt::from_fn(move |f| { + write!( + f, + "
{}", + write_impl_section_heading( + fmt::from_fn(|f| write!( + f, + "Methods from {trait_}<Target = {type_}>", + trait_ = trait_.print(cx), + type_ = type_.print(cx), + )), + &id, + ) + ) + })), + Cow::Owned(derived_id), + ) } }; let mut impls_buf = String::new(); @@ -1381,10 +1394,14 @@ fn render_assoc_items_inner( ); } if !impls_buf.is_empty() { - write!(w, "{tmp_buf}
{impls_buf}
").unwrap(); - for tag in close_tags.into_iter().rev() { - w.write_str(tag).unwrap(); - } + write!( + w, + "{section_heading}
{impls_buf}
{}", + matches!(what, AssocItemRender::DerefFor { .. }) + .then_some("
") + .maybe_display(), + ) + .unwrap(); } } From 74ca12951ce22dfea4f11131f8f244038d4b5f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 10 Apr 2025 17:40:48 +0200 Subject: [PATCH 043/222] Bump `FileEncoder` buffer size to 64 kB --- compiler/rustc_serialize/src/opaque.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 81f6266f8d1f..0a55504a556d 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -19,7 +19,7 @@ pub type FileEncodeResult = Result; pub const MAGIC_END_BYTES: &[u8] = b"rust-end-file"; /// The size of the buffer in `FileEncoder`. -const BUF_SIZE: usize = 8192; +const BUF_SIZE: usize = 64 * 1024; /// `FileEncoder` encodes data to file via fixed-size buffer. /// From 0069cadb9aa28ebd5dce748b1cc2e194d7e85fe7 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Thu, 10 Apr 2025 18:06:32 +0000 Subject: [PATCH 044/222] Micro-optimize `InstSimplify`'s `simplify_primitive_clone` --- .../rustc_mir_transform/src/instsimplify.rs | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 2eff6b31372f..2ecae196de98 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -10,7 +10,6 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, layout}; use rustc_span::{DUMMY_SP, Symbol, sym}; use crate::simplify::simplify_duplicate_switch_targets; -use crate::take_array; pub(super) enum InstSimplify { BeforeInline, @@ -229,7 +228,9 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { terminator: &mut Terminator<'tcx>, statements: &mut Vec>, ) { - let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind + let TerminatorKind::Call { + func, args, destination, target: Some(destination_block), .. + } = &terminator.kind else { return; }; @@ -237,15 +238,8 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { // It's definitely not a clone if there are multiple arguments let [arg] = &args[..] else { return }; - let Some(destination_block) = *target else { return }; - // Only bother looking more if it's easy to know what we're calling - let Some((fn_def_id, fn_args)) = func.const_fn_def() else { return }; - - // Clone needs one arg, so we can cheaply rule out other stuff - if fn_args.len() != 1 { - return; - } + let Some((fn_def_id, ..)) = func.const_fn_def() else { return }; // These types are easily available from locals, so check that before // doing DefId lookups to figure out what we're actually calling. @@ -253,15 +247,12 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return }; - if !inner_ty.is_trivially_pure_clone_copy() { + if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn) + || !inner_ty.is_trivially_pure_clone_copy() + { return; } - if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn) { - return; - } - - let Ok([arg]) = take_array(args) else { return }; let Some(arg_place) = arg.node.place() else { return }; statements.push(Statement { @@ -273,7 +264,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { )), ))), }); - terminator.kind = TerminatorKind::Goto { target: destination_block }; + terminator.kind = TerminatorKind::Goto { target: *destination_block }; } fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) { From 22dd86c015da5074037a821c5b99013cd98b9029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 6 Apr 2025 17:28:08 +0200 Subject: [PATCH 045/222] Encode dep node edge count as u32 instead of usize --- .../src/dep_graph/serialized.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 7750d6d1fef4..38100242ebff 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -226,12 +226,12 @@ impl SerializedDepGraph { // If the length of this node's edge list is small, the length is stored in the header. // If it is not, we fall back to another decoder call. - let num_edges = node_header.len().unwrap_or_else(|| d.read_usize()); + let num_edges = node_header.len().unwrap_or_else(|| d.read_u32()); // The edges index list uses the same varint strategy as rmeta tables; we select the // number of byte elements per-array not per-element. This lets us read the whole edge // list for a node with one decoder call and also use the on-disk format in memory. - let edges_len_bytes = node_header.bytes_per_index() * num_edges; + let edges_len_bytes = node_header.bytes_per_index() * (num_edges as usize); // The in-memory structure for the edges list stores the byte width of the edges on // this node with the offset into the global edge data array. let edges_header = node_header.edges_header(&edge_list_data); @@ -296,7 +296,7 @@ struct SerializedNodeHeader { // The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only // to make the implementation of `SerializedNodeHeader` simpler. struct Unpacked { - len: Option, + len: Option, bytes_per_index: usize, kind: DepKind, hash: PackedFingerprint, @@ -352,7 +352,7 @@ impl SerializedNodeHeader { assert_eq!(fingerprint, res.fingerprint()); assert_eq!(node, res.node()); if let Some(len) = res.len() { - assert_eq!(edge_count, len); + assert_eq!(edge_count, len as usize); } } Self { bytes, _marker: PhantomData } @@ -366,7 +366,7 @@ impl SerializedNodeHeader { let kind = head & mask(Self::KIND_BITS) as u16; let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16; - let len = (head as usize) >> (Self::WIDTH_BITS + Self::KIND_BITS); + let len = (head as u32) >> (Self::WIDTH_BITS + Self::KIND_BITS); Unpacked { len: len.checked_sub(1), @@ -378,7 +378,7 @@ impl SerializedNodeHeader { } #[inline] - fn len(&self) -> Option { + fn len(&self) -> Option { self.unpack().len } @@ -421,7 +421,8 @@ impl NodeInfo { e.write_array(header.bytes); if header.len().is_none() { - e.emit_usize(edges.len()); + // The edges are all unique and the number of unique indices is less than u32::MAX. + e.emit_u32(edges.len().try_into().unwrap()); } let bytes_per_index = header.bytes_per_index(); @@ -456,7 +457,8 @@ impl NodeInfo { e.write_array(header.bytes); if header.len().is_none() { - e.emit_usize(edge_count); + // The edges are all unique and the number of unique indices is less than u32::MAX. + e.emit_u32(edge_count.try_into().unwrap()); } let bytes_per_index = header.bytes_per_index(); From 0ca31277f3198a5b4371adafbd9148e3136074d4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 10 Apr 2025 10:34:55 +0300 Subject: [PATCH 046/222] compiletest: Make `SUGGESTION` annotations viral --- src/tools/compiletest/src/header.rs | 2 +- src/tools/compiletest/src/runtest.rs | 11 ++++++++-- tests/ui/async-await/suggest-missing-await.rs | 1 + .../async-await/suggest-missing-await.stderr | 22 +++++++++---------- tests/ui/cast/cast-as-bool.rs | 2 ++ tests/ui/cast/cast-as-bool.stderr | 22 +++++++++---------- tests/ui/fn/suggest-return-closure.rs | 1 + tests/ui/fn/suggest-return-closure.stderr | 6 ++--- tests/ui/parser/inverted-parameters.rs | 2 ++ tests/ui/parser/inverted-parameters.stderr | 12 +++++----- tests/ui/suggestions/suggest-ref-mut.rs | 2 ++ tests/ui/suggestions/suggest-ref-mut.stderr | 8 +++---- .../issue-90027-async-fn-return-suggestion.rs | 1 + ...ue-90027-async-fn-return-suggestion.stderr | 8 +++---- 14 files changed, 58 insertions(+), 42 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 01a6ae00825d..b64f01169a00 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -306,7 +306,7 @@ impl TestProps { (ErrorKind::Note, true), (ErrorKind::Error, true), (ErrorKind::Warning, true), - (ErrorKind::Suggestion, false), + (ErrorKind::Suggestion, true), ]), } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 9c03fa141bd3..3fbc95f5862b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -711,6 +711,7 @@ impl<'test> TestCx<'test> { let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help)); let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note)); + let expect_sugg = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Suggestion)); // Parse the JSON output from the compiler and extract out the messages. let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res); @@ -737,8 +738,12 @@ impl<'test> TestCx<'test> { None => { // If the test is a known bug, don't require that the error is annotated - if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note) - { + if self.is_unexpected_compiler_message( + &actual_error, + expect_help, + expect_note, + expect_sugg, + ) { self.error(&format!( "{}:{}: unexpected {}: '{}'", file_name, @@ -802,6 +807,7 @@ impl<'test> TestCx<'test> { actual_error: &Error, expect_help: bool, expect_note: bool, + expect_sugg: bool, ) -> bool { actual_error.require_annotation && actual_error.kind.map_or(false, |err_kind| { @@ -811,6 +817,7 @@ impl<'test> TestCx<'test> { match err_kind { ErrorKind::Help => expect_help && default_require_annotations, ErrorKind::Note => expect_note && default_require_annotations, + ErrorKind::Suggestion => expect_sugg && default_require_annotations, _ => default_require_annotations, } }) diff --git a/tests/ui/async-await/suggest-missing-await.rs b/tests/ui/async-await/suggest-missing-await.rs index 989792825cf8..8a9c7cfe9800 100644 --- a/tests/ui/async-await/suggest-missing-await.rs +++ b/tests/ui/async-await/suggest-missing-await.rs @@ -1,4 +1,5 @@ //@ edition:2018 +//@ dont-require-annotations:SUGGESTION fn take_u32(_x: u32) {} diff --git a/tests/ui/async-await/suggest-missing-await.stderr b/tests/ui/async-await/suggest-missing-await.stderr index f9db86ea40a9..9db7eb980eff 100644 --- a/tests/ui/async-await/suggest-missing-await.stderr +++ b/tests/ui/async-await/suggest-missing-await.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:12:14 + --> $DIR/suggest-missing-await.rs:13:14 | LL | take_u32(x) | -------- ^ expected `u32`, found future @@ -7,12 +7,12 @@ LL | take_u32(x) | arguments to this function are incorrect | note: calling an async function returns a future - --> $DIR/suggest-missing-await.rs:12:14 + --> $DIR/suggest-missing-await.rs:13:14 | LL | take_u32(x) | ^ note: function defined here - --> $DIR/suggest-missing-await.rs:3:4 + --> $DIR/suggest-missing-await.rs:4:4 | LL | fn take_u32(_x: u32) {} | ^^^^^^^^ ------- @@ -22,13 +22,13 @@ LL | take_u32(x.await) | ++++++ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:22:5 + --> $DIR/suggest-missing-await.rs:23:5 | LL | dummy() | ^^^^^^^ expected `()`, found future | note: calling an async function returns a future - --> $DIR/suggest-missing-await.rs:22:5 + --> $DIR/suggest-missing-await.rs:23:5 | LL | dummy() | ^^^^^^^ @@ -42,7 +42,7 @@ LL | dummy(); | + error[E0308]: `if` and `else` have incompatible types - --> $DIR/suggest-missing-await.rs:35:9 + --> $DIR/suggest-missing-await.rs:36:9 | LL | let _x = if true { | ______________- @@ -64,7 +64,7 @@ LL | dummy().await | ++++++ error[E0308]: `match` arms have incompatible types - --> $DIR/suggest-missing-await.rs:45:14 + --> $DIR/suggest-missing-await.rs:46:14 | LL | let _x = match 0usize { | ______________- @@ -87,7 +87,7 @@ LL ~ 1 => dummy().await, | error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:53:9 + --> $DIR/suggest-missing-await.rs:54:9 | LL | let _x = match dummy() { | ------- this expression has type `impl Future` @@ -102,7 +102,7 @@ LL | let _x = match dummy().await { | ++++++ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:67:9 + --> $DIR/suggest-missing-await.rs:68:9 | LL | match dummy_result() { | -------------- this expression has type `impl Future>` @@ -118,7 +118,7 @@ LL | match dummy_result().await { | ++++++ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:69:9 + --> $DIR/suggest-missing-await.rs:70:9 | LL | match dummy_result() { | -------------- this expression has type `impl Future>` @@ -134,7 +134,7 @@ LL | match dummy_result().await { | ++++++ error[E0308]: mismatched types - --> $DIR/suggest-missing-await.rs:77:27 + --> $DIR/suggest-missing-await.rs:78:27 | LL | Some(do_async()).map(|()| {}); | ^^ diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs index 511a02718fe2..8f3555094e0a 100644 --- a/tests/ui/cast/cast-as-bool.rs +++ b/tests/ui/cast/cast-as-bool.rs @@ -1,3 +1,5 @@ +//@ dont-require-annotations:SUGGESTION + fn main() { let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool` //~| HELP compare with zero instead diff --git a/tests/ui/cast/cast-as-bool.stderr b/tests/ui/cast/cast-as-bool.stderr index b2c9ae5c6ad6..25377ebebe2b 100644 --- a/tests/ui/cast/cast-as-bool.stderr +++ b/tests/ui/cast/cast-as-bool.stderr @@ -1,5 +1,5 @@ error[E0054]: cannot cast `i32` as `bool` - --> $DIR/cast-as-bool.rs:2:13 + --> $DIR/cast-as-bool.rs:4:13 | LL | let u = 5 as bool; | ^^^^^^^^^ @@ -11,7 +11,7 @@ LL + let u = 5 != 0; | error[E0054]: cannot cast `i32` as `bool` - --> $DIR/cast-as-bool.rs:6:13 + --> $DIR/cast-as-bool.rs:8:13 | LL | let t = (1 + 2) as bool; | ^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL + let t = (1 + 2) != 0; | error[E0054]: cannot cast `u32` as `bool` - --> $DIR/cast-as-bool.rs:10:13 + --> $DIR/cast-as-bool.rs:12:13 | LL | let _ = 5_u32 as bool; | ^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL + let _ = 5_u32 != 0; | error[E0054]: cannot cast `f64` as `bool` - --> $DIR/cast-as-bool.rs:13:13 + --> $DIR/cast-as-bool.rs:15:13 | LL | let _ = 64.0_f64 as bool; | ^^^^^^^^^^^^^^^^ @@ -47,43 +47,43 @@ LL + let _ = 64.0_f64 != 0; | error[E0054]: cannot cast `IntEnum` as `bool` - --> $DIR/cast-as-bool.rs:24:13 + --> $DIR/cast-as-bool.rs:26:13 | LL | let _ = IntEnum::One as bool; | ^^^^^^^^^^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `fn(u8) -> String {uwu}` as `bool` - --> $DIR/cast-as-bool.rs:33:13 + --> $DIR/cast-as-bool.rs:35:13 | LL | let _ = uwu as bool; | ^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `unsafe fn() {owo}` as `bool` - --> $DIR/cast-as-bool.rs:35:13 + --> $DIR/cast-as-bool.rs:37:13 | LL | let _ = owo as bool; | ^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `fn(u8) -> String` as `bool` - --> $DIR/cast-as-bool.rs:38:13 + --> $DIR/cast-as-bool.rs:40:13 | LL | let _ = uwu as fn(u8) -> String as bool; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `char` as `bool` - --> $DIR/cast-as-bool.rs:40:13 + --> $DIR/cast-as-bool.rs:42:13 | LL | let _ = 'x' as bool; | ^^^^^^^^^^^ unsupported cast error[E0054]: cannot cast `*const ()` as `bool` - --> $DIR/cast-as-bool.rs:44:13 + --> $DIR/cast-as-bool.rs:46:13 | LL | let _ = ptr as bool; | ^^^^^^^^^^^ unsupported cast error[E0606]: casting `&'static str` as `bool` is invalid - --> $DIR/cast-as-bool.rs:46:13 + --> $DIR/cast-as-bool.rs:48:13 | LL | let v = "hello" as bool; | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/fn/suggest-return-closure.rs b/tests/ui/fn/suggest-return-closure.rs index 30e25ca8edcc..67be8de92431 100644 --- a/tests/ui/fn/suggest-return-closure.rs +++ b/tests/ui/fn/suggest-return-closure.rs @@ -19,6 +19,7 @@ fn fn_mut() -> _ { let x = String::new(); //~^ HELP: consider changing this to be mutable //~| NOTE binding `x` declared here + //~| SUGGESTION mut |c| { //~ NOTE: value captured here x.push(c); //~^ ERROR: does not live long enough diff --git a/tests/ui/fn/suggest-return-closure.stderr b/tests/ui/fn/suggest-return-closure.stderr index 45c12b548e67..1860d1ca5d92 100644 --- a/tests/ui/fn/suggest-return-closure.stderr +++ b/tests/ui/fn/suggest-return-closure.stderr @@ -21,7 +21,7 @@ LL | fn fn_mut() -> _ { = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types - --> $DIR/suggest-return-closure.rs:32:13 + --> $DIR/suggest-return-closure.rs:33:13 | LL | fn fun() -> _ { | ^ @@ -32,7 +32,7 @@ LL | fn fun() -> _ { = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/suggest-return-closure.rs:23:9 + --> $DIR/suggest-return-closure.rs:24:9 | LL | x.push(c); | ^ cannot borrow as mutable @@ -43,7 +43,7 @@ LL | let mut x = String::new(); | +++ error[E0597]: `x` does not live long enough - --> $DIR/suggest-return-closure.rs:23:9 + --> $DIR/suggest-return-closure.rs:24:9 | LL | let x = String::new(); | - binding `x` declared here diff --git a/tests/ui/parser/inverted-parameters.rs b/tests/ui/parser/inverted-parameters.rs index 5c4272504e06..3bfa8e82d6cb 100644 --- a/tests/ui/parser/inverted-parameters.rs +++ b/tests/ui/parser/inverted-parameters.rs @@ -1,3 +1,5 @@ +//@ dont-require-annotations:SUGGESTION + struct S; impl S { diff --git a/tests/ui/parser/inverted-parameters.stderr b/tests/ui/parser/inverted-parameters.stderr index 866227782039..7b969032d0f9 100644 --- a/tests/ui/parser/inverted-parameters.stderr +++ b/tests/ui/parser/inverted-parameters.stderr @@ -1,5 +1,5 @@ error: expected one of `:`, `@`, or `|`, found `bar` - --> $DIR/inverted-parameters.rs:4:24 + --> $DIR/inverted-parameters.rs:6:24 | LL | fn foo(&self, &str bar) {} | -----^^^ @@ -8,7 +8,7 @@ LL | fn foo(&self, &str bar) {} | help: declare the type after the parameter binding: `: ` error: expected one of `:`, `@`, or `|`, found `quux` - --> $DIR/inverted-parameters.rs:10:10 + --> $DIR/inverted-parameters.rs:12:10 | LL | fn baz(S quux, xyzzy: i32) {} | --^^^^ @@ -17,19 +17,19 @@ LL | fn baz(S quux, xyzzy: i32) {} | help: declare the type after the parameter binding: `: ` error: expected one of `:`, `@`, or `|`, found `a` - --> $DIR/inverted-parameters.rs:15:12 + --> $DIR/inverted-parameters.rs:17:12 | LL | fn one(i32 a b) {} | ^ expected one of `:`, `@`, or `|` error: expected one of `:` or `|`, found `(` - --> $DIR/inverted-parameters.rs:18:23 + --> $DIR/inverted-parameters.rs:20:23 | LL | fn pattern((i32, i32) (a, b)) {} | ^ expected one of `:` or `|` error: expected one of `:`, `@`, or `|`, found `)` - --> $DIR/inverted-parameters.rs:21:12 + --> $DIR/inverted-parameters.rs:23:12 | LL | fn fizz(i32) {} | ^ expected one of `:`, `@`, or `|` @@ -49,7 +49,7 @@ LL | fn fizz(_: i32) {} | ++ error: expected one of `:`, `@`, or `|`, found `S` - --> $DIR/inverted-parameters.rs:27:23 + --> $DIR/inverted-parameters.rs:29:23 | LL | fn missing_colon(quux S) {} | -----^ diff --git a/tests/ui/suggestions/suggest-ref-mut.rs b/tests/ui/suggestions/suggest-ref-mut.rs index 9f5df9303c33..e9baeb8b0ead 100644 --- a/tests/ui/suggestions/suggest-ref-mut.rs +++ b/tests/ui/suggestions/suggest-ref-mut.rs @@ -1,3 +1,5 @@ +//@ dont-require-annotations:SUGGESTION + struct X(usize); impl X { diff --git a/tests/ui/suggestions/suggest-ref-mut.stderr b/tests/ui/suggestions/suggest-ref-mut.stderr index 935a04c052ac..7c0899f0fbc1 100644 --- a/tests/ui/suggestions/suggest-ref-mut.stderr +++ b/tests/ui/suggestions/suggest-ref-mut.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `self.0`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:7:9 + --> $DIR/suggest-ref-mut.rs:9:9 | LL | self.0 = 32; | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written @@ -10,7 +10,7 @@ LL | fn zap(&mut self) { | +++ error[E0594]: cannot assign to `*foo`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:15:5 + --> $DIR/suggest-ref-mut.rs:17:5 | LL | *foo = 32; | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written @@ -21,7 +21,7 @@ LL | let ref mut foo = 16; | +++ error[E0594]: cannot assign to `*bar`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:19:9 + --> $DIR/suggest-ref-mut.rs:21:9 | LL | *bar = 32; | ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written @@ -32,7 +32,7 @@ LL | if let Some(ref mut bar) = Some(16) { | +++ error[E0594]: cannot assign to `*quo`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:23:22 + --> $DIR/suggest-ref-mut.rs:25:22 | LL | ref quo => { *quo = 32; }, | ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs index 0be1237749fc..b9dbae6b57dc 100644 --- a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs +++ b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs @@ -1,4 +1,5 @@ //@ edition:2018 +//@ dont-require-annotations:SUGGESTION async fn hello() { //~ HELP try adding a return type 0 diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr index c46f4ec1ec30..3680df25f0ba 100644 --- a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr +++ b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-90027-async-fn-return-suggestion.rs:4:5 + --> $DIR/issue-90027-async-fn-return-suggestion.rs:5:5 | LL | async fn hello() { | - help: try adding a return type: `-> i32` @@ -7,7 +7,7 @@ LL | 0 | ^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/issue-90027-async-fn-return-suggestion.rs:9:5 + --> $DIR/issue-90027-async-fn-return-suggestion.rs:10:5 | LL | async fn world() -> () { | -- expected `()` because of return type @@ -15,13 +15,13 @@ LL | 0 | ^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5 + --> $DIR/issue-90027-async-fn-return-suggestion.rs:15:5 | LL | hello() | ^^^^^^^ expected `()`, found future | note: calling an async function returns a future - --> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5 + --> $DIR/issue-90027-async-fn-return-suggestion.rs:15:5 | LL | hello() | ^^^^^^^ From 909b6c9f83748008828b6c52d2d6281c460141e1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 10 Apr 2025 10:50:01 +0300 Subject: [PATCH 047/222] compiletest: Turn `TestProps::require_annotations` into a set and further simplify its checking in runtest --- src/tools/compiletest/src/header.rs | 16 +++------ src/tools/compiletest/src/runtest.rs | 49 ++++++++-------------------- 2 files changed, 19 insertions(+), 46 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index b64f01169a00..c53978af3f7d 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use std::env; use std::fs::File; use std::io::BufReader; @@ -198,7 +198,7 @@ pub struct TestProps { /// that don't otherwise want/need `-Z build-std`. pub add_core_stubs: bool, /// Whether line annotatins are required for the given error kind. - pub require_annotations: HashMap, + pub dont_require_annotations: HashSet, } mod directives { @@ -301,13 +301,7 @@ impl TestProps { no_auto_check_cfg: false, has_enzyme: false, add_core_stubs: false, - require_annotations: HashMap::from([ - (ErrorKind::Help, true), - (ErrorKind::Note, true), - (ErrorKind::Error, true), - (ErrorKind::Warning, true), - (ErrorKind::Suggestion, true), - ]), + dont_require_annotations: Default::default(), } } @@ -585,8 +579,8 @@ impl TestProps { if let Some(err_kind) = config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) { - self.require_annotations - .insert(ErrorKind::expect_from_user_str(&err_kind), false); + self.dont_require_annotations + .insert(ErrorKind::expect_from_user_str(&err_kind)); } }, ); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 3fbc95f5862b..999552c99dad 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -22,7 +22,7 @@ use crate::common::{ output_base_dir, output_base_name, output_testname_unique, }; use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; -use crate::errors::{self, Error, ErrorKind}; +use crate::errors::{Error, ErrorKind}; use crate::header::TestProps; use crate::read2::{Truncated, read2_abbreviated}; use crate::util::{PathBufExt, add_dylib_path, logv, static_regex}; @@ -674,7 +674,7 @@ impl<'test> TestCx<'test> { } } - fn check_expected_errors(&self, expected_errors: Vec, proc_res: &ProcRes) { + fn check_expected_errors(&self, expected_errors: Vec, proc_res: &ProcRes) { debug!( "check_expected_errors: expected_errors={:?} proc_res.status={:?}", expected_errors, proc_res.status @@ -709,9 +709,12 @@ impl<'test> TestCx<'test> { self.testpaths.file.display().to_string() }; - let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help)); - let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note)); - let expect_sugg = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Suggestion)); + // Errors and warnings are always expected, other diagnostics are only expected + // if one of them actually occurs in the test. + let expected_kinds: HashSet<_> = [ErrorKind::Error, ErrorKind::Warning] + .into_iter() + .chain(expected_errors.iter().filter_map(|e| e.kind)) + .collect(); // Parse the JSON output from the compiler and extract out the messages. let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res); @@ -737,13 +740,12 @@ impl<'test> TestCx<'test> { } None => { - // If the test is a known bug, don't require that the error is annotated - if self.is_unexpected_compiler_message( - &actual_error, - expect_help, - expect_note, - expect_sugg, - ) { + if actual_error.require_annotation + && actual_error.kind.map_or(false, |kind| { + expected_kinds.contains(&kind) + && !self.props.dont_require_annotations.contains(&kind) + }) + { self.error(&format!( "{}:{}: unexpected {}: '{}'", file_name, @@ -800,29 +802,6 @@ impl<'test> TestCx<'test> { } } - /// Returns `true` if we should report an error about `actual_error`, - /// which did not match any of the expected error. - fn is_unexpected_compiler_message( - &self, - actual_error: &Error, - expect_help: bool, - expect_note: bool, - expect_sugg: bool, - ) -> bool { - actual_error.require_annotation - && actual_error.kind.map_or(false, |err_kind| { - // If the test being checked doesn't contain any "help" or "note" annotations, then - // we don't require annotating "help" or "note" (respecively) diagnostics at all. - let default_require_annotations = self.props.require_annotations[&err_kind]; - match err_kind { - ErrorKind::Help => expect_help && default_require_annotations, - ErrorKind::Note => expect_note && default_require_annotations, - ErrorKind::Suggestion => expect_sugg && default_require_annotations, - _ => default_require_annotations, - } - }) - } - fn should_emit_metadata(&self, pm: Option) -> Emit { match (pm, self.props.fail_mode, self.config.mode) { (Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => Emit::Metadata, From ad72ba2e2c60322d07c90364e0ff161f422b2e40 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 10 Apr 2025 19:33:04 +0300 Subject: [PATCH 048/222] dev-guide: Document `dont-require-annotations` and its use cases in more detail --- .../rustc-dev-guide/src/tests/directives.md | 1 + src/doc/rustc-dev-guide/src/tests/ui.md | 55 +++++++++++++------ 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 8e4a710178ed..2ebd98f68686 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -101,6 +101,7 @@ for more details. | `normalize-stdout` | Normalize actual stdout with a rule `"" -> ""` before comparing against snapshot | `ui`, `incremental` | `"" -> ""`, ``/`` is regex capture and replace syntax | | `dont-check-compiler-stderr` | Don't check actual compiler stderr vs stderr snapshot | `ui` | N/A | | `dont-check-compiler-stdout` | Don't check actual compiler stdout vs stdout snapshot | `ui` | N/A | +| `dont-require-annotations` | Don't require line annotations for the given diagnostic kind (`//~ KIND`) to be exhaustive | `ui`, `incremental` | `ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` | | `run-rustfix` | Apply all suggestions via `rustfix`, snapshot fixed output, and check fixed output builds | `ui` | N/A | | `rustfix-only-machine-applicable` | `run-rustfix` but only machine-applicable suggestions | `ui` | N/A | | `exec-env` | Env var to set when executing a test | `ui`, `crashes` | `=` | diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index e862a07cae0a..3243a3535ac8 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -303,8 +303,7 @@ It should be preferred to using `error-pattern`, which is imprecise and non-exha ### `error-pattern` The `error-pattern` [directive](directives.md) can be used for runtime messages, which don't -have a specific span, or for compile time messages if imprecise matching is required due to -multi-line platform specific diagnostics. +have a specific span, or in exceptional cases for compile time messages. Let's think about this test: @@ -318,7 +317,7 @@ fn main() { ``` We want to ensure this shows "index out of bounds" but we cannot use the `ERROR` -annotation since the error doesn't have any span. Then it's time to use the +annotation since the runtime error doesn't have any span. Then it's time to use the `error-pattern` directive: ```rust,ignore @@ -331,29 +330,51 @@ fn main() { } ``` -But for strict testing, try to use the `ERROR` annotation as much as possible, -including `//~?` annotations for diagnostics without span. -For compile time diagnostics `error-pattern` should very rarely be necessary. +Use of `error-pattern` is not recommended in general. -Per-line annotations (`//~`) are still checked in tests using `error-pattern`. -To opt out of these checks, use `//@ compile-flags: --error-format=human`. -Do that only in exceptional cases. +For strict testing of compile time output, try to use the line annotations `//~` as much as +possible, including `//~?` annotations for diagnostics without span. -### Error levels +If the compile time output is target dependent or too verbose, use directive +`//@ dont-require-annotations: ` to make the line annotation checking +non-exhaustive, some of the compiler messages can stay uncovered by annotations in this mode. -The error levels that you can have are: +For checking runtime output `//@ check-run-results` may be preferable. + +Only use `error-pattern` if none of the above works. + +Line annotations `//~` are still checked in tests using `error-pattern`. +In exceptional cases use `//@ compile-flags: --error-format=human` to opt out of these checks. + +### Diagnostic kinds (error levels) + +The diagnostic kinds that you can have are: - `ERROR` -- `WARN` or `WARNING` +- `WARN` (or `WARNING`) - `NOTE` -- `HELP` and `SUGGESTION` +- `HELP` +- `SUGGESTION` -You are allowed to not include a level, but you should include it at least for -the primary message. - -The `SUGGESTION` level is used for specifying what the expected replacement text +The `SUGGESTION` kind is used for specifying what the expected replacement text should be for a diagnostic suggestion. +`ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations +`//~` by default. + +Other kinds only need to be line-annotated if at least one annotation of that kind appears +in the test file. For example, one `//~ NOTE` will also require all other `//~ NOTE`s in the file +to be written out explicitly. + +Use directive `//@ dont-require-annotations` to opt out of exhaustive annotations. +E.g. use `//@ dont-require-annotations: NOTE` to annotate notes selectively. +Avoid using this directive for `ERROR`s and `WARN`ings, unless there's a serious reason, like +target-dependent compiler output. + +Missing diagnostic kinds (`//~ message`) are currently accepted, but are being phased away. +They will match any compiler output kind, but will not force exhaustive annotations for that kind. +Prefer explicit kind and `//@ dont-require-annotations` to achieve the same effect. + UI tests use the `-A unused` flag by default to ignore all unused warnings, as unused warnings are usually not the focus of a test. However, simple code samples often have unused warnings. If the test is specifically testing an From 06dd9e2d20db8ba9b260fa750f09ea969fb57b87 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 10 Apr 2025 23:39:05 +0300 Subject: [PATCH 049/222] compiletest: Trim the value of `dont-require-annotations` --- src/tools/compiletest/src/header.rs | 2 +- tests/ui/async-await/suggest-missing-await.rs | 2 +- tests/ui/cast/cast-as-bool.rs | 2 +- tests/ui/cfg/cfg_false_no_std-2.rs | 2 +- tests/ui/panic-runtime/two-panic-runtimes.rs | 2 +- tests/ui/panic-runtime/want-abort-got-unwind.rs | 2 +- tests/ui/panic-runtime/want-abort-got-unwind2.rs | 2 +- tests/ui/parser/inverted-parameters.rs | 2 +- tests/ui/suggestions/suggest-ref-mut.rs | 2 +- tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c53978af3f7d..1fd9022ed97e 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -580,7 +580,7 @@ impl TestProps { config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) { self.dont_require_annotations - .insert(ErrorKind::expect_from_user_str(&err_kind)); + .insert(ErrorKind::expect_from_user_str(err_kind.trim())); } }, ); diff --git a/tests/ui/async-await/suggest-missing-await.rs b/tests/ui/async-await/suggest-missing-await.rs index 8a9c7cfe9800..de0b2ce52b69 100644 --- a/tests/ui/async-await/suggest-missing-await.rs +++ b/tests/ui/async-await/suggest-missing-await.rs @@ -1,5 +1,5 @@ //@ edition:2018 -//@ dont-require-annotations:SUGGESTION +//@ dont-require-annotations: SUGGESTION fn take_u32(_x: u32) {} diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs index 8f3555094e0a..fa9664e572c0 100644 --- a/tests/ui/cast/cast-as-bool.rs +++ b/tests/ui/cast/cast-as-bool.rs @@ -1,4 +1,4 @@ -//@ dont-require-annotations:SUGGESTION +//@ dont-require-annotations: SUGGESTION fn main() { let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool` diff --git a/tests/ui/cfg/cfg_false_no_std-2.rs b/tests/ui/cfg/cfg_false_no_std-2.rs index 349c49412ffa..18b2c699fd7a 100644 --- a/tests/ui/cfg/cfg_false_no_std-2.rs +++ b/tests/ui/cfg/cfg_false_no_std-2.rs @@ -1,6 +1,6 @@ // Error, the linked empty library is `no_std` and doesn't provide a panic handler. -//@ dont-require-annotations:ERROR +//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build: cfg_false_lib_no_std_before.rs diff --git a/tests/ui/panic-runtime/two-panic-runtimes.rs b/tests/ui/panic-runtime/two-panic-runtimes.rs index 7add07ef6004..80591edd1077 100644 --- a/tests/ui/panic-runtime/two-panic-runtimes.rs +++ b/tests/ui/panic-runtime/two-panic-runtimes.rs @@ -1,6 +1,6 @@ // ignore-tidy-linelength //@ build-fail -//@ dont-require-annotations:ERROR +//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind2.rs diff --git a/tests/ui/panic-runtime/want-abort-got-unwind.rs b/tests/ui/panic-runtime/want-abort-got-unwind.rs index 1ae2e623f103..42cdf8bc6626 100644 --- a/tests/ui/panic-runtime/want-abort-got-unwind.rs +++ b/tests/ui/panic-runtime/want-abort-got-unwind.rs @@ -1,6 +1,6 @@ // ignore-tidy-linelength //@ build-fail -//@ dont-require-annotations:ERROR +//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ compile-flags:-C panic=abort diff --git a/tests/ui/panic-runtime/want-abort-got-unwind2.rs b/tests/ui/panic-runtime/want-abort-got-unwind2.rs index dc4d3ea86d86..ddf12cd2a9a5 100644 --- a/tests/ui/panic-runtime/want-abort-got-unwind2.rs +++ b/tests/ui/panic-runtime/want-abort-got-unwind2.rs @@ -1,6 +1,6 @@ // ignore-tidy-linelength //@ build-fail -//@ dont-require-annotations:ERROR +//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ aux-build:wants-panic-runtime-unwind.rs diff --git a/tests/ui/parser/inverted-parameters.rs b/tests/ui/parser/inverted-parameters.rs index 3bfa8e82d6cb..bc2f53f0be1b 100644 --- a/tests/ui/parser/inverted-parameters.rs +++ b/tests/ui/parser/inverted-parameters.rs @@ -1,4 +1,4 @@ -//@ dont-require-annotations:SUGGESTION +//@ dont-require-annotations: SUGGESTION struct S; diff --git a/tests/ui/suggestions/suggest-ref-mut.rs b/tests/ui/suggestions/suggest-ref-mut.rs index e9baeb8b0ead..2a933f6305f6 100644 --- a/tests/ui/suggestions/suggest-ref-mut.rs +++ b/tests/ui/suggestions/suggest-ref-mut.rs @@ -1,4 +1,4 @@ -//@ dont-require-annotations:SUGGESTION +//@ dont-require-annotations: SUGGESTION struct X(usize); diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs index b9dbae6b57dc..dd833957a70a 100644 --- a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs +++ b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs @@ -1,5 +1,5 @@ //@ edition:2018 -//@ dont-require-annotations:SUGGESTION +//@ dont-require-annotations: SUGGESTION async fn hello() { //~ HELP try adding a return type 0 From 3375264fa1c6e7fe95b05c7c369f1f884dee1c91 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 10 Apr 2025 20:58:15 +0000 Subject: [PATCH 050/222] Fix `register_group_alias` for tools --- compiler/rustc_lint/src/context.rs | 97 ++++++++++++------------------ compiler/rustc_lint/src/levels.rs | 4 +- compiler/rustc_lint/src/lib.rs | 4 +- 3 files changed, 42 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 885a7308bdc6..9005bc929203 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -83,11 +83,6 @@ enum TargetLint { Ignored, } -pub enum FindLintError { - NotFound, - Removed, -} - struct LintAlias { name: &'static str, /// Whether deprecation warnings should be suppressed for this alias. @@ -231,13 +226,24 @@ impl LintStore { } } - pub fn register_group_alias(&mut self, lint_name: &'static str, alias: &'static str) { - self.lint_groups.insert( + fn insert_group(&mut self, name: &'static str, group: LintGroup) { + let previous = self.lint_groups.insert(name, group); + if previous.is_some() { + bug!("group {name:?} already exists"); + } + } + + pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) { + let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else { + bug!("group alias {alias:?} points to unregistered group {group_name:?}") + }; + + self.insert_group( alias, LintGroup { - lint_ids: vec![], + lint_ids: lint_ids.clone(), is_externally_loaded: false, - depr: Some(LintAlias { name: lint_name, silent: true }), + depr: Some(LintAlias { name: group_name, silent: true }), }, ); } @@ -249,24 +255,17 @@ impl LintStore { deprecated_name: Option<&'static str>, to: Vec, ) { - let new = self - .lint_groups - .insert(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None }) - .is_none(); if let Some(deprecated) = deprecated_name { - self.lint_groups.insert( + self.insert_group( deprecated, LintGroup { - lint_ids: vec![], + lint_ids: to.clone(), is_externally_loaded, depr: Some(LintAlias { name, silent: false }), }, ); } - - if !new { - bug!("duplicate specification of lint group {}", name); - } + self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None }); } /// This lint should give no warning and have no effect. @@ -292,23 +291,15 @@ impl LintStore { self.by_name.insert(name.into(), Removed(reason.into())); } - pub fn find_lints(&self, mut lint_name: &str) -> Result, FindLintError> { + pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> { match self.by_name.get(lint_name) { - Some(&Id(lint_id)) => Ok(vec![lint_id]), - Some(&Renamed(_, lint_id)) => Ok(vec![lint_id]), - Some(&Removed(_)) => Err(FindLintError::Removed), - Some(&Ignored) => Ok(vec![]), - None => loop { - return match self.lint_groups.get(lint_name) { - Some(LintGroup { lint_ids, depr, .. }) => { - if let Some(LintAlias { name, .. }) = depr { - lint_name = name; - continue; - } - Ok(lint_ids.clone()) - } - None => Err(FindLintError::Removed), - }; + Some(Id(lint_id)) => Some(slice::from_ref(lint_id)), + Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)), + Some(Removed(_)) => None, + Some(Ignored) => Some(&[]), + None => match self.lint_groups.get(lint_name) { + Some(LintGroup { lint_ids, .. }) => Some(lint_ids), + None => None, }, } } @@ -374,8 +365,12 @@ impl LintStore { CheckLintNameResult::MissingTool }; } - Some(LintGroup { lint_ids, .. }) => { - return CheckLintNameResult::Tool(lint_ids, None); + Some(LintGroup { lint_ids, depr, .. }) => { + return if let &Some(LintAlias { name, silent: false }) = depr { + CheckLintNameResult::Tool(lint_ids, Some(name.to_string())) + } else { + CheckLintNameResult::Tool(lint_ids, None) + }; } }, Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None), @@ -393,15 +388,11 @@ impl LintStore { None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"), Some(LintGroup { lint_ids, depr, .. }) => { // Check if the lint group name is deprecated - if let Some(LintAlias { name, silent }) = depr { - let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap(); - return if *silent { - CheckLintNameResult::Ok(lint_ids) - } else { - CheckLintNameResult::Tool(lint_ids, Some((*name).to_string())) - }; + if let &Some(LintAlias { name, silent: false }) = depr { + CheckLintNameResult::Tool(lint_ids, Some(name.to_string())) + } else { + CheckLintNameResult::Ok(lint_ids) } - CheckLintNameResult::Ok(lint_ids) } }, Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)), @@ -412,7 +403,7 @@ impl LintStore { fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> { let name_lower = lint_name.to_lowercase(); - if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_ok() { + if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() { // First check if the lint name is (partly) in upper case instead of lower case... return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false))); } @@ -455,18 +446,8 @@ impl LintStore { None => match self.lint_groups.get(&*complete_name) { // Now we are sure, that this lint exists nowhere None => self.no_lint_suggestion(lint_name, tool_name), - Some(LintGroup { lint_ids, depr, .. }) => { - // Reaching this would be weird, but let's cover this case anyway - if let Some(LintAlias { name, silent }) = depr { - let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap(); - if *silent { - CheckLintNameResult::Tool(lint_ids, Some(complete_name)) - } else { - CheckLintNameResult::Tool(lint_ids, Some((*name).to_string())) - } - } else { - CheckLintNameResult::Tool(lint_ids, Some(complete_name)) - } + Some(LintGroup { lint_ids, .. }) => { + CheckLintNameResult::Tool(lint_ids, Some(complete_name)) } }, Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)), diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index d0b1e7bf2553..00775647ac61 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -517,11 +517,11 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let lint_flag_val = Symbol::intern(lint_name); - let Ok(ids) = self.store.find_lints(lint_name) else { + let Some(ids) = self.store.find_lints(lint_name) else { // errors already handled above continue; }; - for id in ids { + for &id in ids { // ForceWarn and Forbid cannot be overridden if let Some(LevelAndSource { level: Level::ForceWarn | Level::Forbid, .. }) = self.current_specs().get(&id) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 9b5c564d3324..e1afd8bacb09 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -125,9 +125,7 @@ use unused::*; #[rustfmt::skip] pub use builtin::{MissingDoc, SoftLints}; -pub use context::{ - CheckLintNameResult, EarlyContext, FindLintError, LateContext, LintContext, LintStore, -}; +pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore}; pub use early::{EarlyCheckNode, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use levels::LintLevelsBuilder; From 13f1c845840fa40135fbed8798ec42df4d93b5d3 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 10 Apr 2025 16:32:56 -0700 Subject: [PATCH 051/222] Apply suggestions from code review Co-authored-by: Ralf Jung --- library/core/src/contracts.rs | 2 +- library/core/src/intrinsics/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/contracts.rs b/library/core/src/contracts.rs index 53f459debabc..495f84bce4bf 100644 --- a/library/core/src/contracts.rs +++ b/library/core/src/contracts.rs @@ -13,7 +13,7 @@ pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_require #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] // Similar to `contract_check_requires`, we need to use the user-facing // `contracts` feature rather than the perma-unstable `contracts_internals`. -// Const-checking doesn't honor allow internal unstable logic used by contract expansion. +// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion. #[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_build_check_ensures"] pub const fn build_check_ensures(cond: C) -> C diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 90f686a67288..9c9c1e41e717 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3484,7 +3484,7 @@ pub const fn contract_check_requires bool + Copy>(cond: C) { #[unstable(feature = "contracts_internals", issue = "128044")] // Similar to `contract_check_requires`, we need to use the user-facing // `contracts` feature rather than the perma-unstable `contracts_internals`. -// Const-checking doesn't honor allow internal unstable logic used by contract expansion. +// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion. #[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_check_ensures"] #[rustc_intrinsic] From 56c08d9b329c34e7be93d4a18a2b8987779140a9 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 30 Mar 2025 23:03:45 -0700 Subject: [PATCH 052/222] indirect-const-stabilize the `exact_div` intrinsic --- library/core/src/intrinsics/mod.rs | 1 + library/core/src/slice/mod.rs | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index ad33e2e5fe94..cbaa810ae068 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2735,6 +2735,7 @@ pub const fn carrying_mul_add, /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` /// /// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] pub const unsafe fn exact_div(x: T, y: T) -> T; diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index b906899a30b3..59f8020f0c38 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1287,7 +1287,6 @@ impl [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { @@ -1333,7 +1332,6 @@ impl [T] { /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1368,7 +1366,6 @@ impl [T] { /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1448,7 +1445,6 @@ impl [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { @@ -1489,7 +1485,6 @@ impl [T] { /// assert_eq!(v, &[1, 1, 2, 2, 9]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1530,7 +1525,6 @@ impl [T] { /// assert_eq!(v, &[9, 1, 1, 2, 2]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] From f97da855b1bbeecb0313023c9b4503eb82649fec Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 11 Apr 2025 15:30:00 +0800 Subject: [PATCH 053/222] suggest: remove redundant `$()?`around `vis` fragments --- compiler/rustc_expand/src/mbe/macro_rules.rs | 44 ++++++++++++++++--- .../macros/remove-repetition-issue-139480.rs | 28 ++++++++++++ .../remove-repetition-issue-139480.stderr | 44 +++++++++++++++++++ 3 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 tests/ui/macros/remove-repetition-issue-139480.rs create mode 100644 tests/ui/macros/remove-repetition-issue-139480.stderr diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 77ec598e62a1..460a06f9c060 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -12,7 +12,7 @@ use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::{Applicability, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_feature::Features; use rustc_hir as hir; use rustc_lint_defs::BuiltinLintDiag; @@ -27,19 +27,18 @@ use rustc_span::hygiene::Transparency; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym}; use tracing::{debug, instrument, trace, trace_span}; -use super::diagnostics; use super::macro_parser::{NamedMatches, NamedParseResult}; +use super::{SequenceRepetition, diagnostics}; use crate::base::{ DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, }; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; -use crate::mbe; use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg}; -use crate::mbe::macro_check; use crate::mbe::macro_parser::NamedMatch::*; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser}; use crate::mbe::transcribe::transcribe; +use crate::mbe::{self, KleeneOp, macro_check}; pub(crate) struct ParserAnyMacro<'a> { parser: Parser<'a>, @@ -640,6 +639,37 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool { } } +/// Checks if a `vis` nonterminal fragment is unnecessarily wrapped in an optional repetition. +/// +/// When a `vis` fragment (which can already be empty) is wrapped in `$(...)?`, +/// this suggests removing the redundant repetition syntax since it provides no additional benefit. +fn check_redundant_vis_repetition( + err: &mut Diag<'_>, + sess: &Session, + seq: &SequenceRepetition, + span: &DelimSpan, +) { + let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne; + let is_vis = seq.tts.first().map_or(false, |tt| { + matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis))) + }); + + if is_vis && is_zero_or_one { + err.note("a `vis` fragment can already be empty"); + err.multipart_suggestion( + "remove the `$(` and `)?`", + vec![ + ( + sess.source_map().span_extend_to_prev_char_before(span.open, '$', true), + "".to_string(), + ), + (span.close.with_hi(seq.kleene.span.hi()), "".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } +} + /// Checks that the lhs contains no repetition which could match an empty token /// tree, because then the matcher would hang indefinitely. fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), ErrorGuaranteed> { @@ -654,8 +684,10 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), TokenTree::Sequence(span, seq) => { if is_empty_token_tree(sess, seq) { let sp = span.entire(); - let guar = sess.dcx().span_err(sp, "repetition matches empty token tree"); - return Err(guar); + let mut err = + sess.dcx().struct_span_err(sp, "repetition matches empty token tree"); + check_redundant_vis_repetition(&mut err, sess, seq, span); + return Err(err.emit()); } check_lhs_no_empty_seq(sess, &seq.tts)? } diff --git a/tests/ui/macros/remove-repetition-issue-139480.rs b/tests/ui/macros/remove-repetition-issue-139480.rs new file mode 100644 index 000000000000..1efb4306763e --- /dev/null +++ b/tests/ui/macros/remove-repetition-issue-139480.rs @@ -0,0 +1,28 @@ +macro_rules! ciallo { + ($($v: vis)? $name: ident) => { + //~^ error: repetition matches empty token tree + }; +} + +macro_rules! meow { + ($name: ident $($v: vis)?) => { + //~^ error: repetition matches empty token tree + }; +} + +macro_rules! gbc { + ($name: ident $/* + this comment gets removed by the suggestion + */ + ($v: vis)?) => { + //~^ error: repetition matches empty token tree + }; +} + +ciallo!(hello); + +meow!(miaow, pub); + +gbc!(mygo,); + +fn main() {} diff --git a/tests/ui/macros/remove-repetition-issue-139480.stderr b/tests/ui/macros/remove-repetition-issue-139480.stderr new file mode 100644 index 000000000000..c2475589ee9a --- /dev/null +++ b/tests/ui/macros/remove-repetition-issue-139480.stderr @@ -0,0 +1,44 @@ +error: repetition matches empty token tree + --> $DIR/remove-repetition-issue-139480.rs:2:7 + | +LL | ($($v: vis)? $name: ident) => { + | ^^^^^^^^^ + | + = note: a `vis` fragment can already be empty +help: remove the `$(` and `)?` + | +LL - ($($v: vis)? $name: ident) => { +LL + ($v: vis $name: ident) => { + | + +error: repetition matches empty token tree + --> $DIR/remove-repetition-issue-139480.rs:8:20 + | +LL | ($name: ident $($v: vis)?) => { + | ^^^^^^^^^ + | + = note: a `vis` fragment can already be empty +help: remove the `$(` and `)?` + | +LL - ($name: ident $($v: vis)?) => { +LL + ($name: ident $v: vis) => { + | + +error: repetition matches empty token tree + --> $DIR/remove-repetition-issue-139480.rs:17:9 + | +LL | ($v: vis)?) => { + | ^^^^^^^^^ + | + = note: a `vis` fragment can already be empty +help: remove the `$(` and `)?` + | +LL - ($name: ident $/* +LL - this comment gets removed by the suggestion +LL - */ +LL - ($v: vis)?) => { +LL + ($name: ident $v: vis) => { + | + +error: aborting due to 3 previous errors + From 923f44c6313b86f3c1eeec264dce1a4317c8bbf6 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 10:41:10 +0200 Subject: [PATCH 054/222] consistent name for `UniversalRegions` --- compiler/rustc_borrowck/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 64ad1c968565..b4e807646c0a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -330,7 +330,7 @@ fn do_mir_borrowck<'tcx>( // will have a lifetime tied to the inference context. let mut body_owned = input_body.clone(); let mut promoted = input_promoted.to_owned(); - let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted); + let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes let location_table = PoloniusLocationTable::new(body); @@ -355,7 +355,7 @@ fn do_mir_borrowck<'tcx>( } = nll::compute_regions( root_cx, &infcx, - free_regions, + universal_regions, body, &promoted, &location_table, From 8cb727424dde83b841610700e40f399848e57700 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 10:42:45 +0200 Subject: [PATCH 055/222] use input `def_id` to compute `movable_coroutine` This previously incorrectly returned `true` for parent functions whose first statement was `let local = ;`. While that didn't cause any bugs as we only ever access `movable_coroutine` for `yield` terminators. It was still wrong. --- compiler/rustc_borrowck/src/lib.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index b4e807646c0a..94c1b54672ac 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -374,17 +374,8 @@ fn do_mir_borrowck<'tcx>( let diags_buffer = &mut BorrowckDiagnosticsBuffer::default(); nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, diags_buffer); - let movable_coroutine = - // The first argument is the coroutine type passed by value - if let Some(local) = body.local_decls.raw.get(1) - // Get the interior types and args which typeck computed - && let ty::Coroutine(def_id, _) = *local.ty.kind() - && tcx.coroutine_movability(def_id) == hir::Movability::Movable -{ - true -} else { - false -}; + let movable_coroutine = body.coroutine.is_some() + && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable; // While promoteds should mostly be correct by construction, we need to check them for // invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`. From 848187cc8a9afe5485958702b2342939d86010f0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 10:46:03 +0200 Subject: [PATCH 056/222] `local_names` creation to `mbcx` creation --- compiler/rustc_borrowck/src/lib.rs | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 94c1b54672ac..a38503c2668a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -304,26 +304,6 @@ fn do_mir_borrowck<'tcx>( root_cx.set_tainted_by_errors(e); } - let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); - for var_debug_info in &input_body.var_debug_info { - if let VarDebugInfoContents::Place(place) = var_debug_info.value { - if let Some(local) = place.as_local() { - if let Some(prev_name) = local_names[local] - && var_debug_info.name != prev_name - { - span_bug!( - var_debug_info.source_info.span, - "local {:?} has many names (`{}` vs `{}`)", - local, - prev_name, - var_debug_info.name - ); - } - local_names[local] = Some(var_debug_info.name); - } - } - } - // Replace all regions with fresh inference variables. This // requires first making our own copy of the MIR. This copy will // be modified (in place) to contain non-lexical lifetimes. It @@ -426,6 +406,26 @@ fn do_mir_borrowck<'tcx>( promoted_mbcx.report_move_errors(); } + let mut local_names = IndexVec::from_elem(None, &body.local_decls); + for var_debug_info in &body.var_debug_info { + if let VarDebugInfoContents::Place(place) = var_debug_info.value { + if let Some(local) = place.as_local() { + if let Some(prev_name) = local_names[local] + && var_debug_info.name != prev_name + { + span_bug!( + var_debug_info.source_info.span, + "local {:?} has many names (`{}` vs `{}`)", + local, + prev_name, + var_debug_info.name + ); + } + local_names[local] = Some(var_debug_info.name); + } + } + } + let mut mbcx = MirBorrowckCtxt { root_cx, infcx: &infcx, From 01864596dc67a753364df1ce2e2c0915401c57ef Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 11:09:27 +0200 Subject: [PATCH 057/222] do not buffer `#[rustc_regions]` dump --- compiler/rustc_borrowck/src/lib.rs | 4 ++-- compiler/rustc_borrowck/src/nll.rs | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a38503c2668a..f20bbc3b2673 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -351,12 +351,12 @@ fn do_mir_borrowck<'tcx>( // We also have a `#[rustc_regions]` annotation that causes us to dump // information. - let diags_buffer = &mut BorrowckDiagnosticsBuffer::default(); - nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, diags_buffer); + nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req); let movable_coroutine = body.coroutine.is_some() && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable; + let diags_buffer = &mut BorrowckDiagnosticsBuffer::default(); // While promoteds should mostly be correct by construction, we need to check them for // invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`. for promoted_body in &promoted { diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 8a2a34f207aa..399417937fdb 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -21,7 +21,7 @@ use tracing::{debug, instrument}; use crate::borrow_set::BorrowSet; use crate::consumers::ConsumerOptions; -use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors}; +use crate::diagnostics::RegionErrors; use crate::polonius::PoloniusDiagnosticsContext; use crate::polonius::legacy::{ PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, @@ -297,7 +297,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, - diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>, ) { let tcx = infcx.tcx; let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); @@ -335,13 +334,11 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( } else { let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements"); regioncx.annotate(tcx, &mut err); - err }; // FIXME(@lcnr): We currently don't dump the inferred hidden types here. - - diagnostics_buffer.buffer_non_error(err); + err.emit(); } fn for_each_region_constraint<'tcx>( From 0e294f2c2f56c688ea14acdeb03f491268f260ac Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 11:18:32 +0200 Subject: [PATCH 058/222] `MirBorrowckCtxt::polonius_output` to ref --- compiler/rustc_borrowck/src/lib.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index f20bbc3b2673..e9b9cdf6e202 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -446,9 +446,9 @@ fn do_mir_borrowck<'tcx>( local_names, region_names: RefCell::default(), next_region_name: RefCell::new(1), - polonius_output, move_errors: Vec::new(), diags_buffer, + polonius_output: polonius_output.as_deref(), polonius_diagnostics: polonius_diagnostics.as_ref(), }; @@ -505,7 +505,6 @@ fn do_mir_borrowck<'tcx>( }; let body_with_facts = if consumer_options.is_some() { - let output_facts = mbcx.polonius_output; Some(Box::new(BodyWithBorrowckFacts { body: body_owned, promoted, @@ -513,7 +512,7 @@ fn do_mir_borrowck<'tcx>( region_inference_context: regioncx, location_table: polonius_input.as_ref().map(|_| location_table), input_facts: polonius_input, - output_facts, + output_facts: polonius_output, })) } else { None @@ -700,12 +699,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { /// The counter for generating new region names. next_region_name: RefCell, - /// Results of Polonius analysis. - polonius_output: Option>, - diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>, move_errors: Vec>, + /// Results of Polonius analysis. + polonius_output: Option<&'a PoloniusOutput>, /// When using `-Zpolonius=next`: the data used to compute errors and diagnostics. polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>, } From 2c65469c2751f11e93e3cc5a9b1dcf1856039196 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 11:24:24 +0200 Subject: [PATCH 059/222] move `dump_polonius_mir` --- compiler/rustc_borrowck/src/lib.rs | 18 ++++++++---------- compiler/rustc_borrowck/src/polonius/dump.rs | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index e9b9cdf6e202..820952283bd1 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -348,6 +348,14 @@ fn do_mir_borrowck<'tcx>( // Dump MIR results into a file, if that is enabled. This lets us // write unit-tests, as well as helping with debugging. nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set); + polonius::dump_polonius_mir( + &infcx, + body, + ®ioncx, + &opt_closure_req, + &borrow_set, + polonius_diagnostics.as_ref(), + ); // We also have a `#[rustc_regions]` annotation that causes us to dump // information. @@ -465,16 +473,6 @@ fn do_mir_borrowck<'tcx>( mbcx.report_move_errors(); - // If requested, dump polonius MIR. - polonius::dump_polonius_mir( - &infcx, - body, - ®ioncx, - &borrow_set, - polonius_diagnostics.as_ref(), - &opt_closure_req, - ); - // For each non-user used mutable variable, check if it's been assigned from // a user-declared local. If so, then put that local into the used_mut set. // Note that this set is expected to be small - only upvars from closures diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index eb53a98832c3..6a943e192082 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -24,9 +24,9 @@ pub(crate) fn dump_polonius_mir<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, + closure_region_requirements: &Option>, borrow_set: &BorrowSet<'tcx>, polonius_diagnostics: Option<&PoloniusDiagnosticsContext>, - closure_region_requirements: &Option>, ) { let tcx = infcx.tcx; if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() { From c5fdddc7f49c492365eab042f3c392b57cdaa7b3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 11:40:38 +0200 Subject: [PATCH 060/222] don't rely on `locals_are_invalidated_at_exit` --- compiler/rustc_borrowck/src/lib.rs | 56 +++++++++++++----------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 820952283bd1..1bc69abe6f9f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -22,6 +22,7 @@ use std::cell::RefCell; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; +use borrow_set::LocalsStateAtExit; use root_cx::BorrowCheckRootCtxt; use rustc_abi::FieldIdx; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -382,7 +383,6 @@ fn do_mir_borrowck<'tcx>( location_table: &location_table, movable_coroutine, fn_self_span_reported: Default::default(), - locals_are_invalidated_at_exit, access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), uninitialized_error_reported: Default::default(), @@ -441,7 +441,6 @@ fn do_mir_borrowck<'tcx>( move_data: &move_data, location_table: &location_table, movable_coroutine, - locals_are_invalidated_at_exit, fn_self_span_reported: Default::default(), access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), @@ -643,13 +642,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { location_table: &'a PoloniusLocationTable, movable_coroutine: bool, - /// This keeps track of whether local variables are free-ed when the function - /// exits even without a `StorageDead`, which appears to be the case for - /// constants. - /// - /// I'm not sure this is the right approach - @eddyb could you try and - /// figure this out? - locals_are_invalidated_at_exit: bool, /// This field keeps track of when borrow errors are reported in the access_place function /// so that there is no duplicate reporting. This field cannot also be used for the conflicting /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion @@ -925,13 +917,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< | TerminatorKind::Return | TerminatorKind::TailCall { .. } | TerminatorKind::CoroutineDrop => { - // Returning from the function implicitly kills storage for all locals and statics. - // Often, the storage will already have been killed by an explicit - // StorageDead, but we don't always emit those (notably on unwind paths), - // so this "extra check" serves as a kind of backup. - for i in state.borrows.iter() { - let borrow = &self.borrow_set[i]; - self.check_for_invalidation_at_exit(loc, borrow, span); + match self.borrow_set.locals_state_at_exit() { + LocalsStateAtExit::AllAreInvalidated => { + // Returning from the function implicitly kills storage for all locals and statics. + // Often, the storage will already have been killed by an explicit + // StorageDead, but we don't always emit those (notably on unwind paths), + // so this "extra check" serves as a kind of backup. + for i in state.borrows.iter() { + let borrow = &self.borrow_set[i]; + self.check_for_invalidation_at_exit(loc, borrow, span); + } + } + // If we do not implicitly invalidate all locals on exit, + // we check for conflicts when dropping or moving this local. + LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {} } } @@ -1703,22 +1702,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // we'll have a memory leak) and assume that all statics have a destructor. // // FIXME: allow thread-locals to borrow other thread locals? - - let (might_be_alive, will_be_dropped) = - if self.body.local_decls[root_place.local].is_ref_to_thread_local() { - // Thread-locals might be dropped after the function exits - // We have to dereference the outer reference because - // borrows don't conflict behind shared references. - root_place.projection = TyCtxtConsts::DEREF_PROJECTION; - (true, true) - } else { - (false, self.locals_are_invalidated_at_exit) - }; - - if !will_be_dropped { - debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place); - return; - } + let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() { + // Thread-locals might be dropped after the function exits + // We have to dereference the outer reference because + // borrows don't conflict behind shared references. + root_place.projection = TyCtxtConsts::DEREF_PROJECTION; + true + } else { + false + }; let sd = if might_be_alive { Deep } else { Shallow(None) }; From 068a33245981765c3678434d5bcb71bd63d5598a Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Fri, 11 Apr 2025 10:15:55 +0000 Subject: [PATCH 061/222] cfi: Remove #[no_sanitize(cfi)] for extern weak functions Previously (https://github.com/rust-lang/rust/pull/115200, https://github.com/rust-lang/rust/pull/138002), we added `#[no_sanitize(cfi)]` to all code paths that call to a weakly linked function. In https://github.com/rust-lang/rust/pull/138349 we fixed the root cause for this issue, which means we can now remove the corresponding attributes. --- library/std/src/sys/fd/unix.rs | 3 --- library/std/src/sys/fs/unix.rs | 14 -------------- library/std/src/sys/pal/unix/thread.rs | 3 --- library/std/src/sys/pal/unix/time.rs | 11 ----------- library/std/src/sys/pal/unix/weak.rs | 3 --- library/std/src/sys/process/unix/unix.rs | 3 --- .../src/sys/thread_local/destructors/linux_like.rs | 3 --- 7 files changed, 40 deletions(-) diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index 2042ea2c73d0..5765cb1386ab 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -257,9 +257,6 @@ impl FileDesc { } #[cfg(all(target_os = "android", target_pointer_width = "32"))] - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[no_sanitize(cfi)] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { weak!( fn preadv64( diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 87865be0387d..687fc322e598 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1463,20 +1463,6 @@ impl File { Ok(()) } - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[cfg_attr( - any( - target_os = "android", - all( - target_os = "linux", - target_env = "gnu", - target_pointer_width = "32", - not(target_arch = "riscv32") - ) - ), - no_sanitize(cfi) - )] pub fn set_times(&self, times: FileTimes) -> io::Result<()> { #[cfg(not(any( target_os = "redox", diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 9078dd1c2316..c0662600db1d 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -189,9 +189,6 @@ impl Thread { } #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[no_sanitize(cfi)] pub fn set_name(name: &CStr) { weak!( fn pthread_setname_np( diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index b8469b1681f0..0074d7674741 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -96,17 +96,6 @@ impl Timespec { } } - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[cfg_attr( - all( - target_os = "linux", - target_env = "gnu", - target_pointer_width = "32", - not(target_arch = "riscv32") - ), - no_sanitize(cfi) - )] pub fn now(clock: libc::clockid_t) -> Timespec { use crate::mem::MaybeUninit; use crate::sys::cvt; diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs index e4c814fba8ce..a034995e6525 100644 --- a/library/std/src/sys/pal/unix/weak.rs +++ b/library/std/src/sys/pal/unix/weak.rs @@ -155,9 +155,6 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void { #[cfg(not(any(target_os = "linux", target_os = "android")))] pub(crate) macro syscall { (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[no_sanitize(cfi)] unsafe fn $name($($param: $t),*) -> $ret { weak!(fn $name($($param: $t),*) -> $ret;); diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 191a09c8da91..3b04ec50db30 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -434,9 +434,6 @@ impl Command { target_os = "nto", target_vendor = "apple", ))] - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[cfg_attr(target_os = "linux", no_sanitize(cfi))] fn posix_spawn( &mut self, stdio: &ChildPipes, diff --git a/library/std/src/sys/thread_local/destructors/linux_like.rs b/library/std/src/sys/thread_local/destructors/linux_like.rs index 817941229eef..d7cbaeb89f42 100644 --- a/library/std/src/sys/thread_local/destructors/linux_like.rs +++ b/library/std/src/sys/thread_local/destructors/linux_like.rs @@ -12,9 +12,6 @@ use crate::mem::transmute; -// FIXME: The Rust compiler currently omits weakly function definitions (i.e., -// __cxa_thread_atexit_impl) and its metadata from LLVM IR. -#[no_sanitize(cfi, kcfi)] pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { /// This is necessary because the __cxa_thread_atexit_impl implementation /// std links to by default may be a C or C++ implementation that was not From 6788ce76c9f66b836a3b6a72d8b6df32627edecc Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 11 Apr 2025 13:47:52 +0200 Subject: [PATCH 062/222] Remove proc_macro::SourceFile::is_real(). --- .../rustc_expand/src/proc_macro_server.rs | 4 ---- library/proc_macro/src/bridge/mod.rs | 1 - library/proc_macro/src/lib.rs | 21 ++----------------- .../ui/proc-macro/auxiliary/span-api-tests.rs | 12 +---------- tests/ui/proc-macro/span-api-tests.rs | 2 -- 5 files changed, 3 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index ee6306e39610..cd4ea8edd6fd 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -689,10 +689,6 @@ impl server::SourceFile for Rustc<'_, '_> { _ => file.name.prefer_local().to_string(), } } - - fn is_real(&mut self, file: &Self::SourceFile) -> bool { - file.is_real_file() - } } impl server::Span for Rustc<'_, '_> { diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 1b5c221425ec..d76e66521314 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -86,7 +86,6 @@ macro_rules! with_api { fn clone($self: &$S::SourceFile) -> $S::SourceFile; fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; fn path($self: &$S::SourceFile) -> String; - fn is_real($self: &$S::SourceFile) -> bool; }, Span { fn debug($self: $S::Span) -> String; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index f1cf0c5a2db7..17beef2d4702 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -623,36 +623,19 @@ impl SourceFile { /// Gets the path to this source file. /// /// ### Note - /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. /// - /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on + /// If `--remap-path-prefix` was passed on /// the command line, the path as given might not actually be valid. - /// - /// [`is_real`]: Self::is_real #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn path(&self) -> PathBuf { PathBuf::from(self.0.path()) } - - /// Returns `true` if this source file is a real source file, and not generated by an external - /// macro's expansion. - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn is_real(&self) -> bool { - // This is a hack until intercrate spans are implemented and we can have real source files - // for spans generated in external macros. - // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 - self.0.is_real() - } } #[unstable(feature = "proc_macro_span", issue = "54725")] impl fmt::Debug for SourceFile { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile") - .field("path", &self.path()) - .field("is_real", &self.is_real()) - .finish() + f.debug_struct("SourceFile").field("path", &self.path()).finish() } } diff --git a/tests/ui/proc-macro/auxiliary/span-api-tests.rs b/tests/ui/proc-macro/auxiliary/span-api-tests.rs index 99db66ed6a94..8853d793943f 100644 --- a/tests/ui/proc-macro/auxiliary/span-api-tests.rs +++ b/tests/ui/proc-macro/auxiliary/span-api-tests.rs @@ -10,21 +10,11 @@ pub fn reemit(input: TokenStream) -> TokenStream { input.to_string().parse().unwrap() } -#[proc_macro] -pub fn assert_fake_source_file(input: TokenStream) -> TokenStream { - for tk in input { - let source_file = tk.span().source_file(); - assert!(!source_file.is_real(), "Source file is real: {:?}", source_file); - } - - "".parse().unwrap() -} - #[proc_macro] pub fn assert_source_file(input: TokenStream) -> TokenStream { for tk in input { let source_file = tk.span().source_file(); - assert!(source_file.is_real(), "Source file is not real: {:?}", source_file); + assert!(!source_file.as_os_str().is_empty(), "No source file for span: {:?}", tk.span()); } "".parse().unwrap() diff --git a/tests/ui/proc-macro/span-api-tests.rs b/tests/ui/proc-macro/span-api-tests.rs index ac42a7ea611a..dd8589735b2e 100644 --- a/tests/ui/proc-macro/span-api-tests.rs +++ b/tests/ui/proc-macro/span-api-tests.rs @@ -8,8 +8,6 @@ extern crate span_test_macros; extern crate span_api_tests; -// FIXME(69775): Investigate `assert_fake_source_file`. - use span_api_tests::{reemit, assert_source_file, macro_stringify}; macro_rules! say_hello { From 3962069982783ccf183e273a983b0c150c51d504 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 11 Apr 2025 14:35:00 +0200 Subject: [PATCH 063/222] Replace proc_macro::SourceFile by Span::{file, local_file}. --- .../rustc_expand/src/proc_macro_server.rs | 47 ++++++++------- compiler/rustc_fluent_macro/src/fluent.rs | 3 + library/proc_macro/src/bridge/client.rs | 6 -- library/proc_macro/src/bridge/mod.rs | 10 +--- library/proc_macro/src/bridge/server.rs | 1 - library/proc_macro/src/lib.rs | 60 ++++++------------- tests/ui/proc-macro/auxiliary/expand-expr.rs | 8 +-- .../proc-macro/auxiliary/macro-only-syntax.rs | 2 +- .../ui/proc-macro/auxiliary/span-api-tests.rs | 5 +- tests/ui/proc-macro/span-api-tests.rs | 12 ++-- 10 files changed, 61 insertions(+), 93 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index cd4ea8edd6fd..0ab779945f21 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -1,5 +1,4 @@ use std::ops::{Bound, Range}; -use std::sync::Arc; use ast::token::IdentIsRaw; use pm::bridge::{ @@ -18,7 +17,7 @@ use rustc_parse::parser::Parser; use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; -use rustc_span::{BytePos, FileName, Pos, SourceFile, Span, Symbol, sym}; +use rustc_span::{BytePos, FileName, Pos, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use crate::base::ExtCtxt; @@ -467,7 +466,6 @@ impl<'a, 'b> Rustc<'a, 'b> { impl server::Types for Rustc<'_, '_> { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type SourceFile = Arc; type Span = Span; type Symbol = Symbol; } @@ -673,24 +671,6 @@ impl server::TokenStream for Rustc<'_, '_> { } } -impl server::SourceFile for Rustc<'_, '_> { - fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool { - Arc::ptr_eq(file1, file2) - } - - fn path(&mut self, file: &Self::SourceFile) -> String { - match &file.name { - FileName::Real(name) => name - .local_path() - .expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`") - .to_str() - .expect("non-UTF8 file path in `proc_macro::SourceFile::path`") - .to_string(), - _ => file.name.prefer_local().to_string(), - } - } -} - impl server::Span for Rustc<'_, '_> { fn debug(&mut self, span: Self::Span) -> String { if self.ecx.ecfg.span_debug { @@ -700,8 +680,29 @@ impl server::Span for Rustc<'_, '_> { } } - fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { - self.psess().source_map().lookup_char_pos(span.lo()).file + fn file(&mut self, span: Self::Span) -> String { + self.psess() + .source_map() + .lookup_char_pos(span.lo()) + .file + .name + .prefer_remapped_unconditionaly() + .to_string() + } + + fn local_file(&mut self, span: Self::Span) -> Option { + self.psess() + .source_map() + .lookup_char_pos(span.lo()) + .file + .name + .clone() + .into_local_path() + .map(|p| { + p.to_str() + .expect("non-UTF8 file path in `proc_macro::SourceFile::path`") + .to_string() + }) } fn parent(&mut self, span: Self::Span) -> Option { diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index b04fd1b48f7a..c96bb48a0368 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -25,7 +25,10 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf { path.to_path_buf() } else { // `/a/b/c/foo/bar.rs` contains the current macro invocation + #[cfg(bootstrap)] let mut source_file_path = span.source_file().path(); + #[cfg(not(bootstrap))] + let mut source_file_path = span.local_file().unwrap(); // `/a/b/c/foo/` source_file_path.pop(); // `/a/b/c/foo/../locales/en-US/example.ftl` diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index f6d4825c67b2..e7d547966a5d 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -111,12 +111,6 @@ impl Clone for TokenStream { } } -impl Clone for SourceFile { - fn clone(&self) -> Self { - self.clone() - } -} - impl Span { pub(crate) fn def_site() -> Span { Bridge::with(|bridge| bridge.globals.def_site) diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index d76e66521314..75d82d746540 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -81,15 +81,8 @@ macro_rules! with_api { $self: $S::TokenStream ) -> Vec>; }, - SourceFile { - fn drop($self: $S::SourceFile); - fn clone($self: &$S::SourceFile) -> $S::SourceFile; - fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; - fn path($self: &$S::SourceFile) -> String; - }, Span { fn debug($self: $S::Span) -> String; - fn source_file($self: $S::Span) -> $S::SourceFile; fn parent($self: $S::Span) -> Option<$S::Span>; fn source($self: $S::Span) -> $S::Span; fn byte_range($self: $S::Span) -> Range; @@ -97,6 +90,8 @@ macro_rules! with_api { fn end($self: $S::Span) -> $S::Span; fn line($self: $S::Span) -> usize; fn column($self: $S::Span) -> usize; + fn file($self: $S::Span) -> String; + fn local_file($self: $S::Span) -> Option; fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; fn subspan($self: $S::Span, start: Bound, end: Bound) -> Option<$S::Span>; fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; @@ -119,7 +114,6 @@ macro_rules! with_api_handle_types { 'owned: FreeFunctions, TokenStream, - SourceFile, 'interned: Span, diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 97e5a603c3ac..5beda7c3c96e 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -82,7 +82,6 @@ with_api_handle_types!(define_server_handles); pub trait Types { type FreeFunctions: 'static; type TokenStream: 'static + Clone; - type SourceFile: 'static + Clone; type Span: 'static + Copy + Eq + Hash; type Symbol: 'static; } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 17beef2d4702..c46dcebedcab 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -491,12 +491,6 @@ impl Span { Span(bridge::client::Span::mixed_site()) } - /// The original source file into which this span points. - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn source_file(&self) -> SourceFile { - SourceFile(self.0.source_file()) - } - /// The `Span` for the tokens in the previous macro expansion from which /// `self` was generated from, if any. #[unstable(feature = "proc_macro_span", issue = "54725")] @@ -546,6 +540,25 @@ impl Span { self.0.column() } + /// The path to the source file in which this span occurs, for display purposes. + /// + /// This might not correspond to a valid file system path. + /// It might be remapped, or might be an artificial path such as `""`. + #[unstable(feature = "proc_macro_span", issue = "54725")] + pub fn file(&self) -> String { + self.0.file() + } + + /// The path to the source file in which this span occurs on disk. + /// + /// This is the actual path on disk. It is unaffected by path remapping. + /// + /// This path should not be embedded in the output of the macro; prefer `file()` instead. + #[unstable(feature = "proc_macro_span", issue = "54725")] + pub fn local_file(&self) -> Option { + self.0.local_file().map(|s| PathBuf::from(s)) + } + /// Creates a new span encompassing `self` and `other`. /// /// Returns `None` if `self` and `other` are from different files. @@ -614,41 +627,6 @@ impl fmt::Debug for Span { } } -/// The source file of a given `Span`. -#[unstable(feature = "proc_macro_span", issue = "54725")] -#[derive(Clone)] -pub struct SourceFile(bridge::client::SourceFile); - -impl SourceFile { - /// Gets the path to this source file. - /// - /// ### Note - /// - /// If `--remap-path-prefix` was passed on - /// the command line, the path as given might not actually be valid. - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn path(&self) -> PathBuf { - PathBuf::from(self.0.path()) - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile").field("path", &self.path()).finish() - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl PartialEq for SourceFile { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl Eq for SourceFile {} - /// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). #[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Clone)] diff --git a/tests/ui/proc-macro/auxiliary/expand-expr.rs b/tests/ui/proc-macro/auxiliary/expand-expr.rs index 78c9fa75d9ff..14efc3c6b9f1 100644 --- a/tests/ui/proc-macro/auxiliary/expand-expr.rs +++ b/tests/ui/proc-macro/auxiliary/expand-expr.rs @@ -3,9 +3,10 @@ extern crate proc_macro; -use proc_macro::*; use std::str::FromStr; +use proc_macro::*; + // Flatten the TokenStream, removing any toplevel `Delimiter::None`s for // comparison. fn flatten(ts: TokenStream) -> Vec { @@ -136,9 +137,8 @@ pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream { .to_string(); assert_eq!(input_t, parse_t); - // Check that the literal matches `Span::call_site().source_file().path()` - let expect_t = - Literal::string(&Span::call_site().source_file().path().to_string_lossy()).to_string(); + // Check that the literal matches `Span::call_site().file()` + let expect_t = Literal::string(&Span::call_site().file()).to_string(); assert_eq!(input_t, expect_t); TokenStream::new() diff --git a/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs b/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs index 4971de284b76..11e1910288ee 100644 --- a/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs +++ b/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs @@ -79,7 +79,7 @@ fn check_useful_span(token: TokenTree, expected_filename: &str) { let span = token.span(); assert!(span.column() < span.end().column()); - let source_path = span.source_file().path(); + let source_path = span.local_file().unwrap(); let filename = source_path.components().last().unwrap(); assert_eq!(filename, Component::Normal(expected_filename.as_ref())); } diff --git a/tests/ui/proc-macro/auxiliary/span-api-tests.rs b/tests/ui/proc-macro/auxiliary/span-api-tests.rs index 8853d793943f..036f2e3ac3f5 100644 --- a/tests/ui/proc-macro/auxiliary/span-api-tests.rs +++ b/tests/ui/proc-macro/auxiliary/span-api-tests.rs @@ -11,10 +11,9 @@ pub fn reemit(input: TokenStream) -> TokenStream { } #[proc_macro] -pub fn assert_source_file(input: TokenStream) -> TokenStream { +pub fn assert_local_file(input: TokenStream) -> TokenStream { for tk in input { - let source_file = tk.span().source_file(); - assert!(!source_file.as_os_str().is_empty(), "No source file for span: {:?}", tk.span()); + assert!(tk.span().local_file().is_some(), "No local file for span: {:?}", tk.span()); } "".parse().unwrap() diff --git a/tests/ui/proc-macro/span-api-tests.rs b/tests/ui/proc-macro/span-api-tests.rs index dd8589735b2e..792859ed05b1 100644 --- a/tests/ui/proc-macro/span-api-tests.rs +++ b/tests/ui/proc-macro/span-api-tests.rs @@ -8,24 +8,24 @@ extern crate span_test_macros; extern crate span_api_tests; -use span_api_tests::{reemit, assert_source_file, macro_stringify}; +use span_api_tests::{reemit, assert_local_file, macro_stringify}; macro_rules! say_hello { ($macname:ident) => ( $macname! { "Hello, world!" }) } -assert_source_file! { "Hello, world!" } +assert_local_file! { "Hello, world!" } -say_hello! { assert_source_file } +say_hello! { assert_local_file } reemit_legacy! { - assert_source_file! { "Hello, world!" } + assert_local_file! { "Hello, world!" } } -say_hello_extern! { assert_source_file } +say_hello_extern! { assert_local_file } reemit! { - assert_source_file! { "Hello, world!" } + assert_local_file! { "Hello, world!" } } fn main() { From 83033838a3d1f6ae073c5e8855452e9d0a201eed Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 12:03:42 +0200 Subject: [PATCH 064/222] remove redundant fields --- .../src/type_check/constraint_conversion.rs | 20 ++++++++----------- .../src/type_check/free_region_relations.rs | 4 ---- compiler/rustc_borrowck/src/type_check/mod.rs | 13 +----------- .../rustc_borrowck/src/universal_regions.rs | 4 ++++ 4 files changed, 13 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index ccb257ae0936..57516565147e 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -21,7 +21,6 @@ use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategor pub(crate) struct ConstraintConversion<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, - tcx: TyCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, /// Each RBP `GK: 'a` is assumed to be true. These encode /// relationships like `T: 'a` that are added via implicit bounds @@ -34,7 +33,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { /// logic expecting to see (e.g.) `ReStatic`, and if we supplied /// our special inference variable there, we would mess that up. region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, @@ -49,7 +47,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, @@ -59,10 +56,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ) -> Self { Self { infcx, - tcx: infcx.tcx, universal_regions, region_bound_pairs, - implicit_region_bound, param_env, known_type_outlives_obligations, locations, @@ -96,7 +91,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // into a vector. These are the regions that we will be // relating to one another. let closure_mapping = &UniversalRegions::closure_mapping( - self.tcx, + self.infcx.tcx, closure_args, closure_requirements.num_external_vids, closure_def_id, @@ -111,7 +106,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { let subject = match outlives_requirement.subject { ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(), ClosureOutlivesSubject::Ty(subject_ty) => { - subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into() + subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into() } }; @@ -127,14 +122,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, constraint_category: ConstraintCategory<'tcx>, ) { + let tcx = self.infcx.tcx; debug!("generate: constraints at: {:#?}", self.locations); // Extract out various useful fields we'll need below. let ConstraintConversion { - tcx, infcx, + universal_regions, region_bound_pairs, - implicit_region_bound, known_type_outlives_obligations, .. } = *self; @@ -145,7 +140,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { break; } - if !self.tcx.recursion_limit().value_within_limit(iteration) { + if !tcx.recursion_limit().value_within_limit(iteration) { bug!( "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}" ); @@ -170,10 +165,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ); } + let implicit_region_bound = + ty::Region::new_var(tcx, universal_regions.implicit_region_bound()); // we don't actually use this for anything, but // the `TypeOutlives` code needs an origin. let origin = infer::RelateParamBound(self.span, t1, None); - TypeOutlives::new( &mut *self, tcx, @@ -205,7 +201,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { /// are dealt with during trait solving. fn replace_placeholders_with_nll>>(&mut self, value: T) -> T { if value.has_placeholders() { - fold_regions(self.tcx, value, |r, _| match r.kind() { + fold_regions(self.infcx.tcx, value, |r, _| match r.kind() { ty::RePlaceholder(placeholder) => { self.constraints.placeholder_region(self.infcx, placeholder) } diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index eaac633b512d..536a27763d29 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -49,14 +49,12 @@ pub(crate) struct CreateResult<'tcx> { pub(crate) fn create<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - implicit_region_bound: ty::Region<'tcx>, universal_regions: UniversalRegions<'tcx>, constraints: &mut MirTypeckRegionConstraints<'tcx>, ) -> CreateResult<'tcx> { UniversalRegionRelationsBuilder { infcx, param_env, - implicit_region_bound, constraints, universal_regions, region_bound_pairs: Default::default(), @@ -181,7 +179,6 @@ struct UniversalRegionRelationsBuilder<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, universal_regions: UniversalRegions<'tcx>, - implicit_region_bound: ty::Region<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, // outputs: @@ -320,7 +317,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { self.infcx, &self.universal_regions, &self.region_bound_pairs, - self.implicit_region_bound, param_env, &known_type_outlives_obligations, Locations::All(span), diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a17dff5d2715..05e0bb3f9f34 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -113,7 +113,6 @@ pub(crate) fn type_check<'a, 'tcx>( move_data: &MoveData<'tcx>, location_map: Rc, ) -> MirTypeckResults<'tcx> { - let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), @@ -129,13 +128,7 @@ pub(crate) fn type_check<'a, 'tcx>( region_bound_pairs, normalized_inputs_and_output, known_type_outlives_obligations, - } = free_region_relations::create( - infcx, - infcx.param_env, - implicit_region_bound, - universal_regions, - &mut constraints, - ); + } = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints); let pre_obligations = infcx.take_registered_region_obligations(); assert!( @@ -160,7 +153,6 @@ pub(crate) fn type_check<'a, 'tcx>( user_type_annotations: &body.user_type_annotations, region_bound_pairs, known_type_outlives_obligations, - implicit_region_bound, reported_errors: Default::default(), universal_regions: &universal_region_relations.universal_regions, location_table, @@ -226,7 +218,6 @@ struct TypeChecker<'a, 'tcx> { user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, region_bound_pairs: RegionBoundPairs<'tcx>, known_type_outlives_obligations: Vec>, - implicit_region_bound: ty::Region<'tcx>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a PoloniusLocationTable, @@ -422,7 +413,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.infcx, self.universal_regions, &self.region_bound_pairs, - self.implicit_region_bound, self.infcx.param_env, &self.known_type_outlives_obligations, locations, @@ -2507,7 +2497,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.infcx, self.universal_regions, &self.region_bound_pairs, - self.implicit_region_bound, self.infcx.param_env, &self.known_type_outlives_obligations, locations, diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 5c57ab99a859..c11e14d214c4 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -438,6 +438,10 @@ impl<'tcx> UniversalRegions<'tcx> { } } + pub(crate) fn implicit_region_bound(&self) -> RegionVid { + self.fr_fn_body + } + pub(crate) fn tainted_by_errors(&self) -> Option { self.indices.tainted_by_errors.get() } From 5d0048303c98ad5226cd84f2132d21be3c6171c0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 12:04:48 +0200 Subject: [PATCH 065/222] `NonGenericOpaqueTypeParam::ty` to `arg` --- compiler/rustc_trait_selection/messages.ftl | 4 ++-- compiler/rustc_trait_selection/src/errors.rs | 2 +- compiler/rustc_trait_selection/src/opaque_types.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 05bbb42fb7c6..74e38f525c8e 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -268,8 +268,8 @@ trait_selection_oc_type_compat = type not compatible with trait trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds .label = opaque type defined here trait_selection_opaque_type_non_generic_param = - expected generic {$kind} parameter, found `{$ty}` - .label = {STREQ($ty, "'static") -> + expected generic {$kind} parameter, found `{$arg}` + .label = {STREQ($arg, "'static") -> [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type *[other] this generic parameter must be used with a generic {$kind} parameter } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index bb4aba9d29e4..4e5581fb1da0 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1926,7 +1926,7 @@ impl Subdiagnostic for AddPreciseCapturingForOvercapture { #[derive(Diagnostic)] #[diag(trait_selection_opaque_type_non_generic_param, code = E0792)] pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { - pub ty: GenericArg<'tcx>, + pub arg: GenericArg<'tcx>, pub kind: &'a str, #[primary_span] pub span: Span, diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 309bf4dda3d8..cce67b066dde 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -70,7 +70,7 @@ pub fn check_opaque_type_parameter_valid<'tcx>( opaque_env.param_is_error(i)?; return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam { - ty: arg, + arg, kind, span, param_span: tcx.def_span(opaque_param.def_id), From 420390c8489c7d95320a4394beeaa6e4170e3258 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 11 Apr 2025 12:49:55 +0200 Subject: [PATCH 066/222] eagerly initialize `definitions` in sub-fn --- compiler/rustc_borrowck/src/nll.rs | 14 +----- .../rustc_borrowck/src/region_infer/mod.rs | 43 ++++++++++--------- 2 files changed, 25 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 399417937fdb..fe899bb054fa 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -117,11 +117,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( Rc::clone(&location_map), ); - // Create the region inference context, taking ownership of the - // region inference data that was contained in `infcx`, and the - // base constraints generated by the type-check. - let var_infos = infcx.get_region_var_infos(); - // If requested, emit legacy polonius facts. polonius::legacy::emit_facts( &mut polonius_facts, @@ -134,13 +129,8 @@ pub(crate) fn compute_regions<'a, 'tcx>( &constraints, ); - let mut regioncx = RegionInferenceContext::new( - infcx, - var_infos, - constraints, - universal_region_relations, - location_map, - ); + let mut regioncx = + RegionInferenceContext::new(infcx, constraints, universal_region_relations, location_map); // If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints // and use them to compute loan liveness. diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 569c46e6403f..c82c7341f028 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -9,7 +9,7 @@ use rustc_errors::Diag; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_index::IndexVec; use rustc_infer::infer::outlives::test_type_match; -use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq}; +use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::bug; use rustc_middle::mir::{ @@ -145,7 +145,7 @@ pub struct RegionInferenceContext<'tcx> { /// variables are identified by their index (`RegionVid`). The /// definition contains information about where the region came /// from as well as its final inferred value. - pub(crate) definitions: IndexVec>, + pub(crate) definitions: Frozen>>, /// The liveness constraints added to each region. For most /// regions, these start out empty and steadily grow, though for @@ -385,6 +385,26 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) { debug!("SCC edges {:#?}", scc_node_to_edges); } +fn create_definitions<'tcx>( + infcx: &BorrowckInferCtxt<'tcx>, + universal_regions: &UniversalRegions<'tcx>, +) -> Frozen>> { + // Create a RegionDefinition for each inference variable. + let mut definitions: IndexVec<_, _> = infcx + .get_region_var_infos() + .iter() + .map(|info| RegionDefinition::new(info.universe, info.origin)) + .collect(); + + // Add the external name for all universal regions. + for (external_name, variable) in universal_regions.named_universal_regions_iter() { + debug!("region {variable:?} has external name {external_name:?}"); + definitions[variable].external_name = Some(external_name); + } + + Frozen::freeze(definitions) +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -395,7 +415,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// of constraints produced by the MIR type check. pub(crate) fn new( infcx: &BorrowckInferCtxt<'tcx>, - var_infos: VarInfos, constraints: MirTypeckRegionConstraints<'tcx>, universal_region_relations: Frozen>, location_map: Rc, @@ -426,11 +445,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx.set_tainted_by_errors(guar); } - // Create a RegionDefinition for each inference variable. - let definitions: IndexVec<_, _> = var_infos - .iter() - .map(|info| RegionDefinition::new(info.universe, info.origin)) - .collect(); + let definitions = create_definitions(infcx, &universal_regions); let constraint_sccs = outlives_constraints.add_outlives_static(&universal_regions, &definitions); @@ -526,18 +541,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// means that the `R1: !1` constraint here will cause /// `R1` to become `'static`. fn init_free_and_bound_regions(&mut self) { - // Update the names (if any) - // This iterator has unstable order but we collect it all into an IndexVec - for (external_name, variable) in - self.universal_region_relations.universal_regions.named_universal_regions_iter() - { - debug!( - "init_free_and_bound_regions: region {:?} has external name {:?}", - variable, external_name - ); - self.definitions[variable].external_name = Some(external_name); - } - for variable in self.definitions.indices() { let scc = self.constraint_sccs.scc(variable); From 5113f5e6025a0742524aece5d69c87ef4257d338 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 11 Apr 2025 15:29:46 +0200 Subject: [PATCH 067/222] Update rust-analyzer for new proc_macro span api. --- .../src/server_impl/rust_analyzer_span.rs | 29 +++++-------------- .../src/server_impl/token_id.rs | 22 ++++---------- 2 files changed, 13 insertions(+), 38 deletions(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 59293ee3f965..80f6d85a3d05 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -11,7 +11,7 @@ use std::{ use intern::Symbol; use proc_macro::bridge::{self, server}; -use span::{FileId, Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; +use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; use tt::{TextRange, TextSize}; use crate::server_impl::{literal_kind_to_internal, token_stream::TokenStreamBuilder, TopSubtree}; @@ -27,10 +27,6 @@ mod tt { type TokenStream = crate::server_impl::TokenStream; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct SourceFile { - file_id: FileId, -} pub struct FreeFunctions; pub struct RaSpanServer { @@ -46,7 +42,6 @@ pub struct RaSpanServer { impl server::Types for RaSpanServer { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type SourceFile = SourceFile; type Span = Span; type Symbol = Symbol; } @@ -245,25 +240,17 @@ impl server::TokenStream for RaSpanServer { } } -impl server::SourceFile for RaSpanServer { - fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool { - file1 == file2 - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - // FIXME - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - impl server::Span for RaSpanServer { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span) } - fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { - SourceFile { file_id: span.anchor.file_id.file_id() } + fn file(&mut self, _: Self::Span) -> String { + // FIXME + String::new() + } + fn local_file(&mut self, _: Self::Span) -> Option { + // FIXME + None } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index 409cf3cc7813..4d7c7c46766b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -24,8 +24,6 @@ type Literal = tt::Literal; type Span = tt::TokenId; type TokenStream = crate::server_impl::TokenStream; -#[derive(Clone)] -pub struct SourceFile; pub struct FreeFunctions; pub struct TokenIdServer { @@ -37,7 +35,6 @@ pub struct TokenIdServer { impl server::Types for TokenIdServer { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type SourceFile = SourceFile; type Span = Span; type Symbol = Symbol; } @@ -223,24 +220,15 @@ impl server::TokenStream for TokenIdServer { } } -impl server::SourceFile for TokenIdServer { - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - impl server::Span for TokenIdServer { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span.0) } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} + fn file(&mut self, _span: Self::Span) -> String { + String::new() + } + fn local_file(&mut self, _span: Self::Span) -> Option { + None } fn save_span(&mut self, _span: Self::Span) -> usize { 0 From dc0fbcab7e0673afe62b3e8e74905d9e5f5b74a4 Mon Sep 17 00:00:00 2001 From: Jesus Checa Hidalgo Date: Fri, 11 Apr 2025 16:57:38 +0200 Subject: [PATCH 068/222] Fix profiler_builtins build script to handle full path to profiler lib LLVM_PROFILER_RT_LIB may be set to an absolute path (e.g., in Fedora builds), but `-l` expects a library name, not a path. After #138273, this caused builds to fail with a "could not find native static library" error. This patch updates the build script to split the path into directory and filename, using `cargo::rustc-link-search` for the directory and `cargo::rustc-link-lib=+verbatim` for the file. This allows profiler_builtins to correctly link the static library even when an absolute path is provided. --- library/profiler_builtins/build.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs index dd85239fa8cf..fc1a9ecc1ec3 100644 --- a/library/profiler_builtins/build.rs +++ b/library/profiler_builtins/build.rs @@ -9,8 +9,14 @@ use std::path::PathBuf; fn main() { if let Ok(rt) = tracked_env_var("LLVM_PROFILER_RT_LIB") { - println!("cargo::rustc-link-lib=static:+verbatim={rt}"); - return; + let rt = PathBuf::from(rt); + if let Some(lib) = rt.file_name() { + if let Some(dir) = rt.parent() { + println!("cargo::rustc-link-search=native={}", dir.display()); + } + println!("cargo::rustc-link-lib=static:+verbatim={}", lib.to_str().unwrap()); + return; + } } let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set"); From 17d412439ad883bc52730cad194088246d557752 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 11 Apr 2025 17:55:25 +0200 Subject: [PATCH 069/222] Update library/core/src/fmt/rt.rs --- library/core/src/fmt/rt.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 05e024b134d1..702aa7e34369 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -72,7 +72,6 @@ macro_rules! argument_new { // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { value: NonNull::<$t>::from_ref($x).cast(), - // SAFETY: function pointers always have the same layout. formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| { let func = $f; // SAFETY: This is the same type as the `value` field. From ac45a672979b28670cf2e5de5afbb0b1fb42c0b2 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 4 Apr 2025 09:58:55 +0000 Subject: [PATCH 070/222] Use delayed bug for normalization errors in drop elaboration Normalization can fail from errors from other items so use a delayed bug instead of checking the body. --- .../rustc_mir_transform/src/elaborate_drop.rs | 11 ++--- .../drop/drop_elaboration_with_errors2.rs} | 6 ++- .../drop/drop_elaboration_with_errors2.stderr | 47 +++++++++++++++++++ .../drop/drop_elaboration_with_errors3.rs} | 8 +++- .../drop/drop_elaboration_with_errors3.stderr | 8 ++++ 5 files changed, 70 insertions(+), 10 deletions(-) rename tests/{crashes/137287.rs => ui/drop/drop_elaboration_with_errors2.rs} (68%) create mode 100644 tests/ui/drop/drop_elaboration_with_errors2.stderr rename tests/{crashes/135668.rs => ui/drop/drop_elaboration_with_errors3.rs} (87%) create mode 100644 tests/ui/drop/drop_elaboration_with_errors3.stderr diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 0d8cf524661c..fa476f961235 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -266,19 +266,16 @@ where let tcx = self.tcx(); assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis); - // The type error for normalization may have been in dropck: see - // `compute_drop_data` in rustc_borrowck, in which case we wouldn't have - // deleted the MIR body and could have an error here as well. let field_ty = match tcx .try_normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args)) { Ok(t) => t, Err(_) => Ty::new_error( self.tcx(), - self.elaborator - .body() - .tainted_by_errors - .expect("Error in drop elaboration not found by dropck."), + self.tcx().dcx().span_delayed_bug( + self.elaborator.body().span, + "Error normalizing in drop elaboration.", + ), ), }; diff --git a/tests/crashes/137287.rs b/tests/ui/drop/drop_elaboration_with_errors2.rs similarity index 68% rename from tests/crashes/137287.rs rename to tests/ui/drop/drop_elaboration_with_errors2.rs index 59fdf568d368..946c253179cb 100644 --- a/tests/crashes/137287.rs +++ b/tests/ui/drop/drop_elaboration_with_errors2.rs @@ -1,11 +1,14 @@ -//@ known-bug: #137287 +// Regression test for #137287 mod defining_scope { use super::*; pub type Alias = impl Sized; + //~^ ERROR unconstrained opaque type + //~| ERROR `impl Trait` in type aliases is unstable pub fn cast(x: Container, T>) -> Container { x + //~^ ERROR mismatched types } } @@ -21,6 +24,7 @@ impl Trait for T { type Assoc = Box; } impl Trait for defining_scope::Alias { + //~^ ERROR conflicting implementations of trait `Trait<_>` type Assoc = usize; } diff --git a/tests/ui/drop/drop_elaboration_with_errors2.stderr b/tests/ui/drop/drop_elaboration_with_errors2.stderr new file mode 100644 index 000000000000..15fe3f6ecc1f --- /dev/null +++ b/tests/ui/drop/drop_elaboration_with_errors2.stderr @@ -0,0 +1,47 @@ +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/drop_elaboration_with_errors2.rs:5:25 + | +LL | pub type Alias = impl Sized; + | ^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0119]: conflicting implementations of trait `Trait<_>` + --> $DIR/drop_elaboration_with_errors2.rs:26:1 + | +LL | impl Trait for T { + | ---------------------- first implementation here +... +LL | impl Trait for defining_scope::Alias { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error: unconstrained opaque type + --> $DIR/drop_elaboration_with_errors2.rs:5:25 + | +LL | pub type Alias = impl Sized; + | ^^^^^^^^^^ + | + = note: `Alias` must be used in combination with a concrete type within the same crate + +error[E0308]: mismatched types + --> $DIR/drop_elaboration_with_errors2.rs:10:9 + | +LL | pub type Alias = impl Sized; + | ---------- the found opaque type +... +LL | pub fn cast(x: Container, T>) -> Container { + | - expected this type parameter --------------- expected `Container` because of return type +LL | x + | ^ expected `Container`, found `Container, T>` + | + = note: expected struct `Container` + found struct `Container, _>` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0119, E0308, E0658. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/crashes/135668.rs b/tests/ui/drop/drop_elaboration_with_errors3.rs similarity index 87% rename from tests/crashes/135668.rs rename to tests/ui/drop/drop_elaboration_with_errors3.rs index 00d7b5db0c67..c5ed63eb7ac2 100644 --- a/tests/crashes/135668.rs +++ b/tests/ui/drop/drop_elaboration_with_errors3.rs @@ -1,5 +1,6 @@ -//@ known-bug: #135668 +// Regression test for #135668 //@ edition: 2021 + use std::future::Future; pub async fn foo() { @@ -11,7 +12,8 @@ async fn create_task() -> impl Sized { } async fn documentation() { - include_str!("nonexistent"); + compile_error!("bonjour"); + //~^ ERROR bonjour } fn bind(_filter: F) -> impl Sized @@ -36,3 +38,5 @@ where { type Assoc = F; } + +fn main() {} diff --git a/tests/ui/drop/drop_elaboration_with_errors3.stderr b/tests/ui/drop/drop_elaboration_with_errors3.stderr new file mode 100644 index 000000000000..2d44e7c66259 --- /dev/null +++ b/tests/ui/drop/drop_elaboration_with_errors3.stderr @@ -0,0 +1,8 @@ +error: bonjour + --> $DIR/drop_elaboration_with_errors3.rs:15:5 + | +LL | compile_error!("bonjour"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From b613e9781a773232f81af9f61a8c8ac34b04873a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 11 Apr 2025 16:15:34 +0000 Subject: [PATCH 071/222] Use with_native_path for Windows Also add a WCStr type --- library/std/src/sys/fs/mod.rs | 30 +++++++++---- library/std/src/sys/fs/windows.rs | 69 +++++++++++++---------------- library/std/src/sys/path/windows.rs | 34 ++++++++++++++ 3 files changed, 86 insertions(+), 47 deletions(-) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 3b176d0d16c4..4c5e36ce67a3 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -20,6 +20,7 @@ cfg_if::cfg_if! { mod windows; use windows as imp; pub use windows::{symlink_inner, junction_point}; + use crate::sys::path::with_native_path; } else if #[cfg(target_os = "hermit")] { mod hermit; use hermit as imp; @@ -39,7 +40,7 @@ cfg_if::cfg_if! { } // FIXME: Replace this with platform-specific path conversion functions. -#[cfg(not(target_family = "unix"))] +#[cfg(not(any(target_family = "unix", target_os = "windows")))] #[inline] pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { f(path) @@ -51,7 +52,7 @@ pub use imp::{ }; pub fn read_dir(path: &Path) -> io::Result { - // FIXME: use with_native_path + // FIXME: use with_native_path on all platforms imp::readdir(path) } @@ -68,8 +69,11 @@ pub fn remove_dir(path: &Path) -> io::Result<()> { } pub fn remove_dir_all(path: &Path) -> io::Result<()> { - // FIXME: use with_native_path - imp::remove_dir_all(path) + // FIXME: use with_native_path on all platforms + #[cfg(not(windows))] + return imp::remove_dir_all(path); + #[cfg(windows)] + with_native_path(path, &imp::remove_dir_all) } pub fn read_link(path: &Path) -> io::Result { @@ -77,6 +81,10 @@ pub fn read_link(path: &Path) -> io::Result { } pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { + // FIXME: use with_native_path on all platforms + #[cfg(windows)] + return imp::symlink(original, link); + #[cfg(not(windows))] with_native_path(original, &|original| { with_native_path(link, &|link| imp::symlink(original, link)) }) @@ -105,11 +113,17 @@ pub fn canonicalize(path: &Path) -> io::Result { } pub fn copy(from: &Path, to: &Path) -> io::Result { - // FIXME: use with_native_path - imp::copy(from, to) + // FIXME: use with_native_path on all platforms + #[cfg(not(windows))] + return imp::copy(from, to); + #[cfg(windows)] + with_native_path(from, &|from| with_native_path(to, &|to| imp::copy(from, to))) } pub fn exists(path: &Path) -> io::Result { - // FIXME: use with_native_path - imp::exists(path) + // FIXME: use with_native_path on all platforms + #[cfg(not(windows))] + return imp::exists(path); + #[cfg(windows)] + with_native_path(path, &imp::exists) } diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 15727c996837..9215f9375671 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -12,7 +12,7 @@ use crate::sync::Arc; use crate::sys::handle::Handle; use crate::sys::pal::api::{self, WinError, set_file_information_by_handle}; use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul}; -use crate::sys::path::maybe_verbatim; +use crate::sys::path::{WCStr, maybe_verbatim}; use crate::sys::time::SystemTime; use crate::sys::{Align8, c, cvt}; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -298,10 +298,12 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { let path = maybe_verbatim(path)?; + // SAFETY: maybe_verbatim returns null-terminated strings + let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) }; Self::open_native(&path, opts) } - fn open_native(path: &[u16], opts: &OpenOptions) -> io::Result { + fn open_native(path: &WCStr, opts: &OpenOptions) -> io::Result { let creation = opts.get_creation_mode()?; let handle = unsafe { c::CreateFileW( @@ -1212,9 +1214,8 @@ pub fn readdir(p: &Path) -> io::Result { } } -pub fn unlink(p: &Path) -> io::Result<()> { - let p_u16s = maybe_verbatim(p)?; - if unsafe { c::DeleteFileW(p_u16s.as_ptr()) } == 0 { +pub fn unlink(path: &WCStr) -> io::Result<()> { + if unsafe { c::DeleteFileW(path.as_ptr()) } == 0 { let err = api::get_last_error(); // if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove // the file while ignoring the readonly attribute. @@ -1223,7 +1224,7 @@ pub fn unlink(p: &Path) -> io::Result<()> { let mut opts = OpenOptions::new(); opts.access_mode(c::DELETE); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT); - if let Ok(f) = File::open_native(&p_u16s, &opts) { + if let Ok(f) = File::open_native(&path, &opts) { if f.posix_delete().is_ok() { return Ok(()); } @@ -1236,10 +1237,7 @@ pub fn unlink(p: &Path) -> io::Result<()> { } } -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = maybe_verbatim(old)?; - let new = maybe_verbatim(new)?; - +pub fn rename(old: &WCStr, new: &WCStr) -> io::Result<()> { if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 { let err = api::get_last_error(); // if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move @@ -1253,7 +1251,8 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation` // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size. - let Ok(new_len_without_nul_in_bytes): Result = ((new.len() - 1) * 2).try_into() + let Ok(new_len_without_nul_in_bytes): Result = + ((new.count_bytes() - 1) * 2).try_into() else { return Err(err).io_result(); }; @@ -1282,7 +1281,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { new.as_ptr().copy_to_nonoverlapping( (&raw mut (*file_rename_info).FileName).cast::(), - new.len(), + new.count_bytes(), ); } @@ -1309,20 +1308,19 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { Ok(()) } -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = maybe_verbatim(p)?; +pub fn rmdir(p: &WCStr) -> io::Result<()> { cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?; Ok(()) } -pub fn remove_dir_all(path: &Path) -> io::Result<()> { +pub fn remove_dir_all(path: &WCStr) -> io::Result<()> { // Open a file or directory without following symlinks. let mut opts = OpenOptions::new(); opts.access_mode(c::FILE_LIST_DIRECTORY); // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories. // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target. opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); - let file = File::open(path, &opts)?; + let file = File::open_native(path, &opts)?; // Test if the file is not a directory or a symlink to a directory. if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 { @@ -1333,14 +1331,14 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { remove_dir_all_iterative(file).io_result() } -pub fn readlink(path: &Path) -> io::Result { +pub fn readlink(path: &WCStr) -> io::Result { // Open the link with no access mode, instead of generic read. // By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so // this is needed for a common case. let mut opts = OpenOptions::new(); opts.access_mode(0); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(path, &opts)?; + let file = File::open_native(&path, &opts)?; file.readlink() } @@ -1378,19 +1376,17 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> } #[cfg(not(target_vendor = "uwp"))] -pub fn link(original: &Path, link: &Path) -> io::Result<()> { - let original = maybe_verbatim(original)?; - let link = maybe_verbatim(link)?; +pub fn link(original: &WCStr, link: &WCStr) -> io::Result<()> { cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?; Ok(()) } #[cfg(target_vendor = "uwp")] -pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { +pub fn link(_original: &WCStr, _link: &WCStr) -> io::Result<()> { return Err(io::const_error!(io::ErrorKind::Unsupported, "hard link are not supported on UWP")); } -pub fn stat(path: &Path) -> io::Result { +pub fn stat(path: &WCStr) -> io::Result { match metadata(path, ReparsePoint::Follow) { Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => { if let Ok(attrs) = lstat(path) { @@ -1404,7 +1400,7 @@ pub fn stat(path: &Path) -> io::Result { } } -pub fn lstat(path: &Path) -> io::Result { +pub fn lstat(path: &WCStr) -> io::Result { metadata(path, ReparsePoint::Open) } @@ -1420,7 +1416,7 @@ impl ReparsePoint { } } -fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { +fn metadata(path: &WCStr, reparse: ReparsePoint) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); @@ -1429,7 +1425,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { // Attempt to open the file normally. // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileExW`. // If the fallback fails for any reason we return the original error. - match File::open(path, &opts) { + match File::open_native(&path, &opts) { Ok(file) => file.file_attr(), Err(e) if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)] @@ -1442,8 +1438,6 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { // However, there are special system files, such as // `C:\hiberfil.sys`, that are locked in a way that denies even that. unsafe { - let path = maybe_verbatim(path)?; - // `FindFirstFileExW` accepts wildcard file names. // Fortunately wildcards are not valid file names and // `ERROR_SHARING_VIOLATION` means the file exists (but is locked) @@ -1482,8 +1476,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { } } -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = maybe_verbatim(p)?; +pub fn set_perm(p: &WCStr, perm: FilePermissions) -> io::Result<()> { unsafe { cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?; Ok(()) @@ -1499,17 +1492,17 @@ fn get_path(f: &File) -> io::Result { ) } -pub fn canonicalize(p: &Path) -> io::Result { +pub fn canonicalize(p: &WCStr) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); // This flag is so we can open directories too opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let f = File::open(p, &opts)?; + let f = File::open_native(p, &opts)?; get_path(&f) } -pub fn copy(from: &Path, to: &Path) -> io::Result { +pub fn copy(from: &WCStr, to: &WCStr) -> io::Result { unsafe extern "system" fn callback( _TotalFileSize: i64, _TotalBytesTransferred: i64, @@ -1528,13 +1521,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { c::PROGRESS_CONTINUE } } - let pfrom = maybe_verbatim(from)?; - let pto = maybe_verbatim(to)?; let mut size = 0i64; cvt(unsafe { c::CopyFileExW( - pfrom.as_ptr(), - pto.as_ptr(), + from.as_ptr(), + to.as_ptr(), Some(callback), (&raw mut size) as *mut _, ptr::null_mut(), @@ -1624,14 +1615,14 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { } // Try to see if a file exists but, unlike `exists`, report I/O errors. -pub fn exists(path: &Path) -> io::Result { +pub fn exists(path: &WCStr) -> io::Result { // Open the file to ensure any symlinks are followed to their target. let mut opts = OpenOptions::new(); // No read, write, etc access rights are needed. opts.access_mode(0); // Backup semantics enables opening directories as well as files. opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - match File::open(path, &opts) { + match File::open_native(path, &opts) { Err(e) => match e.kind() { // The file definitely does not exist io::ErrorKind::NotFound => Ok(false), diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index 6547ed9aa5f3..e0e003f6a819 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -10,6 +10,40 @@ mod tests; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; +/// A null terminated wide string. +#[repr(transparent)] +pub struct WCStr([u16]); + +impl WCStr { + /// Convert a slice to a WCStr without checks. + /// + /// Though it is memory safe, the slice should also not contain interior nulls + /// as this may lead to unwanted truncation. + /// + /// # Safety + /// + /// The slice must end in a null. + pub unsafe fn from_wchars_with_null_unchecked(s: &[u16]) -> &Self { + unsafe { &*(s as *const [u16] as *const Self) } + } + + pub fn as_ptr(&self) -> *const u16 { + self.0.as_ptr() + } + + pub fn count_bytes(&self) -> usize { + self.0.len() + } +} + +#[inline] +pub fn with_native_path(path: &Path, f: &dyn Fn(&WCStr) -> io::Result) -> io::Result { + let path = maybe_verbatim(path)?; + // SAFETY: maybe_verbatim returns null-terminated strings + let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) }; + f(path) +} + #[inline] pub fn is_sep_byte(b: u8) -> bool { b == b'/' || b == b'\\' From e013cf8afcf74a5f27feb7ebb0dca248e5c489fe Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 11 Apr 2025 11:35:10 -0700 Subject: [PATCH 072/222] rustdoc-search: add unbox flag to Result aliases Fixes #139665 --- compiler/rustc_passes/src/check_attr.rs | 1 + library/std/src/io/error.rs | 1 + library/std/src/thread/mod.rs | 1 + tests/rustdoc-js-std/unbox-type-result.js | 20 ++++++++++++++++++++ tests/rustdoc-js/generics-unbox.js | 6 ++++++ tests/rustdoc-js/generics-unbox.rs | 12 ++++++++++++ 6 files changed, 41 insertions(+) create mode 100644 tests/rustdoc-js-std/unbox-type-result.js diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9161b23428a0..c51425078122 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1109,6 +1109,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ItemKind::Trait(_, _, _, generics, _, items) if generics.params.len() != 0 || items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {} + ItemKind::TyAlias(_, _, generics) if generics.params.len() != 0 => {} _ => { self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() }); } diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 2498fb8d24fb..cf3778bd2907 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -48,6 +48,7 @@ use crate::{error, fmt, result, sys}; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), doc(search_unbox))] pub type Result = result::Result; /// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 3f3ba02361cc..2097f1e304ce 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1676,6 +1676,7 @@ impl fmt::Debug for Thread { /// [`Result`]: crate::result::Result /// [`std::panic::resume_unwind`]: crate::panic::resume_unwind #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), doc(search_unbox))] pub type Result = crate::result::Result>; // This packet is used to communicate the return value between the spawned diff --git a/tests/rustdoc-js-std/unbox-type-result.js b/tests/rustdoc-js-std/unbox-type-result.js new file mode 100644 index 000000000000..1f5cba58adf6 --- /dev/null +++ b/tests/rustdoc-js-std/unbox-type-result.js @@ -0,0 +1,20 @@ +// exact-check + +// Test case for https://github.com/rust-lang/rust/issues/139665 +// make sure that std::io::Result and std::thread::Result get unboxed + +const EXPECTED = [ + { + query: "File -> Metadata", + others: [ + { path: "std::fs::File", name: "metadata" }, + { path: "std::fs::File", name: "metadata_at" }, + ] + }, + { + query: "JoinHandle -> T", + others: [ + { path: "std::thread::JoinHandle", name: "join" }, + ] + }, +]; diff --git a/tests/rustdoc-js/generics-unbox.js b/tests/rustdoc-js/generics-unbox.js index 6baf00c814bb..a4f2ba8e3a63 100644 --- a/tests/rustdoc-js/generics-unbox.js +++ b/tests/rustdoc-js/generics-unbox.js @@ -31,4 +31,10 @@ const EXPECTED = [ { 'path': 'generics_unbox', 'name': 'beta' }, ], }, + { + 'query': '-> Sigma', + 'others': [ + { 'path': 'generics_unbox', 'name': 'delta' }, + ], + }, ]; diff --git a/tests/rustdoc-js/generics-unbox.rs b/tests/rustdoc-js/generics-unbox.rs index c2578575997b..b16e35ee3d46 100644 --- a/tests/rustdoc-js/generics-unbox.rs +++ b/tests/rustdoc-js/generics-unbox.rs @@ -42,3 +42,15 @@ pub fn beta(_: Inside) -> Out, Out4> { pub fn gamma(_: Inside) -> Out, Out4> { loop {} } + +pub fn delta(_: i32) -> Epsilon { + loop {} +} + +#[doc(search_unbox)] +pub struct Theta(T); + +#[doc(search_unbox)] +pub type Epsilon = Theta; + +pub struct Sigma; From 394610b6d6b0bde38f75b7cc41ec1931bb7f0323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 11 Apr 2025 21:30:10 +0200 Subject: [PATCH 073/222] Document that `opt-dist` requires metrics to be enabled --- src/doc/rustc-dev-guide/src/building/optimized-build.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md index 0849464eab36..62dfaca89d24 100644 --- a/src/doc/rustc-dev-guide/src/building/optimized-build.md +++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md @@ -109,11 +109,16 @@ like Python or LLVM. Here is an example of how can `opt-dist` be used locally (outside of CI): -1. Build the tool with the following command: +1. Enable metrics in your `bootstrap.toml` file, because `opt-dist` expects it to be enabled: + ```toml + [build] + metrics = true + ``` +2. Build the tool with the following command: ```bash ./x build tools/opt-dist ``` -2. Run the tool with the `local` mode and provide necessary parameters: +3. Run the tool with the `local` mode and provide necessary parameters: ```bash ./build/host/stage0-tools-bin/opt-dist local \ --target-triple \ # select target, e.g. "x86_64-unknown-linux-gnu" From 52b7571707f6873175dfcd46468207640ba056d5 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 11 Apr 2025 23:00:05 -0400 Subject: [PATCH 074/222] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 0e93c5bf6a1d..864f74d4eadc 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 0e93c5bf6a1d5ee7bc2af63d1afb16cd28793601 +Subproject commit 864f74d4eadcaea3eeda37a2e7f4d34de233d51e From 072678ec8631797fb2a8c4555e11418ae5e601f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Sat, 12 Apr 2025 02:18:40 -0400 Subject: [PATCH 075/222] docs: clarify uint exponent for `is_power_of_two` --- library/core/src/num/uint_macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 1b2acdc5a0df..3678bb091e7d 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -3343,7 +3343,7 @@ macro_rules! uint_impl { } } - /// Returns `true` if and only if `self == 2^k` for some `k`. + /// Returns `true` if and only if `self == 2^k` for some unsigned integer `k`. /// /// # Examples /// From 41931320f83f8c7742597e1d1a965901e563b3b1 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 2 Apr 2025 16:41:40 +0800 Subject: [PATCH 076/222] run-make-support: fix artifact name calculations for target This was implemented incorrectly during the porting process, where we relied on std consts. However, `run-make-support` is a host-only library, which meant that these artifact names were for the *host* and not the *target*. --- .../run-make-support/src/artifact_names.rs | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs index 8968f831542e..b0d588d3550a 100644 --- a/src/tools/run-make-support/src/artifact_names.rs +++ b/src/tools/run-make-support/src/artifact_names.rs @@ -1,11 +1,11 @@ //! A collection of helpers to construct artifact names, such as names of dynamic or static -//! librarys which are target-dependent. - -// FIXME(jieyouxu): convert these to return `PathBuf`s instead of strings! +//! libraries which are target-dependent. +use crate::target; use crate::targets::is_msvc; /// Construct the static library name based on the target. +#[track_caller] #[must_use] pub fn static_lib_name(name: &str) -> String { assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace"); @@ -14,15 +14,34 @@ pub fn static_lib_name(name: &str) -> String { } /// Construct the dynamic library name based on the target. +#[track_caller] #[must_use] pub fn dynamic_lib_name(name: &str) -> String { assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace"); - format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION) + format!("{}{name}.{}", dynamic_lib_prefix(), dynamic_lib_extension()) } -/// Construct the name of the import library for the dynamic library, exclusive to MSVC and -/// accepted by link.exe. +fn dynamic_lib_prefix() -> &'static str { + if target().contains("windows") { "" } else { "lib" } +} + +/// Construct the dynamic library extension based on the target. +#[must_use] +pub fn dynamic_lib_extension() -> &'static str { + let target = target(); + + if target.contains("apple") { + "dylib" + } else if target.contains("windows") { + "dll" + } else { + "so" + } +} + +/// Construct the name of the import library for the dynamic library, exclusive to MSVC and accepted +/// by link.exe. #[track_caller] #[must_use] pub fn msvc_import_dynamic_lib_name(name: &str) -> String { @@ -32,20 +51,28 @@ pub fn msvc_import_dynamic_lib_name(name: &str) -> String { format!("{name}.dll.lib") } -/// Construct the dynamic library extension based on the target. -#[must_use] -pub fn dynamic_lib_extension() -> &'static str { - std::env::consts::DLL_EXTENSION -} - /// Construct the name of a rust library (rlib). +#[track_caller] #[must_use] pub fn rust_lib_name(name: &str) -> String { format!("lib{name}.rlib") } /// Construct the binary (executable) name based on the target. +#[track_caller] #[must_use] pub fn bin_name(name: &str) -> String { - format!("{name}{}", std::env::consts::EXE_SUFFIX) + let target = target(); + + if target.contains("windows") { + format!("{name}.exe") + } else if target.contains("uefi") { + format!("{name}.efi") + } else if target.contains("wasm") { + format!("{name}.wasm") + } else if target.contains("nvptx") { + format!("{name}.ptx") + } else { + name.to_string() + } } From 4362789eb0b3001905f338a6e865c437b4756461 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 4 Apr 2025 10:40:38 +0800 Subject: [PATCH 077/222] tests: produce target artifacts and/or require crate type / ignore cross-compile Some tests fail on cross-compiled targets due to various linker problems on cross-compiled target, and having test coverage for these against cross-compiled targets is nice but not necessary. --- tests/run-make/crate-data-smoke/rmake.rs | 32 ++++++++++++++++--- tests/run-make/crate-name-priority/rmake.rs | 2 ++ .../extra-filename-with-temp-outputs/rmake.rs | 2 ++ .../output-type-permutations/rmake.rs | 4 +++ tests/run-make/reproducible-build/rmake.rs | 2 ++ tests/run-make/strip/rmake.rs | 3 +- tests/run-make/symbols-all-mangled/rmake.rs | 2 ++ 7 files changed, 41 insertions(+), 6 deletions(-) diff --git a/tests/run-make/crate-data-smoke/rmake.rs b/tests/run-make/crate-data-smoke/rmake.rs index 70f8e46b6d92..b5708d05a82b 100644 --- a/tests/run-make/crate-data-smoke/rmake.rs +++ b/tests/run-make/crate-data-smoke/rmake.rs @@ -1,9 +1,20 @@ -use run_make_support::{bin_name, rust_lib_name, rustc}; +use run_make_support::{bin_name, rust_lib_name, rustc, target}; fn main() { - rustc().print("crate-name").input("crate.rs").run().assert_stdout_equals("foo"); - rustc().print("file-names").input("crate.rs").run().assert_stdout_equals(bin_name("foo")); rustc() + .target(target()) + .print("crate-name") + .input("crate.rs") + .run() + .assert_stdout_equals("foo"); + rustc() + .target(target()) + .print("file-names") + .input("crate.rs") + .run() + .assert_stdout_equals(bin_name("foo")); + rustc() + .target(target()) .print("file-names") .crate_type("lib") .arg("--test") @@ -11,11 +22,22 @@ fn main() { .run() .assert_stdout_equals(bin_name("foo")); rustc() + .target(target()) .print("file-names") .arg("--test") .input("lib.rs") .run() .assert_stdout_equals(bin_name("mylib")); - rustc().print("file-names").input("lib.rs").run().assert_stdout_equals(rust_lib_name("mylib")); - rustc().print("file-names").input("rlib.rs").run().assert_stdout_equals(rust_lib_name("mylib")); + rustc() + .target(target()) + .print("file-names") + .input("lib.rs") + .run() + .assert_stdout_equals(rust_lib_name("mylib")); + rustc() + .target(target()) + .print("file-names") + .input("rlib.rs") + .run() + .assert_stdout_equals(rust_lib_name("mylib")); } diff --git a/tests/run-make/crate-name-priority/rmake.rs b/tests/run-make/crate-name-priority/rmake.rs index 5bdb49b33cea..82e482b5a2ef 100644 --- a/tests/run-make/crate-name-priority/rmake.rs +++ b/tests/run-make/crate-name-priority/rmake.rs @@ -4,6 +4,8 @@ // and the compiler flags, and checks that the flag is favoured each time. // See https://github.com/rust-lang/rust/pull/15518 +//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`) + use run_make_support::{bin_name, rfs, rustc}; fn main() { diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs index 0910045bb857..f93a3ecc8d1b 100644 --- a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs +++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs @@ -6,6 +6,8 @@ // are named as expected. // See https://github.com/rust-lang/rust/pull/15686 +//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`) + use run_make_support::{bin_name, cwd, has_prefix, has_suffix, rfs, rustc, shallow_find_files}; fn main() { diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs index c0569af6e84a..8da0bfaa12db 100644 --- a/tests/run-make/output-type-permutations/rmake.rs +++ b/tests/run-make/output-type-permutations/rmake.rs @@ -4,6 +4,9 @@ // files are exactly what is expected, no more, no less. // See https://github.com/rust-lang/rust/pull/12020 +//@ ignore-cross-compile +// Reason: some cross-compiled targets don't support various crate types and fail to link. + use std::path::PathBuf; use run_make_support::{ @@ -17,6 +20,7 @@ use run_make_support::{ // `dir`: the name of the directory where the test happens // `rustc_invocation`: the rustc command being tested // Any unexpected output files not listed in `must_exist` or `can_exist` will cause a failure. +#[track_caller] fn assert_expected_output_files(expectations: Expectations, rustc_invocation: impl Fn()) { let Expectations { expected_files: must_exist, allowed_files: can_exist, test_dir: dir } = expectations; diff --git a/tests/run-make/reproducible-build/rmake.rs b/tests/run-make/reproducible-build/rmake.rs index 8a8b0d6d652b..93fc30de07d7 100644 --- a/tests/run-make/reproducible-build/rmake.rs +++ b/tests/run-make/reproducible-build/rmake.rs @@ -20,6 +20,8 @@ // See https://github.com/rust-lang/rust/pull/32293 // Tracking Issue: https://github.com/rust-lang/rust/issues/129080 +//@ ignore-cross-compile (linker binary needs to run) + use run_make_support::{ bin_name, cwd, diff, is_darwin, is_windows, regex, rfs, run_in_tmpdir, rust_lib_name, rustc, }; diff --git a/tests/run-make/strip/rmake.rs b/tests/run-make/strip/rmake.rs index ef1acc26b455..01b31ac30948 100644 --- a/tests/run-make/strip/rmake.rs +++ b/tests/run-make/strip/rmake.rs @@ -1,4 +1,5 @@ -//@ ignore-windows Windows does not actually strip +//@ ignore-windows (Windows does not actually strip) +//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`) // Test that -Cstrip correctly strips/preserves debuginfo and symbols. diff --git a/tests/run-make/symbols-all-mangled/rmake.rs b/tests/run-make/symbols-all-mangled/rmake.rs index 1fb03c62399a..79ddd06bb94b 100644 --- a/tests/run-make/symbols-all-mangled/rmake.rs +++ b/tests/run-make/symbols-all-mangled/rmake.rs @@ -1,5 +1,7 @@ // Check that all symbols in cdylibs, staticlibs and bins are mangled //@ only-elf some object file formats create multiple symbols for each function with different names +//@ ignore-nvptx64 (needs target std) +//@ ignore-cross-compile (host-only) use run_make_support::object::read::{Object, ObjectSymbol}; use run_make_support::{bin_name, dynamic_lib_name, object, rfs, rustc, static_lib_name}; From 762ecf8e00504ba3b19c688497fd016ee781c19d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Apr 2025 15:18:01 +0800 Subject: [PATCH 078/222] tests/ui: remove outdated README We should consolidate our test suite docs in rustc-dev-guide, and this README is very outdated. --- tests/ui/README.md | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 tests/ui/README.md diff --git a/tests/ui/README.md b/tests/ui/README.md deleted file mode 100644 index aa36481ae06e..000000000000 --- a/tests/ui/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# UI Tests - -This folder contains `rustc`'s -[UI tests](https://rustc-dev-guide.rust-lang.org/tests/ui.html). - -## Test Directives (Headers) - -Typically, a UI test will have some test directives / headers which are -special comments that tell compiletest how to build and interpret a test. - -As part of an ongoing effort to rewrite compiletest -(see ), a major -change proposal to change legacy compiletest-style headers `// ` -to [`ui_test`](https://github.com/oli-obk/ui_test)-style headers -`//@ ` was accepted (see -. - -An example directive is `ignore-test`. In legacy compiletest style, the header -would be written as - -```rs -// ignore-test -``` - -but in `ui_test` style, the header would be written as - -```rs -//@ ignore-test -``` - -compiletest is changed to accept only `//@` directives for UI tests -(currently), and will reject and report an error if it encounters any -comments `// ` that may be parsed as a legacy compiletest-style -test header. To fix this, you should migrate to the `ui_test`-style header -`//@ `. From db6e3aa91387ea8abe2cc29cd4b8e245074472da Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Apr 2025 15:24:25 +0800 Subject: [PATCH 079/222] tests: ensure disabled tests have a reason --- tests/ui/bootstrap/self-test/a.rs | 2 +- tests/ui/bootstrap/self-test/b.rs | 2 +- tests/ui/lint/unknown-lints/other.rs | 2 +- tests/ui/precondition-checks/read.rs | 2 +- tests/ui/precondition-checks/write.rs | 2 +- tests/ui/precondition-checks/write_bytes.rs | 2 +- .../next-solver/object-soundness-requires-generalization.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/ui/bootstrap/self-test/a.rs b/tests/ui/bootstrap/self-test/a.rs index 64d2d6f11bbd..b8abd8179c91 100644 --- a/tests/ui/bootstrap/self-test/a.rs +++ b/tests/ui/bootstrap/self-test/a.rs @@ -1,2 +1,2 @@ //! Not used by compiler, this is used by bootstrap cli self-test. -//@ ignore-test +//@ ignore-test (used by bootstrap) diff --git a/tests/ui/bootstrap/self-test/b.rs b/tests/ui/bootstrap/self-test/b.rs index 91f92f67910b..5bbd2f946feb 100644 --- a/tests/ui/bootstrap/self-test/b.rs +++ b/tests/ui/bootstrap/self-test/b.rs @@ -1,2 +1,2 @@ //! Not used by compiler, used by bootstrap cli self-test. -//@ ignore-test +//@ ignore-test (used by bootstrap) diff --git a/tests/ui/lint/unknown-lints/other.rs b/tests/ui/lint/unknown-lints/other.rs index f917bff6d602..253335849161 100644 --- a/tests/ui/lint/unknown-lints/other.rs +++ b/tests/ui/lint/unknown-lints/other.rs @@ -1,4 +1,4 @@ -//@ ignore-test +//@ ignore-test (auxiliary) // Companion to allow-in-other-module.rs diff --git a/tests/ui/precondition-checks/read.rs b/tests/ui/precondition-checks/read.rs index ab9921a0ceeb..d5ab7773987f 100644 --- a/tests/ui/precondition-checks/read.rs +++ b/tests/ui/precondition-checks/read.rs @@ -2,7 +2,7 @@ //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::read requires //@ revisions: null misaligned -//@ ignore-test +//@ ignore-test (unimplemented) use std::ptr; diff --git a/tests/ui/precondition-checks/write.rs b/tests/ui/precondition-checks/write.rs index f76e776fcf35..5d6b9586fad7 100644 --- a/tests/ui/precondition-checks/write.rs +++ b/tests/ui/precondition-checks/write.rs @@ -2,7 +2,7 @@ //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::write requires //@ revisions: null misaligned -//@ ignore-test +//@ ignore-test (unimplemented) use std::ptr; diff --git a/tests/ui/precondition-checks/write_bytes.rs b/tests/ui/precondition-checks/write_bytes.rs index 3f64be9d1ee1..be4f5a089f03 100644 --- a/tests/ui/precondition-checks/write_bytes.rs +++ b/tests/ui/precondition-checks/write_bytes.rs @@ -2,7 +2,7 @@ //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::write requires //@ revisions: null misaligned -//@ ignore-test +//@ ignore-test (unimplemented) use std::ptr; diff --git a/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs index 11a2617ad427..3ef6bea4fd5c 100644 --- a/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs +++ b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -//@ ignore-test +//@ ignore-test (see #114196) trait Trait { type Gat<'lt>; From 86e2a07a13ce7fd6f68c71802db8f8c8eebe0ad0 Mon Sep 17 00:00:00 2001 From: Maksim Bondarenkov Date: Sat, 12 Apr 2025 10:52:46 +0300 Subject: [PATCH 080/222] opt-dist: use executable-extension for host llvm-profdata so the merging step doesn't fail for `opt-dist local` on Windows --- src/tools/opt-dist/src/training.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 30c79f959474..47159a43140f 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -70,7 +70,9 @@ fn merge_llvm_profiles( profdata: LlvmProfdata, ) -> anyhow::Result<()> { let llvm_profdata = match profdata { - LlvmProfdata::Host => env.host_llvm_dir().join("bin/llvm-profdata"), + LlvmProfdata::Host => { + env.host_llvm_dir().join(format!("bin/llvm-profdata{}", executable_extension())) + } LlvmProfdata::Target => env .build_artifacts() .join("llvm") From ddf8237bcb05272a677cba46cffa0296b7477809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 12 Apr 2025 10:05:50 +0200 Subject: [PATCH 081/222] Fix comment in bootstrap --- src/bootstrap/src/core/build_steps/tool.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 1c61f0a56d7b..ded7220fcedc 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -150,10 +150,7 @@ impl Step for ToolBuild { // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer) // could use the additional optimizations. - if self.mode == Mode::ToolRustc && - // rustdoc is performance sensitive, so apply LTO to it. - is_lto_stage(&self.compiler) - { + if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) { let lto = match builder.config.rust_lto { RustcLto::Off => Some("off"), RustcLto::Thin => Some("thin"), From 83dd8a2c2a7d948e669adc7170dfc4bf0b76a873 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 12 Apr 2025 11:33:33 +0200 Subject: [PATCH 082/222] Fix name of field in doc comment --- compiler/rustc_hir/src/hir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c9c4936c1564..6455f33b9d15 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1756,7 +1756,7 @@ pub enum PatKind<'hir> { Never, /// A tuple pattern (e.g., `(a, b)`). - /// If the `..` pattern fragment is present, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position. /// `0 <= position <= subpats.len()` Tuple(&'hir [Pat<'hir>], DotDotPos), From 32dd3831f56973881ad2a47d4b4002d18de26c5f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 12 Apr 2025 11:38:55 +0200 Subject: [PATCH 083/222] bootstrap: fix typo in doc string --- src/bootstrap/src/core/download.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 5bd947f6e636..4e4b948a8fd6 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -417,7 +417,7 @@ enum DownloadSource { Dist, } -/// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions. +/// Functions that are only ever called once, but named for clarity and to avoid thousand-line functions. impl Config { pub(crate) fn download_clippy(&self) -> PathBuf { self.verbose(|| println!("downloading stage0 clippy artifacts")); From 6ffebb65d6daf4fcc82cfc7fd14397bff98df1f2 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 12 Apr 2025 02:26:17 -0700 Subject: [PATCH 084/222] Move args into std::sys --- .../{pal/hermit/args.rs => args/hermit.rs} | 0 library/std/src/sys/args/mod.rs | 34 +++++++++++++++++++ .../src/sys/{pal/sgx/args.rs => args/sgx.rs} | 6 ++-- .../sys/{pal/uefi/args.rs => args/uefi.rs} | 2 +- .../sys/{pal/unix/args.rs => args/unix.rs} | 8 ++--- .../args.rs => args/unsupported.rs} | 0 .../sys/{pal/wasi/args.rs => args/wasi.rs} | 0 .../{pal/windows/args.rs => args/windows.rs} | 9 ++--- .../windows/args => args/windows}/tests.rs | 0 .../sys/{pal/xous/args.rs => args/xous.rs} | 4 +-- .../sys/{pal/zkvm/args.rs => args/zkvm.rs} | 2 +- library/std/src/sys/mod.rs | 1 + library/std/src/sys/pal/hermit/mod.rs | 3 +- library/std/src/sys/pal/sgx/mod.rs | 3 +- library/std/src/sys/pal/solid/mod.rs | 2 -- library/std/src/sys/pal/teeos/mod.rs | 2 -- library/std/src/sys/pal/trusty/mod.rs | 2 -- library/std/src/sys/pal/uefi/mod.rs | 1 - library/std/src/sys/pal/unix/mod.rs | 3 +- library/std/src/sys/pal/unsupported/mod.rs | 1 - library/std/src/sys/pal/wasi/mod.rs | 1 - library/std/src/sys/pal/wasip2/mod.rs | 2 -- library/std/src/sys/pal/wasm/mod.rs | 2 -- library/std/src/sys/pal/windows/mod.rs | 1 - library/std/src/sys/pal/xous/mod.rs | 1 - library/std/src/sys/pal/zkvm/mod.rs | 4 +-- 26 files changed, 53 insertions(+), 41 deletions(-) rename library/std/src/sys/{pal/hermit/args.rs => args/hermit.rs} (100%) create mode 100644 library/std/src/sys/args/mod.rs rename library/std/src/sys/{pal/sgx/args.rs => args/sgx.rs} (89%) rename library/std/src/sys/{pal/uefi/args.rs => args/uefi.rs} (99%) rename library/std/src/sys/{pal/unix/args.rs => args/unix.rs} (98%) rename library/std/src/sys/{pal/unsupported/args.rs => args/unsupported.rs} (100%) rename library/std/src/sys/{pal/wasi/args.rs => args/wasi.rs} (100%) rename library/std/src/sys/{pal/windows/args.rs => args/windows.rs} (99%) rename library/std/src/sys/{pal/windows/args => args/windows}/tests.rs (100%) rename library/std/src/sys/{pal/xous/args.rs => args/xous.rs} (91%) rename library/std/src/sys/{pal/zkvm/args.rs => args/zkvm.rs} (98%) diff --git a/library/std/src/sys/pal/hermit/args.rs b/library/std/src/sys/args/hermit.rs similarity index 100% rename from library/std/src/sys/pal/hermit/args.rs rename to library/std/src/sys/args/hermit.rs diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs new file mode 100644 index 000000000000..6edcafe2c4c5 --- /dev/null +++ b/library/std/src/sys/args/mod.rs @@ -0,0 +1,34 @@ +//! Platform-dependent command line arguments abstraction. + +#![forbid(unsafe_op_in_unsafe_fn)] + +cfg_if::cfg_if! { + if #[cfg(target_family = "unix")] { + mod unix; + pub use unix::*; + } else if #[cfg(target_family = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod sgx; + pub use sgx::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else if #[cfg(target_os = "xous")] { + mod xous; + pub use xous::*; + } else if #[cfg(target_os = "zkvm")] { + mod zkvm; + pub use zkvm::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/library/std/src/sys/pal/sgx/args.rs b/library/std/src/sys/args/sgx.rs similarity index 89% rename from library/std/src/sys/pal/sgx/args.rs rename to library/std/src/sys/args/sgx.rs index e62bf383954e..efc4b7918522 100644 --- a/library/std/src/sys/pal/sgx/args.rs +++ b/library/std/src/sys/args/sgx.rs @@ -1,8 +1,10 @@ -use super::abi::usercalls::alloc; -use super::abi::usercalls::raw::ByteBuffer; +#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers + use crate::ffi::OsString; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::os_str::Buf; +use crate::sys::pal::abi::usercalls::alloc; +use crate::sys::pal::abi::usercalls::raw::ByteBuffer; use crate::sys_common::FromInner; use crate::{fmt, slice}; diff --git a/library/std/src/sys/pal/uefi/args.rs b/library/std/src/sys/args/uefi.rs similarity index 99% rename from library/std/src/sys/pal/uefi/args.rs rename to library/std/src/sys/args/uefi.rs index 0c29caf2db67..4e7412937bd1 100644 --- a/library/std/src/sys/pal/uefi/args.rs +++ b/library/std/src/sys/args/uefi.rs @@ -1,9 +1,9 @@ use r_efi::protocols::loaded_image; -use super::helpers; use crate::env::current_exe; use crate::ffi::OsString; use crate::iter::Iterator; +use crate::sys::pal::helpers; use crate::{fmt, vec}; pub struct Args { diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/args/unix.rs similarity index 98% rename from library/std/src/sys/pal/unix/args.rs rename to library/std/src/sys/args/unix.rs index 0bb7b64007ab..4c30609c0995 100644 --- a/library/std/src/sys/pal/unix/args.rs +++ b/library/std/src/sys/args/unix.rs @@ -11,7 +11,7 @@ use crate::{fmt, vec}; /// One-time global initialization. pub unsafe fn init(argc: isize, argv: *const *const u8) { - imp::init(argc, argv) + unsafe { imp::init(argc, argv) } } /// Returns the command line arguments @@ -141,7 +141,7 @@ mod imp { pub unsafe fn init(argc: isize, argv: *const *const u8) { // on GNU/Linux if we are main then we will init argv and argc twice, it "duplicates work" // BUT edge-cases are real: only using .init_array can break most emulators, dlopen, etc. - really_init(argc, argv); + unsafe { really_init(argc, argv) }; } /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension. @@ -159,9 +159,7 @@ mod imp { argv: *const *const u8, _envp: *const *const u8, ) { - unsafe { - really_init(argc as isize, argv); - } + unsafe { really_init(argc as isize, argv) }; } init_wrapper }; diff --git a/library/std/src/sys/pal/unsupported/args.rs b/library/std/src/sys/args/unsupported.rs similarity index 100% rename from library/std/src/sys/pal/unsupported/args.rs rename to library/std/src/sys/args/unsupported.rs diff --git a/library/std/src/sys/pal/wasi/args.rs b/library/std/src/sys/args/wasi.rs similarity index 100% rename from library/std/src/sys/pal/wasi/args.rs rename to library/std/src/sys/args/wasi.rs diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/args/windows.rs similarity index 99% rename from library/std/src/sys/pal/windows/args.rs rename to library/std/src/sys/args/windows.rs index d973743639ab..55bd6864cae3 100644 --- a/library/std/src/sys/pal/windows/args.rs +++ b/library/std/src/sys/args/windows.rs @@ -6,17 +6,17 @@ #[cfg(test)] mod tests; -use super::ensure_no_nuls; -use super::os::current_exe; use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; +use crate::sys::pal::os::current_exe; +use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::path::get_long_path; use crate::sys::{c, to_u16s}; use crate::sys_common::AsInner; use crate::sys_common::wstr::WStrUnits; -use crate::{fmt, io, iter, vec}; +use crate::{fmt, io, iter, ptr, vec}; pub fn args() -> Args { // SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16 @@ -384,9 +384,6 @@ pub(crate) fn to_user_path(path: &Path) -> io::Result> { from_wide_to_user_path(to_u16s(path)?) } pub(crate) fn from_wide_to_user_path(mut path: Vec) -> io::Result> { - use super::fill_utf16_buf; - use crate::ptr; - // UTF-16 encoded code points, used in parsing and building UTF-16 paths. // All of these are in the ASCII range so they can be cast directly to `u16`. const SEP: u16 = b'\\' as _; diff --git a/library/std/src/sys/pal/windows/args/tests.rs b/library/std/src/sys/args/windows/tests.rs similarity index 100% rename from library/std/src/sys/pal/windows/args/tests.rs rename to library/std/src/sys/args/windows/tests.rs diff --git a/library/std/src/sys/pal/xous/args.rs b/library/std/src/sys/args/xous.rs similarity index 91% rename from library/std/src/sys/pal/xous/args.rs rename to library/std/src/sys/args/xous.rs index 00c44ca220a9..2dd37d53422f 100644 --- a/library/std/src/sys/pal/xous/args.rs +++ b/library/std/src/sys/args/xous.rs @@ -1,6 +1,6 @@ use crate::ffi::OsString; -use crate::sys::pal::xous::os::get_application_parameters; -use crate::sys::pal::xous::os::params::ArgumentList; +use crate::sys::pal::os::get_application_parameters; +use crate::sys::pal::os::params::ArgumentList; use crate::{fmt, vec}; pub struct Args { diff --git a/library/std/src/sys/pal/zkvm/args.rs b/library/std/src/sys/args/zkvm.rs similarity index 98% rename from library/std/src/sys/pal/zkvm/args.rs rename to library/std/src/sys/args/zkvm.rs index 47857f6c448b..194ba7159d45 100644 --- a/library/std/src/sys/pal/zkvm/args.rs +++ b/library/std/src/sys/args/zkvm.rs @@ -1,7 +1,7 @@ -use super::{WORD_SIZE, abi}; use crate::ffi::OsString; use crate::fmt; use crate::sys::os_str; +use crate::sys::pal::{WORD_SIZE, abi}; use crate::sys_common::FromInner; pub struct Args { diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index f8f220fafd1d..bc4bf11cb740 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -9,6 +9,7 @@ mod alloc; mod personality; pub mod anonymous_pipe; +pub mod args; pub mod backtrace; pub mod cmath; pub mod exit_guard; diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 26211bcb1520..821836824e2b 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -18,7 +18,6 @@ use crate::os::raw::c_char; -pub mod args; pub mod env; pub mod futex; pub mod os; @@ -58,7 +57,7 @@ pub extern "C" fn __rust_abort() { // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { unsafe { - args::init(argc, argv); + crate::sys::args::init(argc, argv); } } diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 52684e18ac27..8a87e7a7ae13 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -9,7 +9,6 @@ use crate::io::ErrorKind; use crate::sync::atomic::{AtomicBool, Ordering}; pub mod abi; -pub mod args; pub mod env; mod libunwind_integration; pub mod os; @@ -24,7 +23,7 @@ pub mod waitqueue; // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { unsafe { - args::init(argc, argv); + crate::sys::args::init(argc, argv); } } diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 22052a168fd1..c41dc848a1b4 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -16,8 +16,6 @@ pub mod itron { use super::unsupported; } -#[path = "../unsupported/args.rs"] -pub mod args; pub mod env; // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `crate::sys::error` diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index c1921a2f40df..b8095cec3e97 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -6,8 +6,6 @@ #![allow(unused_variables)] #![allow(dead_code)] -#[path = "../unsupported/args.rs"] -pub mod args; #[path = "../unsupported/env.rs"] pub mod env; //pub mod fd; diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs index 5295d3fdc914..04e6b4c81868 100644 --- a/library/std/src/sys/pal/trusty/mod.rs +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -1,7 +1,5 @@ //! System bindings for the Trusty OS. -#[path = "../unsupported/args.rs"] -pub mod args; #[path = "../unsupported/common.rs"] #[deny(unsafe_op_in_unsafe_fn)] mod common; diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 9760a23084aa..cd901f48b76f 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -13,7 +13,6 @@ //! [`OsString`]: crate::ffi::OsString #![forbid(unsafe_op_in_unsafe_fn)] -pub mod args; pub mod env; pub mod helpers; pub mod os; diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index d7106c339747..20078839a14e 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -6,7 +6,6 @@ use crate::io::ErrorKind; #[macro_use] pub mod weak; -pub mod args; pub mod env; #[cfg(target_os = "fuchsia")] pub mod fuchsia; @@ -47,7 +46,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { reset_sigpipe(sigpipe); stack_overflow::init(); - args::init(argc, argv); + crate::sys::args::init(argc, argv); // Normally, `thread::spawn` will call `Thread::set_name` but since this thread // already exists, we have to call it ourselves. We only do this on Apple targets diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index 38838b915b5c..dea42a95dcc6 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -1,6 +1,5 @@ #![deny(unsafe_op_in_unsafe_fn)] -pub mod args; pub mod env; pub mod os; pub mod pipe; diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 80853e7b5a26..4ea42b1082b1 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -13,7 +13,6 @@ //! compiling for wasm. That way it's a compile time error for something that's //! guaranteed to be a runtime error! -pub mod args; pub mod env; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 504b947d09e2..6445bf2cc0d2 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -6,8 +6,6 @@ //! To begin with, this target mirrors the wasi target 1 to 1, but over //! time this will change significantly. -#[path = "../wasi/args.rs"] -pub mod args; #[path = "../wasi/env.rs"] pub mod env; #[allow(unused)] diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index 8d39b70d0397..af370020d96a 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -16,8 +16,6 @@ #![deny(unsafe_op_in_unsafe_fn)] -#[path = "../unsupported/args.rs"] -pub mod args; pub mod env; #[path = "../unsupported/os.rs"] pub mod os; diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index bdf0cc2c59cf..3c0a5c2de263 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -14,7 +14,6 @@ pub mod compat; pub mod api; -pub mod args; pub mod c; pub mod env; #[cfg(not(target_vendor = "win7"))] diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 58926e2beb1d..4f652d3f130d 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -1,6 +1,5 @@ #![forbid(unsafe_op_in_unsafe_fn)] -pub mod args; #[path = "../unsupported/env.rs"] pub mod env; pub mod os; diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 4659dad16e85..ebd7b0367798 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -8,11 +8,9 @@ //! will likely change over time. #![forbid(unsafe_op_in_unsafe_fn)] -const WORD_SIZE: usize = size_of::(); +pub const WORD_SIZE: usize = size_of::(); pub mod abi; -#[path = "../zkvm/args.rs"] -pub mod args; pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] From 6c6a39e6bfd10bccbf6ca99479655a9ef8d87b39 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Sat, 12 Apr 2025 10:49:39 +0000 Subject: [PATCH 085/222] cfg(kcfi) --- library/core/src/fmt/mod.rs | 2 +- library/core/src/fmt/rt.rs | 7 +++++++ tests/coverage/closure.cov-map | 18 ++++++++++-------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 580f95eddce7..7ca390941bcd 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -7,7 +7,7 @@ use crate::char::{EscapeDebugExtArgs, MAX_LEN_UTF8}; use crate::marker::PhantomData; use crate::num::fmt as numfmt; use crate::ops::Deref; -use crate::{iter, result, str}; +use crate::{iter, mem, result, str}; mod builders; #[cfg(not(no_fp_fmt_parse))] diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 702aa7e34369..c36feff0b62d 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -72,6 +72,13 @@ macro_rules! argument_new { // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { value: NonNull::<$t>::from_ref($x).cast(), + #[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))] + formatter: { + let f: fn(&$t, &mut Formatter<'_>) -> Result = $f; + // SAFETY: This is only called with `value`, which has the right type. + unsafe { mem::transmute(f) } + }, + #[cfg(any(sanitize = "cfi", sanitize = "kcfi"))] formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| { let func = $f; // SAFETY: This is the same type as the `value` field. diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 640f98956840..2d784ba09b60 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -140,17 +140,19 @@ Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 -Function name: closure::main::{closure#18} (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 01, 0e] +Function name: closure::main::{closure#18} +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 -Number of expressions: 0 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Zero) at (prev + 25, 13) to (start + 2, 28) -- Code(Zero) at (prev + 2, 29) to (start + 2, 18) -- Code(Zero) at (prev + 2, 17) to (start + 0, 18) -- Code(Zero) at (prev + 1, 17) to (start + 1, 14) -Highest counter ID seen: (none) +- Code(Counter(0)) at (prev + 25, 13) to (start + 2, 28) +- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14) +Highest counter ID seen: c1 Function name: closure::main::{closure#19} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] From e014fd6b872edd1af42b00d33a963632107618f9 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 12 Apr 2025 02:37:24 -0700 Subject: [PATCH 086/222] Use unsupported args for espidf and vita --- library/std/src/sys/args/mod.rs | 2 +- library/std/src/sys/args/unix.rs | 13 ------------- library/std/src/sys/pal/unix/mod.rs | 2 ++ 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index 6edcafe2c4c5..f24d6eb123e0 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -3,7 +3,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] cfg_if::cfg_if! { - if #[cfg(target_family = "unix")] { + if #[cfg(all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))))] { mod unix; pub use unix::*; } else if #[cfg(target_family = "windows")] { diff --git a/library/std/src/sys/args/unix.rs b/library/std/src/sys/args/unix.rs index 4c30609c0995..13c459f682ff 100644 --- a/library/std/src/sys/args/unix.rs +++ b/library/std/src/sys/args/unix.rs @@ -226,16 +226,3 @@ mod imp { (argc as isize, argv.cast()) } } - -#[cfg(any(target_os = "espidf", target_os = "vita"))] -mod imp { - use crate::ffi::c_char; - use crate::ptr; - - #[inline(always)] - pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} - - pub fn argc_argv() -> (isize, *const *const c_char) { - (0, ptr::null()) - } -} diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 20078839a14e..f8733eb61198 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -26,6 +26,7 @@ pub mod time; pub fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} #[cfg(not(target_os = "espidf"))] +#[cfg_attr(target_os = "vita", allow(unused_variables))] // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. // See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`. @@ -46,6 +47,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { reset_sigpipe(sigpipe); stack_overflow::init(); + #[cfg(not(target_os = "vita"))] crate::sys::args::init(argc, argv); // Normally, `thread::spawn` will call `Thread::set_name` but since this thread From c36e8fcc3c128e31eaa643904c9b8b33d9a5c1a6 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Fri, 11 Apr 2025 14:26:26 +0000 Subject: [PATCH 087/222] In `rustc_mir_tranform`, iterate over index newtypes instead of ints --- compiler/rustc_index_macros/src/newtype.rs | 7 +++ compiler/rustc_mir_transform/src/coroutine.rs | 53 ++++++++----------- .../src/early_otherwise_branch.rs | 3 +- .../rustc_mir_transform/src/match_branches.rs | 17 +++--- .../src/multiple_return_terminators.rs | 14 +++-- compiler/rustc_mir_transform/src/validate.rs | 5 +- 6 files changed, 46 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index f0b58eabbff9..eedbe630cf2c 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -257,6 +257,13 @@ impl Parse for Newtype { } } + impl std::ops::AddAssign for #name { + #[inline] + fn add_assign(&mut self, other: usize) { + *self = *self + other; + } + } + impl rustc_index::Idx for #name { #[inline] fn new(value: usize) -> Self { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 04d96f117072..80c729d66b1e 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -547,7 +547,7 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None); - for bb in START_BLOCK..body.basic_blocks.next_index() { + for bb in body.basic_blocks.indices() { let bb_data = &body[bb]; if bb_data.is_cleanup { continue; @@ -556,11 +556,11 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { match &bb_data.terminator().kind { TerminatorKind::Call { func, .. } => { let func_ty = func.ty(body, tcx); - if let ty::FnDef(def_id, _) = *func_ty.kind() { - if def_id == get_context_def_id { - let local = eliminate_get_context_call(&mut body[bb]); - replace_resume_ty_local(tcx, body, local, context_mut_ref); - } + if let ty::FnDef(def_id, _) = *func_ty.kind() + && def_id == get_context_def_id + { + let local = eliminate_get_context_call(&mut body[bb]); + replace_resume_ty_local(tcx, body, local, context_mut_ref); } } TerminatorKind::Yield { resume_arg, .. } => { @@ -1057,7 +1057,7 @@ fn insert_switch<'tcx>( let blocks = body.basic_blocks_mut().iter_mut(); for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) { - *target = BasicBlock::new(target.index() + 1); + *target += 1; } } @@ -1209,14 +1209,8 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::Typing } // If there's a return terminator the function may return. - for block in body.basic_blocks.iter() { - if let TerminatorKind::Return = block.terminator().kind { - return true; - } - } - + body.basic_blocks.iter().any(|block| matches!(block.terminator().kind, TerminatorKind::Return)) // Otherwise the function can't return. - false } fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { @@ -1293,12 +1287,12 @@ fn create_coroutine_resume_function<'tcx>( kind: TerminatorKind::Goto { target: poison_block }, }; } - } else if !block.is_cleanup { + } else if !block.is_cleanup // Any terminators that *can* unwind but don't have an unwind target set are also // pointed at our poisoning block (unless they're part of the cleanup path). - if let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() { - *unwind = UnwindAction::Cleanup(poison_block); - } + && let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() + { + *unwind = UnwindAction::Cleanup(poison_block); } } } @@ -1340,12 +1334,14 @@ fn create_coroutine_resume_function<'tcx>( make_coroutine_state_argument_indirect(tcx, body); match transform.coroutine_kind { + CoroutineKind::Coroutine(_) + | CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _) => + { + make_coroutine_state_argument_pinned(tcx, body); + } // Iterator::next doesn't accept a pinned argument, // unlike for all other coroutine kinds. CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {} - _ => { - make_coroutine_state_argument_pinned(tcx, body); - } } // Make sure we remove dead blocks to remove @@ -1408,8 +1404,7 @@ fn create_cases<'tcx>( let mut statements = Vec::new(); // Create StorageLive instructions for locals with live storage - for i in 0..(body.local_decls.len()) { - let l = Local::new(i); + for l in body.local_decls.indices() { let needs_storage_live = point.storage_liveness.contains(l) && !transform.remap.contains(l) && !transform.always_live_locals.contains(l); @@ -1535,15 +1530,10 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let coroutine_kind = body.coroutine_kind().unwrap(); // Get the discriminant type and args which typeck computed - let (discr_ty, movable) = match *coroutine_ty.kind() { - ty::Coroutine(_, args) => { - let args = args.as_coroutine(); - (args.discr_ty(tcx), coroutine_kind.movability() == hir::Movability::Movable) - } - _ => { - tcx.dcx().span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}")); - } + let ty::Coroutine(_, args) = coroutine_ty.kind() else { + tcx.dcx().span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}")); }; + let discr_ty = args.as_coroutine().discr_ty(tcx); let new_ret_ty = match coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { @@ -1610,6 +1600,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let always_live_locals = always_storage_live_locals(body); + let movable = coroutine_kind.movability() == hir::Movability::Movable; let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 57f7893be1b8..d49f5d9f9c38 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -103,9 +103,8 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { let mut should_cleanup = false; // Also consider newly generated bbs in the same pass - for i in 0..body.basic_blocks.len() { + for parent in body.basic_blocks.indices() { let bbs = &*body.basic_blocks; - let parent = BasicBlock::from_usize(i); let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { continue }; trace!("SUCCESS: found optimization possibility to apply: {opt_data:?}"); diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 0d9d0368d372..5059837328e2 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -20,13 +20,11 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let typing_env = body.typing_env(tcx); let mut should_cleanup = false; - for i in 0..body.basic_blocks.len() { - let bbs = &*body.basic_blocks; - let bb_idx = BasicBlock::from_usize(i); - match bbs[bb_idx].terminator().kind { + for bb_idx in body.basic_blocks.indices() { + match &body.basic_blocks[bb_idx].terminator().kind { TerminatorKind::SwitchInt { - discr: ref _discr @ (Operand::Copy(_) | Operand::Move(_)), - ref targets, + discr: Operand::Copy(_) | Operand::Move(_), + targets, .. // We require that the possible target blocks don't contain this block. } if !targets.all_targets().contains(&bb_idx) => {} @@ -66,9 +64,10 @@ trait SimplifyMatch<'tcx> { typing_env: ty::TypingEnv<'tcx>, ) -> Option<()> { let bbs = &body.basic_blocks; - let (discr, targets) = match bbs[switch_bb_idx].terminator().kind { - TerminatorKind::SwitchInt { ref discr, ref targets, .. } => (discr, targets), - _ => unreachable!(), + let TerminatorKind::SwitchInt { discr, targets, .. } = + &bbs[switch_bb_idx].terminator().kind + else { + unreachable!(); }; let discr_ty = discr.ty(body.local_decls(), tcx); diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs index c63bfdcee855..f59b849e85c6 100644 --- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs +++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs @@ -18,19 +18,17 @@ impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators { // find basic blocks with no statement and a return terminator let mut bbs_simple_returns = DenseBitSet::new_empty(body.basic_blocks.len()); let bbs = body.basic_blocks_mut(); - for idx in bbs.indices() { - if bbs[idx].statements.is_empty() - && bbs[idx].terminator().kind == TerminatorKind::Return - { + for (idx, bb) in bbs.iter_enumerated() { + if bb.statements.is_empty() && bb.terminator().kind == TerminatorKind::Return { bbs_simple_returns.insert(idx); } } for bb in bbs { - if let TerminatorKind::Goto { target } = bb.terminator().kind { - if bbs_simple_returns.contains(target) { - bb.terminator_mut().kind = TerminatorKind::Return; - } + if let TerminatorKind::Goto { target } = bb.terminator().kind + && bbs_simple_returns.contains(target) + { + bb.terminator_mut().kind = TerminatorKind::Return; } } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index e7930f0a1e3f..66fe3ef4141f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -221,12 +221,11 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { // Check for cycles let mut stack = FxHashSet::default(); - for i in 0..parent.len() { - let mut bb = BasicBlock::from_usize(i); + for (mut bb, parent) in parent.iter_enumerated_mut() { stack.clear(); stack.insert(bb); loop { - let Some(parent) = parent[bb].take() else { break }; + let Some(parent) = parent.take() else { break }; let no_cycle = stack.insert(parent); if !no_cycle { self.fail( From bea202253ec03e2fdc4c97915a24ebe530277edf Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 12 Apr 2025 04:29:12 -0700 Subject: [PATCH 088/222] Unify owned Args types between platforms --- library/std/src/sys/args/common.rs | 43 ++++++++++++++++++++++++++ library/std/src/sys/args/hermit.rs | 43 ++++---------------------- library/std/src/sys/args/uefi.rs | 47 ++++------------------------- library/std/src/sys/args/unix.rs | 44 ++++----------------------- library/std/src/sys/args/wasi.rs | 40 +++--------------------- library/std/src/sys/args/windows.rs | 40 ++++-------------------- library/std/src/sys/args/xous.rs | 42 ++++---------------------- 7 files changed, 77 insertions(+), 222 deletions(-) create mode 100644 library/std/src/sys/args/common.rs diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs new file mode 100644 index 000000000000..43ac5e959234 --- /dev/null +++ b/library/std/src/sys/args/common.rs @@ -0,0 +1,43 @@ +use crate::ffi::OsString; +use crate::{fmt, vec}; + +pub struct Args { + iter: vec::IntoIter, +} + +impl !Send for Args {} +impl !Sync for Args {} + +impl Args { + pub(super) fn new(args: Vec) -> Self { + Args { iter: args.into_iter() } + } +} + +impl fmt::Debug for Args { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.iter.as_slice().fmt(f) + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} diff --git a/library/std/src/sys/args/hermit.rs b/library/std/src/sys/args/hermit.rs index 440242602773..ddd644a55404 100644 --- a/library/std/src/sys/args/hermit.rs +++ b/library/std/src/sys/args/hermit.rs @@ -1,8 +1,12 @@ use crate::ffi::{CStr, OsString, c_char}; use crate::os::hermit::ffi::OsStringExt; +use crate::ptr; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicIsize, AtomicPtr}; -use crate::{fmt, ptr, vec}; + +#[path = "common.rs"] +mod common; +pub use common::Args; static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); @@ -27,40 +31,5 @@ pub fn args() -> Args { }) .collect(); - Args { iter: args.into_iter() } -} - -pub struct Args { - iter: vec::IntoIter, -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.as_slice().fmt(f) - } -} - -impl !Send for Args {} -impl !Sync for Args {} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } + Args::new(args) } diff --git a/library/std/src/sys/args/uefi.rs b/library/std/src/sys/args/uefi.rs index 4e7412937bd1..84406c7f69df 100644 --- a/library/std/src/sys/args/uefi.rs +++ b/library/std/src/sys/args/uefi.rs @@ -4,11 +4,10 @@ use crate::env::current_exe; use crate::ffi::OsString; use crate::iter::Iterator; use crate::sys::pal::helpers; -use crate::{fmt, vec}; -pub struct Args { - parsed_args_list: vec::IntoIter, -} +#[path = "common.rs"] +mod common; +pub use common::Args; pub fn args() -> Args { let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]); @@ -22,51 +21,17 @@ pub fn args() -> Args { let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize; // Break if we are sure that it cannot be UTF-16 if lp_size < size_of::() || lp_size % size_of::() != 0 { - return Args { parsed_args_list: lazy_current_exe().into_iter() }; + return Args::new(lazy_current_exe()); } let lp_size = lp_size / size_of::(); let lp_cmd_line = unsafe { (*protocol.as_ptr()).load_options as *const u16 }; if !lp_cmd_line.is_aligned() { - return Args { parsed_args_list: lazy_current_exe().into_iter() }; + return Args::new(lazy_current_exe()); } let lp_cmd_line = unsafe { crate::slice::from_raw_parts(lp_cmd_line, lp_size) }; - Args { - parsed_args_list: parse_lp_cmd_line(lp_cmd_line) - .unwrap_or_else(lazy_current_exe) - .into_iter(), - } -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.parsed_args_list.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - - fn next(&mut self) -> Option { - self.parsed_args_list.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.parsed_args_list.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.parsed_args_list.next_back() - } + Args::new(parse_lp_cmd_line(lp_cmd_line).unwrap_or_else(lazy_current_exe)) } /// Implements the UEFI command-line argument parsing algorithm. diff --git a/library/std/src/sys/args/unix.rs b/library/std/src/sys/args/unix.rs index 13c459f682ff..7d7815c6dff2 100644 --- a/library/std/src/sys/args/unix.rs +++ b/library/std/src/sys/args/unix.rs @@ -5,9 +5,12 @@ #![allow(dead_code)] // runtime init functions not used during testing -use crate::ffi::{CStr, OsString}; +use crate::ffi::CStr; use crate::os::unix::ffi::OsStringExt; -use crate::{fmt, vec}; + +#[path = "common.rs"] +mod common; +pub use common::Args; /// One-time global initialization. pub unsafe fn init(argc: isize, argv: *const *const u8) { @@ -55,42 +58,7 @@ pub fn args() -> Args { vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec())); } - Args { iter: vec.into_iter() } -} - -pub struct Args { - iter: vec::IntoIter, -} - -impl !Send for Args {} -impl !Sync for Args {} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } + Args::new(vec) } #[cfg(any( diff --git a/library/std/src/sys/args/wasi.rs b/library/std/src/sys/args/wasi.rs index 52cfa202af82..4795789e4c71 100644 --- a/library/std/src/sys/args/wasi.rs +++ b/library/std/src/sys/args/wasi.rs @@ -2,18 +2,14 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::os::wasi::ffi::OsStrExt; -use crate::{fmt, vec}; -pub struct Args { - iter: vec::IntoIter, -} - -impl !Send for Args {} -impl !Sync for Args {} +#[path = "common.rs"] +mod common; +pub use common::Args; /// Returns the command line arguments pub fn args() -> Args { - Args { iter: maybe_args().unwrap_or(Vec::new()).into_iter() } + Args::new(maybe_args().unwrap_or(Vec::new())) } fn maybe_args() -> Option> { @@ -31,31 +27,3 @@ fn maybe_args() -> Option> { Some(ret) } } - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } -} diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs index 55bd6864cae3..47f0e5f2d05f 100644 --- a/library/std/src/sys/args/windows.rs +++ b/library/std/src/sys/args/windows.rs @@ -16,7 +16,11 @@ use crate::sys::path::get_long_path; use crate::sys::{c, to_u16s}; use crate::sys_common::AsInner; use crate::sys_common::wstr::WStrUnits; -use crate::{fmt, io, iter, ptr, vec}; +use crate::{io, iter, ptr}; + +#[path = "common.rs"] +mod common; +pub use common::Args; pub fn args() -> Args { // SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16 @@ -27,7 +31,7 @@ pub fn args() -> Args { current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new()) }); - Args { parsed_args_list: parsed_args_list.into_iter() } + Args::new(parsed_args_list) } } @@ -153,38 +157,6 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>( ret_val } -pub struct Args { - parsed_args_list: vec::IntoIter, -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.parsed_args_list.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.parsed_args_list.next() - } - fn size_hint(&self) -> (usize, Option) { - self.parsed_args_list.size_hint() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.parsed_args_list.next_back() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } -} - #[derive(Debug)] pub(crate) enum Arg { /// Add quotes (if needed) diff --git a/library/std/src/sys/args/xous.rs b/library/std/src/sys/args/xous.rs index 2dd37d53422f..09a47283d657 100644 --- a/library/std/src/sys/args/xous.rs +++ b/library/std/src/sys/args/xous.rs @@ -1,15 +1,13 @@ -use crate::ffi::OsString; use crate::sys::pal::os::get_application_parameters; use crate::sys::pal::os::params::ArgumentList; -use crate::{fmt, vec}; -pub struct Args { - parsed_args_list: vec::IntoIter, -} +#[path = "common.rs"] +mod common; +pub use common::Args; pub fn args() -> Args { let Some(params) = get_application_parameters() else { - return Args { parsed_args_list: vec![].into_iter() }; + return Args::new(vec![]); }; for param in params { @@ -18,36 +16,8 @@ pub fn args() -> Args { for arg in args { parsed_args.push(arg.into()); } - return Args { parsed_args_list: parsed_args.into_iter() }; + return Args::new(parsed_args); } } - Args { parsed_args_list: vec![].into_iter() } -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.parsed_args_list.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.parsed_args_list.next() - } - fn size_hint(&self) -> (usize, Option) { - self.parsed_args_list.size_hint() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.parsed_args_list.next_back() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } + Args::new(vec![]) } From 11256a0fb09b066f2b72f24889f8c02c2ef30098 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 9 Apr 2025 23:22:23 +0900 Subject: [PATCH 089/222] Add regression test for #127424 --- .../const-generics-closure.rs | 13 ++++++++++ .../const-generics-closure.stderr | 26 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr diff --git a/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs new file mode 100644 index 000000000000..aad8cefe5d62 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs @@ -0,0 +1,13 @@ +// Regression test for issue #127424 + +fn bar() -> impl Into< + [u8; { + //~^ ERROR mismatched types [E0308] + let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x }; + //~^ ERROR `for<...>` binders for closures are experimental [E0658] + }], +> { + [89] +} + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr new file mode 100644 index 000000000000..5410bbdc1253 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr @@ -0,0 +1,26 @@ +error[E0658]: `for<...>` binders for closures are experimental + --> $DIR/const-generics-closure.rs:6:17 + | +LL | let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x }; + | ^^^^^^^^^^^ + | + = note: see issue #97362 for more information + = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider removing `for<...>` + +error[E0308]: mismatched types + --> $DIR/const-generics-closure.rs:4:10 + | +LL | [u8; { + | __________^ +LL | | +LL | | let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x }; +LL | | +LL | | }], + | |_____^ expected `usize`, found `()` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. From 1baa62e88494e84c30d293c31b1d214cbe4bc643 Mon Sep 17 00:00:00 2001 From: GenYuLi Date: Sat, 12 Apr 2025 22:26:38 +0800 Subject: [PATCH 090/222] Fix typo in documentation Correct the misspelling of "indentifier" to "identifier" in `library/alloc/src/fmt.rs`. --- library/alloc/src/fmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index e40de13f3d4a..30f42050ac8a 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -109,7 +109,7 @@ //! parameters (corresponding to `format_spec` in [the syntax](#syntax)). These //! parameters affect the string representation of what's being formatted. //! -//! The colon `:` in format syntax divides indentifier of the input data and +//! The colon `:` in format syntax divides identifier of the input data and //! the formatting options, the colon itself does not change anything, only //! introduces the options. //! From 8ae6485dad1dc44943bee1a99cffc19a32f1961e Mon Sep 17 00:00:00 2001 From: bohan Date: Sat, 12 Apr 2025 23:56:48 +0800 Subject: [PATCH 091/222] don't store opaque info during encoding --- compiler/rustc_metadata/src/rmeta/mod.rs | 6 +- .../rustc_middle/src/query/on_disk_cache.rs | 5 +- compiler/rustc_middle/src/ty/parameterized.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 74 +++++-------------- 4 files changed, 23 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 2f27e5f6c5dc..5aa81f41b7b4 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -36,9 +36,7 @@ use rustc_serialize::opaque::FileEncoder; use rustc_session::config::{SymbolManglingVersion, TargetModifier}; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ - ExpnIndex, MacroKind, SyntaxContextDataNonRecursive as SyntaxContextData, -}; +use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTuple}; use table::TableBuilder; @@ -195,7 +193,7 @@ enum LazyState { Previous(NonZero), } -type SyntaxContextTable = LazyTable>>; +type SyntaxContextTable = LazyTable>>; type ExpnDataTable = LazyTable>>; type ExpnHashTable = LazyTable>>; diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index f78398c7c37d..5431097cb1d7 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -16,8 +16,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixed use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::Session; use rustc_span::hygiene::{ - ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, - SyntaxContextDataNonRecursive as SyntaxContextData, + ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextKey, }; use rustc_span::source_map::Spanned; use rustc_span::{ @@ -567,7 +566,7 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { // We look up the position of the associated `SyntaxData` and decode it. let pos = syntax_contexts.get(&id).unwrap(); this.with_position(pos.to_usize(), |decoder| { - let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); + let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); data }) }) diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index b56e08626920..ecd6132b3ef3 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -113,7 +113,7 @@ trivially_parameterized_over_tcx! { rustc_span::Span, rustc_span::Symbol, rustc_span::def_id::DefPathHash, - rustc_span::hygiene::SyntaxContextDataNonRecursive, + rustc_span::hygiene::SyntaxContextKey, rustc_span::Ident, rustc_type_ir::Variance, rustc_hir::Attribute, diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 9be16f8ce0c9..33152d2d9394 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -56,7 +56,7 @@ impl !PartialOrd for SyntaxContext {} /// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal. /// The other fields are only for caching. -type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); +pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); #[derive(Clone, Copy, Debug)] struct SyntaxContextData { @@ -71,17 +71,6 @@ struct SyntaxContextData { dollar_crate_name: Symbol, } -/// Same as `SyntaxContextData`, but `opaque(_and_semitransparent)` cannot be recursive -/// and use `None` if they need to refer to self. Used for encoding and decoding metadata. -#[derive(Encodable, Decodable)] -pub struct SyntaxContextDataNonRecursive { - outer_expn: ExpnId, - outer_transparency: Transparency, - parent: SyntaxContext, - opaque: Option, - opaque_and_semitransparent: Option, -} - impl SyntaxContextData { fn new( (parent, outer_expn, outer_transparency): SyntaxContextKey, @@ -122,19 +111,6 @@ impl SyntaxContextData { } } -impl SyntaxContextDataNonRecursive { - fn recursive(&self, ctxt: SyntaxContext) -> SyntaxContextData { - SyntaxContextData { - outer_expn: self.outer_expn, - outer_transparency: self.outer_transparency, - parent: self.parent, - opaque: self.opaque.unwrap_or(ctxt), - opaque_and_semitransparent: self.opaque_and_semitransparent.unwrap_or(ctxt), - dollar_crate_name: kw::DollarCrate, - } - } -} - rustc_index::newtype_index! { /// A unique ID associated with a macro invocation and expansion. #[orderable] @@ -658,19 +634,6 @@ impl HygieneData { SyntaxContextData::new(key, opaque, opaque_and_semitransparent); ctxt } - - fn non_recursive_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContextDataNonRecursive { - debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); - let data = &self.syntax_context_data[ctxt.0 as usize]; - SyntaxContextDataNonRecursive { - outer_expn: data.outer_expn, - outer_transparency: data.outer_transparency, - parent: data.parent, - opaque: (data.opaque != ctxt).then_some(data.opaque), - opaque_and_semitransparent: (data.opaque_and_semitransparent != ctxt) - .then_some(data.opaque_and_semitransparent), - } - } } pub fn walk_chain(span: Span, to: SyntaxContext) -> Span { @@ -1300,7 +1263,7 @@ impl HygieneEncodeContext { pub fn encode( &self, encoder: &mut T, - mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextDataNonRecursive), + mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey), mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash), ) { // When we serialize a `SyntaxContextData`, we may end up serializing @@ -1425,10 +1388,7 @@ pub fn decode_expn_id( // to track which `SyntaxContext`s we have already decoded. // The provided closure will be invoked to deserialize a `SyntaxContextData` // if we haven't already seen the id of the `SyntaxContext` we are deserializing. -pub fn decode_syntax_context< - D: Decoder, - F: FnOnce(&mut D, u32) -> SyntaxContextDataNonRecursive, ->( +pub fn decode_syntax_context SyntaxContextKey>( d: &mut D, context: &HygieneDecodeContext, decode_data: F, @@ -1450,16 +1410,9 @@ pub fn decode_syntax_context< // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext - let ctxt_data = decode_data(d, raw_id); - - let ctxt = HygieneData::with(|hygiene_data| { - let ctxt_key = (ctxt_data.parent, ctxt_data.outer_expn, ctxt_data.outer_transparency); - *hygiene_data.syntax_context_map.entry(ctxt_key).or_insert_with(|| { - let ctxt = SyntaxContext::from_usize(hygiene_data.syntax_context_data.len()); - hygiene_data.syntax_context_data.push(ctxt_data.recursive(ctxt)); - ctxt - }) - }); + let (parent, expn_id, transparency) = decode_data(d, raw_id); + let ctxt = + HygieneData::with(|hygiene_data| hygiene_data.alloc_ctxt(parent, expn_id, transparency)); let mut inner = context.inner.lock(); let new_len = raw_id as usize + 1; @@ -1471,12 +1424,21 @@ pub fn decode_syntax_context< ctxt } -fn for_all_ctxts_in( +fn for_all_ctxts_in( ctxts: impl Iterator, mut f: F, ) { - let all_data: Vec<_> = - HygieneData::with(|data| ctxts.map(|ctxt| (ctxt, data.non_recursive_ctxt(ctxt))).collect()); + let all_data: Vec<_> = HygieneData::with(|data| { + ctxts + .map(|ctxt| { + (ctxt, { + let item = data.syntax_context_data[ctxt.0 as usize]; + debug_assert!(!item.is_decode_placeholder()); + item.key() + }) + }) + .collect() + }); for (ctxt, data) in all_data.into_iter() { f(ctxt.0, ctxt, &data); } From 6ba9649e7c80b999b956adbdad3e9ecbbb1e24f3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 12 Apr 2025 11:50:33 -0700 Subject: [PATCH 092/222] End all lines in src/stage0 with trailing newline --- src/stage0 | 2 +- src/tools/bump-stage0/src/main.rs | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/stage0 b/src/stage0 index b3841d253f34..6e86501a72ab 100644 --- a/src/stage0 +++ b/src/stage0 @@ -476,4 +476,4 @@ dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=e67a33440c3e021ff2 dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=0ea7e17d7bb67d6a6c4b2f864aaffcd96512f15f17f0acc63751eb1df6c486a7 dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=b73d37b704ab58921172cc561f5598db6a504dcd4d7980966f7c26caaf6d3594 dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.gz=986f6c594d37bcbd3833e053640ba8775f68d26a65c5618386654ef55d7b3542 -dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.xz=c0d9a88c30d2ab38ec3a11fabb5515ed9bc3ac1a8e35a438d68bf7ff82f6b843 \ No newline at end of file +dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.xz=c0d9a88c30d2ab38ec3a11fabb5515ed9bc3ac1a8e35a438d68bf7ff82f6b843 diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs index f51072718a34..d679084ae44b 100644 --- a/src/tools/bump-stage0/src/main.rs +++ b/src/tools/bump-stage0/src/main.rs @@ -65,32 +65,33 @@ impl Tool { nightly_branch, } = &self.config; - file_content.push_str(&format!("dist_server={}", dist_server)); - file_content.push_str(&format!("\nartifacts_server={}", artifacts_server)); + file_content.push_str(&format!("dist_server={}\n", dist_server)); + file_content.push_str(&format!("artifacts_server={}\n", artifacts_server)); file_content.push_str(&format!( - "\nartifacts_with_llvm_assertions_server={}", + "artifacts_with_llvm_assertions_server={}\n", artifacts_with_llvm_assertions_server )); - file_content.push_str(&format!("\ngit_merge_commit_email={}", git_merge_commit_email)); - file_content.push_str(&format!("\ngit_repository={}", git_repository)); - file_content.push_str(&format!("\nnightly_branch={}", nightly_branch)); + file_content.push_str(&format!("git_merge_commit_email={}\n", git_merge_commit_email)); + file_content.push_str(&format!("git_repository={}\n", git_repository)); + file_content.push_str(&format!("nightly_branch={}\n", nightly_branch)); - file_content.push_str("\n\n"); + file_content.push_str("\n"); file_content.push_str(COMMENTS); + file_content.push_str("\n"); let compiler = self.detect_compiler()?; - file_content.push_str(&format!("\ncompiler_date={}", compiler.date)); - file_content.push_str(&format!("\ncompiler_version={}", compiler.version)); + file_content.push_str(&format!("compiler_date={}\n", compiler.date)); + file_content.push_str(&format!("compiler_version={}\n", compiler.version)); if let Some(rustfmt) = self.detect_rustfmt()? { - file_content.push_str(&format!("\nrustfmt_date={}", rustfmt.date)); - file_content.push_str(&format!("\nrustfmt_version={}", rustfmt.version)); + file_content.push_str(&format!("rustfmt_date={}\n", rustfmt.date)); + file_content.push_str(&format!("rustfmt_version={}\n", rustfmt.version)); } file_content.push_str("\n"); for (key, value) in self.checksums { - file_content.push_str(&format!("\n{}={}", key, value)); + file_content.push_str(&format!("{}={}\n", key, value)); } std::fs::write(PATH, file_content)?; From bc94c38d98b327e6a616e1b74da0143a474a3b1a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 12 Apr 2025 04:54:14 +0000 Subject: [PATCH 093/222] Proactively update coroutine drop shim's phase to account for later passes applied during shim query --- compiler/rustc_mir_transform/src/coroutine.rs | 7 +++++++ .../post-cleanup-phase-validation.rs | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/async-await/post-cleanup-phase-validation.rs diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 04d96f117072..02609d65b0f8 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1169,6 +1169,13 @@ fn create_coroutine_drop_shim<'tcx>( dump_mir(tcx, false, "coroutine_drop", &0, &body, |_, _| Ok(())); body.source.instance = drop_instance; + // Creating a coroutine drop shim happens on `Analysis(PostCleanup) -> Runtime(Initial)` + // but the pass manager doesn't update the phase of the coroutine drop shim. Update the + // phase of the drop shim so that later on when we run the pass manager on the shim, in + // the `mir_shims` query, we don't ICE on the intra-pass validation before we've updated + // the phase of the body from analysis. + body.phase = MirPhase::Runtime(RuntimePhase::Initial); + body } diff --git a/tests/ui/async-await/post-cleanup-phase-validation.rs b/tests/ui/async-await/post-cleanup-phase-validation.rs new file mode 100644 index 000000000000..a347e35c26db --- /dev/null +++ b/tests/ui/async-await/post-cleanup-phase-validation.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Zvalidate-mir +//@ edition: 2024 +//@ build-pass + +// Regression test that we don't ICE when encountering a transmute in a coroutine's +// drop shim body, which is conceptually in the Runtime phase but wasn't having the +// phase updated b/c the pass manager neither optimizes nor updates the phase for +// drop shim bodies. + +struct HasDrop; +impl Drop for HasDrop { + fn drop(&mut self) {} +} + +fn main() { + async { + vec![async { HasDrop }.await]; + }; +} From accae530ce1eca367e53325e8596a83e94aac2d2 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Tue, 8 Apr 2025 00:49:54 +0000 Subject: [PATCH 094/222] Move FlagComputation, PatternKind, and TypeWalker to rustc_type_ir --- compiler/rustc_middle/src/arena.rs | 1 - compiler/rustc_middle/src/ty/consts.rs | 15 + compiler/rustc_middle/src/ty/context.rs | 10 +- compiler/rustc_middle/src/ty/flags.rs | 359 ----------------- compiler/rustc_middle/src/ty/generic_args.rs | 15 + compiler/rustc_middle/src/ty/list.rs | 8 +- compiler/rustc_middle/src/ty/mod.rs | 2 - compiler/rustc_middle/src/ty/pattern.rs | 47 ++- compiler/rustc_middle/src/ty/sty.rs | 15 + compiler/rustc_type_ir/src/flags.rs | 365 ++++++++++++++++++ compiler/rustc_type_ir/src/inherent.rs | 2 +- compiler/rustc_type_ir/src/interner.rs | 10 +- compiler/rustc_type_ir/src/ir_print.rs | 7 +- compiler/rustc_type_ir/src/lib.rs | 3 + compiler/rustc_type_ir/src/pattern.rs | 16 + .../src/ty => rustc_type_ir/src}/walk.rs | 122 ++---- 16 files changed, 530 insertions(+), 467 deletions(-) delete mode 100644 compiler/rustc_middle/src/ty/flags.rs create mode 100644 compiler/rustc_type_ir/src/pattern.rs rename compiler/{rustc_middle/src/ty => rustc_type_ir/src}/walk.rs (55%) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 98273a05446a..d1bbb0598fec 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -89,7 +89,6 @@ macro_rules! arena_types { [] name_set: rustc_data_structures::unord::UnordSet, [] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet, - [] pats: rustc_middle::ty::PatternKind<'tcx>, [] valtree: rustc_middle::ty::ValTreeKind<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index ae1c6c670cbc..dc5fe2d8f8b0 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; use rustc_macros::HashStable; +use rustc_type_ir::walk::TypeWalker; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; use crate::ty::{self, Ty, TyCtxt}; @@ -243,4 +244,18 @@ impl<'tcx> Const<'tcx> { pub fn is_ct_infer(self) -> bool { matches!(self.kind(), ty::ConstKind::Infer(_)) } + + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```text + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker> { + TypeWalker::new(self.into()) + } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index abf6cbbcd877..6e5ac13bd2cf 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -870,7 +870,7 @@ impl<'tcx> CtxtInterners<'tcx> { Ty(Interned::new_unchecked( self.type_ .intern(kind, |kind| { - let flags = super::flags::FlagComputation::for_kind(&kind); + let flags = ty::FlagComputation::>::for_kind(&kind); let stable_hash = self.stable_hash(&flags, sess, untracked, &kind); InternedInSet(self.arena.alloc(WithCachedTypeInfo { @@ -896,7 +896,7 @@ impl<'tcx> CtxtInterners<'tcx> { Const(Interned::new_unchecked( self.const_ .intern(kind, |kind: ty::ConstKind<'_>| { - let flags = super::flags::FlagComputation::for_const_kind(&kind); + let flags = ty::FlagComputation::>::for_const_kind(&kind); let stable_hash = self.stable_hash(&flags, sess, untracked, &kind); InternedInSet(self.arena.alloc(WithCachedTypeInfo { @@ -912,7 +912,7 @@ impl<'tcx> CtxtInterners<'tcx> { fn stable_hash<'a, T: HashStable>>( &self, - flags: &ty::flags::FlagComputation, + flags: &ty::FlagComputation>, sess: &'a Session, untracked: &'a Untracked, val: &T, @@ -940,7 +940,7 @@ impl<'tcx> CtxtInterners<'tcx> { Predicate(Interned::new_unchecked( self.predicate .intern(kind, |kind| { - let flags = super::flags::FlagComputation::for_predicate(kind); + let flags = ty::FlagComputation::>::for_predicate(kind); let stable_hash = self.stable_hash(&flags, sess, untracked, &kind); @@ -961,7 +961,7 @@ impl<'tcx> CtxtInterners<'tcx> { } else { self.clauses .intern_ref(clauses, || { - let flags = super::flags::FlagComputation::for_clauses(clauses); + let flags = ty::FlagComputation::>::for_clauses(clauses); InternedInSet(ListWithCachedTypeInfo::from_arena( &*self.arena, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs deleted file mode 100644 index 2424923fb787..000000000000 --- a/compiler/rustc_middle/src/ty/flags.rs +++ /dev/null @@ -1,359 +0,0 @@ -use std::slice; - -use crate::ty::{self, GenericArg, GenericArgKind, InferConst, Ty, TypeFlags}; - -#[derive(Debug)] -pub struct FlagComputation { - pub flags: TypeFlags, - - /// see `Ty::outer_exclusive_binder` for details - pub outer_exclusive_binder: ty::DebruijnIndex, -} - -impl FlagComputation { - fn new() -> FlagComputation { - FlagComputation { flags: TypeFlags::empty(), outer_exclusive_binder: ty::INNERMOST } - } - - #[allow(rustc::usage_of_ty_tykind)] - pub fn for_kind(kind: &ty::TyKind<'_>) -> FlagComputation { - let mut result = FlagComputation::new(); - result.add_kind(kind); - result - } - - pub fn for_predicate(binder: ty::Binder<'_, ty::PredicateKind<'_>>) -> FlagComputation { - let mut result = FlagComputation::new(); - result.add_predicate(binder); - result - } - - pub fn for_const_kind(kind: &ty::ConstKind<'_>) -> FlagComputation { - let mut result = FlagComputation::new(); - result.add_const_kind(kind); - result - } - - pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation { - let mut result = FlagComputation::new(); - for c in clauses { - result.add_flags(c.as_predicate().flags()); - result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder()); - } - result - } - - fn add_flags(&mut self, flags: TypeFlags) { - self.flags = self.flags | flags; - } - - /// indicates that `self` refers to something at binding level `binder` - fn add_bound_var(&mut self, binder: ty::DebruijnIndex) { - let exclusive_binder = binder.shifted_in(1); - self.add_exclusive_binder(exclusive_binder); - } - - /// indicates that `self` refers to something *inside* binding - /// level `binder` -- not bound by `binder`, but bound by the next - /// binder internal to it - fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) { - self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder); - } - - /// Adds the flags/depth from a set of types that appear within the current type, but within a - /// region binder. - fn bound_computation(&mut self, value: ty::Binder<'_, T>, f: F) - where - F: FnOnce(&mut Self, T), - { - let mut computation = FlagComputation::new(); - - if !value.bound_vars().is_empty() { - computation.add_flags(TypeFlags::HAS_BINDER_VARS); - } - - f(&mut computation, value.skip_binder()); - - self.add_flags(computation.flags); - - // The types that contributed to `computation` occurred within - // a region binder, so subtract one from the region depth - // within when adding the depth to `self`. - let outer_exclusive_binder = computation.outer_exclusive_binder; - if outer_exclusive_binder > ty::INNERMOST { - self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1)); - } // otherwise, this binder captures nothing - } - - #[allow(rustc::usage_of_ty_tykind)] - fn add_kind(&mut self, kind: &ty::TyKind<'_>) { - match kind { - &ty::Bool - | &ty::Char - | &ty::Int(_) - | &ty::Float(_) - | &ty::Uint(_) - | &ty::Never - | &ty::Str - | &ty::Foreign(..) => {} - - &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), - - &ty::Param(_) => { - self.add_flags(TypeFlags::HAS_TY_PARAM); - } - - &ty::Closure(_, args) - | &ty::Coroutine(_, args) - | &ty::CoroutineClosure(_, args) - | &ty::CoroutineWitness(_, args) => { - self.add_args(args); - } - - &ty::Bound(debruijn, _) => { - self.add_bound_var(debruijn); - self.add_flags(TypeFlags::HAS_TY_BOUND); - } - - &ty::Placeholder(..) => { - self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); - } - - &ty::Infer(infer) => match infer { - ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { - self.add_flags(TypeFlags::HAS_TY_FRESH) - } - - ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => { - self.add_flags(TypeFlags::HAS_TY_INFER) - } - }, - - &ty::Adt(_, args) => { - self.add_args(args); - } - - &ty::Alias(kind, data) => { - self.add_flags(match kind { - ty::Projection => TypeFlags::HAS_TY_PROJECTION, - ty::Weak => TypeFlags::HAS_TY_WEAK, - ty::Opaque => TypeFlags::HAS_TY_OPAQUE, - ty::Inherent => TypeFlags::HAS_TY_INHERENT, - }); - - self.add_alias_ty(data); - } - - &ty::Dynamic(obj, r, _) => { - for predicate in obj.iter() { - self.bound_computation(predicate, |computation, predicate| match predicate { - ty::ExistentialPredicate::Trait(tr) => computation.add_args(tr.args), - ty::ExistentialPredicate::Projection(p) => { - computation.add_existential_projection(&p); - } - ty::ExistentialPredicate::AutoTrait(_) => {} - }); - } - - self.add_region(r); - } - - &ty::Array(tt, len) => { - self.add_ty(tt); - self.add_const(len); - } - - &ty::Pat(ty, pat) => { - self.add_ty(ty); - match *pat { - ty::PatternKind::Range { start, end } => { - self.add_const(start); - self.add_const(end); - } - } - } - - &ty::Slice(tt) => self.add_ty(tt), - - &ty::RawPtr(ty, _) => { - self.add_ty(ty); - } - - &ty::Ref(r, ty, _) => { - self.add_region(r); - self.add_ty(ty); - } - - &ty::Tuple(types) => { - self.add_tys(types); - } - - &ty::FnDef(_, args) => { - self.add_args(args); - } - - &ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| { - computation.add_tys(sig_tys.inputs_and_output); - }), - - &ty::UnsafeBinder(bound_ty) => { - self.bound_computation(bound_ty.into(), |computation, ty| { - computation.add_ty(ty); - }) - } - } - } - - fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) { - self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom)); - } - - fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) { - match atom { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { - self.add_args(trait_pred.trait_ref.args); - } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate { - trait_ref, - constness: _, - })) => { - self.add_args(trait_ref.args); - } - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( - a, - b, - ))) => { - self.add_region(a); - self.add_region(b); - } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( - ty, - region, - ))) => { - self.add_ty(ty); - self.add_region(region); - } - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - self.add_const(ct); - self.add_ty(ty); - } - ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => { - self.add_ty(a); - self.add_ty(b); - } - ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { - self.add_ty(a); - self.add_ty(b); - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_term, - term, - })) => { - self.add_alias_term(projection_term); - self.add_term(term); - } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { - self.add_args(slice::from_ref(&arg)); - } - ty::PredicateKind::DynCompatible(_def_id) => {} - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { - self.add_const(uv); - } - ty::PredicateKind::ConstEquate(expected, found) => { - self.add_const(expected); - self.add_const(found); - } - ty::PredicateKind::Ambiguous => {} - ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => { - self.add_alias_term(alias); - self.add_term(term); - } - ty::PredicateKind::AliasRelate(t1, t2, _) => { - self.add_term(t1); - self.add_term(t2); - } - } - } - - fn add_ty(&mut self, ty: Ty<'_>) { - self.add_flags(ty.flags()); - self.add_exclusive_binder(ty.outer_exclusive_binder()); - } - - fn add_tys(&mut self, tys: &[Ty<'_>]) { - for &ty in tys { - self.add_ty(ty); - } - } - - fn add_region(&mut self, r: ty::Region<'_>) { - self.add_flags(r.type_flags()); - if let ty::ReBound(debruijn, _) = r.kind() { - self.add_bound_var(debruijn); - } - } - - fn add_const(&mut self, c: ty::Const<'_>) { - self.add_flags(c.flags()); - self.add_exclusive_binder(c.outer_exclusive_binder()); - } - - fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) { - match *c { - ty::ConstKind::Unevaluated(uv) => { - self.add_args(uv.args); - self.add_flags(TypeFlags::HAS_CT_PROJECTION); - } - ty::ConstKind::Infer(infer) => match infer { - InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), - InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), - }, - ty::ConstKind::Bound(debruijn, _) => { - self.add_bound_var(debruijn); - self.add_flags(TypeFlags::HAS_CT_BOUND); - } - ty::ConstKind::Param(_) => { - self.add_flags(TypeFlags::HAS_CT_PARAM); - } - ty::ConstKind::Placeholder(_) => { - self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); - } - ty::ConstKind::Value(cv) => self.add_ty(cv.ty), - ty::ConstKind::Expr(e) => self.add_args(e.args()), - ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), - } - } - - fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { - self.add_args(projection.args); - match projection.term.unpack() { - ty::TermKind::Ty(ty) => self.add_ty(ty), - ty::TermKind::Const(ct) => self.add_const(ct), - } - } - - fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<'_>) { - self.add_args(alias_ty.args); - } - - fn add_alias_term(&mut self, alias_term: ty::AliasTerm<'_>) { - self.add_args(alias_term.args); - } - - fn add_args(&mut self, args: &[GenericArg<'_>]) { - for kind in args { - match kind.unpack() { - GenericArgKind::Type(ty) => self.add_ty(ty), - GenericArgKind::Lifetime(lt) => self.add_region(lt), - GenericArgKind::Const(ct) => self.add_const(ct), - } - } - } - - fn add_term(&mut self, term: ty::Term<'_>) { - match term.unpack() { - ty::TermKind::Ty(ty) => self.add_ty(ty), - ty::TermKind::Const(ct) => self.add_const(ct), - } - } -} diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 9c1ff134f0fd..1f04937232dd 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -11,6 +11,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_serialize::{Decodable, Encodable}; use rustc_type_ir::WithCachedTypeInfo; +use rustc_type_ir::walk::TypeWalker; use smallvec::SmallVec; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -297,6 +298,20 @@ impl<'tcx> GenericArg<'tcx> { GenericArgKind::Const(ct) => ct.is_ct_infer(), } } + + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```text + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker> { + TypeWalker::new(self) + } } impl<'a, 'tcx> Lift> for GenericArg<'a> { diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 0fd370a56195..0cf5820959ee 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -7,9 +7,9 @@ use std::{fmt, iter, mem, ptr, slice}; use rustc_data_structures::aligned::{Aligned, align_of}; use rustc_data_structures::sync::DynSync; use rustc_serialize::{Encodable, Encoder}; +use rustc_type_ir::FlagComputation; -use super::flags::FlagComputation; -use super::{DebruijnIndex, TypeFlags}; +use super::{DebruijnIndex, TyCtxt, TypeFlags}; use crate::arena::Arena; /// `List` is a bit like `&[T]`, but with some critical differences. @@ -299,8 +299,8 @@ impl TypeInfo { } } -impl From for TypeInfo { - fn from(computation: FlagComputation) -> TypeInfo { +impl<'tcx> From>> for TypeInfo { + fn from(computation: FlagComputation>) -> TypeInfo { TypeInfo { flags: computation.flags, outer_exclusive_binder: computation.outer_exclusive_binder, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a2b3acac3f26..61e869f5de41 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -117,7 +117,6 @@ pub mod cast; pub mod codec; pub mod error; pub mod fast_reject; -pub mod flags; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; @@ -128,7 +127,6 @@ pub mod significant_drop_order; pub mod trait_def; pub mod util; pub mod vtable; -pub mod walk; mod adt; mod assoc; diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs index 4cad1ab20991..758adc42e3eb 100644 --- a/compiler/rustc_middle/src/ty/pattern.rs +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -1,14 +1,40 @@ use std::fmt; use rustc_data_structures::intern::Interned; -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::HashStable; +use rustc_type_ir::ir_print::IrPrint; +use rustc_type_ir::{ + FlagComputation, Flags, {self as ir}, +}; +use super::TyCtxt; use crate::ty; +pub type PatternKind<'tcx> = ir::PatternKind>; + #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>); +impl<'tcx> Flags for Pattern<'tcx> { + fn flags(&self) -> rustc_type_ir::TypeFlags { + match &**self { + ty::PatternKind::Range { start, end } => { + FlagComputation::for_const_kind(&start.kind()).flags + | FlagComputation::for_const_kind(&end.kind()).flags + } + } + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + match &**self { + ty::PatternKind::Range { start, end } => { + start.outer_exclusive_binder().max(end.outer_exclusive_binder()) + } + } + } +} + impl<'tcx> std::ops::Deref for Pattern<'tcx> { type Target = PatternKind<'tcx>; @@ -23,9 +49,9 @@ impl<'tcx> fmt::Debug for Pattern<'tcx> { } } -impl<'tcx> fmt::Debug for PatternKind<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { +impl<'tcx> IrPrint> for TyCtxt<'tcx> { + fn print(t: &PatternKind<'tcx>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *t { PatternKind::Range { start, end } => { write!(f, "{start}")?; @@ -53,10 +79,15 @@ impl<'tcx> fmt::Debug for PatternKind<'tcx> { } } } + + fn print_debug(t: &PatternKind<'tcx>, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + Self::print(t, fmt) + } } -#[derive(Clone, PartialEq, Eq, Hash)] -#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] -pub enum PatternKind<'tcx> { - Range { start: ty::Const<'tcx>, end: ty::Const<'tcx> }, +impl<'tcx> rustc_type_ir::inherent::IntoKind for Pattern<'tcx> { + type Kind = PatternKind<'tcx>; + fn kind(self) -> Self::Kind { + *self + } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 27ee363f1c14..d9a65ae57a09 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -16,6 +16,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_type_ir::TyKind::*; +use rustc_type_ir::walk::TypeWalker; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate}; use tracing::instrument; use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; @@ -2029,6 +2030,20 @@ impl<'tcx> Ty<'tcx> { pub fn is_known_rigid(self) -> bool { self.kind().is_known_rigid() } + + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```text + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker> { + TypeWalker::new(self.into()) + } } impl<'tcx> rustc_type_ir::inherent::Tys> for &'tcx ty::List> { diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 6a2498242fee..e9d3a149a730 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -1,3 +1,9 @@ +use std::slice; + +use crate::inherent::*; +use crate::visit::Flags; +use crate::{self as ty, Interner}; + bitflags::bitflags! { /// Flags that we track on types. These flags are propagated upwards /// through the type during type construction, so that we can quickly check @@ -128,3 +134,362 @@ bitflags::bitflags! { const HAS_BINDER_VARS = 1 << 23; } } + +#[derive(Debug)] +pub struct FlagComputation { + pub flags: TypeFlags, + + /// see `Ty::outer_exclusive_binder` for details + pub outer_exclusive_binder: ty::DebruijnIndex, + + interner: std::marker::PhantomData, +} + +impl FlagComputation { + fn new() -> FlagComputation { + FlagComputation { + flags: TypeFlags::empty(), + outer_exclusive_binder: ty::INNERMOST, + interner: std::marker::PhantomData, + } + } + + #[allow(rustc::usage_of_ty_tykind)] + pub fn for_kind(kind: &ty::TyKind) -> FlagComputation { + let mut result = FlagComputation::new(); + result.add_kind(kind); + result + } + + pub fn for_predicate(binder: ty::Binder>) -> FlagComputation { + let mut result = FlagComputation::new(); + result.add_predicate(binder); + result + } + + pub fn for_const_kind(kind: &ty::ConstKind) -> FlagComputation { + let mut result = FlagComputation::new(); + result.add_const_kind(kind); + result + } + + pub fn for_clauses(clauses: &[I::Clause]) -> FlagComputation { + let mut result = FlagComputation::new(); + for c in clauses { + result.add_flags(c.as_predicate().flags()); + result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder()); + } + result + } + + fn add_flags(&mut self, flags: TypeFlags) { + self.flags = self.flags | flags; + } + + /// indicates that `self` refers to something at binding level `binder` + fn add_bound_var(&mut self, binder: ty::DebruijnIndex) { + let exclusive_binder = binder.shifted_in(1); + self.add_exclusive_binder(exclusive_binder); + } + + /// indicates that `self` refers to something *inside* binding + /// level `binder` -- not bound by `binder`, but bound by the next + /// binder internal to it + fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) { + self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder); + } + + /// Adds the flags/depth from a set of types that appear within the current type, but within a + /// region binder. + fn bound_computation(&mut self, value: ty::Binder, f: F) + where + F: FnOnce(&mut Self, T), + { + let mut computation = FlagComputation::new(); + + if !value.bound_vars().is_empty() { + computation.add_flags(TypeFlags::HAS_BINDER_VARS); + } + + f(&mut computation, value.skip_binder()); + + self.add_flags(computation.flags); + + // The types that contributed to `computation` occurred within + // a region binder, so subtract one from the region depth + // within when adding the depth to `self`. + let outer_exclusive_binder = computation.outer_exclusive_binder; + if outer_exclusive_binder > ty::INNERMOST { + self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1)); + } // otherwise, this binder captures nothing + } + + #[allow(rustc::usage_of_ty_tykind)] + fn add_kind(&mut self, kind: &ty::TyKind) { + match *kind { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Float(_) + | ty::Uint(_) + | ty::Never + | ty::Str + | ty::Foreign(..) => {} + + ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), + + ty::Param(_) => { + self.add_flags(TypeFlags::HAS_TY_PARAM); + } + + ty::Closure(_, args) + | ty::Coroutine(_, args) + | ty::CoroutineClosure(_, args) + | ty::CoroutineWitness(_, args) => { + self.add_args(args.as_slice()); + } + + ty::Bound(debruijn, _) => { + self.add_bound_var(debruijn); + self.add_flags(TypeFlags::HAS_TY_BOUND); + } + + ty::Placeholder(..) => { + self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); + } + + ty::Infer(infer) => match infer { + ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { + self.add_flags(TypeFlags::HAS_TY_FRESH) + } + + ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => { + self.add_flags(TypeFlags::HAS_TY_INFER) + } + }, + + ty::Adt(_, args) => { + self.add_args(args.as_slice()); + } + + ty::Alias(kind, data) => { + self.add_flags(match kind { + ty::Projection => TypeFlags::HAS_TY_PROJECTION, + ty::Weak => TypeFlags::HAS_TY_WEAK, + ty::Opaque => TypeFlags::HAS_TY_OPAQUE, + ty::Inherent => TypeFlags::HAS_TY_INHERENT, + }); + + self.add_alias_ty(data); + } + + ty::Dynamic(obj, r, _) => { + for predicate in obj.iter() { + self.bound_computation(predicate, |computation, predicate| match predicate { + ty::ExistentialPredicate::Trait(tr) => { + computation.add_args(tr.args.as_slice()) + } + ty::ExistentialPredicate::Projection(p) => { + computation.add_existential_projection(&p); + } + ty::ExistentialPredicate::AutoTrait(_) => {} + }); + } + + self.add_region(r); + } + + ty::Array(tt, len) => { + self.add_ty(tt); + self.add_const(len); + } + + ty::Pat(ty, pat) => { + self.add_ty(ty); + self.add_flags(pat.flags()); + } + + ty::Slice(tt) => self.add_ty(tt), + + ty::RawPtr(ty, _) => { + self.add_ty(ty); + } + + ty::Ref(r, ty, _) => { + self.add_region(r); + self.add_ty(ty); + } + + ty::Tuple(types) => { + self.add_tys(types); + } + + ty::FnDef(_, args) => { + self.add_args(args.as_slice()); + } + + ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| { + computation.add_tys(sig_tys.inputs_and_output); + }), + + ty::UnsafeBinder(bound_ty) => { + self.bound_computation(bound_ty.into(), |computation, ty| { + computation.add_ty(ty); + }) + } + } + } + + fn add_predicate(&mut self, binder: ty::Binder>) { + self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom)); + } + + fn add_predicate_atom(&mut self, atom: ty::PredicateKind) { + match atom { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { + self.add_args(trait_pred.trait_ref.args.as_slice()); + } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref, + constness: _, + })) => { + self.add_args(trait_ref.args.as_slice()); + } + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( + a, + b, + ))) => { + self.add_region(a); + self.add_region(b); + } + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( + ty, + region, + ))) => { + self.add_ty(ty); + self.add_region(region); + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { + self.add_const(ct); + self.add_ty(ty); + } + ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => { + self.add_ty(a); + self.add_ty(b); + } + ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { + self.add_ty(a); + self.add_ty(b); + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { + projection_term, + term, + })) => { + self.add_alias_term(projection_term); + self.add_term(term); + } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { + self.add_args(slice::from_ref(&arg)); + } + ty::PredicateKind::DynCompatible(_def_id) => {} + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { + self.add_const(uv); + } + ty::PredicateKind::ConstEquate(expected, found) => { + self.add_const(expected); + self.add_const(found); + } + ty::PredicateKind::Ambiguous => {} + ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => { + self.add_alias_term(alias); + self.add_term(term); + } + ty::PredicateKind::AliasRelate(t1, t2, _) => { + self.add_term(t1); + self.add_term(t2); + } + } + } + + fn add_ty(&mut self, ty: I::Ty) { + self.add_flags(ty.flags()); + self.add_exclusive_binder(ty.outer_exclusive_binder()); + } + + fn add_tys(&mut self, tys: I::Tys) { + for ty in tys.iter() { + self.add_ty(ty); + } + } + + fn add_region(&mut self, r: I::Region) { + self.add_flags(r.flags()); + if let ty::ReBound(debruijn, _) = r.kind() { + self.add_bound_var(debruijn); + } + } + + fn add_const(&mut self, c: I::Const) { + self.add_flags(c.flags()); + self.add_exclusive_binder(c.outer_exclusive_binder()); + } + + fn add_const_kind(&mut self, c: &ty::ConstKind) { + match *c { + ty::ConstKind::Unevaluated(uv) => { + self.add_args(uv.args.as_slice()); + self.add_flags(TypeFlags::HAS_CT_PROJECTION); + } + ty::ConstKind::Infer(infer) => match infer { + ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), + ty::InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), + }, + ty::ConstKind::Bound(debruijn, _) => { + self.add_bound_var(debruijn); + self.add_flags(TypeFlags::HAS_CT_BOUND); + } + ty::ConstKind::Param(_) => { + self.add_flags(TypeFlags::HAS_CT_PARAM); + } + ty::ConstKind::Placeholder(_) => { + self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); + } + ty::ConstKind::Value(cv) => self.add_ty(cv.ty()), + ty::ConstKind::Expr(e) => self.add_args(e.args().as_slice()), + ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), + } + } + + fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection) { + self.add_args(projection.args.as_slice()); + match projection.term.kind() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(ct) => self.add_const(ct), + } + } + + fn add_alias_ty(&mut self, alias_ty: ty::AliasTy) { + self.add_args(alias_ty.args.as_slice()); + } + + fn add_alias_term(&mut self, alias_term: ty::AliasTerm) { + self.add_args(alias_term.args.as_slice()); + } + + fn add_args(&mut self, args: &[I::GenericArg]) { + for kind in args { + match kind.kind() { + ty::GenericArgKind::Type(ty) => self.add_ty(ty), + ty::GenericArgKind::Lifetime(lt) => self.add_region(lt), + ty::GenericArgKind::Const(ct) => self.add_const(ct), + } + } + } + + fn add_term(&mut self, term: I::Term) { + match term.kind() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(ct) => self.add_const(ct), + } + } +} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 6e6c40580d83..417803e75ead 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -583,7 +583,7 @@ pub trait Span: Copy + Debug + Hash + Eq + TypeFoldable { pub trait SliceLike: Sized + Copy { type Item: Copy; - type IntoIter: Iterator; + type IntoIter: Iterator + DoubleEndedIterator; fn iter(self) -> Self::IntoIter; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index a9e6764e2182..71bfeabfda87 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -31,6 +31,7 @@ pub trait Interner: + IrPrint> + IrPrint> + IrPrint> + + IrPrint> { type DefId: DefId; type LocalDefId: Copy + Debug + Hash + Eq + Into + TypeFoldable; @@ -104,7 +105,14 @@ pub trait Interner: type ErrorGuaranteed: Copy + Debug + Hash + Eq; type BoundExistentialPredicates: BoundExistentialPredicates; type AllocId: Copy + Debug + Hash + Eq; - type Pat: Copy + Debug + Hash + Eq + Debug + Relate; + type Pat: Copy + + Debug + + Hash + + Eq + + Debug + + Relate + + Flags + + IntoKind>; type Safety: Safety; type Abi: Abi; diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index 0c71f3a3df2a..c259a9747f0d 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -2,8 +2,8 @@ use std::fmt; use crate::{ AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, - HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, - SubtypePredicate, TraitPredicate, TraitRef, + HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, PatternKind, + ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; pub trait IrPrint { @@ -57,9 +57,10 @@ define_display_via_print!( AliasTy, AliasTerm, FnSig, + PatternKind, ); -define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection); +define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection, PatternKind); impl fmt::Display for OutlivesPredicate where diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index bdc61e956f8c..792090effcff 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -31,6 +31,7 @@ pub mod outlives; pub mod relate; pub mod search_graph; pub mod solve; +pub mod walk; // These modules are not `pub` since they are glob-imported. #[macro_use] @@ -44,6 +45,7 @@ mod generic_arg; mod infer_ctxt; mod interner; mod opaque_ty; +mod pattern; mod predicate; mod predicate_kind; mod region_kind; @@ -67,6 +69,7 @@ pub use generic_arg::*; pub use infer_ctxt::*; pub use interner::*; pub use opaque_ty::*; +pub use pattern::*; pub use predicate::*; pub use predicate_kind::*; pub use region_kind::*; diff --git a/compiler/rustc_type_ir/src/pattern.rs b/compiler/rustc_type_ir/src/pattern.rs new file mode 100644 index 000000000000..d74a82da1f92 --- /dev/null +++ b/compiler/rustc_type_ir/src/pattern.rs @@ -0,0 +1,16 @@ +use derive_where::derive_where; +#[cfg(feature = "nightly")] +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::Interner; + +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] +pub enum PatternKind { + Range { start: I::Const, end: I::Const }, +} diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_type_ir/src/walk.rs similarity index 55% rename from compiler/rustc_middle/src/ty/walk.rs rename to compiler/rustc_type_ir/src/walk.rs index a23316ae6fc8..5683e1f1712c 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_type_ir/src/walk.rs @@ -1,20 +1,21 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use rustc_data_structures::sso::SsoHashSet; use smallvec::{SmallVec, smallvec}; use tracing::debug; -use crate::ty::{self, GenericArg, GenericArgKind, Ty}; +use crate::data_structures::SsoHashSet; +use crate::inherent::*; +use crate::{self as ty, Interner}; // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. -type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; +type TypeWalkerStack = SmallVec<[::GenericArg; 8]>; -pub struct TypeWalker<'tcx> { - stack: TypeWalkerStack<'tcx>, +pub struct TypeWalker { + stack: TypeWalkerStack, last_subtree: usize, - pub visited: SsoHashSet>, + pub visited: SsoHashSet, } /// An iterator for walking the type tree. @@ -25,8 +26,8 @@ pub struct TypeWalker<'tcx> { /// in this situation walker only visits each type once. /// It maintains a set of visited types and /// skips any types that are already there. -impl<'tcx> TypeWalker<'tcx> { - pub fn new(root: GenericArg<'tcx>) -> Self { +impl TypeWalker { + pub fn new(root: I::GenericArg) -> Self { Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } } @@ -47,16 +48,16 @@ impl<'tcx> TypeWalker<'tcx> { } } -impl<'tcx> Iterator for TypeWalker<'tcx> { - type Item = GenericArg<'tcx>; +impl Iterator for TypeWalker { + type Item = I::GenericArg; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option { debug!("next(): stack={:?}", self.stack); loop { let next = self.stack.pop()?; self.last_subtree = self.stack.len(); if self.visited.insert(next) { - push_inner(&mut self.stack, next); + push_inner::(&mut self.stack, next); debug!("next: stack={:?}", self.stack); return Some(next); } @@ -64,63 +65,15 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { } } -impl<'tcx> GenericArg<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```text - /// isize => { isize } - /// Foo> => { Foo>, Bar, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(self) -> TypeWalker<'tcx> { - TypeWalker::new(self) - } -} - -impl<'tcx> Ty<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```text - /// isize => { isize } - /// Foo> => { Foo>, Bar, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(self) -> TypeWalker<'tcx> { - TypeWalker::new(self.into()) - } -} - -impl<'tcx> ty::Const<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```text - /// isize => { isize } - /// Foo> => { Foo>, Bar, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(self) -> TypeWalker<'tcx> { - TypeWalker::new(self.into()) - } -} - /// We push `GenericArg`s on the stack in reverse order so as to /// maintain a pre-order traversal. As of the time of this /// writing, the fact that the traversal is pre-order is not /// known to be significant to any code, but it seems like the /// natural order one would expect (basically, the order of the /// types as they are written). -fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) { - match parent.unpack() { - GenericArgKind::Type(parent_ty) => match *parent_ty.kind() { +fn push_inner(stack: &mut TypeWalkerStack, parent: I::GenericArg) { + match parent.kind() { + ty::GenericArgKind::Type(parent_ty) => match parent_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -136,7 +89,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::Foreign(..) => {} ty::Pat(ty, pat) => { - match *pat { + match pat.kind() { ty::PatternKind::Range { start, end } => { stack.push(end.into()); stack.push(start.into()); @@ -163,22 +116,25 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } ty::Dynamic(obj, lt, _) => { stack.push(lt.into()); - stack.extend(obj.iter().rev().flat_map(|predicate| { - let (args, opt_ty) = match predicate.skip_binder() { - ty::ExistentialPredicate::Trait(tr) => (tr.args, None), - ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)), - ty::ExistentialPredicate::AutoTrait(_) => - // Empty iterator - { - (ty::GenericArgs::empty(), None) - } - }; + stack.extend( + obj.iter() + .rev() + .filter_map(|predicate| { + let (args, opt_ty) = match predicate.skip_binder() { + ty::ExistentialPredicate::Trait(tr) => (tr.args, None), + ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)), + ty::ExistentialPredicate::AutoTrait(_) => { + return None; + } + }; - args.iter().rev().chain(opt_ty.map(|term| match term.unpack() { - ty::TermKind::Ty(ty) => ty.into(), - ty::TermKind::Const(ct) => ct.into(), - })) - })); + Some(args.iter().rev().chain(opt_ty.map(|term| match term.kind() { + ty::TermKind::Ty(ty) => ty.into(), + ty::TermKind::Const(ct) => ct.into(), + }))) + }) + .flatten(), + ); } ty::Adt(_, args) | ty::Closure(_, args) @@ -188,7 +144,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::FnDef(_, args) => { stack.extend(args.iter().rev()); } - ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)), + ty::Tuple(ts) => stack.extend(ts.iter().rev().map(|ty| ty.into())), ty::FnPtr(sig_tys, _hdr) => { stack.extend( sig_tys.skip_binder().inputs_and_output.iter().rev().map(|ty| ty.into()), @@ -198,15 +154,15 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) stack.push(bound_ty.skip_binder().into()); } }, - GenericArgKind::Lifetime(_) => {} - GenericArgKind::Const(parent_ct) => match parent_ct.kind() { + ty::GenericArgKind::Lifetime(_) => {} + ty::GenericArgKind::Const(parent_ct) => match parent_ct.kind() { ty::ConstKind::Infer(_) | ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Error(_) => {} - ty::ConstKind::Value(cv) => stack.push(cv.ty.into()), + ty::ConstKind::Value(cv) => stack.push(cv.ty().into()), ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()), ty::ConstKind::Unevaluated(ct) => { From f472cc8cd4c57687aac38fe3589818f1cc7956ba Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 12 Apr 2025 19:58:19 +0200 Subject: [PATCH 095/222] error on unsafe attributes in pre-2024 editions the `no_mangle`, `link_section` and `export_name` attributes are exceptions, and can still be used without an unsafe in earlier editions --- .../src/error_codes/E0755.md | 4 +-- .../src/error_codes/E0756.md | 4 +-- .../src/error_codes/E0757.md | 7 ++-- compiler/rustc_feature/src/builtin_attrs.rs | 33 ++++++++++++++----- compiler/rustc_parse/src/validate_attr.rs | 10 ++++-- tests/codegen/cffi/ffi-const.rs | 2 +- tests/codegen/cffi/ffi-pure.rs | 2 +- .../feature-gates/feature-gate-ffi_const.rs | 2 +- .../feature-gate-ffi_const.stderr | 4 +-- .../ui/feature-gates/feature-gate-ffi_pure.rs | 2 +- .../feature-gate-ffi_pure.stderr | 4 +-- tests/ui/ffi-attrs/ffi_const.rs | 11 ++++--- tests/ui/ffi-attrs/ffi_const.stderr | 25 ++++++++++---- tests/ui/ffi-attrs/ffi_const2.rs | 4 +-- tests/ui/ffi-attrs/ffi_const2.stderr | 4 +-- tests/ui/ffi-attrs/ffi_pure.rs | 11 ++++--- tests/ui/ffi-attrs/ffi_pure.stderr | 25 ++++++++++---- 17 files changed, 102 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0755.md b/compiler/rustc_error_codes/src/error_codes/E0755.md index 88b7f4849690..b67f078c78ec 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0755.md +++ b/compiler/rustc_error_codes/src/error_codes/E0755.md @@ -5,7 +5,7 @@ Erroneous code example: ```compile_fail,E0755 #![feature(ffi_pure)] -#[ffi_pure] // error! +#[unsafe(ffi_pure)] // error! pub fn foo() {} # fn main() {} ``` @@ -17,7 +17,7 @@ side effects or infinite loops: #![feature(ffi_pure)] extern "C" { - #[ffi_pure] // ok! + #[unsafe(ffi_pure)] // ok! pub fn strlen(s: *const i8) -> isize; } # fn main() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md index ffdc421aab58..aadde038d12c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0756.md +++ b/compiler/rustc_error_codes/src/error_codes/E0756.md @@ -6,7 +6,7 @@ Erroneous code example: ```compile_fail,E0756 #![feature(ffi_const)] -#[ffi_const] // error! +#[unsafe(ffi_const)] // error! pub fn foo() {} # fn main() {} ``` @@ -18,7 +18,7 @@ which have no side effects except for their return value: #![feature(ffi_const)] extern "C" { - #[ffi_const] // ok! + #[unsafe(ffi_const)] // ok! pub fn strlen(s: *const i8) -> i32; } # fn main() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0757.md b/compiler/rustc_error_codes/src/error_codes/E0757.md index 41b06b23c4f2..fb75b028f45c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0757.md +++ b/compiler/rustc_error_codes/src/error_codes/E0757.md @@ -6,8 +6,9 @@ Erroneous code example: #![feature(ffi_const, ffi_pure)] extern "C" { - #[ffi_const] - #[ffi_pure] // error: `#[ffi_const]` function cannot be `#[ffi_pure]` + #[unsafe(ffi_const)] + #[unsafe(ffi_pure)] + //~^ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]` pub fn square(num: i32) -> i32; } ``` @@ -19,7 +20,7 @@ As `ffi_const` provides stronger guarantees than `ffi_pure`, remove the #![feature(ffi_const)] extern "C" { - #[ffi_const] + #[unsafe(ffi_const)] pub fn square(num: i32) -> i32; } ``` diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 1e33e2e9393f..7615362e1f9d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -6,6 +6,7 @@ use AttributeDuplicates::*; use AttributeGate::*; use AttributeType::*; use rustc_data_structures::fx::FxHashMap; +use rustc_span::edition::Edition; use rustc_span::{Symbol, sym}; use crate::{Features, Stability}; @@ -65,9 +66,12 @@ pub enum AttributeSafety { /// Normal attribute that does not need `#[unsafe(...)]` Normal, - /// Unsafe attribute that requires safety obligations - /// to be discharged - Unsafe, + /// Unsafe attribute that requires safety obligations to be discharged. + /// + /// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition + /// is less than the one stored in `unsafe_since`. This handles attributes that were safe in + /// earlier editions, but become unsafe in later ones. + Unsafe { unsafe_since: Option }, } #[derive(Clone, Copy)] @@ -187,12 +191,23 @@ macro_rules! template { } macro_rules! ungated { + (unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) }, + template: $tpl, + gate: Ungated, + duplicates: $duplicates, + } + }; (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, - safety: AttributeSafety::Unsafe, + safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, gate: Ungated, duplicates: $duplicates, @@ -217,7 +232,7 @@ macro_rules! gated { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, - safety: AttributeSafety::Unsafe, + safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), @@ -228,7 +243,7 @@ macro_rules! gated { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, - safety: AttributeSafety::Unsafe, + safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), @@ -423,9 +438,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No), - ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No), ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes), diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 6bbd650dcdfe..6a1c2af48ed5 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -157,7 +157,7 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) { let attr_item = attr.get_normal_item(); - if safety == AttributeSafety::Unsafe { + if let AttributeSafety::Unsafe { unsafe_since } = safety { if let ast::Safety::Default = attr_item.unsafety { let path_span = attr_item.path.span; @@ -167,7 +167,13 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: // square bracket respectively. let diag_span = attr_item.span(); - if attr.span.at_least_rust_2024() { + // Attributes can be safe in earlier editions, and become unsafe in later ones. + let emit_error = match unsafe_since { + None => true, + Some(unsafe_since) => attr.span.edition() >= unsafe_since, + }; + + if emit_error { psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { span: path_span, suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { diff --git a/tests/codegen/cffi/ffi-const.rs b/tests/codegen/cffi/ffi-const.rs index 6c90902e89fe..3ea9d517ec25 100644 --- a/tests/codegen/cffi/ffi-const.rs +++ b/tests/codegen/cffi/ffi-const.rs @@ -10,6 +10,6 @@ extern "C" { // CHECK-LABEL: declare{{.*}}void @foo() // CHECK-SAME: [[ATTRS:#[0-9]+]] // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(none){{.*}} } - #[ffi_const] + #[unsafe(ffi_const)] pub fn foo(); } diff --git a/tests/codegen/cffi/ffi-pure.rs b/tests/codegen/cffi/ffi-pure.rs index 2c5d5f5b4b12..a61e80ecf652 100644 --- a/tests/codegen/cffi/ffi-pure.rs +++ b/tests/codegen/cffi/ffi-pure.rs @@ -10,6 +10,6 @@ extern "C" { // CHECK-LABEL: declare{{.*}}void @foo() // CHECK-SAME: [[ATTRS:#[0-9]+]] // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(read){{.*}} } - #[ffi_pure] + #[unsafe(ffi_pure)] pub fn foo(); } diff --git a/tests/ui/feature-gates/feature-gate-ffi_const.rs b/tests/ui/feature-gates/feature-gate-ffi_const.rs index 9f3d783ccd69..35f91b99a6f4 100644 --- a/tests/ui/feature-gates/feature-gate-ffi_const.rs +++ b/tests/ui/feature-gates/feature-gate-ffi_const.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] extern "C" { - #[ffi_const] //~ ERROR the `#[ffi_const]` attribute is an experimental feature + #[unsafe(ffi_const)] //~ ERROR the `#[ffi_const]` attribute is an experimental feature pub fn foo(); } diff --git a/tests/ui/feature-gates/feature-gate-ffi_const.stderr b/tests/ui/feature-gates/feature-gate-ffi_const.stderr index d083b826d6e1..7e8c941be07d 100644 --- a/tests/ui/feature-gates/feature-gate-ffi_const.stderr +++ b/tests/ui/feature-gates/feature-gate-ffi_const.stderr @@ -1,8 +1,8 @@ error[E0658]: the `#[ffi_const]` attribute is an experimental feature --> $DIR/feature-gate-ffi_const.rs:4:5 | -LL | #[ffi_const] - | ^^^^^^^^^^^^ +LL | #[unsafe(ffi_const)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #58328 for more information = help: add `#![feature(ffi_const)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-ffi_pure.rs b/tests/ui/feature-gates/feature-gate-ffi_pure.rs index b0dfa01ff4c2..0f1288b234e4 100644 --- a/tests/ui/feature-gates/feature-gate-ffi_pure.rs +++ b/tests/ui/feature-gates/feature-gate-ffi_pure.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] extern "C" { - #[ffi_pure] //~ ERROR the `#[ffi_pure]` attribute is an experimental feature + #[unsafe(ffi_pure)] //~ ERROR the `#[ffi_pure]` attribute is an experimental feature pub fn foo(); } diff --git a/tests/ui/feature-gates/feature-gate-ffi_pure.stderr b/tests/ui/feature-gates/feature-gate-ffi_pure.stderr index 6544d450eeb9..cf923536d6c5 100644 --- a/tests/ui/feature-gates/feature-gate-ffi_pure.stderr +++ b/tests/ui/feature-gates/feature-gate-ffi_pure.stderr @@ -1,8 +1,8 @@ error[E0658]: the `#[ffi_pure]` attribute is an experimental feature --> $DIR/feature-gate-ffi_pure.rs:4:5 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ | = note: see issue #58329 for more information = help: add `#![feature(ffi_pure)]` to the crate attributes to enable diff --git a/tests/ui/ffi-attrs/ffi_const.rs b/tests/ui/ffi-attrs/ffi_const.rs index aa20a4d4c653..dddc862b0fa6 100644 --- a/tests/ui/ffi-attrs/ffi_const.rs +++ b/tests/ui/ffi-attrs/ffi_const.rs @@ -1,15 +1,18 @@ #![feature(ffi_const)] #![crate_type = "lib"] -#[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions +#[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions pub fn foo() {} -#[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions +#[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions macro_rules! bar { - () => () + () => {}; } extern "C" { - #[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions + #[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions static INT: i32; + + #[ffi_const] //~ ERROR unsafe attribute used without unsafe + fn bar(); } diff --git a/tests/ui/ffi-attrs/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr index 394b98f89712..7f31237539d1 100644 --- a/tests/ui/ffi-attrs/ffi_const.stderr +++ b/tests/ui/ffi-attrs/ffi_const.stderr @@ -1,21 +1,32 @@ +error: unsafe attribute used without unsafe + --> $DIR/ffi_const.rs:16:7 + | +LL | #[ffi_const] + | ^^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(ffi_const)] + | +++++++ + + error[E0756]: `#[ffi_const]` may only be used on foreign functions --> $DIR/ffi_const.rs:4:1 | -LL | #[ffi_const] - | ^^^^^^^^^^^^ +LL | #[unsafe(ffi_const)] + | ^^^^^^^^^^^^^^^^^^^^ error[E0756]: `#[ffi_const]` may only be used on foreign functions --> $DIR/ffi_const.rs:7:1 | -LL | #[ffi_const] - | ^^^^^^^^^^^^ +LL | #[unsafe(ffi_const)] + | ^^^^^^^^^^^^^^^^^^^^ error[E0756]: `#[ffi_const]` may only be used on foreign functions --> $DIR/ffi_const.rs:13:5 | -LL | #[ffi_const] - | ^^^^^^^^^^^^ +LL | #[unsafe(ffi_const)] + | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0756`. diff --git a/tests/ui/ffi-attrs/ffi_const2.rs b/tests/ui/ffi-attrs/ffi_const2.rs index 82fe8a9c91dd..8a8de13b1530 100644 --- a/tests/ui/ffi-attrs/ffi_const2.rs +++ b/tests/ui/ffi-attrs/ffi_const2.rs @@ -1,8 +1,8 @@ #![feature(ffi_const, ffi_pure)] extern "C" { - #[ffi_pure] //~ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]` - #[ffi_const] + #[unsafe(ffi_pure)] //~ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]` + #[unsafe(ffi_const)] pub fn baz(); } diff --git a/tests/ui/ffi-attrs/ffi_const2.stderr b/tests/ui/ffi-attrs/ffi_const2.stderr index b8cbc296370d..d4c9bc42ec9e 100644 --- a/tests/ui/ffi-attrs/ffi_const2.stderr +++ b/tests/ui/ffi-attrs/ffi_const2.stderr @@ -1,8 +1,8 @@ error[E0757]: `#[ffi_const]` function cannot be `#[ffi_pure]` --> $DIR/ffi_const2.rs:4:5 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/ffi-attrs/ffi_pure.rs b/tests/ui/ffi-attrs/ffi_pure.rs index 6d2f3a614ec9..1f4812f55cf1 100644 --- a/tests/ui/ffi-attrs/ffi_pure.rs +++ b/tests/ui/ffi-attrs/ffi_pure.rs @@ -1,15 +1,18 @@ #![feature(ffi_pure)] #![crate_type = "lib"] -#[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions +#[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions pub fn foo() {} -#[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions +#[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions macro_rules! bar { - () => () + () => {}; } extern "C" { - #[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions + #[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions static INT: i32; + + #[ffi_pure] //~ ERROR unsafe attribute used without unsafe + fn bar(); } diff --git a/tests/ui/ffi-attrs/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr index 8b61a4b609fc..bd1177c01e2b 100644 --- a/tests/ui/ffi-attrs/ffi_pure.stderr +++ b/tests/ui/ffi-attrs/ffi_pure.stderr @@ -1,21 +1,32 @@ +error: unsafe attribute used without unsafe + --> $DIR/ffi_pure.rs:16:7 + | +LL | #[ffi_pure] + | ^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(ffi_pure)] + | +++++++ + + error[E0755]: `#[ffi_pure]` may only be used on foreign functions --> $DIR/ffi_pure.rs:4:1 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ error[E0755]: `#[ffi_pure]` may only be used on foreign functions --> $DIR/ffi_pure.rs:7:1 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ error[E0755]: `#[ffi_pure]` may only be used on foreign functions --> $DIR/ffi_pure.rs:13:5 | -LL | #[ffi_pure] - | ^^^^^^^^^^^ +LL | #[unsafe(ffi_pure)] + | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0755`. From 5d90ccb0fa2e9d2bb0146de225921ebc260b30bb Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 13 Apr 2025 00:35:06 +0100 Subject: [PATCH 096/222] Move `select_unpredictable` to the `hint` module --- library/core/src/bool.rs | 48 ------------------ library/core/src/hint.rs | 49 +++++++++++++++++++ library/core/src/intrinsics/mod.rs | 2 +- library/core/src/slice/mod.rs | 2 +- .../core/src/slice/sort/shared/smallsort.rs | 18 +++---- .../intrinsics/select_unpredictable.rs | 8 +-- 6 files changed, 64 insertions(+), 63 deletions(-) diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index d525ab425e60..2016ece007eb 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -61,52 +61,4 @@ impl bool { pub fn then T>(self, f: F) -> Option { if self { Some(f()) } else { None } } - - /// Returns either `true_val` or `false_val` depending on the value of - /// `self`, with a hint to the compiler that `self` is unlikely - /// to be correctly predicted by a CPU’s branch predictor. - /// - /// This method is functionally equivalent to - /// ```ignore (this is just for illustrative purposes) - /// fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { - /// if b { true_val } else { false_val } - /// } - /// ``` - /// but might generate different assembly. In particular, on platforms with - /// a conditional move or select instruction (like `cmov` on x86 or `csel` - /// on ARM) the optimizer might use these instructions to avoid branches, - /// which can benefit performance if the branch predictor is struggling - /// with predicting `condition`, such as in an implementation of binary - /// search. - /// - /// Note however that this lowering is not guaranteed (on any platform) and - /// should not be relied upon when trying to write constant-time code. Also - /// be aware that this lowering might *decrease* performance if `condition` - /// is well-predictable. It is advisable to perform benchmarks to tell if - /// this function is useful. - /// - /// # Examples - /// - /// Distribute values evenly between two buckets: - /// ``` - /// #![feature(select_unpredictable)] - /// - /// use std::hash::BuildHasher; - /// - /// fn append(hasher: &H, v: i32, bucket_one: &mut Vec, bucket_two: &mut Vec) { - /// let hash = hasher.hash_one(&v); - /// let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two); - /// bucket.push(v); - /// } - /// # let hasher = std::collections::hash_map::RandomState::new(); - /// # let mut bucket_one = Vec::new(); - /// # let mut bucket_two = Vec::new(); - /// # append(&hasher, 42, &mut bucket_one, &mut bucket_two); - /// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); - /// ``` - #[inline(always)] - #[unstable(feature = "select_unpredictable", issue = "133962")] - pub fn select_unpredictable(self, true_val: T, false_val: T) -> T { - crate::intrinsics::select_unpredictable(self, true_val, false_val) - } } diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 5ce282b05de7..f6708cc4bc91 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -734,3 +734,52 @@ pub const fn unlikely(b: bool) -> bool { pub const fn cold_path() { crate::intrinsics::cold_path() } + +/// Returns either `true_val` or `false_val` depending on the value of `b`, +/// with a hint to the compiler that `b` is unlikely to be correctly +/// predicted by a CPU’s branch predictor. +/// +/// This method is functionally equivalent to +/// ```ignore (this is just for illustrative purposes) +/// fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { +/// if b { true_val } else { false_val } +/// } +/// ``` +/// but might generate different assembly. In particular, on platforms with +/// a conditional move or select instruction (like `cmov` on x86 or `csel` +/// on ARM) the optimizer might use these instructions to avoid branches, +/// which can benefit performance if the branch predictor is struggling +/// with predicting `condition`, such as in an implementation of binary +/// search. +/// +/// Note however that this lowering is not guaranteed (on any platform) and +/// should not be relied upon when trying to write constant-time code. Also +/// be aware that this lowering might *decrease* performance if `condition` +/// is well-predictable. It is advisable to perform benchmarks to tell if +/// this function is useful. +/// +/// # Examples +/// +/// Distribute values evenly between two buckets: +/// ``` +/// #![feature(select_unpredictable)] +/// +/// use std::hash::BuildHasher; +/// use std::hint; +/// +/// fn append(hasher: &H, v: i32, bucket_one: &mut Vec, bucket_two: &mut Vec) { +/// let hash = hasher.hash_one(&v); +/// let bucket = hint::select_unpredictable(hash % 2 == 0, bucket_one, bucket_two); +/// bucket.push(v); +/// } +/// # let hasher = std::collections::hash_map::RandomState::new(); +/// # let mut bucket_one = Vec::new(); +/// # let mut bucket_two = Vec::new(); +/// # append(&hasher, 42, &mut bucket_one, &mut bucket_two); +/// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); +/// ``` +#[inline(always)] +#[unstable(feature = "select_unpredictable", issue = "133962")] +pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { + crate::intrinsics::select_unpredictable(b, true_val, false_val) +} diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index e99776a71c1d..a55a52cf34c5 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1326,7 +1326,7 @@ pub const fn unlikely(b: bool) -> bool { /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// -/// The public form of this instrinsic is [`bool::select_unpredictable`]. +/// The public form of this instrinsic is [`core::hint::select_unpredictable`]. #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index b906899a30b3..d91b5bacbebc 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2828,7 +2828,7 @@ impl [T] { // Binary search interacts poorly with branch prediction, so force // the compiler to use conditional moves if supported by the target // architecture. - base = (cmp == Greater).select_unpredictable(base, mid); + base = hint::select_unpredictable(cmp == Greater, base, mid); // This is imprecise in the case where `size` is odd and the // comparison returns Greater: the mid element still gets included diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index 95f196a40d01..4280f7570db4 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -2,7 +2,7 @@ use crate::mem::{self, ManuallyDrop, MaybeUninit}; use crate::slice::sort::shared::FreezeMarker; -use crate::{intrinsics, ptr, slice}; +use crate::{hint, intrinsics, ptr, slice}; // It's important to differentiate between SMALL_SORT_THRESHOLD performance for // small slices and small-sort performance sorting small sub-slices as part of @@ -408,8 +408,8 @@ where // } // The goal is to generate cmov instructions here. - let v_a_swap = should_swap.select_unpredictable(v_b, v_a); - let v_b_swap = should_swap.select_unpredictable(v_a, v_b); + let v_a_swap = hint::select_unpredictable(should_swap, v_b, v_a); + let v_b_swap = hint::select_unpredictable(should_swap, v_a, v_b); let v_b_swap_tmp = ManuallyDrop::new(ptr::read(v_b_swap)); ptr::copy(v_a_swap, v_a, 1); @@ -640,15 +640,15 @@ pub unsafe fn sort4_stable bool>( // 1, 1 | c b a d let c3 = is_less(&*c, &*a); let c4 = is_less(&*d, &*b); - let min = c3.select_unpredictable(c, a); - let max = c4.select_unpredictable(b, d); - let unknown_left = c3.select_unpredictable(a, c4.select_unpredictable(c, b)); - let unknown_right = c4.select_unpredictable(d, c3.select_unpredictable(b, c)); + let min = hint::select_unpredictable(c3, c, a); + let max = hint::select_unpredictable(c4, b, d); + let unknown_left = hint::select_unpredictable(c3, a, hint::select_unpredictable(c4, c, b)); + let unknown_right = hint::select_unpredictable(c4, d, hint::select_unpredictable(c3, b, c)); // Sort the last two unknown elements. let c5 = is_less(&*unknown_right, &*unknown_left); - let lo = c5.select_unpredictable(unknown_right, unknown_left); - let hi = c5.select_unpredictable(unknown_left, unknown_right); + let lo = hint::select_unpredictable(c5, unknown_right, unknown_left); + let hi = hint::select_unpredictable(c5, unknown_left, unknown_right); ptr::copy_nonoverlapping(min, dst, 1); ptr::copy_nonoverlapping(lo, dst.add(1), 1); diff --git a/tests/codegen/intrinsics/select_unpredictable.rs b/tests/codegen/intrinsics/select_unpredictable.rs index 68a02c8342d0..2db4ae174b33 100644 --- a/tests/codegen/intrinsics/select_unpredictable.rs +++ b/tests/codegen/intrinsics/select_unpredictable.rs @@ -46,21 +46,21 @@ pub fn test_zst(p: bool, a: (), b: ()) -> () { pub fn test_int2(p: bool, a: u64, b: u64) -> u64 { // CHECK-LABEL: define{{.*}} @test_int2 // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable - p.select_unpredictable(a, b) + core::hint::select_unpredictable(p, a, b) } #[no_mangle] pub fn test_pair2(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) { // CHECK-LABEL: define{{.*}} @test_pair2 // CHECK: select i1 %p, {{.*}}, !unpredictable - p.select_unpredictable(a, b) + core::hint::select_unpredictable(p, a, b) } #[no_mangle] pub fn test_struct2(p: bool, a: Large, b: Large) -> Large { // CHECK-LABEL: define{{.*}} @test_struct2 // CHECK: select i1 %p, {{.*}}, !unpredictable - p.select_unpredictable(a, b) + core::hint::select_unpredictable(p, a, b) } #[no_mangle] @@ -68,5 +68,5 @@ pub fn test_zst2(p: bool, a: (), b: ()) -> () { // CHECK-LABEL: define{{.*}} @test_zst2 // CHECK-NEXT: start: // CHECK-NEXT: ret void - p.select_unpredictable(a, b) + core::hint::select_unpredictable(p, a, b) } From 756670f40ebedd4a6cb1ebf356cb327442888d0a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 23 Mar 2025 20:45:36 -0700 Subject: [PATCH 097/222] Extend the chaining logic to slices too --- library/core/src/cmp.rs | 32 ++++++ library/core/src/slice/cmp.rs | 178 ++++++++++++++++++++++++++++------ library/core/src/tuple.rs | 29 +++++- tests/codegen/array-cmp.rs | 55 +++++++++-- 4 files changed, 256 insertions(+), 38 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 0dc2cc72e06c..c315131f4136 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -2053,6 +2053,22 @@ mod impls { fn ge(&self, other: &&B) -> bool { PartialOrd::ge(*self, *other) } + #[inline] + fn __chaining_lt(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_lt(*self, *other) + } + #[inline] + fn __chaining_le(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_le(*self, *other) + } + #[inline] + fn __chaining_gt(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_gt(*self, *other) + } + #[inline] + fn __chaining_ge(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_ge(*self, *other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for &A @@ -2108,6 +2124,22 @@ mod impls { fn ge(&self, other: &&mut B) -> bool { PartialOrd::ge(*self, *other) } + #[inline] + fn __chaining_lt(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_lt(*self, *other) + } + #[inline] + fn __chaining_le(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_le(*self, *other) + } + #[inline] + fn __chaining_gt(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_gt(*self, *other) + } + #[inline] + fn __chaining_ge(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_ge(*self, *other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for &mut A diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index da85f42926e6..5ce72b46eee3 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -5,6 +5,7 @@ use crate::ascii; use crate::cmp::{self, BytewiseEq, Ordering}; use crate::intrinsics::compare_bytes; use crate::num::NonZero; +use crate::ops::ControlFlow; #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[U]> for [T] @@ -31,12 +32,64 @@ impl Ord for [T] { } } +#[inline] +fn as_underlying(x: ControlFlow) -> u8 { + // SAFETY: This will only compile if `bool` and `ControlFlow` have the same + // size (which isn't guaranteed but this is libcore). Because they have the same + // size, it's a niched implementation, which in one byte means there can't be + // any uninitialized memory. The callers then only check for `0` or `1` from this, + // which must necessarily match the `Break` variant, and we're fine no matter + // what ends up getting picked as the value representing `Continue(())`. + unsafe { crate::mem::transmute(x) } +} + /// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for [T] { + #[inline] fn partial_cmp(&self, other: &[T]) -> Option { SlicePartialOrd::partial_compare(self, other) } + #[inline] + fn lt(&self, other: &Self) -> bool { + // This is certainly not the obvious way to implement these methods. + // Unfortunately, using anything that looks at the discriminant means that + // LLVM sees a check for `2` (aka `ControlFlow::Continue(())`) and + // gets very distracted by that, ending up generating extraneous code. + // This should be changed to something simpler once either LLVM is smarter, + // see , or we generate + // niche discriminant checks in a way that doesn't trigger it. + + as_underlying(self.__chaining_lt(other)) == 1 + } + #[inline] + fn le(&self, other: &Self) -> bool { + as_underlying(self.__chaining_le(other)) != 0 + } + #[inline] + fn gt(&self, other: &Self) -> bool { + as_underlying(self.__chaining_gt(other)) == 1 + } + #[inline] + fn ge(&self, other: &Self) -> bool { + as_underlying(self.__chaining_ge(other)) != 0 + } + #[inline] + fn __chaining_lt(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_lt(self, other) + } + #[inline] + fn __chaining_le(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_le(self, other) + } + #[inline] + fn __chaining_gt(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_gt(self, other) + } + #[inline] + fn __chaining_ge(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_ge(self, other) + } } #[doc(hidden)] @@ -99,26 +152,65 @@ trait SlicePartialOrd: Sized { fn partial_compare(left: &[Self], right: &[Self]) -> Option; } +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialOrd chaining methods +trait SliceChain: Sized { + fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow; + fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow; + fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow; + fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow; +} + +type AlwaysBreak = ControlFlow; + impl SlicePartialOrd for A { default fn partial_compare(left: &[A], right: &[A]) -> Option { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].partial_cmp(&rhs[i]) { - Some(Ordering::Equal) => (), - non_eq => return non_eq, - } - } - - left.len().partial_cmp(&right.len()) + let elem_chain = |a, b| match PartialOrd::partial_cmp(a, b) { + Some(Ordering::Equal) => ControlFlow::Continue(()), + non_eq => ControlFlow::Break(non_eq), + }; + let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::partial_cmp(a, b)); + let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain); + b } } +impl SliceChain for A { + default fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_lt, usize::__chaining_lt) + } + default fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_le, usize::__chaining_le) + } + default fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_gt, usize::__chaining_gt) + } + default fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_ge, usize::__chaining_ge) + } +} + +#[inline] +fn chaining_impl<'l, 'r, A: PartialOrd, B, C>( + left: &'l [A], + right: &'r [A], + elem_chain: impl Fn(&'l A, &'r A) -> ControlFlow, + len_chain: impl for<'a> FnOnce(&'a usize, &'a usize) -> ControlFlow, +) -> ControlFlow { + let l = cmp::min(left.len(), right.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &left[..l]; + let rhs = &right[..l]; + + for i in 0..l { + elem_chain(&lhs[i], &rhs[i])?; + } + + len_chain(&left.len(), &right.len()) +} + // This is the impl that we would like to have. Unfortunately it's not sound. // See `partial_ord_slice.rs`. /* @@ -165,21 +257,13 @@ trait SliceOrd: Sized { impl SliceOrd for A { default fn compare(left: &[Self], right: &[Self]) -> Ordering { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].cmp(&rhs[i]) { - Ordering::Equal => (), - non_eq => return non_eq, - } - } - - left.len().cmp(&right.len()) + let elem_chain = |a, b| match Ord::cmp(a, b) { + Ordering::Equal => ControlFlow::Continue(()), + non_eq => ControlFlow::Break(non_eq), + }; + let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::cmp(a, b)); + let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain); + b } } @@ -191,7 +275,7 @@ impl SliceOrd for A { /// * For every `x` and `y` of this type, `Ord(x, y)` must return the same /// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`. #[rustc_specialization_trait] -unsafe trait UnsignedBytewiseOrd {} +unsafe trait UnsignedBytewiseOrd: Ord {} unsafe impl UnsignedBytewiseOrd for bool {} unsafe impl UnsignedBytewiseOrd for u8 {} @@ -225,6 +309,38 @@ impl SliceOrd for A { } } +// Don't generate our own chaining loops for `memcmp`-able things either. +impl SliceChain for A { + #[inline] + fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_lt()), + } + } + #[inline] + fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_le()), + } + } + #[inline] + fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_gt()), + } + } + #[inline] + fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_ge()), + } + } +} + pub(super) trait SliceContains: Sized { fn slice_contains(&self, x: &[Self]) -> bool; } diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index d754bb903430..02eb805ece12 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -2,7 +2,7 @@ use crate::cmp::Ordering::{self, *}; use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; -use crate::ops::ControlFlow::{Break, Continue}; +use crate::ops::ControlFlow::{self, Break, Continue}; // Recursive macro for implementing n-ary tuple functions and operations // @@ -95,6 +95,22 @@ macro_rules! tuple_impls { fn gt(&self, other: &($($T,)+)) -> bool { lexical_ord!(gt, __chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } + #[inline] + fn __chaining_lt(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } + #[inline] + fn __chaining_le(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } + #[inline] + fn __chaining_gt(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } + #[inline] + fn __chaining_ge(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } } } @@ -187,6 +203,17 @@ macro_rules! lexical_ord { }; } +// Same parameter interleaving as `lexical_ord` above +macro_rules! lexical_chain { + ($chain_rel: ident, $a:expr, $b:expr $(,$rest_a:expr, $rest_b:expr)*) => {{ + PartialOrd::$chain_rel(&$a, &$b)?; + lexical_chain!($chain_rel $(,$rest_a, $rest_b)*) + }}; + ($chain_rel: ident) => { + Continue(()) + }; +} + macro_rules! lexical_partial_cmp { ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => { match ($a).partial_cmp(&$b) { diff --git a/tests/codegen/array-cmp.rs b/tests/codegen/array-cmp.rs index f9b7be898828..0d3376554017 100644 --- a/tests/codegen/array-cmp.rs +++ b/tests/codegen/array-cmp.rs @@ -1,6 +1,7 @@ // Ensure the asm for array comparisons is properly optimized. //@ compile-flags: -C opt-level=2 +//@ needs-deterministic-layouts (checks depend on tuple layout) #![crate_type = "lib"] @@ -19,13 +20,55 @@ pub fn compare() -> bool { } // CHECK-LABEL: @array_of_tuple_le -// CHECK: call{{.+}}i8 @llvm.scmp.i8.i16 -// CHECK: call{{.+}}i8 @llvm.ucmp.i8.i16 -// CHECK: call{{.+}}i8 @llvm.scmp.i8.i16 -// CHECK: call{{.+}}i8 @llvm.ucmp.i8.i16 -// CHECK: %[[RET:.+]] = icmp slt i8 {{.+}}, 1 -// CHECK: ret i8 %[[RET]] #[no_mangle] pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool { + // Ensure that, after all the optimizations have run, the happy path just checks + // `eq` on each corresponding pair and moves onto the next one if it is. + // Then there's a dedup'd comparison for the place that's different. + // (As opposed to, say, running a full `[su]cmp` as part of checking equality.) + + // This is written quite specifically because different library code was triggering + // along the way, so this + // has enough checks to make sure that's not happening. It doesn't need to be + // *exactly* this IR, but be careful if you ever need to update these checks. + + // CHECK: start: + // CHECK: %[[A00:.+]] = load i16, ptr %a + // CHECK: %[[B00:.+]] = load i16, ptr %b + // CHECK-NOT: cmp + // CHECK: %[[EQ00:.+]] = icmp eq i16 %[[A00]], %[[B00]] + // CHECK-NEXT: br i1 %[[EQ00]], label %[[L01:.+]], label %[[EXIT_S:.+]] + + // CHECK: [[L01]]: + // CHECK: %[[PA01:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 2 + // CHECK: %[[PB01:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 2 + // CHECK: %[[A01:.+]] = load i16, ptr %[[PA01]] + // CHECK: %[[B01:.+]] = load i16, ptr %[[PB01]] + // CHECK-NOT: cmp + // CHECK: %[[EQ01:.+]] = icmp eq i16 %[[A01]], %[[B01]] + // CHECK-NEXT: br i1 %[[EQ01]], label %[[L10:.+]], label %[[EXIT_U:.+]] + + // CHECK: [[L10]]: + // CHECK: %[[PA10:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 4 + // CHECK: %[[PB10:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 4 + // CHECK: %[[A10:.+]] = load i16, ptr %[[PA10]] + // CHECK: %[[B10:.+]] = load i16, ptr %[[PB10]] + // CHECK-NOT: cmp + // CHECK: %[[EQ10:.+]] = icmp eq i16 %[[A10]], %[[B10]] + // CHECK-NEXT: br i1 %[[EQ10]], label %[[L11:.+]], label %[[EXIT_S]] + + // CHECK: [[L11]]: + // CHECK: %[[PA11:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 6 + // CHECK: %[[PB11:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 6 + // CHECK: %[[A11:.+]] = load i16, ptr %[[PA11]] + // CHECK: %[[B11:.+]] = load i16, ptr %[[PB11]] + // CHECK-NOT: cmp + // CHECK: %[[EQ11:.+]] = icmp eq i16 %[[A11]], %[[B11]] + // CHECK-NEXT: br i1 %[[EQ11]], label %[[DONE:.+]], label %[[EXIT_U]] + + // CHECK: [[DONE]]: + // CHECK: %[[RET:.+]] = phi i1 [ %{{.+}}, %[[EXIT_S]] ], [ %{{.+}}, %[[EXIT_U]] ], [ true, %[[L11]] ] + // CHECK: ret i1 %[[RET]] + a <= b } From 21b7360a9aecac472d6b7b9716c8e57641f648d0 Mon Sep 17 00:00:00 2001 From: Sky Date: Fri, 14 Feb 2025 15:56:24 -0500 Subject: [PATCH 098/222] Initial `UnsafePinned`/`UnsafeUnpin` impl [Part 1: Libs] --- compiler/rustc_abi/src/layout.rs | 8 +- compiler/rustc_hir/src/lang_items.rs | 3 + compiler/rustc_lint/src/types.rs | 4 +- compiler/rustc_middle/src/ty/adt.rs | 13 ++ compiler/rustc_span/src/symbol.rs | 2 + compiler/rustc_ty_utils/src/layout.rs | 7 +- library/core/src/lib.rs | 1 + library/core/src/marker.rs | 29 +++ library/core/src/pin.rs | 5 + library/core/src/pin/unsafe_pinned.rs | 197 ++++++++++++++++++ .../unsafe-pinned-hides-niche.rs | 29 +++ 11 files changed, 290 insertions(+), 8 deletions(-) create mode 100644 library/core/src/pin/unsafe_pinned.rs create mode 100644 tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 7bffeaf4cc9e..42250aa173bb 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -315,7 +315,7 @@ impl LayoutCalculator { repr: &ReprOptions, variants: &IndexSlice>, is_enum: bool, - is_unsafe_cell: bool, + is_special_no_niche: bool, scalar_valid_range: (Bound, Bound), discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), discriminants: impl Iterator, @@ -348,7 +348,7 @@ impl LayoutCalculator { repr, variants, is_enum, - is_unsafe_cell, + is_special_no_niche, scalar_valid_range, always_sized, present_first, @@ -505,7 +505,7 @@ impl LayoutCalculator { repr: &ReprOptions, variants: &IndexSlice>, is_enum: bool, - is_unsafe_cell: bool, + is_special_no_niche: bool, scalar_valid_range: (Bound, Bound), always_sized: bool, present_first: VariantIdx, @@ -524,7 +524,7 @@ impl LayoutCalculator { let mut st = self.univariant(&variants[v], repr, kind)?; st.variants = Variants::Single { index: v }; - if is_unsafe_cell { + if is_special_no_niche { let hide_niches = |scalar: &mut _| match scalar { Scalar::Initialized { value, valid_range } => { *valid_range = WrappingRange::full(value.size(dl)) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 90fab01ba2d4..d4488b4b6576 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -182,6 +182,7 @@ language_item_table! { DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None; Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0); + UnsafeUnpin, sym::unsafe_unpin, unsafe_unpin_trait, Target::Trait, GenericRequirement::Exact(0); FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0); FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; @@ -235,6 +236,8 @@ language_item_table! { IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1); UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None; + UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None; + VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None; Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a6c82f574a1c..a084dacfb5be 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -864,8 +864,8 @@ fn ty_is_known_nonnull<'tcx>( return true; } - // `UnsafeCell` has its niche hidden. - if def.is_unsafe_cell() { + // `UnsafeCell` and `UnsafePinned` have their niche hidden. + if def.is_unsafe_cell() || def.is_unsafe_pinned() { return false; } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 00fe5cb0c5d6..66517c97a687 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -53,6 +53,10 @@ bitflags::bitflags! { const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; /// Indicates whether the type is `UnsafeCell`. const IS_UNSAFE_CELL = 1 << 9; + /// Indicates whether the type is `UnsafePinned`. + const IS_UNSAFE_PINNED = 1 << 10; + /// Indicates whether the type is anonymous. + const IS_ANONYMOUS = 1 << 11; } } rustc_data_structures::external_bitflags_debug! { AdtFlags } @@ -302,6 +306,9 @@ impl AdtDefData { if tcx.is_lang_item(did, LangItem::UnsafeCell) { flags |= AdtFlags::IS_UNSAFE_CELL; } + if tcx.is_lang_item(did, LangItem::UnsafePinned) { + flags |= AdtFlags::IS_UNSAFE_PINNED; + } AdtDefData { did, variants, flags, repr } } @@ -405,6 +412,12 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_UNSAFE_CELL) } + /// Returns `true` if this is `UnsafePinned`. + #[inline] + pub fn is_unsafe_pinned(self) -> bool { + self.flags().contains(AdtFlags::IS_UNSAFE_PINNED) + } + /// Returns `true` if this is `ManuallyDrop`. #[inline] pub fn is_manually_drop(self) -> bool { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 986370f50191..63be641d0c1e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2215,6 +2215,8 @@ symbols! { unsafe_fields, unsafe_no_drop_flag, unsafe_pin_internals, + unsafe_pinned, + unsafe_unpin, unsize, unsized_const_param_ty, unsized_const_params, diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 0017186c1b08..1915ba623cb2 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -514,6 +514,9 @@ fn layout_of_uncached<'tcx>( return map_layout(cx.calc.layout_of_union(&def.repr(), &variants)); } + // UnsafeCell and UnsafePinned both disable niche optimizations + let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned(); + let get_discriminant_type = |min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max); @@ -542,7 +545,7 @@ fn layout_of_uncached<'tcx>( &def.repr(), &variants, def.is_enum(), - def.is_unsafe_cell(), + is_special_no_niche, tcx.layout_scalar_valid_range(def.did()), get_discriminant_type, discriminants_iter(), @@ -568,7 +571,7 @@ fn layout_of_uncached<'tcx>( &def.repr(), &variants, def.is_enum(), - def.is_unsafe_cell(), + is_special_no_niche, tcx.layout_scalar_valid_range(def.did()), get_discriminant_type, discriminants_iter(), diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index dc06aa4c38d5..5f701921eb66 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -127,6 +127,7 @@ #![feature(ub_checks)] #![feature(unchecked_neg)] #![feature(unchecked_shifts)] +#![feature(unsafe_pinned)] #![feature(utf16_extra)] #![feature(variant_count)] // tidy-alphabetical-end diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 68011310d2ca..9dc20beda6c6 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -17,6 +17,7 @@ use crate::cell::UnsafeCell; use crate::cmp; use crate::fmt::Debug; use crate::hash::{Hash, Hasher}; +use crate::pin::UnsafePinned; /// Implements a given marker trait for multiple types at the same time. /// @@ -878,6 +879,23 @@ marker_impls! { {T: ?Sized} &mut T, } +/// Used to determine whether a type contains any `UnsafePinned` (or `PhantomPinned`) internally, +/// but not through an indirection. This affects, for example, whether we emit `noalias` metadata +/// for `&mut T` or not. +/// +/// This is part of [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html), and is +/// tracked by [#125735](https://github.com/rust-lang/rust/issues/125735). +#[cfg_attr(not(bootstrap), lang = "unsafe_unpin")] +#[cfg_attr(bootstrap, allow(dead_code))] +pub(crate) unsafe auto trait UnsafeUnpin {} + +impl !UnsafeUnpin for UnsafePinned {} +unsafe impl UnsafeUnpin for PhantomData {} +unsafe impl UnsafeUnpin for *const T {} +unsafe impl UnsafeUnpin for *mut T {} +unsafe impl UnsafeUnpin for &T {} +unsafe impl UnsafeUnpin for &mut T {} + /// Types that do not require any pinning guarantees. /// /// For information on what "pinning" is, see the [`pin` module] documentation. @@ -953,6 +971,11 @@ pub auto trait Unpin {} /// A marker type which does not implement `Unpin`. /// /// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default. +// +// FIXME(unsafe_pinned): This is *not* a stable guarantee we want to make, at least not yet. +// Note that for backwards compatibility with the new [`UnsafePinned`] wrapper type, placing this +// marker in your struct acts as if you wrapped the entire struct in an `UnsafePinned`. This type +// will likely eventually be deprecated, and all new code should be using `UnsafePinned` instead. #[stable(feature = "pin", since = "1.33.0")] #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct PhantomPinned; @@ -960,6 +983,12 @@ pub struct PhantomPinned; #[stable(feature = "pin", since = "1.33.0")] impl !Unpin for PhantomPinned {} +// This is a small hack to allow existing code which uses PhantomPinned to opt-out of noalias to +// continue working. Ideally PhantomPinned could just wrap an `UnsafePinned<()>` to get the same +// effect, but we can't add a new field to an already stable unit struct -- that would be a breaking +// change. +impl !UnsafeUnpin for PhantomPinned {} + marker_impls! { #[stable(feature = "pin", since = "1.33.0")] Unpin for diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 2ef1bbfd1fa7..48ed5ae451e4 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -931,6 +931,11 @@ use crate::{ }; use crate::{cmp, fmt}; +mod unsafe_pinned; + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +pub use self::unsafe_pinned::UnsafePinned; + /// A pointer which pins its pointee in place. /// /// [`Pin`] is a wrapper around some kind of pointer `Ptr` which makes that pointer "pin" its diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs new file mode 100644 index 000000000000..5fb628c8adbc --- /dev/null +++ b/library/core/src/pin/unsafe_pinned.rs @@ -0,0 +1,197 @@ +use crate::marker::{PointerLike, Unpin}; +use crate::ops::{CoerceUnsized, DispatchFromDyn}; +use crate::pin::Pin; +use crate::{fmt, ptr}; + +/// This type provides a way to opt-out of typical aliasing rules; +/// specifically, `&mut UnsafePinned` is not guaranteed to be a unique pointer. +/// +/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still +/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work +/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as +/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate +/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not +/// control! Techniques such as pinning via [`Pin`] are needed to ensure soundness. +/// +/// Similar to [`UnsafeCell`](crate::cell::UnsafeCell), `UnsafePinned` will not usually show up in +/// the public API of a library. It is an internal implementation detail of libraries that need to +/// support aliasing mutable references. +/// +/// Further note that this does *not* lift the requirement that shared references must be read-only! +/// Use `UnsafeCell` for that. +/// +/// This type blocks niches the same way `UnsafeCell` does. +#[cfg_attr(not(bootstrap), lang = "unsafe_pinned")] +#[repr(transparent)] +#[unstable(feature = "unsafe_pinned", issue = "125735")] +pub struct UnsafePinned { + value: T, +} + +/// When this type is used, that almost certainly means safe APIs need to use pinning to avoid the +/// aliases from becoming invalidated. Therefore let's mark this as `!Unpin`. You can always opt +/// back in to `Unpin` with an `impl` block, provided your API is still sound while unpinned. +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl !Unpin for UnsafePinned {} + +/// The type is `Copy` when `T` is to avoid people assuming that `Copy` implies there is no +/// `UnsafePinned` anywhere. (This is an issue with `UnsafeCell`: people use `Copy` bounds to mean +/// `Freeze`.) Given that there is no `unsafe impl Copy for ...`, this is also the option that +/// leaves the user more choices (as they can always wrap this in a `!Copy` type). +// FIXME(unsafe_pinned): this may be unsound or a footgun? +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl Copy for UnsafePinned {} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl Clone for UnsafePinned { + fn clone(&self) -> Self { + *self + } +} + +// `Send` and `Sync` are inherited from `T`. This is similar to `SyncUnsafeCell`, since +// we eventually concluded that `UnsafeCell` implicitly making things `!Sync` is sometimes +// unergonomic. A type that needs to be `!Send`/`!Sync` should really have an explicit +// opt-out itself, e.g. via an `PhantomData<*mut T>` or (one day) via `impl !Send`/`impl !Sync`. + +impl UnsafePinned { + /// Constructs a new instance of `UnsafePinned` which will wrap the specified value. + /// + /// All access to the inner value through `&UnsafePinned` or `&mut UnsafePinned` or + /// `Pin<&mut UnsafePinned>` requires `unsafe` code. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn new(value: T) -> Self { + UnsafePinned { value } + } + + /// Unwraps the value, consuming this `UnsafePinned`. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + pub const fn into_inner(self) -> T { + self.value + } +} + +impl UnsafePinned { + /// Get read-write access to the contents of a pinned `UnsafePinned`. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn get_mut_pinned(self: Pin<&mut Self>) -> *mut T { + // SAFETY: we're not using `get_unchecked_mut` to unpin anything + unsafe { self.get_unchecked_mut() }.get_mut_unchecked() + } + + /// Get read-write access to the contents of an `UnsafePinned`. + /// + /// You should usually be using `get_mut_pinned` instead to explicitly track the fact that this + /// memory is "pinned" due to there being aliases. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn get_mut_unchecked(&mut self) -> *mut T { + ptr::from_mut(self) as *mut T + } + + /// Get read-only access to the contents of a shared `UnsafePinned`. + /// + /// Note that `&UnsafePinned` is read-only if `&T` is read-only. This means that if there is + /// mutation of the `T`, future reads from the `*const T` returned here are UB! Use + /// [`UnsafeCell`] if you also need interior mutability. + /// + /// [`UnsafeCell`]: crate::cell::UnsafeCell + /// + /// ```rust,no_run + /// #![feature(unsafe_pinned)] + /// use std::pin::UnsafePinned; + /// + /// unsafe { + /// let mut x = UnsafePinned::new(0); + /// let ptr = x.get(); // read-only pointer, assumes immutability + /// x.get_mut_unchecked().write(1); + /// ptr.read(); // UB! + /// } + /// ``` + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn get(&self) -> *const T { + ptr::from_ref(self) as *const T + } + + /// Gets an immutable pointer to the wrapped value. + /// + /// The difference from [`get`] is that this function accepts a raw pointer, which is useful to + /// avoid the creation of temporary references. + /// + /// [`get`]: UnsafePinned::get + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn raw_get(this: *const Self) -> *const T { + this as *const T + } + + /// Gets a mutable pointer to the wrapped value. + /// + /// The difference from [`get_mut_pinned`] and [`get_mut_unchecked`] is that this function + /// accepts a raw pointer, which is useful to avoid the creation of temporary references. + /// + /// [`get_mut_pinned`]: UnsafePinned::get_mut_pinned + /// [`get_mut_unchecked`]: UnsafePinned::get_mut_unchecked + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn raw_get_mut(this: *mut Self) -> *mut T { + this as *mut T + } +} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl Default for UnsafePinned { + /// Creates an `UnsafePinned`, with the `Default` value for T. + fn default() -> Self { + UnsafePinned::new(T::default()) + } +} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl From for UnsafePinned { + /// Creates a new `UnsafePinned` containing the given value. + fn from(value: T) -> Self { + UnsafePinned::new(value) + } +} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl fmt::Debug for UnsafePinned { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UnsafePinned").finish_non_exhaustive() + } +} + +#[unstable(feature = "coerce_unsized", issue = "18598")] +// #[unstable(feature = "unsafe_pinned", issue = "125735")] +impl, U> CoerceUnsized> for UnsafePinned {} + +// Allow types that wrap `UnsafePinned` to also implement `DispatchFromDyn` +// and become dyn-compatible method receivers. +// Note that currently `UnsafePinned` itself cannot be a method receiver +// because it does not implement Deref. +// In other words: +// `self: UnsafePinned<&Self>` won't work +// `self: UnsafePinned` becomes possible +// FIXME(unsafe_pinned) this logic is copied from UnsafeCell, is it still sound? +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +// #[unstable(feature = "unsafe_pinned", issue = "125735")] +impl, U> DispatchFromDyn> for UnsafePinned {} + +#[unstable(feature = "pointer_like_trait", issue = "none")] +// #[unstable(feature = "unsafe_pinned", issue = "125735")] +impl PointerLike for UnsafePinned {} + +// FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned? diff --git a/tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs b/tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs new file mode 100644 index 000000000000..a1ff9a1f69fd --- /dev/null +++ b/tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs @@ -0,0 +1,29 @@ +//@ check-pass +// this test ensures that UnsafePinned hides the niche of its inner type, just like UnsafeCell does + +#![crate_type = "lib"] +#![feature(unsafe_pinned)] + +use std::num::NonZero; +use std::pin::UnsafePinned; + +macro_rules! assert_size_is { + ($ty:ty = $size:expr) => { + const _: () = assert!(size_of::<$ty>() == $size); + }; +} + +assert_size_is!(UnsafePinned<()> = 0); +assert_size_is!(UnsafePinned = 1); + +assert_size_is!( UnsafePinned< u32> = 4); +assert_size_is!( UnsafePinned< NonZero> = 4); +assert_size_is!( UnsafePinned>> = 4); +assert_size_is!(Option> = 8); +assert_size_is!(Option>> = 8); +assert_size_is!(Option>>> = 8); + +assert_size_is!( UnsafePinned< &()> = size_of::()); +assert_size_is!( UnsafePinned> = size_of::()); +assert_size_is!(Option> = size_of::() * 2); +assert_size_is!(Option>> = size_of::() * 2); From 16334cdfd4640dbae4c3f5699d4f81ae358c715f Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 13 Apr 2025 17:33:55 +0800 Subject: [PATCH 099/222] tests: convert `tests/ui/lint/dead-code/self-assign.rs` to known-bug --- tests/ui/lint/dead-code/self-assign.rs | 30 ++++++++++----- tests/ui/lint/dead-code/self-assign.stderr | 44 ---------------------- 2 files changed, 20 insertions(+), 54 deletions(-) delete mode 100644 tests/ui/lint/dead-code/self-assign.stderr diff --git a/tests/ui/lint/dead-code/self-assign.rs b/tests/ui/lint/dead-code/self-assign.rs index 072a899e1bdb..357846baf221 100644 --- a/tests/ui/lint/dead-code/self-assign.rs +++ b/tests/ui/lint/dead-code/self-assign.rs @@ -1,19 +1,29 @@ -// Test that dead code warnings are issued for superfluous assignments of -// fields or variables to themselves (issue #75356). - -//@ ignore-test FIXME(81658, 83171) +//! Test that dead code warnings are issued for superfluous assignments of fields or variables to +//! themselves (issue #75356). +//! +//! # History of this test (to aid relanding of a fixed version of #81473) +//! +//! - Original lint request was about self-assignments not triggering sth like `dead_code`. +//! - `dead_code` lint expansion for self-assignments was implemented in #87129. +//! - Unfortunately implementation components of #87129 had to be disabled as part of reverts +//! #86212, #83171 (to revert #81473) to address regressions #81626 and #81658. +//! - Consequently, none of the following warnings are emitted. //@ check-pass + +// Implementation of self-assignment `dead_code` lint expansions disabled due to reverts. +//@ known-bug: #75356 + #![allow(unused_assignments)] #![warn(dead_code)] fn main() { let mut x = 0; x = x; - //~^ WARNING: useless assignment of variable of type `i32` to itself + // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself x = (x); - //~^ WARNING: useless assignment of variable of type `i32` to itself + // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself x = {x}; // block expressions don't count as self-assignments @@ -22,10 +32,10 @@ fn main() { struct S<'a> { f: &'a str } let mut s = S { f: "abc" }; s = s; - //~^ WARNING: useless assignment of variable of type `S` to itself + // FIXME ~^ WARNING: useless assignment of variable of type `S` to itself s.f = s.f; - //~^ WARNING: useless assignment of field of type `&str` to itself + // FIXME ~^ WARNING: useless assignment of field of type `&str` to itself struct N0 { x: Box } @@ -34,11 +44,11 @@ fn main() { struct N3 { n: N2 }; let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) }; n3.n.0.n.x = n3.n.0.n.x; - //~^ WARNING: useless assignment of field of type `Box` to itself + // FIXME ~^ WARNING: useless assignment of field of type `Box` to itself let mut t = (1, ((2, 3, (4, 5)),)); t.1.0.2.1 = t.1.0.2.1; - //~^ WARNING: useless assignment of field of type `i32` to itself + // FIXME ~^ WARNING: useless assignment of field of type `i32` to itself let mut y = 0; diff --git a/tests/ui/lint/dead-code/self-assign.stderr b/tests/ui/lint/dead-code/self-assign.stderr deleted file mode 100644 index bb79c0ec72a3..000000000000 --- a/tests/ui/lint/dead-code/self-assign.stderr +++ /dev/null @@ -1,44 +0,0 @@ -warning: useless assignment of variable of type `i32` to itself - --> $DIR/self-assign.rs:10:5 - | -LL | x = x; - | ^^^^^ - | -note: the lint level is defined here - --> $DIR/self-assign.rs:6:9 - | -LL | #![warn(dead_code)] - | ^^^^^^^^^ - -warning: useless assignment of variable of type `i32` to itself - --> $DIR/self-assign.rs:13:5 - | -LL | x = (x); - | ^^^^^^^ - -warning: useless assignment of variable of type `S` to itself - --> $DIR/self-assign.rs:22:5 - | -LL | s = s; - | ^^^^^ - -warning: useless assignment of field of type `&str` to itself - --> $DIR/self-assign.rs:25:5 - | -LL | s.f = s.f; - | ^^^^^^^^^ - -warning: useless assignment of field of type `Box` to itself - --> $DIR/self-assign.rs:34:5 - | -LL | n3.n.0.n.x = n3.n.0.n.x; - | ^^^^^^^^^^^^^^^^^^^^^^^ - -warning: useless assignment of field of type `i32` to itself - --> $DIR/self-assign.rs:38:5 - | -LL | t.1.0.2.1 = t.1.0.2.1; - | ^^^^^^^^^^^^^^^^^^^^^ - -warning: 6 warnings emitted - From 6b2262ecde4bc03d5e3fdca27dbb5493c135e2df Mon Sep 17 00:00:00 2001 From: zjp Date: Sun, 13 Apr 2025 18:07:43 +0800 Subject: [PATCH 100/222] add missing `extern crate rustc_middle` in rustc_smir::run! docstring --- compiler/rustc_smir/src/rustc_internal/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index a546a44c8700..a616a37305b8 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -244,6 +244,7 @@ where /// ```ignore(needs-extern-crate) /// # extern crate rustc_driver; /// # extern crate rustc_interface; +/// # extern crate rustc_middle; /// # #[macro_use] /// # extern crate rustc_smir; /// # extern crate stable_mir; @@ -264,6 +265,7 @@ where /// ```ignore(needs-extern-crate) /// # extern crate rustc_driver; /// # extern crate rustc_interface; +/// # extern crate rustc_middle; /// # #[macro_use] /// # extern crate rustc_smir; /// # extern crate stable_mir; From 6d5f6fd2937a3bce2ed7f75e9210393d98f66125 Mon Sep 17 00:00:00 2001 From: zjp Date: Sun, 13 Apr 2025 18:09:10 +0800 Subject: [PATCH 101/222] import rustc_smir::rustc_internal in run_driver! --- compiler/rustc_smir/src/rustc_internal/mod.rs | 1 + tests/ui-fulldeps/stable-mir/check_abi.rs | 1 - tests/ui-fulldeps/stable-mir/check_allocation.rs | 1 - tests/ui-fulldeps/stable-mir/check_assoc_items.rs | 1 - tests/ui-fulldeps/stable-mir/check_attribute.rs | 1 - tests/ui-fulldeps/stable-mir/check_binop.rs | 1 - tests/ui-fulldeps/stable-mir/check_crate_defs.rs | 1 - tests/ui-fulldeps/stable-mir/check_def_ty.rs | 1 - tests/ui-fulldeps/stable-mir/check_defs.rs | 1 - tests/ui-fulldeps/stable-mir/check_foreign.rs | 1 - tests/ui-fulldeps/stable-mir/check_instance.rs | 1 - tests/ui-fulldeps/stable-mir/check_intrinsics.rs | 1 - tests/ui-fulldeps/stable-mir/check_item_kind.rs | 1 - tests/ui-fulldeps/stable-mir/check_normalization.rs | 1 - tests/ui-fulldeps/stable-mir/check_trait_queries.rs | 1 - tests/ui-fulldeps/stable-mir/check_transform.rs | 1 - tests/ui-fulldeps/stable-mir/check_ty_fold.rs | 1 - tests/ui-fulldeps/stable-mir/compilation-result.rs | 1 - tests/ui-fulldeps/stable-mir/crate-info.rs | 1 - tests/ui-fulldeps/stable-mir/projections.rs | 1 - tests/ui-fulldeps/stable-mir/smir_serde.rs | 1 - tests/ui-fulldeps/stable-mir/smir_visitor.rs | 1 - 22 files changed, 1 insertion(+), 21 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index a616a37305b8..146ba17d14fc 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -330,6 +330,7 @@ macro_rules! run_driver { use rustc_driver::{Callbacks, Compilation, run_compiler}; use rustc_middle::ty::TyCtxt; use rustc_interface::interface; + use rustc_smir::rustc_internal; use stable_mir::CompilerError; use std::ops::ControlFlow; diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index ef2d5b4854be..ebf2e333f085 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::abi::{ ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi, VariantsShape, diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index c102f86a2286..ae2609bbc122 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -19,7 +19,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::crate_def::CrateDef; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{Instance, InstanceKind, StaticDef}; diff --git a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs index f75113676750..9d611543b5aa 100644 --- a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs +++ b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use std::io::Write; use std::collections::HashSet; use stable_mir::CrateDef; diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index de5ba15f6ea4..4148fc0cb6a0 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -15,7 +15,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::{CrateDef, CrateItems}; use std::io::Write; use std::ops::ControlFlow; diff --git a/tests/ui-fulldeps/stable-mir/check_binop.rs b/tests/ui-fulldeps/stable-mir/check_binop.rs index 65b3ffd27ab0..6a141e9c5775 100644 --- a/tests/ui-fulldeps/stable-mir/check_binop.rs +++ b/tests/ui-fulldeps/stable-mir/check_binop.rs @@ -15,7 +15,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::mono::Instance; use stable_mir::mir::visit::{Location, MirVisitor}; use stable_mir::mir::{LocalDecl, Rvalue, Statement, StatementKind, Terminator, TerminatorKind}; diff --git a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs index 71cca94c34f6..31c47192d090 100644 --- a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::CrateDef; use std::collections::HashSet; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs index 37b9a83e33e7..00a34f138673 100644 --- a/tests/ui-fulldeps/stable-mir/check_def_ty.rs +++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::ty::{Ty, ForeignItemKind}; use stable_mir::*; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index cd3d76d87601..1ba73377d6e9 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -19,7 +19,6 @@ extern crate stable_mir; use std::assert_matches::assert_matches; use mir::{mono::Instance, TerminatorKind::*}; use stable_mir::mir::mono::InstanceKind; -use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy}; use stable_mir::*; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs index bc3956b30908..4419050ceb2c 100644 --- a/tests/ui-fulldeps/stable-mir/check_foreign.rs +++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs @@ -17,7 +17,6 @@ extern crate rustc_interface; extern crate rustc_span; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::{ ty::{Abi, ForeignItemKind}, *, diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 72a138f907e7..1510a622cdfd 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -21,7 +21,6 @@ use std::ops::ControlFlow; use mir::mono::Instance; use mir::TerminatorKind::*; -use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind}; use stable_mir::*; diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index 07a2a62e0668..3f04abbb9d76 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -20,7 +20,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::mono::{Instance, InstanceKind}; use stable_mir::mir::visit::{Location, MirVisitor}; use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind}; diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index 647ce534589e..bb8c00c64c95 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::*; use std::io::Write; use std::ops::ControlFlow; diff --git a/tests/ui-fulldeps/stable-mir/check_normalization.rs b/tests/ui-fulldeps/stable-mir/check_normalization.rs index de14202adb9c..797cb4cd5d05 100644 --- a/tests/ui-fulldeps/stable-mir/check_normalization.rs +++ b/tests/ui-fulldeps/stable-mir/check_normalization.rs @@ -17,7 +17,6 @@ extern crate stable_mir; use mir::mono::Instance; use ty::{Ty, TyKind, RigidTy}; -use rustc_smir::rustc_internal; use stable_mir::*; use std::io::Write; use std::ops::ControlFlow; diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index 23c2844d3f16..d9170d0c4081 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::CrateDef; use std::collections::HashSet; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index d9fc924933fa..604cc72c3418 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::Instance; use stable_mir::mir::{Body, ConstOperand, Operand, Rvalue, StatementKind, TerminatorKind}; diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index 9d71697178e5..23233f8406cf 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::{ Body, FieldIdx, MirVisitor, Place, ProjectionElem, visit::{Location, PlaceContext}, diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index b8a9e720e546..39416636fd67 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use std::io::Write; /// This test will generate and analyze a dummy crate using the stable mir. diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 4d2d7e26276b..e2086d5e5790 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -18,7 +18,6 @@ extern crate rustc_interface; extern crate stable_mir; use rustc_hir::def::DefKind; -use rustc_smir::rustc_internal; use stable_mir::ItemKind; use stable_mir::crate_def::CrateDef; use stable_mir::mir::mono::Instance; diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index 6f82eba61fce..f3bd894ac690 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -17,7 +17,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::ItemKind; use stable_mir::crate_def::CrateDef; use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind}; diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs index 9b3638a9f2f4..3b3d743ad326 100644 --- a/tests/ui-fulldeps/stable-mir/smir_serde.rs +++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs @@ -19,7 +19,6 @@ extern crate serde_json; extern crate stable_mir; use rustc_middle::ty::TyCtxt; -use rustc_smir::rustc_internal; use serde_json::to_string; use stable_mir::mir::Body; use std::io::{BufWriter, Write}; diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index 0a579a07cef1..d225d9773fe5 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -16,7 +16,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_smir::rustc_internal; use stable_mir::mir::MirVisitor; use stable_mir::mir::MutMirVisitor; use stable_mir::*; From b203d403676472d0e214092bd076909089550055 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Apr 2025 07:55:20 +0800 Subject: [PATCH 102/222] compiletest: add `camino` for UTF-8 path handling --- Cargo.lock | 1 + src/tools/compiletest/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8e35435e3f9b..c80bfef485c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -719,6 +719,7 @@ version = "0.0.0" dependencies = [ "anstyle-svg", "build_helper", + "camino", "colored", "diff", "getopts", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 3db34ed24cc2..ba1b8f256586 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -10,6 +10,7 @@ doctest = false # tidy-alphabetical-start anstyle-svg = "0.1.3" build_helper = { path = "../../build_helper" } +camino = "1" colored = "2" diff = "0.1.10" getopts = "0.2" From e24b0c8e0a9d0b898ede993b62c32d9ebaff27bd Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Apr 2025 07:55:57 +0800 Subject: [PATCH 103/222] compiletest: consistently use `{Utf8Path,Utf8PathBuf}` Since compiletest already assumes UTF-8 paths and does not try to be robust against non-UTF-8 paths. --- src/tools/compiletest/src/common.rs | 71 ++++--- src/tools/compiletest/src/compute_diff.rs | 17 +- src/tools/compiletest/src/debuggers.rs | 27 ++- src/tools/compiletest/src/errors.rs | 6 +- src/tools/compiletest/src/header.rs | 105 +++++----- src/tools/compiletest/src/header/tests.rs | 26 +-- src/tools/compiletest/src/lib.rs | 149 +++++++------- src/tools/compiletest/src/runtest.rs | 188 ++++++++---------- src/tools/compiletest/src/runtest/assembly.rs | 4 +- .../compiletest/src/runtest/codegen_units.rs | 4 +- src/tools/compiletest/src/runtest/coverage.rs | 21 +- src/tools/compiletest/src/runtest/debugger.rs | 19 +- .../compiletest/src/runtest/debuginfo.rs | 51 ++--- src/tools/compiletest/src/runtest/js_doc.rs | 3 +- src/tools/compiletest/src/runtest/mir_opt.rs | 43 ++-- src/tools/compiletest/src/runtest/run_make.rs | 32 +-- src/tools/compiletest/src/runtest/ui.rs | 10 +- src/tools/compiletest/src/tests.rs | 12 +- src/tools/compiletest/src/util.rs | 38 ++-- src/tools/compiletest/src/util/tests.rs | 10 +- 20 files changed, 403 insertions(+), 433 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6750b5288f42..604c5fcbddff 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -1,18 +1,17 @@ use std::collections::{BTreeSet, HashMap, HashSet}; -use std::ffi::OsString; -use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; use std::sync::OnceLock; use std::{fmt, iter}; use build_helper::git::GitConfig; +use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use serde::de::{Deserialize, Deserializer, Error as _}; pub use self::Mode::*; use crate::executor::{ColorConfig, OutputFormat}; -use crate::util::{PathBufExt, add_dylib_path}; +use crate::util::{Utf8PathBufExt, add_dylib_path}; macro_rules! string_enum { ($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => { @@ -183,25 +182,25 @@ pub struct Config { pub fail_fast: bool, /// The library paths required for running the compiler. - pub compile_lib_path: PathBuf, + pub compile_lib_path: Utf8PathBuf, /// The library paths required for running compiled programs. - pub run_lib_path: PathBuf, + pub run_lib_path: Utf8PathBuf, /// The rustc executable. - pub rustc_path: PathBuf, + pub rustc_path: Utf8PathBuf, /// The cargo executable. - pub cargo_path: Option, + pub cargo_path: Option, /// Rustc executable used to compile run-make recipes. - pub stage0_rustc_path: Option, + pub stage0_rustc_path: Option, /// The rustdoc executable. - pub rustdoc_path: Option, + pub rustdoc_path: Option, /// The coverage-dump executable. - pub coverage_dump_path: Option, + pub coverage_dump_path: Option, /// The Python executable to use for LLDB and htmldocck. pub python: String, @@ -213,27 +212,27 @@ pub struct Config { pub jsondoclint_path: Option, /// The LLVM `FileCheck` binary path. - pub llvm_filecheck: Option, + pub llvm_filecheck: Option, /// Path to LLVM's bin directory. - pub llvm_bin_dir: Option, + pub llvm_bin_dir: Option, /// The path to the Clang executable to run Clang-based tests with. If /// `None` then these tests will be ignored. pub run_clang_based_tests_with: Option, /// The directory containing the sources. - pub src_root: PathBuf, + pub src_root: Utf8PathBuf, /// The directory containing the test suite sources. Must be a subdirectory of `src_root`. - pub src_test_suite_root: PathBuf, + pub src_test_suite_root: Utf8PathBuf, /// Root build directory (e.g. `build/`). - pub build_root: PathBuf, + pub build_root: Utf8PathBuf, /// Test suite specific build directory (e.g. `build/host/test/ui/`). - pub build_test_suite_root: PathBuf, + pub build_test_suite_root: Utf8PathBuf, /// The directory containing the compiler sysroot - pub sysroot_base: PathBuf, + pub sysroot_base: Utf8PathBuf, /// The number of the stage under test. pub stage: u32, @@ -301,7 +300,7 @@ pub struct Config { pub host: String, /// Path to / name of the Microsoft Console Debugger (CDB) executable - pub cdb: Option, + pub cdb: Option, /// Version of CDB pub cdb_version: Option<[u16; 4]>, @@ -322,7 +321,7 @@ pub struct Config { pub system_llvm: bool, /// Path to the android tools - pub android_cross_path: PathBuf, + pub android_cross_path: Utf8PathBuf, /// Extra parameter to run adb on arm-linux-androideabi pub adb_path: String, @@ -346,7 +345,7 @@ pub struct Config { pub color: ColorConfig, /// where to find the remote test client process, if we're using it - pub remote_test_client: Option, + pub remote_test_client: Option, /// mode describing what file the actual ui output will be compared to pub compare_mode: Option, @@ -414,7 +413,7 @@ pub struct Config { /// Path to minicore aux library, used for `no_core` tests that need `core` stubs in /// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g. /// ABI tests. - pub minicore_path: PathBuf, + pub minicore_path: Utf8PathBuf, } impl Config { @@ -804,8 +803,8 @@ fn serde_parse_u32<'de, D: Deserializer<'de>>(deserializer: D) -> Result, compare_mode: &Option, kind: &str, -) -> PathBuf { +) -> Utf8PathBuf { assert!(UI_EXTENSIONS.contains(&kind)); let mut parts = Vec::new(); @@ -865,7 +864,7 @@ pub const UI_COVERAGE_MAP: &str = "cov-map"; /// ``` /// /// This is created early when tests are collected to avoid race conditions. -pub fn output_relative_path(config: &Config, relative_dir: &Path) -> PathBuf { +pub fn output_relative_path(config: &Config, relative_dir: &Utf8Path) -> Utf8PathBuf { config.build_test_suite_root.join(relative_dir) } @@ -874,10 +873,10 @@ pub fn output_testname_unique( config: &Config, testpaths: &TestPaths, revision: Option<&str>, -) -> PathBuf { +) -> Utf8PathBuf { let mode = config.compare_mode.as_ref().map_or("", |m| m.to_str()); let debugger = config.debugger.as_ref().map_or("", |m| m.to_str()); - PathBuf::from(&testpaths.file.file_stem().unwrap()) + Utf8PathBuf::from(&testpaths.file.file_stem().unwrap()) .with_extra_extension(config.mode.output_dir_disambiguator()) .with_extra_extension(revision.unwrap_or("")) .with_extra_extension(mode) @@ -887,7 +886,11 @@ pub fn output_testname_unique( /// Absolute path to the directory where all output for the given /// test/revision should reside. Example: /// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/ -pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { +pub fn output_base_dir( + config: &Config, + testpaths: &TestPaths, + revision: Option<&str>, +) -> Utf8PathBuf { output_relative_path(config, &testpaths.relative_dir) .join(output_testname_unique(config, testpaths, revision)) } @@ -895,12 +898,20 @@ pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option< /// Absolute path to the base filename used as output for the given /// test/revision. Example: /// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/testname -pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { +pub fn output_base_name( + config: &Config, + testpaths: &TestPaths, + revision: Option<&str>, +) -> Utf8PathBuf { output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap()) } /// Absolute path to the directory to use for incremental compilation. Example: /// /path/to/build/host-tuple/test/ui/relative/testname.mode/testname.inc -pub fn incremental_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { +pub fn incremental_dir( + config: &Config, + testpaths: &TestPaths, + revision: Option<&str>, +) -> Utf8PathBuf { output_base_name(config, testpaths, revision).with_extension("inc") } diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs index 4c942c51bae1..509e7e117039 100644 --- a/src/tools/compiletest/src/compute_diff.rs +++ b/src/tools/compiletest/src/compute_diff.rs @@ -1,6 +1,7 @@ use std::collections::VecDeque; use std::fs::{File, FileType}; -use std::path::Path; + +use camino::Utf8Path; #[derive(Debug, PartialEq)] pub enum DiffLine { @@ -112,8 +113,8 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S /// Returns whether any data was actually written. pub(crate) fn write_filtered_diff( diff_filename: &str, - out_dir: &Path, - compare_dir: &Path, + out_dir: &Utf8Path, + compare_dir: &Utf8Path, verbose: bool, filter: Filter, ) -> bool @@ -123,19 +124,21 @@ where use std::io::{Read, Write}; let mut diff_output = File::create(diff_filename).unwrap(); let mut wrote_data = false; - for entry in walkdir::WalkDir::new(out_dir) { + for entry in walkdir::WalkDir::new(out_dir.as_std_path()) { let entry = entry.expect("failed to read file"); let extension = entry.path().extension().and_then(|p| p.to_str()); if filter(entry.file_type(), extension) { - let expected_path = compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap()); + let expected_path = compare_dir + .as_std_path() + .join(entry.path().strip_prefix(&out_dir.as_std_path()).unwrap()); let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; let actual_path = entry.path(); let actual = std::fs::read(&actual_path).unwrap(); let diff = unified_diff::diff( &expected, - &expected_path.to_string_lossy(), + &expected_path.to_str().unwrap(), &actual, - &actual_path.to_string_lossy(), + &actual_path.to_str().unwrap(), 3, ); wrote_data |= !diff.is_empty(); diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index 5126e55aea12..c133d7fd4fbd 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -1,9 +1,9 @@ use std::env; -use std::ffi::OsString; -use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::Arc; +use camino::{Utf8Path, Utf8PathBuf}; + use crate::common::{Config, Debugger}; pub(crate) fn configure_cdb(config: &Config) -> Option> { @@ -78,12 +78,15 @@ fn is_pc_windows_msvc_target(target: &str) -> bool { target.ends_with("-pc-windows-msvc") } -fn find_cdb(target: &str) -> Option { +fn find_cdb(target: &str) -> Option { if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { return None; } - let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?; + let pf86 = Utf8PathBuf::from_path_buf( + env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?.into(), + ) + .unwrap(); let cdb_arch = if cfg!(target_arch = "x86") { "x86" } else if cfg!(target_arch = "x86_64") { @@ -96,8 +99,7 @@ fn find_cdb(target: &str) -> Option { return None; // No compatible CDB.exe in the Windows 10 SDK }; - let mut path = PathBuf::new(); - path.push(pf86); + let mut path = pf86; path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? path.push(cdb_arch); path.push(r"cdb.exe"); @@ -106,15 +108,15 @@ fn find_cdb(target: &str) -> Option { return None; } - Some(path.into_os_string()) + Some(path) } /// Returns Path to CDB pub(crate) fn analyze_cdb( cdb: Option, target: &str, -) -> (Option, Option<[u16; 4]>) { - let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); +) -> (Option, Option<[u16; 4]>) { + let cdb = cdb.map(Utf8PathBuf::from).or_else(|| find_cdb(target)); let mut version = None; if let Some(cdb) = cdb.as_ref() { @@ -143,7 +145,7 @@ pub(crate) fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { pub(crate) fn analyze_gdb( gdb: Option, target: &str, - android_cross_path: &Path, + android_cross_path: &Utf8Path, ) -> (Option, Option) { #[cfg(not(windows))] const GDB_FALLBACK: &str = "gdb"; @@ -152,10 +154,7 @@ pub(crate) fn analyze_gdb( let fallback_gdb = || { if is_android_gdb_target(target) { - let mut gdb_path = match android_cross_path.to_str() { - Some(x) => x.to_owned(), - None => panic!("cannot find android cross path"), - }; + let mut gdb_path = android_cross_path.to_string(); gdb_path.push_str("/bin/gdb"); gdb_path } else { diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 64d68eb7f23e..3bb98276bf52 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -2,9 +2,9 @@ use std::fmt; use std::fs::File; use std::io::BufReader; use std::io::prelude::*; -use std::path::Path; use std::sync::OnceLock; +use camino::Utf8Path; use regex::Regex; use tracing::*; @@ -102,8 +102,8 @@ impl Error { /// /// If revision is not None, then we look /// for `//[X]~` instead, where `X` is the current revision. -pub fn load_errors(testfile: &Path, revision: Option<&str>) -> Vec { - let rdr = BufReader::new(File::open(testfile).unwrap()); +pub fn load_errors(testfile: &Utf8Path, revision: Option<&str>) -> Vec { + let rdr = BufReader::new(File::open(testfile.as_std_path()).unwrap()); // `last_nonfollow_error` tracks the most recently seen // line with an error template that did not use the diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 3406e8749a15..33ecdec49917 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -3,9 +3,9 @@ use std::env; use std::fs::File; use std::io::BufReader; use std::io::prelude::*; -use std::path::{Path, PathBuf}; use std::process::Command; +use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use tracing::*; @@ -45,12 +45,12 @@ pub struct EarlyProps { } impl EarlyProps { - pub fn from_file(config: &Config, testfile: &Path) -> Self { - let file = File::open(testfile).expect("open test file to parse earlyprops"); + pub fn from_file(config: &Config, testfile: &Utf8Path) -> Self { + let file = File::open(testfile.as_std_path()).expect("open test file to parse earlyprops"); Self::from_reader(config, testfile, file) } - pub fn from_reader(config: &Config, testfile: &Path, rdr: R) -> Self { + pub fn from_reader(config: &Config, testfile: &Utf8Path, rdr: R) -> Self { let mut props = EarlyProps::default(); let mut poisoned = false; iter_header( @@ -66,7 +66,7 @@ impl EarlyProps { ); if poisoned { - eprintln!("errors encountered during EarlyProps parsing: {}", testfile.display()); + eprintln!("errors encountered during EarlyProps parsing: {}", testfile); panic!("errors encountered during EarlyProps parsing"); } @@ -88,7 +88,7 @@ pub struct TestProps { pub doc_flags: Vec, // If present, the name of a file that this test should match when // pretty-printed - pub pp_exact: Option, + pub pp_exact: Option, /// Auxiliary crates that should be built and made available to this test. pub(crate) aux: AuxProps, // Environment settings to use for compiling @@ -134,7 +134,7 @@ pub struct TestProps { // not set by end-users; rather it is set by the incremental // testing harness and used when generating compilation // arguments. (In particular, it propagates to the aux-builds.) - pub incremental_dir: Option, + pub incremental_dir: Option, // If `true`, this test will use incremental compilation. // // This can be set manually with the `incremental` header, or implicitly @@ -311,7 +311,12 @@ impl TestProps { } } - pub fn from_aux_file(&self, testfile: &Path, revision: Option<&str>, config: &Config) -> Self { + pub fn from_aux_file( + &self, + testfile: &Utf8Path, + revision: Option<&str>, + config: &Config, + ) -> Self { let mut props = TestProps::new(); // copy over select properties to the aux build: @@ -322,10 +327,10 @@ impl TestProps { props } - pub fn from_file(testfile: &Path, revision: Option<&str>, config: &Config) -> Self { + pub fn from_file(testfile: &Utf8Path, revision: Option<&str>, config: &Config) -> Self { let mut props = TestProps::new(); props.load_from(testfile, revision, config); - props.exec_env.push(("RUSTC".to_string(), config.rustc_path.display().to_string())); + props.exec_env.push(("RUSTC".to_string(), config.rustc_path.to_string())); match (props.pass_mode, props.fail_mode) { (None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check), @@ -340,10 +345,10 @@ impl TestProps { /// tied to a particular revision `foo` (indicated by writing /// `//@[foo]`), then the property is ignored unless `test_revision` is /// `Some("foo")`. - fn load_from(&mut self, testfile: &Path, test_revision: Option<&str>, config: &Config) { + fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config: &Config) { let mut has_edition = false; if !testfile.is_dir() { - let file = File::open(testfile).unwrap(); + let file = File::open(testfile.as_std_path()).unwrap(); let mut poisoned = false; @@ -600,7 +605,7 @@ impl TestProps { ); if poisoned { - eprintln!("errors encountered during TestProps parsing: {}", testfile.display()); + eprintln!("errors encountered during TestProps parsing: {}", testfile); panic!("errors encountered during TestProps parsing"); } } @@ -871,7 +876,7 @@ fn iter_header( mode: Mode, _suite: &str, poisoned: &mut bool, - testfile: &Path, + testfile: &Utf8Path, rdr: impl Read, it: &mut dyn FnMut(DirectiveLine<'_>), ) { @@ -923,9 +928,7 @@ fn iter_header( eprintln!( "error: detected unknown compiletest test directive `{}` in {}:{}", - directive_line.raw_directive, - testfile.display(), - line_number, + directive_line.raw_directive, testfile, line_number, ); return; @@ -937,10 +940,7 @@ fn iter_header( eprintln!( "error: detected trailing compiletest test directive `{}` in {}:{}\n \ help: put the trailing directive in it's own line: `//@ {}`", - trailing_directive, - testfile.display(), - line_number, - trailing_directive, + trailing_directive, testfile, line_number, trailing_directive, ); return; @@ -952,7 +952,12 @@ fn iter_header( } impl Config { - fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec) { + fn parse_and_update_revisions( + &self, + testfile: &Utf8Path, + line: &str, + existing: &mut Vec, + ) { const FORBIDDEN_REVISION_NAMES: [&str; 2] = [ // `//@ revisions: true false` Implying `--cfg=true` and `--cfg=false` makes it very // weird for the test, since if the test writer wants a cfg of the same revision name @@ -965,26 +970,19 @@ impl Config { if let Some(raw) = self.parse_name_value_directive(line, "revisions") { if self.mode == Mode::RunMake { - panic!("`run-make` tests do not support revisions: {}", testfile.display()); + panic!("`run-make` tests do not support revisions: {}", testfile); } let mut duplicates: HashSet<_> = existing.iter().cloned().collect(); for revision in raw.split_whitespace() { if !duplicates.insert(revision.to_string()) { - panic!( - "duplicate revision: `{}` in line `{}`: {}", - revision, - raw, - testfile.display() - ); + panic!("duplicate revision: `{}` in line `{}`: {}", revision, raw, testfile); } if FORBIDDEN_REVISION_NAMES.contains(&revision) { panic!( "revision name `{revision}` is not permitted: `{}` in line `{}`: {}", - revision, - raw, - testfile.display() + revision, raw, testfile ); } @@ -995,8 +993,7 @@ impl Config { "revision name `{revision}` is not permitted in a test suite that uses \ `FileCheck` annotations as it is confusing when used as custom `FileCheck` \ prefix: `{revision}` in line `{}`: {}", - raw, - testfile.display() + raw, testfile ); } @@ -1016,11 +1013,11 @@ impl Config { (name.to_owned(), value.to_owned()) } - fn parse_pp_exact(&self, line: &str, testfile: &Path) -> Option { + fn parse_pp_exact(&self, line: &str, testfile: &Utf8Path) -> Option { if let Some(s) = self.parse_name_value_directive(line, "pp-exact") { - Some(PathBuf::from(&s)) + Some(Utf8PathBuf::from(&s)) } else if self.parse_name_directive(line, "pp-exact") { - testfile.file_name().map(PathBuf::from) + testfile.file_name().map(Utf8PathBuf::from) } else { None } @@ -1126,20 +1123,19 @@ fn expand_variables(mut value: String, config: &Config) -> String { if value.contains(CWD) { let cwd = env::current_dir().unwrap(); - value = value.replace(CWD, &cwd.to_string_lossy()); + value = value.replace(CWD, &cwd.to_str().unwrap()); } if value.contains(SRC_BASE) { - value = value.replace(SRC_BASE, &config.src_test_suite_root.to_str().unwrap()); + value = value.replace(SRC_BASE, &config.src_test_suite_root.as_str()); } if value.contains(TEST_SUITE_BUILD_BASE) { - value = - value.replace(TEST_SUITE_BUILD_BASE, &config.build_test_suite_root.to_str().unwrap()); + value = value.replace(TEST_SUITE_BUILD_BASE, &config.build_test_suite_root.as_str()); } if value.contains(SYSROOT_BASE) { - value = value.replace(SYSROOT_BASE, &config.sysroot_base.to_str().unwrap()); + value = value.replace(SYSROOT_BASE, &config.sysroot_base.as_str()); } if value.contains(TARGET_LINKER) { @@ -1152,9 +1148,9 @@ fn expand_variables(mut value: String, config: &Config) -> String { if value.contains(RUST_SRC_BASE) { let src_base = config.sysroot_base.join("lib/rustlib/src/rust"); - src_base.try_exists().expect(&*format!("{} should exists", src_base.display())); - let src_base = src_base.read_link().unwrap_or(src_base); - value = value.replace(RUST_SRC_BASE, &src_base.to_string_lossy()); + src_base.try_exists().expect(&*format!("{} should exists", src_base)); + let src_base = src_base.read_link_utf8().unwrap_or(src_base); + value = value.replace(RUST_SRC_BASE, &src_base.as_str()); } value @@ -1257,14 +1253,14 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { // contains a path to that static lib, and that it exists. // // See compiler/rustc_llvm/build.rs for more details and similar expectations. - fn is_zstd_in_config(llvm_bin_dir: &Path) -> Option<()> { + fn is_zstd_in_config(llvm_bin_dir: &Utf8Path) -> Option<()> { let llvm_config_path = llvm_bin_dir.join("llvm-config"); let output = Command::new(llvm_config_path).arg("--system-libs").output().ok()?; assert!(output.status.success(), "running llvm-config --system-libs failed"); let libs = String::from_utf8(output.stdout).ok()?; for lib in libs.split_whitespace() { - if lib.ends_with("libzstd.a") && Path::new(lib).exists() { + if lib.ends_with("libzstd.a") && Utf8Path::new(lib).exists() { return Some(()); } } @@ -1282,7 +1278,7 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { // `lld` supports it. If not, an error will be emitted: "LLVM was not built with // LLVM_ENABLE_ZSTD or did not find zstd at build time". #[cfg(unix)] - fn is_lld_built_with_zstd(llvm_bin_dir: &Path) -> Option<()> { + fn is_lld_built_with_zstd(llvm_bin_dir: &Utf8Path) -> Option<()> { let lld_path = llvm_bin_dir.join("lld"); if lld_path.exists() { // We can't call `lld` as-is, it expects to be invoked by a compiler driver using a @@ -1318,7 +1314,7 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { } #[cfg(not(unix))] - fn is_lld_built_with_zstd(_llvm_bin_dir: &Path) -> Option<()> { + fn is_lld_built_with_zstd(_llvm_bin_dir: &Utf8Path) -> Option<()> { None } @@ -1385,7 +1381,7 @@ pub(crate) fn make_test_description( config: &Config, cache: &HeadersCache, name: String, - path: &Path, + path: &Utf8Path, src: R, test_revision: Option<&str>, poisoned: &mut bool, @@ -1416,7 +1412,7 @@ pub(crate) fn make_test_description( ignore_message = Some(reason.into()); } IgnoreDecision::Error { message } => { - eprintln!("error: {}:{line_number}: {message}", path.display()); + eprintln!("error: {}:{line_number}: {message}", path); *poisoned = true; return; } @@ -1446,7 +1442,7 @@ pub(crate) fn make_test_description( ); if local_poisoned { - eprintln!("errors encountered when trying to make test description: {}", path.display()); + eprintln!("errors encountered when trying to make test description: {}", path); panic!("errors encountered when trying to make test description"); } @@ -1555,7 +1551,7 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision { +fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { if let Some(needed_components) = config.parse_name_value_directive(line, "needs-llvm-components") { @@ -1567,8 +1563,7 @@ fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision { if env::var_os("COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS").is_some() { panic!( "missing LLVM component {}, and COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS is set: {}", - missing_component, - path.display() + missing_component, path ); } return IgnoreDecision::Ignore { diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index f3461f3c244f..3a8c3748de99 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -1,6 +1,6 @@ use std::io::Read; -use std::path::Path; +use camino::Utf8Path; use semver::Version; use super::{ @@ -13,7 +13,7 @@ use crate::executor::{CollectedTestDesc, ShouldPanic}; fn make_test_description( config: &Config, name: String, - path: &Path, + path: &Utf8Path, src: R, revision: Option<&str>, ) -> CollectedTestDesc { @@ -230,12 +230,12 @@ fn cfg() -> ConfigBuilder { fn parse_rs(config: &Config, contents: &str) -> EarlyProps { let bytes = contents.as_bytes(); - EarlyProps::from_reader(config, Path::new("a.rs"), bytes) + EarlyProps::from_reader(config, Utf8Path::new("a.rs"), bytes) } fn check_ignore(config: &Config, contents: &str) -> bool { let tn = String::new(); - let p = Path::new("a.rs"); + let p = Utf8Path::new("a.rs"); let d = make_test_description(&config, tn, p, std::io::Cursor::new(contents), None); d.ignore } @@ -244,7 +244,7 @@ fn check_ignore(config: &Config, contents: &str) -> bool { fn should_fail() { let config: Config = cfg().build(); let tn = String::new(); - let p = Path::new("a.rs"); + let p = Utf8Path::new("a.rs"); let d = make_test_description(&config, tn.clone(), p, std::io::Cursor::new(""), None); assert_eq!(d.should_panic, ShouldPanic::No); @@ -784,7 +784,7 @@ fn threads_support() { } } -fn run_path(poisoned: &mut bool, path: &Path, buf: &[u8]) { +fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) { let rdr = std::io::Cursor::new(&buf); iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {}); } @@ -794,7 +794,7 @@ fn test_unknown_directive_check() { let mut poisoned = false; run_path( &mut poisoned, - Path::new("a.rs"), + Utf8Path::new("a.rs"), include_bytes!("./test-auxillary/unknown_directive.rs"), ); assert!(poisoned); @@ -805,7 +805,7 @@ fn test_known_directive_check_no_error() { let mut poisoned = false; run_path( &mut poisoned, - Path::new("a.rs"), + Utf8Path::new("a.rs"), include_bytes!("./test-auxillary/known_directive.rs"), ); assert!(!poisoned); @@ -816,7 +816,7 @@ fn test_error_annotation_no_error() { let mut poisoned = false; run_path( &mut poisoned, - Path::new("a.rs"), + Utf8Path::new("a.rs"), include_bytes!("./test-auxillary/error_annotation.rs"), ); assert!(!poisoned); @@ -827,7 +827,7 @@ fn test_non_rs_unknown_directive_not_checked() { let mut poisoned = false; run_path( &mut poisoned, - Path::new("a.Makefile"), + Utf8Path::new("a.Makefile"), include_bytes!("./test-auxillary/not_rs.Makefile"), ); assert!(!poisoned); @@ -836,21 +836,21 @@ fn test_non_rs_unknown_directive_not_checked() { #[test] fn test_trailing_directive() { let mut poisoned = false; - run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm"); + run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86 only-arm"); assert!(poisoned); } #[test] fn test_trailing_directive_with_comment() { let mut poisoned = false; - run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm with comment"); + run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86 only-arm with comment"); assert!(poisoned); } #[test] fn test_not_trailing_directive() { let mut poisoned = false; - run_path(&mut poisoned, Path::new("a.rs"), b"//@ revisions: incremental"); + run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ revisions: incremental"); assert!(!poisoned); } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 720663b30ef4..b969b22750bc 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -22,16 +22,15 @@ pub mod util; use core::panic; use std::collections::HashSet; -use std::ffi::OsString; use std::fmt::Write; use std::io::{self, ErrorKind}; -use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::sync::{Arc, OnceLock}; use std::time::SystemTime; use std::{env, fs, vec}; use build_helper::git::{get_git_modified_files, get_git_untracked_files}; +use camino::{Utf8Path, Utf8PathBuf}; use getopts::Options; use tracing::*; use walkdir::WalkDir; @@ -230,15 +229,19 @@ pub fn parse_config(args: Vec) -> Config { panic!() } - fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf { - match m.opt_str(nm) { - Some(s) => PathBuf::from(&s), - None => panic!("no option (=path) found for {}", nm), + fn make_absolute(path: Utf8PathBuf) -> Utf8PathBuf { + if path.is_relative() { + Utf8PathBuf::try_from(env::current_dir().unwrap()).unwrap().join(path) + } else { + path } } - fn make_absolute(path: PathBuf) -> PathBuf { - if path.is_relative() { env::current_dir().unwrap().join(path) } else { path } + fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { + match m.opt_str(nm) { + Some(s) => Utf8PathBuf::from(&s), + None => panic!("no option (=path) found for {}", nm), + } } let target = opt_str2(matches.opt_str("target")); @@ -279,12 +282,12 @@ pub fn parse_config(args: Vec) -> Config { .free .iter() .map(|f| { - let path = Path::new(f); + let path = Utf8Path::new(f); let mut iter = path.iter().skip(1); // We skip the test folder and check if the user passed `rmake.rs`. if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() { - path.parent().unwrap().to_str().unwrap().to_string() + path.parent().unwrap().to_string() } else { f.to_string() } @@ -316,8 +319,8 @@ pub fn parse_config(args: Vec) -> Config { assert!( src_test_suite_root.starts_with(&src_root), "`src-root` must be a parent of `src-test-suite-root`: `src-root`=`{}`, `src-test-suite-root` = `{}`", - src_root.display(), - src_test_suite_root.display() + src_root, + src_test_suite_root ); let build_root = opt_path(matches, "build-root"); @@ -332,16 +335,16 @@ pub fn parse_config(args: Vec) -> Config { compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), rustc_path: opt_path(matches, "rustc-path"), - cargo_path: matches.opt_str("cargo-path").map(PathBuf::from), - stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(PathBuf::from), - rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), - coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from), + cargo_path: matches.opt_str("cargo-path").map(Utf8PathBuf::from), + stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(Utf8PathBuf::from), + rustdoc_path: matches.opt_str("rustdoc-path").map(Utf8PathBuf::from), + coverage_dump_path: matches.opt_str("coverage-dump-path").map(Utf8PathBuf::from), python: matches.opt_str("python").unwrap(), jsondocck_path: matches.opt_str("jsondocck-path"), jsondoclint_path: matches.opt_str("jsondoclint-path"), run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), - llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), - llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), + llvm_filecheck: matches.opt_str("llvm-filecheck").map(Utf8PathBuf::from), + llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(Utf8PathBuf::from), src_root, src_test_suite_root, @@ -407,7 +410,7 @@ pub fn parse_config(args: Vec) -> Config { }, only_modified: matches.opt_present("only-modified"), color, - remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), + remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from), compare_mode, rustfix_coverage: matches.opt_present("rustfix-coverage"), has_html_tidy, @@ -450,19 +453,19 @@ pub fn parse_config(args: Vec) -> Config { pub fn log_config(config: &Config) { let c = config; logv(c, "configuration:".to_string()); - logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); - logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); - logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); + logv(c, format!("compile_lib_path: {}", config.compile_lib_path)); + logv(c, format!("run_lib_path: {}", config.run_lib_path)); + logv(c, format!("rustc_path: {}", config.rustc_path)); logv(c, format!("cargo_path: {:?}", config.cargo_path)); logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); - logv(c, format!("src_root: {}", config.src_root.display())); - logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root.display())); + logv(c, format!("src_root: {}", config.src_root)); + logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root)); - logv(c, format!("build_root: {}", config.build_root.display())); - logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root.display())); + logv(c, format!("build_root: {}", config.build_root)); + logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root)); - logv(c, format!("sysroot_base: {}", config.sysroot_base.display())); + logv(c, format!("sysroot_base: {}", config.sysroot_base)); logv(c, format!("stage: {}", config.stage)); logv(c, format!("stage_id: {}", config.stage_id)); @@ -480,16 +483,16 @@ pub fn log_config(config: &Config) { logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); logv(c, format!("target: {}", config.target)); logv(c, format!("host: {}", config.host)); - logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display())); - logv(c, format!("adb_path: {:?}", config.adb_path)); - logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); + logv(c, format!("android-cross-path: {}", config.android_cross_path)); + logv(c, format!("adb_path: {}", config.adb_path)); + logv(c, format!("adb_test_dir: {}", config.adb_test_dir)); logv(c, format!("adb_device_status: {}", config.adb_device_status)); logv(c, format!("ar: {}", config.ar)); logv(c, format!("target-linker: {:?}", config.target_linker)); logv(c, format!("host-linker: {:?}", config.host_linker)); logv(c, format!("verbose: {}", config.verbose)); logv(c, format!("format: {:?}", config.format)); - logv(c, format!("minicore_path: {:?}", config.minicore_path.display())); + logv(c, format!("minicore_path: {}", config.minicore_path)); logv(c, "\n".to_string()); } @@ -517,7 +520,7 @@ pub fn run_tests(config: Arc) { coverage_file_path.push("rustfix_missing_coverage.txt"); if coverage_file_path.exists() { if let Err(e) = fs::remove_file(&coverage_file_path) { - panic!("Could not delete {} due to {}", coverage_file_path.display(), e) + panic!("Could not delete {} due to {}", coverage_file_path, e) } } } @@ -619,13 +622,13 @@ struct TestCollectorCx { config: Arc, cache: HeadersCache, common_inputs_stamp: Stamp, - modified_tests: Vec, + modified_tests: Vec, } /// Mutable state used during test collection. struct TestCollector { tests: Vec, - found_path_stems: HashSet, + found_path_stems: HashSet, poisoned: bool, } @@ -635,14 +638,13 @@ struct TestCollector { /// regardless of whether any filters/tests were specified on the command-line, /// because filtering is handled later by libtest. pub(crate) fn collect_and_make_tests(config: Arc) -> Vec { - debug!("making tests from {}", config.src_test_suite_root.display()); + debug!("making tests from {}", config.src_test_suite_root); let common_inputs_stamp = common_inputs_stamp(&config); let modified_tests = modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| { panic!( "modified_tests got error from dir: {}, error: {}", - config.src_test_suite_root.display(), - err + config.src_test_suite_root, err ) }); let cache = HeadersCache::load(&config); @@ -651,12 +653,9 @@ pub(crate) fn collect_and_make_tests(config: Arc) -> Vec let mut collector = TestCollector { tests: vec![], found_path_stems: HashSet::new(), poisoned: false }; - collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Path::new("")) + collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Utf8Path::new("")) .unwrap_or_else(|reason| { - panic!( - "Could not read tests from {}: {reason}", - cx.config.src_test_suite_root.display() - ) + panic!("Could not read tests from {}: {reason}", cx.config.src_test_suite_root) }); let TestCollector { tests, found_path_stems, poisoned } = collector; @@ -725,24 +724,29 @@ fn common_inputs_stamp(config: &Config) -> Stamp { /// the `--only-modified` flag is in use. /// /// (Might be inaccurate in some cases.) -fn modified_tests(config: &Config, dir: &Path) -> Result, String> { +fn modified_tests(config: &Config, dir: &Utf8Path) -> Result, String> { // If `--only-modified` wasn't passed, the list of modified tests won't be // used for anything, so avoid some work and just return an empty list. if !config.only_modified { return Ok(vec![]); } - let files = - get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])?; + let files = get_git_modified_files( + &config.git_config(), + Some(dir.as_std_path()), + &vec!["rs", "stderr", "fixed"], + )?; // Add new test cases to the list, it will be convenient in daily development. let untracked_files = get_git_untracked_files(&config.git_config(), None)?.unwrap_or(vec![]); let all_paths = [&files[..], &untracked_files[..]].concat(); let full_paths = { - let mut full_paths: Vec = all_paths + let mut full_paths: Vec = all_paths .into_iter() - .map(|f| PathBuf::from(f).with_extension("").with_extension("rs")) - .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None }) + .map(|f| Utf8PathBuf::from(f).with_extension("").with_extension("rs")) + .filter_map( + |f| if Utf8Path::new(&f).exists() { f.canonicalize_utf8().ok() } else { None }, + ) .collect(); full_paths.dedup(); full_paths.sort_unstable(); @@ -756,8 +760,8 @@ fn modified_tests(config: &Config, dir: &Path) -> Result, String> { fn collect_tests_from_dir( cx: &TestCollectorCx, collector: &mut TestCollector, - dir: &Path, - relative_dir_path: &Path, + dir: &Utf8Path, + relative_dir_path: &Utf8Path, ) -> io::Result<()> { // Ignore directories that contain a file named `compiletest-ignore-dir`. if dir.join("compiletest-ignore-dir").exists() { @@ -790,16 +794,16 @@ fn collect_tests_from_dir( // subdirectories we find, except for `auxiliary` directories. // FIXME: this walks full tests tree, even if we have something to ignore // use walkdir/ignore like in tidy? - for file in fs::read_dir(dir)? { + for file in fs::read_dir(dir.as_std_path())? { let file = file?; - let file_path = file.path(); - let file_name = file.file_name(); + let file_path = Utf8PathBuf::try_from(file.path()).unwrap(); + let file_name = file_path.file_name().unwrap(); - if is_test(&file_name) + if is_test(file_name) && (!cx.config.only_modified || cx.modified_tests.contains(&file_path)) { // We found a test file, so create the corresponding libtest structures. - debug!("found test file: {:?}", file_path.display()); + debug!(%file_path, "found test file"); // Record the stem of the test file, to check for overlaps later. let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap()); @@ -810,22 +814,20 @@ fn collect_tests_from_dir( make_test(cx, collector, &paths); } else if file_path.is_dir() { // Recurse to find more tests in a subdirectory. - let relative_file_path = relative_dir_path.join(file.file_name()); - if &file_name != "auxiliary" { - debug!("found directory: {:?}", file_path.display()); + let relative_file_path = relative_dir_path.join(file_name); + if file_name != "auxiliary" { + debug!(%file_path, "found directory"); collect_tests_from_dir(cx, collector, &file_path, &relative_file_path)?; } } else { - debug!("found other file/directory: {:?}", file_path.display()); + debug!(%file_path, "found other file/directory"); } } Ok(()) } /// Returns true if `file_name` looks like a proper test file name. -pub fn is_test(file_name: &OsString) -> bool { - let file_name = file_name.to_str().unwrap(); - +pub fn is_test(file_name: &str) -> bool { if !file_name.ends_with(".rs") { return false; } @@ -844,7 +846,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te let test_path = if cx.config.mode == Mode::RunMake { testpaths.file.join("rmake.rs") } else { - PathBuf::from(&testpaths.file) + testpaths.file.clone() }; // Scan the test file to discover its revisions, if any. @@ -899,7 +901,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te /// The path of the `stamp` file that gets created or updated whenever a /// particular test completes successfully. -fn stamp_file_path(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { +fn stamp_file_path(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> Utf8PathBuf { output_base_dir(config, testpaths, revision).join("stamp") } @@ -912,7 +914,7 @@ fn files_related_to_test( testpaths: &TestPaths, props: &EarlyProps, revision: Option<&str>, -) -> Vec { +) -> Vec { let mut related = vec![]; if testpaths.file.is_dir() { @@ -920,7 +922,7 @@ fn files_related_to_test( for entry in WalkDir::new(&testpaths.file) { let path = entry.unwrap().into_path(); if path.is_file() { - related.push(path); + related.push(Utf8PathBuf::try_from(path).unwrap()); } } } else { @@ -991,7 +993,7 @@ struct Stamp { impl Stamp { /// Creates a timestamp holding the last-modified time of the specified file. - fn from_path(path: &Path) -> Self { + fn from_path(path: &Utf8Path) -> Self { let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH }; stamp.add_path(path); stamp @@ -999,8 +1001,8 @@ impl Stamp { /// Updates this timestamp to the last-modified time of the specified file, /// if it is later than the currently-stored timestamp. - fn add_path(&mut self, path: &Path) { - let modified = fs::metadata(path) + fn add_path(&mut self, path: &Utf8Path) { + let modified = fs::metadata(path.as_std_path()) .and_then(|metadata| metadata.modified()) .unwrap_or(SystemTime::UNIX_EPOCH); self.time = self.time.max(modified); @@ -1009,7 +1011,8 @@ impl Stamp { /// Updates this timestamp to the most recent last-modified time of all files /// recursively contained in the given directory, if it is later than the /// currently-stored timestamp. - fn add_dir(&mut self, path: &Path) { + fn add_dir(&mut self, path: &Utf8Path) { + let path = path.as_std_path(); for entry in WalkDir::new(path) { let entry = entry.unwrap(); if entry.file_type().is_file() { @@ -1042,7 +1045,7 @@ fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str> config.mode, debugger, mode_suffix, - path.display(), + path, revision.map_or("".to_string(), |rev| format!("#{}", rev)) ) } @@ -1064,7 +1067,7 @@ fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str> /// To avoid problems, we forbid test names from overlapping in this way. /// /// See for more context. -fn check_for_overlapping_test_paths(found_path_stems: &HashSet) { +fn check_for_overlapping_test_paths(found_path_stems: &HashSet) { let mut collisions = Vec::new(); for path in found_path_stems { for ancestor in path.ancestors().skip(1) { @@ -1077,7 +1080,7 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet) { collisions.sort(); let collisions: String = collisions .into_iter() - .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n")) + .map(|(path, check_parent)| format!("test {path} clashes with {check_parent}\n")) .collect(); panic!( "{collisions}\n\ diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 208d32833c9c..722ba66e9541 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1,15 +1,15 @@ use std::borrow::Cow; use std::collections::{HashMap, HashSet}; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsString; use std::fs::{self, File, create_dir_all}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::io::prelude::*; use std::io::{self, BufReader}; -use std::path::{Path, PathBuf}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::sync::Arc; use std::{env, iter, str}; +use camino::{Utf8Path, Utf8PathBuf}; use colored::Colorize; use regex::{Captures, Regex}; use tracing::*; @@ -25,7 +25,7 @@ use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::read2::{Truncated, read2_abbreviated}; -use crate::util::{PathBufExt, add_dylib_path, logv, static_regex}; +use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex}; use crate::{ColorConfig, json, stamp_file_path}; mod debugger; @@ -131,7 +131,7 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) { // We're going to be dumping a lot of info. Start on a new line. print!("\n\n"); } - debug!("running {:?}", testpaths.file.display()); + debug!("running {}", testpaths.file); let mut props = TestProps::from_file(&testpaths.file, revision, &config); // For non-incremental (i.e. regular UI) tests, the incremental directory @@ -144,7 +144,7 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) { let cx = TestCx { config: &config, props: &props, testpaths, revision }; if let Err(e) = create_dir_all(&cx.output_base_dir()) { - panic!("failed to create output base directory {}: {e}", cx.output_base_dir().display()); + panic!("failed to create output base directory {}: {e}", cx.output_base_dir()); } if props.incremental { @@ -207,7 +207,8 @@ pub fn compute_stamp_hash(config: &Config) -> String { format!("{:x}", hash.finish()) } -fn remove_and_create_dir_all(path: &Path) { +fn remove_and_create_dir_all(path: &Utf8Path) { + let path = path.as_std_path(); let _ = fs::remove_dir_all(path); fs::create_dir_all(path).unwrap(); } @@ -423,7 +424,7 @@ impl<'test> TestCx<'test> { let aux_dir = self.aux_output_dir_name(); let input: &str = match read_from { ReadFrom::Stdin(_) => "-", - ReadFrom::Path => self.testpaths.file.to_str().unwrap(), + ReadFrom::Path => self.testpaths.file.as_str(), }; let mut rustc = Command::new(&self.config.rustc_path); @@ -590,10 +591,7 @@ impl<'test> TestCx<'test> { // FIXME(#65865) return; } else { - self.fatal(&format!( - "no error pattern specified in {:?}", - self.testpaths.file.display() - )); + self.fatal(&format!("no error pattern specified in {}", self.testpaths.file)); } } @@ -697,17 +695,17 @@ impl<'test> TestCx<'test> { } // On Windows, translate all '\' path separators to '/' - let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/"); + let file_name = self.testpaths.file.to_string().replace(r"\", "/"); // On Windows, keep all '\' path separators to match the paths reported in the JSON output // from the compiler let diagnostic_file_name = if self.props.remap_src_base { - let mut p = PathBuf::from(FAKE_SRC_BASE); + let mut p = Utf8PathBuf::from(FAKE_SRC_BASE); p.push(&self.testpaths.relative_dir); p.push(self.testpaths.file.file_name().unwrap()); - p.display().to_string() + p.to_string() } else { - self.testpaths.file.display().to_string() + self.testpaths.file.to_string() }; let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help)); @@ -887,7 +885,7 @@ impl<'test> TestCx<'test> { /// `root_out_dir` and `root_testpaths` refer to the parameters of the actual test being run. /// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths. - fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes { + fn document(&self, root_out_dir: &Utf8Path, root_testpaths: &TestPaths) -> ProcRes { if self.props.build_aux_docs { for rel_ab in &self.props.aux.builds { let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab); @@ -916,13 +914,13 @@ impl<'test> TestCx<'test> { // actual --out-dir given to the auxiliary or test, as opposed to the root out dir for the entire // test - let out_dir: Cow<'_, Path> = if self.props.unique_doc_out_dir { + let out_dir: Cow<'_, Utf8Path> = if self.props.unique_doc_out_dir { let file_name = self.testpaths.file.file_stem().expect("file name should not be empty"); - let out_dir = PathBuf::from_iter([ + let out_dir = Utf8PathBuf::from_iter([ root_out_dir, - Path::new("docs"), - Path::new(file_name), - Path::new("doc"), + Utf8Path::new("docs"), + Utf8Path::new(file_name), + Utf8Path::new("doc"), ]); create_dir_all(&out_dir).unwrap(); Cow::Owned(out_dir) @@ -935,7 +933,7 @@ impl<'test> TestCx<'test> { rustdoc.current_dir(current_dir); rustdoc .arg("-L") - .arg(self.config.run_lib_path.to_str().unwrap()) + .arg(self.config.run_lib_path.as_path()) .arg("-L") .arg(aux_dir) .arg("-o") @@ -1073,7 +1071,7 @@ impl<'test> TestCx<'test> { let test_ab = of.file.parent().expect("test file path has no parent").join("auxiliary").join(rel_ab); if !test_ab.exists() { - self.fatal(&format!("aux-build `{}` source not found", test_ab.display())) + self.fatal(&format!("aux-build `{}` source not found", test_ab)) } TestPaths { @@ -1110,7 +1108,7 @@ impl<'test> TestCx<'test> { || !self.props.aux.proc_macros.is_empty() } - fn aux_output_dir(&self) -> PathBuf { + fn aux_output_dir(&self) -> Utf8PathBuf { let aux_dir = self.aux_output_dir_name(); if !self.props.aux.builds.is_empty() { @@ -1126,7 +1124,7 @@ impl<'test> TestCx<'test> { aux_dir } - fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) { + fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Utf8Path, rustc: &mut Command) { for rel_ab in &self.props.aux.builds { self.build_auxiliary(of, rel_ab, &aux_dir, None); } @@ -1146,12 +1144,7 @@ impl<'test> TestCx<'test> { |rustc: &mut Command, aux_name: &str, aux_path: &str, aux_type: AuxType| { let lib_name = get_lib_name(&path_to_crate_name(aux_path), aux_type); if let Some(lib_name) = lib_name { - rustc.arg("--extern").arg(format!( - "{}={}/{}", - aux_name, - aux_dir.display(), - lib_name - )); + rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir, lib_name)); } }; @@ -1172,7 +1165,7 @@ impl<'test> TestCx<'test> { let aux_type = self.build_auxiliary(of, aux_file, aux_dir, None); if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) { let lib_path = aux_dir.join(&lib_name); - rustc.arg(format!("-Zcodegen-backend={}", lib_path.display())); + rustc.arg(format!("-Zcodegen-backend={}", lib_path)); } } } @@ -1188,7 +1181,7 @@ impl<'test> TestCx<'test> { if self.props.add_core_stubs { let minicore_path = self.build_minicore(); rustc.arg("--extern"); - rustc.arg(&format!("minicore={}", minicore_path.to_str().unwrap())); + rustc.arg(&format!("minicore={}", minicore_path)); } let aux_dir = self.aux_output_dir(); @@ -1206,7 +1199,7 @@ impl<'test> TestCx<'test> { /// Builds `minicore`. Returns the path to the minicore rlib within the base test output /// directory. - fn build_minicore(&self) -> PathBuf { + fn build_minicore(&self) -> Utf8PathBuf { let output_file_path = self.output_base_dir().join("libminicore.rlib"); let mut rustc = self.make_compile_args( &self.config.minicore_path, @@ -1223,10 +1216,7 @@ impl<'test> TestCx<'test> { let res = self.compose_and_run(rustc, self.config.compile_lib_path.as_path(), None, None); if !res.status.success() { self.fatal_proc_rec( - &format!( - "auxiliary build of {:?} failed to compile: ", - self.config.minicore_path.display() - ), + &format!("auxiliary build of {} failed to compile: ", self.config.minicore_path), &res, ); } @@ -1241,7 +1231,7 @@ impl<'test> TestCx<'test> { &self, of: &TestPaths, source_path: &str, - aux_dir: &Path, + aux_dir: &Utf8Path, aux_type: Option, ) -> AuxType { let aux_testpaths = self.compute_aux_test_paths(of, source_path); @@ -1338,10 +1328,7 @@ impl<'test> TestCx<'test> { ); if !auxres.status.success() { self.fatal_proc_rec( - &format!( - "auxiliary build of {:?} failed to compile: ", - aux_testpaths.file.display() - ), + &format!("auxiliary build of {} failed to compile: ", aux_testpaths.file), &auxres, ); } @@ -1350,8 +1337,8 @@ impl<'test> TestCx<'test> { fn read2_abbreviated(&self, child: Child) -> (Output, Truncated) { let mut filter_paths_from_len = Vec::new(); - let mut add_path = |path: &Path| { - let path = path.display().to_string(); + let mut add_path = |path: &Utf8Path| { + let path = path.to_string(); let windows = path.replace("\\", "\\\\"); if windows != path { filter_paths_from_len.push(windows); @@ -1373,8 +1360,8 @@ impl<'test> TestCx<'test> { fn compose_and_run( &self, mut command: Command, - lib_path: &Path, - aux_path: Option<&Path>, + lib_path: &Utf8Path, + aux_path: Option<&Utf8Path>, input: Option, ) -> ProcRes { let cmdline = { @@ -1419,9 +1406,9 @@ impl<'test> TestCx<'test> { matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json") } - fn get_mir_dump_dir(&self) -> PathBuf { + fn get_mir_dump_dir(&self) -> Utf8PathBuf { let mut mir_dump_dir = self.config.build_test_suite_root.clone(); - debug!("input_file: {:?}", self.testpaths.file); + debug!("input_file: {}", self.testpaths.file); mir_dump_dir.push(&self.testpaths.relative_dir); mir_dump_dir.push(self.testpaths.file.file_stem().unwrap()); mir_dump_dir @@ -1429,7 +1416,7 @@ impl<'test> TestCx<'test> { fn make_compile_args( &self, - input_file: &Path, + input_file: &Utf8Path, output_file: TargetLocation, emit: Emit, allow_unused: AllowUnused, @@ -1470,7 +1457,7 @@ impl<'test> TestCx<'test> { // Similarly, vendored sources shouldn't be shown when running from a dist tarball. rustc.arg("-Z").arg(format!( "ignore-directory-in-diagnostics-source-blocks={}", - self.config.src_root.join("vendor").to_str().unwrap(), + self.config.src_root.join("vendor"), )); // Optionally prevent default --sysroot if specified in test compile-flags. @@ -1494,7 +1481,7 @@ impl<'test> TestCx<'test> { if !is_rustdoc { if let Some(ref incremental_dir) = self.props.incremental_dir { - rustc.args(&["-C", &format!("incremental={}", incremental_dir.display())]); + rustc.args(&["-C", &format!("incremental={}", incremental_dir)]); rustc.args(&["-Z", "incremental-verify-ich"]); } @@ -1538,7 +1525,7 @@ impl<'test> TestCx<'test> { let mir_dump_dir = self.get_mir_dump_dir(); remove_and_create_dir_all(&mir_dump_dir); let mut dir_opt = "-Zdump-mir-dir=".to_string(); - dir_opt.push_str(mir_dump_dir.to_str().unwrap()); + dir_opt.push_str(mir_dump_dir.as_str()); debug!("dir_opt: {:?}", dir_opt); rustc.arg(dir_opt); }; @@ -1631,8 +1618,7 @@ impl<'test> TestCx<'test> { if self.props.remap_src_base { rustc.arg(format!( "--remap-path-prefix={}={}", - self.config.src_test_suite_root.to_str().unwrap(), - FAKE_SRC_BASE, + self.config.src_test_suite_root, FAKE_SRC_BASE, )); } @@ -1755,7 +1741,7 @@ impl<'test> TestCx<'test> { rustc } - fn make_exe_name(&self) -> PathBuf { + fn make_exe_name(&self) -> Utf8PathBuf { // Using a single letter here to keep the path length down for // Windows. Some test names get very long. rustc creates `rcgu` // files with the module name appended to it which can more than @@ -1806,7 +1792,7 @@ impl<'test> TestCx<'test> { } } - fn make_cmdline(&self, command: &Command, libpath: &Path) -> String { + fn make_cmdline(&self, command: &Command, libpath: &Utf8Path) -> String { use crate::util; // Linux and mac don't require adjusting the library search path @@ -1819,7 +1805,7 @@ impl<'test> TestCx<'test> { format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path)) } - format!("{} {:?}", lib_path_cmd_prefix(libpath.to_str().unwrap()), command) + format!("{} {:?}", lib_path_cmd_prefix(libpath.as_str()), command) } } @@ -1833,20 +1819,19 @@ impl<'test> TestCx<'test> { return; } - let path = Path::new(proc_name); + let path = Utf8Path::new(proc_name); let proc_name = if path.file_stem().is_some_and(|p| p == "rmake") { - OsString::from_iter( + String::from_iter( path.parent() .unwrap() .file_name() .into_iter() - .chain(Some(OsStr::new("/"))) + .chain(Some("/")) .chain(path.file_name()), ) } else { path.file_name().unwrap().into() }; - let proc_name = proc_name.to_string_lossy(); println!("------{proc_name} stdout------------------------------"); println!("{}", out); println!("------{proc_name} stderr------------------------------"); @@ -1856,18 +1841,18 @@ impl<'test> TestCx<'test> { fn dump_output_file(&self, out: &str, extension: &str) { let outfile = self.make_out_name(extension); - fs::write(&outfile, out).unwrap(); + fs::write(outfile.as_std_path(), out).unwrap(); } /// Creates a filename for output with the given extension. /// E.g., `/.../testname.revision.mode/testname.extension`. - fn make_out_name(&self, extension: &str) -> PathBuf { + fn make_out_name(&self, extension: &str) -> Utf8PathBuf { self.output_base_name().with_extension(extension) } /// Gets the directory where auxiliary files are written. /// E.g., `/.../testname.revision.mode/auxiliary/`. - fn aux_output_dir_name(&self) -> PathBuf { + fn aux_output_dir_name(&self) -> Utf8PathBuf { self.output_base_dir() .join("auxiliary") .with_extra_extension(self.config.mode.aux_dir_disambiguator()) @@ -1875,12 +1860,12 @@ impl<'test> TestCx<'test> { /// Gets the directory where auxiliary binaries are written. /// E.g., `/.../testname.revision.mode/auxiliary/bin`. - fn aux_bin_output_dir_name(&self) -> PathBuf { + fn aux_bin_output_dir_name(&self) -> Utf8PathBuf { self.aux_output_dir_name().join("bin") } /// Generates a unique name for the test, such as `testname.revision.mode`. - fn output_testname_unique(&self) -> PathBuf { + fn output_testname_unique(&self) -> Utf8PathBuf { output_testname_unique(self.config, self.testpaths, self.safe_revision()) } @@ -1893,14 +1878,14 @@ impl<'test> TestCx<'test> { /// Gets the absolute path to the directory where all output for the given /// test/revision should reside. /// E.g., `/path/to/build/host-tuple/test/ui/relative/testname.revision.mode/`. - fn output_base_dir(&self) -> PathBuf { + fn output_base_dir(&self) -> Utf8PathBuf { output_base_dir(self.config, self.testpaths, self.safe_revision()) } /// Gets the absolute path to the base filename used as output for the given /// test/revision. /// E.g., `/.../relative/testname.revision.mode/testname`. - fn output_base_name(&self) -> PathBuf { + fn output_base_name(&self) -> Utf8PathBuf { output_base_name(self.config, self.testpaths, self.safe_revision()) } @@ -1935,7 +1920,7 @@ impl<'test> TestCx<'test> { // codegen tests (using FileCheck) - fn compile_test_and_save_ir(&self) -> (ProcRes, PathBuf) { + fn compile_test_and_save_ir(&self) -> (ProcRes, Utf8PathBuf) { let output_path = self.output_base_name().with_extension("ll"); let input_file = &self.testpaths.file; let rustc = self.make_compile_args( @@ -1951,7 +1936,7 @@ impl<'test> TestCx<'test> { (proc_res, output_path) } - fn verify_with_filecheck(&self, output: &Path) -> ProcRes { + fn verify_with_filecheck(&self, output: &Utf8Path) -> ProcRes { let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap()); filecheck.arg("--input-file").arg(output).arg(&self.testpaths.file); @@ -1981,7 +1966,7 @@ impl<'test> TestCx<'test> { filecheck.args(&self.props.filecheck_flags); // FIXME(jieyouxu): don't pass an empty Path - self.compose_and_run(filecheck, Path::new(""), None, None) + self.compose_and_run(filecheck, Utf8Path::new(""), None, None) } fn charset() -> &'static str { @@ -1989,7 +1974,7 @@ impl<'test> TestCx<'test> { if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" } } - fn compare_to_default_rustdoc(&mut self, out_dir: &Path) { + fn compare_to_default_rustdoc(&mut self, out_dir: &Utf8Path) { if !self.config.has_html_tidy { return; } @@ -2141,12 +2126,8 @@ impl<'test> TestCx<'test> { }; } - fn get_lines>( - &self, - path: &P, - mut other_files: Option<&mut Vec>, - ) -> Vec { - let content = fs::read_to_string(&path).unwrap(); + fn get_lines(&self, path: &Utf8Path, mut other_files: Option<&mut Vec>) -> Vec { + let content = fs::read_to_string(path.as_std_path()).unwrap(); let mut ignore = false; content .lines() @@ -2192,8 +2173,8 @@ impl<'test> TestCx<'test> { for other_file in other_files { let mut path = self.testpaths.file.clone(); path.set_file_name(&format!("{}.rs", other_file)); - let path = fs::canonicalize(path).expect("failed to canonicalize"); - let normalized = path.to_str().unwrap().replace('\\', "/"); + let path = path.canonicalize_utf8().expect("failed to canonicalize"); + let normalized = path.as_str().replace('\\', "/"); files.insert(normalized, self.get_lines(&path, None)); } @@ -2377,26 +2358,24 @@ impl<'test> TestCx<'test> { let mut normalized = output.to_string(); - let mut normalize_path = |from: &Path, to: &str| { - let mut from = from.display().to_string(); - if json { - from = from.replace("\\", "\\\\"); - } - normalized = normalized.replace(&from, to); + let mut normalize_path = |from: &Utf8Path, to: &str| { + let from = if json { &from.as_str().replace("\\", "\\\\") } else { from.as_str() }; + + normalized = normalized.replace(from, to); }; let parent_dir = self.testpaths.file.parent().unwrap(); normalize_path(parent_dir, "$DIR"); if self.props.remap_src_base { - let mut remapped_parent_dir = PathBuf::from(FAKE_SRC_BASE); - if self.testpaths.relative_dir != Path::new("") { + let mut remapped_parent_dir = Utf8PathBuf::from(FAKE_SRC_BASE); + if self.testpaths.relative_dir != Utf8Path::new("") { remapped_parent_dir.push(&self.testpaths.relative_dir); } normalize_path(&remapped_parent_dir, "$DIR"); } - let base_dir = Path::new("/rustc/FAKE_PREFIX"); + let base_dir = Utf8Path::new("/rustc/FAKE_PREFIX"); // Fake paths into the libstd/libcore normalize_path(&base_dir.join("library"), "$SRC_DIR"); // `ui-fulldeps` tests can show paths to the compiler source when testing macros from @@ -2406,8 +2385,8 @@ impl<'test> TestCx<'test> { // Real paths into the libstd/libcore let rust_src_dir = &self.config.sysroot_base.join("lib/rustlib/src/rust"); - rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir.display())); - let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf()); + rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir)); + let rust_src_dir = rust_src_dir.read_link_utf8().unwrap_or(rust_src_dir.to_path_buf()); normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); // eg. @@ -2547,7 +2526,7 @@ impl<'test> TestCx<'test> { .replace("\r\n", "\n") } - fn expected_output_path(&self, kind: &str) -> PathBuf { + fn expected_output_path(&self, kind: &str) -> Utf8PathBuf { let mut path = expected_output_path(&self.testpaths, self.revision, &self.config.compare_mode, kind); @@ -2576,19 +2555,18 @@ impl<'test> TestCx<'test> { } } - fn load_expected_output_from_path(&self, path: &Path) -> Result { - fs::read_to_string(path).map_err(|err| { - format!("failed to load expected output from `{}`: {}", path.display(), err) - }) + fn load_expected_output_from_path(&self, path: &Utf8Path) -> Result { + fs::read_to_string(path) + .map_err(|err| format!("failed to load expected output from `{}`: {}", path, err)) } - fn delete_file(&self, file: &Path) { + fn delete_file(&self, file: &Utf8Path) { if !file.exists() { // Deleting a nonexistent file would error. return; } - if let Err(e) = fs::remove_file(file) { - self.fatal(&format!("failed to delete `{}`: {}", file.display(), e,)); + if let Err(e) = fs::remove_file(file.as_std_path()) { + self.fatal(&format!("failed to delete `{}`: {}", file, e,)); } } @@ -2694,8 +2672,8 @@ impl<'test> TestCx<'test> { fn show_diff( &self, stream: &str, - expected_path: &Path, - actual_path: &Path, + expected_path: &Utf8Path, + actual_path: &Utf8Path, expected: &str, actual: &str, actual_unnormalized: &str, @@ -2834,7 +2812,7 @@ impl<'test> TestCx<'test> { fs::create_dir_all(&incremental_dir).unwrap(); if self.config.verbose { - println!("init_incremental_test: incremental_dir={}", incremental_dir.display()); + println!("init_incremental_test: incremental_dir={incremental_dir}"); } } } @@ -2892,8 +2870,8 @@ impl ProcRes { #[derive(Debug)] enum TargetLocation { - ThisFile(PathBuf), - ThisDirectory(PathBuf), + ThisFile(Utf8PathBuf), + ThisDirectory(Utf8PathBuf), } enum AllowUnused { diff --git a/src/tools/compiletest/src/runtest/assembly.rs b/src/tools/compiletest/src/runtest/assembly.rs index 89d7de58c203..91d4f620f719 100644 --- a/src/tools/compiletest/src/runtest/assembly.rs +++ b/src/tools/compiletest/src/runtest/assembly.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use camino::Utf8PathBuf; use super::{AllowUnused, Emit, LinkToAux, ProcRes, TargetLocation, TestCx}; @@ -19,7 +19,7 @@ impl TestCx<'_> { } } - fn compile_test_and_save_assembly(&self) -> (ProcRes, PathBuf) { + fn compile_test_and_save_assembly(&self) -> (ProcRes, Utf8PathBuf) { // This works with both `--emit asm` (as default output name for the assembly) // and `ptx-linker` because the latter can write output at requested location. let output_path = self.output_base_name().with_extension("s"); diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs index 6c866cbef21a..8dfa8d18d1a0 100644 --- a/src/tools/compiletest/src/runtest/codegen_units.rs +++ b/src/tools/compiletest/src/runtest/codegen_units.rs @@ -26,9 +26,7 @@ impl TestCx<'_> { .stdout .lines() .filter(|line| line.starts_with(PREFIX)) - .map(|line| { - line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string() - }) + .map(|line| line.replace(&self.testpaths.file.as_str(), "TEST_PATH").to_string()) .map(|line| str_to_mono_item(&line, true)) .collect(); diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs index 56fc5baf5f24..41cfeaee35ff 100644 --- a/src/tools/compiletest/src/runtest/coverage.rs +++ b/src/tools/compiletest/src/runtest/coverage.rs @@ -1,9 +1,9 @@ //! Code specific to the coverage test suites. use std::ffi::OsStr; -use std::path::{Path, PathBuf}; use std::process::Command; +use camino::{Utf8Path, Utf8PathBuf}; use glob::glob; use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP}; @@ -11,7 +11,7 @@ use crate::runtest::{Emit, ProcRes, TestCx, WillExecute}; use crate::util::static_regex; impl<'test> TestCx<'test> { - fn coverage_dump_path(&self) -> &Path { + fn coverage_dump_path(&self) -> &Utf8Path { self.config .coverage_dump_path .as_deref() @@ -79,10 +79,8 @@ impl<'test> TestCx<'test> { std::fs::remove_file(&profdata_path).unwrap(); } - let proc_res = self.exec_compiled_test_general( - &[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())], - false, - ); + let proc_res = + self.exec_compiled_test_general(&[("LLVM_PROFILE_FILE", profraw_path.as_str())], false); if self.props.failure_status.is_some() { self.check_correct_failure_status(&proc_res); } else if !proc_res.status.success() { @@ -158,8 +156,8 @@ impl<'test> TestCx<'test> { /// `.profraw` files and doctest executables to the given vectors. fn run_doctests_for_coverage( &self, - profraw_paths: &mut Vec, - bin_paths: &mut Vec, + profraw_paths: &mut Vec, + bin_paths: &mut Vec, ) { // Put .profraw files and doctest executables in dedicated directories, // to make it easier to glob them all later. @@ -204,10 +202,9 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("rustdoc --test failed!", &proc_res) } - fn glob_iter(path: impl AsRef) -> impl Iterator { - let path_str = path.as_ref().to_str().unwrap(); - let iter = glob(path_str).unwrap(); - iter.map(Result::unwrap) + fn glob_iter(path: impl AsRef) -> impl Iterator { + let iter = glob(path.as_ref().as_str()).unwrap(); + iter.map(Result::unwrap).map(Utf8PathBuf::try_from).map(Result::unwrap) } // Find all profraw files in the profraw directory. diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index d9e5c3fa0d8f..a4103c5b4a9a 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -1,7 +1,8 @@ use std::fmt::Write; use std::fs::File; use std::io::{BufRead, BufReader}; -use std::path::{Path, PathBuf}; + +use camino::{Utf8Path, Utf8PathBuf}; use crate::common::Config; use crate::runtest::ProcRes; @@ -15,11 +16,15 @@ pub(super) struct DebuggerCommands { /// Contains the source line number to check and the line itself check_lines: Vec<(usize, String)>, /// Source file name - file: PathBuf, + file: Utf8PathBuf, } impl DebuggerCommands { - pub fn parse_from(file: &Path, config: &Config, debugger_prefix: &str) -> Result { + pub fn parse_from( + file: &Utf8Path, + config: &Config, + debugger_prefix: &str, + ) -> Result { let command_directive = format!("{debugger_prefix}-command"); let check_directive = format!("{debugger_prefix}-check"); @@ -27,7 +32,7 @@ impl DebuggerCommands { let mut commands = vec![]; let mut check_lines = vec![]; let mut counter = 0; - let reader = BufReader::new(File::open(file).unwrap()); + let reader = BufReader::new(File::open(file.as_std_path()).unwrap()); for (line_no, line) in reader.lines().enumerate() { counter += 1; let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?; @@ -50,7 +55,7 @@ impl DebuggerCommands { } } - Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_owned() }) + Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_path_buf() }) } /// Given debugger output and lines to check, ensure that every line is @@ -81,10 +86,10 @@ impl DebuggerCommands { if missing.is_empty() { Ok(()) } else { - let fname = self.file.file_name().unwrap().to_string_lossy(); + let fname = self.file.file_name().unwrap(); let mut msg = format!( "check directive(s) from `{}` not found in debugger output. errors:", - self.file.display() + self.file ); for (src_lineno, err_line) in missing { diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 50e733cd31b6..31240dff9a19 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -1,9 +1,9 @@ use std::ffi::{OsStr, OsString}; use std::fs::File; use std::io::{BufRead, BufReader, Read}; -use std::path::Path; use std::process::{Command, Output, Stdio}; +use camino::Utf8Path; use tracing::debug; use super::debugger::DebuggerCommands; @@ -73,11 +73,11 @@ impl TestCx<'_> { let mut js_extension = self.testpaths.file.clone(); js_extension.set_extension("cdb.js"); if js_extension.exists() { - script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension.to_string_lossy())); + script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension)); } // Set breakpoints on every line that contains the string "#break" - let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); + let source_file_name = self.testpaths.file.file_name().unwrap(); for line in &dbg_cmds.breakpoint_lines { script_str.push_str(&format!("bp `{}:{}`\n", source_file_name, line)); } @@ -151,16 +151,11 @@ impl TestCx<'_> { if is_android_gdb_target(&self.config.target) { cmds = cmds.replace("run", "continue"); - let tool_path = match self.config.android_cross_path.to_str() { - Some(x) => x.to_owned(), - None => self.fatal("cannot find android cross path"), - }; - // write debugger script let mut script_str = String::with_capacity(2048); script_str.push_str(&format!("set charset {}\n", Self::charset())); - script_str.push_str(&format!("set sysroot {}\n", tool_path)); - script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap())); + script_str.push_str(&format!("set sysroot {}\n", &self.config.android_cross_path)); + script_str.push_str(&format!("file {}\n", exe_file)); script_str.push_str("target remote :5039\n"); script_str.push_str(&format!( "set solib-search-path \ @@ -169,12 +164,8 @@ impl TestCx<'_> { )); for line in &dbg_cmds.breakpoint_lines { script_str.push_str( - format!( - "break {:?}:{}\n", - self.testpaths.file.file_name().unwrap().to_string_lossy(), - *line - ) - .as_str(), + format!("break {}:{}\n", self.testpaths.file.file_name().unwrap(), *line) + .as_str(), ); } script_str.push_str(&cmds); @@ -203,7 +194,7 @@ impl TestCx<'_> { self.config.adb_test_dir.clone(), if self.config.target.contains("aarch64") { "64" } else { "" }, self.config.adb_test_dir.clone(), - exe_file.file_name().unwrap().to_str().unwrap() + exe_file.file_name().unwrap() ); debug!("adb arg: {}", adb_arg); @@ -242,7 +233,7 @@ impl TestCx<'_> { let mut gdb = Command::new(&format!("{}-gdb", self.config.target)); gdb.args(debugger_opts); // FIXME(jieyouxu): don't pass an empty Path - let cmdline = self.make_cmdline(&gdb, Path::new("")); + let cmdline = self.make_cmdline(&gdb, Utf8Path::new("")); logv(self.config, format!("executing {}", cmdline)); cmdline }; @@ -259,7 +250,6 @@ impl TestCx<'_> { } } else { let rust_pp_module_abs_path = self.config.src_root.join("src").join("etc"); - let rust_pp_module_abs_path = rust_pp_module_abs_path.to_str().unwrap(); // write debugger script let mut script_str = String::with_capacity(2048); script_str.push_str(&format!("set charset {}\n", Self::charset())); @@ -274,17 +264,15 @@ impl TestCx<'_> { // GDB's script auto loading safe path script_str.push_str(&format!( "add-auto-load-safe-path {}\n", - rust_pp_module_abs_path.replace(r"\", r"\\") + rust_pp_module_abs_path.as_str().replace(r"\", r"\\") )); - let output_base_dir = self.output_base_dir().to_str().unwrap().to_owned(); - // Add the directory containing the output binary to // include embedded pretty printers to GDB's script // auto loading safe path script_str.push_str(&format!( "add-auto-load-safe-path {}\n", - output_base_dir.replace(r"\", r"\\") + self.output_base_dir().as_str().replace(r"\", r"\\") )); } } @@ -301,12 +289,13 @@ impl TestCx<'_> { script_str.push_str("set print pretty off\n"); // Add the pretty printer directory to GDB's source-file search path - script_str - .push_str(&format!("directory {}\n", rust_pp_module_abs_path.replace(r"\", r"\\"))); + script_str.push_str(&format!( + "directory {}\n", + rust_pp_module_abs_path.as_str().replace(r"\", r"\\") + )); // Load the target executable - script_str - .push_str(&format!("file {}\n", exe_file.to_str().unwrap().replace(r"\", r"\\"))); + script_str.push_str(&format!("file {}\n", exe_file.as_str().replace(r"\", r"\\"))); // Force GDB to print values in the Rust format. script_str.push_str("set language rust\n"); @@ -315,7 +304,7 @@ impl TestCx<'_> { for line in &dbg_cmds.breakpoint_lines { script_str.push_str(&format!( "break '{}':{}\n", - self.testpaths.file.file_name().unwrap().to_string_lossy(), + self.testpaths.file.file_name().unwrap(), *line )); } @@ -410,14 +399,14 @@ impl TestCx<'_> { script_str.push_str(&format!( "command script import {}/lldb_lookup.py\n", - rust_pp_module_abs_path.to_str().unwrap() + rust_pp_module_abs_path )); File::open(rust_pp_module_abs_path.join("lldb_commands")) .and_then(|mut file| file.read_to_string(&mut script_str)) .expect("Failed to read lldb_commands"); // Set breakpoints on every line that contains the string "#break" - let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); + let source_file_name = self.testpaths.file.file_name().unwrap(); for line in &dbg_cmds.breakpoint_lines { script_str.push_str(&format!( "breakpoint set --file '{}' --line {}\n", @@ -451,7 +440,7 @@ impl TestCx<'_> { } } - fn run_lldb(&self, test_executable: &Path, debugger_script: &Path) -> ProcRes { + fn run_lldb(&self, test_executable: &Utf8Path, debugger_script: &Utf8Path) -> ProcRes { // Prepare the lldb_batchmode which executes the debugger script let lldb_script_path = self.config.src_root.join("src/etc/lldb_batchmode.py"); let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { diff --git a/src/tools/compiletest/src/runtest/js_doc.rs b/src/tools/compiletest/src/runtest/js_doc.rs index d630affbec10..fd53f01ca174 100644 --- a/src/tools/compiletest/src/runtest/js_doc.rs +++ b/src/tools/compiletest/src/runtest/js_doc.rs @@ -9,8 +9,7 @@ impl TestCx<'_> { self.document(&out_dir, &self.testpaths); - let file_stem = - self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem"); + let file_stem = self.testpaths.file.file_stem().expect("no file stem"); let res = self.run_command_to_procres( Command::new(&nodejs) .arg(self.config.src_root.join("src/tools/rustdoc-js/tester.js")) diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs index d1ec00357449..ded6a68fe587 100644 --- a/src/tools/compiletest/src/runtest/mir_opt.rs +++ b/src/tools/compiletest/src/runtest/mir_opt.rs @@ -1,6 +1,6 @@ use std::fs; -use std::path::{Path, PathBuf}; +use camino::{Utf8Path, Utf8PathBuf}; use glob::glob; use miropt_test_tools::{MiroptTest, MiroptTestFile, files_for_miropt_test}; use tracing::debug; @@ -14,7 +14,7 @@ impl TestCx<'_> { let should_run = self.should_run(pm); let mut test_info = files_for_miropt_test( - &self.testpaths.file, + &self.testpaths.file.as_std_path(), self.config.get_pointer_width(), self.config.target_cfg().panic.for_miropt_test_tools(), ); @@ -38,20 +38,15 @@ impl TestCx<'_> { fn check_mir_dump(&self, test_info: MiroptTest) { let test_dir = self.testpaths.file.parent().unwrap(); - let test_crate = - self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_"); + let test_crate = self.testpaths.file.file_stem().unwrap().replace('-', "_"); let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info; if self.config.bless { - for e in - glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, suffix)).unwrap() - { + for e in glob(&format!("{}/{}.*{}.mir", test_dir, test_crate, suffix)).unwrap() { fs::remove_file(e.unwrap()).unwrap(); } - for e in - glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, suffix)).unwrap() - { + for e in glob(&format!("{}/{}.*{}.diff", test_dir, test_crate, suffix)).unwrap() { fs::remove_file(e.unwrap()).unwrap(); } } @@ -60,19 +55,15 @@ impl TestCx<'_> { let dumped_string = if let Some(after) = to_file { self.diff_mir_files(from_file.into(), after.into()) } else { - let mut output_file = PathBuf::new(); + let mut output_file = Utf8PathBuf::new(); output_file.push(self.get_mir_dump_dir()); output_file.push(&from_file); - debug!( - "comparing the contents of: {} with {}", - output_file.display(), - expected_file.display() - ); + debug!("comparing the contents of: {} with {:?}", output_file, expected_file); if !output_file.exists() { panic!( "Output file `{}` from test does not exist, available files are in `{}`", - output_file.display(), - output_file.parent().unwrap().display() + output_file, + output_file.parent().unwrap() ); } self.check_mir_test_timestamp(&from_file, &output_file); @@ -107,21 +98,20 @@ impl TestCx<'_> { } } - fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String { - let to_full_path = |path: PathBuf| { + fn diff_mir_files(&self, before: Utf8PathBuf, after: Utf8PathBuf) -> String { + let to_full_path = |path: Utf8PathBuf| { let full = self.get_mir_dump_dir().join(&path); if !full.exists() { panic!( "the mir dump file for {} does not exist (requested in {})", - path.display(), - self.testpaths.file.display(), + path, self.testpaths.file, ); } full }; let before = to_full_path(before); let after = to_full_path(after); - debug!("comparing the contents of: {} with {}", before.display(), after.display()); + debug!("comparing the contents of: {} with {}", before, after); let before = fs::read_to_string(before).unwrap(); let after = fs::read_to_string(after).unwrap(); let before = self.normalize_output(&before, &[]); @@ -138,8 +128,8 @@ impl TestCx<'_> { dumped_string } - fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) { - let t = |file| fs::metadata(file).unwrap().modified().unwrap(); + fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Utf8Path) { + let t = |file: &Utf8Path| fs::metadata(file.as_std_path()).unwrap().modified().unwrap(); let source_file = &self.testpaths.file; let output_time = t(output_file); let source_time = t(source_file); @@ -147,8 +137,7 @@ impl TestCx<'_> { debug!("source file time: {:?} output file time: {:?}", source_time, output_time); panic!( "test source file `{}` is newer than potentially stale output file `{}`.", - source_file.display(), - test_name + source_file, test_name ); } } diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 073116933bdb..a5ce929f9b8e 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -1,8 +1,8 @@ -use std::path::Path; use std::process::{Command, Output, Stdio}; use std::{env, fs}; use build_helper::fs::{ignore_not_found, recursive_remove}; +use camino::{Utf8Path, Utf8PathBuf}; use super::{ProcRes, TestCx, disable_error_reporting}; use crate::util::{copy_dir_all, dylib_env_var}; @@ -39,14 +39,16 @@ impl TestCx<'_> { // Copy all input files (apart from rmake.rs) to the temporary directory, // so that the input directory structure from `tests/run-make/` is mirrored // to the `rmake_out` directory. - for path in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) { - let path = path.unwrap().path().to_path_buf(); + for entry in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) { + let entry = entry.unwrap(); + let path = entry.path(); + let path = <&Utf8Path>::try_from(path).unwrap(); if path.file_name().is_some_and(|s| s != "rmake.rs") { let target = rmake_out_dir.join(path.strip_prefix(&self.testpaths.file).unwrap()); if path.is_dir() { - copy_dir_all(&path, target).unwrap(); + copy_dir_all(&path, &target).unwrap(); } else { - fs::copy(&path, target).unwrap(); + fs::copy(path.as_std_path(), target).unwrap(); } } } @@ -83,8 +85,10 @@ impl TestCx<'_> { // on some linux distros. // 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc. - let base_dylib_search_paths = - Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap())); + let base_dylib_search_paths = Vec::from_iter( + env::split_paths(&env::var(dylib_env_var()).unwrap()) + .map(|p| Utf8PathBuf::try_from(p).expect("dylib env var contains non-UTF8 paths")), + ); // Calculate the paths of the recipe binary. As previously discussed, this is placed at // `/` with `bin_name` being `rmake` or `rmake.exe` depending on @@ -113,13 +117,13 @@ impl TestCx<'_> { .arg("-o") .arg(&recipe_bin) // Specify library search paths for `run_make_support`. - .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy())) - .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy())) - .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy())) + .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap())) + .arg(format!("-Ldependency={}", &support_lib_deps)) + .arg(format!("-Ldependency={}", &support_lib_deps_deps)) // Provide `run_make_support` as extern prelude, so test writers don't need to write // `extern run_make_support;`. .arg("--extern") - .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) + .arg(format!("run_make_support={}", &support_lib_path)) .arg("--edition=2021") .arg(&self.testpaths.file.join("rmake.rs")) .arg("-Cprefer-dynamic"); @@ -240,7 +244,7 @@ impl TestCx<'_> { if self.config.target.contains("msvc") && !self.config.cc.is_empty() { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. - let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); + let lib = Utf8Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); // MSYS doesn't like passing flags of the form `/foo` as it thinks it's // a path and instead passes `C:\msys64\foo`, so convert all @@ -262,8 +266,8 @@ impl TestCx<'_> { cmd.env("IS_MSVC", "1") .env("IS_WINDOWS", "1") - .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) - .env("MSVC_LIB_PATH", format!("{}", lib.display())) + .env("MSVC_LIB", format!("'{}' -nologo", lib)) + .env("MSVC_LIB_PATH", &lib) // Note: we diverge from legacy run_make and don't lump `CC` the compiler and // default flags together. .env("CC_DEFAULT_FLAGS", &cflags) diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index 974e5170465e..e87b037cd289 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -68,7 +68,7 @@ impl TestCx<'_> { { let mut coverage_file_path = self.config.build_test_suite_root.clone(); coverage_file_path.push("rustfix_missing_coverage.txt"); - debug!("coverage_file_path: {}", coverage_file_path.display()); + debug!("coverage_file_path: {}", coverage_file_path); let mut file = OpenOptions::new() .create(true) @@ -76,8 +76,8 @@ impl TestCx<'_> { .open(coverage_file_path.as_path()) .expect("could not create or open file"); - if let Err(e) = writeln!(file, "{}", self.testpaths.file.display()) { - panic!("couldn't write to {}: {e:?}", coverage_file_path.display()); + if let Err(e) = writeln!(file, "{}", self.testpaths.file) { + panic!("couldn't write to {}: {e:?}", coverage_file_path); } } } else if self.props.run_rustfix { @@ -119,7 +119,7 @@ impl TestCx<'_> { self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap()); println!( "To only update this specific test, also pass `--test-args {}`", - relative_path_to_file.display(), + relative_path_to_file, ); self.fatal_proc_rec( &format!("{} errors occurred comparing output.", errors), @@ -211,8 +211,6 @@ impl TestCx<'_> { let crate_name = self.testpaths.file.file_stem().expect("test must have a file stem"); // crate name must be alphanumeric or `_`. - let crate_name = - crate_name.to_str().expect("crate name implies file name must be valid UTF-8"); // replace `a.foo` -> `a__foo` for crate name purposes. // replace `revision-name-with-dashes` -> `revision_name_with_underscore` let crate_name = crate_name.replace('.', "__"); diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 43c6dc0a67e8..e3e4a81755d0 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -1,5 +1,3 @@ -use std::ffi::OsString; - use crate::debuggers::{extract_gdb_version, extract_lldb_version}; use crate::is_test; @@ -60,11 +58,11 @@ fn test_extract_lldb_version() { #[test] fn is_test_test() { - assert!(is_test(&OsString::from("a_test.rs"))); - assert!(!is_test(&OsString::from(".a_test.rs"))); - assert!(!is_test(&OsString::from("a_cat.gif"))); - assert!(!is_test(&OsString::from("#a_dog_gif"))); - assert!(!is_test(&OsString::from("~a_temp_file"))); + assert!(is_test("a_test.rs")); + assert!(!is_test(".a_test.rs")); + assert!(!is_test("a_cat.gif")); + assert!(!is_test("#a_dog_gif")); + assert!(!is_test("~a_temp_file")); } #[test] diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index bff02f1db9f0..81f5679aead7 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -1,8 +1,7 @@ use std::env; -use std::ffi::OsStr; -use std::path::{Path, PathBuf}; use std::process::Command; +use camino::{Utf8Path, Utf8PathBuf}; use tracing::*; use crate::common::Config; @@ -34,21 +33,21 @@ pub fn logv(config: &Config, s: String) { } } -pub trait PathBufExt { +pub trait Utf8PathBufExt { /// Append an extension to the path, even if it already has one. - fn with_extra_extension>(&self, extension: S) -> PathBuf; + fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf; } -impl PathBufExt for PathBuf { - fn with_extra_extension>(&self, extension: S) -> PathBuf { - if extension.as_ref().is_empty() { +impl Utf8PathBufExt for Utf8PathBuf { + fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf { + if extension.is_empty() { self.clone() } else { - let mut fname = self.file_name().unwrap().to_os_string(); - if !extension.as_ref().to_str().unwrap().starts_with('.') { - fname.push("."); + let mut fname = self.file_name().unwrap().to_string(); + if !extension.starts_with('.') { + fname.push_str("."); } - fname.push(extension); + fname.push_str(extension); self.with_file_name(fname) } } @@ -71,22 +70,27 @@ pub fn dylib_env_var() -> &'static str { /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path. /// If the dylib_path_var is already set for this cmd, the old value will be overwritten! -pub fn add_dylib_path(cmd: &mut Command, paths: impl Iterator>) { +pub fn add_dylib_path( + cmd: &mut Command, + paths: impl Iterator>, +) { let path_env = env::var_os(dylib_env_var()); let old_paths = path_env.as_ref().map(env::split_paths); let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten()); cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap()); } -pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { - std::fs::create_dir_all(&dst)?; - for entry in std::fs::read_dir(src)? { +pub fn copy_dir_all(src: &Utf8Path, dst: &Utf8Path) -> std::io::Result<()> { + std::fs::create_dir_all(dst.as_std_path())?; + for entry in std::fs::read_dir(src.as_std_path())? { let entry = entry?; + let path = Utf8PathBuf::try_from(entry.path()).unwrap(); + let file_name = path.file_name().unwrap(); let ty = entry.file_type()?; if ty.is_dir() { - copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; + copy_dir_all(&path, &dst.join(file_name))?; } else { - std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + std::fs::copy(path.as_std_path(), dst.join(file_name).as_std_path())?; } } Ok(()) diff --git a/src/tools/compiletest/src/util/tests.rs b/src/tools/compiletest/src/util/tests.rs index b09a183b14e6..5bcae0dcee14 100644 --- a/src/tools/compiletest/src/util/tests.rs +++ b/src/tools/compiletest/src/util/tests.rs @@ -3,12 +3,12 @@ use super::*; #[test] fn path_buf_with_extra_extension_test() { assert_eq!( - PathBuf::from("foo.rs.stderr"), - PathBuf::from("foo.rs").with_extra_extension("stderr") + Utf8PathBuf::from("foo.rs.stderr"), + Utf8PathBuf::from("foo.rs").with_extra_extension("stderr") ); assert_eq!( - PathBuf::from("foo.rs.stderr"), - PathBuf::from("foo.rs").with_extra_extension(".stderr") + Utf8PathBuf::from("foo.rs.stderr"), + Utf8PathBuf::from("foo.rs").with_extra_extension(".stderr") ); - assert_eq!(PathBuf::from("foo.rs"), PathBuf::from("foo.rs").with_extra_extension("")); + assert_eq!(Utf8PathBuf::from("foo.rs"), Utf8PathBuf::from("foo.rs").with_extra_extension("")); } From 957324b0a0f532dff28755155c5ce07a2ca04383 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Apr 2025 12:32:27 +0800 Subject: [PATCH 104/222] rustdoc-gui-test: pass a `camino::Utf8PathBuf` to `compiletest` --- Cargo.lock | 1 + src/tools/rustdoc-gui-test/Cargo.toml | 1 + src/tools/rustdoc-gui-test/src/main.rs | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c80bfef485c2..b0d6aa5659a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4672,6 +4672,7 @@ name = "rustdoc-gui-test" version = "0.1.0" dependencies = [ "build_helper", + "camino", "compiletest", "getopts", "walkdir", diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml index f7384a98f856..8d958ac94f30 100644 --- a/src/tools/rustdoc-gui-test/Cargo.toml +++ b/src/tools/rustdoc-gui-test/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] build_helper = { path = "../../build_helper" } +camino = "1" compiletest = { path = "../compiletest" } getopts = "0.2" walkdir = "2" diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index f1c6e13d3ae8..addb0af4a541 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -118,7 +118,11 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse ..Default::default() }; - let test_props = TestProps::from_file(&librs, None, &compiletest_c); + let test_props = TestProps::from_file( + &camino::Utf8PathBuf::try_from(librs).unwrap(), + None, + &compiletest_c, + ); if !test_props.compile_flags.is_empty() { cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" ")); From 15a93c5683fa4a5c7a10b3e3385178ff0fd0fed6 Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Sun, 13 Apr 2025 21:15:15 +0800 Subject: [PATCH 105/222] std/thread: Use default stack size from menuconfig for NuttX * Update comments to clarify the usage of zero as an indication for default stack size configuration * Adjust conditional compilation to reflect the changes in stack size handling for the NuttX platform This change improves clarity and consistency in stack size configuration across platforms. Signed-off-by: Huang Qi --- library/std/src/sys/pal/unix/thread.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 9078dd1c2316..4f1517b7ef42 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -8,14 +8,19 @@ use crate::sys::weak::weak; use crate::sys::{os, stack_overflow}; use crate::time::Duration; use crate::{cmp, io, ptr}; -#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))] +#[cfg(not(any( + target_os = "l4re", + target_os = "vxworks", + target_os = "espidf", + target_os = "nuttx" +)))] pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; #[cfg(target_os = "l4re")] pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; #[cfg(target_os = "vxworks")] pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024; -#[cfg(target_os = "espidf")] -pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF menuconfig system should be used +#[cfg(any(target_os = "espidf", target_os = "nuttx"))] +pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used #[cfg(target_os = "fuchsia")] mod zircon { @@ -52,10 +57,10 @@ impl Thread { let mut attr: mem::MaybeUninit = mem::MaybeUninit::uninit(); assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); - #[cfg(target_os = "espidf")] + #[cfg(any(target_os = "espidf", target_os = "nuttx"))] if stack > 0 { // Only set the stack if a non-zero value is passed - // 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used + // 0 is used as an indication that the default stack size configured in the ESP-IDF/NuttX menuconfig system should be used assert_eq!( libc::pthread_attr_setstacksize( attr.as_mut_ptr(), @@ -65,7 +70,7 @@ impl Thread { ); } - #[cfg(not(target_os = "espidf"))] + #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] { let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr())); From a404015775276f2e21e16c69fab36cc8228d51f6 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 8 Apr 2025 12:28:42 +0530 Subject: [PATCH 106/222] std: sys: process: uefi: Use NULL stdin by default According to the docs in `Command::output`: > By default, stdout and stderr are captured (and used to provide the resulting output). Stdin is not inherited from the parent and any attempt by the child process to read from the stdin stream will result in the stream immediately closing. This was being violated by UEFI which was inheriting stdin by default. While the docs don't explicitly state that the default should be NULL, the behaviour seems like reading from NULL. UEFI however, has a bit of a problem. The `EFI_SIMPLE_TEXT_INPUT_PROTOCOL` only provides support for reading 1 key press. This means that you either get an error, or it is assumed that the keypress was read successfully. So there is no way to have a successful read of length 0. Currently, I am returning UNSUPPORTED error when trying to read from NULL stdin. On linux however, you will get a read of length 0 for Null stdin. One possible way to get around this is to translate one of the UEFI errors to a read 0 (Maybe unsupported?). It is also possible to have a non-standard error code, but well, not sure if we go that route. Alternatively, if meaning of Stdio::Null is platform dependent, it should be fine to keep the current behaviour of returning an error. Signed-off-by: Ayush Singh --- library/std/src/sys/process/uefi.rs | 112 +++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index b46418ae9bb6..fb5aa5ca2669 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -1,4 +1,4 @@ -use r_efi::protocols::simple_text_output; +use r_efi::protocols::{simple_text_input, simple_text_output}; use crate::collections::BTreeMap; pub use crate::ffi::OsString as EnvKey; @@ -122,6 +122,22 @@ impl Command { } } + fn create_stdin( + s: Stdio, + ) -> io::Result>> { + match s { + Stdio::Null => unsafe { + helpers::OwnedProtocol::create( + uefi_command_internal::InputProtocol::null(), + simple_text_input::PROTOCOL_GUID, + ) + } + .map(Some), + Stdio::Inherit => Ok(None), + Stdio::MakePipe => unsupported(), + } + } + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; @@ -149,6 +165,14 @@ impl Command { cmd.stderr_inherit() }; + // Setup Stdin + let stdin = Self::create_stdin(Stdio::Null)?; + if let Some(con) = stdin { + cmd.stdin_init(con) + } else { + cmd.stdin_inherit() + }; + let env = env_changes(&self.env); // Set any new vars @@ -334,7 +358,7 @@ impl<'a> fmt::Debug for CommandArgs<'a> { #[allow(dead_code)] mod uefi_command_internal { - use r_efi::protocols::{loaded_image, simple_text_output}; + use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output}; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_error}; @@ -350,6 +374,7 @@ mod uefi_command_internal { handle: NonNull, stdout: Option>, stderr: Option>, + stdin: Option>, st: OwnedTable, args: Option<(*mut u16, usize)>, } @@ -384,7 +409,14 @@ mod uefi_command_internal { helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap(); let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table }); - Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None }) + Ok(Self { + handle: child_handle, + stdout: None, + stderr: None, + stdin: None, + st, + args: None, + }) } } @@ -445,6 +477,17 @@ mod uefi_command_internal { } } + fn set_stdin( + &mut self, + handle: r_efi::efi::Handle, + protocol: *mut simple_text_input::Protocol, + ) { + unsafe { + (*self.st.as_mut_ptr()).console_in_handle = handle; + (*self.st.as_mut_ptr()).con_in = protocol; + } + } + pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol) { self.set_stdout( protocol.handle().as_ptr(), @@ -471,6 +514,19 @@ mod uefi_command_internal { unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) } } + pub(crate) fn stdin_init(&mut self, protocol: helpers::OwnedProtocol) { + self.set_stdin( + protocol.handle().as_ptr(), + protocol.as_ref() as *const InputProtocol as *mut simple_text_input::Protocol, + ); + self.stdin = Some(protocol); + } + + pub(crate) fn stdin_inherit(&mut self) { + let st: NonNull = system_table().cast(); + unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) } + } + pub fn stderr(&self) -> io::Result> { match &self.stderr { Some(stderr) => stderr.as_ref().utf8(), @@ -722,6 +778,56 @@ mod uefi_command_internal { } } + #[repr(C)] + pub(crate) struct InputProtocol { + reset: simple_text_input::ProtocolReset, + read_key_stroke: simple_text_input::ProtocolReadKeyStroke, + wait_for_key: r_efi::efi::Event, + } + + impl InputProtocol { + pub(crate) fn null() -> Self { + let evt = helpers::OwnedEvent::new( + r_efi::efi::EVT_NOTIFY_WAIT, + r_efi::efi::TPL_CALLBACK, + Some(Self::empty_notify), + None, + ) + .unwrap(); + + Self { + reset: Self::null_reset, + read_key_stroke: Self::null_read_key, + wait_for_key: evt.into_raw(), + } + } + + extern "efiapi" fn null_reset( + _: *mut simple_text_input::Protocol, + _: r_efi::efi::Boolean, + ) -> r_efi::efi::Status { + r_efi::efi::Status::SUCCESS + } + + extern "efiapi" fn null_read_key( + _: *mut simple_text_input::Protocol, + _: *mut simple_text_input::InputKey, + ) -> r_efi::efi::Status { + r_efi::efi::Status::UNSUPPORTED + } + + extern "efiapi" fn empty_notify(_: r_efi::efi::Event, _: *mut crate::ffi::c_void) {} + } + + impl Drop for InputProtocol { + fn drop(&mut self) { + // Close wait_for_key + unsafe { + let _ = helpers::OwnedEvent::from_raw(self.wait_for_key); + } + } + } + pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> { const QUOTE: u16 = 0x0022; const SPACE: u16 = 0x0020; From af25995d11f8630a071a7f4776f0798d22942a9f Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 13 Apr 2025 20:11:44 +0530 Subject: [PATCH 107/222] std: sys: stdio: uefi: Tread UNSUPPORTED Status as read(0) Allows implementing Stdio::Null for Command in a deterministic manner. Signed-off-by: Ayush Singh --- library/std/src/sys/stdio/uefi.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/stdio/uefi.rs b/library/std/src/sys/stdio/uefi.rs index 257e321dd03d..ccd6bf658b0f 100644 --- a/library/std/src/sys/stdio/uefi.rs +++ b/library/std/src/sys/stdio/uefi.rs @@ -142,8 +142,12 @@ impl io::Write for Stderr { // UTF-16 character should occupy 4 bytes at most in UTF-8 pub const STDIN_BUF_SIZE: usize = 4; -pub fn is_ebadf(_err: &io::Error) -> bool { - false +pub fn is_ebadf(err: &io::Error) -> bool { + if let Some(x) = err.raw_os_error() { + r_efi::efi::Status::UNSUPPORTED.as_usize() == x + } else { + false + } } pub fn panic_output() -> Option { From d994fef7495ecbc1e18c95588253869f3a765edf Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 10 Apr 2025 10:40:50 +0530 Subject: [PATCH 108/222] std: sys: process: uefi: Allow specifying Stdin Stdio::MakePipe is not supported. For Stdio::Null, return UNSUPPORTED. This is treated as read(0). Additionally, have infinte loop on the notify function to prevent wait_for_key from returning. Signed-off-by: Ayush Singh --- library/std/src/sys/process/uefi.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index fb5aa5ca2669..5f922292d054 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -23,6 +23,7 @@ pub struct Command { args: Vec, stdout: Option, stderr: Option, + stdin: Option, env: CommandEnv, } @@ -48,6 +49,7 @@ impl Command { args: Vec::new(), stdout: None, stderr: None, + stdin: None, env: Default::default(), } } @@ -64,8 +66,8 @@ impl Command { panic!("unsupported") } - pub fn stdin(&mut self, _stdin: Stdio) { - panic!("unsupported") + pub fn stdin(&mut self, stdin: Stdio) { + self.stdin = Some(stdin); } pub fn stdout(&mut self, stdout: Stdio) { @@ -166,7 +168,8 @@ impl Command { }; // Setup Stdin - let stdin = Self::create_stdin(Stdio::Null)?; + let stdin = self.stdin.unwrap_or(Stdio::Null); + let stdin = Self::create_stdin(stdin)?; if let Some(con) = stdin { cmd.stdin_init(con) } else { From 93bee0789a45ea7d5d65bb9301c4ad5ece3abeb2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 12 Apr 2025 22:40:34 +0300 Subject: [PATCH 109/222] UI tests: migrate remaining compile time `error-pattern`s to line annotations when possible. --- tests/incremental/const-generic-type-cycle.rs | 5 +- tests/incremental/delayed_span_bug.rs | 3 +- tests/incremental/link_order/main.rs | 3 +- tests/rustdoc-ui/deprecated-attrs.rs | 1 - tests/rustdoc-ui/deprecated-attrs.stderr | 6 +- tests/rustdoc-ui/invalid-theme-name.rs | 2 +- .../ui-fulldeps/missing-rustc-driver-error.rs | 8 +- tests/ui/abi/fixed_x18.rs | 1 - tests/ui/associated-types/issue-36499.rs | 2 - tests/ui/associated-types/issue-36499.stderr | 2 +- tests/ui/check-cfg/cargo-feature.rs | 3 +- .../codegen/empty-static-libs-issue-108825.rs | 4 +- .../cfg-arg-invalid-1.rs | 6 +- .../cfg-arg-invalid-2.rs | 6 +- .../cfg-arg-invalid-4.rs | 6 +- .../cfg-arg-invalid-6.rs | 6 +- .../cfg-arg-invalid-8.rs | 6 +- .../cfg-arg-invalid-9.rs | 6 +- .../cfg-empty-codemap.rs | 6 +- tests/ui/consts/miri_unleashed/drop.rs | 3 +- tests/ui/consts/miri_unleashed/drop.stderr | 4 +- tests/ui/debuginfo/dwarf-versions.rs | 1 - .../error-codes/E0152-duplicate-lang-items.rs | 4 +- .../E0152-duplicate-lang-items.stderr | 3 +- tests/ui/error-codes/E0602.rs | 6 +- .../extern-flag/invalid-crate-name-dashed.rs | 2 +- tests/ui/issues/issue-37131.rs | 3 +- .../layout/unknown-when-no-type-parameter.rs | 4 +- .../unknown-when-no-type-parameter.stderr | 2 +- .../suggest-libname-only-1.rs | 3 +- .../suggest-libname-only-1.stderr | 2 +- .../suggest-libname-only-2.rs | 3 +- .../suggest-libname-only-2.stderr | 2 +- tests/ui/lint/cli-unknown-force-warn.rs | 6 +- tests/ui/lint/lint-removed-cmdline-deny.rs | 6 +- .../ui/lint/lint-removed-cmdline-deny.stderr | 4 +- tests/ui/lint/lint-removed-cmdline.rs | 6 +- tests/ui/lint/lint-removed-cmdline.stderr | 4 +- tests/ui/lint/lint-renamed-cmdline-deny.rs | 9 +- .../ui/lint/lint-renamed-cmdline-deny.stderr | 4 +- tests/ui/lint/lint-renamed-cmdline.rs | 6 +- tests/ui/lint/lint-renamed-cmdline.stderr | 4 +- .../ui/lint/lint-unknown-lint-cmdline-deny.rs | 11 +- tests/ui/lint/lint-unknown-lint-cmdline.rs | 11 +- tests/ui/lint/non-local-defs/cargo-update.rs | 3 +- tests/ui/missing/missing-return.rs | 5 +- tests/ui/missing/missing-return.stderr | 2 +- tests/ui/nested-ty-params.rs | 1 - tests/ui/nested-ty-params.stderr | 4 +- tests/ui/no_std/no-std-no-start-binary.rs | 1 - tests/ui/optimization-remark.rs | 5 +- .../packed/packed-struct-generic-transmute.rs | 2 - .../packed-struct-generic-transmute.stderr | 2 +- tests/ui/packed/packed-struct-transmute.rs | 1 - .../ui/packed/packed-struct-transmute.stderr | 2 +- tests/ui/parser/utf16-be-without-bom.rs | Bin 202 -> 183 bytes tests/ui/parser/utf16-le-without-bom.rs | Bin 203 -> 184 bytes tests/ui/print-request/print-lints-help.rs | 5 +- tests/ui/proc-macro/inner-attrs.rs | 9 +- tests/ui/proc-macro/inner-attrs.stderr | 8 +- tests/ui/proc-macro/inner-attrs.stdout | 806 +++++++++--------- ...region-invariant-static-error-reporting.rs | 3 +- .../forbidden-target-feature-flag-disable.rs | 2 +- .../tied-features-no-implication-1.rs | 2 - .../deny-unstable-lint-command-line.rs | 3 +- ...warn-unknown-unstable-lint-command-line.rs | 3 +- 66 files changed, 546 insertions(+), 518 deletions(-) diff --git a/tests/incremental/const-generic-type-cycle.rs b/tests/incremental/const-generic-type-cycle.rs index cd0437f7ef66..40a40ebd13fe 100644 --- a/tests/incremental/const-generic-type-cycle.rs +++ b/tests/incremental/const-generic-type-cycle.rs @@ -3,7 +3,6 @@ // //@ compile-flags: -Zincremental-ignore-spans //@ revisions: cpass cfail -//@ error-pattern: cycle detected when computing type of `Bar::N` #![feature(trait_alias)] #![crate_type="lib"] @@ -13,5 +12,9 @@ trait Bar {} #[cfg(cfail)] trait Bar {} +//[cfail]~^ ERROR cycle detected when computing type of `Bar::N` +//[cfail]~| ERROR cycle detected when computing type of `Bar::N` +//[cfail]~| ERROR cycle detected when computing type of `Bar::N` +//[cfail]~| ERROR `(dyn Bar<{ 2 + 1 }> + 'static)` is forbidden as the type of a const generic parameter trait BB = Bar<{ 2 + 1 }>; diff --git a/tests/incremental/delayed_span_bug.rs b/tests/incremental/delayed_span_bug.rs index 1534aca5dddf..7b409db2e18e 100644 --- a/tests/incremental/delayed_span_bug.rs +++ b/tests/incremental/delayed_span_bug.rs @@ -1,8 +1,7 @@ //@ revisions: cfail1 cfail2 //@ should-ice -//@ error-pattern: delayed bug triggered by #[rustc_delayed_bug_from_inside_query] #![feature(rustc_attrs)] #[rustc_delayed_bug_from_inside_query] -fn main() {} +fn main() {} //~ ERROR delayed bug triggered by #[rustc_delayed_bug_from_inside_query] diff --git a/tests/incremental/link_order/main.rs b/tests/incremental/link_order/main.rs index 847a47a75598..20931e25dd4b 100644 --- a/tests/incremental/link_order/main.rs +++ b/tests/incremental/link_order/main.rs @@ -1,5 +1,4 @@ //@ aux-build:my_lib.rs -//@ error-pattern: error: linking with //@ revisions:cfail1 cfail2 //@ compile-flags:-Z query-dep-graph @@ -10,3 +9,5 @@ extern crate my_lib; fn main() {} + +//~? ERROR linking with diff --git a/tests/rustdoc-ui/deprecated-attrs.rs b/tests/rustdoc-ui/deprecated-attrs.rs index 0ae65a5eaf7c..dcf8a52de41d 100644 --- a/tests/rustdoc-ui/deprecated-attrs.rs +++ b/tests/rustdoc-ui/deprecated-attrs.rs @@ -1,5 +1,4 @@ //@ compile-flags: --passes unknown-pass -//@ error-pattern: the `passes` flag no longer functions #![doc(no_default_passes)] //~^ ERROR unknown `doc` attribute `no_default_passes` diff --git a/tests/rustdoc-ui/deprecated-attrs.stderr b/tests/rustdoc-ui/deprecated-attrs.stderr index a30523e73297..3e9820522338 100644 --- a/tests/rustdoc-ui/deprecated-attrs.stderr +++ b/tests/rustdoc-ui/deprecated-attrs.stderr @@ -4,7 +4,7 @@ warning: the `passes` flag no longer functions = help: you may want to use --document-private-items error: unknown `doc` attribute `no_default_passes` - --> $DIR/deprecated-attrs.rs:4:8 + --> $DIR/deprecated-attrs.rs:3:8 | LL | #![doc(no_default_passes)] | ^^^^^^^^^^^^^^^^^ no longer functions @@ -15,7 +15,7 @@ LL | #![doc(no_default_passes)] = note: `#[deny(invalid_doc_attributes)]` on by default error: unknown `doc` attribute `passes` - --> $DIR/deprecated-attrs.rs:11:8 + --> $DIR/deprecated-attrs.rs:10:8 | LL | #![doc(passes = "collapse-docs unindent-comments")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no longer functions @@ -25,7 +25,7 @@ LL | #![doc(passes = "collapse-docs unindent-comments")] = note: `doc(passes)` is now a no-op error: unknown `doc` attribute `plugins` - --> $DIR/deprecated-attrs.rs:17:8 + --> $DIR/deprecated-attrs.rs:16:8 | LL | #![doc(plugins = "xxx")] | ^^^^^^^^^^^^^^^ no longer functions diff --git a/tests/rustdoc-ui/invalid-theme-name.rs b/tests/rustdoc-ui/invalid-theme-name.rs index 7f1d191c89de..22b5e616a3d4 100644 --- a/tests/rustdoc-ui/invalid-theme-name.rs +++ b/tests/rustdoc-ui/invalid-theme-name.rs @@ -1,4 +1,4 @@ //@ compile-flags:--theme {{src-base}}/invalid-theme-name.rs -//@ error-pattern: must have a .css extension //~? ERROR invalid argument: "$DIR/invalid-theme-name.rs" +//~? HELP must have a .css extension diff --git a/tests/ui-fulldeps/missing-rustc-driver-error.rs b/tests/ui-fulldeps/missing-rustc-driver-error.rs index d582efada908..c6dff2d99dde 100644 --- a/tests/ui-fulldeps/missing-rustc-driver-error.rs +++ b/tests/ui-fulldeps/missing-rustc-driver-error.rs @@ -1,11 +1,15 @@ // Test that we get the following hint when trying to use a compiler crate without rustc_driver. -//@ error-pattern: try adding `extern crate rustc_driver;` at the top level of this crate -//@ compile-flags: --emit link --error-format=human +//@ compile-flags: --emit link //@ normalize-stderr: ".*crate .* required.*\n\n" -> "" //@ normalize-stderr: "aborting due to [0-9]+" -> "aborting due to NUMBER" +//@ dont-require-annotations: ERROR #![feature(rustc_private)] extern crate rustc_serialize; fn main() {} + +//~? HELP try adding `extern crate rustc_driver;` at the top level of this crate +//~? HELP try adding `extern crate rustc_driver;` at the top level of this crate +//~? HELP try adding `extern crate rustc_driver;` at the top level of this crate diff --git a/tests/ui/abi/fixed_x18.rs b/tests/ui/abi/fixed_x18.rs index d373468f68fe..d64b845e5bd1 100644 --- a/tests/ui/abi/fixed_x18.rs +++ b/tests/ui/abi/fixed_x18.rs @@ -2,7 +2,6 @@ // Behavior on aarch64 is tested by tests/codegen/fixed-x18.rs. // //@ revisions: x64 i686 arm riscv32 riscv64 -//@ error-pattern: the `-Zfixed-x18` flag is not supported //@ dont-check-compiler-stderr // //@ compile-flags: -Zfixed-x18 diff --git a/tests/ui/associated-types/issue-36499.rs b/tests/ui/associated-types/issue-36499.rs index 606918b40b70..941b1aaa0d54 100644 --- a/tests/ui/associated-types/issue-36499.rs +++ b/tests/ui/associated-types/issue-36499.rs @@ -1,5 +1,3 @@ -//@ error-pattern: aborting due to 1 previous error - fn main() { 2 + +2; //~ ERROR leading `+` is not supported } diff --git a/tests/ui/associated-types/issue-36499.stderr b/tests/ui/associated-types/issue-36499.stderr index dd91bac81586..aebf0faae2dc 100644 --- a/tests/ui/associated-types/issue-36499.stderr +++ b/tests/ui/associated-types/issue-36499.stderr @@ -1,5 +1,5 @@ error: leading `+` is not supported - --> $DIR/issue-36499.rs:4:9 + --> $DIR/issue-36499.rs:2:9 | LL | 2 + +2; | ^ unexpected `+` diff --git a/tests/ui/check-cfg/cargo-feature.rs b/tests/ui/check-cfg/cargo-feature.rs index a9380ddae1a9..a02b0437057f 100644 --- a/tests/ui/check-cfg/cargo-feature.rs +++ b/tests/ui/check-cfg/cargo-feature.rs @@ -10,7 +10,7 @@ //@ [none]compile-flags: --check-cfg=cfg(feature,values()) //@ [some]compile-flags: --check-cfg=cfg(feature,values("bitcode")) //@ [some]compile-flags: --check-cfg=cfg(CONFIG_NVME,values("y")) -//@ [none]error-pattern:Cargo.toml +//@ dont-require-annotations: HELP #[cfg(feature = "serde")] //~^ WARNING unexpected `cfg` condition value @@ -27,6 +27,7 @@ fn tokio() {} #[cfg(CONFIG_NVME = "m")] //[none]~^ WARNING unexpected `cfg` condition name //[some]~^^ WARNING unexpected `cfg` condition value +//[none]~| HELP Cargo.toml fn tokio() {} fn main() {} diff --git a/tests/ui/codegen/empty-static-libs-issue-108825.rs b/tests/ui/codegen/empty-static-libs-issue-108825.rs index 46bd6d6b2da4..4c644be0954e 100644 --- a/tests/ui/codegen/empty-static-libs-issue-108825.rs +++ b/tests/ui/codegen/empty-static-libs-issue-108825.rs @@ -3,7 +3,6 @@ //@ compile-flags: -Cpanic=abort --print=native-static-libs //@ build-pass -//@ error-pattern: note: native-static-libs: //@ dont-check-compiler-stderr (libcore links `/defaultlib:msvcrt` or `/defaultlib:libcmt` on MSVC) //@ ignore-pass (the note is emitted later in the compilation pipeline, needs build) @@ -14,3 +13,6 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } + +//~? NOTE native-static-libs: +//~? NOTE Link against the following native artifacts when linking against this static library diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs index cd181f4a49f6..28d2d266b623 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg a(b=c) -//@ error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") +//@ compile-flags: --cfg a(b=c) + fn main() {} + +//~? ERROR invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs index a0c16bd1f80a..a46022602e27 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg a{b} -//@ error-pattern: invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`) +//@ compile-flags: --cfg a{b} + fn main() {} + +//~? ERROR invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`) diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs index 30402d51852f..ba34708c171b 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg a(b) -//@ error-pattern: invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`) +//@ compile-flags: --cfg a(b) + fn main() {} + +//~? ERROR invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`) diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs index e0ce66eab877..2c2fc105958a 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg a{ -//@ error-pattern: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`) +//@ compile-flags: --cfg a{ + fn main() {} + +//~? ERROR invalid `--cfg` argument: `a{` (expected `key` or `key="value"`) diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs index 33f8da25830e..c9185fc7b259 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs @@ -1,3 +1,5 @@ -//@ compile-flags: --error-format=human --cfg ) -//@ error-pattern: invalid `--cfg` argument: `)` (expected `key` or `key="value"`) +//@ compile-flags: --cfg ) + fn main() {} + +//~? ERROR invalid `--cfg` argument: `)` (expected `key` or `key="value"`) diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs index 8ab3b101da79..8d07165dfae4 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs @@ -1,4 +1,6 @@ // Test for missing quotes around value, issue #66450. -//@ compile-flags: --error-format=human --cfg key=value -//@ error-pattern: invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") +//@ compile-flags: --cfg key=value + fn main() {} + +//~? ERROR invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") diff --git a/tests/ui/conditional-compilation/cfg-empty-codemap.rs b/tests/ui/conditional-compilation/cfg-empty-codemap.rs index d8fc02777595..9f7ef1bcf9aa 100644 --- a/tests/ui/conditional-compilation/cfg-empty-codemap.rs +++ b/tests/ui/conditional-compilation/cfg-empty-codemap.rs @@ -1,8 +1,8 @@ // Tests that empty source_maps don't ICE (#23301) -//@ compile-flags: --error-format=human --cfg "" - -//@ error-pattern: invalid `--cfg` argument: `""` (expected `key` or `key="value"`) +//@ compile-flags: --cfg "" pub fn main() { } + +//~? ERROR invalid `--cfg` argument: `""` (expected `key` or `key="value"`) diff --git a/tests/ui/consts/miri_unleashed/drop.rs b/tests/ui/consts/miri_unleashed/drop.rs index 17d089222d96..190072d9c206 100644 --- a/tests/ui/consts/miri_unleashed/drop.rs +++ b/tests/ui/consts/miri_unleashed/drop.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Zunleash-the-miri-inside-of-you -//@ error-pattern: calling non-const function ` as Drop>::drop` use std::mem::ManuallyDrop; @@ -15,5 +14,7 @@ static TEST_OK: () = { static TEST_BAD: () = { let _v: Vec = Vec::new(); }; //~ ERROR could not evaluate static initializer + //~| NOTE calling non-const function ` as Drop>::drop` + //~| NOTE inside `std::ptr::drop_in_place::> - shim(Some(Vec))` //~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/drop.stderr b/tests/ui/consts/miri_unleashed/drop.stderr index 40a29d5a819a..f9ff5491ea6c 100644 --- a/tests/ui/consts/miri_unleashed/drop.stderr +++ b/tests/ui/consts/miri_unleashed/drop.stderr @@ -1,5 +1,5 @@ error[E0080]: could not evaluate static initializer - --> $DIR/drop.rs:17:1 + --> $DIR/drop.rs:16:1 | LL | }; | ^ calling non-const function ` as Drop>::drop` @@ -10,7 +10,7 @@ note: inside `std::ptr::drop_in_place::> - shim(Some(Vec))` warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/drop.rs:16:9 + --> $DIR/drop.rs:15:9 | LL | let _v: Vec = Vec::new(); | ^^ diff --git a/tests/ui/debuginfo/dwarf-versions.rs b/tests/ui/debuginfo/dwarf-versions.rs index 6030b2fcf3cd..bb18cadce435 100644 --- a/tests/ui/debuginfo/dwarf-versions.rs +++ b/tests/ui/debuginfo/dwarf-versions.rs @@ -6,7 +6,6 @@ //@[zero] compile-flags: -Zdwarf-version=0 //@[one] compile-flags: -Zdwarf-version=1 -//@[one] error-pattern: requested DWARF version 1 is not supported //@[two] compile-flags: -Zdwarf-version=2 //@[two] check-pass diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.rs b/tests/ui/error-codes/E0152-duplicate-lang-items.rs index 089810b1ad24..f707b72f9b2b 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.rs +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.rs @@ -3,8 +3,9 @@ //! //! Issue: -//@ error-pattern: first defined in crate `std` //@ normalize-stderr: "loaded from .*libstd-.*.rlib" -> "loaded from SYSROOT/libstd-*.rlib" +//@ dont-require-annotations: NOTE + #![feature(lang_items)] extern crate core; @@ -14,6 +15,7 @@ use core::panic::PanicInfo; #[lang = "panic_impl"] fn panic_impl(info: &PanicInfo) -> ! { //~^ ERROR: found duplicate lang item `panic_impl` + //~| NOTE first defined in crate `std` loop {} } diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr index 3c3d64322f3c..2fe0d18fc2f4 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr @@ -1,8 +1,9 @@ error[E0152]: found duplicate lang item `panic_impl` - --> $DIR/E0152-duplicate-lang-items.rs:15:1 + --> $DIR/E0152-duplicate-lang-items.rs:16:1 | LL | / fn panic_impl(info: &PanicInfo) -> ! { LL | | +LL | | LL | | loop {} LL | | } | |_^ diff --git a/tests/ui/error-codes/E0602.rs b/tests/ui/error-codes/E0602.rs index cba15bb92d45..381bd1ffb54c 100644 --- a/tests/ui/error-codes/E0602.rs +++ b/tests/ui/error-codes/E0602.rs @@ -1,11 +1,11 @@ //@ compile-flags:-D bogus //@ check-pass - -//@ error-pattern:requested on the command line with `-D bogus` -//@ error-pattern:`#[warn(unknown_lints)]` on by default +//@ dont-require-annotations: NOTE fn main() {} //~? WARN unknown lint: `bogus` //~? WARN unknown lint: `bogus` //~? WARN unknown lint: `bogus` +//~? NOTE requested on the command line with `-D bogus` +//~? NOTE `#[warn(unknown_lints)]` on by default diff --git a/tests/ui/extern-flag/invalid-crate-name-dashed.rs b/tests/ui/extern-flag/invalid-crate-name-dashed.rs index b336cc84569e..bbf473cc5142 100644 --- a/tests/ui/extern-flag/invalid-crate-name-dashed.rs +++ b/tests/ui/extern-flag/invalid-crate-name-dashed.rs @@ -1,5 +1,4 @@ //@ compile-flags: --extern=my-awesome-library=libawesome.rlib -//@ error-pattern: consider replacing the dashes with underscores: `my_awesome_library` // In a sense, this is a regression test for issue #113035. We no longer suggest // `pub use my-awesome-library::*;` (sic!) as we outright ban this crate name. @@ -9,3 +8,4 @@ pub use my_awesome_library::*; fn main() {} //~? ERROR crate name `my-awesome-library` passed to `--extern` is not a valid ASCII identifier +//~? HELP consider replacing the dashes with underscores: `my_awesome_library` diff --git a/tests/ui/issues/issue-37131.rs b/tests/ui/issues/issue-37131.rs index 16681ac21d11..e91c76e1390e 100644 --- a/tests/ui/issues/issue-37131.rs +++ b/tests/ui/issues/issue-37131.rs @@ -1,4 +1,6 @@ //~ ERROR can't find crate for `std` +//~| NOTE target may not be installed +//~| NOTE can't find crate // Tests that compiling for a target which is not installed will result in a helpful // error message. @@ -6,5 +8,4 @@ //@ ignore-arm //@ needs-llvm-components: arm -//@ error-pattern:target may not be installed fn main() { } diff --git a/tests/ui/layout/unknown-when-no-type-parameter.rs b/tests/ui/layout/unknown-when-no-type-parameter.rs index 500b7938eeb0..87f90aa438ab 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.rs +++ b/tests/ui/layout/unknown-when-no-type-parameter.rs @@ -1,13 +1,13 @@ #![feature(trivial_bounds)] -//@ error-pattern: the type `<() as Project>::Assoc` has an unknown layout - trait Project { type Assoc; } fn foo() where (): Project { [(); size_of::<<() as Project>::Assoc>()]; //~ ERROR evaluation of constant value failed + //~| NOTE the type `<() as Project>::Assoc` has an unknown layout + //~| NOTE inside `std::mem::size_of::<<() as Project>::Assoc>` } fn main() {} diff --git a/tests/ui/layout/unknown-when-no-type-parameter.stderr b/tests/ui/layout/unknown-when-no-type-parameter.stderr index a2dbb191ee27..35fbb11f156a 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.stderr +++ b/tests/ui/layout/unknown-when-no-type-parameter.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/unknown-when-no-type-parameter.rs:10:10 + --> $DIR/unknown-when-no-type-parameter.rs:8:10 | LL | [(); size_of::<<() as Project>::Assoc>()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `<() as Project>::Assoc` has an unknown layout diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.rs b/tests/ui/link-native-libs/suggest-libname-only-1.rs index 4ccfa086bde6..c69949d1fdb3 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-1.rs +++ b/tests/ui/link-native-libs/suggest-libname-only-1.rs @@ -1,10 +1,11 @@ //@ build-fail //@ compile-flags: --crate-type rlib -//@ error-pattern: only provide the library name `foo`, not the full filename #[link(name = "libfoo.a", kind = "static")] extern { } //~ WARN extern declarations without an explicit ABI are deprecated + //~| HELP explicitly specify the "C" ABI pub fn main() { } //~? ERROR could not find native static library `libfoo.a` +//~? HELP only provide the library name `foo`, not the full filename diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.stderr b/tests/ui/link-native-libs/suggest-libname-only-1.stderr index 85a3599e8dbd..0320294a8004 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-1.stderr +++ b/tests/ui/link-native-libs/suggest-libname-only-1.stderr @@ -1,5 +1,5 @@ warning: extern declarations without an explicit ABI are deprecated - --> $DIR/suggest-libname-only-1.rs:6:1 + --> $DIR/suggest-libname-only-1.rs:5:1 | LL | extern { } | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.rs b/tests/ui/link-native-libs/suggest-libname-only-2.rs index c35b4a674b77..d5150c327cd5 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-2.rs +++ b/tests/ui/link-native-libs/suggest-libname-only-2.rs @@ -1,10 +1,11 @@ //@ build-fail //@ compile-flags: --crate-type rlib -//@ error-pattern: only provide the library name `bar`, not the full filename #[link(name = "bar.lib", kind = "static")] extern { } //~ WARN extern declarations without an explicit ABI are deprecated + //~| HELP explicitly specify the "C" ABI pub fn main() { } //~? ERROR could not find native static library `bar.lib` +//~? HELP only provide the library name `bar`, not the full filename diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.stderr b/tests/ui/link-native-libs/suggest-libname-only-2.stderr index d5c88931ad54..e492aea27b45 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-2.stderr +++ b/tests/ui/link-native-libs/suggest-libname-only-2.stderr @@ -1,5 +1,5 @@ warning: extern declarations without an explicit ABI are deprecated - --> $DIR/suggest-libname-only-2.rs:6:1 + --> $DIR/suggest-libname-only-2.rs:5:1 | LL | extern { } | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/lint/cli-unknown-force-warn.rs b/tests/ui/lint/cli-unknown-force-warn.rs index 330d5570e21b..0c60f48c5142 100644 --- a/tests/ui/lint/cli-unknown-force-warn.rs +++ b/tests/ui/lint/cli-unknown-force-warn.rs @@ -3,12 +3,12 @@ //@ check-pass //@ compile-flags: --force-warn foo-qux - -//@ error-pattern: requested on the command line with `--force-warn foo_qux` -//@ error-pattern: `#[warn(unknown_lints)]` on by default +//@ dont-require-annotations: NOTE fn main() {} //~? WARN unknown lint: `foo_qux` //~? WARN unknown lint: `foo_qux` //~? WARN unknown lint: `foo_qux` +//~? NOTE requested on the command line with `--force-warn foo_qux` +//~? NOTE `#[warn(unknown_lints)]` on by default diff --git a/tests/ui/lint/lint-removed-cmdline-deny.rs b/tests/ui/lint/lint-removed-cmdline-deny.rs index 6616781d5cb7..83bbd248aa0c 100644 --- a/tests/ui/lint/lint-removed-cmdline-deny.rs +++ b/tests/ui/lint/lint-removed-cmdline-deny.rs @@ -2,9 +2,7 @@ // cc #30346 //@ compile-flags:-D renamed-and-removed-lints -D raw_pointer_derive - -//@ error-pattern:requested on the command line with `-D raw_pointer_derive` -//@ error-pattern:requested on the command line with `-D renamed-and-removed-lints` +//@ dont-require-annotations: NOTE #![warn(unused)] @@ -14,3 +12,5 @@ fn main() { let unused = (); } //~ ERROR unused variable: `unused` //~? ERROR lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok //~? ERROR lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok //~? ERROR lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +//~? NOTE requested on the command line with `-D raw_pointer_derive` +//~? NOTE requested on the command line with `-D renamed-and-removed-lints` diff --git a/tests/ui/lint/lint-removed-cmdline-deny.stderr b/tests/ui/lint/lint-removed-cmdline-deny.stderr index 27a3504a16a7..2fb237339cd8 100644 --- a/tests/ui/lint/lint-removed-cmdline-deny.stderr +++ b/tests/ui/lint/lint-removed-cmdline-deny.stderr @@ -14,13 +14,13 @@ error: lint `raw_pointer_derive` has been removed: using derive with raw pointer = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused variable: `unused` - --> $DIR/lint-removed-cmdline-deny.rs:12:17 + --> $DIR/lint-removed-cmdline-deny.rs:10:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-removed-cmdline-deny.rs:11:8 + --> $DIR/lint-removed-cmdline-deny.rs:9:8 | LL | #[deny(warnings)] | ^^^^^^^^ diff --git a/tests/ui/lint/lint-removed-cmdline.rs b/tests/ui/lint/lint-removed-cmdline.rs index 4dde3dbc3817..f83747a3a6be 100644 --- a/tests/ui/lint/lint-removed-cmdline.rs +++ b/tests/ui/lint/lint-removed-cmdline.rs @@ -2,9 +2,7 @@ // cc #30346 //@ compile-flags:-D raw_pointer_derive - -//@ error-pattern:`#[warn(renamed_and_removed_lints)]` on by default -//@ error-pattern:requested on the command line with `-D raw_pointer_derive` +//@ dont-require-annotations: NOTE #![warn(unused)] @@ -14,3 +12,5 @@ fn main() { let unused = (); } //~ ERROR unused variable: `unused` //~? WARN lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok //~? WARN lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok //~? WARN lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +//~? NOTE `#[warn(renamed_and_removed_lints)]` on by default +//~? NOTE requested on the command line with `-D raw_pointer_derive` diff --git a/tests/ui/lint/lint-removed-cmdline.stderr b/tests/ui/lint/lint-removed-cmdline.stderr index 7994f9bcfd91..64e7c572ca73 100644 --- a/tests/ui/lint/lint-removed-cmdline.stderr +++ b/tests/ui/lint/lint-removed-cmdline.stderr @@ -14,13 +14,13 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw point = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused variable: `unused` - --> $DIR/lint-removed-cmdline.rs:12:17 + --> $DIR/lint-removed-cmdline.rs:10:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-removed-cmdline.rs:11:8 + --> $DIR/lint-removed-cmdline.rs:9:8 | LL | #[deny(warnings)] | ^^^^^^^^ diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.rs b/tests/ui/lint/lint-renamed-cmdline-deny.rs index 0ea4ce408175..c8b035078154 100644 --- a/tests/ui/lint/lint-renamed-cmdline-deny.rs +++ b/tests/ui/lint/lint-renamed-cmdline-deny.rs @@ -1,8 +1,6 @@ //@ compile-flags:-D renamed-and-removed-lints -D bare_trait_object - -//@ error-pattern:use the new name `bare_trait_objects` -//@ error-pattern:requested on the command line with `-D bare_trait_object` -//@ error-pattern:requested on the command line with `-D renamed-and-removed-lints` +//@ dont-require-annotations: HELP +//@ dont-require-annotations: NOTE #[deny(unused)] fn main() { let unused = (); } //~ ERROR unused variable: `unused` @@ -10,3 +8,6 @@ fn main() { let unused = (); } //~ ERROR unused variable: `unused` //~? ERROR lint `bare_trait_object` has been renamed to `bare_trait_objects` //~? ERROR lint `bare_trait_object` has been renamed to `bare_trait_objects` //~? ERROR lint `bare_trait_object` has been renamed to `bare_trait_objects` +//~? HELP use the new name `bare_trait_objects` +//~? NOTE requested on the command line with `-D bare_trait_object` +//~? NOTE requested on the command line with `-D renamed-and-removed-lints` diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.stderr b/tests/ui/lint/lint-renamed-cmdline-deny.stderr index a49cdc84f9e4..b42b82834c19 100644 --- a/tests/ui/lint/lint-renamed-cmdline-deny.stderr +++ b/tests/ui/lint/lint-renamed-cmdline-deny.stderr @@ -17,13 +17,13 @@ error: lint `bare_trait_object` has been renamed to `bare_trait_objects` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused variable: `unused` - --> $DIR/lint-renamed-cmdline-deny.rs:8:17 + --> $DIR/lint-renamed-cmdline-deny.rs:6:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-renamed-cmdline-deny.rs:7:8 + --> $DIR/lint-renamed-cmdline-deny.rs:5:8 | LL | #[deny(unused)] | ^^^^^^ diff --git a/tests/ui/lint/lint-renamed-cmdline.rs b/tests/ui/lint/lint-renamed-cmdline.rs index 45df7b6d640d..757cb514267c 100644 --- a/tests/ui/lint/lint-renamed-cmdline.rs +++ b/tests/ui/lint/lint-renamed-cmdline.rs @@ -1,7 +1,5 @@ //@ compile-flags:-D bare_trait_object - -//@ error-pattern:requested on the command line with `-D bare_trait_object` -//@ error-pattern:`#[warn(renamed_and_removed_lints)]` on by default +//@ dont-require-annotations: NOTE #[deny(unused)] fn main() { let unused = (); } //~ ERROR unused variable: `unused` @@ -9,3 +7,5 @@ fn main() { let unused = (); } //~ ERROR unused variable: `unused` //~? WARN lint `bare_trait_object` has been renamed to `bare_trait_objects` //~? WARN lint `bare_trait_object` has been renamed to `bare_trait_objects` //~? WARN lint `bare_trait_object` has been renamed to `bare_trait_objects` +//~? NOTE requested on the command line with `-D bare_trait_object` +//~? NOTE `#[warn(renamed_and_removed_lints)]` on by default diff --git a/tests/ui/lint/lint-renamed-cmdline.stderr b/tests/ui/lint/lint-renamed-cmdline.stderr index 901e7a642d1f..efd399e21694 100644 --- a/tests/ui/lint/lint-renamed-cmdline.stderr +++ b/tests/ui/lint/lint-renamed-cmdline.stderr @@ -17,13 +17,13 @@ warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused variable: `unused` - --> $DIR/lint-renamed-cmdline.rs:7:17 + --> $DIR/lint-renamed-cmdline.rs:5:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-renamed-cmdline.rs:6:8 + --> $DIR/lint-renamed-cmdline.rs:4:8 | LL | #[deny(unused)] | ^^^^^^ diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs index e2f7c73eacf0..ac001e1b6a04 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs +++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs @@ -1,9 +1,6 @@ //@ compile-flags:-D unknown-lints -D bogus -D dead_cod - -//@ error-pattern:requested on the command line with `-D bogus` -//@ error-pattern:requested on the command line with `-D dead_cod` -//@ error-pattern:requested on the command line with `-D unknown-lints` -//@ error-pattern:did you mean: `dead_code` +//@ dont-require-annotations: HELP +//@ dont-require-annotations: NOTE fn main() { } @@ -13,3 +10,7 @@ fn main() { } //~? ERROR unknown lint: `dead_cod` //~? ERROR unknown lint: `bogus` //~? ERROR unknown lint: `dead_cod` +//~? NOTE requested on the command line with `-D bogus` +//~? NOTE requested on the command line with `-D dead_cod` +//~? NOTE requested on the command line with `-D unknown-lints` +//~? HELP did you mean: `dead_code` diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.rs b/tests/ui/lint/lint-unknown-lint-cmdline.rs index 931e945a1a32..7eb8c1f73142 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline.rs +++ b/tests/ui/lint/lint-unknown-lint-cmdline.rs @@ -1,10 +1,7 @@ //@ check-pass //@ compile-flags:-D bogus -D dead_cod - -//@ error-pattern:requested on the command line with `-D bogus` -//@ error-pattern:`#[warn(unknown_lints)]` on by default -//@ error-pattern:requested on the command line with `-D dead_cod` -//@ error-pattern:did you mean: `dead_code` +//@ dont-require-annotations: HELP +//@ dont-require-annotations: NOTE fn main() { } @@ -14,3 +11,7 @@ fn main() { } //~? WARN unknown lint: `dead_cod` //~? WARN unknown lint: `bogus` //~? WARN unknown lint: `dead_cod` +//~? NOTE requested on the command line with `-D bogus` +//~? NOTE `#[warn(unknown_lints)]` on by default +//~? NOTE requested on the command line with `-D dead_cod` +//~? HELP did you mean: `dead_code` diff --git a/tests/ui/lint/non-local-defs/cargo-update.rs b/tests/ui/lint/non-local-defs/cargo-update.rs index 8b8c15795d37..f778752b28af 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.rs +++ b/tests/ui/lint/non-local-defs/cargo-update.rs @@ -8,7 +8,7 @@ // // and since we specifically want to check the presence // of the `cargo update` suggestion we assert it here. -//@ error-pattern: `cargo update -p non_local_macro` +//@ dont-require-annotations: NOTE extern crate non_local_macro; @@ -16,5 +16,6 @@ struct LocalStruct; non_local_macro::non_local_impl!(LocalStruct); //~^ WARN non-local `impl` definition +//~| NOTE `cargo update -p non_local_macro` fn main() {} diff --git a/tests/ui/missing/missing-return.rs b/tests/ui/missing/missing-return.rs index 5d9839a969c1..4d48e7c13e2c 100644 --- a/tests/ui/missing/missing-return.rs +++ b/tests/ui/missing/missing-return.rs @@ -1,5 +1,4 @@ -//@ error-pattern: return - fn f() -> isize { } //~ ERROR mismatched types - + //~| NOTE implicitly returns `()` as its body has no tail or `return` expression + //~| NOTE expected `isize`, found `()` fn main() { f(); } diff --git a/tests/ui/missing/missing-return.stderr b/tests/ui/missing/missing-return.stderr index 5f7fb504075c..b2d202b9b572 100644 --- a/tests/ui/missing/missing-return.stderr +++ b/tests/ui/missing/missing-return.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/missing-return.rs:3:11 + --> $DIR/missing-return.rs:1:11 | LL | fn f() -> isize { } | - ^^^^^ expected `isize`, found `()` diff --git a/tests/ui/nested-ty-params.rs b/tests/ui/nested-ty-params.rs index 866e6230f9ea..c00c3bc33723 100644 --- a/tests/ui/nested-ty-params.rs +++ b/tests/ui/nested-ty-params.rs @@ -1,4 +1,3 @@ -//@ error-pattern:can't use generic parameters from outer item fn hd(v: Vec ) -> U { fn hd1(w: [U]) -> U { return w[0]; } //~^ ERROR can't use generic parameters from outer item diff --git a/tests/ui/nested-ty-params.stderr b/tests/ui/nested-ty-params.stderr index a9cdec667199..7ca65b421b25 100644 --- a/tests/ui/nested-ty-params.stderr +++ b/tests/ui/nested-ty-params.stderr @@ -1,5 +1,5 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/nested-ty-params.rs:3:16 + --> $DIR/nested-ty-params.rs:2:16 | LL | fn hd(v: Vec ) -> U { | - type parameter from outer item @@ -9,7 +9,7 @@ LL | fn hd1(w: [U]) -> U { return w[0]; } | help: try introducing a local generic parameter here: `` error[E0401]: can't use generic parameters from outer item - --> $DIR/nested-ty-params.rs:3:23 + --> $DIR/nested-ty-params.rs:2:23 | LL | fn hd(v: Vec ) -> U { | - type parameter from outer item diff --git a/tests/ui/no_std/no-std-no-start-binary.rs b/tests/ui/no_std/no-std-no-start-binary.rs index df68b99346af..6853e2d4228f 100644 --- a/tests/ui/no_std/no-std-no-start-binary.rs +++ b/tests/ui/no_std/no-std-no-start-binary.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Cpanic=abort --emit link -//@ error-pattern:using `fn main` requires the standard library // Make sure that we don't emit an error message mentioning internal lang items. diff --git a/tests/ui/optimization-remark.rs b/tests/ui/optimization-remark.rs index ebcf3b40ab25..165fc63c0076 100644 --- a/tests/ui/optimization-remark.rs +++ b/tests/ui/optimization-remark.rs @@ -12,9 +12,8 @@ // //@ [merge1] compile-flags: -Cremark=all -Cremark=giraffe //@ [merge2] compile-flags: -Cremark=inline -Cremark=giraffe -// -//@ error-pattern: inline (missed): 'f' not inlined into 'g' //@ dont-check-compiler-stderr +//@ dont-require-annotations: NOTE #[no_mangle] #[inline(never)] @@ -25,3 +24,5 @@ pub fn f() { pub fn g() { f(); } + +//~? NOTE inline (missed): 'f' not inlined into 'g' diff --git a/tests/ui/packed/packed-struct-generic-transmute.rs b/tests/ui/packed/packed-struct-generic-transmute.rs index 17e72bebc7dc..66972633d800 100644 --- a/tests/ui/packed/packed-struct-generic-transmute.rs +++ b/tests/ui/packed/packed-struct-generic-transmute.rs @@ -3,8 +3,6 @@ // the error points to the start of the file, not the line with the // transmute -//@ error-pattern: cannot transmute between types of different sizes, or dependently-sized types - use std::mem; #[repr(packed)] diff --git a/tests/ui/packed/packed-struct-generic-transmute.stderr b/tests/ui/packed/packed-struct-generic-transmute.stderr index e91f49884298..983742b78be1 100644 --- a/tests/ui/packed/packed-struct-generic-transmute.stderr +++ b/tests/ui/packed/packed-struct-generic-transmute.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/packed-struct-generic-transmute.rs:24:38 + --> $DIR/packed-struct-generic-transmute.rs:22:38 | LL | let oof: Oof<[u8; 5], i32> = mem::transmute(foo); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/packed/packed-struct-transmute.rs b/tests/ui/packed/packed-struct-transmute.rs index 5ad6524ff817..24ac1f4ac41c 100644 --- a/tests/ui/packed/packed-struct-transmute.rs +++ b/tests/ui/packed/packed-struct-transmute.rs @@ -4,7 +4,6 @@ // transmute //@ normalize-stderr: "\d+ bits" -> "N bits" -//@ error-pattern: cannot transmute between types of different sizes, or dependently-sized types use std::mem; diff --git a/tests/ui/packed/packed-struct-transmute.stderr b/tests/ui/packed/packed-struct-transmute.stderr index 4d75820e9449..c5f556f6d0c1 100644 --- a/tests/ui/packed/packed-struct-transmute.stderr +++ b/tests/ui/packed/packed-struct-transmute.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/packed-struct-transmute.rs:26:24 + --> $DIR/packed-struct-transmute.rs:25:24 | LL | let oof: Oof = mem::transmute(foo); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/parser/utf16-be-without-bom.rs b/tests/ui/parser/utf16-be-without-bom.rs index 538728735f06c249c0bff31d9ffc067cc19a2a01..1f2abc1ad5616cf155dd8a747578b1396dab1340 100644 GIT binary patch delta 74 zcmX@bxSergkFtTjzJo$aeqM=gQEFjnW>KncVqRW;Nn%N6eqOPaf@@Hae-Ia!zJ6U< T8H6*@N{XWn#!k_gxIqd4w+tBB delta 140 zcmdnac#5%JU*AC?IX|}`GbdFyEhjO(*h)cHH?^oJzeqPNzbH4c#5SWeH!+V3qz)on zkXTZZT9jv{P@0#WmtUTzP+XE&RHBfdrcjcfor+auYDGb6a!G26LVjK< diff --git a/tests/ui/parser/utf16-le-without-bom.rs b/tests/ui/parser/utf16-le-without-bom.rs index fc413663c9c09ac7b521f8a39e7e856c3067fb0f..bb95f0dd07178ce8768bcf576213f4f9cc3c7d4c 100644 GIT binary patch delta 74 zcmX@jxPx(GkFtTjzJo$aeqM=gQEFjnW>KncVqRW;Nn%N6eqOPaf@@Hae-Ia!zJ6U< T8H6*@N{XWn#!k_gxIr2Kx1Si? delta 140 zcmdnNc$%?ZU*AC?IX|}`GbdFyEhjO(*h)cHH?^oJzeqPNzbH4c#5SWeH!+V3qz)on zkXTZZT9jv{P@0#WmtUTzP+XE&RHBfdrcjcfor+auYDGb6a!G26LVjK $DIR/inner-attrs.rs:65:12 + --> $DIR/inner-attrs.rs:64:12 | LL | #![print_attr] | ^^^^^^^^^^ not a non-macro inner attribute @@ -11,19 +11,19 @@ LL | #![print_attr] | ^^^^^^^^^^ not a non-macro inner attribute error: expected non-macro inner attribute, found attribute macro `print_attr` - --> $DIR/inner-attrs.rs:73:12 + --> $DIR/inner-attrs.rs:74:12 | LL | #![print_attr] | ^^^^^^^^^^ not a non-macro inner attribute error: expected non-macro inner attribute, found attribute macro `print_attr` - --> $DIR/inner-attrs.rs:77:12 + --> $DIR/inner-attrs.rs:79:12 | LL | #![print_attr] | ^^^^^^^^^^ not a non-macro inner attribute warning: extern declarations without an explicit ABI are deprecated - --> $DIR/inner-attrs.rs:82:1 + --> $DIR/inner-attrs.rs:85:1 | LL | extern { | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/proc-macro/inner-attrs.stdout b/tests/ui/proc-macro/inner-attrs.stdout index ed47ee2cf5ac..4496f7b90c4e 100644 --- a/tests/ui/proc-macro/inner-attrs.stdout +++ b/tests/ui/proc-macro/inner-attrs.stdout @@ -2,7 +2,7 @@ PRINT-ATTR_ARGS INPUT (DISPLAY): first PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "first", - span: $DIR/inner-attrs.rs:18:25: 18:30 (#0), + span: $DIR/inner-attrs.rs:17:25: 17:30 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(second)] fn foo() @@ -13,44 +13,74 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/inner-attrs.rs:19:1: 19:2 (#0), + span: $DIR/inner-attrs.rs:18:1: 18:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:19:3: 19:24 (#0), + span: $DIR/inner-attrs.rs:18:3: 18:24 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "second", - span: $DIR/inner-attrs.rs:19:25: 19:31 (#0), + span: $DIR/inner-attrs.rs:18:25: 18:31 (#0), }, ], - span: $DIR/inner-attrs.rs:19:24: 19:32 (#0), + span: $DIR/inner-attrs.rs:18:24: 18:32 (#0), }, ], - span: $DIR/inner-attrs.rs:19:2: 19:33 (#0), + span: $DIR/inner-attrs.rs:18:2: 18:33 (#0), }, Ident { ident: "fn", - span: $DIR/inner-attrs.rs:20:1: 20:3 (#0), + span: $DIR/inner-attrs.rs:19:1: 19:3 (#0), }, Ident { ident: "foo", - span: $DIR/inner-attrs.rs:20:4: 20:7 (#0), + span: $DIR/inner-attrs.rs:19:4: 19:7 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:7: 20:9 (#0), + span: $DIR/inner-attrs.rs:19:7: 19:9 (#0), }, Group { delimiter: Brace, stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:20:5: 20:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:20:6: 20:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:20:8: 20:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "third", + span: $DIR/inner-attrs.rs:20:30: 20:35 (#0), + }, + ], + span: $DIR/inner-attrs.rs:20:29: 20:36 (#0), + }, + ], + span: $DIR/inner-attrs.rs:20:7: 20:37 (#0), + }, Punct { ch: '#', spacing: Joint, @@ -68,58 +98,28 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ ident: "print_target_and_args", span: $DIR/inner-attrs.rs:21:8: 21:29 (#0), }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "third", - span: $DIR/inner-attrs.rs:21:30: 21:35 (#0), - }, - ], - span: $DIR/inner-attrs.rs:21:29: 21:36 (#0), - }, - ], - span: $DIR/inner-attrs.rs:21:7: 21:37 (#0), - }, - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:22:5: 22:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:22:6: 22:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:22:8: 22:29 (#0), - }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "fourth", - span: $DIR/inner-attrs.rs:22:30: 22:36 (#0), + span: $DIR/inner-attrs.rs:21:30: 21:36 (#0), }, ], - span: $DIR/inner-attrs.rs:22:29: 22:37 (#0), + span: $DIR/inner-attrs.rs:21:29: 21:37 (#0), }, ], - span: $DIR/inner-attrs.rs:22:7: 22:38 (#0), + span: $DIR/inner-attrs.rs:21:7: 21:38 (#0), }, ], - span: $DIR/inner-attrs.rs:20:10: 23:2 (#0), + span: $DIR/inner-attrs.rs:19:10: 22:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): second PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "second", - span: $DIR/inner-attrs.rs:19:25: 19:31 (#0), + span: $DIR/inner-attrs.rs:18:25: 18:31 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): fn foo() @@ -129,16 +129,106 @@ PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn foo() PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "fn", - span: $DIR/inner-attrs.rs:20:1: 20:3 (#0), + span: $DIR/inner-attrs.rs:19:1: 19:3 (#0), }, Ident { ident: "foo", - span: $DIR/inner-attrs.rs:20:4: 20:7 (#0), + span: $DIR/inner-attrs.rs:19:4: 19:7 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:7: 20:9 (#0), + span: $DIR/inner-attrs.rs:19:7: 19:9 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:20:5: 20:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:20:6: 20:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:20:8: 20:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "third", + span: $DIR/inner-attrs.rs:20:30: 20:35 (#0), + }, + ], + span: $DIR/inner-attrs.rs:20:29: 20:36 (#0), + }, + ], + span: $DIR/inner-attrs.rs:20:7: 20:37 (#0), + }, + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:21:5: 21:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:21:6: 21:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:21:8: 21:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "fourth", + span: $DIR/inner-attrs.rs:21:30: 21:36 (#0), + }, + ], + span: $DIR/inner-attrs.rs:21:29: 21:37 (#0), + }, + ], + span: $DIR/inner-attrs.rs:21:7: 21:38 (#0), + }, + ], + span: $DIR/inner-attrs.rs:19:10: 22:2 (#0), + }, +] +PRINT-ATTR_ARGS INPUT (DISPLAY): third +PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ + Ident { + ident: "third", + span: $DIR/inner-attrs.rs:20:30: 20:35 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): fn foo() { #![print_target_and_args(fourth)] } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn foo() { #! [print_target_and_args(fourth)] } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/inner-attrs.rs:19:1: 19:3 (#0), + }, + Ident { + ident: "foo", + span: $DIR/inner-attrs.rs:19:4: 19:7 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/inner-attrs.rs:19:7: 19:9 (#0), }, Group { delimiter: Brace, @@ -160,146 +250,56 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ ident: "print_target_and_args", span: $DIR/inner-attrs.rs:21:8: 21:29 (#0), }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "third", - span: $DIR/inner-attrs.rs:21:30: 21:35 (#0), - }, - ], - span: $DIR/inner-attrs.rs:21:29: 21:36 (#0), - }, - ], - span: $DIR/inner-attrs.rs:21:7: 21:37 (#0), - }, - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:22:5: 22:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:22:6: 22:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:22:8: 22:29 (#0), - }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "fourth", - span: $DIR/inner-attrs.rs:22:30: 22:36 (#0), + span: $DIR/inner-attrs.rs:21:30: 21:36 (#0), }, ], - span: $DIR/inner-attrs.rs:22:29: 22:37 (#0), + span: $DIR/inner-attrs.rs:21:29: 21:37 (#0), }, ], - span: $DIR/inner-attrs.rs:22:7: 22:38 (#0), + span: $DIR/inner-attrs.rs:21:7: 21:38 (#0), }, ], - span: $DIR/inner-attrs.rs:20:10: 23:2 (#0), - }, -] -PRINT-ATTR_ARGS INPUT (DISPLAY): third -PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ - Ident { - ident: "third", - span: $DIR/inner-attrs.rs:21:30: 21:35 (#0), - }, -] -PRINT-ATTR INPUT (DISPLAY): fn foo() { #![print_target_and_args(fourth)] } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn foo() { #! [print_target_and_args(fourth)] } -PRINT-ATTR INPUT (DEBUG): TokenStream [ - Ident { - ident: "fn", - span: $DIR/inner-attrs.rs:20:1: 20:3 (#0), - }, - Ident { - ident: "foo", - span: $DIR/inner-attrs.rs:20:4: 20:7 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:7: 20:9 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:22:5: 22:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:22:6: 22:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:22:8: 22:29 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "fourth", - span: $DIR/inner-attrs.rs:22:30: 22:36 (#0), - }, - ], - span: $DIR/inner-attrs.rs:22:29: 22:37 (#0), - }, - ], - span: $DIR/inner-attrs.rs:22:7: 22:38 (#0), - }, - ], - span: $DIR/inner-attrs.rs:20:10: 23:2 (#0), + span: $DIR/inner-attrs.rs:19:10: 22:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): fourth PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "fourth", - span: $DIR/inner-attrs.rs:22:30: 22:36 (#0), + span: $DIR/inner-attrs.rs:21:30: 21:36 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): fn foo() {} PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "fn", - span: $DIR/inner-attrs.rs:20:1: 20:3 (#0), + span: $DIR/inner-attrs.rs:19:1: 19:3 (#0), }, Ident { ident: "foo", - span: $DIR/inner-attrs.rs:20:4: 20:7 (#0), + span: $DIR/inner-attrs.rs:19:4: 19:7 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:7: 20:9 (#0), + span: $DIR/inner-attrs.rs:19:7: 19:9 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/inner-attrs.rs:20:10: 23:2 (#0), + span: $DIR/inner-attrs.rs:19:10: 22:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): mod_first PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "mod_first", - span: $DIR/inner-attrs.rs:25:25: 25:34 (#0), + span: $DIR/inner-attrs.rs:24:25: 24:34 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(mod_second)] mod inline_mod @@ -313,39 +313,69 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/inner-attrs.rs:26:1: 26:2 (#0), + span: $DIR/inner-attrs.rs:25:1: 25:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:26:3: 26:24 (#0), + span: $DIR/inner-attrs.rs:25:3: 25:24 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "mod_second", - span: $DIR/inner-attrs.rs:26:25: 26:35 (#0), + span: $DIR/inner-attrs.rs:25:25: 25:35 (#0), }, ], - span: $DIR/inner-attrs.rs:26:24: 26:36 (#0), + span: $DIR/inner-attrs.rs:25:24: 25:36 (#0), }, ], - span: $DIR/inner-attrs.rs:26:2: 26:37 (#0), + span: $DIR/inner-attrs.rs:25:2: 25:37 (#0), }, Ident { ident: "mod", - span: $DIR/inner-attrs.rs:27:1: 27:4 (#0), + span: $DIR/inner-attrs.rs:26:1: 26:4 (#0), }, Ident { ident: "inline_mod", - span: $DIR/inner-attrs.rs:27:5: 27:15 (#0), + span: $DIR/inner-attrs.rs:26:5: 26:15 (#0), }, Group { delimiter: Brace, stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:27:5: 27:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:27:6: 27:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:27:8: 27:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "mod_third", + span: $DIR/inner-attrs.rs:27:30: 27:39 (#0), + }, + ], + span: $DIR/inner-attrs.rs:27:29: 27:40 (#0), + }, + ], + span: $DIR/inner-attrs.rs:27:7: 27:41 (#0), + }, Punct { ch: '#', spacing: Joint, @@ -363,58 +393,28 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ ident: "print_target_and_args", span: $DIR/inner-attrs.rs:28:8: 28:29 (#0), }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "mod_third", - span: $DIR/inner-attrs.rs:28:30: 28:39 (#0), - }, - ], - span: $DIR/inner-attrs.rs:28:29: 28:40 (#0), - }, - ], - span: $DIR/inner-attrs.rs:28:7: 28:41 (#0), - }, - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:29:5: 29:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:29:6: 29:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:29:8: 29:29 (#0), - }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "mod_fourth", - span: $DIR/inner-attrs.rs:29:30: 29:40 (#0), + span: $DIR/inner-attrs.rs:28:30: 28:40 (#0), }, ], - span: $DIR/inner-attrs.rs:29:29: 29:41 (#0), + span: $DIR/inner-attrs.rs:28:29: 28:41 (#0), }, ], - span: $DIR/inner-attrs.rs:29:7: 29:42 (#0), + span: $DIR/inner-attrs.rs:28:7: 28:42 (#0), }, ], - span: $DIR/inner-attrs.rs:27:16: 30:2 (#0), + span: $DIR/inner-attrs.rs:26:16: 29:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): mod_second PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "mod_second", - span: $DIR/inner-attrs.rs:26:25: 26:35 (#0), + span: $DIR/inner-attrs.rs:25:25: 25:35 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): mod inline_mod @@ -427,11 +427,96 @@ PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): mod inline_mod PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "mod", - span: $DIR/inner-attrs.rs:27:1: 27:4 (#0), + span: $DIR/inner-attrs.rs:26:1: 26:4 (#0), }, Ident { ident: "inline_mod", - span: $DIR/inner-attrs.rs:27:5: 27:15 (#0), + span: $DIR/inner-attrs.rs:26:5: 26:15 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:27:5: 27:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:27:6: 27:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:27:8: 27:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "mod_third", + span: $DIR/inner-attrs.rs:27:30: 27:39 (#0), + }, + ], + span: $DIR/inner-attrs.rs:27:29: 27:40 (#0), + }, + ], + span: $DIR/inner-attrs.rs:27:7: 27:41 (#0), + }, + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:28:5: 28:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:28:6: 28:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_target_and_args", + span: $DIR/inner-attrs.rs:28:8: 28:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "mod_fourth", + span: $DIR/inner-attrs.rs:28:30: 28:40 (#0), + }, + ], + span: $DIR/inner-attrs.rs:28:29: 28:41 (#0), + }, + ], + span: $DIR/inner-attrs.rs:28:7: 28:42 (#0), + }, + ], + span: $DIR/inner-attrs.rs:26:16: 29:2 (#0), + }, +] +PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third +PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ + Ident { + ident: "mod_third", + span: $DIR/inner-attrs.rs:27:30: 27:39 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): mod inline_mod { #![print_target_and_args(mod_fourth)] } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): mod inline_mod { #! [print_target_and_args(mod_fourth)] } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "mod", + span: $DIR/inner-attrs.rs:26:1: 26:4 (#0), + }, + Ident { + ident: "inline_mod", + span: $DIR/inner-attrs.rs:26:5: 26:15 (#0), }, Group { delimiter: Brace, @@ -453,129 +538,44 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ ident: "print_target_and_args", span: $DIR/inner-attrs.rs:28:8: 28:29 (#0), }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "mod_third", - span: $DIR/inner-attrs.rs:28:30: 28:39 (#0), - }, - ], - span: $DIR/inner-attrs.rs:28:29: 28:40 (#0), - }, - ], - span: $DIR/inner-attrs.rs:28:7: 28:41 (#0), - }, - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:29:5: 29:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:29:6: 29:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:29:8: 29:29 (#0), - }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "mod_fourth", - span: $DIR/inner-attrs.rs:29:30: 29:40 (#0), + span: $DIR/inner-attrs.rs:28:30: 28:40 (#0), }, ], - span: $DIR/inner-attrs.rs:29:29: 29:41 (#0), + span: $DIR/inner-attrs.rs:28:29: 28:41 (#0), }, ], - span: $DIR/inner-attrs.rs:29:7: 29:42 (#0), + span: $DIR/inner-attrs.rs:28:7: 28:42 (#0), }, ], - span: $DIR/inner-attrs.rs:27:16: 30:2 (#0), - }, -] -PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third -PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ - Ident { - ident: "mod_third", - span: $DIR/inner-attrs.rs:28:30: 28:39 (#0), - }, -] -PRINT-ATTR INPUT (DISPLAY): mod inline_mod { #![print_target_and_args(mod_fourth)] } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): mod inline_mod { #! [print_target_and_args(mod_fourth)] } -PRINT-ATTR INPUT (DEBUG): TokenStream [ - Ident { - ident: "mod", - span: $DIR/inner-attrs.rs:27:1: 27:4 (#0), - }, - Ident { - ident: "inline_mod", - span: $DIR/inner-attrs.rs:27:5: 27:15 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Punct { - ch: '#', - spacing: Joint, - span: $DIR/inner-attrs.rs:29:5: 29:6 (#0), - }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:29:6: 29:7 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_target_and_args", - span: $DIR/inner-attrs.rs:29:8: 29:29 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "mod_fourth", - span: $DIR/inner-attrs.rs:29:30: 29:40 (#0), - }, - ], - span: $DIR/inner-attrs.rs:29:29: 29:41 (#0), - }, - ], - span: $DIR/inner-attrs.rs:29:7: 29:42 (#0), - }, - ], - span: $DIR/inner-attrs.rs:27:16: 30:2 (#0), + span: $DIR/inner-attrs.rs:26:16: 29:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): mod_fourth PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "mod_fourth", - span: $DIR/inner-attrs.rs:29:30: 29:40 (#0), + span: $DIR/inner-attrs.rs:28:30: 28:40 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): mod inline_mod {} PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "mod", - span: $DIR/inner-attrs.rs:27:1: 27:4 (#0), + span: $DIR/inner-attrs.rs:26:1: 26:4 (#0), }, Ident { ident: "inline_mod", - span: $DIR/inner-attrs.rs:27:5: 27:15 (#0), + span: $DIR/inner-attrs.rs:26:5: 26:15 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/inner-attrs.rs:27:16: 30:2 (#0), + span: $DIR/inner-attrs.rs:26:16: 29:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint @@ -585,63 +585,63 @@ PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct MyDerivePrint PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/inner-attrs.rs:37:1: 37:7 (#0), + span: $DIR/inner-attrs.rs:36:1: 36:7 (#0), }, Ident { ident: "MyDerivePrint", - span: $DIR/inner-attrs.rs:37:8: 37:21 (#0), + span: $DIR/inner-attrs.rs:36:8: 36:21 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "field", - span: $DIR/inner-attrs.rs:38:5: 38:10 (#0), + span: $DIR/inner-attrs.rs:37:5: 37:10 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/inner-attrs.rs:38:10: 38:11 (#0), + span: $DIR/inner-attrs.rs:37:10: 37:11 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "u8", - span: $DIR/inner-attrs.rs:38:13: 38:15 (#0), + span: $DIR/inner-attrs.rs:37:13: 37:15 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:38:15: 38:16 (#0), + span: $DIR/inner-attrs.rs:37:15: 37:16 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "match", - span: $DIR/inner-attrs.rs:39:9: 39:14 (#0), + span: $DIR/inner-attrs.rs:38:9: 38:14 (#0), }, Ident { ident: "true", - span: $DIR/inner-attrs.rs:39:15: 39:19 (#0), + span: $DIR/inner-attrs.rs:38:15: 38:19 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "_", - span: $DIR/inner-attrs.rs:40:13: 40:14 (#0), + span: $DIR/inner-attrs.rs:39:13: 39:14 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/inner-attrs.rs:40:15: 40:16 (#0), + span: $DIR/inner-attrs.rs:39:15: 39:16 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/inner-attrs.rs:40:16: 40:17 (#0), + span: $DIR/inner-attrs.rs:39:16: 39:17 (#0), }, Group { delimiter: Brace, @@ -649,69 +649,69 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/inner-attrs.rs:41:17: 41:18 (#0), + span: $DIR/inner-attrs.rs:40:17: 40:18 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/inner-attrs.rs:41:18: 41:19 (#0), + span: $DIR/inner-attrs.rs:40:18: 40:19 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "rustc_dummy", - span: $DIR/inner-attrs.rs:41:41: 41:52 (#0), + span: $DIR/inner-attrs.rs:40:41: 40:52 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "third", - span: $DIR/inner-attrs.rs:41:53: 41:58 (#0), + span: $DIR/inner-attrs.rs:40:53: 40:58 (#0), }, ], - span: $DIR/inner-attrs.rs:41:52: 41:59 (#0), + span: $DIR/inner-attrs.rs:40:52: 40:59 (#0), }, ], - span: $DIR/inner-attrs.rs:41:19: 41:61 (#0), + span: $DIR/inner-attrs.rs:40:19: 40:61 (#0), }, Ident { ident: "true", - span: $DIR/inner-attrs.rs:42:17: 42:21 (#0), + span: $DIR/inner-attrs.rs:41:17: 41:21 (#0), }, ], - span: $DIR/inner-attrs.rs:40:18: 43:14 (#0), + span: $DIR/inner-attrs.rs:39:18: 42:14 (#0), }, ], - span: $DIR/inner-attrs.rs:39:20: 44:10 (#0), + span: $DIR/inner-attrs.rs:38:20: 43:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:44:10: 44:11 (#0), + span: $DIR/inner-attrs.rs:43:10: 43:11 (#0), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: $DIR/inner-attrs.rs:45:9: 45:10 (#0), + span: $DIR/inner-attrs.rs:44:9: 44:10 (#0), }, ], - span: $DIR/inner-attrs.rs:38:17: 46:6 (#0), + span: $DIR/inner-attrs.rs:37:17: 45:6 (#0), }, ], - span: $DIR/inner-attrs.rs:38:12: 46:7 (#0), + span: $DIR/inner-attrs.rs:37:12: 45:7 (#0), }, ], - span: $DIR/inner-attrs.rs:37:22: 47:2 (#0), + span: $DIR/inner-attrs.rs:36:22: 46:2 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "tuple_attrs", - span: $DIR/inner-attrs.rs:50:29: 50:40 (#0), + span: $DIR/inner-attrs.rs:49:29: 49:40 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }); @@ -724,23 +724,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "3", suffix: None, - span: $DIR/inner-attrs.rs:51:9: 51:10 (#0), + span: $DIR/inner-attrs.rs:50:9: 50:10 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:51:10: 51:11 (#0), + span: $DIR/inner-attrs.rs:50:10: 50:11 (#0), }, Literal { kind: Integer, symbol: "4", suffix: None, - span: $DIR/inner-attrs.rs:51:12: 51:13 (#0), + span: $DIR/inner-attrs.rs:50:12: 50:13 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:51:13: 51:14 (#0), + span: $DIR/inner-attrs.rs:50:13: 50:14 (#0), }, Group { delimiter: Brace, @@ -748,85 +748,85 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, + span: $DIR/inner-attrs.rs:51:13: 51:14 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:51:14: 51:15 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/inner-attrs.rs:51:16: 51:24 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/inner-attrs.rs:51:25: 51:28 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/inner-attrs.rs:51:29: 51:34 (#0), + }, + ], + span: $DIR/inner-attrs.rs:51:28: 51:35 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/inner-attrs.rs:51:35: 51:36 (#0), + }, + Ident { + ident: "rustc_dummy", + span: $DIR/inner-attrs.rs:51:37: 51:48 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "innermost", + span: $DIR/inner-attrs.rs:51:49: 51:58 (#0), + }, + ], + span: $DIR/inner-attrs.rs:51:48: 51:59 (#0), + }, + ], + span: $DIR/inner-attrs.rs:51:24: 51:60 (#0), + }, + ], + span: $DIR/inner-attrs.rs:51:15: 51:61 (#0), + }, + Literal { + kind: Integer, + symbol: "5", + suffix: None, span: $DIR/inner-attrs.rs:52:13: 52:14 (#0), }, - Punct { - ch: '!', - spacing: Alone, - span: $DIR/inner-attrs.rs:52:14: 52:15 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "cfg_attr", - span: $DIR/inner-attrs.rs:52:16: 52:24 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "not", - span: $DIR/inner-attrs.rs:52:25: 52:28 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "FALSE", - span: $DIR/inner-attrs.rs:52:29: 52:34 (#0), - }, - ], - span: $DIR/inner-attrs.rs:52:28: 52:35 (#0), - }, - Punct { - ch: ',', - spacing: Alone, - span: $DIR/inner-attrs.rs:52:35: 52:36 (#0), - }, - Ident { - ident: "rustc_dummy", - span: $DIR/inner-attrs.rs:52:37: 52:48 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "innermost", - span: $DIR/inner-attrs.rs:52:49: 52:58 (#0), - }, - ], - span: $DIR/inner-attrs.rs:52:48: 52:59 (#0), - }, - ], - span: $DIR/inner-attrs.rs:52:24: 52:60 (#0), - }, - ], - span: $DIR/inner-attrs.rs:52:15: 52:61 (#0), - }, - Literal { - kind: Integer, - symbol: "5", - suffix: None, - span: $DIR/inner-attrs.rs:53:13: 53:14 (#0), - }, ], - span: $DIR/inner-attrs.rs:51:15: 54:10 (#0), + span: $DIR/inner-attrs.rs:50:15: 53:10 (#0), }, ], - span: $DIR/inner-attrs.rs:50:43: 55:6 (#0), + span: $DIR/inner-attrs.rs:49:43: 54:6 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:55:6: 55:7 (#0), + span: $DIR/inner-attrs.rs:54:6: 54:7 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "tuple_attrs", - span: $DIR/inner-attrs.rs:57:29: 57:40 (#0), + span: $DIR/inner-attrs.rs:56:29: 56:40 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }); @@ -839,23 +839,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "3", suffix: None, - span: $DIR/inner-attrs.rs:58:9: 58:10 (#0), + span: $DIR/inner-attrs.rs:57:9: 57:10 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:58:10: 58:11 (#0), + span: $DIR/inner-attrs.rs:57:10: 57:11 (#0), }, Literal { kind: Integer, symbol: "4", suffix: None, - span: $DIR/inner-attrs.rs:58:12: 58:13 (#0), + span: $DIR/inner-attrs.rs:57:12: 57:13 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:58:13: 58:14 (#0), + span: $DIR/inner-attrs.rs:57:13: 57:14 (#0), }, Group { delimiter: Brace, @@ -863,105 +863,105 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/inner-attrs.rs:59:13: 59:14 (#0), + span: $DIR/inner-attrs.rs:58:13: 58:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/inner-attrs.rs:59:14: 59:15 (#0), + span: $DIR/inner-attrs.rs:58:14: 58:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg_attr", - span: $DIR/inner-attrs.rs:59:16: 59:24 (#0), + span: $DIR/inner-attrs.rs:58:16: 58:24 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/inner-attrs.rs:59:25: 59:28 (#0), + span: $DIR/inner-attrs.rs:58:25: 58:28 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/inner-attrs.rs:59:29: 59:34 (#0), + span: $DIR/inner-attrs.rs:58:29: 58:34 (#0), }, ], - span: $DIR/inner-attrs.rs:59:28: 59:35 (#0), + span: $DIR/inner-attrs.rs:58:28: 58:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:59:35: 59:36 (#0), + span: $DIR/inner-attrs.rs:58:35: 58:36 (#0), }, Ident { ident: "rustc_dummy", - span: $DIR/inner-attrs.rs:59:37: 59:48 (#0), + span: $DIR/inner-attrs.rs:58:37: 58:48 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "innermost", - span: $DIR/inner-attrs.rs:59:49: 59:58 (#0), + span: $DIR/inner-attrs.rs:58:49: 58:58 (#0), }, ], - span: $DIR/inner-attrs.rs:59:48: 59:59 (#0), + span: $DIR/inner-attrs.rs:58:48: 58:59 (#0), }, ], - span: $DIR/inner-attrs.rs:59:24: 59:60 (#0), + span: $DIR/inner-attrs.rs:58:24: 58:60 (#0), }, ], - span: $DIR/inner-attrs.rs:59:15: 59:61 (#0), + span: $DIR/inner-attrs.rs:58:15: 58:61 (#0), }, Literal { kind: Integer, symbol: "5", suffix: None, - span: $DIR/inner-attrs.rs:60:13: 60:14 (#0), + span: $DIR/inner-attrs.rs:59:13: 59:14 (#0), }, ], - span: $DIR/inner-attrs.rs:58:15: 61:10 (#0), + span: $DIR/inner-attrs.rs:57:15: 60:10 (#0), }, ], - span: $DIR/inner-attrs.rs:57:43: 62:6 (#0), + span: $DIR/inner-attrs.rs:56:43: 61:6 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:62:6: 62:7 (#0), + span: $DIR/inner-attrs.rs:61:6: 61:7 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): tenth PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "tenth", - span: $DIR/inner-attrs.rs:84:42: 84:47 (#0), + span: $DIR/inner-attrs.rs:87:42: 87:47 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): fn weird_extern() {} PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "fn", - span: $DIR/inner-attrs.rs:83:5: 83:7 (#0), + span: $DIR/inner-attrs.rs:86:5: 86:7 (#0), }, Ident { ident: "weird_extern", - span: $DIR/inner-attrs.rs:83:8: 83:20 (#0), + span: $DIR/inner-attrs.rs:86:8: 86:20 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/inner-attrs.rs:83:20: 83:22 (#0), + span: $DIR/inner-attrs.rs:86:20: 86:22 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/inner-attrs.rs:83:23: 85:6 (#0), + span: $DIR/inner-attrs.rs:86:23: 88:6 (#0), }, ] diff --git a/tests/ui/regions/region-invariant-static-error-reporting.rs b/tests/ui/regions/region-invariant-static-error-reporting.rs index e58eea3f61ae..9792c101fa89 100644 --- a/tests/ui/regions/region-invariant-static-error-reporting.rs +++ b/tests/ui/regions/region-invariant-static-error-reporting.rs @@ -3,7 +3,7 @@ // over time, but this test used to exhibit some pretty bogus messages // that were not remotely helpful. -//@ error-pattern:requires that `'a` must outlive `'static` +//@ dont-require-annotations: NOTE struct Invariant<'a>(Option<&'a mut &'a mut ()>); @@ -14,6 +14,7 @@ fn unify<'a>(x: Option>, f: fn(Invariant<'a>)) { x.unwrap() } else { mk_static() //~ ERROR lifetime may not live long enough + //~| NOTE assignment requires that `'a` must outlive `'static` }; f(bad); } diff --git a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs index fda0b1c08cb2..d394dbe7b15d 100644 --- a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs +++ b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs @@ -4,7 +4,7 @@ //@ compile-flags: -Ctarget-feature=-forced-atomics // For now this is just a warning. //@ build-pass -//@error-pattern: unsound because it changes the ABI + #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/ui/target-feature/tied-features-no-implication-1.rs b/tests/ui/target-feature/tied-features-no-implication-1.rs index 0a98a7eeccf4..63a1d77dae9f 100644 --- a/tests/ui/target-feature/tied-features-no-implication-1.rs +++ b/tests/ui/target-feature/tied-features-no-implication-1.rs @@ -2,9 +2,7 @@ //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu //@ needs-llvm-components: aarch64 //@[paca] compile-flags: -Ctarget-feature=+paca -//@[paca] error-pattern: the target features paca, pacg must all be either enabled or disabled together //@[pacg] compile-flags: -Ctarget-feature=+pacg -//@[paca] error-pattern: the target features paca, pacg must all be either enabled or disabled together #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs b/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs index 9304e20b4290..6005bc96ad6d 100644 --- a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs +++ b/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs @@ -1,6 +1,7 @@ //~ ERROR unknown lint: `test_unstable_lint` +//~^ NOTE the `test_unstable_lint` lint is unstable //@ check-fail //@ compile-flags: -Dunknown_lints -Atest_unstable_lint -//@ error-pattern: the `test_unstable_lint` lint is unstable +//@ dont-require-annotations: NOTE fn main() {} diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs index 76983419c685..c32a21a01632 100644 --- a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs +++ b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs @@ -1,6 +1,7 @@ //~ WARN unknown lint: `test_unstable_lint` +//~^ NOTE the `test_unstable_lint` lint is unstable //@ check-pass //@ compile-flags: -Wunknown_lints -Atest_unstable_lint -//@ error-pattern: the `test_unstable_lint` lint is unstable +//@ dont-require-annotations: NOTE fn main() {} From 9f35fe47c75cf404a7ae2c64dbeaf37277106504 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 4 Oct 2024 12:54:09 +0000 Subject: [PATCH 110/222] JumpThreading: Re-enable and fix Not ops on non-booleans --- .../rustc_mir_transform/src/jump_threading.rs | 29 +++++------- ...bitwise_not.JumpThreading.panic-abort.diff | 6 +-- ...itwise_not.JumpThreading.panic-unwind.diff | 6 +-- ...logical_not.JumpThreading.panic-abort.diff | 46 +++++++++++++++++++ ...ogical_not.JumpThreading.panic-unwind.diff | 46 +++++++++++++++++++ tests/mir-opt/jump_threading.rs | 14 ++++-- 6 files changed, 120 insertions(+), 27 deletions(-) create mode 100644 tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff create mode 100644 tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 0a72a9d669fe..375cf88e3e9b 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -150,14 +150,6 @@ impl Condition { fn matches(&self, value: ScalarInt) -> bool { (self.value == value) == (self.polarity == Polarity::Eq) } - - fn inv(mut self) -> Self { - self.polarity = match self.polarity { - Polarity::Eq => Polarity::Ne, - Polarity::Ne => Polarity::Eq, - }; - self - } } #[derive(Copy, Clone, Debug)] @@ -495,19 +487,20 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } } } - // Transfer the conditions on the copy rhs, after inversing polarity. + // Transfer the conditions on the copy rhs, after inverting the value of the condition. Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { - if !place.ty(self.body, self.tcx).ty.is_bool() { - // Constructing the conditions by inverting the polarity - // of equality is only correct for bools. That is to say, - // `!a == b` is not `a != b` for integers greater than 1 bit. - return; - } + let layout = self.ecx.layout_of(place.ty(self.body, self.tcx).ty).unwrap(); let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; let Some(place) = self.map.find(place.as_ref()) else { return }; - // FIXME: I think This could be generalized to not bool if we - // actually perform a logical not on the condition's value. - let conds = conditions.map(self.arena, Condition::inv); + let conds = conditions.map(self.arena, |mut cond| { + cond.value = self + .ecx + .unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout)) + .unwrap() + .to_scalar_int() + .unwrap(); + cond + }); state.insert_value_idx(place, conds, &self.map); } // We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`. diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff index 047441e60991..c3272f21d6c1 100644 --- a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff @@ -3,7 +3,7 @@ fn bitwise_not() -> i32 { let mut _0: i32; - let mut _1: i32; + let _1: i32; let mut _2: bool; let mut _3: i32; let mut _4: i32; @@ -13,7 +13,6 @@ bb0: { StorageLive(_1); - _1 = const 0_i32; _1 = const 1_i32; StorageLive(_2); StorageLive(_3); @@ -22,7 +21,8 @@ _3 = Not(move _4); StorageDead(_4); _2 = Eq(move _3, const 0_i32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; +- switchInt(move _2) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; } bb1: { diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff index 047441e60991..c3272f21d6c1 100644 --- a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff @@ -3,7 +3,7 @@ fn bitwise_not() -> i32 { let mut _0: i32; - let mut _1: i32; + let _1: i32; let mut _2: bool; let mut _3: i32; let mut _4: i32; @@ -13,7 +13,6 @@ bb0: { StorageLive(_1); - _1 = const 0_i32; _1 = const 1_i32; StorageLive(_2); StorageLive(_3); @@ -22,7 +21,8 @@ _3 = Not(move _4); StorageDead(_4); _2 = Eq(move _3, const 0_i32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; +- switchInt(move _2) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; } bb1: { diff --git a/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff new file mode 100644 index 000000000000..ad8be1ef5a18 --- /dev/null +++ b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff @@ -0,0 +1,46 @@ +- // MIR for `logical_not` before JumpThreading ++ // MIR for `logical_not` after JumpThreading + + fn logical_not() -> i32 { + let mut _0: i32; + let _1: bool; + let mut _2: bool; + let mut _3: bool; + let mut _4: bool; + scope 1 { + debug a => _1; + } + + bb0: { + StorageLive(_1); + _1 = const false; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = copy _1; + _3 = Not(move _4); + StorageDead(_4); + _2 = Eq(move _3, const true); +- switchInt(move _2) -> [0: bb2, otherwise: bb1]; ++ goto -> bb1; + } + + bb1: { + StorageDead(_3); + _0 = const 1_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff new file mode 100644 index 000000000000..ad8be1ef5a18 --- /dev/null +++ b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff @@ -0,0 +1,46 @@ +- // MIR for `logical_not` before JumpThreading ++ // MIR for `logical_not` after JumpThreading + + fn logical_not() -> i32 { + let mut _0: i32; + let _1: bool; + let mut _2: bool; + let mut _3: bool; + let mut _4: bool; + scope 1 { + debug a => _1; + } + + bb0: { + StorageLive(_1); + _1 = const false; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = copy _1; + _3 = Not(move _4); + StorageDead(_4); + _2 = Eq(move _3, const true); +- switchInt(move _2) -> [0: bb2, otherwise: bb1]; ++ goto -> bb1; + } + + bb1: { + StorageDead(_3); + _0 = const 1_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 743ee8e728bb..009e1060700c 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -532,14 +532,19 @@ fn floats() -> u32 { pub fn bitwise_not() -> i32 { // CHECK-LABEL: fn bitwise_not( - // CHECK: switchInt( // Test for #131195, which was optimizing `!a == b` into `a != b`. - let mut a: i32 = 0; - a = 1; + let a = 1; if !a == 0 { 1 } else { 0 } } +pub fn logical_not() -> i32 { + // CHECK-LABEL: fn logical_not( + + let a = false; + if !a == true { 1 } else { 0 } +} + fn main() { // CHECK-LABEL: fn main( too_complex(Ok(0)); @@ -555,6 +560,8 @@ fn main() { aggregate(7); assume(7, false); floats(); + bitwise_not(); + logical_not(); } // EMIT_MIR jump_threading.too_complex.JumpThreading.diff @@ -572,3 +579,4 @@ fn main() { // EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff // EMIT_MIR jump_threading.floats.JumpThreading.diff // EMIT_MIR jump_threading.bitwise_not.JumpThreading.diff +// EMIT_MIR jump_threading.logical_not.JumpThreading.diff From 41a5d8ef3da4769bdd4349ef540110a6e80e6c1e Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 7 Oct 2024 17:31:43 +0000 Subject: [PATCH 111/222] JumpThreading: Bail out on interp errors --- .../rustc_mir_transform/src/jump_threading.rs | 158 ++++++++++-------- 1 file changed, 91 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 375cf88e3e9b..8b4b214a3d45 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -90,7 +90,11 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { }; for bb in body.basic_blocks.indices() { - finder.start_from_switch(bb); + let old_len = finder.opportunities.len(); + // If we have any const-eval errors discard any opportunities found + if finder.start_from_switch(bb).is_none() { + finder.opportunities.truncate(old_len); + } } let opportunities = finder.opportunities; @@ -172,8 +176,21 @@ impl<'a> ConditionSet<'a> { self.iter().filter(move |c| c.matches(value)) } - fn map(self, arena: &'a DroplessArena, f: impl Fn(Condition) -> Condition) -> ConditionSet<'a> { - ConditionSet(arena.alloc_from_iter(self.iter().map(f))) + fn map( + self, + arena: &'a DroplessArena, + f: impl Fn(Condition) -> Option, + ) -> Option> { + let mut all_ok = true; + let set = arena.alloc_from_iter(self.iter().map_while(|c| { + if let Some(c) = f(c) { + Some(c) + } else { + all_ok = false; + None + } + })); + all_ok.then_some(ConditionSet(set)) } } @@ -184,28 +201,28 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { /// Recursion entry point to find threading opportunities. #[instrument(level = "trace", skip(self))] - fn start_from_switch(&mut self, bb: BasicBlock) { + fn start_from_switch(&mut self, bb: BasicBlock) -> Option<()> { let bbdata = &self.body[bb]; if bbdata.is_cleanup || self.loop_headers.contains(bb) { - return; + return Some(()); } - let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return }; - let Some(discr) = discr.place() else { return }; + let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return Some(()) }; + let Some(discr) = discr.place() else { return Some(()) }; debug!(?discr, ?bb); let discr_ty = discr.ty(self.body, self.tcx).ty; let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { - return; + return Some(()); }; - let Some(discr) = self.map.find(discr.as_ref()) else { return }; + let Some(discr) = self.map.find(discr.as_ref()) else { return Some(()) }; debug!(?discr); let cost = CostChecker::new(self.tcx, self.typing_env, None, self.body); let mut state = State::new_reachable(); let conds = if let Some((value, then, else_)) = targets.as_static_if() { - let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; + let value = ScalarInt::try_from_uint(value, discr_layout.size)?; self.arena.alloc_from_iter([ Condition { value, polarity: Polarity::Eq, target: then }, Condition { value, polarity: Polarity::Ne, target: else_ }, @@ -219,7 +236,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let conds = ConditionSet(conds); state.insert_value_idx(discr, conds, &self.map); - self.find_opportunity(bb, state, cost, 0); + self.find_opportunity(bb, state, cost, 0) } /// Recursively walk statements backwards from this bb's terminator to find threading @@ -231,10 +248,10 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { mut state: State>, mut cost: CostChecker<'_, 'tcx>, depth: usize, - ) { + ) -> Option<()> { // Do not thread through loop headers. if self.loop_headers.contains(bb) { - return; + return Some(()); } debug!(cost = ?cost.cost()); @@ -242,16 +259,16 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { self.body.basic_blocks[bb].statements.iter().enumerate().rev() { if self.is_empty(&state) { - return; + return Some(()); } cost.visit_statement(stmt, Location { block: bb, statement_index }); if cost.cost() > MAX_COST { - return; + return Some(()); } // Attempt to turn the `current_condition` on `lhs` into a condition on another place. - self.process_statement(bb, stmt, &mut state); + self.process_statement(bb, stmt, &mut state)?; // When a statement mutates a place, assignments to that place that happen // above the mutation cannot fulfill a condition. @@ -263,7 +280,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } if self.is_empty(&state) || depth >= MAX_BACKTRACK { - return; + return Some(()); } let last_non_rec = self.opportunities.len(); @@ -276,9 +293,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { match term.kind { TerminatorKind::SwitchInt { ref discr, ref targets } => { self.process_switch_int(discr, targets, bb, &mut state); - self.find_opportunity(pred, state, cost, depth + 1); + self.find_opportunity(pred, state, cost, depth + 1)?; } - _ => self.recurse_through_terminator(pred, || state, &cost, depth), + _ => self.recurse_through_terminator(pred, || state, &cost, depth)?, } } else if let &[ref predecessors @ .., last_pred] = &predecessors[..] { for &pred in predecessors { @@ -303,12 +320,13 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let first = &mut new_tos[0]; *first = ThreadingOpportunity { chain: vec![bb], target: first.target }; self.opportunities.truncate(last_non_rec + 1); - return; + return Some(()); } for op in self.opportunities[last_non_rec..].iter_mut() { op.chain.push(bb); } + Some(()) } /// Extract the mutated place from a statement. @@ -422,23 +440,23 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { lhs: PlaceIndex, rhs: &Operand<'tcx>, state: &mut State>, - ) { + ) -> Option<()> { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Operand::Constant(constant) => { - let Some(constant) = - self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err() - else { - return; - }; + let constant = self + .ecx + .eval_mir_constant(&constant.const_, constant.span, None) + .discard_err()?; self.process_constant(bb, lhs, constant, state); } // Transfer the conditions on the copied rhs. Operand::Move(rhs) | Operand::Copy(rhs) => { - let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; + let Some(rhs) = self.map.find(rhs.as_ref()) else { return Some(()) }; state.insert_place_idx(rhs, lhs, &self.map); } } + Some(()) } #[instrument(level = "trace", skip(self))] @@ -448,14 +466,18 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { lhs_place: &Place<'tcx>, rhs: &Rvalue<'tcx>, state: &mut State>, - ) { - let Some(lhs) = self.map.find(lhs_place.as_ref()) else { return }; + ) -> Option<()> { + let Some(lhs) = self.map.find(lhs_place.as_ref()) else { + return Some(()); + }; match rhs { - Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state), + Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state)?, // Transfer the conditions on the copy rhs. - Rvalue::CopyForDeref(rhs) => self.process_operand(bb, lhs, &Operand::Copy(*rhs), state), + Rvalue::CopyForDeref(rhs) => { + self.process_operand(bb, lhs, &Operand::Copy(*rhs), state)? + } Rvalue::Discriminant(rhs) => { - let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return }; + let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return Some(()) }; state.insert_place_idx(rhs, lhs, &self.map); } // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. @@ -463,7 +485,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let agg_ty = lhs_place.ty(self.body, self.tcx).ty; let lhs = match kind { // Do not support unions. - AggregateKind::Adt(.., Some(_)) => return, + AggregateKind::Adt(.., Some(_)) => return Some(()), AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => { if let Some(discr_target) = self.map.apply(lhs, TrackElem::Discriminant) && let Some(discr_value) = self @@ -476,31 +498,31 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { if let Some(idx) = self.map.apply(lhs, TrackElem::Variant(*variant_index)) { idx } else { - return; + return Some(()); } } _ => lhs, }; for (field_index, operand) in operands.iter_enumerated() { if let Some(field) = self.map.apply(lhs, TrackElem::Field(field_index)) { - self.process_operand(bb, field, operand, state); + self.process_operand(bb, field, operand, state)?; } } } // Transfer the conditions on the copy rhs, after inverting the value of the condition. Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { let layout = self.ecx.layout_of(place.ty(self.body, self.tcx).ty).unwrap(); - let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; - let Some(place) = self.map.find(place.as_ref()) else { return }; + let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return Some(()) }; + let Some(place) = self.map.find(place.as_ref()) else { return Some(()) }; let conds = conditions.map(self.arena, |mut cond| { cond.value = self .ecx .unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout)) - .unwrap() + .discard_err()? .to_scalar_int() - .unwrap(); - cond - }); + .discard_err()?; + Some(cond) + })?; state.insert_value_idx(place, conds, &self.map); } // We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`. @@ -510,34 +532,34 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { box (Operand::Move(place) | Operand::Copy(place), Operand::Constant(value)) | box (Operand::Constant(value), Operand::Move(place) | Operand::Copy(place)), ) => { - let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; - let Some(place) = self.map.find(place.as_ref()) else { return }; + let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return Some(()) }; + let Some(place) = self.map.find(place.as_ref()) else { return Some(()) }; let equals = match op { BinOp::Eq => ScalarInt::TRUE, BinOp::Ne => ScalarInt::FALSE, - _ => return, + _ => return Some(()), }; if value.const_.ty().is_floating_point() { // Floating point equality does not follow bit-patterns. // -0.0 and NaN both have special rules for equality, // and therefore we cannot use integer comparisons for them. // Avoid handling them, though this could be extended in the future. - return; + return Some(()); } - let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.typing_env) - else { - return; - }; - let conds = conditions.map(self.arena, |c| Condition { - value, - polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne }, - ..c - }); + let value = value.const_.try_eval_scalar_int(self.tcx, self.typing_env)?; + let conds = conditions.map(self.arena, |c| { + Some(Condition { + value, + polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne }, + ..c + }) + })?; state.insert_value_idx(place, conds, &self.map); } _ => {} } + Some(()) } #[instrument(level = "trace", skip(self))] @@ -546,7 +568,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { bb: BasicBlock, stmt: &Statement<'tcx>, state: &mut State>, - ) { + ) -> Option<()> { let register_opportunity = |c: Condition| { debug!(?bb, ?c.target, "register"); self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target }) @@ -559,30 +581,32 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // If we expect `discriminant(place) ?= A`, // we have an opportunity if `variant_index ?= A`. StatementKind::SetDiscriminant { box place, variant_index } => { - let Some(discr_target) = self.map.find_discr(place.as_ref()) else { return }; + let Some(discr_target) = self.map.find_discr(place.as_ref()) else { + return Some(()); + }; let enum_ty = place.ty(self.body, self.tcx).ty; // `SetDiscriminant` guarantees that the discriminant is now `variant_index`. // Even if the discriminant write does nothing due to niches, it is UB to set the // discriminant when the data does not encode the desired discriminant. - let Some(discr) = - self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err() - else { - return; - }; + let discr = + self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err()?; self.process_immediate(bb, discr_target, discr, state); } // If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`. StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume( Operand::Copy(place) | Operand::Move(place), )) => { - let Some(conditions) = state.try_get(place.as_ref(), &self.map) else { return }; + let Some(conditions) = state.try_get(place.as_ref(), &self.map) else { + return Some(()); + }; conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity); } StatementKind::Assign(box (lhs_place, rhs)) => { - self.process_assign(bb, lhs_place, rhs, state); + self.process_assign(bb, lhs_place, rhs, state)?; } _ => {} } + Some(()) } #[instrument(level = "trace", skip(self, state, cost))] @@ -593,7 +617,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { state: impl FnOnce() -> State>, cost: &CostChecker<'_, 'tcx>, depth: usize, - ) { + ) -> Option<()> { let term = self.body.basic_blocks[bb].terminator(); let place_to_flood = match term.kind { // We come from a target, so those are not possible. @@ -608,9 +632,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Yield { .. } => bug!("{term:?} invalid"), // Cannot reason about inline asm. - TerminatorKind::InlineAsm { .. } => return, + TerminatorKind::InlineAsm { .. } => return Some(()), // `SwitchInt` is handled specially. - TerminatorKind::SwitchInt { .. } => return, + TerminatorKind::SwitchInt { .. } => return Some(()), // We can recurse, no thing particular to do. TerminatorKind::Goto { .. } => None, // Flood the overwritten place, and progress through. @@ -625,7 +649,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { if let Some(place_to_flood) = place_to_flood { state.flood_with(place_to_flood.as_ref(), &self.map, ConditionSet::BOTTOM); } - self.find_opportunity(bb, state, cost.clone(), depth + 1); + self.find_opportunity(bb, state, cost.clone(), depth + 1) } #[instrument(level = "trace", skip(self))] From d50a8d5fb3727277f82440524e20a67e29dead4c Mon Sep 17 00:00:00 2001 From: jyn Date: Tue, 11 Mar 2025 00:24:08 -0400 Subject: [PATCH 112/222] Improve `-Z crate-attr` diagnostics - Show the `#![ ... ]` in the span (to make it clear that it should not be included in the CLI argument) - Show more detailed errors when the crate has valid token trees but invalid syntax. Previously, `crate-attr=feature(foo),feature(bar)` would just say "invalid crate attribute" and point at the comma. Now, it explicitly says that the comma was unexpected, which is useful when using `--error-format=short`. It also fixes the column to show the correct span. - Recover from parse errors. Previously we would abort immediately on syntax errors; now we go on to try and type-check the rest of the crate. The new diagnostic code also happens to be slightly shorter. --- compiler/rustc_ast/src/attr/mod.rs | 2 +- compiler/rustc_builtin_macros/messages.ftl | 2 - .../rustc_builtin_macros/src/cmdline_attrs.rs | 57 ++++++++----------- compiler/rustc_builtin_macros/src/errors.rs | 7 --- .../ui/attributes/z-crate-attr/garbage.stderr | 16 +++--- tests/ui/attributes/z-crate-attr/injection.rs | 6 +- .../attributes/z-crate-attr/injection.stderr | 17 ++++-- .../ui/attributes/z-crate-attr/injection2.rs | 3 + .../attributes/z-crate-attr/injection2.stderr | 15 +++++ .../attributes/z-crate-attr/inner-attr.stderr | 6 +- tests/ui/attributes/z-crate-attr/multiple.rs | 4 +- .../attributes/z-crate-attr/multiple.stderr | 8 +-- .../z-crate-attr/unbalanced-paren.rs | 4 +- .../z-crate-attr/unbalanced-paren.stderr | 13 +++-- 14 files changed, 82 insertions(+), 78 deletions(-) create mode 100644 tests/ui/attributes/z-crate-attr/injection2.rs create mode 100644 tests/ui/attributes/z-crate-attr/injection2.stderr diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 0b65246693dd..d656d9b0b8af 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -627,7 +627,7 @@ pub fn mk_doc_comment( Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span } } -pub fn mk_attr( +fn mk_attr( g: &AttrIdGenerator, style: AttrStyle, unsafety: Safety, diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 603dc90bafca..5316e90847ac 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -231,8 +231,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments builtin_macros_format_use_positional = consider using a positional formatting argument instead -builtin_macros_invalid_crate_attribute = invalid crate attribute - builtin_macros_multiple_default_attrs = multiple `#[default]` attributes .note = only one `#[default]` attribute is needed .label = `#[default]` used here diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 6afd8c4b43b9..423b6a15b646 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -1,44 +1,37 @@ //! Attributes injected into the crate root from command line using `-Z crate-attr`. -use rustc_ast::attr::mk_attr; -use rustc_ast::{self as ast, AttrItem, AttrStyle, token}; -use rustc_parse::parser::ForceCollect; -use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; +use rustc_ast::{self as ast}; +use rustc_errors::Diag; +use rustc_parse::parser::attr::InnerAttrPolicy; +use rustc_parse::{parse_in, source_str_to_stream}; use rustc_session::parse::ParseSess; use rustc_span::FileName; -use crate::errors; - pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { - let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str( - psess, - FileName::cli_crate_attr_source_code(raw_attr), - raw_attr.clone(), - )); - - let start_span = parser.token.span; - let AttrItem { unsafety, path, args, tokens: _ } = - match parser.parse_attr_item(ForceCollect::No) { - Ok(ai) => ai, - Err(err) => { + let source = format!("#![{raw_attr}]"); + let parse = || -> Result>> { + let tokens = source_str_to_stream( + psess, + FileName::cli_crate_attr_source_code(raw_attr), + source, + None, + )?; + parse_in(psess, tokens, "", |p| { + p.parse_attribute(InnerAttrPolicy::Permitted) + }) + .map_err(|e| vec![e]) + }; + let meta = match parse() { + Ok(meta) => meta, + Err(errs) => { + for err in errs { err.emit(); - continue; } - }; - let end_span = parser.token.span; - if parser.token != token::Eof { - psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); - continue; - } + continue; + } + }; - krate.attrs.push(mk_attr( - &psess.attr_id_generator, - AttrStyle::Inner, - unsafety, - path, - args, - start_span.to(end_span), - )); + krate.attrs.push(meta); } } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 4bbe212f4296..c2b1dff4cf1f 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -109,13 +109,6 @@ pub(crate) struct ProcMacro { pub(crate) span: Span, } -#[derive(Diagnostic)] -#[diag(builtin_macros_invalid_crate_attribute)] -pub(crate) struct InvalidCrateAttr { - #[primary_span] - pub(crate) span: Span, -} - #[derive(Diagnostic)] #[diag(builtin_macros_non_abi)] pub(crate) struct NonABI { diff --git a/tests/ui/attributes/z-crate-attr/garbage.stderr b/tests/ui/attributes/z-crate-attr/garbage.stderr index 082046e31f8c..12d18b0845fc 100644 --- a/tests/ui/attributes/z-crate-attr/garbage.stderr +++ b/tests/ui/attributes/z-crate-attr/garbage.stderr @@ -1,20 +1,20 @@ error: unknown start of token: ` - --> :1:1 + --> :1:4 | -LL | `%~@$# - | ^ +LL | #![`%~@$#] + | ^ | help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not | -LL - `%~@$# -LL + '%~@$# +LL - #![`%~@$#] +LL + #!['%~@$#] | error: expected identifier, found `%` - --> :1:2 + --> :1:5 | -LL | `%~@$# - | ^ expected identifier +LL | #![`%~@$#] + | ^ expected identifier error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/z-crate-attr/injection.rs b/tests/ui/attributes/z-crate-attr/injection.rs index a91f9d2886e3..ee7a27c7490c 100644 --- a/tests/ui/attributes/z-crate-attr/injection.rs +++ b/tests/ui/attributes/z-crate-attr/injection.rs @@ -1,5 +1,3 @@ //@ compile-flags: '-Zcrate-attr=feature(yeet_expr)]fn main(){}#[inline' - -fn foo() {} - -//~? ERROR unexpected closing delimiter: `]` +//~? ERROR unexpected token +fn foo() {} //~ ERROR `main` function not found diff --git a/tests/ui/attributes/z-crate-attr/injection.stderr b/tests/ui/attributes/z-crate-attr/injection.stderr index 6fec98baf8df..899dad07e604 100644 --- a/tests/ui/attributes/z-crate-attr/injection.stderr +++ b/tests/ui/attributes/z-crate-attr/injection.stderr @@ -1,8 +1,15 @@ -error: unexpected closing delimiter: `]` - --> :1:19 +error: unexpected token: keyword `fn` + --> :1:23 | -LL | feature(yeet_expr)]fn main(){}#[inline - | ^ unexpected closing delimiter +LL | #![feature(yeet_expr)]fn main(){}#[inline] + | ^^ unexpected token after this -error: aborting due to 1 previous error +error[E0601]: `main` function not found in crate `injection` + --> $DIR/injection.rs:3:12 + | +LL | fn foo() {} + | ^ consider adding a `main` function to `$DIR/injection.rs` +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/tests/ui/attributes/z-crate-attr/injection2.rs b/tests/ui/attributes/z-crate-attr/injection2.rs new file mode 100644 index 000000000000..67ae3d17f3e7 --- /dev/null +++ b/tests/ui/attributes/z-crate-attr/injection2.rs @@ -0,0 +1,3 @@ +//@ compile-flags: -Zcrate-attr=feature(yeet_expr)]#![allow(warnings) +//~? ERROR unexpected token +fn foo() {} //~ ERROR `main` function not found diff --git a/tests/ui/attributes/z-crate-attr/injection2.stderr b/tests/ui/attributes/z-crate-attr/injection2.stderr new file mode 100644 index 000000000000..51f54f900a19 --- /dev/null +++ b/tests/ui/attributes/z-crate-attr/injection2.stderr @@ -0,0 +1,15 @@ +error: unexpected token: `#` + --> :1:23 + | +LL | #![feature(yeet_expr)]#![allow(warnings)] + | ^ unexpected token after this + +error[E0601]: `main` function not found in crate `injection2` + --> $DIR/injection2.rs:3:12 + | +LL | fn foo() {} + | ^ consider adding a `main` function to `$DIR/injection2.rs` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/tests/ui/attributes/z-crate-attr/inner-attr.stderr b/tests/ui/attributes/z-crate-attr/inner-attr.stderr index 06a063d310b6..1acb8c2e750b 100644 --- a/tests/ui/attributes/z-crate-attr/inner-attr.stderr +++ b/tests/ui/attributes/z-crate-attr/inner-attr.stderr @@ -1,8 +1,8 @@ error: expected identifier, found `#` - --> :1:1 + --> :1:4 | -LL | #![feature(foo)] - | ^ expected identifier +LL | #![#![feature(foo)]] + | ^ expected identifier error: aborting due to 1 previous error diff --git a/tests/ui/attributes/z-crate-attr/multiple.rs b/tests/ui/attributes/z-crate-attr/multiple.rs index 47d35d2c3fdf..8c60ea64feca 100644 --- a/tests/ui/attributes/z-crate-attr/multiple.rs +++ b/tests/ui/attributes/z-crate-attr/multiple.rs @@ -1,5 +1,3 @@ //@ compile-flags: -Zcrate-attr=feature(foo),feature(bar) - +//~? ERROR expected `]` fn main() {} - -//~? ERROR invalid crate attribute diff --git a/tests/ui/attributes/z-crate-attr/multiple.stderr b/tests/ui/attributes/z-crate-attr/multiple.stderr index 9f968a7e1346..b95c95dcd739 100644 --- a/tests/ui/attributes/z-crate-attr/multiple.stderr +++ b/tests/ui/attributes/z-crate-attr/multiple.stderr @@ -1,8 +1,8 @@ -error: invalid crate attribute - --> :1:1 +error: expected `]`, found `,` + --> :1:16 | -LL | feature(foo),feature(bar) - | ^^^^^^^^^^^^^ +LL | #![feature(foo),feature(bar)] + | ^ expected `]` error: aborting due to 1 previous error diff --git a/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs b/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs index 77d5d698f659..5ef0a75a3a87 100644 --- a/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs +++ b/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs @@ -1,6 +1,4 @@ // Show diagnostics for unbalanced parens. //@ compile-flags: -Zcrate-attr=( - +//~? ERROR mismatched closing delimiter fn main() {} - -//~? ERROR this file contains an unclosed delimiter diff --git a/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr b/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr index 47b1b764ba9a..f6545d1db8bc 100644 --- a/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr +++ b/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr @@ -1,10 +1,11 @@ -error: this file contains an unclosed delimiter - --> :1:2 +error: mismatched closing delimiter: `]` + --> :1:4 | -LL | ( - | -^ - | | - | unclosed delimiter +LL | #![(] + | -^^ mismatched closing delimiter + | || + | |unclosed delimiter + | closing delimiter possibly meant for this error: aborting due to 1 previous error From 2f96e784e2f2085087ababfc509fb877000299fe Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Apr 2025 22:01:54 +0000 Subject: [PATCH 113/222] Visit place in BackwardIncompatibleDropHint statement --- compiler/rustc_borrowck/src/def_use.rs | 3 +++ compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 2 +- compiler/rustc_middle/src/mir/visit.rs | 14 ++++++++++++-- .../src/cleanup_post_borrowck.rs | 3 ++- compiler/rustc_mir_transform/src/simplify.rs | 14 -------------- ...d.method_1.ElaborateDrops.after.panic-abort.mir | 3 --- ....method_1.ElaborateDrops.after.panic-unwind.mir | 3 --- 8 files changed, 19 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index 263f68d6a3dc..b9ced81c46c1 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -77,6 +77,9 @@ pub(crate) fn categorize(context: PlaceContext) -> Option { // Debug info is neither def nor use. PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, + // Backwards incompatible drop hint is not a use, just a marker for linting. + PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint) => None, + PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => { bug!("These statements are not allowed in this MIR phase") } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 64ad1c968565..f6903250a2e9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1301,7 +1301,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { error_reported } - /// Through #123739, backward incompatible drops (BIDs) are introduced. + /// Through #123739, `BackwardIncompatibleDropHint`s (BIDs) are introduced. /// We would like to emit lints whether borrow checking fails at these future drop locations. #[instrument(level = "debug", skip(self, state))] fn check_backward_incompatible_drop( diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 5a038b27337c..bf701e309698 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -859,7 +859,7 @@ impl Debug for Statement<'_> { BackwardIncompatibleDropHint { ref place, reason: _ } => { // For now, we don't record the reason because there is only one use case, // which is to report breaking change in drop order by Edition 2024 - write!(fmt, "backward incompatible drop({place:?})") + write!(fmt, "BackwardIncompatibleDropHint({place:?})") } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 3c83d962900a..de4d5140e857 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -457,9 +457,15 @@ macro_rules! make_mir_visitor { } } } + StatementKind::BackwardIncompatibleDropHint { place, .. } => { + self.visit_place( + place, + PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint), + location + ); + } StatementKind::ConstEvalCounter => {} StatementKind::Nop => {} - StatementKind::BackwardIncompatibleDropHint { .. } => {} } } @@ -1348,6 +1354,8 @@ pub enum NonUseContext { AscribeUserTy(ty::Variance), /// The data of a user variable, for debug info. VarDebugInfo, + /// A `BackwardIncompatibleDropHint` statement, meant for edition 2024 lints. + BackwardIncompatibleDropHint, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -1422,7 +1430,9 @@ impl PlaceContext { use NonUseContext::*; match self { PlaceContext::MutatingUse(_) => ty::Invariant, - PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant, + PlaceContext::NonUse( + StorageDead | StorageLive | VarDebugInfo | BackwardIncompatibleDropHint, + ) => ty::Invariant, PlaceContext::NonMutatingUse( Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | RawBorrow | Projection, diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index cb8440198573..4be67b873f73 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -35,7 +35,8 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck { // MIR building, and are not needed after InstrumentCoverage. CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. }, ) - | StatementKind::FakeRead(..) => statement.make_nop(), + | StatementKind::FakeRead(..) + | StatementKind::BackwardIncompatibleDropHint { .. } => statement.make_nop(), StatementKind::Assign(box ( _, Rvalue::Cast( diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 84905f4a400f..5947637cded9 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -597,20 +597,6 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { self.tcx } - fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { - if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } = - &mut statement.kind - { - self.visit_local( - &mut place.local, - PlaceContext::MutatingUse(MutatingUseContext::Store), - location, - ); - } else { - self.super_statement(statement, location); - } - } - fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir index ee6e16d20fd8..7d7cb76960ed 100644 --- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir +++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir @@ -73,9 +73,6 @@ fn method_1(_1: Guard) -> () { } bb7: { - backward incompatible drop(_2); - backward incompatible drop(_4); - backward incompatible drop(_5); goto -> bb21; } diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir index ee6e16d20fd8..7d7cb76960ed 100644 --- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir +++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir @@ -73,9 +73,6 @@ fn method_1(_1: Guard) -> () { } bb7: { - backward incompatible drop(_2); - backward incompatible drop(_4); - backward incompatible drop(_5); goto -> bb21; } From 75558b2ffe4f7f8ece1c964bf8b791f6f475b914 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Apr 2025 10:11:22 +1100 Subject: [PATCH 114/222] Remove unused `StaticLifetimeVisitor`. --- compiler/rustc_middle/src/ty/diagnostics.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index d3abb3d64b8c..674c7a5e3ee7 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -592,18 +592,6 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { } } -/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. -pub struct StaticLifetimeVisitor<'tcx>(pub Vec, pub crate::hir::map::Map<'tcx>); - -impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { - fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) { - if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = lt.res - { - self.0.push(lt.ident.span); - } - } -} - pub struct IsSuggestableVisitor<'tcx> { tcx: TyCtxt<'tcx>, infer_suggestable: bool, From 7c5f2265e8267f9f116086d31d7ec83c0198c37b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Apr 2025 10:13:05 +1100 Subject: [PATCH 115/222] Remove unused `Map` field from `TraitObjectVisitor`. Also reduce visibility. --- compiler/rustc_middle/src/ty/context.rs | 4 ++-- compiler/rustc_middle/src/ty/diagnostics.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index abf6cbbcd877..92d7645bf747 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2147,7 +2147,7 @@ impl<'tcx> TyCtxt<'tcx> { return vec![]; }; - let mut v = TraitObjectVisitor(vec![], self.hir()); + let mut v = TraitObjectVisitor(vec![]); v.visit_ty_unambig(hir_output); v.0 } @@ -2160,7 +2160,7 @@ impl<'tcx> TyCtxt<'tcx> { scope_def_id: LocalDefId, ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option)> { let hir_id = self.local_def_id_to_hir_id(scope_def_id); - let mut v = TraitObjectVisitor(vec![], self.hir()); + let mut v = TraitObjectVisitor(vec![]); // when the return type is a type alias if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir_fn_decl_by_hir_id(hir_id) && let hir::TyKind::Path(hir::QPath::Resolved( diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 674c7a5e3ee7..09db6eee2c9e 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -571,7 +571,7 @@ pub fn suggest_constraining_type_params<'a>( } /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. -pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>); +pub(crate) struct TraitObjectVisitor<'tcx>(pub(crate) Vec<&'tcx hir::Ty<'tcx>>); impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) { From 1a3dee40628c01733af12bae02c32d856db6cb0d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Apr 2025 10:08:37 +1100 Subject: [PATCH 116/222] Remove `rustc_middle::hir::Map`. It's unused. --- compiler/rustc_middle/src/hir/map.rs | 10 ---------- compiler/rustc_middle/src/hir/mod.rs | 5 ----- 2 files changed, 15 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index daf95420c432..e0dd76bce824 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -18,16 +18,6 @@ use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::query::LocalCrate; use crate::ty::TyCtxt; -// FIXME: the structure was necessary in the past but now it -// only serves as "namespace" for HIR-related methods, and can be -// removed if all the methods are reasonably renamed and moved to tcx -// (https://github.com/rust-lang/rust/pull/118256#issuecomment-1826442834). -#[allow(unused)] // FIXME: temporary -#[derive(Copy, Clone)] -pub struct Map<'hir> { - pub(super) tcx: TyCtxt<'hir>, -} - /// An iterator that walks up the ancestor tree of a given `HirId`. /// Constructed using `tcx.hir_parent_iter(hir_id)`. struct ParentHirIterator<'tcx> { diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 640ac70d3a75..a28dcb0cb8ef 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -116,11 +116,6 @@ impl ModuleItems { } impl<'tcx> TyCtxt<'tcx> { - #[inline(always)] - pub fn hir(self) -> map::Map<'tcx> { - map::Map { tcx: self } - } - pub fn parent_module(self, id: HirId) -> LocalModDefId { if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod { LocalModDefId::new_unchecked(id.owner.def_id) From 9734e44b836fa66546b7acc116ad579685f5112e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Apr 2025 13:00:45 +1100 Subject: [PATCH 117/222] Documentation fixes. Remove old references to the HIR map. --- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_middle/src/hir/map.rs | 6 ++- compiler/rustc_middle/src/query/mod.rs | 16 +++---- .../rustc-dev-guide/src/appendix/glossary.md | 1 - src/doc/rustc-dev-guide/src/hir.md | 43 ++++++++----------- 5 files changed, 33 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 93d20dfa7996..3c2897ef1d95 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -6,7 +6,7 @@ //! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR. //! - Example: find all items with a `#[foo]` attribute on them. //! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids -//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and +//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir_item*(id)` to filter and //! access actual item-like thing, respectively. //! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access //! the hir_owners themselves or not. diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index e0dd76bce824..fee707f7b4c9 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1,3 +1,7 @@ +//! This module used to contain a type called `Map`. That type has since been +//! eliminated, and all its methods are now on `TyCtxt`. But the module name +//! stays as `map` because there isn't an obviously better name for it. + use rustc_abi::ExternAbi; use rustc_ast::visit::{VisitorResult, walk_list}; use rustc_data_structures::fingerprint::Fingerprint; @@ -325,7 +329,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns an iterator of the `DefId`s for all body-owners in this /// crate. If you would prefer to iterate over the bodies - /// themselves, you can do `self.hir().krate().body_ids.iter()`. + /// themselves, you can do `self.hir_crate(()).body_ids.iter()`. #[inline] pub fn hir_body_owners(self) -> impl Iterator { self.hir_crate_items(()).body_owners.iter().copied() diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 28a59d3e73e8..e94f088304b1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -161,11 +161,11 @@ rustc_queries! { /// Represents crate as a whole (as distinct from the top-level crate module). /// - /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir_crate()`), - /// we will have to assume that any change means that you need to be recompiled. - /// This is because the `hir_crate` query gives you access to all other items. - /// To avoid this fate, do not call `tcx.hir_crate()`; instead, - /// prefer wrappers like [`TyCtxt::hir_visit_all_item_likes_in_crate`]. + /// If you call `tcx.hir_crate(())` we will have to assume that any change + /// means that you need to be recompiled. This is because the `hir_crate` + /// query gives you access to all other items. To avoid this fate, do not + /// call `tcx.hir_crate(())`; instead, prefer wrappers like + /// [`TyCtxt::hir_visit_all_item_likes_in_crate`]. query hir_crate(key: ()) -> &'tcx Crate<'tcx> { arena_cache eval_always @@ -197,7 +197,7 @@ rustc_queries! { /// Gives access to the HIR node's parent for the HIR owner `key`. /// - /// This can be conveniently accessed by methods on `tcx.hir()`. + /// This can be conveniently accessed by `tcx.hir_*` methods. /// Avoid calling this query directly. query hir_owner_parent(key: hir::OwnerId) -> hir::HirId { desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) } @@ -205,7 +205,7 @@ rustc_queries! { /// Gives access to the HIR nodes and bodies inside `key` if it's a HIR owner. /// - /// This can be conveniently accessed by methods on `tcx.hir()`. + /// This can be conveniently accessed by `tcx.hir_*` methods. /// Avoid calling this query directly. query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> { desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) } @@ -214,7 +214,7 @@ rustc_queries! { /// Gives access to the HIR attributes inside the HIR owner `key`. /// - /// This can be conveniently accessed by methods on `tcx.hir()`. + /// This can be conveniently accessed by `tcx.hir_*` methods. /// Avoid calling this query directly. query hir_attr_map(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> { desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) } diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index a7c3236d356b..1837b59e850a 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -31,7 +31,6 @@ Term | Meaning generics | The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters. HIR | The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md)) `HirId` | Identifies a particular node in the HIR by combining a def-id with an "intra-definition offset". See [the HIR chapter for more](../hir.md#identifiers-in-the-hir). -HIR map | The HIR map, accessible via `tcx.hir()`, allows you to quickly navigate the HIR and convert between various forms of identifiers. ICE | Short for _internal compiler error_, this is when the compiler crashes. ICH | Short for _incremental compilation hash_, these are used as fingerprints for things such as HIR and crate metadata, to check if changes have been made. This is useful in incremental compilation to see if part of a crate has changed and should be recompiled. `infcx` | The type inference context (`InferCtxt`). (see `rustc_middle::infer`) diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md index 75f5a9e20452..65779f3129d9 100644 --- a/src/doc/rustc-dev-guide/src/hir.md +++ b/src/doc/rustc-dev-guide/src/hir.md @@ -100,7 +100,7 @@ The HIR uses a bunch of different identifiers that coexist and serve different p a wrapper around a [`HirId`]. For more info about HIR bodies, please refer to the [HIR chapter][hir-bodies]. -These identifiers can be converted into one another through the [HIR map][map]. +These identifiers can be converted into one another through the `TyCtxt`. [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html [`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html @@ -110,30 +110,24 @@ These identifiers can be converted into one another through the [HIR map][map]. [`CrateNum`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.CrateNum.html [`DefIndex`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefIndex.html [`Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html -[hir-map]: ./hir.md#the-hir-map [hir-bodies]: ./hir.md#hir-bodies -[map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html -## The HIR Map +## HIR Operations Most of the time when you are working with the HIR, you will do so via -the **HIR Map**, accessible in the tcx via [`tcx.hir()`] (and defined in -the [`hir::map`] module). The [HIR map] contains a [number of methods] to -convert between IDs of various kinds and to lookup data associated -with a HIR node. +`TyCtxt`. It contains a number of methods, defined in the `hir::map` module and +mostly prefixed with `hir_`, to convert between IDs of various kinds and to +lookup data associated with a HIR node. -[`tcx.hir()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir -[`hir::map`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/index.html -[HIR map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html -[number of methods]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#methods +[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html For example, if you have a [`LocalDefId`], and you would like to convert it -to a [`HirId`], you can use [`tcx.hir().local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id]. +to a [`HirId`], you can use [`tcx.local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id]. You need a `LocalDefId`, rather than a `DefId`, since only local items have HIR nodes. -[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.local_def_id_to_hir_id +[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.local_def_id_to_hir_id -Similarly, you can use [`tcx.hir().find(n)`][find] to lookup the node for a +Similarly, you can use [`tcx.hir_node(n)`][hir_node] to lookup the node for a [`HirId`]. This returns a `Option>`, where [`Node`] is an enum defined in the map. By matching on this, you can find out what sort of node the `HirId` referred to and also get a pointer to the data @@ -142,15 +136,16 @@ that `n` must be some HIR expression, you can do [`tcx.hir_expect_expr(n)`][expect_expr], which will extract and return the [`&hir::Expr`][Expr], panicking if `n` is not in fact an expression. -[find]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.find +[hir_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_node [`Node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html [expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.expect_expr [Expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Expr.html -Finally, you can use the HIR map to find the parents of nodes, via -calls like [`tcx.hir().get_parent(n)`][get_parent]. +Finally, you can find the parents of nodes, via +calls like [`tcx.parent_hir_node(n)`][parent_hir_node]. + +[get_parent_item]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.parent_hir_node -[get_parent]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.get_parent ## HIR Bodies @@ -158,10 +153,10 @@ A [`rustc_hir::Body`] represents some kind of executable code, such as the body of a function/closure or the definition of a constant. Bodies are associated with an **owner**, which is typically some kind of item (e.g. an `fn()` or `const`), but could also be a closure expression -(e.g. `|x, y| x + y`). You can use the HIR map to find the body -associated with a given def-id ([`maybe_body_owned_by`]) or to find -the owner of a body ([`body_owner_def_id`]). +(e.g. `|x, y| x + y`). You can use the `TyCtxt` to find the body +associated with a given def-id ([`hir_maybe_body_owned_by`]) or to find +the owner of a body ([`hir_body_owner_def_id`]). [`rustc_hir::Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html -[`maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.maybe_body_owned_by -[`body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.body_owner_def_id +[`hir_maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_maybe_body_owned_by +[`hir_body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_body_owner_def_id From ed5f31ab01d41a01b7206eafdf97b458dc41141a Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sun, 13 Apr 2025 04:21:10 -0700 Subject: [PATCH 118/222] Avoid unused clones in Cloned and Copied Avoid cloning in `Cloned` or copying in `Copied` when elements are only needed by reference or not at all. There is already some precedent for this, given that `__iterator_get_unchecked` is implemented, which can skip elements. The reduced clones are technically observable by a user impl of `Clone`. --- library/core/src/iter/adapters/cloned.rs | 88 +++++++++++++++++++++- library/core/src/iter/adapters/copied.rs | 95 +++++++++++++++++++----- 2 files changed, 163 insertions(+), 20 deletions(-) diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index aea6d64281ae..72d746289711 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,5 +1,6 @@ use core::num::NonZero; +use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; @@ -41,13 +42,31 @@ where self.it.next().cloned() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } + #[inline] + fn count(self) -> usize { + self.it.count() + } + + fn last(self) -> Option { + self.it.last().cloned() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_by(n) + } + + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).cloned() + } + fn try_fold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -61,6 +80,58 @@ where self.it.map(T::clone).fold(init, f) } + fn find

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.find(move |x| predicate(&x)).cloned() + } + + fn max_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.max_by(move |&x, &y| compare(x, y)).cloned() + } + + fn min_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.min_by(move |&x, &y| compare(x, y)).cloned() + } + + fn cmp(self, other: O) -> Ordering + where + O: IntoIterator, + Self::Item: Ord, + { + self.it.cmp_by(other, |x, y| x.cmp(&y)) + } + + fn partial_cmp(self, other: O) -> Option + where + O: IntoIterator, + Self::Item: PartialOrd, + { + self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + } + + fn eq(self, other: O) -> bool + where + O: IntoIterator, + Self::Item: PartialEq, + { + self.it.eq_by(other, |x, y| x == &y) + } + + fn is_sorted_by(self, mut compare: F) -> bool + where + F: FnMut(&Self::Item, &Self::Item) -> bool, + { + self.it.is_sorted_by(move |&x, &y| compare(x, y)) + } + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccessNoCoerce, @@ -81,9 +152,13 @@ where self.it.next_back().cloned() } + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_back_by(n) + } + fn try_rfold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -96,6 +171,13 @@ where { self.it.map(T::clone).rfold(init, f) } + + fn rfind

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.rfind(move |x| predicate(&x)).cloned() + } } #[stable(feature = "iter_cloned", since = "1.1.0")] @@ -104,10 +186,12 @@ where I: ExactSizeIterator, T: Clone, { + #[inline] fn len(&self) -> usize { self.it.len() } + #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 23e4e25ab538..73913aa34a9e 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,3 +1,4 @@ +use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; @@ -48,20 +49,35 @@ where fn next_chunk( &mut self, - ) -> Result<[Self::Item; N], array::IntoIter> - where - Self: Sized, - { + ) -> Result<[Self::Item; N], array::IntoIter> { >::spec_next_chunk(&mut self.it) } + #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } + #[inline] + fn count(self) -> usize { + self.it.count() + } + + fn last(self) -> Option { + self.it.last().copied() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_by(n) + } + + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).copied() + } + fn try_fold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -75,21 +91,56 @@ where self.it.fold(init, copy_fold(f)) } - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).copied() + fn find

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.find(move |x| predicate(&x)).copied() } - fn last(self) -> Option { - self.it.last().copied() + fn max_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.max_by(move |&x, &y| compare(x, y)).copied() } - fn count(self) -> usize { - self.it.count() + fn min_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.min_by(move |&x, &y| compare(x, y)).copied() } - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_by(n) + fn cmp(self, other: O) -> Ordering + where + O: IntoIterator, + Self::Item: Ord, + { + self.it.cmp_by(other, |x, y| x.cmp(&y)) + } + + fn partial_cmp(self, other: O) -> Option + where + O: IntoIterator, + Self::Item: PartialOrd, + { + self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + } + + fn eq(self, other: O) -> bool + where + O: IntoIterator, + Self::Item: PartialEq, + { + self.it.eq_by(other, |x, y| x == &y) + } + + fn is_sorted_by(self, mut compare: F) -> bool + where + F: FnMut(&Self::Item, &Self::Item) -> bool, + { + self.it.is_sorted_by(move |&x, &y| compare(x, y)) } unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T @@ -112,9 +163,13 @@ where self.it.next_back().copied() } + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_back_by(n) + } + fn try_rfold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -128,9 +183,11 @@ where self.it.rfold(init, copy_fold(f)) } - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_back_by(n) + fn rfind

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.rfind(move |x| predicate(&x)).copied() } } @@ -140,10 +197,12 @@ where I: ExactSizeIterator, T: Copy, { + #[inline] fn len(&self) -> usize { self.it.len() } + #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } From 3efd9f5d0c39c427025c7f388c7793017d2eea18 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Mon, 14 Apr 2025 01:38:18 +0200 Subject: [PATCH 119/222] Switch to `diagnostic::on_unimplemented` --- compiler/rustc_data_structures/src/marker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 744ae9b6fe2a..5f07cfef1335 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -1,13 +1,13 @@ use std::alloc::Allocator; -#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \ +#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")] // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()` // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a // `Send` type in `IntoDynSyncSend` will create a `DynSend` type. pub unsafe auto trait DynSend {} -#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \ +#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`")] // This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()` // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a From c73598f0fb0ef2cfcdc784e577a96bb8041445ba Mon Sep 17 00:00:00 2001 From: xizheyin Date: Mon, 17 Mar 2025 22:22:32 +0800 Subject: [PATCH 120/222] Report span of test when should_panic test failed Signed-off-by: xizheyin --- library/test/src/test_result.rs | 7 +++- .../failed-doctest-should-panic.stdout | 2 +- .../test-should-panic-failed-show-span.rs | 42 +++++++++++++++++++ ...t-should-panic-failed-show-span.run.stdout | 38 +++++++++++++++++ .../test-should-panic-failed-show-span.stderr | 21 ++++++++++ 5 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 tests/ui/test-attrs/test-should-panic-failed-show-span.rs create mode 100644 tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout create mode 100644 tests/ui/test-attrs/test-should-panic-failed-show-span.stderr diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index 959cd730fa43..a312894c25c4 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -77,7 +77,12 @@ pub(crate) fn calc_result( // The test should have panicked, but didn't panic. (ShouldPanic::Yes, None) | (ShouldPanic::YesWithMessage(_), None) => { - TestResult::TrFailedMsg("test did not panic as expected".to_string()) + let fn_location = if !desc.source_file.is_empty() { + &format!(" at {}:{}:{}", desc.source_file, desc.start_line, desc.start_col) + } else { + "" + }; + TestResult::TrFailedMsg(format!("test did not panic as expected{}", fn_location)) } // The test should not have panicked, but did panic. diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout index 90c0463d832e..2b04b77c9dc5 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout @@ -5,7 +5,7 @@ test $DIR/failed-doctest-should-panic.rs - Foo (line 10) - should panic ... FAIL failures: ---- $DIR/failed-doctest-should-panic.rs - Foo (line 10) stdout ---- -note: test did not panic as expected +note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:10:0 failures: $DIR/failed-doctest-should-panic.rs - Foo (line 10) diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.rs b/tests/ui/test-attrs/test-should-panic-failed-show-span.rs new file mode 100644 index 000000000000..960673bcc0d9 --- /dev/null +++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.rs @@ -0,0 +1,42 @@ +//@ run-fail +//@ check-run-results +//@ compile-flags: --test +//@ exec-env:RUST_BACKTRACE=0 +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ run-flags: --test-threads=1 + +#[test] +#[should_panic] +fn should_panic_with_any_message() { + panic!("Panic!"); +} + +#[test] +#[should_panic = "message"] +fn should_panic_with_message() { + panic!("message"); +} + +#[test] +#[should_panic] +fn should_panic_with_any_message_does_not_panic() { + // DON'T PANIC +} + +#[test] +#[should_panic = "message"] +fn should_panic_with_message_does_not_panic() { + // DON'T PANIC +} + +#[test] +#[should_panic = "message"] +fn should_panic_with_substring_panics_with_incorrect_string() { + panic!("ZOMGWTFBBQ"); +} + +#[test] +#[should_panic = "message"] +fn should_panic_with_substring_panics_with_non_string_value() { + panic!(123); //~ WARNING panic message is not a string literal +} diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout new file mode 100644 index 000000000000..4edc67694b9e --- /dev/null +++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout @@ -0,0 +1,38 @@ + +running 6 tests +test should_panic_with_any_message - should panic ... ok +test should_panic_with_any_message_does_not_panic - should panic ... FAILED +test should_panic_with_message - should panic ... ok +test should_panic_with_message_does_not_panic - should panic ... FAILED +test should_panic_with_substring_panics_with_incorrect_string - should panic ... FAILED +test should_panic_with_substring_panics_with_non_string_value - should panic ... FAILED + +failures: + +---- should_panic_with_any_message_does_not_panic stdout ---- +note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:22:4 +---- should_panic_with_message_does_not_panic stdout ---- +note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:28:4 +---- should_panic_with_substring_panics_with_incorrect_string stdout ---- + +thread 'should_panic_with_substring_panics_with_incorrect_string' panicked at $DIR/test-should-panic-failed-show-span.rs:35:5: +ZOMGWTFBBQ +note: panic did not contain expected string + panic message: `"ZOMGWTFBBQ"`, + expected substring: `"message"` +---- should_panic_with_substring_panics_with_non_string_value stdout ---- + +thread 'should_panic_with_substring_panics_with_non_string_value' panicked at $DIR/test-should-panic-failed-show-span.rs:41:5: +Box +note: expected panic with string value, + found non-string value: `TypeId(0x56ced5e4a15bd89050bb9674fa2df013)` + expected substring: `"message"` + +failures: + should_panic_with_any_message_does_not_panic + should_panic_with_message_does_not_panic + should_panic_with_substring_panics_with_incorrect_string + should_panic_with_substring_panics_with_non_string_value + +test result: FAILED. 2 passed; 4 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.stderr b/tests/ui/test-attrs/test-should-panic-failed-show-span.stderr new file mode 100644 index 000000000000..e803ff5513c6 --- /dev/null +++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.stderr @@ -0,0 +1,21 @@ +warning: panic message is not a string literal + --> $DIR/test-should-panic-failed-show-span.rs:41:12 + | +LL | panic!(123); + | ^^^ + | + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 + = note: for more information, see + = note: `#[warn(non_fmt_panics)]` on by default +help: add a "{}" format string to `Display` the message + | +LL | panic!("{}", 123); + | +++++ +help: or use std::panic::panic_any instead + | +LL - panic!(123); +LL + std::panic::panic_any(123); + | + +warning: 1 warning emitted + From dc3a586eed198548316fcbfff2d5c28df0728750 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 8 Apr 2025 09:40:37 +0800 Subject: [PATCH 121/222] Adjust test directives Signed-off-by: xizheyin --- .../test-should-panic-failed-show-span.rs | 10 ++++++--- ...t-should-panic-failed-show-span.run.stderr | 13 ++++++++++++ ...t-should-panic-failed-show-span.run.stdout | 12 +++-------- .../test-should-panic-failed-show-span.stderr | 21 ------------------- 4 files changed, 23 insertions(+), 33 deletions(-) create mode 100644 tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr delete mode 100644 tests/ui/test-attrs/test-should-panic-failed-show-span.stderr diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.rs b/tests/ui/test-attrs/test-should-panic-failed-show-span.rs index 960673bcc0d9..f400f614142d 100644 --- a/tests/ui/test-attrs/test-should-panic-failed-show-span.rs +++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.rs @@ -1,9 +1,12 @@ +//@ compile-flags: --test +//@ run-flags: --test-threads=1 --nocapture //@ run-fail //@ check-run-results -//@ compile-flags: --test //@ exec-env:RUST_BACKTRACE=0 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ run-flags: --test-threads=1 +//@ normalize-stdout: "TypeId\(0x[0-9a-f]+\)" -> "TypeId($$HEX)" +//@ needs-threads +//@ needs-unwind (panic) #[test] #[should_panic] @@ -37,6 +40,7 @@ fn should_panic_with_substring_panics_with_incorrect_string() { #[test] #[should_panic = "message"] +#[expect(non_fmt_panics)] fn should_panic_with_substring_panics_with_non_string_value() { - panic!(123); //~ WARNING panic message is not a string literal + panic!(123); } diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr new file mode 100644 index 000000000000..db379a16b52a --- /dev/null +++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr @@ -0,0 +1,13 @@ + +thread 'should_panic_with_any_message' panicked at $DIR/test-should-panic-failed-show-span.rs:14:5: +Panic! +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + +thread 'should_panic_with_message' panicked at $DIR/test-should-panic-failed-show-span.rs:20:5: +message + +thread 'should_panic_with_substring_panics_with_incorrect_string' panicked at $DIR/test-should-panic-failed-show-span.rs:38:5: +ZOMGWTFBBQ + +thread 'should_panic_with_substring_panics_with_non_string_value' panicked at $DIR/test-should-panic-failed-show-span.rs:45:5: +Box diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout index 4edc67694b9e..75600b4d3d66 100644 --- a/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout +++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout @@ -10,22 +10,16 @@ test should_panic_with_substring_panics_with_non_string_value - should panic ... failures: ---- should_panic_with_any_message_does_not_panic stdout ---- -note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:22:4 +note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:25:4 ---- should_panic_with_message_does_not_panic stdout ---- -note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:28:4 +note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:31:4 ---- should_panic_with_substring_panics_with_incorrect_string stdout ---- - -thread 'should_panic_with_substring_panics_with_incorrect_string' panicked at $DIR/test-should-panic-failed-show-span.rs:35:5: -ZOMGWTFBBQ note: panic did not contain expected string panic message: `"ZOMGWTFBBQ"`, expected substring: `"message"` ---- should_panic_with_substring_panics_with_non_string_value stdout ---- - -thread 'should_panic_with_substring_panics_with_non_string_value' panicked at $DIR/test-should-panic-failed-show-span.rs:41:5: -Box note: expected panic with string value, - found non-string value: `TypeId(0x56ced5e4a15bd89050bb9674fa2df013)` + found non-string value: `TypeId($HEX)` expected substring: `"message"` failures: diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.stderr b/tests/ui/test-attrs/test-should-panic-failed-show-span.stderr deleted file mode 100644 index e803ff5513c6..000000000000 --- a/tests/ui/test-attrs/test-should-panic-failed-show-span.stderr +++ /dev/null @@ -1,21 +0,0 @@ -warning: panic message is not a string literal - --> $DIR/test-should-panic-failed-show-span.rs:41:12 - | -LL | panic!(123); - | ^^^ - | - = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 - = note: for more information, see - = note: `#[warn(non_fmt_panics)]` on by default -help: add a "{}" format string to `Display` the message - | -LL | panic!("{}", 123); - | +++++ -help: or use std::panic::panic_any instead - | -LL - panic!(123); -LL + std::panic::panic_any(123); - | - -warning: 1 warning emitted - From edfdb9205c9f507628d957b048420a8d3a29a0d2 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Mon, 14 Apr 2025 14:00:04 +0800 Subject: [PATCH 122/222] Add ui test unreachable-by-call-arguments-issue-139627.rs Signed-off-by: xizheyin --- ...eachable-by-call-arguments-issue-139627.rs | 15 ++++++++ ...able-by-call-arguments-issue-139627.stderr | 36 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs create mode 100644 tests/ui/reachable/unreachable-by-call-arguments-issue-139627.stderr diff --git a/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs new file mode 100644 index 000000000000..422ae95e8b72 --- /dev/null +++ b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs @@ -0,0 +1,15 @@ +#![deny(unreachable_code)] +#![deny(unused)] + +pub enum Void {} + +pub struct S(T); + +pub fn foo(void: Void, void1: Void) { //~ ERROR unused variable: `void1` + let s = S(void); //~ ERROR unused variable: `s` + drop(s); //~ ERROR unreachable expression + let s1 = S { 0: void1 }; + drop(s1); +} + +fn main() {} diff --git a/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.stderr b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.stderr new file mode 100644 index 000000000000..ce24705324e5 --- /dev/null +++ b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.stderr @@ -0,0 +1,36 @@ +error: unreachable expression + --> $DIR/unreachable-by-call-arguments-issue-139627.rs:10:10 + | +LL | let s = S(void); + | ------- any code following this expression is unreachable +LL | drop(s); + | ^ unreachable expression + | +note: this expression has type `S`, which is uninhabited + --> $DIR/unreachable-by-call-arguments-issue-139627.rs:9:13 + | +LL | let s = S(void); + | ^^^^^^^ +note: the lint level is defined here + --> $DIR/unreachable-by-call-arguments-issue-139627.rs:2:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unreachable_code)]` implied by `#[deny(unused)]` + +error: unused variable: `s` + --> $DIR/unreachable-by-call-arguments-issue-139627.rs:9:9 + | +LL | let s = S(void); + | ^ help: if this is intentional, prefix it with an underscore: `_s` + | + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: unused variable: `void1` + --> $DIR/unreachable-by-call-arguments-issue-139627.rs:8:24 + | +LL | pub fn foo(void: Void, void1: Void) { + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_void1` + +error: aborting due to 3 previous errors + From abce592029671a2f65e50901ad5fc55e42fdf930 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 11 Apr 2025 19:44:11 +1000 Subject: [PATCH 123/222] Use `Symbol` in `LateContext::get_associated_type`. To avoid unnecessary interning. --- compiler/rustc_lint/src/context.rs | 9 +++++++-- compiler/rustc_lint/src/deref_into_dyn_supertrait.rs | 2 +- src/tools/clippy/clippy_lints/src/format_args.rs | 2 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 2 +- .../clippy_lints/src/methods/iter_overeager_cloned.rs | 2 +- .../clippy_lints/src/methods/unnecessary_iter_cloned.rs | 2 +- .../clippy_lints/src/methods/unnecessary_to_owned.rs | 6 +++--- src/tools/clippy/clippy_utils/src/ty/mod.rs | 2 +- 8 files changed, 16 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 16c9e08c78d3..a2d5ffe256d5 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -855,11 +855,16 @@ impl<'tcx> LateContext<'tcx> { &self, self_ty: Ty<'tcx>, trait_id: DefId, - name: &str, + name: Symbol, ) -> Option> { let tcx = self.tcx; tcx.associated_items(trait_id) - .find_by_ident_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) + .find_by_ident_and_kind( + tcx, + Ident::with_dummy_span(name), + ty::AssocKind::Type, + trait_id, + ) .and_then(|assoc| { let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]); tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok() diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index ec8f84415759..5989ef9519cd 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { && let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind() && let Some(self_principal) = data.principal() // `::Target` is `dyn target_principal` - && let Some(target) = cx.get_associated_type(self_ty, did, "Target") + && let Some(target) = cx.get_associated_type(self_ty, did, sym::Target) && let ty::Dynamic(data, _, ty::Dyn) = target.kind() && let Some(target_principal) = data.principal() // `target_principal` is a supertrait of `t_principal` diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 3862ff7921db..06224f57c5c5 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -550,7 +550,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { // a `Target` that is in `self.ty_msrv_map`. if let Some(deref_trait_id) = self.cx.tcx.lang_items().deref_trait() && implements_trait(self.cx, ty, deref_trait_id, &[]) - && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, "Target") + && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, sym::Target) && let Some(msrv) = self.ty_msrv_map.get(&target_ty) && msrv.is_none_or(|msrv| self.msrv.meets(self.cx, msrv)) { diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 72e22ae59d8f..b01929747d69 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -644,7 +644,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { && cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| { implements_trait(cx, ty, deref_id, &[]) && cx - .get_associated_type(ty, deref_id, "Target") + .get_associated_type(ty, deref_id, sym::Target) .is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1)) })) }, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index f51bdc78f8a5..7bb625222ec0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -48,7 +48,7 @@ pub(super) fn check<'tcx>( && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id) && cx.tcx.trait_of_item(method_id) == Some(iter_id) && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv) - && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item") + && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, sym::Item) && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty)) { if needs_into_iter diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index c0e015685881..20cf35363d13 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -99,7 +99,7 @@ pub fn check_for_loop_iter( && let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) && let collection_ty = cx.typeck_results().expr_ty(collection) && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) - && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") + && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, sym::Item) && iter_item_ty == into_iter_item_ty && let Some(collection_snippet) = collection.span.get_source_text(cx) { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 62ba3012643c..206b0a8ae3cd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -153,7 +153,7 @@ fn check_addr_of_expr( } if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && implements_trait(cx, receiver_ty, deref_trait_id, &[]) - && cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty) + && cx.get_associated_type(receiver_ty, deref_trait_id, sym::Target) == Some(target_ty) // Make sure that it's actually calling the right `.to_string()`, (#10033) // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow) // but that's ok for Cow::into_owned specifically) @@ -322,7 +322,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb // add `.as_ref()` to the suggestion. let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String) && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) - && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, "Target") + && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, sym::Target) != Some(cx.tcx.types.str_) { ".as_ref()" @@ -648,7 +648,7 @@ fn is_to_string_on_string_like<'a>( && let GenericArgKind::Type(ty) = generic_arg.unpack() && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) - && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) + && (cx.get_associated_type(ty, deref_trait_id, sym::Target) == Some(cx.tcx.types.str_) || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { true diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 29cbf62c3d4c..3779e2f30623 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -156,7 +156,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { cx.tcx .get_diagnostic_item(sym::Iterator) - .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item")) + .and_then(|iter_did| cx.get_associated_type(ty, iter_did, sym::Item)) } /// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type From ce2aa97cd647bdfcb5859489d93526622bb388a0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 11 Apr 2025 06:28:59 +1000 Subject: [PATCH 124/222] Move `has_self` field to `hir::AssocKind::Fn`. `hir::AssocItem` currently has a boolean `fn_has_self_parameter` field, which is misplaced, because it's only relevant for associated fns, not for associated consts or types. This commit moves it (and renames it) to the `AssocKind::Fn` variant, where it belongs. This requires introducing a new C-style enum, `AssocTag`, which is like `AssocKind` but without the fields. This is because `AssocKind` values are passed to various functions like `find_by_ident_and_kind` to indicate what kind of associated item should be searched for, and having to specify `has_self` isn't relevant there. New methods: - Predicates `AssocItem::is_fn` and `AssocItem::is_method`. - `AssocItem::as_tag` which converts `AssocItem::kind` to `AssocTag`. Removed `find_by_name_and_kinds`, which is unused. `AssocItem::descr` can now distinguish between methods and associated functions, which slightly improves some error messages. --- compiler/rustc_ast_lowering/src/delegation.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 2 +- .../rustc_codegen_cranelift/src/main_shim.rs | 4 +- .../rustc_hir_analysis/src/check/check.rs | 4 +- .../src/check/compare_impl_item.rs | 14 +- compiler/rustc_hir_analysis/src/check/mod.rs | 8 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 6 +- compiler/rustc_hir_analysis/src/collect.rs | 6 +- .../src/collect/resolve_bound_vars.rs | 16 +-- .../src/collect/type_of/opaque.rs | 4 +- .../src/hir_ty_lowering/bounds.rs | 26 ++-- .../src/hir_ty_lowering/errors.rs | 57 ++++---- .../src/hir_ty_lowering/mod.rs | 124 ++++++++++-------- .../rustc_hir_analysis/src/impl_wf_check.rs | 2 +- compiler/rustc_hir_typeck/src/demand.rs | 10 +- compiler/rustc_hir_typeck/src/expr.rs | 4 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 5 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 2 +- compiler/rustc_hir_typeck/src/method/mod.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 15 +-- .../rustc_hir_typeck/src/method/suggest.rs | 27 ++-- compiler/rustc_lint/src/context.rs | 7 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 11 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 4 +- compiler/rustc_middle/src/ty/adjustment.rs | 4 +- compiler/rustc_middle/src/ty/assoc.rs | 62 +++++---- compiler/rustc_middle/src/ty/instance.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 4 +- .../src/builder/matches/test.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 2 +- .../src/mono_checks/move_check.rs | 4 +- .../rustc_resolve/src/late/diagnostics.rs | 2 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 2 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 5 +- .../rustc_smir/src/stable_mir/mir/pretty.rs | 3 +- compiler/rustc_smir/src/stable_mir/ty.rs | 6 +- .../src/error_reporting/infer/mod.rs | 8 +- .../trait_impl_difference.rs | 2 +- .../infer/nice_region_error/util.rs | 2 +- .../error_reporting/infer/note_and_explain.rs | 2 +- .../src/error_reporting/traits/ambiguity.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 2 +- .../src/traits/dyn_compatibility.rs | 4 +- .../src/traits/vtable.rs | 6 +- compiler/rustc_ty_utils/src/assoc.rs | 20 ++- src/librustdoc/clean/inline.rs | 12 +- src/librustdoc/clean/mod.rs | 4 +- .../src/bool_assert_comparison.rs | 2 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 11 +- .../src/methods/needless_collect.rs | 4 +- .../clippy_lints/src/methods/or_fun_call.rs | 2 +- .../src/needless_borrows_for_generic_args.rs | 2 +- .../clippy_lints/src/same_name_method.rs | 3 +- .../src/unconditional_recursion.rs | 4 +- .../clippy/clippy_lints/src/unused_self.rs | 2 +- src/tools/clippy/clippy_utils/src/ty/mod.rs | 6 +- .../impl_bounds.stderr | 4 +- .../normalize/normalize-param-env-2.stderr | 4 +- 60 files changed, 288 insertions(+), 284 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 2296b05f69b4..93c627f64c96 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .delegation_fn_sigs .get(&local_def_id) .is_some_and(|sig| sig.has_self), - None => self.tcx.associated_item(def_id).fn_has_self_parameter, + None => self.tcx.associated_item(def_id).is_method(), }, _ => span_bug!(span, "unexpected DefKind for delegation item"), } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8a8ecc3b96e3..fe6dff7ff1b6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -647,7 +647,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { && tc.polarity() == ty::PredicatePolarity::Positive && supertrait_def_ids(tcx, tc.def_id()) .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order()) - .any(|item| item.fn_has_self_parameter) + .any(|item| item.is_method()) }) }) { return None; diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 3b48adb7e918..6eef97c14dd2 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -1,6 +1,6 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_hir::LangItem; -use rustc_middle::ty::{AssocKind, GenericArg}; +use rustc_middle::ty::{AssocTag, GenericArg}; use rustc_session::config::EntryFnType; use rustc_span::{DUMMY_SP, Ident}; @@ -107,7 +107,7 @@ pub(crate) fn maybe_create_entry_wrapper( .find_by_ident_and_kind( tcx, Ident::from_str("report"), - AssocKind::Fn, + AssocTag::Fn, termination_trait, ) .unwrap(); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f50746dd18d6..c2706a1d4013 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -443,7 +443,7 @@ fn best_definition_site_of_opaque<'tcx>( let impl_def_id = tcx.local_parent(parent); for assoc in tcx.associated_items(impl_def_id).in_definition_order() { match assoc.kind { - ty::AssocKind::Const | ty::AssocKind::Fn => { + ty::AssocKind::Const | ty::AssocKind::Fn { .. } => { if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local()) { return Some(span); @@ -942,7 +942,7 @@ fn check_impl_items_against_trait<'tcx>( if res.is_ok() { match ty_impl_item.kind { - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait( tcx, ty_impl_item, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 29a9931696ff..7dfdf1ae237d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -43,7 +43,7 @@ pub(super) fn compare_impl_item( debug!(?impl_trait_ref); match impl_item.kind { - ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref), + ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref), ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref), ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref), } @@ -1036,7 +1036,7 @@ fn report_trait_method_mismatch<'tcx>( ); match &terr { TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0) - if trait_m.fn_has_self_parameter => + if trait_m.is_method() => { let ty = trait_sig.inputs()[0]; let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty()); @@ -1255,7 +1255,7 @@ fn compare_self_type<'tcx>( get_self_string(self_arg_ty, can_eq_self) }; - match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) { + match (trait_m.is_method(), impl_m.is_method()) { (false, false) | (true, true) => {} (false, true) => { @@ -1363,7 +1363,7 @@ fn compare_number_of_generics<'tcx>( let mut err_occurred = None; for (kind, trait_count, impl_count) in matchings { if impl_count != trait_count { - let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| { + let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| { let mut spans = generics .params .iter() @@ -1373,7 +1373,7 @@ fn compare_number_of_generics<'tcx>( } => { // A fn can have an arbitrary number of extra elided lifetimes for the // same signature. - !matches!(kind, ty::AssocKind::Fn) + !item.is_fn() } _ => true, }) @@ -1386,7 +1386,7 @@ fn compare_number_of_generics<'tcx>( }; let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() { let trait_item = tcx.hir_expect_trait_item(def_id); - let arg_spans: Vec = arg_spans(trait_.kind, trait_item.generics); + let arg_spans: Vec = arg_spans(&trait_, trait_item.generics); let impl_trait_spans: Vec = trait_item .generics .params @@ -1412,7 +1412,7 @@ fn compare_number_of_generics<'tcx>( _ => None, }) .collect(); - let spans = arg_spans(impl_.kind, impl_item.generics); + let spans = arg_spans(&impl_, impl_item.generics); let span = spans.first().copied(); let mut err = tcx.dcx().struct_span_err( diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 30921b6f055d..523db9440a41 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -407,14 +407,14 @@ fn fn_sig_suggestion<'tcx>( .enumerate() .map(|(i, ty)| { Some(match ty.kind() { - ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(), + ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(), ty::Ref(reg, ref_ty, mutability) if i == 0 => { let reg = format!("{reg} "); let reg = match ®[..] { "'_ " | " " => "", reg => reg, }; - if assoc.fn_has_self_parameter { + if assoc.is_method() { match ref_ty.kind() { ty::Param(param) if param.name == kw::SelfUpper => { format!("&{}{}self", reg, mutability.prefix_str()) @@ -427,7 +427,7 @@ fn fn_sig_suggestion<'tcx>( } } _ => { - if assoc.fn_has_self_parameter && i == 0 { + if assoc.is_method() && i == 0 { format!("self: {ty}") } else { format!("_: {ty}") @@ -489,7 +489,7 @@ fn suggestion_signature<'tcx>( ); match assoc.kind { - ty::AssocKind::Fn => fn_sig_suggestion( + ty::AssocKind::Fn { .. } => fn_sig_suggestion( tcx, tcx.liberate_late_bound_regions( assoc.def_id, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 6292d03bf6ac..af7830fd6642 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { let item_required_bounds = match tcx.associated_item(item_def_id).kind { // In our example, this corresponds to `into_iter` method - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { // For methods, we check the function signature's return type for any GATs // to constrain. In the `into_iter` case, we see that the return type // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. @@ -1089,7 +1089,7 @@ fn check_associated_item( ); Ok(()) } - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { let sig = tcx.fn_sig(item.def_id).instantiate_identity(); let hir_sig = sig_if_method.expect("bad signature for method"); check_fn_or_method( @@ -1716,7 +1716,7 @@ fn check_method_receiver<'tcx>( ) -> Result<(), ErrorGuaranteed> { let tcx = wfcx.tcx(); - if !method.fn_has_self_parameter { + if !method.is_method() { return Ok(()); } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index deded6904d48..4520fbe352ce 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -44,7 +44,7 @@ use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument}; use crate::errors; -use crate::hir_ty_lowering::errors::assoc_kind_str; +use crate::hir_ty_lowering::errors::assoc_tag_str; use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; pub(crate) mod dump; @@ -450,7 +450,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { item_def_id: DefId, item_segment: &rustc_hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { if let Some(trait_ref) = poly_trait_ref.no_bound_vars() { let item_args = self.lowerer().lower_generic_args_of_assoc_item( @@ -525,7 +525,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { inferred_sugg, bound, mpart_sugg, - what: assoc_kind_str(kind), + what: assoc_tag_str(assoc_tag), })) } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 9bcda35ee87a..1c477755e5ac 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1811,7 +1811,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.tcx, type_def_id, constraint.ident, - ty::AssocKind::Fn, + ty::AssocTag::Fn, ) { bound_vars.extend( self.tcx @@ -1843,7 +1843,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.tcx, type_def_id, constraint.ident, - ty::AssocKind::Type, + ty::AssocTag::Type, ) .map(|(bound_vars, _)| bound_vars); self.with(scope, |this| { @@ -1875,13 +1875,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, def_id: DefId, assoc_ident: Ident, - assoc_kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Option<(Vec, &'tcx ty::AssocItem)> { let trait_defines_associated_item_named = |trait_def_id: DefId| { tcx.associated_items(trait_def_id).find_by_ident_and_kind( tcx, assoc_ident, - assoc_kind, + assoc_tag, trait_def_id, ) }; @@ -1894,8 +1894,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let Some((def_id, bound_vars)) = stack.pop() else { break None; }; - // See issue #83753. If someone writes an associated type on a non-trait, just treat it as - // there being no supertrait HRTBs. + // See issue #83753. If someone writes an associated type on a non-trait, just treat it + // as there being no supertrait HRTBs. match tcx.def_kind(def_id) { DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {} _ => break None, @@ -2067,7 +2067,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.tcx, trait_def_id, item_segment.ident, - ty::AssocKind::Fn, + ty::AssocTag::Fn, ) }); @@ -2112,7 +2112,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.tcx, trait_def_id, item_segment.ident, - ty::AssocKind::Fn, + ty::AssocTag::Fn, ) else { return; }; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 772197a53ace..f06636447194 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -32,7 +32,9 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type( for &assoc_id in tcx.associated_item_def_ids(impl_def_id) { let assoc = tcx.associated_item(assoc_id); match assoc.kind { - ty::AssocKind::Const | ty::AssocKind::Fn => locator.check(assoc_id.expect_local()), + ty::AssocKind::Const | ty::AssocKind::Fn { .. } => { + locator.check(assoc_id.expect_local()) + } // Associated types don't have bodies, so they can't constrain hidden types ty::AssocKind::Type => {} } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 24d05b49861c..bf91eb1b8fda 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -431,16 +431,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); - let assoc_kind = if constraint.gen_args.parenthesized + let assoc_tag = if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { - ty::AssocKind::Fn + ty::AssocTag::Fn } else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } = constraint.kind { - ty::AssocKind::Const + ty::AssocTag::Const } else { - ty::AssocKind::Type + ty::AssocTag::Type }; // Given something like `U: Trait`, we want to produce a predicate like @@ -453,7 +453,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // trait SuperTrait { type T; } let candidate = if self.probe_trait_that_defines_assoc_item( trait_ref.def_id(), - assoc_kind, + assoc_tag, constraint.ident, ) { // Simple case: The assoc item is defined in the current trait. @@ -464,7 +464,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.probe_single_bound_for_assoc_item( || traits::supertraits(tcx, trait_ref), AssocItemQSelf::Trait(trait_ref.def_id()), - assoc_kind, + assoc_tag, constraint.ident, path_span, Some(constraint), @@ -474,7 +474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let assoc_item = self .probe_assoc_item( constraint.ident, - assoc_kind, + assoc_tag, hir_ref_id, constraint.span, candidate.def_id(), @@ -493,7 +493,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) .or_insert(constraint.span); - let projection_term = if let ty::AssocKind::Fn = assoc_kind { + let projection_term = if let ty::AssocTag::Fn = assoc_tag { let bound_vars = tcx.late_bound_vars(constraint.hir_id); ty::Binder::bind_with_vars( self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(), @@ -542,7 +542,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; match constraint.kind { - hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => { + hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocTag::Fn = assoc_tag => { return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound { span: constraint.span, })); @@ -679,7 +679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_def_id, hir_ty.span, item_segment, - ty::AssocKind::Type, + ty::AssocTag::Type, ); return Ty::new_error(tcx, guar); }; @@ -771,7 +771,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) }, AssocItemQSelf::SelfTyAlias, - ty::AssocKind::Fn, + ty::AssocTag::Fn, assoc_ident, span, None, @@ -783,7 +783,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), qself.span, - ty::AssocKind::Fn, + ty::AssocTag::Fn, assoc_ident, span, )?, @@ -823,7 +823,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let trait_def_id = bound.def_id(); let assoc_ty = self - .probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id) + .probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id) .expect("failed to find associated type"); Ok((bound, assoc_ty.def_id)) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 5a0524d33fde..4f8d5471b6f4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -116,7 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, all_candidates: impl Fn() -> I, qself: AssocItemQSelf, - assoc_kind: ty::AssocKind, + assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, constraint: Option<&hir::AssocItemConstraint<'tcx>>, @@ -134,14 +134,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) { return self.complain_about_assoc_kind_mismatch( assoc_item, - assoc_kind, + assoc_tag, assoc_ident, span, constraint, ); } - let assoc_kind_str = assoc_kind_str(assoc_kind); + let assoc_kind_str = assoc_tag_str(assoc_tag); let qself_str = qself.to_string(tcx); // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a @@ -168,7 +168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let all_candidate_names: Vec<_> = all_candidates() .flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order()) .filter_map(|item| { - (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name) + (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then_some(item.name) }) .collect(); @@ -200,7 +200,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order()) .filter_map(|item| { - (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name) + (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then_some(item.name) }) .collect(); @@ -213,7 +213,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .filter(|trait_def_id| { tcx.associated_items(trait_def_id) .filter_by_name_unhygienic(suggested_name) - .any(|item| item.kind == assoc_kind) + .any(|item| item.as_tag() == assoc_tag) }) .collect::>()[..] { @@ -330,7 +330,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn complain_about_assoc_kind_mismatch( &self, assoc_item: &ty::AssocItem, - assoc_kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ident: Ident, span: Span, constraint: Option<&hir::AssocItemConstraint<'tcx>>, @@ -375,17 +375,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::Term::Ty(ty) => ty.span, hir::Term::Const(ct) => ct.span(), }; - (span, Some(ident.span), assoc_item.kind, assoc_kind) + (span, Some(ident.span), assoc_item.as_tag(), assoc_tag) } else { - (ident.span, None, assoc_kind, assoc_item.kind) + (ident.span, None, assoc_tag, assoc_item.as_tag()) }; self.dcx().emit_err(errors::AssocKindMismatch { span, - expected: assoc_kind_str(expected), - got: assoc_kind_str(got), + expected: assoc_tag_str(expected), + got: assoc_tag_str(got), expected_because_label, - assoc_kind: assoc_kind_str(assoc_item.kind), + assoc_kind: assoc_tag_str(assoc_item.as_tag()), def_span: tcx.def_span(assoc_item.def_id), bound_on_assoc_const_label, wrap_in_braces_sugg, @@ -398,9 +398,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { types: &[String], traits: &[String], name: Symbol, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> ErrorGuaranteed { - let kind_str = assoc_kind_str(kind); + let kind_str = assoc_tag_str(assoc_tag); let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}"); if self @@ -569,7 +569,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { candidates: Vec<(DefId, (DefId, DefId))>, fulfillment_errors: Vec>, span: Span, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> ErrorGuaranteed { // FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`. // Either @@ -579,14 +579,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); - let kind_str = assoc_kind_str(kind); + let assoc_tag_str = assoc_tag_str(assoc_tag); let adt_did = self_ty.ty_adt_def().map(|def| def.did()); let add_def_label = |err: &mut Diag<'_>| { if let Some(did) = adt_did { err.span_label( tcx.def_span(did), format!( - "associated {kind_str} `{name}` not found for this {}", + "associated {assoc_tag_str} `{name}` not found for this {}", tcx.def_descr(did) ), ); @@ -615,11 +615,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx(), name.span, E0220, - "associated {kind_str} `{name}` not found for `{self_ty}` in the current scope" + "associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope" ); err.span_label(name.span, format!("associated item not found in `{self_ty}`")); err.note(format!( - "the associated {kind_str} was found for\n{type_candidates}{additional_types}", + "the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}", )); add_def_label(&mut err); return err.emit(); @@ -700,7 +700,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut err = self.dcx().struct_span_err( name.span, - format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied") + format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied") ); if !bounds.is_empty() { err.note(format!( @@ -710,7 +710,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } err.span_label( name.span, - format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") + format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") ); for (span, mut bounds) in bound_spans { @@ -812,7 +812,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind( tcx, ident, - ty::AssocKind::Type, + ty::AssocTag::Type, trait_def, ); @@ -1022,12 +1022,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|simple_ty| tcx.incoherent_impls(simple_ty)) }) && let name = Symbol::intern(&format!("{ident2}_{ident3}")) - && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls + && let Some(item) = inherent_impls .iter() .flat_map(|inherent_impl| { tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name) }) .next() + && item.is_fn() { Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type") .with_span_suggestion_verbose( @@ -1629,10 +1630,10 @@ fn generics_args_err_extend<'a>( } } -pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str { - match kind { - ty::AssocKind::Fn => "function", - ty::AssocKind::Const => "constant", - ty::AssocKind::Type => "type", +pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str { + match assoc_tag { + ty::AssocTag::Fn => "function", + ty::AssocTag::Const => "constant", + ty::AssocTag::Type => "type", } } 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 83aa0d956201..0fb406d99080 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, - TypeVisitableExt, TypingMode, Upcast, fold_regions, + self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, + TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::{debug, instrument}; -use self::errors::assoc_kind_str; +use self::errors::assoc_tag_str; use crate::check::check_abi_fn_ptr; use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; @@ -168,7 +168,7 @@ pub trait HirTyLowerer<'tcx> { item_def_id: DefId, item_segment: &hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>; fn lower_fn_sig( @@ -251,10 +251,10 @@ enum LowerAssocMode { } impl LowerAssocMode { - fn kind(self) -> ty::AssocKind { + fn assoc_tag(self) -> ty::AssocTag { match self { - LowerAssocMode::Type { .. } => ty::AssocKind::Type, - LowerAssocMode::Const => ty::AssocKind::Const, + LowerAssocMode::Type { .. } => ty::AssocTag::Type, + LowerAssocMode::Const => ty::AssocTag::Const, } } @@ -268,7 +268,8 @@ impl LowerAssocMode { fn permit_variants(self) -> bool { match self { LowerAssocMode::Type { permit_variants } => permit_variants, - // FIXME(mgca): Support paths like `Option::::None` or `Option::::Some` which resolve to const ctors/fn items respectively + // FIXME(mgca): Support paths like `Option::::None` or `Option::::Some` which + // resolve to const ctors/fn items respectively. LowerAssocMode::Const => false, } } @@ -932,12 +933,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_trait_that_defines_assoc_item( &self, trait_def_id: DefId, - assoc_kind: ty::AssocKind, + assoc_tag: AssocTag, assoc_ident: Ident, ) -> bool { self.tcx() .associated_items(trait_def_id) - .find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_kind, trait_def_id) + .find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_tag, trait_def_id) .is_some() } @@ -975,7 +976,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, ty_param_def_id: LocalDefId, ty_param_span: Span, - kind: ty::AssocKind, + assoc_tag: AssocTag, assoc_ident: Ident, span: Span, ) -> Result, ErrorGuaranteed> { @@ -993,7 +994,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident) }, AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span), - kind, + assoc_tag, assoc_ident, span, None, @@ -1010,7 +1011,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, all_candidates: impl Fn() -> I, qself: AssocItemQSelf, - assoc_kind: ty::AssocKind, + assoc_tag: AssocTag, assoc_ident: Ident, span: Span, constraint: Option<&hir::AssocItemConstraint<'tcx>>, @@ -1021,14 +1022,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let mut matching_candidates = all_candidates().filter(|r| { - self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_kind, assoc_ident) + self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_tag, assoc_ident) }); let Some(bound) = matching_candidates.next() else { let reported = self.complain_about_assoc_item_not_found( all_candidates, qself, - assoc_kind, + assoc_tag, assoc_ident, span, constraint, @@ -1040,7 +1041,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let Some(bound2) = matching_candidates.next() { debug!(?bound2); - let assoc_kind_str = errors::assoc_kind_str(assoc_kind); + let assoc_kind_str = errors::assoc_tag_str(assoc_tag); let qself_str = qself.to_string(tcx); let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem { span, @@ -1059,14 +1060,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ); - // FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!). + // FIXME(#97583): Print associated item bindings properly (i.e., not as equality + // predicates!). // FIXME: Turn this into a structured, translateable & more actionable suggestion. let mut where_bounds = vec![]; for bound in [bound, bound2].into_iter().chain(matching_candidates) { let bound_id = bound.def_id(); let bound_span = tcx .associated_items(bound_id) - .find_by_ident_and_kind(tcx, assoc_ident, assoc_kind, bound_id) + .find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id) .and_then(|item| tcx.hir_span_if_local(item.def_id)); if let Some(bound_span) = bound_span { @@ -1265,7 +1267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { qself_ty, hir_ref_id, span, - mode.kind(), + mode.assoc_tag(), )? { return Ok(LoweredAssoc::Term(did, args)); } @@ -1296,7 +1298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) }, AssocItemQSelf::SelfTyAlias, - mode.kind(), + mode.assoc_tag(), assoc_ident, span, None, @@ -1308,12 +1310,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), qself.span, - mode.kind(), + mode.assoc_tag(), assoc_ident, span, )?, _ => { - let kind_str = assoc_kind_str(mode.kind()); + let kind_str = assoc_tag_str(mode.assoc_tag()); let reported = if variant_resolution.is_some() { // Variant in type position let msg = format!("expected {kind_str}, found variant `{assoc_ident}`"); @@ -1420,7 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &[qself_ty.to_string()], &traits, assoc_ident.name, - mode.kind(), + mode.assoc_tag(), ) }; return Err(reported); @@ -1429,10 +1431,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let trait_did = bound.def_id(); let assoc_item = self - .probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did) + .probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did) .expect("failed to find associated item"); - let (def_id, args) = - self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?; + let (def_id, args) = self.lower_assoc_shared( + span, + assoc_item.def_id, + assoc_segment, + bound, + mode.assoc_tag(), + )?; let result = LoweredAssoc::Term(def_id, args); if let Some(variant_def_id) = variant_resolution { @@ -1469,20 +1476,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, block: HirId, span: Span, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result)>, ErrorGuaranteed> { let tcx = self.tcx(); if !tcx.features().inherent_associated_types() { - match kind { - // Don't attempt to look up inherent associated types when the feature is not enabled. - // Theoretically it'd be fine to do so since we feature-gate their definition site. - // However, due to current limitations of the implementation (caused by us performing - // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle - // errors (#108491) which mask the feature-gate error, needlessly confusing users - // who use IATs by accident (#113265). - ty::AssocKind::Type => return Ok(None), - ty::AssocKind::Const => { + match assoc_tag { + // Don't attempt to look up inherent associated types when the feature is not + // enabled. Theoretically it'd be fine to do so since we feature-gate their + // definition site. However, due to current limitations of the implementation + // (caused by us performing selection during HIR ty lowering instead of in the + // trait solver), IATs can lead to cycle errors (#108491) which mask the + // feature-gate error, needlessly confusing users who use IATs by accident + // (#113265). + ty::AssocTag::Type => return Ok(None), + ty::AssocTag::Const => { // We also gate the mgca codepath for type-level uses of inherent consts // with the inherent_associated_types feature gate since it relies on the // same machinery and has similar rough edges. @@ -1494,7 +1502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) .emit()); } - ty::AssocKind::Fn => unreachable!(), + ty::AssocTag::Fn => unreachable!(), } } @@ -1503,7 +1511,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .inherent_impls(adt_did) .iter() .filter_map(|&impl_| { - let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?; + let (item, scope) = + self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?; Some((impl_, (item.def_id, scope))) }) .collect(); @@ -1542,7 +1551,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty, |self_ty| { self.select_inherent_assoc_candidates( - infcx, name, span, self_ty, param_env, candidates, kind, + infcx, name, span, self_ty, param_env, candidates, assoc_tag, ) }, )?; @@ -1570,7 +1579,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, param_env: ParamEnv<'tcx>, candidates: Vec<(DefId, (DefId, DefId))>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> { let tcx = self.tcx(); let mut fulfillment_errors = Vec::new(); @@ -1621,7 +1630,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { candidates, fulfillment_errors, span, - kind, + assoc_tag, )), &[applicable_candidate] => Ok(applicable_candidate), @@ -1640,12 +1649,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_assoc_item( &self, ident: Ident, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, block: HirId, span: Span, scope: DefId, ) -> Option { - let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?; + let (item, scope) = self.probe_assoc_item_unchecked(ident, assoc_tag, block, scope)?; self.check_assoc_item(item.def_id, ident, scope, block, span); Some(item) } @@ -1657,7 +1666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_assoc_item_unchecked( &self, ident: Ident, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, block: HirId, scope: DefId, ) -> Option<(ty::AssocItem, /*scope*/ DefId)> { @@ -1670,7 +1679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let item = tcx .associated_items(scope) .filter_by_name_unhygienic(ident.name) - .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?; + .find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?; Some((*item, def_scope)) } @@ -1770,7 +1779,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_def_id, trait_segment, item_segment, - ty::AssocKind::Type, + ty::AssocTag::Type, ) { Ok((item_def_id, item_args)) => { Ty::new_projection_from_args(self.tcx(), item_def_id, item_args) @@ -1795,7 +1804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_def_id, trait_segment, item_segment, - ty::AssocKind::Const, + ty::AssocTag::Const, ) { Ok((item_def_id, item_args)) => { let uv = ty::UnevaluatedConst::new(item_def_id, item_args); @@ -1813,7 +1822,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_def_id: DefId, trait_segment: &hir::PathSegment<'tcx>, item_segment: &hir::PathSegment<'tcx>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> { let tcx = self.tcx(); @@ -1821,7 +1830,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?trait_def_id); let Some(self_ty) = opt_self_ty else { - return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind)); + return Err(self.error_missing_qpath_self_ty( + trait_def_id, + span, + item_segment, + assoc_tag, + )); }; debug!(?self_ty); @@ -1840,7 +1854,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_def_id: DefId, span: Span, item_segment: &hir::PathSegment<'tcx>, - kind: ty::AssocKind, + assoc_tag: ty::AssocTag, ) -> ErrorGuaranteed { let tcx = self.tcx(); let path_str = tcx.def_path_str(trait_def_id); @@ -1877,7 +1891,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that // references the trait. Relevant for the first case in // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` - self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind) + self.report_ambiguous_assoc( + span, + &type_names, + &[path_str], + item_segment.ident.name, + assoc_tag, + ) } pub fn prohibit_generic_args<'a>( @@ -2862,7 +2882,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind( tcx, *ident, - ty::AssocKind::Fn, + ty::AssocTag::Fn, trait_ref.def_id, )?; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index c30b39dfe765..1ab36ce1dcb9 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -119,7 +119,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained( vec![] } } - ty::AssocKind::Fn | ty::AssocKind::Const => vec![], + ty::AssocKind::Fn { .. } | ty::AssocKind::Const => vec![], } }) .collect(); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index fec459954107..d1bc54ed73ea 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1089,14 +1089,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This function checks whether the method is not static and does not accept other parameters than `self`. fn has_only_self_parameter(&self, method: &AssocItem) -> bool { - match method.kind { - ty::AssocKind::Fn => { - method.fn_has_self_parameter - && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() - == 1 - } - _ => false, - } + method.is_method() + && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1 } /// If the given `HirId` corresponds to a block with a trailing expression, return that expression diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index de2f039cb1c8..56c205b6f879 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2588,9 +2588,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. - .filter(|item| { - matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter - }) + .filter(|item| item.is_fn() && !item.is_method()) .filter_map(|item| { // Only assoc fns that return `Self` let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 81eb8510785b..3a0f3a4a5f0b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -616,7 +616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some((DefKind::AssocFn, def_id)) = self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) && let Some(assoc) = tcx.opt_associated_item(def_id) - && assoc.fn_has_self_parameter + && assoc.is_method() { Some(*receiver) } else { @@ -642,8 +642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { TraitsInScope, |mut ctxt| ctxt.probe_for_similar_candidate(), ) - && let ty::AssocKind::Fn = assoc.kind - && assoc.fn_has_self_parameter + && assoc.is_method() { let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id); let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e14f1528d2c4..74cc8181418c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -314,7 +314,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { item_def_id: DefId, item_segment: &rustc_hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - _kind: ty::AssocKind, + _assoc_tag: ty::AssocTag, ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { let trait_ref = self.instantiate_binder_with_fresh_vars( span, diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index ddfd27ccf6b7..39cb139a199e 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -379,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let def_id = method_item.def_id; - if method_item.kind != ty::AssocKind::Fn { + if !method_item.is_fn() { span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function"); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 0a01ec89a327..d5d85c812b2d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -992,7 +992,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool { match method.kind { - ty::AssocKind::Fn => self.probe(|_| { + ty::AssocKind::Fn { .. } => self.probe(|_| { let args = self.fresh_args_for_item(self.span, method.def_id); let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args); let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); @@ -1678,7 +1678,6 @@ impl<'tcx> Pick<'tcx> { kind: _, container: _, trait_item_def_id: _, - fn_has_self_parameter: _, opt_rpitit_info: _, }, kind: _, @@ -1712,7 +1711,7 @@ impl<'tcx> Pick<'tcx> { )); match (self.item.kind, self.item.container) { - (ty::AssocKind::Fn, _) => { + (ty::AssocKind::Fn { .. }, _) => { // FIXME: This should be a `span_suggestion` instead of `help` // However `self.span` only // highlights the method name, so we can't use it. Also consider reusing @@ -2252,10 +2251,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // In Path mode (i.e., resolving a value like `T::next`), consider any // associated value (i.e., methods, constants) but not types. match self.mode { - Mode::MethodCall => item.fn_has_self_parameter, + Mode::MethodCall => item.is_method(), Mode::Path => match item.kind { ty::AssocKind::Type => false, - ty::AssocKind::Fn | ty::AssocKind::Const => true, + ty::AssocKind::Fn { .. } | ty::AssocKind::Const => true, }, } // FIXME -- check for types that deref to `Self`, @@ -2277,7 +2276,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { impl_ty: Ty<'tcx>, args: GenericArgsRef<'tcx>, ) -> (Ty<'tcx>, Option>) { - if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall { + if item.is_fn() && self.mode == Mode::MethodCall { let sig = self.xform_method_sig(item.def_id, args); (sig.inputs()[0], Some(sig.output())) } else { @@ -2328,8 +2327,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// Determine if the given associated item type is relevant in the current context. fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool { match (self.mode, kind) { - (Mode::MethodCall, ty::AssocKind::Fn) => true, - (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true, + (Mode::MethodCall, ty::AssocKind::Fn { .. }) => true, + (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn { .. }) => true, _ => false, } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 68f13d654d6e..1b9771636a7d 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -713,7 +713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(candidate) = tcx.associated_items(impl_def_id).find_by_ident_and_kind( self.tcx, item_ident, - ty::AssocKind::Type, + ty::AssocTag::Type, impl_def_id, ) && let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def() @@ -1442,7 +1442,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(assoc) = self.associated_value(*def_id, item_ident) { // Check for both mode is the same so we avoid suggesting // incorrect associated item. - match (mode, assoc.fn_has_self_parameter, source) { + match (mode, assoc.is_method(), source) { (Mode::MethodCall, true, SelfSource::MethodCall(_)) => { // We check that the suggest type is actually // different from the received one @@ -1834,7 +1834,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id); let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args); let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig); - if similar_candidate.fn_has_self_parameter { + if similar_candidate.is_method() { if let Some(args) = args && fn_sig.inputs()[1..].len() == args.len() { @@ -1902,7 +1902,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols) && candidates.contains(&item_name.name) - && let ty::AssocKind::Fn = inherent_method.kind + && inherent_method.is_fn() { let args = ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id) @@ -2116,8 +2116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only assoc fn with no receivers and only if // they are resolvable .filter(|item| { - matches!(item.kind, ty::AssocKind::Fn) - && !item.fn_has_self_parameter + matches!(item.kind, ty::AssocKind::Fn { has_self: false }) && self .probe_for_name( Mode::Path, @@ -2261,7 +2260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let assoc = self.associated_value(assoc_did, item_name)?; - if assoc.kind != ty::AssocKind::Fn { + if !assoc.is_fn() { return None; } @@ -3208,7 +3207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If this method receives `&self`, then the provided // argument _should_ coerce, so it's valid to suggest // just changing the path. - && pick.item.fn_has_self_parameter + && pick.item.is_method() && let Some(self_ty) = self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0) && self_ty.is_ref() @@ -3560,7 +3559,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || (("Pin::new" == *pre) && ((sym::as_ref == item_name.name) || !unpin)) || inputs_len.is_some_and(|inputs_len| { - pick.item.kind == ty::AssocKind::Fn + pick.item.is_fn() && self .tcx .fn_sig(pick.item.def_id) @@ -3618,7 +3617,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && pick.autoderefs == 0 // Check that the method of the same name that was found on the new `Pin` // receiver has the same number of arguments that appear in the user's code. - && inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len) + && inputs_len.is_some_and(|inputs_len| pick.item.is_fn() && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len) { let indent = self .tcx @@ -3756,7 +3755,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self .associated_value(info.def_id, item_name) .filter(|item| { - if let ty::AssocKind::Fn = item.kind { + if item.is_fn() { let id = item .def_id .as_local() @@ -4279,13 +4278,13 @@ fn print_disambiguation_help<'tcx>( item: ty::AssocItem, ) -> Option { let trait_impl_type = trait_ref.self_ty().peel_refs(); - let trait_ref = if item.fn_has_self_parameter { + let trait_ref = if item.is_method() { trait_ref.print_only_trait_name().to_string() } else { format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name()) }; Some( - if matches!(item.kind, ty::AssocKind::Fn) + if item.is_fn() && let SelfSource::MethodCall(receiver) = source && let Some(args) = args { @@ -4304,7 +4303,7 @@ fn print_disambiguation_help<'tcx>( let args = if let Some(first_arg_type) = first_arg_type && (first_arg_type == tcx.types.self_param || first_arg_type == trait_impl_type - || item.fn_has_self_parameter) + || item.is_method()) { Some(receiver) } else { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index a2d5ffe256d5..dd3c514704a1 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -859,12 +859,7 @@ impl<'tcx> LateContext<'tcx> { ) -> Option> { let tcx = self.tcx; tcx.associated_items(trait_id) - .find_by_ident_and_kind( - tcx, - Ident::with_dummy_span(name), - ty::AssocKind::Type, - trait_id, - ) + .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id) .and_then(|assoc| { let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]); tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok() diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4cc12ca2e0bf..cc3b2a241e4a 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1337,10 +1337,12 @@ impl<'a> CrateMetadataRef<'a> { } else { self.item_name(id) }; - let (kind, has_self) = match self.def_kind(id) { - DefKind::AssocConst => (ty::AssocKind::Const, false), - DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)), - DefKind::AssocTy => (ty::AssocKind::Type, false), + let kind = match self.def_kind(id) { + DefKind::AssocConst => ty::AssocKind::Const, + DefKind::AssocFn => { + ty::AssocKind::Fn { has_self: self.get_fn_has_self_parameter(id, sess) } + } + DefKind::AssocTy => ty::AssocKind::Type, _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; let container = self.root.tables.assoc_container.get(self, id).unwrap(); @@ -1353,7 +1355,6 @@ impl<'a> CrateMetadataRef<'a> { def_id: self.local_def_id(id), trait_item_def_id: self.get_trait_item_def_id(id), container, - fn_has_self_parameter: has_self, opt_rpitit_info, } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5c8e2888ec98..cc9da16ffdbb 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1338,7 +1338,7 @@ fn should_encode_const(def_kind: DefKind) -> bool { fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { if let Some(assoc_item) = tcx.opt_associated_item(def_id) && assoc_item.container == ty::AssocItemContainer::Trait - && assoc_item.kind == ty::AssocKind::Fn + && assoc_item.is_fn() { true } else { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4dfb362f3a22..db19c858e7c1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1636,8 +1636,8 @@ pub fn find_self_call<'tcx>( &body[block].terminator && let Operand::Constant(box ConstOperand { const_, .. }) = func && let ty::FnDef(def_id, fn_args) = *const_.ty().kind() - && let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = - tcx.opt_associated_item(def_id) + && let Some(item) = tcx.opt_associated_item(def_id) + && item.is_method() && let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] = **args { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index f8ab555305f0..3425da485595 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -5,7 +5,7 @@ use rustc_hir::lang_items::LangItem; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::Span; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{Ty, TyCtxt}; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum PointerCoercion { @@ -133,7 +133,7 @@ impl OverloadedDeref { }; tcx.associated_items(trait_def_id) .in_definition_order() - .find(|m| m.kind == ty::AssocKind::Fn) + .find(|item| item.is_fn()) .unwrap() .def_id } diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index bbaf735fbdb9..3c1e5ed9e114 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -26,10 +26,6 @@ pub struct AssocItem { /// the associated item on the trait that this implements. pub trait_item_def_id: Option, - /// Whether this is a method with an explicit self - /// as its first parameter, allowing method calls. - pub fn_has_self_parameter: bool, - /// `Some` if the associated item (an associated type) comes from the /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` /// provides additional information about its source. @@ -78,7 +74,7 @@ impl AssocItem { pub fn signature(&self, tcx: TyCtxt<'_>) -> String { match self.kind { - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { // We skip the binder here because the binder would deanonymize all // late-bound regions, and we don't want method signatures to show up // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound @@ -99,12 +95,28 @@ impl AssocItem { pub fn descr(&self) -> &'static str { match self.kind { ty::AssocKind::Const => "associated const", - ty::AssocKind::Fn if self.fn_has_self_parameter => "method", - ty::AssocKind::Fn => "associated function", + ty::AssocKind::Fn { has_self: true } => "method", + ty::AssocKind::Fn { has_self: false } => "associated function", ty::AssocKind::Type => "associated type", } } + pub fn is_fn(&self) -> bool { + matches!(self.kind, ty::AssocKind::Fn { .. }) + } + + pub fn is_method(&self) -> bool { + matches!(self.kind, ty::AssocKind::Fn { has_self: true }) + } + + pub fn as_tag(&self) -> AssocTag { + match self.kind { + AssocKind::Const => AssocTag::Const, + AssocKind::Fn { .. } => AssocTag::Fn, + AssocKind::Type => AssocTag::Type, + } + } + pub fn is_impl_trait_in_trait(&self) -> bool { self.opt_rpitit_info.is_some() } @@ -131,7 +143,7 @@ impl AssocItem { #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] pub enum AssocKind { Const, - Fn, + Fn { has_self: bool }, Type, } @@ -139,14 +151,14 @@ impl AssocKind { pub fn namespace(&self) -> Namespace { match *self { ty::AssocKind::Type => Namespace::TypeNS, - ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS, + ty::AssocKind::Const | ty::AssocKind::Fn { .. } => Namespace::ValueNS, } } pub fn as_def_kind(&self) -> DefKind { match self { AssocKind::Const => DefKind::AssocConst, - AssocKind::Fn => DefKind::AssocFn, + AssocKind::Fn { .. } => DefKind::AssocFn, AssocKind::Type => DefKind::AssocTy, } } @@ -155,15 +167,22 @@ impl AssocKind { impl std::fmt::Display for AssocKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - // FIXME: fails to distinguish between "associated function" and - // "method" because `has_self` isn't known here. - AssocKind::Fn => write!(f, "method"), + AssocKind::Fn { has_self: true } => write!(f, "method"), + AssocKind::Fn { has_self: false } => write!(f, "associated function"), AssocKind::Const => write!(f, "associated const"), AssocKind::Type => write!(f, "associated type"), } } } +// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum AssocTag { + Const, + Fn, + Type, +} + /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name. /// /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since @@ -207,27 +226,14 @@ impl AssocItems { &self, tcx: TyCtxt<'_>, ident: Ident, - kind: AssocKind, + assoc_tag: AssocTag, parent_def_id: DefId, ) -> Option<&ty::AssocItem> { self.filter_by_name_unhygienic(ident.name) - .filter(|item| item.kind == kind) + .filter(|item| item.as_tag() == assoc_tag) .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) } - /// Returns the associated item with the given identifier and any of `AssocKind`, if one - /// exists. The identifier is matched hygienically. - pub fn find_by_ident_and_kinds( - &self, - tcx: TyCtxt<'_>, - ident: Ident, - // Sorted in order of what kinds to look at - kinds: &[AssocKind], - parent_def_id: DefId, - ) -> Option<&ty::AssocItem> { - kinds.iter().find_map(|kind| self.find_by_ident_and_kind(tcx, ident, *kind, parent_def_id)) - } - /// Returns the associated item with the given identifier in the given `Namespace`, if one /// exists. The identifier is matched hygienically. pub fn find_by_ident_and_namespace( diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 07f2a602f2bf..faad0a82acbf 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -746,7 +746,7 @@ impl<'tcx> Instance<'tcx> { let call_once = tcx .associated_items(fn_once) .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Fn) + .find(|it| it.is_fn()) .unwrap() .def_id; let track_caller = diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a2b3acac3f26..30c889c39d93 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1464,7 +1464,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator { self.associated_items(id) .in_definition_order() - .filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value()) + .filter(move |item| item.is_fn() && item.defaultness(self).has_value()) } pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 857b462b9eb1..dfc11de283d8 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -819,7 +819,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Get an English description for the item's kind. pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str { match def_kind { - DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method", + DefKind::AssocFn if self.associated_item(def_id).is_method() => "method", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { hir::CoroutineKind::Desugared( @@ -873,7 +873,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Gets an English article for the [`TyCtxt::def_kind_descr`]. pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str { match def_kind { - DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a", + DefKind::AssocFn if self.associated_item(def_id).is_method() => "a", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an", diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index d1f9d4c34fe1..16da60929984 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -715,7 +715,7 @@ fn trait_method<'tcx>( let item = tcx .associated_items(trait_def_id) .filter_by_name_unhygienic(method_name) - .find(|item| item.kind == ty::AssocKind::Fn) + .find(|item| item.is_fn()) .expect("trait method not found"); let method_ty = Ty::new_fn_def(tcx, item.def_id, args); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index c9771467e499..c13ffae36498 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -66,7 +66,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< let call_mut = tcx .associated_items(fn_mut) .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Fn) + .find(|it| it.is_fn()) .unwrap() .def_id; diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs index 55d52d5075dc..7251ef478c6f 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Location, traversal}; -use rustc_middle::ty::{self, AssocKind, Instance, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, AssocTag, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_session::Limit; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_span::source_map::Spanned; @@ -194,7 +194,7 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> if let Some(new) = tcx.associated_items(impl_def_id).find_by_ident_and_kind( tcx, fn_ident, - AssocKind::Fn, + AssocTag::Fn, def_id, ) { return Some(new.def_id); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c2761bd2717f..ae81021e0bea 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1994,7 +1994,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .iter() .flat_map(|i| self.r.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. - .filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter) + .filter(|item| item.is_fn() && !item.is_method()) .filter_map(|item| { // Only assoc fns that return `Self` let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder(); 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 129a32c6edd8..718b9a4fa3b8 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 @@ -446,7 +446,7 @@ pub(crate) fn transform_instance<'tcx>( let call = tcx .associated_items(trait_id) .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Fn) + .find(|it| it.is_fn()) .expect("No call-family function on closure-like Fn trait?") .def_id; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 28fc68d5e491..94f3be9fef73 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -896,9 +896,9 @@ impl<'tcx> Stable<'tcx> for ty::AssocKind { fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::AssocKind; - match self { + match *self { ty::AssocKind::Const => AssocKind::Const, - ty::AssocKind::Fn => AssocKind::Fn, + ty::AssocKind::Fn { has_self } => AssocKind::Fn { has_self }, ty::AssocKind::Type => AssocKind::Type, } } @@ -926,7 +926,6 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem { kind: self.kind.stable(tables), container: self.container.stable(tables), trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)), - fn_has_self_parameter: self.fn_has_self_parameter, opt_rpitit_info: self.opt_rpitit_info.map(|rpitit| rpitit.stable(tables)), } } diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs index 439ebe978e59..60d9e122940b 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs @@ -22,7 +22,8 @@ impl Display for Ty { impl Display for AssocKind { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - AssocKind::Fn => write!(f, "method"), + AssocKind::Fn { has_self: true } => write!(f, "method"), + AssocKind::Fn { has_self: false } => write!(f, "associated function"), AssocKind::Const => write!(f, "associated const"), AssocKind::Type => write!(f, "associated type"), } diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 3fcbbb0e138b..63ce756162a5 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1586,10 +1586,6 @@ pub struct AssocItem { /// the associated item on the trait that this implements. pub trait_item_def_id: Option, - /// Whether this is a method with an explicit self - /// as its first parameter, allowing method calls. - pub fn_has_self_parameter: bool, - /// `Some` if the associated item (an associated type) comes from the /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` /// provides additional information about its source. @@ -1599,7 +1595,7 @@ pub struct AssocItem { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AssocKind { Const, - Fn, + Fn { has_self: bool }, Type, } 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 40f8af1f6913..cbadb46c17d9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2334,7 +2334,7 @@ impl<'tcx> ObligationCause<'tcx> { subdiags: Vec, ) -> ObligationCauseFailureCode { match self.code() { - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => { ObligationCauseFailureCode::MethodCompat { span, subdiags } } ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { @@ -2398,7 +2398,7 @@ impl<'tcx> ObligationCause<'tcx> { fn as_requirement_str(&self) -> &'static str { match self.code() { - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => { "method type is compatible with trait" } ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { @@ -2422,7 +2422,9 @@ pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { let kind = match self.0.code() { - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat", + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => { + "method_compat" + } ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat", ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { "const_compat" diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index 742059228510..b66bd2c6ab78 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -98,7 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let assoc_item = self.tcx().associated_item(trait_item_def_id); let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; match assoc_item.kind { - ty::AssocKind::Fn => { + ty::AssocKind::Fn { .. } => { if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id)) { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index fd2d2fa72105..4a71ab4e06a3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -158,6 +158,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { && self .tcx() .opt_associated_item(scope_def_id.to_def_id()) - .is_some_and(|i| i.fn_has_self_parameter) + .is_some_and(|i| i.is_method()) } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 5583deda99a4..02f21b5465c6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -782,7 +782,7 @@ fn foo(&self) -> Self::T { String::new() } let methods: Vec<(Span, String)> = items .in_definition_order() .filter(|item| { - ty::AssocKind::Fn == item.kind + item.is_fn() && Some(item.name) != current_method_ident && !tcx.is_doc_hidden(item.def_id) }) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 59c93db9c8ff..e3e1583a48fa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -349,7 +349,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { let (verb, noun) = match self.tcx.associated_item(item_id).kind { ty::AssocKind::Const => ("refer to the", "constant"), - ty::AssocKind::Fn => ("call", "function"), + ty::AssocKind::Fn { .. } => ("call", "function"), // This is already covered by E0223, but this following single match // arm doesn't hurt here. ty::AssocKind::Type => ("refer to the", "type"), 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 b963e4a2c7c4..38aac8e70b52 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5411,7 +5411,7 @@ fn point_at_assoc_type_restriction( tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind( tcx, Ident::with_dummy_span(name), - ty::AssocKind::Type, + ty::AssocTag::Type, data.impl_or_alias_def_id, ) { diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index bf9fcb0915a5..76892db9ef7b 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -301,7 +301,7 @@ pub fn dyn_compatibility_violations_for_assoc_item( ty::AssocKind::Const => { vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)] } - ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item) + ty::AssocKind::Fn { .. } => virtual_call_violations_for_method(tcx, trait_def_id, item) .into_iter() .map(|v| { let node = tcx.hir_get_if_local(item.def_id); @@ -344,7 +344,7 @@ fn virtual_call_violations_for_method<'tcx>( let sig = tcx.fn_sig(method.def_id).instantiate_identity(); // The method's first parameter must be named `self` - if !method.fn_has_self_parameter { + if !method.is_method() { let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem { generics, kind: hir::TraitItemKind::Fn(sig, _), diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 165174c0bcc1..3565c11249ad 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -197,10 +197,8 @@ fn own_existential_vtable_entries_iter( tcx: TyCtxt<'_>, trait_def_id: DefId, ) -> impl Iterator { - let trait_methods = tcx - .associated_items(trait_def_id) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Fn); + let trait_methods = + tcx.associated_items(trait_def_id).in_definition_order().filter(|item| item.is_fn()); // Now list each method's DefId (for within its trait). let own_entries = trait_methods.filter_map(move |&trait_method| { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 9520d948f51f..79de071b6878 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -129,10 +129,10 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem { fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem { let owner_id = trait_item_ref.id.owner_id; - let (kind, has_self) = match trait_item_ref.kind { - hir::AssocItemKind::Const => (ty::AssocKind::Const, false), - hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), - hir::AssocItemKind::Type => (ty::AssocKind::Type, false), + let kind = match trait_item_ref.kind { + hir::AssocItemKind::Const => ty::AssocKind::Const, + hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { has_self }, + hir::AssocItemKind::Type => ty::AssocKind::Type, }; ty::AssocItem { @@ -141,17 +141,16 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty def_id: owner_id.to_def_id(), trait_item_def_id: Some(owner_id.to_def_id()), container: ty::AssocItemContainer::Trait, - fn_has_self_parameter: has_self, opt_rpitit_info: None, } } fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem { let def_id = impl_item_ref.id.owner_id; - let (kind, has_self) = match impl_item_ref.kind { - hir::AssocItemKind::Const => (ty::AssocKind::Const, false), - hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), - hir::AssocItemKind::Type => (ty::AssocKind::Type, false), + let kind = match impl_item_ref.kind { + hir::AssocItemKind::Const => ty::AssocKind::Const, + hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { has_self }, + hir::AssocItemKind::Type => ty::AssocKind::Type, }; ty::AssocItem { @@ -160,7 +159,6 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A def_id: def_id.to_def_id(), trait_item_def_id: impl_item_ref.trait_item_def_id, container: ty::AssocItemContainer::Impl, - fn_has_self_parameter: has_self, opt_rpitit_info: None, } } @@ -269,7 +267,6 @@ fn associated_type_for_impl_trait_in_trait( def_id, trait_item_def_id: None, container: ty::AssocItemContainer::Trait, - fn_has_self_parameter: false, opt_rpitit_info: Some(ImplTraitInTraitData::Trait { fn_def_id: fn_def_id.to_def_id(), opaque_def_id: opaque_ty_def_id.to_def_id(), @@ -322,7 +319,6 @@ fn associated_type_for_impl_trait_in_impl( def_id, trait_item_def_id: Some(trait_assoc_def_id), container: ty::AssocItemContainer::Impl, - fn_has_self_parameter: false, opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), }); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 3a2b6974681b..2f6870e3c368 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -490,17 +490,17 @@ pub(crate) fn build_impl( return true; } if let Some(associated_trait) = associated_trait { - let assoc_kind = match item.kind { - hir::ImplItemKind::Const(..) => ty::AssocKind::Const, - hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, - hir::ImplItemKind::Type(..) => ty::AssocKind::Type, + let assoc_tag = match item.kind { + hir::ImplItemKind::Const(..) => ty::AssocTag::Const, + hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn, + hir::ImplItemKind::Type(..) => ty::AssocTag::Type, }; let trait_item = tcx .associated_items(associated_trait.def_id) .find_by_ident_and_kind( tcx, item.ident, - assoc_kind, + assoc_tag, associated_trait.def_id, ) .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name. @@ -527,7 +527,7 @@ pub(crate) fn build_impl( .find_by_ident_and_kind( tcx, item.ident(tcx), - item.kind, + item.as_tag(), associated_trait.def_id, ) .unwrap(); // corresponding associated item has to exist diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 45a915719e9f..7cfd204aa137 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1374,10 +1374,10 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo } } } - ty::AssocKind::Fn => { + ty::AssocKind::Fn { has_self } => { let mut item = inline::build_function(cx, assoc_item.def_id); - if assoc_item.fn_has_self_parameter { + if has_self { let self_ty = match assoc_item.container { ty::AssocItemContainer::Impl => { tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity() diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index ad18c7039eed..4a876b854165 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -56,7 +56,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - cx.tcx.associated_items(trait_id).find_by_ident_and_kind( cx.tcx, Ident::from_str("Output"), - ty::AssocKind::Type, + ty::AssocTag::Type, trait_id, ) }) diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index b01929747d69..77085d52a32e 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -13,7 +13,7 @@ use rustc_hir::{ QPath, TraitItemRef, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; +use rustc_middle::ty::{self, FnSig, Ty}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; @@ -288,8 +288,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden .items() .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) .any(|i| { - i.kind == AssocKind::Fn - && i.fn_has_self_parameter + i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1 }); @@ -466,7 +465,7 @@ fn check_for_is_empty( .inherent_impls(impl_ty) .iter() .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) - .find(|item| item.kind == AssocKind::Fn); + .find(|item| item.is_fn()); let (msg, is_empty_span, self_kind) = match is_empty { None => ( @@ -486,7 +485,7 @@ fn check_for_is_empty( None, ), Some(is_empty) - if !(is_empty.fn_has_self_parameter + if !(is_empty.is_method() && check_is_empty_sig( cx, cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(), @@ -608,7 +607,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool { fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { - if item.kind == AssocKind::Fn { + if item.is_fn() { let sig = cx.tcx.fn_sig(item.def_id).skip_binder(); let ty = sig.skip_binder(); ty.inputs().len() == 1 diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 239ee6c729fb..e4a29b6560e5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -17,7 +17,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_span::symbol::Ident; use rustc_span::{Span, sym}; @@ -241,7 +241,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_ident_and_kind( cx.tcx, Ident::with_dummy_span(sym::Item), - AssocKind::Type, + AssocTag::Type, iter_trait, ) && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index c03420a5143e..6eeeea5d77c7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -78,7 +78,7 @@ pub(super) fn check<'tcx>( .iter() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .find_map(|assoc| { - if assoc.fn_has_self_parameter + if assoc.is_method() && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1 { Some(assoc.def_id) diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index f686cc912ddb..e579dd5947d7 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -299,7 +299,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool { .associated_items(trait_def_id) .in_definition_order() .any(|assoc_item| { - if assoc_item.fn_has_self_parameter { + if assoc_item.is_method() { let self_ty = cx .tcx .fn_sig(assoc_item.def_id) diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 552135b15fd8..ae677e110af2 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::AssocKind; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::symbol::Symbol; @@ -85,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { cx.tcx .associated_items(did) .in_definition_order() - .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn)) + .filter(|assoc_item| assoc_item.is_fn()) .map(|assoc_item| assoc_item.name) .collect() } else { diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index 51c7d6fce312..2104eb302ab8 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -10,7 +10,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, kw}; use rustc_span::{Span, sym}; @@ -322,7 +322,7 @@ impl UnconditionalRecursion { .in_definition_order() // We're not interested in foreign implementations of the `Default` trait. .find(|item| { - item.kind == AssocKind::Fn && item.def_id.is_local() && item.name == kw::Default + item.is_fn() && item.def_id.is_local() && item.name == kw::Default }) && let Some(body_node) = cx.tcx.hir_get_if_local(assoc_item.def_id) && let Some(body_id) = body_node.body_id() diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 582aa6e6001e..d0067b1a65e7 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { .is_some() }; if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind - && assoc_item.fn_has_self_parameter + && assoc_item.is_method() && let ImplItemKind::Fn(.., body_id) = &impl_item.kind && (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api) && let body = cx.tcx.hir_body(*body_id) diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 3779e2f30623..d33e59342a59 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, + self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; @@ -1112,7 +1112,7 @@ pub fn make_projection<'tcx>( let Some(assoc_item) = tcx.associated_items(container_id).find_by_ident_and_kind( tcx, Ident::with_dummy_span(assoc_ty), - AssocKind::Type, + AssocTag::Type, container_id, ) else { debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`"); @@ -1345,7 +1345,7 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n .associated_items(did) .filter_by_name_unhygienic(method_name) .next() - .filter(|item| item.kind == AssocKind::Fn) + .filter(|item| item.as_tag() == AssocTag::Fn) }) } else { None diff --git a/tests/ui/generic-associated-types/impl_bounds.stderr b/tests/ui/generic-associated-types/impl_bounds.stderr index 231c0dd89c52..7847bbd813cd 100644 --- a/tests/ui/generic-associated-types/impl_bounds.stderr +++ b/tests/ui/generic-associated-types/impl_bounds.stderr @@ -57,14 +57,14 @@ note: required for `Fooy` to implement `Copy` | LL | #[derive(Copy, Clone)] | ^^^^ unsatisfied trait bound introduced in this `derive` macro -note: the requirement `Fooy: Copy` appears on the `impl`'s method `d` but not on the corresponding trait's method +note: the requirement `Fooy: Copy` appears on the `impl`'s associated function `d` but not on the corresponding trait's associated function --> $DIR/impl_bounds.rs:7:8 | LL | trait Foo { | --- in this trait ... LL | fn d() where Self: Clone; - | ^ this trait's method doesn't have the requirement `Fooy: Copy` + | ^ this trait's associated function doesn't have the requirement `Fooy: Copy` help: consider restricting type parameter `T` with trait `Copy` | LL | impl Foo for Fooy { diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr index 74a0a90885da..d179c8059623 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr @@ -4,14 +4,14 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` LL | Self::Assoc: A, | ^^^^ | -note: the requirement `<() as A>::Assoc: A` appears on the `impl`'s method `f` but not on the corresponding trait's method +note: the requirement `<() as A>::Assoc: A` appears on the `impl`'s associated function `f` but not on the corresponding trait's associated function --> $DIR/normalize-param-env-2.rs:12:8 | LL | trait A { | - in this trait ... LL | fn f() - | ^ this trait's method doesn't have the requirement `<() as A>::Assoc: A` + | ^ this trait's associated function doesn't have the requirement `<() as A>::Assoc: A` error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` --> $DIR/normalize-param-env-2.rs:24:22 From 8c8212ef12b13ccb635c81aa9e29915dd1c189e5 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Mon, 14 Apr 2025 14:29:14 +0800 Subject: [PATCH 125/222] Consistent with treating Ctor Call as Struct in liveness analysis Signed-off-by: xizheyin --- compiler/rustc_passes/src/liveness.rs | 5 ++- ...eachable-by-call-arguments-issue-139627.rs | 7 ++-- ...able-by-call-arguments-issue-139627.stderr | 36 ------------------- 3 files changed, 8 insertions(+), 40 deletions(-) delete mode 100644 tests/ui/reachable/unreachable-by-call-arguments-issue-139627.stderr diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 06eb76c30c5f..24fac1999111 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1021,7 +1021,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Call(ref f, args) => { - let succ = self.check_is_ty_uninhabited(expr, succ); + let is_ctor = |f: &Expr<'_>| matches!(f.kind, hir::ExprKind::Path(hir::QPath::Resolved(_, path)) if matches!(path.res, rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Ctor(_, _), _))); + let succ = + if !is_ctor(f) { self.check_is_ty_uninhabited(expr, succ) } else { succ }; + let succ = self.propagate_through_exprs(args, succ); self.propagate_through_expr(f, succ) } diff --git a/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs index 422ae95e8b72..b3310ac1c754 100644 --- a/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs +++ b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs @@ -1,3 +1,4 @@ +//@ check-pass #![deny(unreachable_code)] #![deny(unused)] @@ -5,9 +6,9 @@ pub enum Void {} pub struct S(T); -pub fn foo(void: Void, void1: Void) { //~ ERROR unused variable: `void1` - let s = S(void); //~ ERROR unused variable: `s` - drop(s); //~ ERROR unreachable expression +pub fn foo(void: Void, void1: Void) { + let s = S(void); + drop(s); let s1 = S { 0: void1 }; drop(s1); } diff --git a/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.stderr b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.stderr deleted file mode 100644 index ce24705324e5..000000000000 --- a/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error: unreachable expression - --> $DIR/unreachable-by-call-arguments-issue-139627.rs:10:10 - | -LL | let s = S(void); - | ------- any code following this expression is unreachable -LL | drop(s); - | ^ unreachable expression - | -note: this expression has type `S`, which is uninhabited - --> $DIR/unreachable-by-call-arguments-issue-139627.rs:9:13 - | -LL | let s = S(void); - | ^^^^^^^ -note: the lint level is defined here - --> $DIR/unreachable-by-call-arguments-issue-139627.rs:2:9 - | -LL | #![deny(unused)] - | ^^^^^^ - = note: `#[deny(unreachable_code)]` implied by `#[deny(unused)]` - -error: unused variable: `s` - --> $DIR/unreachable-by-call-arguments-issue-139627.rs:9:9 - | -LL | let s = S(void); - | ^ help: if this is intentional, prefix it with an underscore: `_s` - | - = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` - -error: unused variable: `void1` - --> $DIR/unreachable-by-call-arguments-issue-139627.rs:8:24 - | -LL | pub fn foo(void: Void, void1: Void) { - | ^^^^^ help: if this is intentional, prefix it with an underscore: `_void1` - -error: aborting due to 3 previous errors - From f3344ef4bd57ac7609b40f1da75d685032e965f1 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 14 Apr 2025 15:28:41 +0800 Subject: [PATCH 126/222] tests: use `compiletest-ignore-dir` for bootstrap self-tests --- tests/ui/bootstrap/self-test/a.rs | 1 - tests/ui/bootstrap/self-test/b.rs | 1 - tests/ui/bootstrap/self-test/compiletest-ignore-dir | 0 3 files changed, 2 deletions(-) create mode 100644 tests/ui/bootstrap/self-test/compiletest-ignore-dir diff --git a/tests/ui/bootstrap/self-test/a.rs b/tests/ui/bootstrap/self-test/a.rs index b8abd8179c91..0818665af9f2 100644 --- a/tests/ui/bootstrap/self-test/a.rs +++ b/tests/ui/bootstrap/self-test/a.rs @@ -1,2 +1 @@ //! Not used by compiler, this is used by bootstrap cli self-test. -//@ ignore-test (used by bootstrap) diff --git a/tests/ui/bootstrap/self-test/b.rs b/tests/ui/bootstrap/self-test/b.rs index 5bbd2f946feb..aeb4688830db 100644 --- a/tests/ui/bootstrap/self-test/b.rs +++ b/tests/ui/bootstrap/self-test/b.rs @@ -1,2 +1 @@ //! Not used by compiler, used by bootstrap cli self-test. -//@ ignore-test (used by bootstrap) diff --git a/tests/ui/bootstrap/self-test/compiletest-ignore-dir b/tests/ui/bootstrap/self-test/compiletest-ignore-dir new file mode 100644 index 000000000000..e69de29bb2d1 From 1ac3d6bba71fce59939e6a4d50de98e289e87b9b Mon Sep 17 00:00:00 2001 From: "Eddy (Eduard) Stefes" Date: Mon, 14 Apr 2025 09:49:43 +0200 Subject: [PATCH 127/222] Let CStrings be either 1 or 2 byte aligned. Some architectures (like s390x) require strings to be 2 byte aligned. Therefor the section name will be marked with a .2 postfix on this architectures. Allowing a section name with a .1 or .2 postfix will make the test pass on either platform. --- tests/assembly/cstring-merging.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/assembly/cstring-merging.rs b/tests/assembly/cstring-merging.rs index 07f25d1e1a42..b5c530ac35d7 100644 --- a/tests/assembly/cstring-merging.rs +++ b/tests/assembly/cstring-merging.rs @@ -5,7 +5,7 @@ use std::ffi::CStr; -// CHECK: .section .rodata.str1.1,"aMS" +// CHECK: .section .rodata.str1.{{[12]}},"aMS" // CHECK: .Lanon.{{.+}}: // CHECK-NEXT: .asciz "foo" #[unsafe(no_mangle)] From 6a8718cab772ecfbce3de7a701e9abf8e476bc37 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Mon, 14 Apr 2025 11:06:46 +0900 Subject: [PATCH 128/222] Add test for issue 34834 --- .../associated_type_bound/hrtb-associated.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/ui/traits/associated_type_bound/hrtb-associated.rs diff --git a/tests/ui/traits/associated_type_bound/hrtb-associated.rs b/tests/ui/traits/associated_type_bound/hrtb-associated.rs new file mode 100644 index 000000000000..59e5a09c0cbb --- /dev/null +++ b/tests/ui/traits/associated_type_bound/hrtb-associated.rs @@ -0,0 +1,30 @@ +//@ check-pass +//! This test ensures that HRTB (higher-ranked trait bounds) on associated types +//! compile correctly. This was previously rejected by the compiler. +//! Related issue: + +pub trait Provides<'a> { + type Item; +} + +pub trait Selector: for<'a> Provides<'a> { + type Namespace: PartialEq + for<'a> PartialEq<>::Item>; + + fn get_namespace(&self) -> ::Item; +} + +pub struct MySelector; + +impl<'a> Provides<'a> for MySelector { + type Item = &'a str; +} + +impl Selector for MySelector { + type Namespace = String; + + fn get_namespace(&self) -> &str { + unimplemented!() + } +} + +fn main() {} From 2c2c9df653079893c34dc9ef72201fdab3a67abc Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 14 Apr 2025 12:43:16 +0200 Subject: [PATCH 129/222] drop global where-bounds before merging candidates --- .../src/solve/trait_goals.rs | 8 +++-- .../cycles/inductive-cycle-but-err.rs | 8 +++++ .../cycles/inductive-cycle-but-err.stderr | 21 +++++++++--- ...global-where-bound-region-constraints-2.rs | 33 +++++++++++++++++++ .../global-where-bound-region-constraints.rs | 29 ++++++++++++++++ 5 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs create mode 100644 tests/ui/traits/winnowing/global-where-bound-region-constraints.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index d42c9980f463..b96ffcbc7957 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1238,10 +1238,11 @@ where D: SolverDelegate, I: Interner, { + #[instrument(level = "debug", skip(self, goal), ret)] pub(super) fn merge_trait_candidates( &mut self, goal: Goal>, - candidates: Vec>, + mut candidates: Vec>, ) -> Result<(CanonicalResponse, Option), NoSolution> { if let TypingMode::Coherence = self.typing_mode() { let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); @@ -1323,13 +1324,16 @@ where // If there are *only* global where bounds, then make sure to return that this // is still reported as being proven-via the param-env so that rigid projections - // operate correctly. + // operate correctly. Otherwise, drop all global where-bounds before merging the + // remaining candidates. let proven_via = if candidates.iter().all(|c| matches!(c.source, CandidateSource::ParamEnv(_))) { TraitGoalProvenVia::ParamEnv } else { + candidates.retain(|c| !matches!(c.source, CandidateSource::ParamEnv(_))); TraitGoalProvenVia::Misc }; + let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); if let Some(response) = self.try_merge_responses(&all_candidates) { Ok((response, Some(proven_via))) diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs index b0c778e7f574..754fc872e457 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs @@ -34,9 +34,17 @@ where MultipleNested: Trait, {} +// We ignore the trivially true global where-bounds when checking that this +// impl is well-formed, meaning that we depend on `MultipleNested: Trait` when +// recursively proving `MultipleCandidates: Trait`. +// +// These overflow errors will disappear once we treat these cycles as either +// productive or an error. impl Trait for MultipleNested +//~^ ERROR overflow evaluating the requirement `MultipleNested: Trait` where MultipleCandidates: Trait, + //~^ ERROR overflow evaluating the requirement `MultipleCandidates: Trait` DoesNotImpl: Trait, {} diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr index acacaf6a331d..7895a2636345 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr @@ -1,16 +1,29 @@ +error[E0275]: overflow evaluating the requirement `MultipleNested: Trait` + --> $DIR/inductive-cycle-but-err.rs:43:16 + | +LL | impl Trait for MultipleNested + | ^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `MultipleCandidates: Trait` + --> $DIR/inductive-cycle-but-err.rs:46:25 + | +LL | MultipleCandidates: Trait, + | ^^^^^ + error[E0277]: the trait bound `MultipleCandidates: Trait` is not satisfied - --> $DIR/inductive-cycle-but-err.rs:46:19 + --> $DIR/inductive-cycle-but-err.rs:54:19 | LL | impls_trait::(); | ^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `MultipleCandidates` | = help: the trait `Trait` is implemented for `MultipleCandidates` note: required by a bound in `impls_trait` - --> $DIR/inductive-cycle-but-err.rs:43:19 + --> $DIR/inductive-cycle-but-err.rs:51:19 | LL | fn impls_trait() {} | ^^^^^ required by this bound in `impls_trait` -error: aborting due to 1 previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0275, E0277. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs b/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs new file mode 100644 index 000000000000..d422605a2923 --- /dev/null +++ b/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs @@ -0,0 +1,33 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#172. +// +// In this test the global where-bound simply constrains the +// object lifetime bound to 'static while the builtin impl +// ends up also emitting a `dyn Any: 'static` type outlives +// constraint. This previously resulted in ambiguity. We now +// always prefer the impl. + +pub trait Any: 'static {} + +pub trait Downcast: Any +where + T: Any, +{ +} + +// elided object lifetime: `dyn Any + 'static` +impl dyn Any { + pub fn is(&self) + where + T: Any, + // elaboration adds global where-clause `dyn Any + 'static: Any` + Self: Downcast, + { + } +} + +fn main() {} diff --git a/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs b/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs new file mode 100644 index 000000000000..3bc8b0438bf8 --- /dev/null +++ b/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs @@ -0,0 +1,29 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#172. +// +// The next-generation trait solver previously simply tried +// to merge the global where-bounds with the impl candidates. +// This caused ambiguity in case the where-bound had stricter +// region requirements than the impl. + +trait Trait {} +struct Foo<'a, 'b>(&'a (), &'b ()); +impl<'a> Trait for Foo<'a, 'static> {} + +fn impls_trait() {} +fn foo() +where + Foo<'static, 'static>: Trait, +{ + // impl requires `'1 to be 'static + // global where-bound requires both '0 and '1 to be 'static + // + // we always prefer the impl here. + impls_trait::>(); +} + +fn main() {} From ce9d8678ca9d25c603dfc655a5f955bee4a0a9fe Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 14 Apr 2025 10:37:51 +0200 Subject: [PATCH 130/222] do not leak auto traits in item bounds --- .../src/solve/trait_goals.rs | 32 ++++++++++++++---- .../avoid-query-cycle-via-item-bound.rs | 33 +++++++++++++++++++ tests/ui/impl-trait/in-trait/refine-cycle.rs | 3 ++ 3 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index d42c9980f463..3adfac3d4292 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -164,6 +164,7 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { + let cx = ecx.cx(); if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -174,20 +175,37 @@ where // Only consider auto impls of unsafe traits when there are no unsafe // fields. - if ecx.cx().trait_is_unsafe(goal.predicate.def_id()) + if cx.trait_is_unsafe(goal.predicate.def_id()) && goal.predicate.self_ty().has_unsafe_fields() { return Err(NoSolution); } - // We only look into opaque types during analysis for opaque types - // outside of their defining scope. Doing so for opaques in the - // defining scope may require calling `typeck` on the same item we're - // currently type checking, which will result in a fatal cycle that - // ideally we want to avoid, since we can make progress on this goal - // via an alias bound or a locally-inferred hidden type instead. + // We leak the implemented auto traits of opaques outside of their defining scope. + // This depends on `typeck` of the defining scope of that opaque, which may result in + // fatal query cycles. + // + // We only get to this point if we're outside of the defining scope as we'd otherwise + // be able to normalize the opaque type. We may also cycle in case `typeck` of a defining + // scope relies on the current context, e.g. either because it also leaks auto trait + // bounds of opaques defined in the current context or by evaluating the current item. + // + // To avoid this we don't try to leak auto trait bounds if they can also be proven via + // item bounds of the opaque. These bounds are always applicable as auto traits must not + // have any generic parameters. They would also get preferred over the impl candidate + // when merging candidates anyways. + // + // See tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs. if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id)); + for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() { + if item_bound + .as_trait_clause() + .is_some_and(|b| b.def_id() == goal.predicate.def_id()) + { + return Err(NoSolution); + } + } } ecx.probe_and_evaluate_goal_for_constituent_tys( diff --git a/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs b/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs new file mode 100644 index 000000000000..7f366fdcabd2 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs @@ -0,0 +1,33 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +// When proving auto trait bounds, make sure that we depend on auto trait +// leakage if we can also prove it via an item bound. +fn is_send(_: T) {} + +fn direct() -> impl Send { + is_send(check(false)); // leaks auto traits, depends on `check` + 1u16 +} + +trait Indir: Send {} +impl Indir for u32 {} +fn indir() -> impl Indir { + is_send(check(false)); // leaks auto traits, depends on `check` + 1u32 +} + +fn check(b: bool) -> impl Sized { + if b { + // must not leak auto traits, as we otherwise get a query cycle. + is_send(direct()); + is_send(indir()); + } + 1u64 +} + +fn main() { + check(true); +} diff --git a/tests/ui/impl-trait/in-trait/refine-cycle.rs b/tests/ui/impl-trait/in-trait/refine-cycle.rs index 78d672a7ed60..d97f9821347e 100644 --- a/tests/ui/impl-trait/in-trait/refine-cycle.rs +++ b/tests/ui/impl-trait/in-trait/refine-cycle.rs @@ -1,4 +1,7 @@ //@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) // Make sure that refinement checking doesn't cause a cycle in `Instance::resolve` // which calls `compare_impl_item`. From 2e79f7cd6102ac7faa4938f61f056e26b08249a9 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 14 Apr 2025 10:38:16 +0200 Subject: [PATCH 131/222] move tests --- .../impl-trait/{ => auto-trait-leakage}/auto-trait-coherence.rs | 0 .../{ => auto-trait-leakage}/auto-trait-coherence.stderr | 0 .../{ => auto-trait-leakage}/auto-trait-contains-err.rs | 0 .../{ => auto-trait-leakage}/auto-trait-contains-err.stderr | 0 .../impl-trait/{ => auto-trait-leakage}/auto-trait-leak-rpass.rs | 0 tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-leak.rs | 0 .../ui/impl-trait/{ => auto-trait-leakage}/auto-trait-leak.stderr | 0 tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-leak2.rs | 0 .../impl-trait/{ => auto-trait-leakage}/auto-trait-leak2.stderr | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-coherence.rs (100%) rename tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-coherence.stderr (100%) rename tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-contains-err.rs (100%) rename tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-contains-err.stderr (100%) rename tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-leak-rpass.rs (100%) rename tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-leak.rs (100%) rename tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-leak.stderr (100%) rename tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-leak2.rs (100%) rename tests/ui/impl-trait/{ => auto-trait-leakage}/auto-trait-leak2.stderr (100%) diff --git a/tests/ui/impl-trait/auto-trait-coherence.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-coherence.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.rs diff --git a/tests/ui/impl-trait/auto-trait-coherence.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-coherence.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.stderr diff --git a/tests/ui/impl-trait/auto-trait-contains-err.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-contains-err.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.rs diff --git a/tests/ui/impl-trait/auto-trait-contains-err.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-contains-err.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.stderr diff --git a/tests/ui/impl-trait/auto-trait-leak-rpass.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak-rpass.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak-rpass.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak-rpass.rs diff --git a/tests/ui/impl-trait/auto-trait-leak.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs diff --git a/tests/ui/impl-trait/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr diff --git a/tests/ui/impl-trait/auto-trait-leak2.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak2.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs diff --git a/tests/ui/impl-trait/auto-trait-leak2.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak2.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr From 836ea25b4d42d307a75e98ec0c703dbc8bcdab79 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 14 Apr 2025 11:02:36 +0200 Subject: [PATCH 132/222] add RPITIT tests: method compat auto trait leakage --- ...atability-via-leakage-cycle.current.stderr | 58 +++++++++ ...ompatability-via-leakage-cycle.next.stderr | 122 ++++++++++++++++++ .../method-compatability-via-leakage-cycle.rs | 30 +++++ .../method-compatability-via-leakage.rs | 14 ++ 4 files changed, 224 insertions(+) create mode 100644 tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr create mode 100644 tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr create mode 100644 tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs create mode 100644 tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr new file mode 100644 index 000000000000..bf598d627094 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr @@ -0,0 +1,58 @@ +error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `::foo::{opaque#0}: core::marker::Send`... +note: ...which requires computing type of opaque `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `::foo` contains FFI-unwind calls... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 + | +LL | impl Trait for u32 { + | ^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr new file mode 100644 index 000000000000..6bec5bbc0632 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr @@ -0,0 +1,122 @@ +error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires computing type of `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires computing type of opaque `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `::foo` contains FFI-unwind calls... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 + | +LL | impl Trait for u32 { + | ^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires computing type of `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires computing type of opaque `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `::foo` contains FFI-unwind calls... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 + | +LL | impl Trait for u32 { + | ^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs new file mode 100644 index 000000000000..917820dc2b8b --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs @@ -0,0 +1,30 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ known-bug: #139788 + +// Recursively using the trait method inside of an impl in case checking +// method compatability relies on opaque type leakage currently causes a +// cycle error. + +trait Trait { + // desugars to + // type Assoc: Sized + Send; + // fn foo(b: bool) -> Self::Assoc; + fn foo(b: bool) -> impl Sized + Send; +} + +impl Trait for u32 { + // desugars to + // type Assoc = impl_rpit::; + // fn foo(b: bool) -> Self::Assoc { .. } + fn foo(b: bool) -> impl Sized { + if b { + u32::foo(false) + } else { + 1u32 + } + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs new file mode 100644 index 000000000000..249ec0728c1a --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +trait Trait { + fn foo() -> impl Sized + Send; +} + +impl Trait for u32 { + fn foo() -> impl Sized {} +} + +fn main() {} From 582718380119e0e7aa2da76ea49d111b3735c2c3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Apr 2025 13:56:51 +0200 Subject: [PATCH 133/222] ptr docs: add missing backtics around 'usize' --- library/core/src/ptr/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 2357ba23aa0d..445c789a7de2 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -278,7 +278,7 @@ //! ### Using Strict Provenance //! //! Most code needs no changes to conform to strict provenance, as the only really concerning -//! operation is casts from usize to a pointer. For code which *does* cast a `usize` to a pointer, +//! operation is casts from `usize` to a pointer. For code which *does* cast a `usize` to a pointer, //! the scope of the change depends on exactly what you're doing. //! //! In general, you just need to make sure that if you want to convert a `usize` address to a From 9c88eb6c4344cc2387900bb362f09291f031e9c2 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 14 Apr 2025 14:46:48 +0200 Subject: [PATCH 134/222] normalize: prefer ParamEnv over AliasBound --- .../src/solve/assembly/mod.rs | 51 +++++++++++-------- .../norm-where-bound-gt-alias-bound.rs | 29 +++++++++++ 2 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 384a304c4a9d..ee000b117486 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -792,37 +792,46 @@ where }; match proven_via { - // Even when a trait bound has been proven using a where-bound, we - // still need to consider alias-bounds for normalization, see - // tests/ui/next-solver/alias-bound-shadowed-by-env.rs. - // - // FIXME(const_trait_impl): should this behavior also be used by - // constness checking. Doing so is *at least theoretically* breaking, - // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754 TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => { - let mut candidates_from_env_and_bounds: Vec<_> = candidates - .iter() - .filter(|c| { - matches!( - c.source, - CandidateSource::AliasBound | CandidateSource::ParamEnv(_) - ) - }) - .map(|c| c.result) - .collect(); + let mut considered_candidates = Vec::new(); + considered_candidates.extend( + candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + .map(|c| c.result), + ); + + // Even when a trait bound has been proven using a where-bound, we + // still need to consider alias-bounds for normalization, see + // tests/ui/next-solver/alias-bound-shadowed-by-env.rs. + // + // We still need to prefer where-bounds over alias-bounds however. + // See tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs. + // + // FIXME(const_trait_impl): should this behavior also be used by + // constness checking. Doing so is *at least theoretically* breaking, + // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754 + if considered_candidates.is_empty() { + considered_candidates.extend( + candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::AliasBound)) + .map(|c| c.result), + ); + } // If the trait goal has been proven by using the environment, we want to treat // aliases as rigid if there are no applicable projection bounds in the environment. - if candidates_from_env_and_bounds.is_empty() { + if considered_candidates.is_empty() { if let Ok(response) = inject_normalize_to_rigid_candidate(self) { - candidates_from_env_and_bounds.push(response); + considered_candidates.push(response); } } - if let Some(response) = self.try_merge_responses(&candidates_from_env_and_bounds) { + if let Some(response) = self.try_merge_responses(&considered_candidates) { Ok(response) } else { - self.flounder(&candidates_from_env_and_bounds) + self.flounder(&considered_candidates) } } TraitGoalProvenVia::Misc => { diff --git a/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs new file mode 100644 index 000000000000..cdfb0ee45af4 --- /dev/null +++ b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs @@ -0,0 +1,29 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Make sure we prefer the `I::IntoIterator: Iterator` +// where-bound over the `I::Intoiterator: Iterator` +// alias-bound. + +trait Iterator { + type Item; +} + +trait IntoIterator { + type Item; + type IntoIter: Iterator; +} + +fn normalize>() {} + +fn foo() +where + I: IntoIterator, + I::IntoIter: Iterator, +{ + normalize::(); +} + +fn main() {} From dc584580f36dd7d92c8b93405e6a0a1efc727a88 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 14 Apr 2025 14:27:15 +0100 Subject: [PATCH 135/222] Add myself to mailmap --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index b09aebd12dd8..c3ce111bfe3b 100644 --- a/.mailmap +++ b/.mailmap @@ -292,6 +292,7 @@ James Hinshelwood James Miller James Perry James Sanderson +Jamie Hill-Daniel Jana Dönszelmann Jana Dönszelmann Jana Dönszelmann From d5de2fa8bba93cf5cde42b4605b6886f8660f5bf Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 14 Apr 2025 15:32:34 +0200 Subject: [PATCH 136/222] use `realpath` in `bootstrap.py` when creating build-dir this avoids crashes when `./build` is a symlink to a non-existent directory. --- src/bootstrap/bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 01a9792f1b37..42c314eaa654 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1298,7 +1298,7 @@ def bootstrap(args): build.check_vendored_status() if not os.path.exists(build.build_dir): - os.makedirs(build.build_dir) + os.makedirs(os.path.realpath(build.build_dir)) # Fetch/build the bootstrap build.download_toolchain() From 1b46969a11b2cfa000593b225af94a9d3bfbedfc Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 14 Apr 2025 14:16:30 +0100 Subject: [PATCH 137/222] Specify `--print info=file` syntax in `--help` --- compiler/rustc_session/src/config.rs | 14 ++++---------- tests/run-make/rustc-help/help-v.diff | 2 +- tests/run-make/rustc-help/help-v.stdout | 6 ++++-- tests/run-make/rustc-help/help.stdout | 6 ++++-- .../invalid-compile-flags/print-without-arg.stderr | 5 +++-- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index bdd54a15147b..fc05470d941c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1560,9 +1560,10 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE ) }); -static PRINT_KINDS_STRING: LazyLock = LazyLock::new(|| { +static PRINT_HELP: LazyLock = LazyLock::new(|| { format!( - "[{}]", + "Compiler information to print on stdout (or to a file)\n\ + INFO may be one of ({}).", PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::>().join("|") ) }); @@ -1621,14 +1622,7 @@ pub fn rustc_optgroups() -> Vec { "Comma separated list of types of output for the compiler to emit", "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]", ), - opt( - Stable, - Multi, - "", - "print", - "Compiler information to print on stdout", - &PRINT_KINDS_STRING, - ), + opt(Stable, Multi, "", "print", &PRINT_HELP, "INFO[=FILE]"), opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""), opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""), opt(Stable, Opt, "o", "", "Write output to ", "FILENAME"), diff --git a/tests/run-make/rustc-help/help-v.diff b/tests/run-make/rustc-help/help-v.diff index 22c5dd81bdb0..30703f6424e7 100644 --- a/tests/run-make/rustc-help/help-v.diff +++ b/tests/run-make/rustc-help/help-v.diff @@ -1,4 +1,4 @@ -@@ -51,10 +51,27 @@ +@@ -53,10 +53,27 @@ Set a codegen option -V, --version Print version info and exit -v, --verbose Use verbose output diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index f19ca1e9f90a..13af6e21060b 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -29,8 +29,10 @@ Options: --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] Comma separated list of types of output for the compiler to emit - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] - Compiler information to print on stdout + --print INFO[=FILE] + Compiler information to print on stdout (or to a file) + INFO may be one of + (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models). -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o FILENAME Write output to diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index f7d352966035..62757d989eb3 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -29,8 +29,10 @@ Options: --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] Comma separated list of types of output for the compiler to emit - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] - Compiler information to print on stdout + --print INFO[=FILE] + Compiler information to print on stdout (or to a file) + INFO may be one of + (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models). -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o FILENAME Write output to diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/invalid-compile-flags/print-without-arg.stderr index 8abaee5056ba..fd2a36e761be 100644 --- a/tests/ui/invalid-compile-flags/print-without-arg.stderr +++ b/tests/ui/invalid-compile-flags/print-without-arg.stderr @@ -1,5 +1,6 @@ error: Argument to option 'print' missing Usage: - --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models] - Compiler information to print on stdout + --print INFO[=FILE] Compiler information to print on stdout (or to a file) + INFO may be one of + (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models). From 3da0a19a291e62d1bb315b233a5fb74bcccb12ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 14 Apr 2025 16:27:33 +0200 Subject: [PATCH 138/222] Improve wording of post-merge report --- src/ci/citool/src/analysis.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 208a494183c0..9fc7c309bfbd 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -520,23 +520,27 @@ fn report_test_diffs( } if doctest_count > 0 { + let prefix = + if doctest_count < original_diff_count { "Additionally, " } else { "" }; println!( - "\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.", + "\n{prefix}{doctest_count} doctest {} were found. These are ignored, as they are noisy.", pluralize("diff", doctest_count) ); } // Now print the job group index - println!("\n**Job group index**\n"); - for (group, jobs) in job_index.into_iter().enumerate() { - println!( - "- {}: {}", - format_job_group(group as u64), - jobs.iter() - .map(|j| format_job_link(job_info_resolver, job_metrics, j)) - .collect::>() - .join(", ") - ); + if !job_index.is_empty() { + println!("\n**Job group index**\n"); + for (group, jobs) in job_index.into_iter().enumerate() { + println!( + "- {}: {}", + format_job_group(group as u64), + jobs.iter() + .map(|j| format_job_link(job_info_resolver, job_metrics, j)) + .collect::>() + .join(", ") + ); + } } }, ); From 7ad16974b995746b9156d90b8b80fb137afcd1e9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Jan 2025 15:57:13 +0000 Subject: [PATCH 139/222] Allow const patterns of matches to contain pattern types --- compiler/rustc_borrowck/src/type_check/mod.rs | 14 ++-- .../src/builder/matches/test.rs | 29 +++++++- tests/ui/type/pattern_types/derives.rs | 3 +- tests/ui/type/pattern_types/derives.stderr | 2 +- tests/ui/type/pattern_types/derives_fail.rs | 26 +++++++ .../ui/type/pattern_types/derives_fail.stderr | 74 +++++++++++++++++++ tests/ui/type/pattern_types/matching.rs | 26 +++++++ tests/ui/type/pattern_types/matching_fail.rs | 25 +++++++ .../type/pattern_types/matching_fail.stderr | 43 +++++++++++ 9 files changed, 233 insertions(+), 9 deletions(-) create mode 100644 tests/ui/type/pattern_types/derives_fail.rs create mode 100644 tests/ui/type/pattern_types/derives_fail.stderr create mode 100644 tests/ui/type/pattern_types/matching.rs create mode 100644 tests/ui/type/pattern_types/matching_fail.rs create mode 100644 tests/ui/type/pattern_types/matching_fail.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f6144a25938c..65e16260b569 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1568,11 +1568,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } CastKind::Transmute => { - span_mirbug!( - self, - rvalue, - "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR", - ); + let ty_from = op.ty(self.body, tcx); + match ty_from.kind() { + ty::Pat(base, _) if base == ty => {} + _ => span_mirbug!( + self, + rvalue, + "Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR", + ), + } } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index d1f9d4c34fe1..57cf8fa719c2 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -140,8 +140,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); - let expect_ty = value.ty(); - let expect = self.literal_operand(test.span, value); + let mut expect_ty = value.ty(); + let mut expect = self.literal_operand(test.span, value); let mut place = place; let mut block = block; @@ -174,6 +174,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place = ref_str; ty = ref_str_ty; } + &ty::Pat(base, _) => { + assert_eq!(ty, value.ty()); + assert!(base.is_trivially_pure_clone_copy()); + + let transmuted_place = self.temp(base, test.span); + self.cfg.push_assign( + block, + self.source_info(scrutinee_span), + transmuted_place, + Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base), + ); + + let transmuted_expect = self.temp(base, test.span); + self.cfg.push_assign( + block, + self.source_info(test.span), + transmuted_expect, + Rvalue::Cast(CastKind::Transmute, expect, base), + ); + + place = transmuted_place; + expect = Operand::Copy(transmuted_expect); + ty = base; + expect_ty = base; + } _ => {} } diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs index 3878c47554d9..a3959b383177 100644 --- a/tests/ui/type/pattern_types/derives.rs +++ b/tests/ui/type/pattern_types/derives.rs @@ -1,4 +1,5 @@ -//! Check that pattern types don't implement traits of their base automatically +//! Check that pattern types don't implement traits of their base automatically. +//! Exceptions are `Clone` and `Copy`, which have builtin impls for pattern types. #![feature(pattern_types)] #![feature(pattern_type_macro)] diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr index f59617ebc456..2d83684b152e 100644 --- a/tests/ui/type/pattern_types/derives.stderr +++ b/tests/ui/type/pattern_types/derives.stderr @@ -1,5 +1,5 @@ error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` - --> $DIR/derives.rs:10:20 + --> $DIR/derives.rs:11:20 | LL | #[derive(Clone, Copy, PartialEq)] | --------- in this derive macro expansion diff --git a/tests/ui/type/pattern_types/derives_fail.rs b/tests/ui/type/pattern_types/derives_fail.rs new file mode 100644 index 000000000000..a3fbad667207 --- /dev/null +++ b/tests/ui/type/pattern_types/derives_fail.rs @@ -0,0 +1,26 @@ +//! Check that pattern types don't implement traits of their base automatically. +//! Exceptions are `Clone` and `Copy`, which have bultin impls for pattern types. + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] +#[repr(transparent)] +struct Nanoseconds(NanoI32); +//~^ ERROR: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied +//~| ERROR: `(i32) is 0..=999999999` doesn't implement `Debug` +//~| ERROR: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied +//~| ERROR: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied +//~| ERROR: the trait bound `(i32) is 0..=999999999: Default` is not satisfied +//~| ERROR: can't compare `(i32) is 0..=999999999` with `_` +//~| ERROR: `==` cannot be applied + +type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999); + +fn main() { + let x = Nanoseconds(unsafe { std::mem::transmute(42) }); + let y = x.clone(); + if y == x {} +} diff --git a/tests/ui/type/pattern_types/derives_fail.stderr b/tests/ui/type/pattern_types/derives_fail.stderr new file mode 100644 index 000000000000..78bef726341d --- /dev/null +++ b/tests/ui/type/pattern_types/derives_fail.stderr @@ -0,0 +1,74 @@ +error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | --------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ + +error[E0277]: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | -- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Eq` is not implemented for `(i32) is 0..=999999999` + | +note: required by a bound in `AssertParamIsEq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL + +error[E0277]: `(i32) is 0..=999999999` doesn't implement `Debug` + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ----- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = help: the trait `Debug` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | --- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Ord` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: can't compare `(i32) is 0..=999999999` with `_` + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ---------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ no implementation for `(i32) is 0..=999999999 < _` and `(i32) is 0..=999999999 > _` + | + = help: the trait `PartialOrd<_>` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ---- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Hash` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: the trait bound `(i32) is 0..=999999999: Default` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Default` is not implemented for `(i32) is 0..=999999999` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/type/pattern_types/matching.rs b/tests/ui/type/pattern_types/matching.rs new file mode 100644 index 000000000000..b8463a8e8229 --- /dev/null +++ b/tests/ui/type/pattern_types/matching.rs @@ -0,0 +1,26 @@ +#![feature(pattern_types, pattern_type_macro, structural_match)] + +//@ check-pass + +use std::marker::StructuralPartialEq; +use std::pat::pattern_type; + +struct Thing(pattern_type!(u32 is 1..)); + +impl StructuralPartialEq for Thing {} +impl PartialEq for Thing { + fn eq(&self, other: &Thing) -> bool { + unsafe { std::mem::transmute::<_, u32>(self.0) == std::mem::transmute::<_, u32>(other.0) } + } +} + +impl Eq for Thing {} + +const TWO: Thing = Thing(2); + +const _: () = match TWO { + TWO => {} + _ => unreachable!(), +}; + +fn main() {} diff --git a/tests/ui/type/pattern_types/matching_fail.rs b/tests/ui/type/pattern_types/matching_fail.rs new file mode 100644 index 000000000000..8e2c741e3e0a --- /dev/null +++ b/tests/ui/type/pattern_types/matching_fail.rs @@ -0,0 +1,25 @@ +#![feature(pattern_types, pattern_type_macro, structural_match)] + +use std::pat::pattern_type; + +const THREE: pattern_type!(u32 is 1..) = 3; + +const _: () = match THREE { + THREE => {} + //~^ ERROR non-structural type + _ => unreachable!(), +}; + +const _: () = match THREE { + 3 => {} + //~^ ERROR mismatched types + _ => unreachable!(), +}; + +const _: () = match 3 { + THREE => {} + //~^ ERROR mismatched types + _ => unreachable!(), +}; + +fn main() {} diff --git a/tests/ui/type/pattern_types/matching_fail.stderr b/tests/ui/type/pattern_types/matching_fail.stderr new file mode 100644 index 000000000000..446180d80f24 --- /dev/null +++ b/tests/ui/type/pattern_types/matching_fail.stderr @@ -0,0 +1,43 @@ +error: constant of non-structural type `(u32) is 1..` in a pattern + --> $DIR/matching_fail.rs:8:5 + | +LL | const THREE: pattern_type!(u32 is 1..) = 3; + | -------------------------------------- constant defined here +... +LL | THREE => {} + | ^^^^^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + +error[E0308]: mismatched types + --> $DIR/matching_fail.rs:14:5 + | +LL | const _: () = match THREE { + | ----- this expression has type `(u32) is 1..` +LL | 3 => {} + | ^ expected `(u32) is 1..`, found integer + | + = note: expected pattern type `(u32) is 1..` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/matching_fail.rs:20:5 + | +LL | const THREE: pattern_type!(u32 is 1..) = 3; + | -------------------------------------- constant defined here +... +LL | const _: () = match 3 { + | - this expression has type `{integer}` +LL | THREE => {} + | ^^^^^ + | | + | expected integer, found `(u32) is 1..` + | `THREE` is interpreted as a constant, not a new binding + | help: introduce a new binding instead: `other_three` + | + = note: expected type `{integer}` + found pattern type `(u32) is 1..` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. From 13b4734e3102b4fd5ad99b98a8cc46744faf5d68 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Apr 2025 22:43:16 +0000 Subject: [PATCH 140/222] Derive Obligation's fold impls --- compiler/rustc_infer/src/traits/mod.rs | 7 +++- .../src/traits/structural_impls.rs | 32 +------------------ 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index b537750f1b51..6d5ad96e31c9 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -12,6 +12,7 @@ use std::hash::{Hash, Hasher}; use hir::def_id::LocalDefId; use rustc_hir as hir; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; pub use rustc_middle::traits::*; @@ -35,9 +36,11 @@ use crate::infer::InferCtxt; /// either identifying an `impl` (e.g., `impl Eq for i32`) that /// satisfies the obligation, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone)] +#[derive(Clone, TypeFoldable, TypeVisitable)] pub struct Obligation<'tcx, T> { /// The reason we have to prove this thing. + #[type_foldable(identity)] + #[type_visitable(ignore)] pub cause: ObligationCause<'tcx>, /// The environment in which we should prove this thing. @@ -51,6 +54,8 @@ pub struct Obligation<'tcx, T> { /// If this goes over a certain threshold, we abort compilation -- /// in such cases, we can not say whether or not the predicate /// holds for certain. Stupid halting problem; such a drag. + #[type_foldable(identity)] + #[type_visitable(ignore)] pub recursion_depth: usize, } diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 4335073d9bc6..03661ebf7ec5 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -1,8 +1,6 @@ use std::fmt; -use rustc_middle::ty::{ - self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, try_visit, -}; +use rustc_middle::ty; use crate::traits; use crate::traits::project::Normalized; @@ -34,31 +32,3 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { write!(f, "MismatchedProjectionTypes({:?})", self.err) } } - -/////////////////////////////////////////////////////////////////////////// -// TypeFoldable implementations. - -impl<'tcx, O: TypeFoldable>> TypeFoldable> - for traits::Obligation<'tcx, O> -{ - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - Ok(traits::Obligation { - cause: self.cause, - recursion_depth: self.recursion_depth, - predicate: self.predicate.try_fold_with(folder)?, - param_env: self.param_env.try_fold_with(folder)?, - }) - } -} - -impl<'tcx, O: TypeVisitable>> TypeVisitable> - for traits::Obligation<'tcx, O> -{ - fn visit_with>>(&self, visitor: &mut V) -> V::Result { - try_visit!(self.predicate.visit_with(visitor)); - self.param_env.visit_with(visitor) - } -} From 1f3199c89995ee7ae5cbdaa81d1df5138660d61a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Apr 2025 16:53:24 +0200 Subject: [PATCH 141/222] Disable some r-a tests in bootstrap. --- src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index 15de88ea656d..4bd365be7ca8 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -97,6 +97,7 @@ fn test_fn_like_macro_clone_raw_ident() { } #[test] +#[cfg(not(bootstrap))] fn test_fn_like_fn_like_span_join() { assert_expand( "fn_like_span_join", @@ -111,6 +112,7 @@ fn test_fn_like_fn_like_span_join() { } #[test] +#[cfg(not(bootstrap))] fn test_fn_like_fn_like_span_ops() { assert_expand( "fn_like_span_ops", From 83ea3454dfaf7ff54171035a70a89d03085d2a9d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Apr 2025 02:08:35 +0000 Subject: [PATCH 142/222] Remove define_debug_via_print for ExistentialProjection --- compiler/rustc_type_ir/src/ir_print.rs | 2 +- compiler/rustc_type_ir/src/predicate.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index c259a9747f0d..388ad09cb200 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -60,7 +60,7 @@ define_display_via_print!( PatternKind, ); -define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection, PatternKind); +define_debug_via_print!(TraitRef, ExistentialTraitRef, PatternKind); impl fmt::Display for OutlivesPredicate where diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 22d0fa23d0c5..8e10636ff657 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -374,7 +374,7 @@ impl ty::Binder> { } /// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", From 4b63362f3d0a455707f64ce345ca3a5467b04764 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Mon, 14 Apr 2025 15:52:25 +0000 Subject: [PATCH 143/222] Use `newtype_index!`-generated types more idiomatically --- compiler/rustc_ast_lowering/src/path.rs | 3 +-- .../rustc_borrowck/src/region_infer/mod.rs | 3 +-- .../src/debuginfo/create_scope_map.rs | 4 +-- compiler/rustc_hir/src/definitions.rs | 9 +++---- .../src/check/compare_impl_item.rs | 7 ++--- .../src/infer/region_constraints/mod.rs | 4 +-- .../rustc_infer/src/infer/snapshot/fudge.rs | 7 ++--- compiler/rustc_middle/src/mir/pretty.rs | 6 ++--- compiler/rustc_middle/src/ty/fold.rs | 2 +- compiler/rustc_middle/src/ty/visit.rs | 12 +++------ compiler/rustc_mir_build/src/thir/cx/expr.rs | 4 +-- compiler/rustc_mir_transform/src/coroutine.rs | 4 +-- .../rustc_mir_transform/src/elaborate_drop.rs | 17 ++++++------ compiler/rustc_mir_transform/src/inline.rs | 12 ++++----- compiler/rustc_mir_transform/src/patch.rs | 2 +- .../rustc_mir_transform/src/promote_consts.rs | 14 ++++++---- .../src/solve/eval_ctxt/canonical.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 7 +++-- compiler/rustc_resolve/src/late.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 27 ++++++------------- 20 files changed, 61 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index c464c159c34c..0bd65aec10f4 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -448,8 +448,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { generic_args.args.insert_many( 0, - (start.as_u32()..end.as_u32()).map(|i| { - let id = NodeId::from_u32(i); + (start..end).map(|id| { let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span); GenericArg::Lifetime(l) }), diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index c82c7341f028..f8af9e59f635 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -338,8 +338,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) { let num_components = sccs.num_sccs(); let mut components = vec![FxIndexSet::default(); num_components]; - for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() { - let reg_var = ty::RegionVid::from_usize(reg_var_idx); + for (reg_var, scc_idx) in sccs.scc_indices().iter_enumerated() { let origin = var_to_origin.get(®_var).unwrap_or(&RegionCtxt::Unknown); components[scc_idx.as_usize()].insert((reg_var, *origin)); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index f52991b36979..d2591139d6ed 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -3,7 +3,6 @@ use std::collections::hash_map::Entry; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext}; use rustc_codegen_ssa::traits::*; use rustc_data_structures::fx::FxHashMap; -use rustc_index::Idx; use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::{Body, SourceScope}; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; @@ -43,8 +42,7 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>( let mut instantiated = DenseBitSet::new_empty(mir.source_scopes.len()); let mut discriminators = FxHashMap::default(); // Instantiate all scopes. - for idx in 0..mir.source_scopes.len() { - let scope = SourceScope::new(idx); + for scope in mir.source_scopes.indices() { make_mir_scope( cx, instance, diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 34f3c169505f..bf7b1eefcf68 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -47,12 +47,9 @@ impl DefPathTable { debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id()); let local_hash = def_path_hash.local_hash(); - let index = { - let index = DefIndex::from(self.index_to_key.len()); - debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index); - self.index_to_key.push(key); - index - }; + let index = self.index_to_key.push(key); + debug!("DefPathTable::insert() - {key:?} <-> {index:?}"); + self.def_path_hashes.push(local_hash); debug_assert!(self.def_path_hashes.len() == self.index_to_key.len()); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 29a9931696ff..106e9ca15548 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -606,7 +606,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // with placeholders, which imply nothing about outlives bounds, and then // prove below that the hidden types are well formed. let universe = infcx.create_next_universe(); - let mut idx = 0; + let mut idx = ty::BoundVar::ZERO; let mapping: FxIndexMap<_, _> = collector .types .iter() @@ -623,10 +623,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx, ty::Placeholder { universe, - bound: ty::BoundTy { - var: ty::BoundVar::from_usize(idx), - kind: ty::BoundTyKind::Anon, - }, + bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon }, }, ), ) diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 8366aa6ec422..40e2e654b2ea 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -618,9 +618,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len()); ( range.clone(), - (range.start.index()..range.end.index()) - .map(|index| self.storage.var_infos[ty::RegionVid::from(index)].origin) - .collect(), + (range.start..range.end).map(|index| self.storage.var_infos[index].origin).collect(), ) } diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index b5d3c26b05e0..39c8c40ea7d8 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -30,11 +30,12 @@ fn const_vars_since_snapshot<'tcx>( snapshot_var_len: usize, ) -> (Range, Vec) { let range = vars_since_snapshot(table, snapshot_var_len); + let range = range.start.vid..range.end.vid; ( - range.start.vid..range.end.vid, - (range.start.index()..range.end.index()) - .map(|index| match table.probe_value(ConstVid::from_u32(index)) { + range.clone(), + range + .map(|index| match table.probe_value(index) { ConstVariableValue::Known { value: _ } => { ConstVariableOrigin { param_def_id: None, span: rustc_span::DUMMY_SP } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 5a038b27337c..e7bd2cb27fa7 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -531,12 +531,12 @@ fn write_mir_intro<'tcx>( // construct a scope tree and write it out let mut scope_tree: FxHashMap> = Default::default(); - for (index, scope_data) in body.source_scopes.iter().enumerate() { + for (index, scope_data) in body.source_scopes.iter_enumerated() { if let Some(parent) = scope_data.parent_scope { - scope_tree.entry(parent).or_default().push(SourceScope::new(index)); + scope_tree.entry(parent).or_default().push(index); } else { // Only the argument scope has no parent, because it's the root. - assert_eq!(index, OUTERMOST_SOURCE_SCOPE.index()); + assert_eq!(index, OUTERMOST_SOURCE_SCOPE); } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 8dc73e4ce85e..8d6871d2f1fe 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -278,7 +278,7 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable>, { - let shift_bv = |bv: ty::BoundVar| ty::BoundVar::from_usize(bv.as_usize() + bound_vars); + let shift_bv = |bv: ty::BoundVar| bv + bound_vars; self.replace_escaping_bound_vars_uncached( value, FnMutDelegate { diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index b341b30af6ac..44c7b6a7c9e8 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -231,9 +231,7 @@ impl MaxUniverse { impl<'tcx> TypeVisitor> for MaxUniverse { fn visit_ty(&mut self, t: Ty<'tcx>) { if let ty::Placeholder(placeholder) = t.kind() { - self.max_universe = ty::UniverseIndex::from_u32( - self.max_universe.as_u32().max(placeholder.universe.as_u32()), - ); + self.max_universe = self.max_universe.max(placeholder.universe); } t.super_visit_with(self) @@ -241,9 +239,7 @@ impl<'tcx> TypeVisitor> for MaxUniverse { fn visit_const(&mut self, c: ty::consts::Const<'tcx>) { if let ty::ConstKind::Placeholder(placeholder) = c.kind() { - self.max_universe = ty::UniverseIndex::from_u32( - self.max_universe.as_u32().max(placeholder.universe.as_u32()), - ); + self.max_universe = self.max_universe.max(placeholder.universe); } c.super_visit_with(self) @@ -251,9 +247,7 @@ impl<'tcx> TypeVisitor> for MaxUniverse { fn visit_region(&mut self, r: ty::Region<'tcx>) { if let ty::RePlaceholder(placeholder) = r.kind() { - self.max_universe = ty::UniverseIndex::from_u32( - self.max_universe.as_u32().max(placeholder.universe.as_u32()), - ); + self.max_universe = self.max_universe.max(placeholder.universe); } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 31e22e69111b..fde23413972b 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -191,7 +191,7 @@ impl<'tcx> ThirBuildCx<'tcx> { let pointer_target = ExprKind::Field { lhs: self.thir.exprs.push(expr), variant_index: FIRST_VARIANT, - name: FieldIdx::from(0u32), + name: FieldIdx::ZERO, }; let arg = Expr { temp_lifetime, ty: pin_ty, span, kind: pointer_target }; let arg = self.thir.exprs.push(arg); @@ -226,7 +226,7 @@ impl<'tcx> ThirBuildCx<'tcx> { adt_def: self.tcx.adt_def(pin_did), variant_index: FIRST_VARIANT, args, - fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]), + fields: Box::new([FieldExpr { name: FieldIdx::ZERO, expr }]), user_ty: None, base: AdtExprBase::None, })); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 4405bd82410e..92d5e152f58e 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -203,7 +203,7 @@ struct TransformVisitor<'tcx> { impl<'tcx> TransformVisitor<'tcx> { fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock { - let block = BasicBlock::new(body.basic_blocks.len()); + let block = body.basic_blocks.next_index(); let source_info = SourceInfo::outermost(body.span); let none_value = match self.coroutine_kind { @@ -1193,7 +1193,7 @@ fn insert_panic_block<'tcx>( body: &mut Body<'tcx>, message: AssertMessage<'tcx>, ) -> BasicBlock { - let assert_block = BasicBlock::new(body.basic_blocks.len()); + let assert_block = body.basic_blocks.next_index(); let kind = TerminatorKind::Assert { cond: Operand::Constant(Box::new(ConstOperand { span: body.span, diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index fa476f961235..e3057a2f648f 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -258,17 +258,16 @@ where ) -> Vec<(Place<'tcx>, Option)> { variant .fields - .iter() - .enumerate() - .map(|(i, f)| { - let field = FieldIdx::new(i); - let subpath = self.elaborator.field_subpath(variant_path, field); + .iter_enumerated() + .map(|(field_idx, field)| { + let subpath = self.elaborator.field_subpath(variant_path, field_idx); let tcx = self.tcx(); assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis); - let field_ty = match tcx - .try_normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args)) - { + let field_ty = match tcx.try_normalize_erasing_regions( + self.elaborator.typing_env(), + field.ty(tcx, args), + ) { Ok(t) => t, Err(_) => Ty::new_error( self.tcx(), @@ -279,7 +278,7 @@ where ), }; - (tcx.mk_place_field(base_place, field, field_ty), subpath) + (tcx.mk_place_field(base_place, field_idx, field_ty), subpath) }) .collect() } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 0ab24e48d443..69e80ed54eae 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -903,9 +903,9 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( let mut integrator = Integrator { args: &args, - new_locals: Local::new(caller_body.local_decls.len()).., - new_scopes: SourceScope::new(caller_body.source_scopes.len()).., - new_blocks: BasicBlock::new(caller_body.basic_blocks.len()).., + new_locals: caller_body.local_decls.next_index().., + new_scopes: caller_body.source_scopes.next_index().., + new_blocks: caller_body.basic_blocks.next_index().., destination: destination_local, callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(), callsite, @@ -1169,7 +1169,7 @@ impl Integrator<'_, '_> { if idx < self.args.len() { self.args[idx] } else { - Local::new(self.new_locals.start.index() + (idx - self.args.len())) + self.new_locals.start + (idx - self.args.len()) } }; trace!("mapping local `{:?}` to `{:?}`", local, new); @@ -1177,13 +1177,13 @@ impl Integrator<'_, '_> { } fn map_scope(&self, scope: SourceScope) -> SourceScope { - let new = SourceScope::new(self.new_scopes.start.index() + scope.index()); + let new = self.new_scopes.start + scope.index(); trace!("mapping scope `{:?}` to `{:?}`", scope, new); new } fn map_block(&self, block: BasicBlock) -> BasicBlock { - let new = BasicBlock::new(self.new_blocks.start.index() + block.index()); + let new = self.new_blocks.start + block.index(); trace!("mapping block `{:?}` to `{:?}`", block, new); new } diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index 6a177faeac81..12ace04c5e26 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -181,7 +181,7 @@ impl<'tcx> MirPatch<'tcx> { /// Queues the addition of a new basic block. pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { - let block = BasicBlock::new(self.term_patch_map.len()); + let block = self.term_patch_map.next_index(); debug!("MirPatch: new_block: {:?}: {:?}", block, data); self.new_blocks.push(data); self.term_patch_map.push(None); diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index c8d8dc147e94..47d438309700 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -18,7 +18,7 @@ use either::{Left, Right}; use rustc_const_eval::check_consts::{ConstCx, qualifs}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_index::{Idx, IndexSlice, IndexVec}; +use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, GenericArgs, List, Ty, TyCtxt, TypeVisitableExt}; @@ -864,17 +864,21 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { new_temp } - fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> { + fn promote_candidate( + mut self, + candidate: Candidate, + next_promoted_index: Promoted, + ) -> Body<'tcx> { let def = self.source.source.def_id(); let (mut rvalue, promoted_op) = { let promoted = &mut self.promoted; - let promoted_id = Promoted::new(next_promoted_id); let tcx = self.tcx; let mut promoted_operand = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span); let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def)); - let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) }; + let uneval = + mir::UnevaluatedConst { def, args, promoted: Some(next_promoted_index) }; ConstOperand { span, user_ty: None, const_: Const::Unevaluated(uneval, ty) } }; @@ -1034,7 +1038,7 @@ fn promote_candidates<'tcx>( required_consts: Vec::new(), }; - let mut promoted = promoter.promote_candidate(candidate, promotions.len()); + let mut promoted = promoter.promote_candidate(candidate, promotions.next_index()); promoted.source.promoted = Some(promotions.next_index()); promotions.push(promoted); } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 4edc293ad807..d56b0e5847e5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -355,7 +355,7 @@ where // exist at all (see the FIXME at the start of this method), we have to deal with // them for now. delegate.instantiate_canonical_var_with_infer(info, span, |idx| { - ty::UniverseIndex::from(prev_universe.index() + idx.index()) + prev_universe + idx.index() }) } else if info.is_existential() { // As an optimization we sometimes avoid creating a new inference variable here. diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 06eb76c30c5f..7054bbf468b9 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -578,8 +578,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { where F: FnMut(Variable) -> bool, { - for var_idx in 0..self.ir.var_kinds.len() { - let var = Variable::from(var_idx); + for var in self.ir.var_kinds.indices() { if test(var) { write!(wr, " {var:?}")?; } @@ -609,8 +608,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!( "^^ liveness computation results for body {} (entry={:?})", { - for ln_idx in 0..self.ir.lnks.len() { - debug!("{:?}", self.ln_str(LiveNode::from(ln_idx))); + for ln_idx in self.ir.lnks.indices() { + debug!("{:?}", self.ln_str(ln_idx)); } hir_id }, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a7170edb9867..13de81684884 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1948,7 +1948,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.record_lifetime_res( anchor_id, - LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) }, + LifetimeRes::ElidedAnchor { start: id, end: id + 1 }, LifetimeElisionCandidate::Ignore, ); self.resolve_anonymous_lifetime(<, anchor_id, true); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index de337710b5ef..8ac8dc67fbd8 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -643,7 +643,7 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( ) -> GenericArgsRef<'tcx> { struct ReplaceParamAndInferWithPlaceholder<'tcx> { tcx: TyCtxt<'tcx>, - idx: u32, + idx: ty::BoundVar, } impl<'tcx> TypeFolder> for ReplaceParamAndInferWithPlaceholder<'tcx> { @@ -653,19 +653,13 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if let ty::Infer(_) = t.kind() { - let idx = { - let idx = self.idx; - self.idx += 1; - idx - }; + let idx = self.idx; + self.idx += 1; Ty::new_placeholder( self.tcx, ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, - bound: ty::BoundTy { - var: ty::BoundVar::from_u32(idx), - kind: ty::BoundTyKind::Anon, - }, + bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon }, }, ) } else { @@ -675,16 +669,11 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { if let ty::ConstKind::Infer(_) = c.kind() { + let idx = self.idx; + self.idx += 1; ty::Const::new_placeholder( self.tcx, - ty::PlaceholderConst { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundVar::from_u32({ - let idx = self.idx; - self.idx += 1; - idx - }), - }, + ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, bound: idx }, ) } else { c.super_fold_with(self) @@ -692,7 +681,7 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( } } - args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 }) + args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: ty::BoundVar::ZERO }) } /// Normalizes the predicates and checks whether they hold in an empty environment. If this From 3df7882272c96a19bcff6269e4f9f0aba34b6c6f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Apr 2025 16:49:56 +0000 Subject: [PATCH 144/222] Normalize ADT fields in find_tails_for_unsizing --- compiler/rustc_monomorphize/src/collector.rs | 65 ++++++++++--------- tests/crashes/74451.rs | 42 ------------ .../codegen-smart-pointer-with-alias.rs | 32 +++++++++ 3 files changed, 65 insertions(+), 74 deletions(-) delete mode 100644 tests/crashes/74451.rs create mode 100644 tests/ui/coercion/codegen-smart-pointer-with-alias.rs diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1dbb35f92c2c..d1d0f7cacaee 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -688,7 +688,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let target_ty = self.monomorphize(target_ty); let source_ty = self.monomorphize(source_ty); let (source_ty, target_ty) = - find_vtable_types_for_unsizing(self.tcx.at(span), source_ty, target_ty); + find_tails_for_unsizing(self.tcx.at(span), source_ty, target_ty); // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. @@ -1037,36 +1037,35 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> /// /// Finally, there is also the case of custom unsizing coercions, e.g., for /// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'tcx>( +fn find_tails_for_unsizing<'tcx>( tcx: TyCtxtAt<'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>, ) -> (Ty<'tcx>, Ty<'tcx>) { - let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { - let typing_env = ty::TypingEnv::fully_monomorphized(); - if tcx.type_has_metadata(inner_source, typing_env) { - (inner_source, inner_target) - } else { - tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env) - } - }; + let typing_env = ty::TypingEnv::fully_monomorphized(); + debug_assert!(!source_ty.has_param(), "{source_ty} should be fully monomorphic"); + debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic"); match (source_ty.kind(), target_ty.kind()) { - (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _)) - | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b), + ( + &ty::Ref(_, source_pointee, _), + &ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _), + ) + | (&ty::RawPtr(source_pointee, _), &ty::RawPtr(target_pointee, _)) => { + tcx.struct_lockstep_tails_for_codegen(source_pointee, target_pointee, typing_env) + } + + // `Box` could go through the ADT code below, b/c it'll unpeel to `Unique`, + // and eventually bottom out in a raw ref, but we can micro-optimize it here. (_, _) if let Some(source_boxed) = source_ty.boxed_ty() && let Some(target_boxed) = target_ty.boxed_ty() => { - ptr_vtable(source_boxed, target_boxed) + tcx.struct_lockstep_tails_for_codegen(source_boxed, target_boxed, typing_env) } - // T as dyn* Trait - (_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty), - (&ty::Adt(source_adt_def, source_args), &ty::Adt(target_adt_def, target_args)) => { assert_eq!(source_adt_def, target_adt_def); - let CustomCoerceUnsized::Struct(coerce_index) = match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) { Ok(ccu) => ccu, @@ -1075,21 +1074,23 @@ fn find_vtable_types_for_unsizing<'tcx>( return (e, e); } }; - - let source_fields = &source_adt_def.non_enum_variant().fields; - let target_fields = &target_adt_def.non_enum_variant().fields; - - assert!( - coerce_index.index() < source_fields.len() - && source_fields.len() == target_fields.len() - ); - - find_vtable_types_for_unsizing( - tcx, - source_fields[coerce_index].ty(*tcx, source_args), - target_fields[coerce_index].ty(*tcx, target_args), - ) + let coerce_field = &source_adt_def.non_enum_variant().fields[coerce_index]; + // We're getting a possibly unnormalized type, so normalize it. + let source_field = + tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, source_args)); + let target_field = + tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, target_args)); + find_tails_for_unsizing(tcx, source_field, target_field) } + + // `T` as `dyn* Trait` unsizes *directly*. + // + // FIXME(dyn_star): This case is a bit awkward, b/c we're not really computing + // a tail here. We probably should handle this separately in the *caller* of + // this function, rather than returning something that is semantically different + // than what we return above. + (_, &ty::Dynamic(_, _, ty::DynStar)) => (source_ty, target_ty), + _ => bug!( "find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", source_ty, @@ -1308,7 +1309,7 @@ fn visit_mentioned_item<'tcx>( } MentionedItem::UnsizeCast { source_ty, target_ty } => { let (source_ty, target_ty) = - find_vtable_types_for_unsizing(tcx.at(span), source_ty, target_ty); + find_tails_for_unsizing(tcx.at(span), source_ty, target_ty); // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. diff --git a/tests/crashes/74451.rs b/tests/crashes/74451.rs deleted file mode 100644 index 8f9369946789..000000000000 --- a/tests/crashes/74451.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@ known-bug: #74451 -//@ compile-flags: -Copt-level=0 - -#![feature(specialization)] -#![feature(unsize, coerce_unsized)] -#![allow(incomplete_features)] -#![crate_type = "lib"] - -use std::ops::CoerceUnsized; - -pub struct SmartassPtr(A::Data); - -pub trait Smartass { - type Data; - type Data2: CoerceUnsized<*const [u8]>; -} - -pub trait MaybeObjectSafe {} - -impl MaybeObjectSafe for () {} - -impl Smartass for T { - type Data = ::Data2; - default type Data2 = *const [u8; 0]; -} - -impl Smartass for () { - type Data2 = *const [u8; 1]; -} - -impl Smartass for dyn MaybeObjectSafe { - type Data = *const [u8]; - type Data2 = *const [u8; 0]; -} - -impl CoerceUnsized> for SmartassPtr - where ::Data: std::ops::CoerceUnsized<::Data> -{} - -pub fn conv(s: SmartassPtr<()>) -> SmartassPtr { - s // This shouldn't coerce -} diff --git a/tests/ui/coercion/codegen-smart-pointer-with-alias.rs b/tests/ui/coercion/codegen-smart-pointer-with-alias.rs new file mode 100644 index 000000000000..a68952bb70aa --- /dev/null +++ b/tests/ui/coercion/codegen-smart-pointer-with-alias.rs @@ -0,0 +1,32 @@ +//@ build-pass + +// Regression test for . + +// Make sure that the unsize coercion we collect in mono for `Signal -> Signal` +// doesn't choke on the fact that the inner unsized field of `Signal` is a (trivial) alias. +// This exercises a normalize call that is necessary since we're getting a type from the type +// system, which isn't guaranteed to be normalized after substitution. + +#![feature(coerce_unsized)] + +use std::ops::CoerceUnsized; + +trait Mirror { + type Assoc: ?Sized; +} +impl Mirror for T { + type Assoc = T; +} + +trait Any {} +impl Any for T {} + +struct Signal<'a, T: ?Sized>(<&'a T as Mirror>::Assoc); + +// This `CoerceUnsized` impl isn't special; it's a bit more restricted than we'd see in the wild, +// but this ICE also reproduces if we were to make it general over `Signal -> Signal`. +impl<'a> CoerceUnsized> for Signal<'a, i32> {} + +fn main() { + Signal(&1i32) as Signal; +} From 188d44dd6e4949606e31c8009dffa4773ea25214 Mon Sep 17 00:00:00 2001 From: 0x79de <0x79de@gmail.com> Date: Mon, 14 Apr 2025 21:25:48 +0300 Subject: [PATCH 145/222] Fix: Map EOPNOTSUPP to ErrorKind::Unsupported on Unix This change maps the EOPNOTSUPP errno value (95) to std::io::ErrorKind::Unsupported in the decode_error_kind function for Unix platforms. Previously, it was incorrectly mapped to ErrorKind::Uncategorized. Fixes #139803 --- library/std/src/sys/pal/unix/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index f8733eb61198..3a790d9c868c 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -274,6 +274,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ETXTBSY => ExecutableFileBusy, libc::EXDEV => CrossesDevices, libc::EINPROGRESS => InProgress, + libc::EOPNOTSUPP => Unsupported, libc::EACCES | libc::EPERM => PermissionDenied, From cb22c1d5e949b64aafb99994befde4bd25a421e9 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 14 Apr 2025 14:36:53 +0200 Subject: [PATCH 146/222] Allow (but don't require) `#[unsafe(naked)]` so that `compiler-builtins` can upgrade to it --- compiler/rustc_parse/src/validate_attr.rs | 6 +++ tests/ui/asm/naked-functions.rs | 56 +++++++++++------------ 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 6a1c2af48ed5..b518fca7a658 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -194,6 +194,12 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: } } } else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { + // Allow (but don't require) `#[unsafe(naked)]` so that compiler-builtins can upgrade to it. + // FIXME(#139797): remove this special case when compiler-builtins has upgraded. + if attr.has_name(sym::naked) { + return; + } + psess.dcx().emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: attr_item.path.clone(), diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 5bf2e2a3abd0..8ba0eecb7b5c 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -8,7 +8,7 @@ use std::arch::{asm, naked_asm}; -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn inline_asm_macro() { asm!("", options(raw)); //~^ERROR the `asm!` macro is not allowed in naked functions @@ -20,7 +20,7 @@ pub struct P { y: u16, } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn patterns( mut a: u32, //~^ ERROR patterns not allowed in naked function parameters @@ -34,27 +34,27 @@ pub unsafe extern "C" fn patterns( naked_asm!("") } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn inc(a: u32) -> u32 { //~^ ERROR naked functions must contain a single `naked_asm!` invocation a + 1 //~^ ERROR referencing function parameters is not allowed in naked functions } -#[naked] +#[unsafe(naked)] #[allow(asm_sub_register)] pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { naked_asm!("/* {0} */", in(reg) a) //~^ ERROR the `in` operand cannot be used with `naked_asm!` } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { //~^ ERROR naked functions must contain a single `naked_asm!` invocation (|| a + 1)() } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn unsupported_operands() { //~^ ERROR naked functions must contain a single `naked_asm!` invocation let mut a = 0usize; @@ -76,12 +76,12 @@ pub unsafe extern "C" fn unsupported_operands() { ); } -#[naked] +#[unsafe(naked)] pub extern "C" fn missing_assembly() { //~^ ERROR naked functions must contain a single `naked_asm!` invocation } -#[naked] +#[unsafe(naked)] pub extern "C" fn too_many_asm_blocks() { //~^ ERROR naked functions must contain a single `naked_asm!` invocation unsafe { @@ -92,7 +92,7 @@ pub extern "C" fn too_many_asm_blocks() { } pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { - #[naked] + #[unsafe(naked)] pub extern "C" fn inner(y: usize) -> usize { //~^ ERROR naked functions must contain a single `naked_asm!` invocation *&y @@ -101,14 +101,14 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { inner } -#[naked] +#[unsafe(naked)] unsafe extern "C" fn invalid_options() { naked_asm!("", options(nomem, preserves_flags)); //~^ ERROR the `nomem` option cannot be used with `naked_asm!` //~| ERROR the `preserves_flags` option cannot be used with `naked_asm!` } -#[naked] +#[unsafe(naked)] unsafe extern "C" fn invalid_options_continued() { naked_asm!("", options(readonly, nostack), options(pure)); //~^ ERROR the `readonly` option cannot be used with `naked_asm!` @@ -116,20 +116,20 @@ unsafe extern "C" fn invalid_options_continued() { //~| ERROR the `pure` option cannot be used with `naked_asm!` } -#[naked] +#[unsafe(naked)] unsafe extern "C" fn invalid_may_unwind() { naked_asm!("", options(may_unwind)); //~^ ERROR the `may_unwind` option cannot be used with `naked_asm!` } -#[naked] +#[unsafe(naked)] pub extern "C" fn valid_a() -> T { unsafe { naked_asm!(""); } } -#[naked] +#[unsafe(naked)] pub extern "C" fn valid_b() { unsafe { { @@ -140,32 +140,32 @@ pub extern "C" fn valid_b() { } } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn valid_c() { naked_asm!(""); } #[cfg(target_arch = "x86_64")] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn valid_att_syntax() { naked_asm!("", options(att_syntax)); } -#[naked] -#[naked] +#[unsafe(naked)] +#[unsafe(naked)] pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { compile_error!("this is a user specified error") //~^ ERROR this is a user specified error } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { compile_error!("this is a user specified error"); //~^ ERROR this is a user specified error naked_asm!("") } -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { naked_asm!(invalid_syntax) //~^ ERROR asm template must be a string literal @@ -173,7 +173,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { #[cfg(target_arch = "x86_64")] #[cfg_attr(target_pointer_width = "64", no_mangle)] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_cfg_attributes() { naked_asm!("", options(att_syntax)); } @@ -182,20 +182,20 @@ pub unsafe extern "C" fn compatible_cfg_attributes() { #[warn(dead_code)] #[deny(dead_code)] #[forbid(dead_code)] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_diagnostic_attributes() { naked_asm!("", options(raw)); } #[deprecated = "test"] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_deprecated_attributes() { naked_asm!("", options(raw)); } #[cfg(target_arch = "x86_64")] #[must_use] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { naked_asm!( " @@ -207,13 +207,13 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { #[export_name = "exported_function_name"] #[link_section = ".custom_section"] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_ffi_attributes_1() { naked_asm!("", options(raw)); } #[cold] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_codegen_attributes() { naked_asm!("", options(raw)); } @@ -222,13 +222,13 @@ pub unsafe extern "C" fn compatible_codegen_attributes() { /// a doc comment // a normal comment #[doc(alias = "ADocAlias")] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_doc_attributes() { naked_asm!("", options(raw)); } #[linkage = "external"] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn compatible_linkage() { naked_asm!("", options(raw)); } From 1d757833c6aa126e468275c1cd7285dee53a1de6 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 14 Apr 2025 18:35:51 +0000 Subject: [PATCH 147/222] Remove safe remove --- compiler/rustc_incremental/src/persist/fs.rs | 34 ++++---------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 76a1ff3cf382..f0d24d27e85a 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -290,7 +290,7 @@ pub(crate) fn prepare_session_directory(sess: &Session, crate_name: Symbol) { // Try to remove the session directory we just allocated. We don't // know if there's any garbage in it from the failed copy action. - if let Err(err) = safe_remove_dir_all(&session_dir) { + if let Err(err) = std_fs::remove_dir_all(&session_dir) { sess.dcx().emit_warn(errors::DeletePartial { path: &session_dir, err }); } @@ -324,7 +324,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option) { incr_comp_session_dir.display() ); - if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) { + if let Err(err) = std_fs::remove_dir_all(&*incr_comp_session_dir) { sess.dcx().emit_warn(errors::DeleteFull { path: &incr_comp_session_dir, err }); } @@ -715,7 +715,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result< for directory_name in session_directories { if !lock_file_to_session_dir.items().any(|(_, dir)| *dir == directory_name) { let path = crate_directory.join(directory_name); - if let Err(err) = safe_remove_dir_all(&path) { + if let Err(err) = std_fs::remove_dir_all(&path) { sess.dcx().emit_warn(errors::InvalidGcFailed { path: &path, err }); } } @@ -821,7 +821,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result< all_except_most_recent(deletion_candidates).into_items().all(|(path, lock)| { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); - if let Err(err) = safe_remove_dir_all(&path) { + if let Err(err) = std_fs::remove_dir_all(&path) { sess.dcx().emit_warn(errors::FinalizedGcFailed { path: &path, err }); } else { delete_session_dir_lock_file(sess, &lock_file_path(&path)); @@ -839,7 +839,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result< fn delete_old(sess: &Session, path: &Path) { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); - if let Err(err) = safe_remove_dir_all(path) { + if let Err(err) = std_fs::remove_dir_all(path) { sess.dcx().emit_warn(errors::SessionGcFailed { path, err }); } else { delete_session_dir_lock_file(sess, &lock_file_path(path)); @@ -862,30 +862,8 @@ fn all_except_most_recent( } } -/// Since paths of artifacts within session directories can get quite long, we -/// need to support deleting files with very long paths. The regular -/// WinApi functions only support paths up to 260 characters, however. In order -/// to circumvent this limitation, we canonicalize the path of the directory -/// before passing it to std::fs::remove_dir_all(). This will convert the path -/// into the '\\?\' format, which supports much longer paths. -fn safe_remove_dir_all(p: &Path) -> io::Result<()> { - let canonicalized = match try_canonicalize(p) { - Ok(canonicalized) => canonicalized, - Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), - Err(err) => return Err(err), - }; - - std_fs::remove_dir_all(canonicalized) -} - fn safe_remove_file(p: &Path) -> io::Result<()> { - let canonicalized = match try_canonicalize(p) { - Ok(canonicalized) => canonicalized, - Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), - Err(err) => return Err(err), - }; - - match std_fs::remove_file(canonicalized) { + match std_fs::remove_file(p) { Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()), result => result, } From b26f3d4347ca589305a19d10c6e651b071849716 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 11 Apr 2025 16:50:20 +1000 Subject: [PATCH 148/222] Move `opt_rpitit_info` field to `hir::AssocKind::Type`. From `hir::AssocItem`. --- .../rustc_hir_analysis/src/check/check.rs | 6 ++-- .../src/check/compare_impl_item.rs | 19 ++++++----- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 6 ++-- .../src/collect/type_of/opaque.rs | 2 +- .../errors/wrong_number_of_generic_args.rs | 4 +-- .../src/hir_ty_lowering/dyn_compatibility.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 2 +- .../rustc_hir_analysis/src/impl_wf_check.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 12 ++----- compiler/rustc_metadata/src/rmeta/decoder.rs | 12 ++++--- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 +-- compiler/rustc_middle/src/ty/assoc.rs | 34 +++++++++++-------- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 6 ++-- compiler/rustc_middle/src/ty/sty.rs | 2 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 2 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 7 ++-- .../rustc_smir/src/stable_mir/mir/pretty.rs | 2 +- compiler/rustc_smir/src/stable_mir/ty.rs | 18 +++++----- .../src/error_reporting/infer/mod.rs | 8 +++-- .../src/error_reporting/traits/ambiguity.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 2 +- .../src/traits/dyn_compatibility.rs | 4 +-- .../src/traits/select/confirmation.rs | 4 +-- compiler/rustc_ty_utils/src/assoc.rs | 24 +++++++------ src/librustdoc/clean/mod.rs | 2 +- .../src/implied_bounds_in_impls.rs | 2 +- 28 files changed, 103 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index c2706a1d4013..12c36e0f4c26 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -449,7 +449,7 @@ fn best_definition_site_of_opaque<'tcx>( return Some(span); } } - ty::AssocKind::Type => {} + ty::AssocKind::Type { .. } => {} } } @@ -740,7 +740,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { for &assoc_item in assoc_items.in_definition_order() { match assoc_item.kind { - ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { + ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => { let trait_args = GenericArgs::identity_for_item(tcx, def_id); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, @@ -953,7 +953,7 @@ fn check_impl_items_against_trait<'tcx>( ); } ty::AssocKind::Const => {} - ty::AssocKind::Type => {} + ty::AssocKind::Type { .. } => {} } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 7dfdf1ae237d..d208aa71971e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -44,7 +44,7 @@ pub(super) fn compare_impl_item( match impl_item.kind { ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref), - ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref), + ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref), ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref), } } @@ -1703,7 +1703,7 @@ fn compare_generic_param_kinds<'tcx>( trait_item: ty::AssocItem, delay: bool, ) -> Result<(), ErrorGuaranteed> { - assert_eq!(impl_item.kind, trait_item.kind); + assert_eq!(impl_item.as_tag(), trait_item.as_tag()); let ty_const_params_of = |def_id| { tcx.generics_of(def_id).own_params.iter().filter(|param| { @@ -2235,16 +2235,19 @@ fn param_env_with_gat_bounds<'tcx>( // of the RPITITs associated with the same body. This is because checking // the item bounds of RPITITs often involves nested RPITITs having to prove // bounds about themselves. - let impl_tys_to_install = match impl_ty.opt_rpitit_info { - None => vec![impl_ty], - Some( - ty::ImplTraitInTraitData::Impl { fn_def_id } - | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, - ) => tcx + let impl_tys_to_install = match impl_ty.kind { + ty::AssocKind::Type { + opt_rpitit_info: + Some( + ty::ImplTraitInTraitData::Impl { fn_def_id } + | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, + ), + } => tcx .associated_types_for_impl_traits_in_associated_fn(fn_def_id) .iter() .map(|def_id| tcx.associated_item(*def_id)) .collect(), + _ => vec![impl_ty], }; for impl_ty in impl_tys_to_install { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 523db9440a41..ec934b1f620d 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -499,7 +499,7 @@ fn suggestion_signature<'tcx>( tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), assoc, ), - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { let (generics, where_clauses) = bounds_from_generic_predicates( tcx, tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index af7830fd6642..c6c370c4a846 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -408,7 +408,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { let gat_def_id = gat_item.def_id.expect_local(); let gat_item = tcx.associated_item(gat_def_id); // If this item is not an assoc ty, or has no args, then it's not a GAT - if gat_item.kind != ty::AssocKind::Type { + if !gat_item.is_type() { continue; } let gat_generics = tcx.generics_of(gat_def_id); @@ -453,7 +453,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { ) } // In our example, this corresponds to the `Iter` and `Item` associated types - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { // If our associated item is a GAT with missing bounds, add them to // the param-env here. This allows this GAT to propagate missing bounds // to other GATs. @@ -1101,7 +1101,7 @@ fn check_associated_item( ); check_method_receiver(wfcx, hir_sig, item, self_ty) } - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { if let ty::AssocItemContainer::Trait = item.container { check_associated_type_bounds(wfcx, item, span) } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index f06636447194..653adc6b3ba5 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -36,7 +36,7 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type( locator.check(assoc_id.expect_local()) } // Associated types don't have bodies, so they can't constrain hidden types - ty::AssocKind::Type => {} + ty::AssocKind::Type { .. } => {} } } diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 610b293a114e..70d60bfcf2d2 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -4,7 +4,7 @@ use GenericArgsInfo::*; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize}; use rustc_hir as hir; -use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; +use rustc_middle::ty::{self as ty, AssocItems, TyCtxt}; use rustc_span::def_id::DefId; use tracing::debug; @@ -486,7 +486,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let items: &AssocItems = self.tcx.associated_items(self.def_id); items .in_definition_order() - .filter(|item| item.kind == AssocKind::Type) + .filter(|item| item.is_type()) .filter(|item| { !self .gen_args diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index e64cd8ec302c..2e39beed8ae3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -201,7 +201,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.associated_items(pred.trait_ref.def_id) .in_definition_order() // We only care about associated types. - .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.is_type()) // No RPITITs -- they're not dyn-compatible for now. .filter(|item| !item.is_impl_trait_in_trait()) // If the associated type has a `where Self: Sized` bound, 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 0fb406d99080..0394dd20e28c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1733,7 +1733,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .any(|i| { i.kind.namespace() == Namespace::TypeNS && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident - && matches!(i.kind, ty::AssocKind::Type) + && i.is_type() }) // Consider only accessible traits && tcx.visibility(*trait_def_id) diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 1ab36ce1dcb9..127ca846b9fe 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -112,7 +112,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained( .flat_map(|def_id| { let item = tcx.associated_item(def_id); match item.kind { - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { if item.defaultness(tcx).has_value() { cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true) } else { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index d5d85c812b2d..07cb8c2a5bbb 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1671,15 +1671,7 @@ impl<'tcx> Pick<'tcx> { /// Do not use for type checking. pub(crate) fn differs_from(&self, other: &Self) -> bool { let Self { - item: - AssocItem { - def_id, - name: _, - kind: _, - container: _, - trait_item_def_id: _, - opt_rpitit_info: _, - }, + item: AssocItem { def_id, name: _, kind: _, container: _, trait_item_def_id: _ }, kind: _, import_ids: _, autoderefs: _, @@ -2253,7 +2245,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { match self.mode { Mode::MethodCall => item.is_method(), Mode::Path => match item.kind { - ty::AssocKind::Type => false, + ty::AssocKind::Type { .. } => false, ty::AssocKind::Fn { .. } | ty::AssocKind::Const => true, }, } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index cc3b2a241e4a..3cbe09280f69 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1342,12 +1342,17 @@ impl<'a> CrateMetadataRef<'a> { DefKind::AssocFn => { ty::AssocKind::Fn { has_self: self.get_fn_has_self_parameter(id, sess) } } - DefKind::AssocTy => ty::AssocKind::Type, + DefKind::AssocTy => ty::AssocKind::Type { + opt_rpitit_info: self + .root + .tables + .opt_rpitit_info + .get(self, id) + .map(|d| d.decode(self)), + }, _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; let container = self.root.tables.assoc_container.get(self, id).unwrap(); - let opt_rpitit_info = - self.root.tables.opt_rpitit_info.get(self, id).map(|d| d.decode(self)); ty::AssocItem { name, @@ -1355,7 +1360,6 @@ impl<'a> CrateMetadataRef<'a> { def_id: self.local_def_id(id), trait_item_def_id: self.get_trait_item_def_id(id), container, - opt_rpitit_info, } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index cc9da16ffdbb..b900100c3c01 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1691,7 +1691,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match item.container { AssocItemContainer::Trait => { - if let ty::AssocKind::Type = item.kind { + if item.is_type() { self.encode_explicit_item_bounds(def_id); self.encode_explicit_item_self_bounds(def_id); if tcx.is_conditionally_const(def_id) { @@ -1706,7 +1706,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } - if let Some(rpitit_info) = item.opt_rpitit_info { + if let ty::AssocKind::Type { opt_rpitit_info: Some(rpitit_info) } = item.kind { record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info); if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) { record_array!( diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 3c1e5ed9e114..eac8f04f84f9 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -25,11 +25,6 @@ pub struct AssocItem { /// If this is an item in an impl of a trait then this is the `DefId` of /// the associated item on the trait that this implements. pub trait_item_def_id: Option, - - /// `Some` if the associated item (an associated type) comes from the - /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` - /// provides additional information about its source. - pub opt_rpitit_info: Option, } impl AssocItem { @@ -81,7 +76,7 @@ impl AssocItem { // regions just fine, showing `fn(&MyType)`. tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string() } - ty::AssocKind::Type => format!("type {};", self.name), + ty::AssocKind::Type { .. } => format!("type {};", self.name), ty::AssocKind::Const => { format!( "const {}: {:?};", @@ -97,10 +92,14 @@ impl AssocItem { ty::AssocKind::Const => "associated const", ty::AssocKind::Fn { has_self: true } => "method", ty::AssocKind::Fn { has_self: false } => "associated function", - ty::AssocKind::Type => "associated type", + ty::AssocKind::Type { .. } => "associated type", } } + pub fn is_type(&self) -> bool { + matches!(self.kind, ty::AssocKind::Type { .. }) + } + pub fn is_fn(&self) -> bool { matches!(self.kind, ty::AssocKind::Fn { .. }) } @@ -113,12 +112,12 @@ impl AssocItem { match self.kind { AssocKind::Const => AssocTag::Const, AssocKind::Fn { .. } => AssocTag::Fn, - AssocKind::Type => AssocTag::Type, + AssocKind::Type { .. } => AssocTag::Type, } } pub fn is_impl_trait_in_trait(&self) -> bool { - self.opt_rpitit_info.is_some() + matches!(self.kind, AssocKind::Type { opt_rpitit_info: Some(_) }) } /// Returns true if: @@ -143,14 +142,21 @@ impl AssocItem { #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] pub enum AssocKind { Const, - Fn { has_self: bool }, - Type, + Fn { + has_self: bool, + }, + Type { + /// `Some` if the associated type comes from an RPITIT. The + /// `ImplTraitInTraitData` provides additional information about its + /// source. + opt_rpitit_info: Option, + }, } impl AssocKind { pub fn namespace(&self) -> Namespace { match *self { - ty::AssocKind::Type => Namespace::TypeNS, + ty::AssocKind::Type { .. } => Namespace::TypeNS, ty::AssocKind::Const | ty::AssocKind::Fn { .. } => Namespace::ValueNS, } } @@ -159,7 +165,7 @@ impl AssocKind { match self { AssocKind::Const => DefKind::AssocConst, AssocKind::Fn { .. } => DefKind::AssocFn, - AssocKind::Type => DefKind::AssocTy, + AssocKind::Type { .. } => DefKind::AssocTy, } } } @@ -170,7 +176,7 @@ impl std::fmt::Display for AssocKind { AssocKind::Fn { has_self: true } => write!(f, "method"), AssocKind::Fn { has_self: false } => write!(f, "associated function"), AssocKind::Const => write!(f, "associated const"), - AssocKind::Type => write!(f, "associated type"), + AssocKind::Type { .. } => write!(f, "associated type"), } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index abf6cbbcd877..fb25b8e130b5 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -464,7 +464,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator { self.associated_items(def_id) .in_definition_order() - .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) + .filter(|assoc_item| assoc_item.is_type()) .map(|assoc_item| assoc_item.def_id) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 30c889c39d93..395d2ec48142 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1610,8 +1610,10 @@ impl<'tcx> TyCtxt<'tcx> { /// return-position `impl Trait` from a trait, then provide the source info /// about where that RPITIT came from. pub fn opt_rpitit_info(self, def_id: DefId) -> Option { - if let DefKind::AssocTy = self.def_kind(def_id) { - self.associated_item(def_id).opt_rpitit_info + if let DefKind::AssocTy = self.def_kind(def_id) + && let AssocKind::Type { opt_rpitit_info } = self.associated_item(def_id).kind + { + opt_rpitit_info } else { None } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 27ee363f1c14..bb178fe42538 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -734,7 +734,7 @@ impl<'tcx> Ty<'tcx> { .map(|principal| { tcx.associated_items(principal.def_id()) .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.is_type()) .filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .count() 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 718b9a4fa3b8..d2917478e4e4 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 @@ -240,7 +240,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc .flat_map(|super_poly_trait_ref| { tcx.associated_items(super_poly_trait_ref.def_id()) .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.is_type()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .map(move |assoc_ty| { super_poly_trait_ref.map_bound(|super_trait_ref| { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 94f3be9fef73..55f698b8f211 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -894,12 +894,14 @@ impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule { impl<'tcx> Stable<'tcx> for ty::AssocKind { type T = stable_mir::ty::AssocKind; - fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::AssocKind; match *self { ty::AssocKind::Const => AssocKind::Const, ty::AssocKind::Fn { has_self } => AssocKind::Fn { has_self }, - ty::AssocKind::Type => AssocKind::Type, + ty::AssocKind::Type { opt_rpitit_info } => AssocKind::Type { + opt_rpitit_info: opt_rpitit_info.map(|rpitit| rpitit.stable(tables)), + }, } } } @@ -926,7 +928,6 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem { kind: self.kind.stable(tables), container: self.container.stable(tables), trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)), - opt_rpitit_info: self.opt_rpitit_info.map(|rpitit| rpitit.stable(tables)), } } } diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs index 60d9e122940b..9fa97763907f 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs @@ -25,7 +25,7 @@ impl Display for AssocKind { AssocKind::Fn { has_self: true } => write!(f, "method"), AssocKind::Fn { has_self: false } => write!(f, "associated function"), AssocKind::Const => write!(f, "associated const"), - AssocKind::Type => write!(f, "associated type"), + AssocKind::Type { .. } => write!(f, "associated type"), } } } diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 63ce756162a5..6eac0885d763 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1585,18 +1585,20 @@ pub struct AssocItem { /// If this is an item in an impl of a trait then this is the `DefId` of /// the associated item on the trait that this implements. pub trait_item_def_id: Option, - - /// `Some` if the associated item (an associated type) comes from the - /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` - /// provides additional information about its source. - pub opt_rpitit_info: Option, } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AssocKind { Const, - Fn { has_self: bool }, - Type, + Fn { + has_self: bool, + }, + Type { + /// `Some` if the associated type comes from an RPITIT. The + /// `ImplTraitInTraitData` provides additional information about its + /// source. + opt_rpitit_info: Option, + }, } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] @@ -1613,6 +1615,6 @@ pub enum ImplTraitInTraitData { impl AssocItem { pub fn is_impl_trait_in_trait(&self) -> bool { - self.opt_rpitit_info.is_some() + matches!(self.kind, AssocKind::Type { opt_rpitit_info: Some(_) }) } } 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 cbadb46c17d9..1c71fe028d4d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2337,7 +2337,7 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => { ObligationCauseFailureCode::MethodCompat { span, subdiags } } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => { ObligationCauseFailureCode::TypeCompat { span, subdiags } } ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { @@ -2401,7 +2401,7 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => { "method type is compatible with trait" } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => { "associated type is compatible with trait" } ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { @@ -2425,7 +2425,9 @@ impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => { "method_compat" } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat", + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => { + "type_compat" + } ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { "const_compat" } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index e3e1583a48fa..c4b0ca9cf8fc 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -352,7 +352,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::AssocKind::Fn { .. } => ("call", "function"), // This is already covered by E0223, but this following single match // arm doesn't hurt here. - ty::AssocKind::Type => ("refer to the", "type"), + ty::AssocKind::Type { .. } => ("refer to the", "type"), }; // Replace the more general E0283 with a more specific error 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 38aac8e70b52..084942cd8afd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2112,7 +2112,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_ref: DefId, ) { if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) { - if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind { + if let ty::AssocKind::Const | ty::AssocKind::Type { .. } = assoc_item.kind { err.note(format!( "{}s cannot be accessed directly on a `trait`, they can only be \ accessed through a specific `impl`", diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 76892db9ef7b..1ef16f34702e 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -188,7 +188,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span tcx.associated_items(trait_def_id) .in_definition_order() // We're only looking at associated type bounds - .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| item.is_type()) // Ignore GATs with `Self: Sized` .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied()) @@ -320,7 +320,7 @@ pub fn dyn_compatibility_violations_for_assoc_item( }) .collect(), // Associated types can only be dyn-compatible if they have `Self: Sized` bounds. - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() { vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)] } else { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 69e7b2a43ff9..d71d1e9ae0fa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -594,9 +594,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Associated types that require `Self: Sized` do not show up in the built-in // implementation of `Trait for dyn Trait`, and can be dropped here. .filter(|item| !tcx.generics_require_sized_self(item.def_id)) - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None }, - ) + .filter_map(|item| if item.is_type() { Some(item.def_id) } else { None }) .collect(); for assoc_type in assoc_types { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 79de071b6878..2275fbb97923 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -132,7 +132,7 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty let kind = match trait_item_ref.kind { hir::AssocItemKind::Const => ty::AssocKind::Const, hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { has_self }, - hir::AssocItemKind::Type => ty::AssocKind::Type, + hir::AssocItemKind::Type => ty::AssocKind::Type { opt_rpitit_info: None }, }; ty::AssocItem { @@ -141,7 +141,6 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty def_id: owner_id.to_def_id(), trait_item_def_id: Some(owner_id.to_def_id()), container: ty::AssocItemContainer::Trait, - opt_rpitit_info: None, } } @@ -150,7 +149,7 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A let kind = match impl_item_ref.kind { hir::AssocItemKind::Const => ty::AssocKind::Const, hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { has_self }, - hir::AssocItemKind::Type => ty::AssocKind::Type, + hir::AssocItemKind::Type => ty::AssocKind::Type { opt_rpitit_info: None }, }; ty::AssocItem { @@ -159,7 +158,6 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A def_id: def_id.to_def_id(), trait_item_def_id: impl_item_ref.trait_item_def_id, container: ty::AssocItemContainer::Impl, - opt_rpitit_info: None, } } @@ -263,14 +261,15 @@ fn associated_type_for_impl_trait_in_trait( trait_assoc_ty.associated_item(ty::AssocItem { name: kw::Empty, - kind: ty::AssocKind::Type, + kind: ty::AssocKind::Type { + opt_rpitit_info: Some(ImplTraitInTraitData::Trait { + fn_def_id: fn_def_id.to_def_id(), + opaque_def_id: opaque_ty_def_id.to_def_id(), + }), + }, def_id, trait_item_def_id: None, container: ty::AssocItemContainer::Trait, - opt_rpitit_info: Some(ImplTraitInTraitData::Trait { - fn_def_id: fn_def_id.to_def_id(), - opaque_def_id: opaque_ty_def_id.to_def_id(), - }), }); // Copy visility of the containing function. @@ -315,11 +314,14 @@ fn associated_type_for_impl_trait_in_impl( impl_assoc_ty.associated_item(ty::AssocItem { name: kw::Empty, - kind: ty::AssocKind::Type, + kind: ty::AssocKind::Type { + opt_rpitit_info: Some(ImplTraitInTraitData::Impl { + fn_def_id: impl_fn_def_id.to_def_id(), + }), + }, def_id, trait_item_def_id: Some(trait_assoc_def_id), container: ty::AssocItemContainer::Impl, - opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), }); // Copy visility of the containing function. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7cfd204aa137..74dbc7d06001 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1412,7 +1412,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo RequiredMethodItem(item) } } - ty::AssocKind::Type => { + ty::AssocKind::Type { .. } => { let my_name = assoc_item.name; fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index d02d9b2102bd..430f24111832 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -315,7 +315,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { assocs .filter_by_name_unhygienic(constraint.ident.name) .next() - .is_some_and(|assoc| assoc.kind == ty::AssocKind::Type) + .is_some_and(|assoc| assoc.is_type()) }) { emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound); From 89e93a51c81b521a9601b365e3325d31e44e9198 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 Apr 2025 15:39:47 +1000 Subject: [PATCH 149/222] Move two methods from `AssocKind` to `AssocItem`. Because all the other similar methods are on `AssocItem`. --- .../src/coherence/inherent_impls_overlap.rs | 2 +- .../src/hir_ty_lowering/lint.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_hir_typeck/src/method/mod.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 4 +-- .../rustc_hir_typeck/src/method/suggest.rs | 4 +-- compiler/rustc_middle/src/ty/assoc.rs | 33 +++++++++---------- .../src/error_reporting/traits/suggestions.rs | 2 +- .../passes/collect_intra_doc_links.rs | 4 +-- 9 files changed, 26 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index dc616576c9c1..cbfad1f6883e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -64,7 +64,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool { // Symbols and namespace match, compare hygienically. - item1.kind.namespace() == item2.kind.namespace() + item1.namespace() == item2.namespace() && item1.ident(self.tcx).normalize_to_macros_2_0() == item2.ident(self.tcx).normalize_to_macros_2_0() } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 8e62dce21913..49fd55b03a25 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -501,7 +501,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let names: Vec<_> = tcx .associated_items(trait_def_id) .in_definition_order() - .filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS) + .filter(|assoc| assoc.namespace() == Namespace::ValueNS) .map(|cand| cand.name) .collect(); if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) { 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 0394dd20e28c..7605c6c6a420 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1731,7 +1731,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.associated_items(*trait_def_id) .in_definition_order() .any(|i| { - i.kind.namespace() == Namespace::TypeNS + i.namespace() == Namespace::TypeNS && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident && i.is_type() }) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 39cb139a199e..1b67e2306aa7 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let def_kind = pick.item.kind.as_def_kind(); + let def_kind = pick.item.as_def_kind(); tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span)); Ok((def_kind, pick.item.def_id)) } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 07cb8c2a5bbb..c14b7823e370 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1583,7 +1583,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }, None, ) { - self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id))); + self.private_candidate.set(Some((pick.item.as_def_kind(), pick.item.def_id))); } } None @@ -1694,7 +1694,7 @@ impl<'tcx> Pick<'tcx> { if self.unstable_candidates.is_empty() { return; } - let def_kind = self.item.kind.as_def_kind(); + let def_kind = self.item.as_def_kind(); tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| { lint.primary_message(format!( "{} {} with this name may be added to the standard library in the future", diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 1b9771636a7d..962871ed2d11 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1819,7 +1819,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mode: Mode, ) { let tcx = self.tcx; - let def_kind = similar_candidate.kind.as_def_kind(); + let def_kind = similar_candidate.as_def_kind(); let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id); let msg = format!( "there is {an} {} `{}` with a similar name", @@ -4288,7 +4288,7 @@ fn print_disambiguation_help<'tcx>( && let SelfSource::MethodCall(receiver) = source && let Some(args) = args { - let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id); + let def_kind_descr = tcx.def_kind_descr(item.as_def_kind(), item.def_id); let item_name = item.ident(tcx); let first_input = tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0); diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index eac8f04f84f9..6138157d8362 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -96,6 +96,20 @@ impl AssocItem { } } + pub fn namespace(&self) -> Namespace { + match self.kind { + ty::AssocKind::Type { .. } => Namespace::TypeNS, + ty::AssocKind::Const | ty::AssocKind::Fn { .. } => Namespace::ValueNS, + } + } + + pub fn as_def_kind(&self) -> DefKind { + match self.kind { + AssocKind::Const => DefKind::AssocConst, + AssocKind::Fn { .. } => DefKind::AssocFn, + AssocKind::Type { .. } => DefKind::AssocTy, + } + } pub fn is_type(&self) -> bool { matches!(self.kind, ty::AssocKind::Type { .. }) } @@ -153,23 +167,6 @@ pub enum AssocKind { }, } -impl AssocKind { - pub fn namespace(&self) -> Namespace { - match *self { - ty::AssocKind::Type { .. } => Namespace::TypeNS, - ty::AssocKind::Const | ty::AssocKind::Fn { .. } => Namespace::ValueNS, - } - } - - pub fn as_def_kind(&self) -> DefKind { - match self { - AssocKind::Const => DefKind::AssocConst, - AssocKind::Fn { .. } => DefKind::AssocFn, - AssocKind::Type { .. } => DefKind::AssocTy, - } - } -} - impl std::fmt::Display for AssocKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -250,7 +247,7 @@ impl AssocItems { parent_def_id: DefId, ) -> Option<&ty::AssocItem> { self.filter_by_name_unhygienic(ident.name) - .filter(|item| item.kind.namespace() == ns) + .filter(|item| item.namespace() == ns) .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) } } 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 084942cd8afd..08b95b450583 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2116,7 +2116,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.note(format!( "{}s cannot be accessed directly on a `trait`, they can only be \ accessed through a specific `impl`", - self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id) + self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id) )); err.span_suggestion( span, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fdbb792d25da..297597b3deac 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -60,7 +60,7 @@ fn filter_assoc_items_by_name_and_namespace( ns: Namespace, ) -> impl Iterator { tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| { - item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) + item.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) }) } @@ -743,7 +743,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { ns, ) .map(|item| { - let res = Res::Def(item.kind.as_def_kind(), item.def_id); + let res = Res::Def(item.as_def_kind(), item.def_id); (res, item.def_id) }) .collect::>(), From 78599d83e7ab9f8cd4cbb9e982ddf12f258d6b18 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 Apr 2025 13:15:01 +1000 Subject: [PATCH 150/222] Move `name` field from `AssocItem` to `AssocKind` variants. To accurately reflect that RPITIT assoc items don't have a name. This avoids the use of `kw::Empty` to mean "no name", which is error prone. Helps with #137978. --- .../rustc_hir_analysis/src/check/check.rs | 4 +- .../src/check/compare_impl_item.rs | 32 +++--- compiler/rustc_hir_analysis/src/check/mod.rs | 10 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +- .../src/coherence/inherent_impls_overlap.rs | 8 +- .../src/collect/type_of/opaque.rs | 2 +- .../errors/wrong_number_of_generic_args.rs | 2 +- .../src/hir_ty_lowering/errors.rs | 38 ++++--- .../src/hir_ty_lowering/lint.rs | 2 +- .../rustc_hir_analysis/src/impl_wf_check.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 5 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 9 +- .../src/fn_ctxt/suggestions.rs | 11 +- compiler/rustc_hir_typeck/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 25 ++--- .../rustc_hir_typeck/src/method/suggest.rs | 27 +++-- compiler/rustc_hir_typeck/src/op.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 30 +++--- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/ty/assoc.rs | 101 ++++++++++++------ compiler/rustc_middle/src/ty/mod.rs | 5 +- compiler/rustc_middle/src/ty/print/pretty.rs | 6 +- .../src/check_undefined_transmutes.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 5 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 18 ++-- .../rustc_smir/src/stable_mir/mir/pretty.rs | 6 +- compiler/rustc_smir/src/stable_mir/ty.rs | 25 ++--- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- .../src/error_reporting/infer/mod.rs | 6 +- .../error_reporting/infer/note_and_explain.rs | 2 +- .../src/error_reporting/infer/region.rs | 2 +- .../src/error_reporting/traits/ambiguity.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 8 +- .../src/traits/dyn_compatibility.rs | 42 ++++---- .../src/traits/project.rs | 9 +- compiler/rustc_ty_utils/src/assoc.rs | 23 ++-- src/librustdoc/clean/mod.rs | 12 +-- src/librustdoc/clean/types.rs | 2 +- .../clippy_lints/src/assigning_clones.rs | 4 +- .../src/methods/double_ended_iterator_last.rs | 2 +- .../clippy_lints/src/missing_trait_methods.rs | 2 +- .../clippy_lints/src/same_name_method.rs | 2 +- .../src/unconditional_recursion.rs | 2 +- 43 files changed, 276 insertions(+), 231 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 12c36e0f4c26..4f338c6a19e6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -443,7 +443,7 @@ fn best_definition_site_of_opaque<'tcx>( let impl_def_id = tcx.local_parent(parent); for assoc in tcx.associated_items(impl_def_id).in_definition_order() { match assoc.kind { - ty::AssocKind::Const | ty::AssocKind::Fn { .. } => { + ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => { if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local()) { return Some(span); @@ -952,7 +952,7 @@ fn check_impl_items_against_trait<'tcx>( .instantiate_identity(), ); } - ty::AssocKind::Const => {} + ty::AssocKind::Const { .. } => {} ty::AssocKind::Type { .. } => {} } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index d208aa71971e..af26d2ee00ca 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -45,7 +45,9 @@ pub(super) fn compare_impl_item( match impl_item.kind { ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref), ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref), - ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref), + ty::AssocKind::Const { .. } => { + compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref) + } } } @@ -654,7 +656,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( cause.span, E0053, "method `{}` has an incompatible return type for trait", - trait_m.name + trait_m.name() ); infcx.err_ctxt().note_type_err( &mut diag, @@ -1032,7 +1034,7 @@ fn report_trait_method_mismatch<'tcx>( impl_err_span, E0053, "method `{}` has an incompatible type for trait", - trait_m.name + trait_m.name() ); match &terr { TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0) @@ -1266,14 +1268,14 @@ fn compare_self_type<'tcx>( impl_m_span, E0185, "method `{}` has a `{}` declaration in the impl, but not in the trait", - trait_m.name, + trait_m.name(), self_descr ); err.span_label(impl_m_span, format!("`{self_descr}` used in impl")); if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) { err.span_label(span, format!("trait method declared without `{self_descr}`")); } else { - err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name(), trait_m.signature(tcx)); } return Err(err.emit_unless(delay)); } @@ -1286,14 +1288,14 @@ fn compare_self_type<'tcx>( impl_m_span, E0186, "method `{}` has a `{}` declaration in the trait, but not in the impl", - trait_m.name, + trait_m.name(), self_descr ); err.span_label(impl_m_span, format!("expected `{self_descr}` in impl")); if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) { err.span_label(span, format!("`{self_descr}` used in trait")); } else { - err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name(), trait_m.signature(tcx)); } return Err(err.emit_unless(delay)); @@ -1421,7 +1423,7 @@ fn compare_number_of_generics<'tcx>( "{} `{}` has {} {kind} parameter{} but its trait \ declaration has {} {kind} parameter{}", item_kind, - trait_.name, + trait_.name(), impl_count, pluralize!(impl_count), trait_count, @@ -1512,7 +1514,7 @@ fn compare_number_of_method_arguments<'tcx>( impl_span, E0050, "method `{}` has {} but the declaration in trait `{}` has {}", - trait_m.name, + trait_m.name(), potentially_plural_count(impl_number_args, "parameter"), tcx.def_path_str(trait_m.def_id), trait_number_args @@ -1527,7 +1529,7 @@ fn compare_number_of_method_arguments<'tcx>( ), ); } else { - err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name(), trait_m.signature(tcx)); } err.span_label( @@ -1581,7 +1583,7 @@ fn compare_synthetic_generics<'tcx>( impl_span, E0643, "method `{}` has incompatible signature for trait", - trait_m.name + trait_m.name() ); err.span_label(trait_span, "declaration in trait here"); if impl_synthetic { @@ -1741,7 +1743,7 @@ fn compare_generic_param_kinds<'tcx>( E0053, "{} `{}` has an incompatible generic parameter for trait `{}`", impl_item.descr(), - trait_item.name, + trait_item.name(), &tcx.def_path_str(tcx.parent(trait_item.def_id)) ); @@ -1877,7 +1879,7 @@ fn compare_const_predicate_entailment<'tcx>( cause.span, E0326, "implemented const `{}` has an incompatible type for trait", - trait_ct.name + trait_ct.name() ); let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| { @@ -2237,8 +2239,8 @@ fn param_env_with_gat_bounds<'tcx>( // bounds about themselves. let impl_tys_to_install = match impl_ty.kind { ty::AssocKind::Type { - opt_rpitit_info: - Some( + data: + ty::AssocTypeData::Rpitit( ty::ImplTraitInTraitData::Impl { fn_def_id } | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, ), diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index ec934b1f620d..5fbd771976bb 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -205,7 +205,7 @@ fn missing_items_err( let missing_items_msg = missing_items .clone() - .map(|trait_item| trait_item.name.to_string()) + .map(|trait_item| trait_item.name().to_string()) .collect::>() .join("`, `"); @@ -236,7 +236,7 @@ fn missing_items_err( let code = format!("{padding}{snippet}\n{padding}"); if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) { missing_trait_item_label - .push(errors::MissingTraitItemLabel { span, item: trait_item.name }); + .push(errors::MissingTraitItemLabel { span, item: trait_item.name() }); missing_trait_item.push(errors::MissingTraitItemSuggestion { span: sugg_sp, code, @@ -504,9 +504,9 @@ fn suggestion_signature<'tcx>( tcx, tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), ); - format!("type {}{generics} = /* Type */{where_clauses};", assoc.name) + format!("type {}{generics} = /* Type */{where_clauses};", assoc.name()) } - ty::AssocKind::Const => { + ty::AssocKind::Const { name } => { let ty = tcx.type_of(assoc.def_id).instantiate_identity(); let val = tcx .infer_ctxt() @@ -514,7 +514,7 @@ fn suggestion_signature<'tcx>( .err_ctxt() .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty) .unwrap_or_else(|| "value".to_string()); - format!("const {}: {} = {};", assoc.name, ty, val) + format!("const {}: {} = {};", name, ty, val) } } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index c6c370c4a846..33d5a86beb3b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -474,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { gat_generics, ) } - ty::AssocKind::Const => None, + ty::AssocKind::Const { .. } => None, }; if let Some(item_required_bounds) = item_required_bounds { @@ -1076,7 +1076,7 @@ fn check_associated_item( }; match item.kind { - ty::AssocKind::Const => { + ty::AssocKind::Const { .. } => { let ty = tcx.type_of(item.def_id).instantiate_identity(); let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index cbfad1f6883e..242639125b19 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -51,7 +51,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { for &item1 in impl_items1.in_definition_order() { let collision = impl_items2 - .filter_by_name_unhygienic(item1.name) + .filter_by_name_unhygienic(item1.name()) .any(|&item2| self.compare_hygienically(item1, item2)); if collision { @@ -113,7 +113,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { let mut res = Ok(()); for &item1 in impl_items1.in_definition_order() { let collision = impl_items2 - .filter_by_name_unhygienic(item1.name) + .filter_by_name_unhygienic(item1.name()) .find(|&&item2| self.compare_hygienically(item1, item2)); if let Some(item2) = collision { @@ -230,11 +230,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> { let mut ids = impl_items .in_definition_order() .filter_map(|item| { - let entry = connected_region_ids.entry(item.name); + let entry = connected_region_ids.entry(item.name()); if let IndexEntry::Occupied(e) = &entry { Some(*e.get()) } else { - idents_to_add.push(item.name); + idents_to_add.push(item.name()); None } }) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 653adc6b3ba5..50e20a19edae 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -32,7 +32,7 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type( for &assoc_id in tcx.associated_item_def_ids(impl_def_id) { let assoc = tcx.associated_item(assoc_id); match assoc.kind { - ty::AssocKind::Const | ty::AssocKind::Fn { .. } => { + ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => { locator.check(assoc_id.expect_local()) } // Associated types don't have bodies, so they can't constrain hidden types diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 70d60bfcf2d2..526ee30209c7 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -492,7 +492,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .gen_args .constraints .iter() - .any(|constraint| constraint.ident.name == item.name) + .any(|constraint| constraint.ident.name == item.name()) }) .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| self.tcx.item_ident(item.def_id).to_string()) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 4f8d5471b6f4..72f219bfeb80 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -168,7 +168,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let all_candidate_names: Vec<_> = all_candidates() .flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order()) .filter_map(|item| { - (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then_some(item.name) + if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag { + item.opt_name() + } else { + None + } }) .collect(); @@ -200,7 +204,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order()) .filter_map(|item| { - (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then_some(item.name) + (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag) + .then_some(item.name()) }) .collect(); @@ -337,7 +342,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> ErrorGuaranteed { let tcx = self.tcx(); - let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind + let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind && let Some(constraint) = constraint && let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind { @@ -761,7 +766,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `issue-22560.rs`. let mut dyn_compatibility_violations = Ok(()); for (assoc_item, trait_ref) in &missing_assoc_types { - names.entry(trait_ref).or_default().push(assoc_item.name); + names.entry(trait_ref).or_default().push(assoc_item.name()); names_len += 1; let violations = @@ -852,16 +857,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut names: UnordMap<_, usize> = Default::default(); for (item, _) in &missing_assoc_types { types_count += 1; - *names.entry(item.name).or_insert(0) += 1; + *names.entry(item.name()).or_insert(0) += 1; } let mut dupes = false; let mut shadows = false; for (item, trait_ref) in &missing_assoc_types { - let prefix = if names[&item.name] > 1 { + let name = item.name(); + let prefix = if names[&name] > 1 { let trait_def_id = trait_ref.def_id(); dupes = true; format!("{}::", tcx.def_path_str(trait_def_id)) - } else if bound_names.get(&item.name).is_some_and(|x| *x != item) { + } else if bound_names.get(&name).is_some_and(|x| *x != item) { let trait_def_id = trait_ref.def_id(); shadows = true; format!("{}::", tcx.def_path_str(trait_def_id)) @@ -871,7 +877,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut is_shadowed = false; - if let Some(assoc_item) = bound_names.get(&item.name) + if let Some(assoc_item) = bound_names.get(&name) && *assoc_item != item { is_shadowed = true; @@ -880,17 +886,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" }; err.span_label( tcx.def_span(assoc_item.def_id), - format!("`{}{}` shadowed here{}", prefix, item.name, rename_message), + format!("`{}{}` shadowed here{}", prefix, name, rename_message), ); } let rename_message = if is_shadowed { ", consider renaming it" } else { "" }; if let Some(sp) = tcx.hir_span_if_local(item.def_id) { - err.span_label( - sp, - format!("`{}{}` defined here{}", prefix, item.name, rename_message), - ); + err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message)); } } if potential_assoc_types.len() == missing_assoc_types.len() { @@ -903,7 +906,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { let types: Vec<_> = missing_assoc_types .iter() - .map(|(item, _)| format!("{} = Type", item.name)) + .map(|(item, _)| format!("{} = Type", item.name())) .collect(); let code = if let Some(snippet) = snippet.strip_suffix('>') { // The user wrote `Trait<'a>` or similar and we don't have a type we can @@ -938,16 +941,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut names: FxIndexMap<_, usize> = FxIndexMap::default(); for (item, _) in &missing_assoc_types { types_count += 1; - *names.entry(item.name).or_insert(0) += 1; + *names.entry(item.name()).or_insert(0) += 1; } let mut label = vec![]; for (item, trait_ref) in &missing_assoc_types { - let postfix = if names[&item.name] > 1 { + let name = item.name(); + let postfix = if names[&name] > 1 { format!(" (from trait `{}`)", trait_ref.print_trait_sugared()) } else { String::new() }; - label.push(format!("`{}`{}", item.name, postfix)); + label.push(format!("`{}`{}", name, postfix)); } if !label.is_empty() { err.span_label( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 49fd55b03a25..483b61add338 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -502,7 +502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .associated_items(trait_def_id) .in_definition_order() .filter(|assoc| assoc.namespace() == Namespace::ValueNS) - .map(|cand| cand.name) + .map(|cand| cand.name()) .collect(); if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) { diag.span_suggestion_verbose( diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 127ca846b9fe..cbdc501291bc 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -119,7 +119,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained( vec![] } } - ty::AssocKind::Fn { .. } | ty::AssocKind::Const => vec![], + ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => vec![], } }) .collect(); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 56c205b6f879..532c5092a4e9 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2601,8 +2601,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } let input_len = fn_sig.inputs().skip_binder().len(); - let order = !item.name.as_str().starts_with("new"); - Some((order, item.name, input_len)) + let name = item.name(); + let order = !name.as_str().starts_with("new"); + Some((order, name, input_len)) }) .collect::>(); items.sort_by_key(|(order, _, _)| *order); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 3a0f3a4a5f0b..da0e8e362d66 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -683,10 +683,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .all(|(expected, found)| self.may_coerce(*expected, *found)) && fn_sig.inputs()[1..].len() == input_types.len() { + let assoc_name = assoc.name(); err.span_suggestion_verbose( call_name.span, - format!("you might have meant to use `{}`", assoc.name), - assoc.name, + format!("you might have meant to use `{}`", assoc_name), + assoc_name, Applicability::MaybeIncorrect, ); return; @@ -706,7 +707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.def_span(assoc.def_id), format!( "there's is a method with similar name `{}`, but the arguments don't match", - assoc.name, + assoc.name(), ), ); return; @@ -718,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!( "there's is a method with similar name `{}`, but their argument count \ doesn't match", - assoc.name, + assoc.name(), ), ); return; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 912098c4e2d6..91eb1989864f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -381,9 +381,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut suggestions = methods .iter() .filter_map(|conversion_method| { + let conversion_method_name = conversion_method.name(); let receiver_method_ident = expr.method_ident(); if let Some(method_ident) = receiver_method_ident - && method_ident.name == conversion_method.name + && method_ident.name == conversion_method_name { return None; // do not suggest code that is already there (#53348) } @@ -391,20 +392,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let method_call_list = [sym::to_vec, sym::to_string]; let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind && receiver_method.ident.name == sym::clone - && method_call_list.contains(&conversion_method.name) + && method_call_list.contains(&conversion_method_name) // If receiver is `.clone()` and found type has one of those methods, // we guess that the user wants to convert from a slice type (`&[]` or `&str`) // to an owned type (`Vec` or `String`). These conversions clone internally, // so we remove the user's `clone` call. { - vec![(receiver_method.ident.span, conversion_method.name.to_string())] + vec![(receiver_method.ident.span, conversion_method_name.to_string())] } else if expr.precedence() < ExprPrecedence::Unambiguous { vec![ (expr.span.shrink_to_lo(), "(".to_string()), - (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)), + (expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)), ] } else { - vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))] + vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method_name))] }; let struct_pat_shorthand_field = self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 1d86ff14471a..0c6240d1f74b 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -266,7 +266,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty() { if let Some(item) = tcx.opt_associated_item(def_id.into()) - && let ty::AssocKind::Const = item.kind + && let ty::AssocKind::Const { .. } = item.kind && let ty::AssocItemContainer::Impl = item.container && let Some(trait_item_def_id) = item.trait_item_def_id { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index c14b7823e370..ba4396a5ab35 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1671,7 +1671,7 @@ impl<'tcx> Pick<'tcx> { /// Do not use for type checking. pub(crate) fn differs_from(&self, other: &Self) -> bool { let Self { - item: AssocItem { def_id, name: _, kind: _, container: _, trait_item_def_id: _ }, + item: AssocItem { def_id, kind: _, container: _, trait_item_def_id: _ }, kind: _, import_ids: _, autoderefs: _, @@ -1714,17 +1714,12 @@ impl<'tcx> Pick<'tcx> { tcx.def_path_str(self.item.def_id), )); } - (ty::AssocKind::Const, ty::AssocItemContainer::Trait) => { + (ty::AssocKind::Const { name }, ty::AssocItemContainer::Trait) => { let def_id = self.item.container_id(tcx); lint.span_suggestion( span, "use the fully qualified path to the associated const", - format!( - "<{} as {}>::{}", - self.self_ty, - tcx.def_path_str(def_id), - self.item.name - ), + format!("<{} as {}>::{}", self.self_ty, tcx.def_path_str(def_id), name), Applicability::MachineApplicable, ); } @@ -2213,7 +2208,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let best_name = { let names = applicable_close_candidates .iter() - .map(|cand| cand.name) + .map(|cand| cand.name()) .collect::>(); find_best_match_for_name_with_substrings( &names, @@ -2225,10 +2220,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { applicable_close_candidates .iter() .find(|cand| self.matches_by_doc_alias(cand.def_id)) - .map(|cand| cand.name) + .map(|cand| cand.name()) }); Ok(best_name.and_then(|best_name| { - applicable_close_candidates.into_iter().find(|method| method.name == best_name) + applicable_close_candidates + .into_iter() + .find(|method| method.name() == best_name) })) } }) @@ -2246,7 +2243,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { Mode::MethodCall => item.is_method(), Mode::Path => match item.kind { ty::AssocKind::Type { .. } => false, - ty::AssocKind::Fn { .. } | ty::AssocKind::Const => true, + ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => true, }, } // FIXME -- check for types that deref to `Self`, @@ -2320,7 +2317,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool { match (self.mode, kind) { (Mode::MethodCall, ty::AssocKind::Fn { .. }) => true, - (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn { .. }) => true, + (Mode::Path, ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. }) => true, _ => false, } } @@ -2402,7 +2399,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } match edit_distance_with_substrings( name.as_str(), - x.name.as_str(), + x.name().as_str(), max_dist, ) { Some(d) => d > 0, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 962871ed2d11..6a9fd7cdd483 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1722,7 +1722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that had unsatisfied trait bounds if unsatisfied_predicates.is_empty() // ...or if we already suggested that name because of `rustc_confusable` annotation. - && Some(similar_candidate.name) != confusable_suggested + && Some(similar_candidate.name()) != confusable_suggested { self.find_likely_intended_associated_item( &mut err, @@ -1821,10 +1821,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let def_kind = similar_candidate.as_def_kind(); let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id); + let similar_candidate_name = similar_candidate.name(); let msg = format!( "there is {an} {} `{}` with a similar name", self.tcx.def_kind_descr(def_kind, similar_candidate.def_id), - similar_candidate.name, + similar_candidate_name, ); // Methods are defined within the context of a struct and their first parameter // is always `self`, which represents the instance of the struct the method is @@ -1843,7 +1844,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( span, msg, - similar_candidate.name, + similar_candidate_name, Applicability::MaybeIncorrect, ); } else { @@ -1865,7 +1866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( span, msg, - similar_candidate.name, + similar_candidate_name, Applicability::MaybeIncorrect, ); } else { @@ -1878,7 +1879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( span, msg, - similar_candidate.name, + similar_candidate_name, Applicability::MaybeIncorrect, ); } else { @@ -1918,6 +1919,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer::FnCall, fn_sig, ); + let name = inherent_method.name(); if let Some(ref args) = call_args && fn_sig.inputs()[1..] .iter() @@ -1927,20 +1929,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { err.span_suggestion_verbose( item_name.span, - format!("you might have meant to use `{}`", inherent_method.name), - inherent_method.name, + format!("you might have meant to use `{}`", name), + name, Applicability::MaybeIncorrect, ); - return Some(inherent_method.name); + return Some(name); } else if let None = call_args { err.span_note( self.tcx.def_span(inherent_method.def_id), - format!( - "you might have meant to use method `{}`", - inherent_method.name, - ), + format!("you might have meant to use method `{}`", name), ); - return Some(inherent_method.name); + return Some(name); } } } @@ -2116,7 +2115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only assoc fn with no receivers and only if // they are resolvable .filter(|item| { - matches!(item.kind, ty::AssocKind::Fn { has_self: false }) + matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. }) && self .probe_for_name( Mode::Path, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 93f77b8409f0..0e42a84ca32a 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -372,7 +372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .associated_item_def_ids(def_id) .iter() .find(|item_def_id| { - self.tcx.associated_item(*item_def_id).name == sym::Output + self.tcx.associated_item(*item_def_id).name() == sym::Output }) .cloned() }); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 3cbe09280f69..3c2245347f97 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1332,30 +1332,26 @@ impl<'a> CrateMetadataRef<'a> { } fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { - let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() { - kw::Empty - } else { - self.item_name(id) - }; let kind = match self.def_kind(id) { - DefKind::AssocConst => ty::AssocKind::Const, - DefKind::AssocFn => { - ty::AssocKind::Fn { has_self: self.get_fn_has_self_parameter(id, sess) } - } - DefKind::AssocTy => ty::AssocKind::Type { - opt_rpitit_info: self - .root - .tables - .opt_rpitit_info - .get(self, id) - .map(|d| d.decode(self)), + DefKind::AssocConst => ty::AssocKind::Const { name: self.item_name(id) }, + DefKind::AssocFn => ty::AssocKind::Fn { + name: self.item_name(id), + has_self: self.get_fn_has_self_parameter(id, sess), }, + DefKind::AssocTy => { + let data = if let Some(rpitit_info) = self.root.tables.opt_rpitit_info.get(self, id) + { + ty::AssocTypeData::Rpitit(rpitit_info.decode(self)) + } else { + ty::AssocTypeData::Normal(self.item_name(id)) + }; + ty::AssocKind::Type { data } + } _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; let container = self.root.tables.assoc_container.get(self, id).unwrap(); ty::AssocItem { - name, kind, def_id: self.local_def_id(id), trait_item_def_id: self.get_trait_item_def_id(id), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b900100c3c01..177318bfe15e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1706,7 +1706,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } - if let ty::AssocKind::Type { opt_rpitit_info: Some(rpitit_info) } = item.kind { + if let ty::AssocKind::Type { data: ty::AssocTypeData::Rpitit(rpitit_info) } = item.kind { record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info); if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) { record_array!( diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 6138157d8362..0c44fd2758d5 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -18,7 +18,6 @@ pub enum AssocItemContainer { #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)] pub struct AssocItem { pub def_id: DefId, - pub name: Symbol, pub kind: AssocKind, pub container: AssocItemContainer, @@ -28,8 +27,24 @@ pub struct AssocItem { } impl AssocItem { + // Gets the identifier, if it has one. + pub fn opt_name(&self) -> Option { + match self.kind { + ty::AssocKind::Type { data: AssocTypeData::Normal(name) } => Some(name), + ty::AssocKind::Type { data: AssocTypeData::Rpitit(_) } => None, + ty::AssocKind::Const { name } => Some(name), + ty::AssocKind::Fn { name, .. } => Some(name), + } + } + + // Gets the identifier name. Aborts if it lacks one, i.e. is an RPITIT + // associated type. + pub fn name(&self) -> Symbol { + self.opt_name().expect("name of non-Rpitit assoc item") + } + pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { - Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) + Ident::new(self.name(), tcx.def_ident_span(self.def_id).unwrap()) } /// Gets the defaultness of the associated item. @@ -76,22 +91,18 @@ impl AssocItem { // regions just fine, showing `fn(&MyType)`. tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string() } - ty::AssocKind::Type { .. } => format!("type {};", self.name), - ty::AssocKind::Const => { - format!( - "const {}: {:?};", - self.name, - tcx.type_of(self.def_id).instantiate_identity() - ) + ty::AssocKind::Type { .. } => format!("type {};", self.name()), + ty::AssocKind::Const { name } => { + format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity()) } } } pub fn descr(&self) -> &'static str { match self.kind { - ty::AssocKind::Const => "associated const", - ty::AssocKind::Fn { has_self: true } => "method", - ty::AssocKind::Fn { has_self: false } => "associated function", + ty::AssocKind::Const { .. } => "associated const", + ty::AssocKind::Fn { has_self: true, .. } => "method", + ty::AssocKind::Fn { has_self: false, .. } => "associated function", ty::AssocKind::Type { .. } => "associated type", } } @@ -99,13 +110,13 @@ impl AssocItem { pub fn namespace(&self) -> Namespace { match self.kind { ty::AssocKind::Type { .. } => Namespace::TypeNS, - ty::AssocKind::Const | ty::AssocKind::Fn { .. } => Namespace::ValueNS, + ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS, } } pub fn as_def_kind(&self) -> DefKind { match self.kind { - AssocKind::Const => DefKind::AssocConst, + AssocKind::Const { .. } => DefKind::AssocConst, AssocKind::Fn { .. } => DefKind::AssocFn, AssocKind::Type { .. } => DefKind::AssocTy, } @@ -119,19 +130,19 @@ impl AssocItem { } pub fn is_method(&self) -> bool { - matches!(self.kind, ty::AssocKind::Fn { has_self: true }) + matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. }) } pub fn as_tag(&self) -> AssocTag { match self.kind { - AssocKind::Const => AssocTag::Const, + AssocKind::Const { .. } => AssocTag::Const, AssocKind::Fn { .. } => AssocTag::Fn, AssocKind::Type { .. } => AssocTag::Type, } } pub fn is_impl_trait_in_trait(&self) -> bool { - matches!(self.kind, AssocKind::Type { opt_rpitit_info: Some(_) }) + matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) }) } /// Returns true if: @@ -139,7 +150,7 @@ impl AssocItem { /// - If it is in a trait impl, the item from the original trait has this attribute, or /// - It is an inherent assoc const. pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool { - if self.kind != ty::AssocKind::Const { + if !matches!(self.kind, ty::AssocKind::Const { .. }) { return false; } @@ -153,26 +164,45 @@ impl AssocItem { } } +#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] +pub enum AssocTypeData { + Normal(Symbol), + /// The associated type comes from an RPITIT. It has no name, and the + /// `ImplTraitInTraitData` provides additional information about its + /// source. + Rpitit(ty::ImplTraitInTraitData), +} + #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] pub enum AssocKind { - Const, - Fn { - has_self: bool, - }, - Type { - /// `Some` if the associated type comes from an RPITIT. The - /// `ImplTraitInTraitData` provides additional information about its - /// source. - opt_rpitit_info: Option, - }, + Const { name: Symbol }, + Fn { name: Symbol, has_self: bool }, + Type { data: AssocTypeData }, +} + +impl AssocKind { + pub fn namespace(&self) -> Namespace { + match *self { + ty::AssocKind::Type { .. } => Namespace::TypeNS, + ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS, + } + } + + pub fn as_def_kind(&self) -> DefKind { + match self { + AssocKind::Const { .. } => DefKind::AssocConst, + AssocKind::Fn { .. } => DefKind::AssocFn, + AssocKind::Type { .. } => DefKind::AssocTy, + } + } } impl std::fmt::Display for AssocKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - AssocKind::Fn { has_self: true } => write!(f, "method"), - AssocKind::Fn { has_self: false } => write!(f, "associated function"), - AssocKind::Const => write!(f, "associated const"), + AssocKind::Fn { has_self: true, .. } => write!(f, "method"), + AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"), + AssocKind::Const { .. } => write!(f, "associated const"), AssocKind::Type { .. } => write!(f, "associated type"), } } @@ -193,17 +223,17 @@ pub enum AssocTag { /// done only on items with the same name. #[derive(Debug, Clone, PartialEq, HashStable)] pub struct AssocItems { - items: SortedIndexMultiMap, + items: SortedIndexMultiMap, ty::AssocItem>, } impl AssocItems { /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order. pub fn new(items_in_def_order: impl IntoIterator) -> Self { - let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect(); + let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect(); AssocItems { items } } - /// Returns a slice of associated items in the order they were defined. + /// Returns an iterator over associated items in the order they were defined. /// /// New code should avoid relying on definition order. If you need a particular associated item /// for a known trait, make that trait a lang item instead of indexing this array. @@ -220,7 +250,8 @@ impl AssocItems { &self, name: Symbol, ) -> impl '_ + Iterator { - self.items.get_by_key(name) + assert!(!name.is_empty()); + self.items.get_by_key(Some(name)) } /// Returns the associated item with the given identifier and `AssocKind`, if one exists. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 395d2ec48142..1945538b1c2f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1611,9 +1611,10 @@ impl<'tcx> TyCtxt<'tcx> { /// about where that RPITIT came from. pub fn opt_rpitit_info(self, def_id: DefId) -> Option { if let DefKind::AssocTy = self.def_kind(def_id) - && let AssocKind::Type { opt_rpitit_info } = self.associated_item(def_id).kind + && let AssocKind::Type { data: AssocTypeData::Rpitit(rpitit_info) } = + self.associated_item(def_id).kind { - opt_rpitit_info + Some(rpitit_info) } else { None } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2f93197bcef1..d739218af5ee 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1214,7 +1214,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { && assoc .trait_container(tcx) .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine)) - && assoc.name == rustc_span::sym::Return + && assoc.opt_name() == Some(rustc_span::sym::Return) { if let ty::Coroutine(_, args) = args.type_at(0).kind() { let return_ty = args.as_coroutine().return_ty(); @@ -1237,7 +1237,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(", "); } - p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name)); + p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name())); match term.unpack() { TermKind::Ty(ty) => p!(print(ty)), @@ -3291,7 +3291,7 @@ define_print! { } ty::ExistentialProjection<'tcx> { - let name = cx.tcx().associated_item(self.def_id).name; + let name = cx.tcx().associated_item(self.def_id).name(); // The args don't contain the self ty (as it has been erased) but the corresp. // generics do as the trait always has a self ty param. We need to offset. let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..]; diff --git a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs index ed3b1ae4f42f..daddb5dedbcf 100644 --- a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs +++ b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> { if self.tcx.is_const_fn(def_id) || matches!( self.tcx.opt_associated_item(def_id), - Some(AssocItem { kind: AssocKind::Const, .. }) + Some(AssocItem { kind: AssocKind::Const { .. }, .. }) ) { let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index ae81021e0bea..d4fe446cc9f7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2007,8 +2007,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if def.did() != def_id { return None; } - let order = !item.name.as_str().starts_with("new"); - Some((order, item.name, input_len)) + let name = item.name(); + let order = !name.as_str().starts_with("new"); + Some((order, name, input_len)) }) .collect::>(); items.sort_by_key(|(order, _, _)| *order); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 55f698b8f211..a757329bcf2a 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -895,12 +895,19 @@ impl<'tcx> Stable<'tcx> for ty::AssocKind { type T = stable_mir::ty::AssocKind; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - use stable_mir::ty::AssocKind; + use stable_mir::ty::{AssocKind, AssocTypeData}; match *self { - ty::AssocKind::Const => AssocKind::Const, - ty::AssocKind::Fn { has_self } => AssocKind::Fn { has_self }, - ty::AssocKind::Type { opt_rpitit_info } => AssocKind::Type { - opt_rpitit_info: opt_rpitit_info.map(|rpitit| rpitit.stable(tables)), + ty::AssocKind::Const { name } => AssocKind::Const { name: name.to_string() }, + ty::AssocKind::Fn { name, has_self } => { + AssocKind::Fn { name: name.to_string(), has_self } + } + ty::AssocKind::Type { data } => AssocKind::Type { + data: match data { + ty::AssocTypeData::Normal(name) => AssocTypeData::Normal(name.to_string()), + ty::AssocTypeData::Rpitit(rpitit) => { + AssocTypeData::Rpitit(rpitit.stable(tables)) + } + }, }, } } @@ -924,7 +931,6 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { stable_mir::ty::AssocItem { def_id: tables.assoc_def(self.def_id), - name: self.name.to_string(), kind: self.kind.stable(tables), container: self.container.stable(tables), trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)), diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs index 9fa97763907f..8a6be0cd37a0 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs @@ -22,9 +22,9 @@ impl Display for Ty { impl Display for AssocKind { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - AssocKind::Fn { has_self: true } => write!(f, "method"), - AssocKind::Fn { has_self: false } => write!(f, "associated function"), - AssocKind::Const => write!(f, "associated const"), + AssocKind::Fn { has_self: true, .. } => write!(f, "method"), + AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"), + AssocKind::Const { .. } => write!(f, "associated const"), AssocKind::Type { .. } => write!(f, "associated type"), } } diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 6eac0885d763..4b153007bd86 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1578,7 +1578,6 @@ crate_def! { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct AssocItem { pub def_id: AssocDef, - pub name: Symbol, pub kind: AssocKind, pub container: AssocItemContainer, @@ -1587,18 +1586,20 @@ pub struct AssocItem { pub trait_item_def_id: Option, } +#[derive(Clone, PartialEq, Debug, Eq, Serialize)] +pub enum AssocTypeData { + Normal(Symbol), + /// The associated type comes from an RPITIT. It has no name, and the + /// `ImplTraitInTraitData` provides additional information about its + /// source. + Rpitit(ImplTraitInTraitData), +} + #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AssocKind { - Const, - Fn { - has_self: bool, - }, - Type { - /// `Some` if the associated type comes from an RPITIT. The - /// `ImplTraitInTraitData` provides additional information about its - /// source. - opt_rpitit_info: Option, - }, + Const { name: Symbol }, + Fn { name: Symbol, has_self: bool }, + Type { data: AssocTypeData }, } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] @@ -1615,6 +1616,6 @@ pub enum ImplTraitInTraitData { impl AssocItem { pub fn is_impl_trait_in_trait(&self) -> bool { - matches!(self.kind, AssocKind::Type { opt_rpitit_info: Some(_) }) + matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) }) } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index d28f10ba9e38..a4e1266e7643 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -615,7 +615,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { cx.print_def_path(trait_ref.def_id, trait_ref.args)?; } ty::ExistentialPredicate::Projection(projection) => { - let name = cx.tcx.associated_item(projection.def_id).name; + let name = cx.tcx.associated_item(projection.def_id).name(); cx.push("p"); cx.push_ident(name.as_str()); match projection.term.unpack() { 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 1c71fe028d4d..fdd547448f00 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2340,7 +2340,7 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => { ObligationCauseFailureCode::TypeCompat { span, subdiags } } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => { ObligationCauseFailureCode::ConstCompat { span, subdiags } } ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => { @@ -2404,7 +2404,7 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => { "associated type is compatible with trait" } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => { "const is compatible with trait" } ObligationCauseCode::MainFunctionType => "`main` function has the correct type", @@ -2428,7 +2428,7 @@ impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => { "type_compat" } - ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => { "const_compat" } ObligationCauseCode::MainFunctionType => "fn_main_correct_type", diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 02f21b5465c6..be508c8cee13 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -783,7 +783,7 @@ fn foo(&self) -> Self::T { String::new() } .in_definition_order() .filter(|item| { item.is_fn() - && Some(item.name) != current_method_ident + && Some(item.name()) != current_method_ident && !tcx.is_doc_hidden(item.def_id) }) .filter_map(|item| { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 49c6acedcfa4..df3cce880dd4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -1017,7 +1017,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( " for lifetime parameter {}in trait containing associated type `{}`", br_string(br), - self.tcx.associated_item(def_id).name + self.tcx.associated_item(def_id).name() ), infer::RegionParameterDefinition(_, name) => { format!(" for lifetime parameter `{name}`") diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index c4b0ca9cf8fc..54b50851b74d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -348,7 +348,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let None = self.tainted_by_errors() { let (verb, noun) = match self.tcx.associated_item(item_id).kind { - ty::AssocKind::Const => ("refer to the", "constant"), + ty::AssocKind::Const { .. } => ("refer to the", "constant"), ty::AssocKind::Fn { .. } => ("call", "function"), // This is already covered by E0223, but this following single match // arm doesn't hurt here. 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 08b95b450583..7d95a7b3fed2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2112,7 +2112,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_ref: DefId, ) { if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) { - if let ty::AssocKind::Const | ty::AssocKind::Type { .. } = assoc_item.kind { + if let ty::AssocKind::Const { .. } | ty::AssocKind::Type { .. } = assoc_item.kind { err.note(format!( "{}s cannot be accessed directly on a `trait`, they can only be \ accessed through a specific `impl`", @@ -2121,7 +2121,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.span_suggestion( span, "use the fully qualified path to an implementation", - format!("::{}", self.tcx.def_path_str(trait_ref), assoc_item.name), + format!( + "::{}", + self.tcx.def_path_str(trait_ref), + assoc_item.name() + ), Applicability::HasPlaceholders, ); } diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 1ef16f34702e..519394685a8e 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -298,31 +298,33 @@ pub fn dyn_compatibility_violations_for_assoc_item( match item.kind { // Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all, // and associated const bounds in trait objects aren't a thing yet either. - ty::AssocKind::Const => { - vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)] + ty::AssocKind::Const { name } => { + vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)] } - ty::AssocKind::Fn { .. } => virtual_call_violations_for_method(tcx, trait_def_id, item) - .into_iter() - .map(|v| { - let node = tcx.hir_get_if_local(item.def_id); - // Get an accurate span depending on the violation. - let span = match (&v, node) { - (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, - (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, - (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span, - (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { - node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) - } - _ => item.ident(tcx).span, - }; + ty::AssocKind::Fn { name, .. } => { + virtual_call_violations_for_method(tcx, trait_def_id, item) + .into_iter() + .map(|v| { + let node = tcx.hir_get_if_local(item.def_id); + // Get an accurate span depending on the violation. + let span = match (&v, node) { + (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, + (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, + (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span, + (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { + node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) + } + _ => item.ident(tcx).span, + }; - DynCompatibilityViolation::Method(item.name, v, span) - }) - .collect(), + DynCompatibilityViolation::Method(name, v, span) + }) + .collect() + } // Associated types can only be dyn-compatible if they have `Self: Sized` bounds. ty::AssocKind::Type { .. } => { if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() { - vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)] + vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)] } else { // We will permit associated types if they are explicitly mentioned in the trait object. // We can't check this here, as here we only check if it is guaranteed to not be possible. diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 83591219b14d..0dce504903ca 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1393,7 +1393,7 @@ fn confirm_future_candidate<'cx, 'tcx>( coroutine_sig, ); - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Output); let predicate = ty::ProjectionPredicate { projection_term: ty::AliasTerm::new_from_args( @@ -1439,7 +1439,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>( gen_sig, ); - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item); let predicate = ty::ProjectionPredicate { projection_term: ty::AliasTerm::new_from_args( @@ -1485,7 +1485,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>( gen_sig, ); - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item); let ty::Adt(_poll_adt, args) = *yield_ty.kind() else { bug!(); @@ -2005,7 +2005,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( if !assoc_ty.item.defaultness(tcx).has_value() { debug!( "confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.name, obligation.predicate + assoc_ty.item.name(), + obligation.predicate ); if tcx.impl_self_is_guaranteed_unsized(impl_def_id) { // We treat this projection as rigid here, which is represented via diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 2275fbb97923..6cb9fdc6f931 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -6,7 +6,6 @@ use rustc_hir::{self as hir, AmbigArg}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_span::kw; pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { @@ -129,14 +128,14 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem { fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem { let owner_id = trait_item_ref.id.owner_id; + let name = trait_item_ref.ident.name; let kind = match trait_item_ref.kind { - hir::AssocItemKind::Const => ty::AssocKind::Const, - hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { has_self }, - hir::AssocItemKind::Type => ty::AssocKind::Type { opt_rpitit_info: None }, + hir::AssocItemKind::Const => ty::AssocKind::Const { name }, + hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self }, + hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }, }; ty::AssocItem { - name: trait_item_ref.ident.name, kind, def_id: owner_id.to_def_id(), trait_item_def_id: Some(owner_id.to_def_id()), @@ -146,14 +145,14 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem { let def_id = impl_item_ref.id.owner_id; + let name = impl_item_ref.ident.name; let kind = match impl_item_ref.kind { - hir::AssocItemKind::Const => ty::AssocKind::Const, - hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { has_self }, - hir::AssocItemKind::Type => ty::AssocKind::Type { opt_rpitit_info: None }, + hir::AssocItemKind::Const => ty::AssocKind::Const { name }, + hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self }, + hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }, }; ty::AssocItem { - name: impl_item_ref.ident.name, kind, def_id: def_id.to_def_id(), trait_item_def_id: impl_item_ref.trait_item_def_id, @@ -260,9 +259,8 @@ fn associated_type_for_impl_trait_in_trait( trait_assoc_ty.def_ident_span(Some(span)); trait_assoc_ty.associated_item(ty::AssocItem { - name: kw::Empty, kind: ty::AssocKind::Type { - opt_rpitit_info: Some(ImplTraitInTraitData::Trait { + data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait { fn_def_id: fn_def_id.to_def_id(), opaque_def_id: opaque_ty_def_id.to_def_id(), }), @@ -313,9 +311,8 @@ fn associated_type_for_impl_trait_in_impl( impl_assoc_ty.def_ident_span(Some(span)); impl_assoc_ty.associated_item(ty::AssocItem { - name: kw::Empty, kind: ty::AssocKind::Type { - opt_rpitit_info: Some(ImplTraitInTraitData::Impl { + data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id(), }), }, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 74dbc7d06001..2a95acc622ea 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -521,7 +521,7 @@ fn projection_to_path_segment<'tcx>( let item = cx.tcx.associated_item(def_id); let generics = cx.tcx.generics_of(def_id); PathSegment { - name: item.name, + name: item.name(), args: GenericArgs::AngleBracketed { args: clean_middle_generic_args( cx, @@ -1340,7 +1340,7 @@ pub(crate) fn clean_impl_item<'tcx>( pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item { let tcx = cx.tcx; let kind = match assoc_item.kind { - ty::AssocKind::Const => { + ty::AssocKind::Const { .. } => { let ty = clean_middle_ty( ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()), cx, @@ -1374,7 +1374,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo } } } - ty::AssocKind::Fn { has_self } => { + ty::AssocKind::Fn { has_self, .. } => { let mut item = inline::build_function(cx, assoc_item.def_id); if has_self { @@ -1413,7 +1413,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo } } ty::AssocKind::Type { .. } => { - let my_name = assoc_item.name; + let my_name = assoc_item.name(); fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool { match (¶m.kind, arg) { @@ -1554,7 +1554,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo } }; - Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx) + Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name()), kind, cx) } fn first_non_private_clean_path<'tcx>( @@ -2223,7 +2223,7 @@ pub(crate) fn clean_middle_ty<'tcx>( Type::QPath(Box::new(QPathData { assoc: PathSegment { - name: cx.tcx.associated_item(def_id).name, + name: cx.tcx.associated_item(def_id).name(), args: GenericArgs::AngleBracketed { args: clean_middle_generic_args( cx, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 06e75fe1764e..7786b216112b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2504,7 +2504,7 @@ impl Impl { self.trait_ .as_ref() .map(|t| t.def_id()) - .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect()) + .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect()) .unwrap_or_default() } diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index ab34af7c3174..e5439a6d401b 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -111,8 +111,8 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { // Only suggest if `clone_from`/`clone_into` is explicitly implemented && resolved_assoc_items.in_definition_order().any(|assoc| match which_trait { - CloneTrait::Clone => assoc.name == sym::clone_from, - CloneTrait::ToOwned => assoc.name.as_str() == "clone_into", + CloneTrait::Clone => assoc.name() == sym::clone_from, + CloneTrait::ToOwned => assoc.name().as_str() == "clone_into", } ) && !clone_source_borrows_from_dest(cx, lhs, rhs.span) diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs index e82211bbf3ef..b5adc69e9a79 100644 --- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args) // find the provided definition of Iterator::last && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last") + && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last") // if the resolved method is the same as the provided definition && fn_def.def_id() == last_def.def_id { diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 7ee746365d10..e266c36b6e73 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { cx, MISSING_TRAIT_METHODS, cx.tcx.def_span(item.owner_id), - format!("missing trait method provided by default: `{}`", assoc.name), + format!("missing trait method provided by default: `{}`", assoc.name()), |diag| { diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method"); }, diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index ae677e110af2..33815cc3bac1 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { .associated_items(did) .in_definition_order() .filter(|assoc_item| assoc_item.is_fn()) - .map(|assoc_item| assoc_item.name) + .map(|assoc_item| assoc_item.name()) .collect() } else { BTreeSet::new() diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index 2104eb302ab8..0c17cc5d8f66 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -322,7 +322,7 @@ impl UnconditionalRecursion { .in_definition_order() // We're not interested in foreign implementations of the `Default` trait. .find(|item| { - item.is_fn() && item.def_id.is_local() && item.name == kw::Default + item.is_fn() && item.def_id.is_local() && item.name() == kw::Default }) && let Some(body_node) = cx.tcx.hir_get_if_local(assoc_item.def_id) && let Some(body_id) = body_node.body_id() From c2712bcd2d8586a0c35f0d66a221f87aee3f6884 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 11 Mar 2025 17:36:27 -0700 Subject: [PATCH 151/222] ci: add runners for vanilla LLVM 20 Ubuntu 25.04 has `llvm-20` packages that we can start testing with. The `Dockerfile` is otherwise the same as the `llvm-18`/`19` runners. --- .../host-x86_64/x86_64-gnu-llvm-20/Dockerfile | 69 +++++++++++++++++++ src/ci/github-actions/jobs.yml | 25 +++++++ 2 files changed, 94 insertions(+) create mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile new file mode 100644 index 000000000000..408b87125e0c --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile @@ -0,0 +1,69 @@ +FROM ubuntu:25.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bzip2 \ + g++ \ + gcc-multilib \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + sudo \ + gdb \ + llvm-20-tools \ + llvm-20-dev \ + libedit-dev \ + libssl-dev \ + pkg-config \ + zlib1g-dev \ + xz-utils \ + nodejs \ + mingw-w64 \ + # libgccjit dependencies + flex \ + libmpfr-dev \ + libgmp-dev \ + libmpc3 \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install powershell (universal package) so we can test x.ps1 on Linux +# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep. +RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ + dpkg --ignore-depends=libicu72 -i powershell.deb && \ + rm -f powershell.deb + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# We are disabling CI LLVM since this builder is intentionally using a host +# LLVM, rather than the typical src/llvm-project LLVM. +ENV NO_DOWNLOAD_CI_LLVM 1 +ENV EXTERNAL_LLVM 1 + +# Using llvm-link-shared due to libffi issues -- see #34486 +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --llvm-root=/usr/lib/llvm-20 \ + --enable-llvm-link-shared \ + --set rust.randomize-layout=true \ + --set rust.thin-lto-import-instr-limit=10 + +COPY scripts/shared.sh /scripts/ + +ARG SCRIPT_ARG + +COPY scripts/add_dummy_commit.sh /tmp/ +COPY scripts/x86_64-gnu-llvm.sh /tmp/ +COPY scripts/x86_64-gnu-llvm2.sh /tmp/ +COPY scripts/x86_64-gnu-llvm3.sh /tmp/ +COPY scripts/stage_2_test_set1.sh /tmp/ +COPY scripts/stage_2_test_set2.sh /tmp/ + +ENV SCRIPT "/tmp/add_dummy_commit.sh && /tmp/${SCRIPT_ARG}" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index fbda749b6a2a..fd4650ba2853 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -304,6 +304,31 @@ auto: - name: x86_64-gnu-distcheck <<: *job-linux-8c + # The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel. + # x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}. + - name: x86_64-gnu-llvm-20-1 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-20 + DOCKER_SCRIPT: stage_2_test_set1.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-20-{1,3} + - name: x86_64-gnu-llvm-20-2 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-20 + DOCKER_SCRIPT: x86_64-gnu-llvm2.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-20-{1,2} + - name: x86_64-gnu-llvm-20-3 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-20 + DOCKER_SCRIPT: x86_64-gnu-llvm3.sh + <<: *job-linux-4c + # The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel. # x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}. - name: x86_64-gnu-llvm-19-1 From 9676d4aeb7d918179f4b5d39e10ad360ec5b2577 Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 8 Apr 2025 14:58:28 -0500 Subject: [PATCH 152/222] std: add Output::exit_ok approved in ACP https://github.com/rust-lang/libs-team/issues/554 --- library/std/src/process.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 3b765a9537bc..4562741e31cc 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1286,6 +1286,40 @@ pub struct Output { pub stderr: Vec, } +impl Output { + /// Returns an error if a nonzero exit status was received. + /// + /// If the [`Command`] exited successfully, + /// `self` is returned. + /// + /// This is equivalent to calling [`exit_ok`](ExitStatus::exit_ok) + /// on [`Output.status`](Output::status). + /// + /// Note that this will throw away the [`Output::stderr`] field in the error case. + /// If the child process outputs useful informantion to stderr, you can: + /// * Use `cmd.stderr(Stdio::inherit())` to forward the + /// stderr child process to the parent's stderr, + /// usually printing it to console where the user can see it. + /// This is usually correct for command-line applications. + /// * Capture `stderr` using a custom error type. + /// This is usually correct for libraries. + /// + /// # Examples + /// + /// ``` + /// #![feature(exit_status_error)] + /// # #[cfg(unix)] { + /// use std::process::Command; + /// assert!(Command::new("false").output().unwrap().exit_ok().is_err()); + /// # } + /// ``` + #[unstable(feature = "exit_status_error", issue = "84908")] + pub fn exit_ok(self) -> Result { + self.status.exit_ok()?; + Ok(self) + } +} + // If either stderr or stdout are valid utf8 strings it prints the valid // strings, otherwise it prints the byte sequence instead #[stable(feature = "process_output_debug", since = "1.7.0")] From f8edc831caa53cd08879f93dcf11b6e6daf5d1a5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Apr 2025 10:05:20 +1000 Subject: [PATCH 153/222] Pretty-print `PatKind::Missing` as `_`. Printing "no pattern" as `_` isn't ideal, but better than crashing, and HIR pretty-printing already has plenty of imperfections. The added `f2` and `f6` examples are ones that triggered the crash. Note that some of the added examples are printed badly, e.g. `fn(, ...)`. The next commit will fix those. Fixes #139633. --- compiler/rustc_hir_pretty/src/lib.rs | 7 +++--- tests/pretty/hir-fn-variadic.pp | 36 ++++++++++++++++++++++++++++ tests/pretty/hir-fn-variadic.rs | 16 +++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e5ab317685f9..9cae080aeb34 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1871,10 +1871,11 @@ impl<'a> State<'a> { fn print_pat(&mut self, pat: &hir::Pat<'_>) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); - // Pat isn't normalized, but the beauty of it - // is that it doesn't matter + // Pat isn't normalized, but the beauty of it is that it doesn't matter. match pat.kind { - PatKind::Missing => unreachable!(), + // Printing `_` isn't ideal for a missing pattern, but it's easy and good enough. + // E.g. `fn(u32)` gets printed as `fn(_: u32)`. + PatKind::Missing => self.word("_"), PatKind::Wild => self.word("_"), PatKind::Never => self.word("!"), PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => { diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index dfbaff696440..136e8b44ec20 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -13,3 +13,39 @@ extern "C" { } unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::() } + +fn main() { + fn g1(_: extern "C" fn(_: u8, va: ...)) { } + fn g2(_: extern "C" fn(_: u8, ...)) { } + fn g3(_: extern "C" fn(u8, va: ...)) { } + fn g4(_: extern "C" fn(u8, ...)) { } + + fn g5(_: extern "C" fn(, va: ...)) { } + fn g6(_: extern "C" fn(, ...)) { } + + { + let _ = + { + unsafe extern "C" fn f1(_: u8, va: ...) { } + }; + }; + { + let _ = + { + unsafe extern "C" fn f2(_: u8, _: ...) { } + }; + }; + + { + let _ = + { + unsafe extern "C" fn f5(, va: ...) { } + }; + }; + { + let _ = + { + unsafe extern "C" fn f6(, _: ...) { } + }; + }; +} diff --git a/tests/pretty/hir-fn-variadic.rs b/tests/pretty/hir-fn-variadic.rs index 3d3f7ee18315..99aa402c480b 100644 --- a/tests/pretty/hir-fn-variadic.rs +++ b/tests/pretty/hir-fn-variadic.rs @@ -11,3 +11,19 @@ extern "C" { pub unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::() } + +fn main() { + fn g1(_: extern "C" fn(_: u8, va: ...)) {} + fn g2(_: extern "C" fn(_: u8, ...)) {} + fn g3(_: extern "C" fn(u8, va: ...)) {} + fn g4(_: extern "C" fn(u8, ...)) {} + + fn g5(_: extern "C" fn(va: ...)) {} + fn g6(_: extern "C" fn(...)) {} + + _ = { unsafe extern "C" fn f1(_: u8, va: ...) {} }; + _ = { unsafe extern "C" fn f2(_: u8, ...) {} }; + + _ = { unsafe extern "C" fn f5(va: ...) {} }; + _ = { unsafe extern "C" fn f6(...) {} }; +} From 16670e167664e8ba7f2c1dcd6654988b37b4478e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Apr 2025 10:17:32 +1000 Subject: [PATCH 154/222] Fix HIR pretty-printing of fns with just a variadic arg. Avoid the extraneous comma. --- compiler/rustc_hir_pretty/src/lib.rs | 4 +++- tests/pretty/hir-fn-variadic.pp | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9cae080aeb34..ff4385c3bcce 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2165,7 +2165,9 @@ impl<'a> State<'a> { s.end(); }); if decl.c_variadic { - self.word(", "); + if !decl.inputs.is_empty() { + self.word(", "); + } print_arg(self, None); self.word("..."); } diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index 136e8b44ec20..b6bc8e95127f 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -20,8 +20,8 @@ fn main() { fn g3(_: extern "C" fn(u8, va: ...)) { } fn g4(_: extern "C" fn(u8, ...)) { } - fn g5(_: extern "C" fn(, va: ...)) { } - fn g6(_: extern "C" fn(, ...)) { } + fn g5(_: extern "C" fn(va: ...)) { } + fn g6(_: extern "C" fn(...)) { } { let _ = @@ -39,13 +39,13 @@ fn main() { { let _ = { - unsafe extern "C" fn f5(, va: ...) { } + unsafe extern "C" fn f5(va: ...) { } }; }; { let _ = { - unsafe extern "C" fn f6(, _: ...) { } + unsafe extern "C" fn f6(_: ...) { } }; }; } From 1376810d44d62dc7e8146f988e41aa2a9f641cf8 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Tue, 15 Apr 2025 02:34:32 +0100 Subject: [PATCH 155/222] Basic tests of MPMC receiver cloning Ref: https://github.com/rust-lang/rust/issues/126840#issuecomment-2802321146 --- library/std/tests/sync/mpmc.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/library/std/tests/sync/mpmc.rs b/library/std/tests/sync/mpmc.rs index 81b92297f76a..78abcb3bcbe1 100644 --- a/library/std/tests/sync/mpmc.rs +++ b/library/std/tests/sync/mpmc.rs @@ -63,6 +63,24 @@ fn smoke_port_gone() { assert!(tx.send(1).is_err()); } +#[test] +fn smoke_receiver_clone() { + let (tx, rx) = channel::(); + let rx2 = rx.clone(); + drop(rx); + tx.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 1); +} + +#[test] +fn smoke_receiver_clone_port_gone() { + let (tx, rx) = channel::(); + let rx2 = rx.clone(); + drop(rx); + drop(rx2); + assert!(tx.send(1).is_err()); +} + #[test] fn smoke_shared_port_gone() { let (tx, rx) = channel::(); @@ -124,6 +142,18 @@ fn chan_gone_concurrent() { while rx.recv().is_ok() {} } +#[test] +fn receiver_cloning() { + let (tx, rx) = channel::(); + let rx2 = rx.clone(); + + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + assert_eq!(rx2.recv(), Ok(1)); + assert_eq!(rx.recv(), Ok(2)); +} + #[test] fn stress() { let count = if cfg!(miri) { 100 } else { 10000 }; From e53f2a01cea46bd7f9181e76353bde190255ea20 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Apr 2025 12:26:37 +1000 Subject: [PATCH 156/222] Remove some `kw::Empty` uses in rustdoc. Some `unwrap` uses here, but they are on paths involving item kinds that are known to have an identifier. --- src/librustdoc/clean/mod.rs | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 45a915719e9f..736dd3a1d865 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -117,7 +117,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< hir::ItemKind::Use(path, kind) => { let hir::UsePath { segments, span, .. } = *path; let path = hir::Path { segments, res: *res, span }; - clean_use_statement_inner(import, name, &path, kind, cx, &mut Default::default()) + clean_use_statement_inner(import, Some(name), &path, kind, cx, &mut Default::default()) } _ => unreachable!(), } @@ -125,8 +125,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< items.extend(doc.items.values().flat_map(|(item, renamed, _)| { // Now we actually lower the imports, skipping everything else. if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { - let name = renamed.unwrap_or(kw::Empty); // using kw::Empty is a bit of a hack - clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted) + clean_use_statement(item, *renamed, path, hir::UseKind::Glob, cx, &mut inserted) } else { // skip everything else Vec::new() @@ -2792,10 +2791,11 @@ fn clean_maybe_renamed_item<'tcx>( use hir::ItemKind; let def_id = item.owner_id.to_def_id(); - let mut name = renamed.unwrap_or_else(|| { - // FIXME: using kw::Empty is a bit of a hack - cx.tcx.hir_opt_name(item.hir_id()).unwrap_or(kw::Empty) - }); + let mut name = if renamed.is_some() { + renamed + } else { + cx.tcx.hir_opt_name(item.hir_id()) + }; cx.with_param_env(def_id, |cx| { let kind = match item.kind { @@ -2836,7 +2836,7 @@ fn clean_maybe_renamed_item<'tcx>( item_type: Some(type_), })), item.owner_id.def_id.to_def_id(), - name, + name.unwrap(), import_id, renamed, )); @@ -2861,13 +2861,15 @@ fn clean_maybe_renamed_item<'tcx>( }), ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx), ItemKind::Macro(_, macro_def, MacroKind::Bang) => MacroItem(Macro { - source: display_macro_source(cx, name, macro_def), + source: display_macro_source(cx, name.unwrap(), macro_def), macro_rules: macro_def.macro_rules, }), - ItemKind::Macro(_, _, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx), + ItemKind::Macro(_, _, macro_kind) => { + clean_proc_macro(item, name.as_mut().unwrap(), macro_kind, cx) + } // proc macros can have a name set by attributes ItemKind::Fn { ref sig, generics, body: body_id, .. } => { - clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) + clean_fn_or_proc_macro(item, sig, generics, body_id, name.as_mut().unwrap(), cx) } ItemKind::Trait(_, _, _, generics, bounds, item_ids) => { let items = item_ids @@ -2883,7 +2885,7 @@ fn clean_maybe_renamed_item<'tcx>( })) } ItemKind::ExternCrate(orig_name, _) => { - return clean_extern_crate(item, name, orig_name, cx); + return clean_extern_crate(item, name.unwrap(), orig_name, cx); } ItemKind::Use(path, kind) => { return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default()); @@ -2895,7 +2897,7 @@ fn clean_maybe_renamed_item<'tcx>( cx, kind, item.owner_id.def_id.to_def_id(), - name, + name.unwrap(), import_id, renamed, )] @@ -3006,7 +3008,7 @@ fn clean_extern_crate<'tcx>( fn clean_use_statement<'tcx>( import: &hir::Item<'tcx>, - name: Symbol, + name: Option, path: &hir::UsePath<'tcx>, kind: hir::UseKind, cx: &mut DocContext<'tcx>, @@ -3023,7 +3025,7 @@ fn clean_use_statement<'tcx>( fn clean_use_statement_inner<'tcx>( import: &hir::Item<'tcx>, - name: Symbol, + name: Option, path: &hir::Path<'tcx>, kind: hir::UseKind, cx: &mut DocContext<'tcx>, @@ -3042,7 +3044,7 @@ fn clean_use_statement_inner<'tcx>( let visibility = cx.tcx.visibility(import.owner_id); let attrs = cx.tcx.hir_attrs(import.hir_id()); let inline_attr = hir_attr_lists(attrs, sym::doc).get_word_attr(sym::inline); - let pub_underscore = visibility.is_public() && name == kw::Underscore; + let pub_underscore = visibility.is_public() && name == Some(kw::Underscore); let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id); let import_def_id = import.owner_id.def_id; @@ -3108,6 +3110,7 @@ fn clean_use_statement_inner<'tcx>( } Import::new_glob(resolve_use_source(cx, path), true) } else { + let name = name.unwrap(); if inline_attr.is_none() && let Res::Def(DefKind::Mod, did) = path.res && !did.is_local() From e21691529549152625a509e7e69af0b813420c53 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 12 Feb 2025 08:06:34 -0600 Subject: [PATCH 157/222] Stabilize `-Zdwarf-version` as `-Cdwarf-version` --- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 3 +++ compiler/rustc_session/src/session.rs | 10 ++++++++-- src/doc/rustc/src/codegen-options/index.md | 13 +++++++++++++ .../src/compiler-flags/dwarf-version.md | 13 ------------- .../auxiliary/dwarf-mixed-versions-lto-aux.rs | 2 +- tests/assembly/dwarf-mixed-versions-lto.rs | 2 +- tests/assembly/dwarf4.rs | 4 ++-- tests/assembly/dwarf5.rs | 4 ++-- tests/run-make/embed-source-dwarf/rmake.rs | 2 +- tests/ui/debuginfo/dwarf-versions.rs | 16 ++++++++-------- .../auxiliary/dwarf-mixed-versions-lto-aux.rs | 2 +- tests/ui/lto/dwarf-mixed-versions-lto.rs | 2 +- 13 files changed, 42 insertions(+), 32 deletions(-) delete mode 100644 src/doc/unstable-book/src/compiler-flags/dwarf-version.md diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 75a1b61b4165..d405d044cae6 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -614,6 +614,7 @@ fn test_codegen_options_tracking_hash() { tracked!(control_flow_guard, CFGuard::Checks); tracked!(debug_assertions, Some(true)); tracked!(debuginfo, DebugInfo::Limited); + tracked!(dwarf_version, Some(5)); tracked!(embed_bitcode, false); tracked!(force_frame_pointers, FramePointer::Always); tracked!(force_unwind_tables, Some(true)); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c70f1500d393..ea3a1f8bd8cc 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1956,6 +1956,9 @@ options! { "allow the linker to link its default libraries (default: no)"), dlltool: Option = (None, parse_opt_pathbuf, [UNTRACKED], "import library generation tool (ignored except when targeting windows-gnu)"), + #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")] + dwarf_version: Option = (None, parse_opt_number, [TRACKED], + "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), embed_bitcode: bool = (true, parse_bool, [TRACKED], "emit bitcode in rlibs (default: yes)"), extra_filename: String = (String::new(), parse_string, [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1359f7eb7bb4..010ae42c2802 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -764,7 +764,11 @@ impl Session { /// Returns the DWARF version passed on the CLI or the default for the target. pub fn dwarf_version(&self) -> u32 { - self.opts.unstable_opts.dwarf_version.unwrap_or(self.target.default_dwarf_version) + self.opts + .cg + .dwarf_version + .or(self.opts.unstable_opts.dwarf_version) + .unwrap_or(self.target.default_dwarf_version) } pub fn stack_protector(&self) -> StackProtector { @@ -1327,7 +1331,9 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.dcx().emit_err(errors::BranchProtectionRequiresAArch64); } - if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version { + if let Some(dwarf_version) = + sess.opts.cg.dwarf_version.or(sess.opts.unstable_opts.dwarf_version) + { // DWARF 1 is not supported by LLVM and DWARF 6 is not yet finalized. if dwarf_version < 2 || dwarf_version > 5 { sess.dcx().emit_err(errors::UnsupportedDwarfVersion { dwarf_version }); diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 8c1769a8c772..a3b70e7f9771 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -110,6 +110,19 @@ It takes a path to [the dlltool executable](https://sourceware.org/binutils/docs If this flag is not specified, a dlltool executable will be inferred based on the host environment and target. +## dwarf-version + +This option controls the version of DWARF that the compiler emits, on platforms +that use DWARF to encode debug information. It takes one of the following +values: + +* `2`: DWARF version 2 (the default on certain platforms, like Android). +* `3`: DWARF version 3 (the default on certain platforms, like AIX). +* `4`: DWARF version 4 (the default on most platforms, like Linux & macOS). +* `5`: DWARF version 5. + +DWARF version 1 is not supported. + ## embed-bitcode This flag controls whether or not the compiler embeds LLVM bitcode into object diff --git a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md deleted file mode 100644 index e88799d2cf04..000000000000 --- a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md +++ /dev/null @@ -1,13 +0,0 @@ -## `dwarf-version` - -The tracking issue for this feature is: - ----------------------------- - -This option controls the version of DWARF that the compiler emits, on platforms -that use DWARF to encode debug information. It takes one of the following -values: - -* `2`: DWARF version 2 (the default on certain platforms, like macOS). -* `4`: DWARF version 4 (the default on certain platforms, like Linux). -* `5`: DWARF version 5. diff --git a/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs b/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs index faff6e7e2d05..257608f881f1 100644 --- a/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs +++ b/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -g --crate-type=rlib -Zdwarf-version=4 +//@ compile-flags: -g --crate-type=rlib -Cdwarf-version=4 pub fn check_is_even(number: &u64) -> bool { number % 2 == 0 diff --git a/tests/assembly/dwarf-mixed-versions-lto.rs b/tests/assembly/dwarf-mixed-versions-lto.rs index f1fc0814c9db..9910a6e2f5fc 100644 --- a/tests/assembly/dwarf-mixed-versions-lto.rs +++ b/tests/assembly/dwarf-mixed-versions-lto.rs @@ -4,7 +4,7 @@ //@ only-linux //@ aux-build:dwarf-mixed-versions-lto-aux.rs -//@ compile-flags: -C lto -g -Zdwarf-version=5 +//@ compile-flags: -C lto -g -Cdwarf-version=5 //@ assembly-output: emit-asm //@ no-prefer-dynamic diff --git a/tests/assembly/dwarf4.rs b/tests/assembly/dwarf4.rs index 6013adf3386a..03a388603b44 100644 --- a/tests/assembly/dwarf4.rs +++ b/tests/assembly/dwarf4.rs @@ -1,7 +1,7 @@ -// Makes sure that `-Z dwarf-version=4` causes `rustc` to emit DWARF version 4. +// Makes sure that `-C dwarf-version=4` causes `rustc` to emit DWARF version 4. //@ assembly-output: emit-asm //@ add-core-stubs -//@ compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=4 -Copt-level=0 +//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=4 -Copt-level=0 //@ needs-llvm-components: x86 #![feature(no_core, lang_items)] diff --git a/tests/assembly/dwarf5.rs b/tests/assembly/dwarf5.rs index 9cd596e78345..9bd92cc0d097 100644 --- a/tests/assembly/dwarf5.rs +++ b/tests/assembly/dwarf5.rs @@ -1,7 +1,7 @@ -// Makes sure that `-Z dwarf-version=5` causes `rustc` to emit DWARF version 5. +// Makes sure that `-C dwarf-version=5` causes `rustc` to emit DWARF version 5. //@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=5 -Copt-level=0 +//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=5 -Copt-level=0 //@ needs-llvm-components: x86 #![feature(no_core, lang_items)] diff --git a/tests/run-make/embed-source-dwarf/rmake.rs b/tests/run-make/embed-source-dwarf/rmake.rs index 0aae07ff2e64..550c8b9b3c90 100644 --- a/tests/run-make/embed-source-dwarf/rmake.rs +++ b/tests/run-make/embed-source-dwarf/rmake.rs @@ -21,7 +21,7 @@ fn main() { .output(&output) .arg("-g") .arg("-Zembed-source=yes") - .arg("-Zdwarf-version=5") + .arg("-Cdwarf-version=5") .run(); let output = rfs::read(output); let obj = object::File::parse(output.as_slice()).unwrap(); diff --git a/tests/ui/debuginfo/dwarf-versions.rs b/tests/ui/debuginfo/dwarf-versions.rs index bb18cadce435..8f731f10ead4 100644 --- a/tests/ui/debuginfo/dwarf-versions.rs +++ b/tests/ui/debuginfo/dwarf-versions.rs @@ -1,25 +1,25 @@ // This test verifies the expected behavior of various options passed to -// `-Zdwarf-version`: 2 - 5 (valid) with all other options being invalid. +// `-Cdwarf-version`: 2 - 5 (valid) with all other options being invalid. //@ revisions: zero one two three four five six -//@[zero] compile-flags: -Zdwarf-version=0 +//@[zero] compile-flags: -Cdwarf-version=0 -//@[one] compile-flags: -Zdwarf-version=1 +//@[one] compile-flags: -Cdwarf-version=1 -//@[two] compile-flags: -Zdwarf-version=2 +//@[two] compile-flags: -Cdwarf-version=2 //@[two] check-pass -//@[three] compile-flags: -Zdwarf-version=3 +//@[three] compile-flags: -Cdwarf-version=3 //@[three] check-pass -//@[four] compile-flags: -Zdwarf-version=4 +//@[four] compile-flags: -Cdwarf-version=4 //@[four] check-pass -//@[five] compile-flags: -Zdwarf-version=5 +//@[five] compile-flags: -Cdwarf-version=5 //@[five] check-pass -//@[six] compile-flags: -Zdwarf-version=6 +//@[six] compile-flags: -Cdwarf-version=6 //@ compile-flags: -g --target x86_64-unknown-linux-gnu --crate-type cdylib //@ needs-llvm-components: x86 diff --git a/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs b/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs index 3c81127ee65c..2f2bf57f42b4 100644 --- a/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs +++ b/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -g --crate-type=rlib -Zdwarf-version=4 +//@ compile-flags: -g --crate-type=rlib -Cdwarf-version=4 pub fn say_hi() { println!("hello there") diff --git a/tests/ui/lto/dwarf-mixed-versions-lto.rs b/tests/ui/lto/dwarf-mixed-versions-lto.rs index 14ef65a868e0..900274eb22f4 100644 --- a/tests/ui/lto/dwarf-mixed-versions-lto.rs +++ b/tests/ui/lto/dwarf-mixed-versions-lto.rs @@ -4,7 +4,7 @@ //@ ignore-msvc Platform must use DWARF //@ aux-build:dwarf-mixed-versions-lto-aux.rs -//@ compile-flags: -C lto -g -Zdwarf-version=5 +//@ compile-flags: -C lto -g -Cdwarf-version=5 //@ no-prefer-dynamic //@ build-pass From 4c23295dd9449d8feacdab476cd98ac7a7e27eec Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 3 Apr 2025 16:17:16 +1100 Subject: [PATCH 158/222] Use a constant for unstable features needed by compiletest --- src/bootstrap/src/core/build_steps/check.rs | 4 ++-- src/bootstrap/src/core/build_steps/test.rs | 4 ++-- src/bootstrap/src/core/build_steps/tool.rs | 13 ++++++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index b191d0f6b306..ae9511b78674 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -3,7 +3,7 @@ use crate::core::build_steps::compile::{ add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make, }; -use crate::core::build_steps::tool::{SourceType, prepare_tool_cargo}; +use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo}; use crate::core::builder::{ self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description, }; @@ -416,7 +416,7 @@ impl Step for Compiletest { &[], ); - cargo.allow_features("test"); + cargo.allow_features(COMPILETEST_ALLOW_FEATURES); // For ./x.py clippy, don't run with --all-targets because // linting tests and benchmarks can produce very noisy results diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index e23c1ab5a238..b1a3bba08871 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -15,7 +15,7 @@ use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; -use crate::core::build_steps::tool::{self, SourceType, Tool}; +use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool}; use crate::core::build_steps::toolstate::ToolState; use crate::core::build_steps::{compile, dist, llvm}; use crate::core::builder::{ @@ -721,7 +721,7 @@ impl Step for CompiletestTest { SourceType::InTree, &[], ); - cargo.allow_features("test"); + cargo.allow_features(COMPILETEST_ALLOW_FEATURES); run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder); } } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index ded7220fcedc..528a45d215bf 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -444,7 +444,11 @@ macro_rules! bootstrap_tool { SourceType::InTree }, extra_features: vec![], - allow_features: concat!($($allow_features)*), + allow_features: { + let mut _value = ""; + $( _value = $allow_features; )? + _value + }, cargo_args: vec![], artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* { ToolArtifactKind::Library @@ -458,6 +462,8 @@ macro_rules! bootstrap_tool { } } +pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "test"; + bootstrap_tool!( // This is marked as an external tool because it includes dependencies // from submodules. Trying to keep the lints in sync between all the repos @@ -468,7 +474,7 @@ bootstrap_tool!( Tidy, "src/tools/tidy", "tidy"; Linkchecker, "src/tools/linkchecker", "linkchecker"; CargoTest, "src/tools/cargotest", "cargotest"; - Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test"; + Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; BuildManifest, "src/tools/build-manifest", "build-manifest"; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; RustInstaller, "src/tools/rust-installer", "rust-installer"; @@ -483,7 +489,8 @@ bootstrap_tool!( GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; SuggestTests, "src/tools/suggest-tests", "suggest-tests"; GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; - RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test"; + // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features. + RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization"; UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator"; From 6fda3e52c94d2b84678133ea339996629f47fcf2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 11 Apr 2025 16:10:09 +1000 Subject: [PATCH 159/222] compiletest: Extract libtest-specific executor code to a submodule --- src/tools/compiletest/src/executor.rs | 103 +--------------- src/tools/compiletest/src/executor/libtest.rs | 111 ++++++++++++++++++ src/tools/compiletest/src/lib.rs | 2 +- 3 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 src/tools/compiletest/src/executor/libtest.rs diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 527d6b8a36eb..49764479dd69 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -4,20 +4,11 @@ //! This will hopefully make it easier to migrate away from libtest someday. use std::borrow::Cow; -use std::io; use std::sync::Arc; use crate::common::{Config, TestPaths}; -/// Delegates to libtest to run the list of collected tests. -/// -/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed. -pub(crate) fn execute_tests(config: &Config, tests: Vec) -> io::Result { - let opts = test_opts(config); - let tests = tests.into_iter().map(|t| t.into_libtest()).collect::>(); - - test::run_tests_console(&opts, tests) -} +pub(crate) mod libtest; /// Information needed to create a `test::TestDescAndFn`. pub(crate) struct CollectedTest { @@ -35,45 +26,6 @@ pub(crate) struct CollectedTestDesc { pub(crate) should_panic: ShouldPanic, } -impl CollectedTest { - fn into_libtest(self) -> test::TestDescAndFn { - let Self { desc, config, testpaths, revision } = self; - let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc; - - // Libtest requires the ignore message to be a &'static str, so we might - // have to leak memory to create it. This is fine, as we only do so once - // per test, so the leak won't grow indefinitely. - let ignore_message = ignore_message.map(|msg| match msg { - Cow::Borrowed(s) => s, - Cow::Owned(s) => &*String::leak(s), - }); - - let desc = test::TestDesc { - name: test::DynTestName(name), - ignore, - ignore_message, - source_file: "", - start_line: 0, - start_col: 0, - end_line: 0, - end_col: 0, - should_panic: should_panic.to_libtest(), - compile_fail: false, - no_run: false, - test_type: test::TestType::Unknown, - }; - - // This closure is invoked when libtest returns control to compiletest - // to execute the test. - let testfn = test::DynTestFn(Box::new(move || { - crate::runtest::run(config, &testpaths, revision.as_deref()); - Ok(()) - })); - - test::TestDescAndFn { desc, testfn } - } -} - /// Whether console output should be colored or not. #[derive(Copy, Clone, Default, Debug)] pub enum ColorConfig { @@ -83,16 +35,6 @@ pub enum ColorConfig { NeverColor, } -impl ColorConfig { - fn to_libtest(self) -> test::ColorConfig { - match self { - Self::AutoColor => test::ColorConfig::AutoColor, - Self::AlwaysColor => test::ColorConfig::AlwaysColor, - Self::NeverColor => test::ColorConfig::NeverColor, - } - } -} - /// Format of the test results output. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum OutputFormat { @@ -105,52 +47,9 @@ pub enum OutputFormat { Json, } -impl OutputFormat { - fn to_libtest(self) -> test::OutputFormat { - match self { - Self::Pretty => test::OutputFormat::Pretty, - Self::Terse => test::OutputFormat::Terse, - Self::Json => test::OutputFormat::Json, - } - } -} - /// Whether test is expected to panic or not. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub(crate) enum ShouldPanic { No, Yes, } - -impl ShouldPanic { - fn to_libtest(self) -> test::ShouldPanic { - match self { - Self::No => test::ShouldPanic::No, - Self::Yes => test::ShouldPanic::Yes, - } - } -} - -fn test_opts(config: &Config) -> test::TestOpts { - test::TestOpts { - exclude_should_panic: false, - filters: config.filters.clone(), - filter_exact: config.filter_exact, - run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, - format: config.format.to_libtest(), - logfile: None, - run_tests: true, - bench_benchmarks: true, - nocapture: config.nocapture, - color: config.color.to_libtest(), - shuffle: false, - shuffle_seed: None, - test_threads: None, - skip: config.skip.clone(), - list: false, - options: test::Options::new(), - time_options: None, - force_run_in_process: false, - fail_fast: config.fail_fast, - } -} diff --git a/src/tools/compiletest/src/executor/libtest.rs b/src/tools/compiletest/src/executor/libtest.rs new file mode 100644 index 000000000000..032b3f4fa9a8 --- /dev/null +++ b/src/tools/compiletest/src/executor/libtest.rs @@ -0,0 +1,111 @@ +//! This submodule encapsulates all of the code that actually interacts with +//! libtest, so that it can be easily removed after the new executor becomes +//! the default. + +use std::borrow::Cow; +use std::io; + +use crate::common::Config; +use crate::executor::{CollectedTest, CollectedTestDesc, ColorConfig, OutputFormat, ShouldPanic}; + +/// Delegates to libtest to run the list of collected tests. +/// +/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed. +pub(crate) fn execute_tests(config: &Config, tests: Vec) -> io::Result { + let opts = test_opts(config); + let tests = tests.into_iter().map(|t| t.into_libtest()).collect::>(); + + test::run_tests_console(&opts, tests) +} + +impl CollectedTest { + fn into_libtest(self) -> test::TestDescAndFn { + let Self { desc, config, testpaths, revision } = self; + let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc; + + // Libtest requires the ignore message to be a &'static str, so we might + // have to leak memory to create it. This is fine, as we only do so once + // per test, so the leak won't grow indefinitely. + let ignore_message = ignore_message.map(|msg| match msg { + Cow::Borrowed(s) => s, + Cow::Owned(s) => &*String::leak(s), + }); + + let desc = test::TestDesc { + name: test::DynTestName(name), + ignore, + ignore_message, + source_file: "", + start_line: 0, + start_col: 0, + end_line: 0, + end_col: 0, + should_panic: should_panic.to_libtest(), + compile_fail: false, + no_run: false, + test_type: test::TestType::Unknown, + }; + + // This closure is invoked when libtest returns control to compiletest + // to execute the test. + let testfn = test::DynTestFn(Box::new(move || { + crate::runtest::run(config, &testpaths, revision.as_deref()); + Ok(()) + })); + + test::TestDescAndFn { desc, testfn } + } +} + +impl ColorConfig { + fn to_libtest(self) -> test::ColorConfig { + match self { + Self::AutoColor => test::ColorConfig::AutoColor, + Self::AlwaysColor => test::ColorConfig::AlwaysColor, + Self::NeverColor => test::ColorConfig::NeverColor, + } + } +} + +impl OutputFormat { + fn to_libtest(self) -> test::OutputFormat { + match self { + Self::Pretty => test::OutputFormat::Pretty, + Self::Terse => test::OutputFormat::Terse, + Self::Json => test::OutputFormat::Json, + } + } +} + +impl ShouldPanic { + fn to_libtest(self) -> test::ShouldPanic { + match self { + Self::No => test::ShouldPanic::No, + Self::Yes => test::ShouldPanic::Yes, + } + } +} + +fn test_opts(config: &Config) -> test::TestOpts { + test::TestOpts { + exclude_should_panic: false, + filters: config.filters.clone(), + filter_exact: config.filter_exact, + run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, + format: config.format.to_libtest(), + logfile: None, + run_tests: true, + bench_benchmarks: true, + nocapture: config.nocapture, + color: config.color.to_libtest(), + shuffle: false, + shuffle_seed: None, + test_threads: None, + skip: config.skip.clone(), + list: false, + options: test::Options::new(), + time_options: None, + force_run_in_process: false, + fail_fast: config.fail_fast, + } +} diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index b969b22750bc..72bb4101dd20 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -573,7 +573,7 @@ pub fn run_tests(config: Arc) { // Delegate to libtest to filter and run the big list of structures created // during test discovery. When libtest decides to run a test, it will // return control to compiletest by invoking a closure. - let res = crate::executor::execute_tests(&config, tests); + let res = crate::executor::libtest::execute_tests(&config, tests); // Check the outcome reported by libtest. match res { From e3d68139200da0e5010321b286e3e15e4a9530e0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 6 Apr 2025 10:48:44 +1000 Subject: [PATCH 160/222] compiletest: Add an experimental new executor to replace libtest The new executor can be enabled by passing `--new-executor` or `-n` to compiletest. For example: `./x test ui -- -n` --- src/bootstrap/src/core/build_steps/tool.rs | 2 +- src/tools/compiletest/src/common.rs | 5 + src/tools/compiletest/src/executor.rs | 248 +++++++++++++++++- .../compiletest/src/executor/deadline.rs | 78 ++++++ src/tools/compiletest/src/executor/json.rs | 111 ++++++++ src/tools/compiletest/src/lib.rs | 20 +- 6 files changed, 452 insertions(+), 12 deletions(-) create mode 100644 src/tools/compiletest/src/executor/deadline.rs create mode 100644 src/tools/compiletest/src/executor/json.rs diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 528a45d215bf..3426da51a808 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -462,7 +462,7 @@ macro_rules! bootstrap_tool { } } -pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "test"; +pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "test,internal_output_capture"; bootstrap_tool!( // This is marked as an external tool because it includes dependencies diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 604c5fcbddff..31c696ed41ff 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -414,6 +414,11 @@ pub struct Config { /// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g. /// ABI tests. pub minicore_path: Utf8PathBuf, + + /// If true, run tests with the "new" executor that was written to replace + /// compiletest's dependency on libtest. Eventually this will become the + /// default, and the libtest dependency will be removed. + pub new_executor: bool, } impl Config { diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 49764479dd69..0c173d476aff 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -1,15 +1,253 @@ -//! This module encapsulates all of the code that interacts directly with -//! libtest, to execute the collected tests. -//! -//! This will hopefully make it easier to migrate away from libtest someday. +//! This module contains a reimplementation of the subset of libtest +//! functionality needed by compiletest. use std::borrow::Cow; -use std::sync::Arc; +use std::collections::HashMap; +use std::hash::{BuildHasherDefault, DefaultHasher}; +use std::num::NonZero; +use std::sync::{Arc, Mutex, mpsc}; +use std::{env, hint, io, mem, panic, thread}; use crate::common::{Config, TestPaths}; +mod deadline; +mod json; pub(crate) mod libtest; +pub(crate) fn run_tests(config: &Config, tests: Vec) -> bool { + let tests_len = tests.len(); + let filtered = filter_tests(config, tests); + // Iterator yielding tests that haven't been started yet. + let mut fresh_tests = (0..).map(TestId).zip(&filtered); + + let concurrency = get_concurrency(); + assert!(concurrency > 0); + let concurrent_capacity = concurrency.min(filtered.len()); + + let mut listener = json::Listener::new(); + let mut running_tests = HashMap::with_capacity_and_hasher( + concurrent_capacity, + BuildHasherDefault::::new(), + ); + let mut deadline_queue = deadline::DeadlineQueue::with_capacity(concurrent_capacity); + + let num_filtered_out = tests_len - filtered.len(); + listener.suite_started(filtered.len(), num_filtered_out); + + // Channel used by test threads to report the test outcome when done. + let (completion_tx, completion_rx) = mpsc::channel::(); + + // Unlike libtest, we don't have a separate code path for concurrency=1. + // In that case, the tests will effectively be run serially anyway. + loop { + // Spawn new test threads, up to the concurrency limit. + // FIXME(let_chains): Use a let-chain here when stable in bootstrap. + 'spawn: while running_tests.len() < concurrency { + let Some((id, test)) = fresh_tests.next() else { break 'spawn }; + listener.test_started(test); + deadline_queue.push(id, test); + let join_handle = spawn_test_thread(id, test, completion_tx.clone()); + running_tests.insert(id, RunningTest { test, join_handle }); + } + + // If all running tests have finished, and there weren't any unstarted + // tests to spawn, then we're done. + if running_tests.is_empty() { + break; + } + + let completion = deadline_queue + .read_channel_while_checking_deadlines(&completion_rx, |_id, test| { + listener.test_timed_out(test); + }) + .expect("receive channel should never be closed early"); + + let RunningTest { test, join_handle } = running_tests.remove(&completion.id).unwrap(); + if let Some(join_handle) = join_handle { + join_handle.join().unwrap_or_else(|_| { + panic!("thread for `{}` panicked after reporting completion", test.desc.name) + }); + } + + listener.test_finished(test, &completion); + + if completion.outcome.is_failed() && config.fail_fast { + // Prevent any other in-flight threads from panicking when they + // write to the completion channel. + mem::forget(completion_rx); + break; + } + } + + let suite_passed = listener.suite_finished(); + suite_passed +} + +/// Spawns a thread to run a single test, and returns the thread's join handle. +/// +/// Returns `None` if the test was ignored, so no thread was spawned. +fn spawn_test_thread( + id: TestId, + test: &CollectedTest, + completion_tx: mpsc::Sender, +) -> Option> { + if test.desc.ignore && !test.config.run_ignored { + completion_tx + .send(TestCompletion { id, outcome: TestOutcome::Ignored, stdout: None }) + .unwrap(); + return None; + } + + let runnable_test = RunnableTest::new(test); + let should_panic = test.desc.should_panic; + let run_test = move || run_test_inner(id, should_panic, runnable_test, completion_tx); + + let thread_builder = thread::Builder::new().name(test.desc.name.clone()); + let join_handle = thread_builder.spawn(run_test).unwrap(); + Some(join_handle) +} + +/// Runs a single test, within the dedicated thread spawned by the caller. +fn run_test_inner( + id: TestId, + should_panic: ShouldPanic, + runnable_test: RunnableTest, + completion_sender: mpsc::Sender, +) { + let is_capture = !runnable_test.config.nocapture; + let capture_buf = is_capture.then(|| Arc::new(Mutex::new(vec![]))); + + if let Some(capture_buf) = &capture_buf { + io::set_output_capture(Some(Arc::clone(capture_buf))); + } + + let panic_payload = panic::catch_unwind(move || runnable_test.run()).err(); + + if is_capture { + io::set_output_capture(None); + } + + let outcome = match (should_panic, panic_payload) { + (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded, + (ShouldPanic::No, Some(_)) => TestOutcome::Failed { message: None }, + (ShouldPanic::Yes, None) => { + TestOutcome::Failed { message: Some("test did not panic as expected") } + } + }; + let stdout = capture_buf.map(|mutex| mutex.lock().unwrap_or_else(|e| e.into_inner()).to_vec()); + + completion_sender.send(TestCompletion { id, outcome, stdout }).unwrap(); +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +struct TestId(usize); + +struct RunnableTest { + config: Arc, + testpaths: TestPaths, + revision: Option, +} + +impl RunnableTest { + fn new(test: &CollectedTest) -> Self { + let config = Arc::clone(&test.config); + let testpaths = test.testpaths.clone(); + let revision = test.revision.clone(); + Self { config, testpaths, revision } + } + + fn run(&self) { + __rust_begin_short_backtrace(|| { + crate::runtest::run( + Arc::clone(&self.config), + &self.testpaths, + self.revision.as_deref(), + ); + }); + } +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +#[inline(never)] +fn __rust_begin_short_backtrace T>(f: F) -> T { + let result = f(); + + // prevent this frame from being tail-call optimised away + hint::black_box(result) +} + +struct RunningTest<'a> { + test: &'a CollectedTest, + join_handle: Option>, +} + +/// Test completion message sent by individual test threads when their test +/// finishes (successfully or unsuccessfully). +struct TestCompletion { + id: TestId, + outcome: TestOutcome, + stdout: Option>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +enum TestOutcome { + Succeeded, + Failed { message: Option<&'static str> }, + Ignored, +} + +impl TestOutcome { + fn is_failed(&self) -> bool { + matches!(self, Self::Failed { .. }) + } +} + +/// Applies command-line arguments for filtering/skipping tests by name. +/// +/// Adapted from `filter_tests` in libtest. +/// +/// FIXME(#139660): After the libtest dependency is removed, redesign the whole +/// filtering system to do a better job of understanding and filtering _paths_, +/// instead of being tied to libtest's substring/exact matching behaviour. +fn filter_tests(opts: &Config, tests: Vec) -> Vec { + let mut filtered = tests; + + let matches_filter = |test: &CollectedTest, filter_str: &str| { + let test_name = &test.desc.name; + if opts.filter_exact { test_name == filter_str } else { test_name.contains(filter_str) } + }; + + // Remove tests that don't match the test filter + if !opts.filters.is_empty() { + filtered.retain(|test| opts.filters.iter().any(|filter| matches_filter(test, filter))); + } + + // Skip tests that match any of the skip filters + if !opts.skip.is_empty() { + filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf))); + } + + filtered +} + +/// Determines the number of tests to run concurrently. +/// +/// Copied from `get_concurrency` in libtest. +/// +/// FIXME(#139660): After the libtest dependency is removed, consider making +/// bootstrap specify the number of threads on the command-line, instead of +/// propagating the `RUST_TEST_THREADS` environment variable. +fn get_concurrency() -> usize { + if let Ok(value) = env::var("RUST_TEST_THREADS") { + match value.parse::>().ok() { + Some(n) => n.get(), + _ => panic!("RUST_TEST_THREADS is `{value}`, should be a positive integer."), + } + } else { + thread::available_parallelism().map(|n| n.get()).unwrap_or(1) + } +} + /// Information needed to create a `test::TestDescAndFn`. pub(crate) struct CollectedTest { pub(crate) desc: CollectedTestDesc, diff --git a/src/tools/compiletest/src/executor/deadline.rs b/src/tools/compiletest/src/executor/deadline.rs new file mode 100644 index 000000000000..83b8591a4164 --- /dev/null +++ b/src/tools/compiletest/src/executor/deadline.rs @@ -0,0 +1,78 @@ +use std::collections::VecDeque; +use std::sync::mpsc::{self, RecvError, RecvTimeoutError}; +use std::time::{Duration, Instant}; + +use crate::executor::{CollectedTest, TestId}; + +const TEST_WARN_TIMEOUT_S: u64 = 60; + +struct DeadlineEntry<'a> { + id: TestId, + test: &'a CollectedTest, + deadline: Instant, +} + +pub(crate) struct DeadlineQueue<'a> { + queue: VecDeque>, +} + +impl<'a> DeadlineQueue<'a> { + pub(crate) fn with_capacity(capacity: usize) -> Self { + Self { queue: VecDeque::with_capacity(capacity) } + } + + pub(crate) fn push(&mut self, id: TestId, test: &'a CollectedTest) { + let deadline = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S); + self.queue.push_back(DeadlineEntry { id, test, deadline }); + } + + /// Equivalent to `rx.read()`, except that if any test exceeds its deadline + /// during the wait, the given callback will also be called for that test. + pub(crate) fn read_channel_while_checking_deadlines( + &mut self, + rx: &mpsc::Receiver, + mut on_deadline_passed: impl FnMut(TestId, &CollectedTest), + ) -> Result { + loop { + let Some(next_deadline) = self.next_deadline() else { + // All currently-running tests have already exceeded their + // deadline, so do a normal receive. + return rx.recv(); + }; + let wait_duration = next_deadline.saturating_duration_since(Instant::now()); + + let recv_result = rx.recv_timeout(wait_duration); + match recv_result { + Ok(value) => return Ok(value), + Err(RecvTimeoutError::Timeout) => { + // Notify the callback of tests that have exceeded their + // deadline, then loop and do annother channel read. + for DeadlineEntry { id, test, .. } in self.remove_tests_past_deadline() { + on_deadline_passed(id, test); + } + } + Err(RecvTimeoutError::Disconnected) => return Err(RecvError), + } + } + } + + fn next_deadline(&self) -> Option { + Some(self.queue.front()?.deadline) + } + + fn remove_tests_past_deadline(&mut self) -> Vec> { + let now = Instant::now(); + let mut timed_out = vec![]; + while let Some(deadline_entry) = pop_front_if(&mut self.queue, |entry| now < entry.deadline) + { + timed_out.push(deadline_entry); + } + timed_out + } +} + +/// FIXME(vec_deque_pop_if): Use `VecDeque::pop_front_if` when it is stable in bootstrap. +fn pop_front_if(queue: &mut VecDeque, predicate: impl FnOnce(&T) -> bool) -> Option { + let first = queue.front()?; + if predicate(first) { queue.pop_front() } else { None } +} diff --git a/src/tools/compiletest/src/executor/json.rs b/src/tools/compiletest/src/executor/json.rs new file mode 100644 index 000000000000..c74ed81a36b8 --- /dev/null +++ b/src/tools/compiletest/src/executor/json.rs @@ -0,0 +1,111 @@ +//! Collects statistics and emits suite/test events as JSON messages, using +//! the same JSON format as libtest's JSON formatter. +//! +//! These messages are then parsed by bootstrap, which replaces them with +//! user-friendly terminal output. + +use std::time::Instant; + +use serde_json::json; + +use crate::executor::{CollectedTest, TestCompletion, TestOutcome}; + +pub(crate) struct Listener { + suite_start: Option, + passed: usize, + failed: usize, + ignored: usize, + filtered_out: usize, +} + +impl Listener { + pub(crate) fn new() -> Self { + Self { suite_start: None, passed: 0, failed: 0, ignored: 0, filtered_out: 0 } + } + + fn print_message(&self, message: &serde_json::Value) { + println!("{message}"); + } + + fn now(&self) -> Instant { + Instant::now() + } + + pub(crate) fn suite_started(&mut self, test_count: usize, filtered_out: usize) { + self.suite_start = Some(self.now()); + self.filtered_out = filtered_out; + let message = json!({ "type": "suite", "event": "started", "test_count": test_count }); + self.print_message(&message); + } + + pub(crate) fn test_started(&mut self, test: &CollectedTest) { + let name = test.desc.name.as_str(); + let message = json!({ "type": "test", "event": "started", "name": name }); + self.print_message(&message); + } + + pub(crate) fn test_timed_out(&mut self, test: &CollectedTest) { + let name = test.desc.name.as_str(); + let message = json!({ "type": "test", "event": "timeout", "name": name }); + self.print_message(&message); + } + + pub(crate) fn test_finished(&mut self, test: &CollectedTest, completion: &TestCompletion) { + let event; + let name = test.desc.name.as_str(); + let mut maybe_message = None; + let maybe_stdout = completion.stdout.as_deref().map(String::from_utf8_lossy); + + match completion.outcome { + TestOutcome::Succeeded => { + self.passed += 1; + event = "ok"; + } + TestOutcome::Failed { message } => { + self.failed += 1; + maybe_message = message; + event = "failed"; + } + TestOutcome::Ignored => { + self.ignored += 1; + maybe_message = test.desc.ignore_message.as_deref(); + event = "ignored"; + } + }; + + // This emits optional fields as `null`, instead of omitting them + // completely as libtest does, but bootstrap can parse the result + // either way. + let json = json!({ + "type": "test", + "event": event, + "name": name, + "message": maybe_message, + "stdout": maybe_stdout, + }); + + self.print_message(&json); + } + + pub(crate) fn suite_finished(&mut self) -> bool { + let exec_time = self.suite_start.map(|start| (self.now() - start).as_secs_f64()); + let suite_passed = self.failed == 0; + + let event = if suite_passed { "ok" } else { "failed" }; + let message = json!({ + "type": "suite", + "event": event, + "passed": self.passed, + "failed": self.failed, + "ignored": self.ignored, + // Compiletest doesn't run any benchmarks, but we still need to set this + // field to 0 so that bootstrap's JSON parser can read our message. + "measured": 0, + "filtered_out": self.filtered_out, + "exec_time": exec_time, + }); + + self.print_message(&message); + suite_passed + } +} diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 72bb4101dd20..4bbd4ab4790d 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1,7 +1,8 @@ #![crate_name = "compiletest"] -// The `test` crate is the only unstable feature -// allowed here, just to share similar code. +// Needed by the libtest-based test executor. #![feature(test)] +// Needed by the "new" test executor that does not depend on libtest. +#![feature(internal_output_capture)] extern crate test; @@ -202,6 +203,7 @@ pub fn parse_config(args: Vec) -> Config { "COMMAND", ) .reqopt("", "minicore-path", "path to minicore aux library", "PATH") + .optflag("n", "new-executor", "enables the new test executor instead of using libtest") .optopt( "", "debugger", @@ -447,6 +449,8 @@ pub fn parse_config(args: Vec) -> Config { diff_command: matches.opt_str("compiletest-diff-tool"), minicore_path: opt_path(matches, "minicore-path"), + + new_executor: matches.opt_present("new-executor"), } } @@ -570,10 +574,14 @@ pub fn run_tests(config: Arc) { tests.sort_by(|a, b| Ord::cmp(&a.desc.name, &b.desc.name)); - // Delegate to libtest to filter and run the big list of structures created - // during test discovery. When libtest decides to run a test, it will - // return control to compiletest by invoking a closure. - let res = crate::executor::libtest::execute_tests(&config, tests); + // Delegate to the executor to filter and run the big list of test structures + // created during test discovery. When the executor decides to run a test, + // it will return control to the rest of compiletest by calling `runtest::run`. + let res = if config.new_executor { + Ok(executor::run_tests(&config, tests)) + } else { + crate::executor::libtest::execute_tests(&config, tests) + }; // Check the outcome reported by libtest. match res { From 31320a925f53264a1905c5228392de9638bf2d52 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Apr 2025 12:28:18 +1000 Subject: [PATCH 161/222] Remove another `kw::Empty` use in rustdoc. Again by using `Option` to represent "no name". --- src/librustdoc/clean/mod.rs | 35 ++++++++++++++++-------------- src/librustdoc/clean/types.rs | 4 ++-- src/librustdoc/html/format.rs | 8 ++++--- src/librustdoc/json/conversions.rs | 7 ++++-- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 736dd3a1d865..1bba43cc45fd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -117,7 +117,14 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< hir::ItemKind::Use(path, kind) => { let hir::UsePath { segments, span, .. } = *path; let path = hir::Path { segments, res: *res, span }; - clean_use_statement_inner(import, Some(name), &path, kind, cx, &mut Default::default()) + clean_use_statement_inner( + import, + Some(name), + &path, + kind, + cx, + &mut Default::default(), + ) } _ => unreachable!(), } @@ -1071,10 +1078,10 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib .. } = param { - func.decl - .inputs - .values - .insert(a.get() as _, Argument { name, type_: *ty, is_const: true }); + func.decl.inputs.values.insert( + a.get() as _, + Argument { name: Some(name), type_: *ty, is_const: true }, + ); } else { panic!("unexpected non const in position {pos}"); } @@ -1131,9 +1138,9 @@ fn clean_args_from_types_and_names<'tcx>( // If at least one argument has a name, use `_` as the name of unnamed // arguments. Otherwise omit argument names. let default_name = if idents.iter().any(|ident| nonempty_name(ident).is_some()) { - kw::Underscore + Some(kw::Underscore) } else { - kw::Empty + None }; Arguments { @@ -1142,7 +1149,7 @@ fn clean_args_from_types_and_names<'tcx>( .enumerate() .map(|(i, ty)| Argument { type_: clean_ty(ty, cx), - name: idents.get(i).and_then(nonempty_name).unwrap_or(default_name), + name: idents.get(i).and_then(nonempty_name).or(default_name), is_const: false, }) .collect(), @@ -1161,7 +1168,7 @@ fn clean_args_from_types_and_body_id<'tcx>( .iter() .zip(body.params) .map(|(ty, param)| Argument { - name: name_from_pat(param.pat), + name: Some(name_from_pat(param.pat)), type_: clean_ty(ty, cx), is_const: false, }) @@ -1217,11 +1224,11 @@ fn clean_poly_fn_sig<'tcx>( .iter() .map(|t| Argument { type_: clean_middle_ty(t.map_bound(|t| *t), cx, None, None), - name: if let Some(Some(ident)) = names.next() { + name: Some(if let Some(Some(ident)) = names.next() { ident.name } else { kw::Underscore - }, + }), is_const: false, }) .collect(), @@ -2791,11 +2798,7 @@ fn clean_maybe_renamed_item<'tcx>( use hir::ItemKind; let def_id = item.owner_id.to_def_id(); - let mut name = if renamed.is_some() { - renamed - } else { - cx.tcx.hir_opt_name(item.hir_id()) - }; + let mut name = if renamed.is_some() { renamed } else { cx.tcx.hir_opt_name(item.hir_id()) }; cx.with_param_env(def_id, |cx| { let kind = match item.kind { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 06e75fe1764e..1d398a6458fd 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1426,7 +1426,7 @@ pub(crate) struct Arguments { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct Argument { pub(crate) type_: Type, - pub(crate) name: Symbol, + pub(crate) name: Option, /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics` /// feature. More information in . pub(crate) is_const: bool, @@ -1434,7 +1434,7 @@ pub(crate) struct Argument { impl Argument { pub(crate) fn to_receiver(&self) -> Option<&Type> { - if self.name == kw::SelfLower { Some(&self.type_) } else { None } + if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None } } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 41e9a5a66516..4d55df71a910 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1238,8 +1238,8 @@ impl clean::Arguments { .iter() .map(|input| { fmt::from_fn(|f| { - if !input.name.is_empty() { - write!(f, "{}: ", input.name)?; + if let Some(name) = input.name { + write!(f, "{}: ", name)?; } input.type_.print(cx).fmt(f) }) @@ -1361,7 +1361,9 @@ impl clean::FnDecl { if input.is_const { write!(f, "const ")?; } - write!(f, "{}: ", input.name)?; + if let Some(name) = input.name { + write!(f, "{}: ", name)?; + } input.type_.print(cx).fmt(f)?; } match (line_wrapping_indent, last_input_index) { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 9d8eb70fbe07..5d85a4676b7e 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -11,7 +11,7 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_metadata::rendered_const; use rustc_middle::{bug, ty}; -use rustc_span::{Pos, Symbol}; +use rustc_span::{Pos, Symbol, kw}; use rustdoc_json_types::*; use crate::clean::{self, ItemId}; @@ -611,7 +611,10 @@ impl FromClean for FunctionSignature { inputs: inputs .values .into_iter() - .map(|arg| (arg.name.to_string(), arg.type_.into_json(renderer))) + // `_` is the most sensible name for missing param names. + .map(|arg| { + (arg.name.unwrap_or(kw::Underscore).to_string(), arg.type_.into_json(renderer)) + }) .collect(), output: if output.is_unit() { None } else { Some(output.into_json(renderer)) }, is_c_variadic: c_variadic, From 5fb0f570f5d4b63db0bde517432b76099a2d683d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Apr 2025 13:26:19 +1000 Subject: [PATCH 162/222] Avoid another `kw::Empty` use. `sym::dummy` also appears to work. --- src/librustdoc/clean/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index afcca81a485f..8ee08edec199 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -234,7 +234,7 @@ pub(super) fn clean_middle_path<'tcx>( args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, ) -> Path { let def_kind = cx.tcx.def_kind(did); - let name = cx.tcx.opt_item_name(did).unwrap_or(kw::Empty); + let name = cx.tcx.opt_item_name(did).unwrap_or(sym::dummy); Path { res: Res::Def(def_kind, did), segments: thin_vec![PathSegment { From 40978580ec3c4d6d32245e578979a745f310e9c3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Apr 2025 13:31:17 +1000 Subject: [PATCH 163/222] Avoid using `kw::Empty` when comparing names. --- src/librustdoc/html/render/print_item.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 96847f13f655..45cb0adecf3b 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::{Symbol, kw, sym}; +use rustc_span::symbol::{Symbol, sym}; use tracing::{debug, info}; use super::type_layout::document_type_layout; @@ -347,9 +347,12 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i // but we actually want stable items to come first return is_stable2.cmp(&is_stable1); } - let lhs = i1.name.unwrap_or(kw::Empty); - let rhs = i2.name.unwrap_or(kw::Empty); - compare_names(lhs.as_str(), rhs.as_str()) + match (i1.name, i2.name) { + (Some(name1), Some(name2)) => compare_names(name1.as_str(), name2.as_str()), + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (None, None) => Ordering::Equal, + } } let tcx = cx.tcx(); From 65942d19cdb722db4544c4fcdcc0f054ff048701 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Apr 2025 15:01:48 +1000 Subject: [PATCH 164/222] Avoid using `kw::Empty` for param names in rustdoc. --- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/render/search_index.rs | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 21c823f49d15..adf15018ad2d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -208,7 +208,7 @@ pub(crate) struct IndexItemFunctionType { inputs: Vec, output: Vec, where_clause: Vec>, - param_names: Vec, + param_names: Vec>, } impl IndexItemFunctionType { diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index b39701fae1d6..1360ab94cb1c 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -709,8 +709,11 @@ pub(crate) fn build_index( let mut result = Vec::new(); for (index, item) in self.items.iter().enumerate() { if let Some(ty) = &item.search_type - && let my = - ty.param_names.iter().map(|sym| sym.as_str()).collect::>() + && let my = ty + .param_names + .iter() + .filter_map(|sym| sym.map(|sym| sym.to_string())) + .collect::>() && my != prev { result.push((index, my.join(","))); @@ -1372,7 +1375,7 @@ fn simplify_fn_constraint<'a>( /// Used to allow type-based search on constants and statics. fn make_nullary_fn( clean_type: &clean::Type, -) -> (Vec, Vec, Vec, Vec>) { +) -> (Vec, Vec, Vec>, Vec>) { let mut rgen: FxIndexMap)> = Default::default(); let output = get_index_type(clean_type, vec![], &mut rgen); (vec![], vec![output], vec![], vec![]) @@ -1387,7 +1390,7 @@ fn get_fn_inputs_and_outputs( tcx: TyCtxt<'_>, impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>, cache: &Cache, -) -> (Vec, Vec, Vec, Vec>) { +) -> (Vec, Vec, Vec>, Vec>) { let decl = &func.decl; let mut rgen: FxIndexMap)> = Default::default(); @@ -1441,10 +1444,10 @@ fn get_fn_inputs_and_outputs( simplified_params .iter() .map(|(name, (_idx, _traits))| match name { - SimplifiedParam::Symbol(name) => *name, - SimplifiedParam::Anonymous(_) => kw::Empty, + SimplifiedParam::Symbol(name) => Some(*name), + SimplifiedParam::Anonymous(_) => None, SimplifiedParam::AssociatedType(def_id, name) => { - Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name)) + Some(Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name))) } }) .collect(), From f3847f0639c851224bb709444ae76865c0b1959b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 8 Apr 2025 13:50:01 +1000 Subject: [PATCH 165/222] Remove some "name isn't empty" assertions. These were low value even before #137978 resulted in empty names being used much less. (Why check for non-emptiness in these three places? There are thousands of places in the compiler you could check.) --- compiler/rustc_ast_lowering/src/lib.rs | 1 - compiler/rustc_hir_typeck/src/expr.rs | 10 ++-------- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 3 +-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b1d1c35e64a1..5be740609c7c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1765,7 +1765,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ident: Ident, is_anon_in_path: IsAnonInPath, ) -> &'hir hir::Lifetime { - debug_assert_ne!(ident.name, kw::Empty); let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); let res = match res { LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param), diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index de2f039cb1c8..7964b5f17c5c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1600,11 +1600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(method) } Err(error) => { - if segment.ident.name == kw::Empty { - span_bug!(rcvr.span, "empty method name") - } else { - Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false)) - } + Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false)) } }; @@ -2942,9 +2938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_error(self.tcx(), guar); } - let guar = if field.name == kw::Empty { - self.dcx().span_bug(field.span, "field name with no name") - } else if self.method_exists_for_diagnostic( + let guar = if self.method_exists_for_diagnostic( field, base_ty, expr.hir_id, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 91190a32ff54..87d92b3fbde8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -27,9 +27,9 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; -use rustc_span::{Span, kw}; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCauseCode, StructurallyNormalizeExt, @@ -833,7 +833,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_missing_method = matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait(); - assert_ne!(item_name.name, kw::Empty); self.report_method_error( hir_id, ty.normalized, From 2b43e664964bd6eeff6d0a1787ab2ef2a04f3e94 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Apr 2025 07:16:57 +1000 Subject: [PATCH 166/222] Remove a `kw::Empty` usage in symbol mangling. Field names are never empty, so the unwrap is unnecessary. --- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index d28f10ba9e38..789de471ddc0 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -776,7 +776,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { self.push_disambiguator( disambiguated_field.disambiguator as u64, ); - self.push_ident(field_name.unwrap_or(kw::Empty).as_str()); + self.push_ident(field_name.unwrap().as_str()); field.print(self)?; } From c12b4aade031e4ca4babb9cdfbe53f466ae76462 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Apr 2025 15:45:25 +1000 Subject: [PATCH 167/222] Use a dummy ident for a `lint_if_path_starts_with_module` call. This is pretty weird code. As the `HACK` comment indicates, we push the empty ident here only to make the path longer, so certain checks to occur within `lint_if_path_starts_with_module`. `dummy` is a better choice because it explicitly communicates that the actual value doesn't matter. --- compiler/rustc_resolve/src/imports.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 3f3b455f4db2..762e08b2be5f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1012,7 +1012,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); - full_path.push(Segment::from_ident(Ident::empty())); + full_path.push(Segment::from_ident(Ident::dummy())); self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); } From 2009ca6d88a363b84b4733e253835fe13ec96540 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 14 Apr 2025 13:54:14 +0000 Subject: [PATCH 168/222] Remove #![feature(no_sanitize)] --- library/core/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index dc06aa4c38d5..c2d65f073640 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -169,7 +169,6 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(no_core)] -#![feature(no_sanitize)] #![feature(optimize_attribute)] #![feature(prelude_import)] #![feature(repr_simd)] From 1cbdfab75d6dbf9c383ece8fe2e2642e5db2f2e7 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 14 Apr 2025 13:54:49 +0000 Subject: [PATCH 169/222] Use full path for core::mem::transmute Suggested-by: Tamir Duberstein Signed-off-by: Alice Ryhl --- library/core/src/fmt/mod.rs | 2 +- library/core/src/fmt/rt.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 7ca390941bcd..580f95eddce7 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -7,7 +7,7 @@ use crate::char::{EscapeDebugExtArgs, MAX_LEN_UTF8}; use crate::marker::PhantomData; use crate::num::fmt as numfmt; use crate::ops::Deref; -use crate::{iter, mem, result, str}; +use crate::{iter, result, str}; mod builders; #[cfg(not(no_fp_fmt_parse))] diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index c36feff0b62d..b9cae8645cd3 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -76,7 +76,7 @@ macro_rules! argument_new { formatter: { let f: fn(&$t, &mut Formatter<'_>) -> Result = $f; // SAFETY: This is only called with `value`, which has the right type. - unsafe { mem::transmute(f) } + unsafe { core::mem::transmute(f) } }, #[cfg(any(sanitize = "cfi", sanitize = "kcfi"))] formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| { From 6513df96525704d3c40f16faf2672adaaa3186ac Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 14 Apr 2025 06:52:32 +0000 Subject: [PATCH 170/222] Add comment Co-authored-by: Ralf Jung --- library/core/src/fmt/rt.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index b9cae8645cd3..adcfdd309b7e 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -72,6 +72,25 @@ macro_rules! argument_new { // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { value: NonNull::<$t>::from_ref($x).cast(), + // The Rust ABI considers all pointers to be equivalent, so transmuting a fn(&T) to + // fn(NonNull<()>) and calling it with a NonNull<()> that points at a T is allowed. + // However, the CFI sanitizer does not allow this, and triggers a crash when it + // happens. + // + // To avoid this crash, we use a helper function when CFI is enabled. To avoid the + // cost of this helper function (mainly code-size) when it is not needed, we + // transmute the function pointer otherwise. + // + // This is similar to what the Rust compiler does internally with vtables when KCFI + // is enabled, where it generates trampoline functions that only serve to adjust the + // expected type of the argument. `ArgumentType::Placeholder` is a bit like a + // manually constructed trait object, so it is not surprising that the same approach + // has to be applied here as well. + // + // It is still considered problematic (from the Rust side) that CFI rejects entirely + // legal Rust programs, so we do not consider anything done here a stable guarantee, + // but meanwhile we carry this work-around to keep Rust compatible with CFI and + // KCFI. #[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))] formatter: { let f: fn(&$t, &mut Formatter<'_>) -> Result = $f; From 4ac3877521084501c44d3bea1251398448cb7ecd Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 15 Apr 2025 09:28:04 +0200 Subject: [PATCH 171/222] unstable book; document `macro_metavar_expr_concat` --- .../macro-metavar-expr-concat.md | 133 ++++++++++++++++++ .../language-features/macro-metavar-expr.md | 10 ++ .../src/library-features/concat-idents.md | 2 + 3 files changed, 145 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md create mode 100644 src/doc/unstable-book/src/language-features/macro-metavar-expr.md diff --git a/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md new file mode 100644 index 000000000000..b6dbdb144077 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md @@ -0,0 +1,133 @@ +# `macro_metavar_expr_concat` + +The tracking issue for this feature is: [#124225] + +------------------------ + +In stable Rust, there is no way to create new identifiers by joining identifiers to literals or other identifiers without using procedural macros such as [`paste`]. + `#![feature(macro_metavar_expr_concat)]` introduces a way to do this, using the concat metavariable expression. + +> This feature uses the syntax from [`macro_metavar_expr`] but is otherwise +> independent. It replaces the old unstable feature [`concat_idents`]. + +> This is an experimental feature; it and its syntax will require a RFC before stabilization. + + +### Overview + +`#![feature(macro_metavar_expr_concat)]` provides the `concat` metavariable expression for creating new identifiers: + +```rust +#![feature(macro_metavar_expr_concat)] + +macro_rules! create_some_structs { + ($name:ident) => { + pub struct ${ concat(First, $name) }; + pub struct ${ concat(Second, $name) }; + pub struct ${ concat(Third, $name) }; + } +} + +create_some_structs!(Thing); +``` + +This macro invocation expands to: + +```rust +pub struct FirstThing; +pub struct SecondThing; +pub struct ThirdThing; +``` + +### Syntax + +This feature builds upon the metavariable expression syntax `${ .. }` as specified in [RFC 3086] ([`macro_metavar_expr`]). + `concat` is available like `${ concat(items) }`, where `items` is a comma separated sequence of idents and/or literals. + +### Examples + +#### Create a function or method with a concatenated name + +```rust +#![feature(macro_metavar_expr_concat)] + +macro_rules! make_getter { + ($name:ident, $field: ident, $ret:ty) => { + impl $name { + pub fn ${ concat(get_, $field) }(&self) -> &$ret { + &self.$field + } + } + } +} + +pub struct Thing { + description: String, +} + +make_getter!(Thing, description, String); +``` + +This expands to: + +```rust +pub struct Thing { + description: String, +} + +impl Thing { + pub fn get_description(&self) -> &String { + &self.description + } +} +``` + +#### Create names for macro generated tests + +```rust +#![feature(macro_metavar_expr_concat)] + +macro_rules! test_math { + ($integer:ident) => { + #[test] + fn ${ concat(test_, $integer, _, addition) } () { + let a: $integer = 73; + let b: $integer = 42; + assert_eq!(a + b, 115) + } + + #[test] + fn ${ concat(test_, $integer, _, subtraction) } () { + let a: $integer = 73; + let b: $integer = 42; + assert_eq!(a - b, 31) + } + } +} + +test_math!(i32); +test_math!(u64); +test_math!(u128); +``` + +Running this returns the following output: + +```text +running 6 tests +test test_i32_subtraction ... ok +test test_i32_addition ... ok +test test_u128_addition ... ok +test test_u128_subtraction ... ok +test test_u64_addition ... ok +test test_u64_subtraction ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s +``` + +[`paste`]: https://crates.io/crates/paste +[RFC 3086]: https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html +[`concat_idents!`]: https://doc.rust-lang.org/nightly/std/macro.concat_idents.html +[`macro_metavar_expr`]: ../language-features/macro-metavar-expr.md +[`concat_idents`]: ../library-features/concat-idents.md +[#124225]: https://github.com/rust-lang/rust/issues/124225 +[declarative macros]: https://doc.rust-lang.org/stable/reference/macros-by-example.html diff --git a/src/doc/unstable-book/src/language-features/macro-metavar-expr.md b/src/doc/unstable-book/src/language-features/macro-metavar-expr.md new file mode 100644 index 000000000000..7ce64c1a3549 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/macro-metavar-expr.md @@ -0,0 +1,10 @@ +# `macro_metavar_expr` + +The tracking issue for this feature is: [#83527] + +------------------------ + +> This feature is not to be confused with [`macro_metavar_expr_concat`]. + +[`macro_metavar_expr_concat`]: ./macro-metavar-expr-concat.md +[#83527]: https://github.com/rust-lang/rust/issues/83527 diff --git a/src/doc/unstable-book/src/library-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md index 73f6cfa21787..4366172fb996 100644 --- a/src/doc/unstable-book/src/library-features/concat-idents.md +++ b/src/doc/unstable-book/src/library-features/concat-idents.md @@ -6,6 +6,8 @@ The tracking issue for this feature is: [#29599] ------------------------ +> This feature is expected to be superseded by [`macro_metavar_expr_concat`](../language-features/macro-metavar-expr-concat.md). + The `concat_idents` feature adds a macro for concatenating multiple identifiers into one identifier. From fc8df06f4feb6cc051e15e6596821d276b0797bb Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 14 Apr 2025 18:24:30 +0200 Subject: [PATCH 172/222] update submodules if the directory doesn't exist --- src/bootstrap/src/core/config/config.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 25ec64f90b53..2266e61bf608 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2888,6 +2888,13 @@ impl Config { let absolute_path = self.src.join(relative_path); + // NOTE: This check is required because `jj git clone` doesn't create directories for + // submodules, they are completely ignored. The code below assumes this directory exists, + // so create it here. + if !absolute_path.exists() { + t!(fs::create_dir_all(&absolute_path)); + } + // NOTE: The check for the empty directory is here because when running x.py the first time, // the submodule won't be checked out. Check it out now so we can build it. if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository() From 1397dabd1ec2e58f0cea27fd281dac7104083cca Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 14 Apr 2025 19:04:34 +0200 Subject: [PATCH 173/222] fix typo --- src/tools/compiletest/src/runtest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 24fc2ddb7410..093dc7fa56ca 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2383,7 +2383,7 @@ impl<'test> TestCx<'test> { if json { // escaped newlines in json strings should be readable - // in the stderr files. There's no point int being correct, + // in the stderr files. There's no point in being correct, // since only humans process the stderr files. // Thus we just turn escaped newlines back into newlines. normalized = normalized.replace("\\n", "\n"); From 6c441cc7a53e3c9ca0dd1957b8055ccdd851b488 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 14 Apr 2025 19:04:34 +0200 Subject: [PATCH 174/222] canonicalize test build dir before normalizing it Fix fixes failures of the following tests when build directory is a symlink: - `tests/ui/error-codes/E{0464,0523}.rs` - `tests/ui/crate-loading/crateresolve{1,2}.rs` (those are the same tests) --- src/tools/compiletest/src/runtest.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 093dc7fa56ca..fc83ea420430 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2375,9 +2375,13 @@ impl<'test> TestCx<'test> { let rust_src_dir = rust_src_dir.read_link_utf8().unwrap_or(rust_src_dir.to_path_buf()); normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); + // Canonicalize test build directory path. + // Without this some tests fail if build directory is a symlink. + let output_base_dir = self.output_base_dir().canonicalize_utf8().unwrap(); + // eg. // /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui//$name.$revision.$mode/ - normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR"); + normalize_path(&output_base_dir, "$TEST_BUILD_DIR"); // eg. /home/user/rust/build normalize_path(&self.config.build_root, "$BUILD_DIR"); From c49b0bdb1ad82ec4dd28c616ab08c72b06c81019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 14 Apr 2025 19:40:47 +0200 Subject: [PATCH 175/222] Use `rust-cache` to speed-up `citool` compilation --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51dd0f81ed14..2e83bbf643fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,13 @@ jobs: steps: - name: Checkout the source code uses: actions/checkout@v4 + # Cache citool to make its build faster, as it's in the critical path. + # The rust-cache doesn't bleed into the main `job`, so it should not affect any other + # Rust compilation. + - name: Cache citool + uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 + with: + workspaces: src/ci/citool - name: Calculate the CI job matrix env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} From 8887af72a0b1f37a34b02d488ca3278576e2d73d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 14 Apr 2025 20:48:51 +0200 Subject: [PATCH 176/222] Improve parse errors for lifetimes in type position --- compiler/rustc_parse/messages.ftl | 4 +- compiler/rustc_parse/src/errors.rs | 2 + compiler/rustc_parse/src/parser/ty.rs | 63 +++++++++++++++++-- .../gat-trait-path-parenthesised-args.rs | 2 +- .../gat-trait-path-parenthesised-args.stderr | 7 ++- .../trait-object-macro-matcher.e2015.stderr | 32 ++++++++++ .../trait-object-macro-matcher.e2021.stderr | 16 +++++ .../macro/trait-object-macro-matcher.rs | 12 +++- .../macro/trait-object-macro-matcher.stderr | 23 ------- .../recover/recover-ampersand-less-ref-ty.rs | 13 ++++ .../recover-ampersand-less-ref-ty.stderr | 24 +++++++ ...trait-object-lifetime-parens.e2015.stderr} | 13 ++-- .../trait-object-lifetime-parens.e2021.stderr | 51 +++++++++++++++ .../ui/parser/trait-object-lifetime-parens.rs | 14 ++++- 14 files changed, 234 insertions(+), 42 deletions(-) create mode 100644 tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr create mode 100644 tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr delete mode 100644 tests/ui/parser/macro/trait-object-macro-matcher.stderr create mode 100644 tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs create mode 100644 tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr rename tests/ui/parser/{trait-object-lifetime-parens.stderr => trait-object-lifetime-parens.e2015.stderr} (60%) create mode 100644 tests/ui/parser/trait-object-lifetime-parens.e2021.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 93fa89b68b97..e2b5e1cdd0ad 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -642,7 +642,9 @@ parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual bi .suggestion = add `mut` to each binding parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding .suggestion = remove the `mut` prefix -parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+` + +parse_need_plus_after_trait_object_lifetime = lifetimes must be followed by `+` to form a trait object type + .suggestion = consider adding a trait bound after the potential lifetime bound parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}` .suggestion = consider creating a new `{$kw_str}` definition instead of nesting diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index dfdef018bc37..b28939e062af 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2806,6 +2806,8 @@ pub(crate) struct ReturnTypesUseThinArrow { pub(crate) struct NeedPlusAfterTraitObjectLifetime { #[primary_span] pub span: Span, + #[suggestion(code = " + /* Trait */", applicability = "has-placeholders")] + pub suggestion: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 93705da22c45..f468d5433d93 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -7,7 +7,7 @@ use rustc_ast::{ Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, }; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -411,6 +411,9 @@ impl<'a> Parser<'a> { TyKind::Path(None, path) if maybe_bounds => { self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true) } + // For `('a) + …`, we know that `'a` in type position already lead to an error being + // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and + // other irrelevant consequential errors. TyKind::TraitObject(bounds, TraitObjectSyntax::None) if maybe_bounds && bounds.len() == 1 && !trailing_plus => { @@ -425,12 +428,60 @@ impl<'a> Parser<'a> { } fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { - let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()); - let bounds = self.parse_generic_bounds_common(allow_plus)?; - if lt_no_plus { - self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime { span: lo }); + // A lifetime only begins a bare trait object type if it is followed by `+`! + if self.token.is_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()) { + // In Rust 2021 and beyond, we assume that the user didn't intend to write a bare trait + // object type with a leading lifetime bound since that seems very unlikely given the + // fact that `dyn`-less trait objects are *semantically* invalid. + if self.psess.edition.at_least_rust_2021() { + let lt = self.expect_lifetime(); + let mut err = self.dcx().struct_span_err(lo, "expected type, found lifetime"); + err.span_label(lo, "expected type"); + return Ok(match self.maybe_recover_ref_ty_no_leading_ampersand(lt, lo, err) { + Ok(ref_ty) => ref_ty, + Err(err) => TyKind::Err(err.emit()), + }); + } + + self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime { + span: lo, + suggestion: lo.shrink_to_hi(), + }); + } + Ok(TyKind::TraitObject( + self.parse_generic_bounds_common(allow_plus)?, + TraitObjectSyntax::None, + )) + } + + fn maybe_recover_ref_ty_no_leading_ampersand<'cx>( + &mut self, + lt: Lifetime, + lo: Span, + mut err: Diag<'cx>, + ) -> Result> { + if !self.may_recover() { + return Err(err); + } + let snapshot = self.create_snapshot_for_diagnostic(); + let mutbl = self.parse_mutability(); + match self.parse_ty_no_plus() { + Ok(ty) => { + err.span_suggestion_verbose( + lo.shrink_to_lo(), + "you might have meant to write a reference type here", + "&", + Applicability::MaybeIncorrect, + ); + err.emit(); + Ok(TyKind::Ref(Some(lt), MutTy { ty, mutbl })) + } + Err(diag) => { + diag.cancel(); + self.restore_snapshot(snapshot); + Err(err) + } } - Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } fn parse_remaining_bounds_path( diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs index 85661c1b8448..294fb6743fbc 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs @@ -3,7 +3,7 @@ trait X { } fn foo<'a>(arg: Box>) {} - //~^ ERROR: lifetime in trait object type must be followed by `+` + //~^ ERROR: lifetimes must be followed by `+` to form a trait object type //~| ERROR: parenthesized generic arguments cannot be used //~| ERROR associated type takes 0 generic arguments but 1 generic argument //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr index 99300ea1cb7f..e18d8198c945 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr @@ -1,8 +1,13 @@ -error: lifetime in trait object type must be followed by `+` +error: lifetimes must be followed by `+` to form a trait object type --> $DIR/gat-trait-path-parenthesised-args.rs:5:29 | LL | fn foo<'a>(arg: Box>) {} | ^^ + | +help: consider adding a trait bound after the potential lifetime bound + | +LL | fn foo<'a>(arg: Box>) {} + | +++++++++++++ error: parenthesized generic arguments cannot be used in associated type constraints --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr new file mode 100644 index 000000000000..f2db351de4a7 --- /dev/null +++ b/tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr @@ -0,0 +1,32 @@ +error: lifetimes must be followed by `+` to form a trait object type + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ + | +help: consider adding a trait bound after the potential lifetime bound + | +LL | m!('static + /* Trait */); + | +++++++++++++ + +error: lifetimes must be followed by `+` to form a trait object type + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding a trait bound after the potential lifetime bound + | +LL | m!('static + /* Trait */); + | +++++++++++++ + +error[E0224]: at least one trait is required for an object type + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0224`. diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr new file mode 100644 index 000000000000..7d9e8d795d18 --- /dev/null +++ b/tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr @@ -0,0 +1,16 @@ +error: expected type, found lifetime + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ expected type + +error: expected type, found lifetime + --> $DIR/trait-object-macro-matcher.rs:17:8 + | +LL | m!('static); + | ^^^^^^^ expected type + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.rs b/tests/ui/parser/macro/trait-object-macro-matcher.rs index d4ec199070e7..ba61752fe402 100644 --- a/tests/ui/parser/macro/trait-object-macro-matcher.rs +++ b/tests/ui/parser/macro/trait-object-macro-matcher.rs @@ -1,6 +1,10 @@ // A single lifetime is not parsed as a type. // `ty` matcher in particular doesn't accept a single lifetime +//@ revisions: e2015 e2021 +//@[e2015] edition: 2015 +//@[e2021] edition: 2021 + macro_rules! m { ($t: ty) => { let _: $t; @@ -8,8 +12,10 @@ macro_rules! m { } fn main() { + //[e2021]~vv ERROR expected type, found lifetime + //[e2021]~v ERROR expected type, found lifetime m!('static); - //~^ ERROR lifetime in trait object type must be followed by `+` - //~| ERROR lifetime in trait object type must be followed by `+` - //~| ERROR at least one trait is required for an object type + //[e2015]~^ ERROR lifetimes must be followed by `+` to form a trait object type + //[e2015]~| ERROR lifetimes must be followed by `+` to form a trait object type + //[e2015]~| ERROR at least one trait is required for an object type } diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.stderr deleted file mode 100644 index 81dca6f71c43..000000000000 --- a/tests/ui/parser/macro/trait-object-macro-matcher.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: lifetime in trait object type must be followed by `+` - --> $DIR/trait-object-macro-matcher.rs:11:8 - | -LL | m!('static); - | ^^^^^^^ - -error: lifetime in trait object type must be followed by `+` - --> $DIR/trait-object-macro-matcher.rs:11:8 - | -LL | m!('static); - | ^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0224]: at least one trait is required for an object type - --> $DIR/trait-object-macro-matcher.rs:11:8 - | -LL | m!('static); - | ^^^^^^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0224`. diff --git a/tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs new file mode 100644 index 000000000000..8f1a42473b5a --- /dev/null +++ b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs @@ -0,0 +1,13 @@ +//@ edition: 2021 + +struct Entity<'a> { + name: 'a str, //~ ERROR expected type, found lifetime + //~^ HELP you might have meant to write a reference type here +} + +struct Buffer<'buf> { + bytes: 'buf mut [u8], //~ ERROR expected type, found lifetime + //~^ HELP you might have meant to write a reference type here +} + +fn main() {} diff --git a/tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr new file mode 100644 index 000000000000..033348b2c405 --- /dev/null +++ b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr @@ -0,0 +1,24 @@ +error: expected type, found lifetime + --> $DIR/recover-ampersand-less-ref-ty.rs:4:11 + | +LL | name: 'a str, + | ^^ expected type + | +help: you might have meant to write a reference type here + | +LL | name: &'a str, + | + + +error: expected type, found lifetime + --> $DIR/recover-ampersand-less-ref-ty.rs:9:12 + | +LL | bytes: 'buf mut [u8], + | ^^^^ expected type + | +help: you might have meant to write a reference type here + | +LL | bytes: &'buf mut [u8], + | + + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/trait-object-lifetime-parens.stderr b/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr similarity index 60% rename from tests/ui/parser/trait-object-lifetime-parens.stderr rename to tests/ui/parser/trait-object-lifetime-parens.e2015.stderr index 280c0e40c640..cf0b3d77f5b5 100644 --- a/tests/ui/parser/trait-object-lifetime-parens.stderr +++ b/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr @@ -1,5 +1,5 @@ error: parenthesized lifetime bounds are not supported - --> $DIR/trait-object-lifetime-parens.rs:5:21 + --> $DIR/trait-object-lifetime-parens.rs:9:21 | LL | fn f<'a, T: Trait + ('a)>() {} | ^^^^ @@ -11,7 +11,7 @@ LL + fn f<'a, T: Trait + 'a>() {} | error: parenthesized lifetime bounds are not supported - --> $DIR/trait-object-lifetime-parens.rs:8:24 + --> $DIR/trait-object-lifetime-parens.rs:12:24 | LL | let _: Box; | ^^^^ @@ -22,11 +22,16 @@ LL - let _: Box; LL + let _: Box; | -error: lifetime in trait object type must be followed by `+` - --> $DIR/trait-object-lifetime-parens.rs:10:17 +error: lifetimes must be followed by `+` to form a trait object type + --> $DIR/trait-object-lifetime-parens.rs:16:17 | LL | let _: Box<('a) + Trait>; | ^^ + | +help: consider adding a trait bound after the potential lifetime bound + | +LL | let _: Box<('a + /* Trait */) + Trait>; + | +++++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr new file mode 100644 index 000000000000..3518321ea201 --- /dev/null +++ b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr @@ -0,0 +1,51 @@ +error: parenthesized lifetime bounds are not supported + --> $DIR/trait-object-lifetime-parens.rs:9:21 + | +LL | fn f<'a, T: Trait + ('a)>() {} + | ^^^^ + | +help: remove the parentheses + | +LL - fn f<'a, T: Trait + ('a)>() {} +LL + fn f<'a, T: Trait + 'a>() {} + | + +error: parenthesized lifetime bounds are not supported + --> $DIR/trait-object-lifetime-parens.rs:12:24 + | +LL | let _: Box; + | ^^^^ + | +help: remove the parentheses + | +LL - let _: Box; +LL + let _: Box; + | + +error: expected type, found lifetime + --> $DIR/trait-object-lifetime-parens.rs:16:17 + | +LL | let _: Box<('a) + Trait>; + | ^^ expected type + +error[E0178]: expected a path on the left-hand side of `+`, not `((/*ERROR*/))` + --> $DIR/trait-object-lifetime-parens.rs:16:16 + | +LL | let _: Box<('a) + Trait>; + | ^^^^^^^^^^^^ expected a path + +error[E0782]: expected a type, found a trait + --> $DIR/trait-object-lifetime-parens.rs:12:16 + | +LL | let _: Box; + | ^^^^^^^^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | let _: Box; + | +++ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0178, E0782. +For more information about an error, try `rustc --explain E0178`. diff --git a/tests/ui/parser/trait-object-lifetime-parens.rs b/tests/ui/parser/trait-object-lifetime-parens.rs index f44ebe5ba5bf..0ff4660bb0d5 100644 --- a/tests/ui/parser/trait-object-lifetime-parens.rs +++ b/tests/ui/parser/trait-object-lifetime-parens.rs @@ -1,4 +1,8 @@ -#![allow(bare_trait_objects)] +//@ revisions: e2015 e2021 +//@[e2015] edition: 2015 +//@[e2021] edition: 2021 + +#![cfg_attr(e2015, allow(bare_trait_objects))] trait Trait {} @@ -6,8 +10,12 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s fn check<'a>() { let _: Box; //~ ERROR parenthesized lifetime bounds are not supported - // FIXME: It'd be great if we could add suggestion to the following case. - let _: Box<('a) + Trait>; //~ ERROR lifetime in trait object type must be followed by `+` + //[e2021]~^ ERROR expected a type, found a trait + // FIXME: It'd be great if we could suggest removing the parentheses here too. + //[e2015]~v ERROR lifetimes must be followed by `+` to form a trait object type + let _: Box<('a) + Trait>; + //[e2021]~^ ERROR expected type, found lifetime + //[e2021]~| ERROR expected a path on the left-hand side of `+` } fn main() {} From 6242335fdb7444876abf1c3669b6aab1649a0a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 15 Apr 2025 07:44:24 +0200 Subject: [PATCH 177/222] Improve diagnostic for E0178 (bad `+` in type) Namely, use a more sensical primary span. Don't pretty-print AST nodes for the diagnostic message. Why: * It's lossy (e.g., it doesn't replicate trailing `+`s in trait objects. * It's prone to leak error nodes (printed as `(/*ERROR*/)`) since the LHS can easily represent recovered code (e.g., `fn(i32?) + T`). --- compiler/rustc_parse/messages.ftl | 2 +- compiler/rustc_parse/src/errors.rs | 1 - .../rustc_parse/src/parser/diagnostics.rs | 10 ++++----- tests/ui/did_you_mean/E0178.stderr | 18 ++++++++------- ...reference-without-parens-suggestion.stderr | 8 +++---- .../ui/impl-trait/impl-trait-plus-priority.rs | 4 ++-- .../impl-trait-plus-priority.stderr | 10 +++++---- .../issues/issue-73568-lifetime-after-mut.rs | 2 +- .../issue-73568-lifetime-after-mut.stderr | 4 ++-- tests/ui/parser/trait-object-bad-parens.rs | 12 ++++------ .../ui/parser/trait-object-bad-parens.stderr | 22 +++++++++---------- .../trait-object-lifetime-parens.e2021.stderr | 4 ++-- .../parser/trait-object-polytrait-priority.rs | 2 +- .../trait-object-polytrait-priority.stderr | 4 ++-- 14 files changed, 51 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e2b5e1cdd0ad..80cd87a69f78 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -543,7 +543,7 @@ parse_maybe_recover_from_bad_qpath_stage_2 = .suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths parse_maybe_recover_from_bad_type_plus = - expected a path on the left-hand side of `+`, not `{$ty}` + expected a path on the left-hand side of `+` parse_maybe_report_ambiguous_plus = ambiguous `+` in a type diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index b28939e062af..aad8a8bc2052 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -30,7 +30,6 @@ pub(crate) struct AmbiguousPlus { #[derive(Diagnostic)] #[diag(parse_maybe_recover_from_bad_type_plus, code = E0178)] pub(crate) struct BadTypePlus { - pub ty: String, #[primary_span] pub span: Span, #[subdiagnostic] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ef044fe9d638..40246ed78be3 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1636,19 +1636,19 @@ impl<'a> Parser<'a> { self.bump(); // `+` let _bounds = self.parse_generic_bounds()?; - let sum_span = ty.span.to(self.prev_token.span); - let sub = match &ty.kind { TyKind::Ref(_lifetime, mut_ty) => { let lo = mut_ty.ty.span.shrink_to_lo(); let hi = self.prev_token.span.shrink_to_hi(); BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } } } - TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span }, - _ => BadTypePlusSub::ExpectPath { span: sum_span }, + TyKind::Ptr(..) | TyKind::BareFn(..) => { + BadTypePlusSub::ForgotParen { span: ty.span.to(self.prev_token.span) } + } + _ => BadTypePlusSub::ExpectPath { span: ty.span }, }; - self.dcx().emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub }); + self.dcx().emit_err(BadTypePlus { span: ty.span, sub }); Ok(()) } diff --git a/tests/ui/did_you_mean/E0178.stderr b/tests/ui/did_you_mean/E0178.stderr index 5f289da8a6c3..36e4dbdf7c45 100644 --- a/tests/ui/did_you_mean/E0178.stderr +++ b/tests/ui/did_you_mean/E0178.stderr @@ -1,41 +1,43 @@ -error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/E0178.rs:6:8 | LL | w: &'a Foo + Copy, - | ^^^^^^^^^^^^^^ + | ^^^^^^^ | help: try adding parentheses | LL | w: &'a (Foo + Copy), | + + -error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/E0178.rs:7:8 | LL | x: &'a Foo + 'a, - | ^^^^^^^^^^^^ + | ^^^^^^^ | help: try adding parentheses | LL | x: &'a (Foo + 'a), | + + -error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/E0178.rs:8:8 | LL | y: &'a mut Foo + 'a, - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | help: try adding parentheses | LL | y: &'a mut (Foo + 'a), | + + -error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/E0178.rs:9:8 | LL | z: fn() -> Foo + 'a, - | ^^^^^^^^^^^^^^^^ perhaps you forgot parentheses? + | ^^^^^^^^^^^----- + | | + | perhaps you forgot parentheses? error: aborting due to 4 previous errors diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index 4fee6cc9a222..762b37b9e9d6 100644 --- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -1,19 +1,19 @@ -error[E0178]: expected a path on the left-hand side of `+`, not `&Copy` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 | LL | let _: &Copy + 'static; - | ^^^^^^^^^^^^^^^ + | ^^^^^ | help: try adding parentheses | LL | let _: &(Copy + 'static); | + + -error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12 | LL | let _: &'static Copy + 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | help: try adding parentheses | diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.rs b/tests/ui/impl-trait/impl-trait-plus-priority.rs index 5575493a17d3..8f76d4126622 100644 --- a/tests/ui/impl-trait/impl-trait-plus-priority.rs +++ b/tests/ui/impl-trait/impl-trait-plus-priority.rs @@ -27,7 +27,7 @@ type A = fn() -> impl A + B; type A = fn() -> dyn A + B; //~^ ERROR ambiguous `+` in a type type A = fn() -> A + B; -//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> A` +//~^ ERROR expected a path on the left-hand side of `+` type A = Fn() -> impl A +; //~^ ERROR ambiguous `+` in a type @@ -44,6 +44,6 @@ type A = &impl A + B; type A = &dyn A + B; //~^ ERROR ambiguous `+` in a type type A = &A + B; -//~^ ERROR expected a path on the left-hand side of `+`, not `&A` +//~^ ERROR expected a path on the left-hand side of `+` fn main() {} diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.stderr b/tests/ui/impl-trait/impl-trait-plus-priority.stderr index 03e7910095a9..161206579603 100644 --- a/tests/ui/impl-trait/impl-trait-plus-priority.stderr +++ b/tests/ui/impl-trait/impl-trait-plus-priority.stderr @@ -31,11 +31,13 @@ help: try adding parentheses LL | type A = fn() -> (dyn A + B); | + + -error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/impl-trait-plus-priority.rs:29:10 | LL | type A = fn() -> A + B; - | ^^^^^^^^^^^^^ perhaps you forgot parentheses? + | ^^^^^^^^^---- + | | + | perhaps you forgot parentheses? error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:32:18 @@ -103,11 +105,11 @@ help: try adding parentheses LL | type A = &(dyn A + B); | + + -error[E0178]: expected a path on the left-hand side of `+`, not `&A` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/impl-trait-plus-priority.rs:46:10 | LL | type A = &A + B; - | ^^^^^^ + | ^^ | help: try adding parentheses | diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs index cf754a6854ec..782a46ab060e 100644 --- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs +++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs @@ -12,7 +12,7 @@ mac!('a); // avoid false positives fn y<'a>(y: &mut 'a + Send) { - //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a` + //~^ ERROR expected a path on the left-hand side of `+` //~| ERROR at least one trait is required for an object type let z = y as &mut 'a + Send; //~^ ERROR expected value, found trait `Send` diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr index 6b8f8e4fe4ee..ae1ed72853de 100644 --- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr +++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr @@ -10,11 +10,11 @@ LL - fn x<'a>(x: &mut 'a i32){} LL + fn x<'a>(x: &'a mut i32){} | -error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/issue-73568-lifetime-after-mut.rs:14:13 | LL | fn y<'a>(y: &mut 'a + Send) { - | ^^^^^^^^^^^^^^ + | ^^^^^^^ | help: try adding parentheses | diff --git a/tests/ui/parser/trait-object-bad-parens.rs b/tests/ui/parser/trait-object-bad-parens.rs index 8e267c7448fe..bb047a4b4314 100644 --- a/tests/ui/parser/trait-object-bad-parens.rs +++ b/tests/ui/parser/trait-object-bad-parens.rs @@ -5,12 +5,8 @@ auto trait Auto {} fn main() { - let _: Box<((Auto)) + Auto>; - //~^ ERROR expected a path on the left-hand side of `+`, not `((Auto))` - let _: Box<(Auto + Auto) + Auto>; - //~^ ERROR expected a path on the left-hand side of `+`, not `(Auto + Auto)` - let _: Box<(Auto +) + Auto>; - //~^ ERROR expected a path on the left-hand side of `+`, not `(Auto)` - let _: Box<(dyn Auto) + Auto>; - //~^ ERROR expected a path on the left-hand side of `+`, not `(dyn Auto)` + let _: Box<((Auto)) + Auto>; //~ ERROR expected a path on the left-hand side of `+` + let _: Box<(Auto + Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+` + let _: Box<(Auto +) + Auto>; //~ ERROR expected a path on the left-hand side of `+` + let _: Box<(dyn Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+` } diff --git a/tests/ui/parser/trait-object-bad-parens.stderr b/tests/ui/parser/trait-object-bad-parens.stderr index 74e484eebee1..7c2559ce89fd 100644 --- a/tests/ui/parser/trait-object-bad-parens.stderr +++ b/tests/ui/parser/trait-object-bad-parens.stderr @@ -1,26 +1,26 @@ -error[E0178]: expected a path on the left-hand side of `+`, not `((Auto))` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/trait-object-bad-parens.rs:8:16 | LL | let _: Box<((Auto)) + Auto>; - | ^^^^^^^^^^^^^^^ expected a path + | ^^^^^^^^ expected a path -error[E0178]: expected a path on the left-hand side of `+`, not `(Auto + Auto)` - --> $DIR/trait-object-bad-parens.rs:10:16 +error[E0178]: expected a path on the left-hand side of `+` + --> $DIR/trait-object-bad-parens.rs:9:16 | LL | let _: Box<(Auto + Auto) + Auto>; - | ^^^^^^^^^^^^^^^^^^^^ expected a path + | ^^^^^^^^^^^^^ expected a path -error[E0178]: expected a path on the left-hand side of `+`, not `(Auto)` - --> $DIR/trait-object-bad-parens.rs:12:16 +error[E0178]: expected a path on the left-hand side of `+` + --> $DIR/trait-object-bad-parens.rs:10:16 | LL | let _: Box<(Auto +) + Auto>; - | ^^^^^^^^^^^^^^^ expected a path + | ^^^^^^^^ expected a path -error[E0178]: expected a path on the left-hand side of `+`, not `(dyn Auto)` - --> $DIR/trait-object-bad-parens.rs:14:16 +error[E0178]: expected a path on the left-hand side of `+` + --> $DIR/trait-object-bad-parens.rs:11:16 | LL | let _: Box<(dyn Auto) + Auto>; - | ^^^^^^^^^^^^^^^^^ expected a path + | ^^^^^^^^^^ expected a path error: aborting due to 4 previous errors diff --git a/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr index 3518321ea201..b65c079788a9 100644 --- a/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr +++ b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr @@ -28,11 +28,11 @@ error: expected type, found lifetime LL | let _: Box<('a) + Trait>; | ^^ expected type -error[E0178]: expected a path on the left-hand side of `+`, not `((/*ERROR*/))` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/trait-object-lifetime-parens.rs:16:16 | LL | let _: Box<('a) + Trait>; - | ^^^^^^^^^^^^ expected a path + | ^^^^ expected a path error[E0782]: expected a type, found a trait --> $DIR/trait-object-lifetime-parens.rs:12:16 diff --git a/tests/ui/parser/trait-object-polytrait-priority.rs b/tests/ui/parser/trait-object-polytrait-priority.rs index e7f085104ae9..85568f0fe1b1 100644 --- a/tests/ui/parser/trait-object-polytrait-priority.rs +++ b/tests/ui/parser/trait-object-polytrait-priority.rs @@ -4,6 +4,6 @@ trait Trait<'a> {} fn main() { let _: &for<'a> Trait<'a> + 'static; - //~^ ERROR expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>` + //~^ ERROR expected a path on the left-hand side of `+` //~| HELP try adding parentheses } diff --git a/tests/ui/parser/trait-object-polytrait-priority.stderr b/tests/ui/parser/trait-object-polytrait-priority.stderr index 8cb564e79300..a291a8e229c4 100644 --- a/tests/ui/parser/trait-object-polytrait-priority.stderr +++ b/tests/ui/parser/trait-object-polytrait-priority.stderr @@ -1,8 +1,8 @@ -error[E0178]: expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>` +error[E0178]: expected a path on the left-hand side of `+` --> $DIR/trait-object-polytrait-priority.rs:6:12 | LL | let _: &for<'a> Trait<'a> + 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | help: try adding parentheses | From 73065b9484aa844bd4a26aa3cbf03e3f4c7ec4cb Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Tue, 15 Apr 2025 12:28:32 +0200 Subject: [PATCH 178/222] CI: rename MacOS runner --- src/ci/github-actions/jobs.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index fbda749b6a2a..9ee3e06fa727 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -23,8 +23,8 @@ runners: os: ubuntu-24.04-16core-64gb <<: *base-job - - &job-macos-xl - os: macos-13 # We use the standard runner for now + - &job-macos + os: macos-13 <<: *base-job - &job-macos-m1 @@ -355,7 +355,7 @@ auto: NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift - <<: *job-macos-xl + <<: *job-macos - name: dist-apple-various env: @@ -372,18 +372,18 @@ auto: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-xl + <<: *job-macos - name: x86_64-apple-1 env: <<: *env-x86_64-apple-tests - <<: *job-macos-xl + <<: *job-macos - name: x86_64-apple-2 env: SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc <<: *env-x86_64-apple-tests - <<: *job-macos-xl + <<: *job-macos - name: dist-aarch64-apple env: From ee53c26b41a74eb0ecf785e8cfac98e5aa980756 Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Tue, 8 Apr 2025 05:29:19 +0300 Subject: [PATCH 179/222] Add `explicit_extern_abis` unstable feature also add `explicit-extern-abis` feature section to the unstable book. --- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + .../language-features/explicit-extern-abis.md | 23 +++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/explicit-extern-abis.md diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 36e375c778d3..d0ac822ba26e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -477,6 +477,8 @@ declare_features! ( (incomplete, ergonomic_clones, "1.87.0", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. (unstable, exhaustive_patterns, "1.13.0", Some(51085)), + /// Disallows `extern` without an explicit ABI. + (unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)), /// Allows explicit tail calls via `become` expression. (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d1f3eb16e4e4..0a2e4e4977f3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -916,6 +916,7 @@ symbols! { expf16, expf32, expf64, + explicit_extern_abis, explicit_generic_args_with_impl_trait, explicit_tail_calls, export_name, diff --git a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md new file mode 100644 index 000000000000..ba622466ba74 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md @@ -0,0 +1,23 @@ +# `explicit_extern_abis` + +The tracking issue for this feature is: #134986 + +------ + +Disallow `extern` without an explicit ABI. We should write `extern "C"` +(or another ABI) instead of just `extern`. + +By making the ABI explicit, it becomes much clearer that "C" is just one of the +possible choices, rather than the "standard" way for external functions. +Removing the default makes it easier to add a new ABI on equal footing as "C". + +```rust,editionfuture,compile_fail +#![feature(explicit_extern_abis)] + +extern fn function1() {} // ERROR `extern` declarations without an explicit ABI + // are disallowed + +extern "C" fn function2() {} // compiles + +extern "aapcs" fn function3() {} // compiles +``` From 502b630cd1042d8b2b613a12278a01c641cf096a Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 15 Apr 2025 13:11:14 +0200 Subject: [PATCH 180/222] tidy: don't crush on non-existent submodules --- src/tools/tidy/src/deps.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 88c2a02798ac..46e55859a578 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -682,8 +682,10 @@ pub static CRATES: &[&str] = &[ pub fn has_missing_submodule(root: &Path, submodules: &[&str]) -> bool { !CiEnv::is_ci() && submodules.iter().any(|submodule| { + let path = root.join(submodule); + !path.exists() // If the directory is empty, we can consider it as an uninitialized submodule. - read_dir(root.join(submodule)).unwrap().next().is_none() + || read_dir(path).unwrap().next().is_none() }) } From 52f4b16075bf01d2c8f8539c26fb9b135967713f Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 15 Apr 2025 14:06:51 +0200 Subject: [PATCH 181/222] use helper function instead of writing rustfmt stamp by hand --- src/bootstrap/src/core/build_steps/format.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index b1a97bde97b5..43b831adf1f7 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -81,7 +81,8 @@ fn update_rustfmt_version(build: &Builder<'_>) { let Some((version, stamp_file)) = get_rustfmt_version(build) else { return; }; - t!(std::fs::write(stamp_file.path(), version)) + + t!(stamp_file.add_stamp(version).write()); } /// Returns the Rust files modified between the `merge-base` of HEAD and From dda4d7bc44aa4909aae72cd38965a11ccf46c02e Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 15 Apr 2025 14:06:51 +0200 Subject: [PATCH 182/222] slightly correct comments and diagnostics about checking modifications I feel like they are still wrong, but maybe less so .-. The `info:` was unhelpful -- we only use upstream in CI nowdays. --- src/bootstrap/src/core/build_steps/format.rs | 17 +++++++++-------- src/build_helper/src/git.rs | 6 ++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 43b831adf1f7..25d5f97d7eec 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -85,11 +85,15 @@ fn update_rustfmt_version(build: &Builder<'_>) { t!(stamp_file.add_stamp(version).write()); } -/// Returns the Rust files modified between the `merge-base` of HEAD and -/// rust-lang/master and what is now on the disk. Does not include removed files. +/// Returns the Rust files modified between the last merge commit and what is now on the disk. +/// Does not include removed files. /// /// Returns `None` if all files should be formatted. fn get_modified_rs_files(build: &Builder<'_>) -> Result>, String> { + // In CI `get_git_modified_files` returns something different to normal environment. + // This shouldn't be called in CI anyway. + assert!(!build.config.is_running_on_ci); + if !verify_rustfmt_version(build) { return Ok(None); } @@ -104,7 +108,7 @@ struct RustfmtConfig { // Prints output describing a collection of paths, with lines such as "formatted modified file // foo/bar/baz" or "skipped 20 untracked files". -fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths: &[String]) { +fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { let len = paths.len(); let adjective = if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() }; @@ -115,9 +119,6 @@ fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths: } else { println!("fmt: {verb} {len} {adjective}files"); } - if len > 1000 && !build.config.is_running_on_ci { - println!("hint: if this number seems too high, try running `git fetch origin master`"); - } } pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { @@ -190,7 +191,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { ) .map(|x| x.to_string()) .collect(); - print_paths(build, "skipped", Some("untracked"), &untracked_paths); + print_paths("skipped", Some("untracked"), &untracked_paths); for untracked_path in untracked_paths { // The leading `/` makes it an exact match against the @@ -319,7 +320,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { }); let mut paths = formatted_paths.into_inner().unwrap(); paths.sort(); - print_paths(build, if check { "checked" } else { "formatted" }, adjective, &paths); + print_paths(if check { "checked" } else { "formatted" }, adjective, &paths); drop(tx); diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 693e0fc8f46d..f5347c308241 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -114,7 +114,9 @@ fn git_upstream_merge_base( Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned()) } -/// Searches for the nearest merge commit in the repository that also exists upstream. +/// Searches for the nearest merge commit in the repository. +/// +/// **In CI** finds the nearest merge commit that *also exists upstream*. /// /// It looks for the most recent commit made by the merge bot by matching the author's email /// address with the merge bot's email. @@ -165,7 +167,7 @@ pub fn get_closest_merge_commit( Ok(output_result(&mut git)?.trim().to_owned()) } -/// Returns the files that have been modified in the current branch compared to the master branch. +/// Returns the files that have been modified in the current branch compared to the last merge. /// The `extensions` parameter can be used to filter the files by their extension. /// Does not include removed files. /// If `extensions` is empty, all files will be returned. From 8934ac575988f2c15b7910d2f683b2792e5916cb Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 15 Apr 2025 14:06:51 +0200 Subject: [PATCH 183/222] add a comment for code that isn't --- src/bootstrap/src/core/build_steps/format.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 25d5f97d7eec..6641c4b4e139 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -214,7 +214,13 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { override_builder.add(&format!("/{file}")).expect(&file); } } - Ok(None) => {} + Ok(None) => { + // NOTE: `Ok(None)` signifies that we need to format all files. + // The tricky part here is that if `override_builder` isn't given any white + // list files (i.e. files to be formatted, added without leading `!`), it + // will instead look for *all* files. So, by doing nothing here, we are + // actually making it so we format all files. + } Err(err) => { eprintln!("fmt warning: Something went wrong running git commands:"); eprintln!("fmt warning: {err}"); From 812095031b82b5974e03dafd6bf33d69de712474 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 15 Apr 2025 23:51:10 +0900 Subject: [PATCH 184/222] Add test for issue 125668 --- tests/ui/consts/const-blocks/const-block-in-array-size.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/ui/consts/const-blocks/const-block-in-array-size.rs diff --git a/tests/ui/consts/const-blocks/const-block-in-array-size.rs b/tests/ui/consts/const-blocks/const-block-in-array-size.rs new file mode 100644 index 000000000000..ecab24322869 --- /dev/null +++ b/tests/ui/consts/const-blocks/const-block-in-array-size.rs @@ -0,0 +1,5 @@ +//@ check-pass + +type A = [u32; const { 2 }]; + +fn main() {} From 043c5ff98262409a9c338001200c4cf2a66e72c8 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 15 Apr 2025 10:54:08 -0700 Subject: [PATCH 185/222] Add warning comment to `Take::get_ref` and `Chain::get_ref` The methods `Take::get_mut` and `Chain::get_mut` include comments warning about modifying the I/O state of the underlying reader. However, many readers (e.g. `File`) allow I/O using a shared reference (e.g. `&File`). So, add the same caveat to the `get_ref` methods. --- library/std/src/io/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index b6545eada86a..5242261cf93f 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2658,6 +2658,10 @@ impl Chain { /// Gets references to the underlying readers in this `Chain`. /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + /// /// # Examples /// /// ```no_run @@ -2915,6 +2919,10 @@ impl Take { /// Gets a reference to the underlying reader. /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying reader as doing so may corrupt the internal limit of this + /// `Take`. + /// /// # Examples /// /// ```no_run From 38f7060a73acd5ec6ed7d4820dccbf2aa584fc68 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 15 Apr 2025 21:00:11 +0300 Subject: [PATCH 186/222] Revert "Deduplicate template parameter creation" This reverts commit 6adc2c1fd6ecde7bf83c8b8fbc71f402ced87054. --- .../src/debuginfo/metadata.rs | 36 +++++++------------ .../src/debuginfo/metadata/enums/mod.rs | 1 - .../rustc_codegen_llvm/src/debuginfo/mod.rs | 34 ++++++++++++++++-- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1eb8f367c544..7f3e486ca310 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1315,31 +1315,21 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( ty: Ty<'tcx>, ) -> SmallVec> { if let ty::Adt(def, args) = *ty.kind() { - let generics = cx.tcx.generics_of(def.did()); - return get_template_parameters(cx, generics, args); - } - - return smallvec![]; -} - -pub(super) fn get_template_parameters<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, - generics: &ty::Generics, - args: ty::GenericArgsRef<'tcx>, -) -> SmallVec> { - if args.types().next().is_some() { - let names = get_parameter_names(cx, generics); - let template_params: SmallVec<_> = iter::zip(args, names) - .filter_map(|(kind, name)| { - kind.as_type().map(|ty| { - let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); - let actual_type_di_node = type_di_node(cx, actual_type); - Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node)) + if args.types().next().is_some() { + let generics = cx.tcx.generics_of(def.did()); + let names = get_parameter_names(cx, generics); + let template_params: SmallVec<_> = iter::zip(args, names) + .filter_map(|(kind, name)| { + kind.as_type().map(|ty| { + let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); + let actual_type_di_node = type_di_node(cx, actual_type); + Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node)) + }) }) - }) - .collect(); + .collect(); - return template_params; + return template_params; + } } return smallvec![]; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 6792c307fdc4..7c701926d2c5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -363,7 +363,6 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>( state_specific_fields.into_iter().chain(common_fields).collect() }, - // FIXME: this is a no-op. `build_generic_type_param_di_nodes` only works for Adts. |cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty), ) .di_node diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index ae7d080db66f..0f94a1dbb0d5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -2,8 +2,8 @@ use std::cell::{OnceCell, RefCell}; use std::ops::Range; -use std::ptr; use std::sync::Arc; +use std::{iter, ptr}; use libc::c_uint; use metadata::create_subroutine_type; @@ -486,10 +486,40 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { generics: &ty::Generics, args: GenericArgsRef<'tcx>, ) -> &'ll DIArray { - let template_params = metadata::get_template_parameters(cx, generics, args); + if args.types().next().is_none() { + return create_DIArray(DIB(cx), &[]); + } + + // Again, only create type information if full debuginfo is enabled + let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full { + let names = get_parameter_names(cx, generics); + iter::zip(args, names) + .filter_map(|(kind, name)| { + kind.as_type().map(|ty| { + let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); + let actual_type_metadata = type_di_node(cx, actual_type); + Some(cx.create_template_type_parameter( + name.as_str(), + actual_type_metadata, + )) + }) + }) + .collect() + } else { + vec![] + }; + create_DIArray(DIB(cx), &template_params) } + fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec { + let mut names = generics.parent.map_or_else(Vec::new, |def_id| { + get_parameter_names(cx, cx.tcx.generics_of(def_id)) + }); + names.extend(generics.own_params.iter().map(|param| param.name)); + names + } + /// Returns a scope, plus `true` if that's a type scope for "class" methods, /// otherwise `false` for plain namespace scopes. fn get_containing_scope<'ll, 'tcx>( From c774adcbb535e69bffe5be329af006959f897fbd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Apr 2025 15:10:43 +0000 Subject: [PATCH 187/222] Split TypeFolder and FallibleTypeFolder --- compiler/rustc_macros/src/type_foldable.rs | 60 ++++-- compiler/rustc_middle/src/infer/canonical.rs | 9 - compiler/rustc_middle/src/mir/syntax.rs | 4 + compiler/rustc_middle/src/ty/generic_args.rs | 47 ++++- compiler/rustc_middle/src/ty/mod.rs | 7 + .../rustc_middle/src/ty/structural_impls.rs | 191 ++++++++++------- compiler/rustc_middle/src/ty/util.rs | 36 ++++ compiler/rustc_type_ir/src/binder.rs | 10 +- compiler/rustc_type_ir/src/fold.rs | 192 ++++++++++-------- compiler/rustc_type_ir_macros/src/lib.rs | 27 ++- 10 files changed, 396 insertions(+), 187 deletions(-) diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index c4f584dca430..85051311bee9 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -14,31 +14,33 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m s.add_bounds(synstructure::AddBounds::Generics); s.bind_with(|_| synstructure::BindStyle::Move); + let try_body_fold = s.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|_, index| { + let bind = &bindings[index]; + + // retain value of fields with #[type_foldable(identity)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + bind.to_token_stream() + } else { + quote! { + ::rustc_middle::ty::TypeFoldable::try_fold_with(#bind, __folder)? + } + } + }) + }); + let body_fold = s.each_variant(|vi| { let bindings = vi.bindings(); vi.construct(|_, index| { let bind = &bindings[index]; - let mut fixed = false; - // retain value of fields with #[type_foldable(identity)] - bind.ast().attrs.iter().for_each(|x| { - if !x.path().is_ident("type_foldable") { - return; - } - let _ = x.parse_nested_meta(|nested| { - if nested.path.is_ident("identity") { - fixed = true; - } - Ok(()) - }); - }); - - if fixed { + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { bind.to_token_stream() } else { quote! { - ::rustc_middle::ty::TypeFoldable::try_fold_with(#bind, __folder)? + ::rustc_middle::ty::TypeFoldable::fold_with(#bind, __folder) } } }) @@ -51,8 +53,32 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m self, __folder: &mut __F ) -> Result { - Ok(match self { #body_fold }) + Ok(match self { #try_body_fold }) + } + + fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>( + self, + __folder: &mut __F + ) -> Self { + match self { #body_fold } } }, ) } + +fn has_ignore_attr(attrs: &[syn::Attribute], name: &'static str, meta: &'static str) -> bool { + let mut ignored = false; + attrs.iter().for_each(|attr| { + if !attr.path().is_ident(name) { + return; + } + let _ = attr.parse_nested_meta(|nested| { + if nested.path.is_ident(meta) { + ignored = true; + } + Ok(()) + }); + }); + + ignored +} diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 3cd148cd4427..5b8603744961 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -39,15 +39,6 @@ pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo>; pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues>; pub type CanonicalVarInfos<'tcx> = &'tcx List>; -impl<'tcx> ty::TypeFoldable> for CanonicalVarInfos<'tcx> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_canonical_var_infos(v)) - } -} - /// When we canonicalize a value to form a query, we wind up replacing /// various parts of it with canonical variables. This struct stores /// those replaced bits to remember for when we process the query diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index ff9d32ebb719..c7561f8afef9 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -931,6 +931,8 @@ pub enum TerminatorKind<'tcx> { asm_macro: InlineAsmMacro, /// The template for the inline assembly, with placeholders. + #[type_foldable(identity)] + #[type_visitable(ignore)] template: &'tcx [InlineAsmTemplatePiece], /// The operands for the inline assembly, as `Operand`s or `Place`s. @@ -941,6 +943,8 @@ pub enum TerminatorKind<'tcx> { /// Source spans for each line of the inline assembly code. These are /// used to map assembler errors back to the line in the source code. + #[type_foldable(identity)] + #[type_visitable(ignore)] line_spans: &'tcx [Span], /// Valid targets for the inline assembly. diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 1f04937232dd..8de64b3bfac6 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -17,7 +17,7 @@ use smallvec::SmallVec; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::{ self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, InlineConstArgs, - Lift, List, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, VisitorResult, + Lift, List, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, VisitorResult, walk_visitable_list, }; @@ -337,6 +337,14 @@ impl<'tcx> TypeFoldable> for GenericArg<'tcx> { GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into), } } + + fn fold_with>>(self, folder: &mut F) -> Self { + match self.unpack() { + GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(), + GenericArgKind::Type(ty) => ty.fold_with(folder).into(), + GenericArgKind::Const(ct) => ct.fold_with(folder).into(), + } + } } impl<'tcx> TypeVisitable> for GenericArg<'tcx> { @@ -606,6 +614,27 @@ impl<'tcx> TypeFoldable> for GenericArgsRef<'tcx> { } } 0 => Ok(self), + _ => ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_args(v)), + } + } + + fn fold_with>>(self, folder: &mut F) -> Self { + // See justification for this behavior in `try_fold_with`. + match self.len() { + 1 => { + let param0 = self[0].fold_with(folder); + if param0 == self[0] { self } else { folder.cx().mk_args(&[param0]) } + } + 2 => { + let param0 = self[0].fold_with(folder); + let param1 = self[1].fold_with(folder); + if param0 == self[0] && param1 == self[1] { + self + } else { + folder.cx().mk_args(&[param0, param1]) + } + } + 0 => self, _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_args(v)), } } @@ -641,6 +670,22 @@ impl<'tcx> TypeFoldable> for &'tcx ty::List> { Ok(folder.cx().mk_type_list(&[param0, param1])) } } + _ => ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)), + } + } + + fn fold_with>>(self, folder: &mut F) -> Self { + // See comment justifying behavior in `try_fold_with`. + match self.len() { + 2 => { + let param0 = self[0].fold_with(folder); + let param1 = self[1].fold_with(folder); + if param0 == self[0] && param1 == self[1] { + self + } else { + folder.cx().mk_type_list(&[param0, param1]) + } + } _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)), } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 61e869f5de41..673e1cafa9df 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -537,6 +537,13 @@ impl<'tcx> TypeFoldable> for Term<'tcx> { ty::TermKind::Const(ct) => ct.try_fold_with(folder).map(Into::into), } } + + fn fold_with>>(self, folder: &mut F) -> Self { + match self.unpack() { + ty::TermKind::Ty(ty) => ty.fold_with(folder).into(), + ty::TermKind::Const(ct) => ct.fold_with(folder).into(), + } + } } impl<'tcx> TypeVisitable> for Term<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 798ef352c408..40eef541423c 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -6,20 +6,19 @@ use std::fmt::{self, Debug}; use rustc_abi::TyAndLayout; -use rustc_ast::InlineAsmTemplatePiece; use rustc_hir::def::Namespace; use rustc_hir::def_id::LocalDefId; -use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_type_ir::{ConstKind, VisitorResult, try_visit}; +use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit}; use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Pattern, Region}; +use crate::infer::canonical::CanonicalVarInfos; use crate::mir::PlaceElem; use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths}; use crate::ty::{ - self, FallibleTypeFolder, InferConst, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable, - TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, + self, FallibleTypeFolder, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitor, }; impl fmt::Debug for ty::TraitDef { @@ -271,6 +270,7 @@ TrivialTypeTraversalImpls! { crate::ty::AssocKind, crate::ty::BoundRegion, crate::ty::BoundVar, + crate::ty::InferConst, crate::ty::Placeholder, crate::ty::Placeholder, crate::ty::Placeholder, @@ -337,24 +337,6 @@ impl<'tcx> TypeVisitable> for ty::AdtDef<'tcx> { } } -impl<'tcx> TypeFoldable> for &'tcx ty::List> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_poly_existential_predicates(v)) - } -} - -impl<'tcx> TypeFoldable> for &'tcx ty::List> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_const_list(v)) - } -} - impl<'tcx> TypeFoldable> for Pattern<'tcx> { fn try_fold_with>>( self, @@ -363,6 +345,11 @@ impl<'tcx> TypeFoldable> for Pattern<'tcx> { let pat = (*self).clone().try_fold_with(folder)?; Ok(if pat == *self { self } else { folder.cx().mk_pat(pat) }) } + + fn fold_with>>(self, folder: &mut F) -> Self { + let pat = (*self).clone().fold_with(folder); + if pat == *self { self } else { folder.cx().mk_pat(pat) } + } } impl<'tcx> TypeVisitable> for Pattern<'tcx> { @@ -378,6 +365,10 @@ impl<'tcx> TypeFoldable> for Ty<'tcx> { ) -> Result { folder.try_fold_ty(self) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_ty(self) + } } impl<'tcx> TypeVisitable> for Ty<'tcx> { @@ -436,6 +427,45 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { Ok(if *self.kind() == kind { self } else { folder.cx().mk_ty_from_kind(kind) }) } + + fn super_fold_with>>(self, folder: &mut F) -> Self { + let kind = match *self.kind() { + ty::RawPtr(ty, mutbl) => ty::RawPtr(ty.fold_with(folder), mutbl), + ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), + ty::Slice(typ) => ty::Slice(typ.fold_with(folder)), + ty::Adt(tid, args) => ty::Adt(tid, args.fold_with(folder)), + ty::Dynamic(trait_ty, region, representation) => { + ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder), representation) + } + ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)), + ty::FnDef(def_id, args) => ty::FnDef(def_id, args.fold_with(folder)), + ty::FnPtr(sig_tys, hdr) => ty::FnPtr(sig_tys.fold_with(folder), hdr), + ty::UnsafeBinder(f) => ty::UnsafeBinder(f.fold_with(folder)), + ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl), + ty::Coroutine(did, args) => ty::Coroutine(did, args.fold_with(folder)), + ty::CoroutineWitness(did, args) => ty::CoroutineWitness(did, args.fold_with(folder)), + ty::Closure(did, args) => ty::Closure(did, args.fold_with(folder)), + ty::CoroutineClosure(did, args) => ty::CoroutineClosure(did, args.fold_with(folder)), + ty::Alias(kind, data) => ty::Alias(kind, data.fold_with(folder)), + ty::Pat(ty, pat) => ty::Pat(ty.fold_with(folder), pat.fold_with(folder)), + + ty::Bool + | ty::Char + | ty::Str + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Error(_) + | ty::Infer(_) + | ty::Param(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Never + | ty::Foreign(..) => return self, + }; + + if *self.kind() == kind { self } else { folder.cx().mk_ty_from_kind(kind) } + } } impl<'tcx> TypeSuperVisitable> for Ty<'tcx> { @@ -496,6 +526,10 @@ impl<'tcx> TypeFoldable> for ty::Region<'tcx> { ) -> Result { folder.try_fold_region(self) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_region(self) + } } impl<'tcx> TypeVisitable> for ty::Region<'tcx> { @@ -511,6 +545,10 @@ impl<'tcx> TypeFoldable> for ty::Predicate<'tcx> { ) -> Result { folder.try_fold_predicate(self) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_predicate(self) + } } // FIXME(clause): This is wonky @@ -521,6 +559,10 @@ impl<'tcx> TypeFoldable> for ty::Clause<'tcx> { ) -> Result { Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause()) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_predicate(self.as_predicate()).expect_clause() + } } impl<'tcx> TypeVisitable> for ty::Predicate<'tcx> { @@ -543,6 +585,11 @@ impl<'tcx> TypeSuperFoldable> for ty::Predicate<'tcx> { let new = self.kind().try_fold_with(folder)?; Ok(folder.cx().reuse_or_mk_predicate(self, new)) } + + fn super_fold_with>>(self, folder: &mut F) -> Self { + let new = self.kind().fold_with(folder); + folder.cx().reuse_or_mk_predicate(self, new) + } } impl<'tcx> TypeSuperVisitable> for ty::Predicate<'tcx> { @@ -563,15 +610,6 @@ impl<'tcx> TypeSuperVisitable> for ty::Clauses<'tcx> { } } -impl<'tcx> TypeFoldable> for ty::Clauses<'tcx> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_clauses(v)) - } -} - impl<'tcx> TypeFoldable> for ty::Const<'tcx> { fn try_fold_with>>( self, @@ -579,6 +617,10 @@ impl<'tcx> TypeFoldable> for ty::Const<'tcx> { ) -> Result { folder.try_fold_const(self) } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_const(self) + } } impl<'tcx> TypeVisitable> for ty::Const<'tcx> { @@ -606,6 +648,20 @@ impl<'tcx> TypeSuperFoldable> for ty::Const<'tcx> { }; if kind != self.kind() { Ok(folder.cx().mk_ct_from_kind(kind)) } else { Ok(self) } } + + fn super_fold_with>>(self, folder: &mut F) -> Self { + let kind = match self.kind() { + ConstKind::Param(p) => ConstKind::Param(p.fold_with(folder)), + ConstKind::Infer(i) => ConstKind::Infer(i.fold_with(folder)), + ConstKind::Bound(d, b) => ConstKind::Bound(d.fold_with(folder), b.fold_with(folder)), + ConstKind::Placeholder(p) => ConstKind::Placeholder(p.fold_with(folder)), + ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.fold_with(folder)), + ConstKind::Value(v) => ConstKind::Value(v.fold_with(folder)), + ConstKind::Error(e) => ConstKind::Error(e.fold_with(folder)), + ConstKind::Expr(e) => ConstKind::Expr(e.fold_with(folder)), + }; + if kind != self.kind() { folder.cx().mk_ct_from_kind(kind) } else { self } + } } impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { @@ -639,20 +695,9 @@ impl<'tcx> TypeFoldable> for rustc_span::ErrorGuaranteed { ) -> Result { Ok(self) } -} -impl<'tcx> TypeFoldable> for InferConst { - fn try_fold_with>>( - self, - _folder: &mut F, - ) -> Result { - Ok(self) - } -} - -impl<'tcx> TypeVisitable> for InferConst { - fn visit_with>>(&self, _visitor: &mut V) -> V::Result { - V::Result::output() + fn fold_with>>(self, _folder: &mut F) -> Self { + self } } @@ -683,23 +728,9 @@ impl<'tcx, T: TypeFoldable> + Debug + Clone> TypeFoldable TypeFoldable> for &'tcx [InlineAsmTemplatePiece] { - fn try_fold_with>>( - self, - _folder: &mut F, - ) -> Result { - Ok(self) - } -} - -impl<'tcx> TypeFoldable> for &'tcx [Span] { - fn try_fold_with>>( - self, - _folder: &mut F, - ) -> Result { - Ok(self) + fn fold_with>>(self, folder: &mut F) -> Self { + Spanned { node: self.node.fold_with(folder), span: self.span.fold_with(folder) } } } @@ -710,13 +741,37 @@ impl<'tcx> TypeFoldable> for &'tcx ty::List { ) -> Result { Ok(self) } -} -impl<'tcx> TypeFoldable> for &'tcx ty::List> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_place_elems(v)) + fn fold_with>>(self, _folder: &mut F) -> Self { + self } } + +macro_rules! list_fold { + ($($ty:ty : $mk:ident),+ $(,)?) => { + $( + impl<'tcx> TypeFoldable> for $ty { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + ty::util::try_fold_list(self, folder, |tcx, v| tcx.$mk(v)) + } + + fn fold_with>>( + self, + folder: &mut F, + ) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.$mk(v)) + } + } + )* + } +} + +list_fold! { + ty::Clauses<'tcx> : mk_clauses, + &'tcx ty::List> : mk_poly_existential_predicates, + &'tcx ty::List> : mk_place_elems, + CanonicalVarInfos<'tcx> : mk_canonical_var_infos, +} diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 857b462b9eb1..e7140720b1c7 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1647,6 +1647,42 @@ pub fn fold_list<'tcx, F, L, T>( list: L, folder: &mut F, intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> L, +) -> L +where + F: TypeFolder>, + L: AsRef<[T]>, + T: TypeFoldable> + PartialEq + Copy, +{ + let slice = list.as_ref(); + let mut iter = slice.iter().copied(); + // Look for the first element that changed + match iter.by_ref().enumerate().find_map(|(i, t)| { + let new_t = t.fold_with(folder); + if new_t != t { Some((i, new_t)) } else { None } + }) { + Some((i, new_t)) => { + // An element changed, prepare to intern the resulting list + let mut new_list = SmallVec::<[_; 8]>::with_capacity(slice.len()); + new_list.extend_from_slice(&slice[..i]); + new_list.push(new_t); + for t in iter { + new_list.push(t.fold_with(folder)) + } + intern(folder.cx(), &new_list) + } + None => list, + } +} + +/// Does the equivalent of +/// ```ignore (illustrative) +/// let v = self.iter().map(|p| p.try_fold_with(folder)).collect::>(); +/// folder.tcx().intern_*(&v) +/// ``` +pub fn try_fold_list<'tcx, F, L, T>( + list: L, + folder: &mut F, + intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> L, ) -> Result where F: FallibleTypeFolder>, diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index e9055940310d..27ea4e211fef 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -122,6 +122,10 @@ impl> TypeFoldable for Binder { fn try_fold_with>(self, folder: &mut F) -> Result { folder.try_fold_binder(self) } + + fn fold_with>(self, folder: &mut F) -> Self { + folder.fold_binder(self) + } } impl> TypeVisitable for Binder { @@ -135,7 +139,11 @@ impl> TypeSuperFoldable for Binder { self, folder: &mut F, ) -> Result { - self.try_map_bound(|ty| ty.try_fold_with(folder)) + self.try_map_bound(|t| t.try_fold_with(folder)) + } + + fn super_fold_with>(self, folder: &mut F) -> Self { + self.map_bound(|t| t.fold_with(folder)) } } diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index e58f25f4ce78..ce1188070ca7 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -45,6 +45,7 @@ //! - u.fold_with(folder) //! ``` +use std::convert::Infallible; use std::mem; use std::sync::Arc; @@ -56,12 +57,6 @@ use crate::inherent::*; use crate::visit::{TypeVisitable, TypeVisitableExt as _}; use crate::{self as ty, Interner, TypeFlags}; -#[cfg(feature = "nightly")] -type Never = !; - -#[cfg(not(feature = "nightly"))] -type Never = std::convert::Infallible; - /// This trait is implemented for every type that can be folded, /// providing the skeleton of the traversal. /// @@ -82,18 +77,24 @@ pub trait TypeFoldable: TypeVisitable + Clone { /// /// For types of interest (such as `Ty`), the implementation of this method /// calls a folder method specifically for that type (such as - /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable` - /// to `TypeFolder`. + /// `F::try_fold_ty`). This is where control transfers from [`TypeFoldable`] + /// to [`FallibleTypeFolder`]. fn try_fold_with>(self, folder: &mut F) -> Result; - /// A convenient alternative to `try_fold_with` for use with infallible - /// folders. Do not override this method, to ensure coherence with - /// `try_fold_with`. - fn fold_with>(self, folder: &mut F) -> Self { - match self.try_fold_with(folder) { - Ok(t) => t, - } - } + /// The entry point for folding. To fold a value `t` with a folder `f` + /// call: `t.fold_with(f)`. + /// + /// For most types, this just traverses the value, calling `fold_with` + /// on each field/element. + /// + /// For types of interest (such as `Ty`), the implementation of this method + /// calls a folder method specifically for that type (such as + /// `F::fold_ty`). This is where control transfers from `TypeFoldable` + /// to `TypeFolder`. + /// + /// Same as [`TypeFoldable::try_fold_with`], but not fallible. Make sure to keep + /// the behavior in sync across functions. + fn fold_with>(self, folder: &mut F) -> Self; } // This trait is implemented for types of interest. @@ -112,11 +113,7 @@ pub trait TypeSuperFoldable: TypeFoldable { /// A convenient alternative to `try_super_fold_with` for use with /// infallible folders. Do not override this method, to ensure coherence /// with `try_super_fold_with`. - fn super_fold_with>(self, folder: &mut F) -> Self { - match self.try_super_fold_with(folder) { - Ok(t) => t, - } - } + fn super_fold_with>(self, folder: &mut F) -> Self; } /// This trait is implemented for every infallible folding traversal. There is @@ -128,7 +125,7 @@ pub trait TypeSuperFoldable: TypeFoldable { /// A blanket implementation of [`FallibleTypeFolder`] will defer to /// the infallible methods of this trait to ensure that the two APIs /// are coherent. -pub trait TypeFolder: FallibleTypeFolder { +pub trait TypeFolder: Sized { fn cx(&self) -> I; fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder @@ -195,42 +192,6 @@ pub trait FallibleTypeFolder: Sized { } } -// This blanket implementation of the fallible trait for infallible folders -// delegates to infallible methods to ensure coherence. -impl FallibleTypeFolder for F -where - F: TypeFolder, -{ - type Error = Never; - - fn cx(&self) -> I { - TypeFolder::cx(self) - } - - fn try_fold_binder(&mut self, t: ty::Binder) -> Result, Never> - where - T: TypeFoldable, - { - Ok(self.fold_binder(t)) - } - - fn try_fold_ty(&mut self, t: I::Ty) -> Result { - Ok(self.fold_ty(t)) - } - - fn try_fold_region(&mut self, r: I::Region) -> Result { - Ok(self.fold_region(r)) - } - - fn try_fold_const(&mut self, c: I::Const) -> Result { - Ok(self.fold_const(c)) - } - - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { - Ok(self.fold_predicate(p)) - } -} - /////////////////////////////////////////////////////////////////////////// // Traversal implementations. @@ -238,6 +199,10 @@ impl, U: TypeFoldable> TypeFoldable for (T fn try_fold_with>(self, folder: &mut F) -> Result<(T, U), F::Error> { Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?)) } + + fn fold_with>(self, folder: &mut F) -> Self { + (self.0.fold_with(folder), self.1.fold_with(folder)) + } } impl, B: TypeFoldable, C: TypeFoldable> TypeFoldable @@ -253,6 +218,10 @@ impl, B: TypeFoldable, C: TypeFoldable> Ty self.2.try_fold_with(folder)?, )) } + + fn fold_with>(self, folder: &mut F) -> Self { + (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) + } } impl> TypeFoldable for Option { @@ -262,6 +231,10 @@ impl> TypeFoldable for Option { None => None, }) } + + fn fold_with>(self, folder: &mut F) -> Self { + Some(self?.fold_with(folder)) + } } impl, E: TypeFoldable> TypeFoldable for Result { @@ -271,41 +244,61 @@ impl, E: TypeFoldable> TypeFoldable for Re Err(e) => Err(e.try_fold_with(folder)?), }) } + + fn fold_with>(self, folder: &mut F) -> Self { + match self { + Ok(v) => Ok(v.fold_with(folder)), + Err(e) => Err(e.fold_with(folder)), + } + } +} + +fn fold_arc( + mut arc: Arc, + fold: impl FnOnce(T) -> Result, +) -> Result, E> { + // We merely want to replace the contained `T`, if at all possible, + // so that we don't needlessly allocate a new `Arc` or indeed clone + // the contained type. + unsafe { + // First step is to ensure that we have a unique reference to + // the contained type, which `Arc::make_mut` will accomplish (by + // allocating a new `Arc` and cloning the `T` only if required). + // This is done *before* casting to `Arc>` so that + // panicking during `make_mut` does not leak the `T`. + Arc::make_mut(&mut arc); + + // Casting to `Arc>` is safe because `ManuallyDrop` + // is `repr(transparent)`. + let ptr = Arc::into_raw(arc).cast::>(); + let mut unique = Arc::from_raw(ptr); + + // Call to `Arc::make_mut` above guarantees that `unique` is the + // sole reference to the contained value, so we can avoid doing + // a checked `get_mut` here. + let slot = Arc::get_mut(&mut unique).unwrap_unchecked(); + + // Semantically move the contained type out from `unique`, fold + // it, then move the folded value back into `unique`. Should + // folding fail, `ManuallyDrop` ensures that the "moved-out" + // value is not re-dropped. + let owned = mem::ManuallyDrop::take(slot); + let folded = fold(owned)?; + *slot = mem::ManuallyDrop::new(folded); + + // Cast back to `Arc`. + Ok(Arc::from_raw(Arc::into_raw(unique).cast())) + } } impl> TypeFoldable for Arc { - fn try_fold_with>(mut self, folder: &mut F) -> Result { - // We merely want to replace the contained `T`, if at all possible, - // so that we don't needlessly allocate a new `Arc` or indeed clone - // the contained type. - unsafe { - // First step is to ensure that we have a unique reference to - // the contained type, which `Arc::make_mut` will accomplish (by - // allocating a new `Arc` and cloning the `T` only if required). - // This is done *before* casting to `Arc>` so that - // panicking during `make_mut` does not leak the `T`. - Arc::make_mut(&mut self); + fn try_fold_with>(self, folder: &mut F) -> Result { + fold_arc(self, |t| t.try_fold_with(folder)) + } - // Casting to `Arc>` is safe because `ManuallyDrop` - // is `repr(transparent)`. - let ptr = Arc::into_raw(self).cast::>(); - let mut unique = Arc::from_raw(ptr); - - // Call to `Arc::make_mut` above guarantees that `unique` is the - // sole reference to the contained value, so we can avoid doing - // a checked `get_mut` here. - let slot = Arc::get_mut(&mut unique).unwrap_unchecked(); - - // Semantically move the contained type out from `unique`, fold - // it, then move the folded value back into `unique`. Should - // folding fail, `ManuallyDrop` ensures that the "moved-out" - // value is not re-dropped. - let owned = mem::ManuallyDrop::take(slot); - let folded = owned.try_fold_with(folder)?; - *slot = mem::ManuallyDrop::new(folded); - - // Cast back to `Arc`. - Ok(Arc::from_raw(Arc::into_raw(unique).cast())) + fn fold_with>(self, folder: &mut F) -> Self { + match fold_arc::(self, |t| Ok(t.fold_with(folder))) { + Ok(t) => t, } } } @@ -315,30 +308,51 @@ impl> TypeFoldable for Box { *self = (*self).try_fold_with(folder)?; Ok(self) } + + fn fold_with>(mut self, folder: &mut F) -> Self { + *self = (*self).fold_with(folder); + self + } } impl> TypeFoldable for Vec { fn try_fold_with>(self, folder: &mut F) -> Result { self.into_iter().map(|t| t.try_fold_with(folder)).collect() } + + fn fold_with>(self, folder: &mut F) -> Self { + self.into_iter().map(|t| t.fold_with(folder)).collect() + } } impl> TypeFoldable for ThinVec { fn try_fold_with>(self, folder: &mut F) -> Result { self.into_iter().map(|t| t.try_fold_with(folder)).collect() } + + fn fold_with>(self, folder: &mut F) -> Self { + self.into_iter().map(|t| t.fold_with(folder)).collect() + } } impl> TypeFoldable for Box<[T]> { fn try_fold_with>(self, folder: &mut F) -> Result { Vec::from(self).try_fold_with(folder).map(Vec::into_boxed_slice) } + + fn fold_with>(self, folder: &mut F) -> Self { + Vec::into_boxed_slice(Vec::from(self).fold_with(folder)) + } } impl, Ix: Idx> TypeFoldable for IndexVec { fn try_fold_with>(self, folder: &mut F) -> Result { self.raw.try_fold_with(folder).map(IndexVec::from_raw) } + + fn fold_with>(self, folder: &mut F) -> Self { + IndexVec::from_raw(self.raw.fold_with(folder)) + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 8eefecdc980e..3a10d0d41ef3 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -83,7 +83,7 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke s.add_where_predicate(parse_quote! { I: Interner }); s.add_bounds(synstructure::AddBounds::Fields); s.bind_with(|_| synstructure::BindStyle::Move); - let body_fold = s.each_variant(|vi| { + let body_try_fold = s.each_variant(|vi| { let bindings = vi.bindings(); vi.construct(|_, index| { let bind = &bindings[index]; @@ -99,6 +99,22 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke }) }); + let body_fold = s.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|_, index| { + let bind = &bindings[index]; + + // retain value of fields with #[type_foldable(identity)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + bind.to_token_stream() + } else { + quote! { + ::rustc_type_ir::TypeFoldable::fold_with(#bind, __folder) + } + } + }) + }); + // We filter fields which get ignored and don't require them to implement // `TypeFoldable`. We do so after generating `body_fold` as we still need // to generate code for them. @@ -111,7 +127,14 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke self, __folder: &mut __F ) -> Result { - Ok(match self { #body_fold }) + Ok(match self { #body_try_fold }) + } + + fn fold_with<__F: ::rustc_type_ir::TypeFolder>( + self, + __folder: &mut __F + ) -> Self { + match self { #body_fold } } }, ) From 11e5987d017b4ab8dfc522d674aea704aad8605a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Apr 2025 18:46:07 +0000 Subject: [PATCH 188/222] Don't compute name of associated item if it's an RPITIT --- .../rustc_hir_analysis/src/hir_ty_lowering/errors.rs | 3 +-- .../in-trait/dont-probe-missing-item-name.rs | 12 ++++++++++++ .../in-trait/dont-probe-missing-item-name.stderr | 9 +++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs create mode 100644 tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 72f219bfeb80..3759a224ff75 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -204,8 +204,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order()) .filter_map(|item| { - (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag) - .then_some(item.name()) + (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then(|| item.name()) }) .collect(); diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs new file mode 100644 index 000000000000..450f41e209df --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs @@ -0,0 +1,12 @@ +// Regression test for . + +// Test that we don't try to get the (nonexistent) name of the RPITIT in `Trait::foo` +// when emitting an error for a missing associated item `Trait::Output`. + +trait Trait { + fn foo() -> impl Sized; + fn bar() -> Self::Output; + //~^ ERROR associated type `Output` not found for `Self` +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr new file mode 100644 index 000000000000..74e15785af19 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr @@ -0,0 +1,9 @@ +error[E0220]: associated type `Output` not found for `Self` + --> $DIR/dont-probe-missing-item-name.rs:8:23 + | +LL | fn bar() -> Self::Output; + | ^^^^^^ associated type `Output` not found + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0220`. From 2020adba86cb2852b11ab11a440975fb331e8424 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Apr 2025 16:59:16 +0200 Subject: [PATCH 189/222] Fix wrong suggestion for async gen block and add regression ui test for #139839 --- .../src/diagnostics/conflict_errors.rs | 13 +++-- .../async-gen-move-suggestion.fixed | 35 ++++++++++++++ .../async-await/async-gen-move-suggestion.rs | 35 ++++++++++++++ .../async-gen-move-suggestion.stderr | 47 +++++++++++++++++++ 4 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 tests/ui/async-await/async-gen-move-suggestion.fixed create mode 100644 tests/ui/async-await/async-gen-move-suggestion.rs create mode 100644 tests/ui/async-await/async-gen-move-suggestion.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index fe6dff7ff1b6..959cf9fa5139 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3376,10 +3376,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) { Ok(string) => { - let coro_prefix = if string.starts_with("async") { - // `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize` - // to `u32`. - Some(5) + let coro_prefix = if let Some(sub) = string.strip_prefix("async") { + let trimmed_sub = sub.trim_end(); + if trimmed_sub.ends_with("gen") { + // `async` is 5 chars long. + Some((trimmed_sub.len() + 5) as _) + } else { + // `async` is 5 chars long. + Some(5) + } } else if string.starts_with("gen") { // `gen` is 3 chars long Some(3) diff --git a/tests/ui/async-await/async-gen-move-suggestion.fixed b/tests/ui/async-await/async-gen-move-suggestion.fixed new file mode 100644 index 000000000000..d80207655289 --- /dev/null +++ b/tests/ui/async-await/async-gen-move-suggestion.fixed @@ -0,0 +1,35 @@ +// This is a regression test for . +// It ensures that the "add `move` keyword" suggestion is valid. + +//@ run-rustfix +//@ edition:2024 + +#![feature(coroutines)] +#![feature(gen_blocks)] +#![feature(async_iterator)] + +use std::async_iter::AsyncIterator; + +#[allow(dead_code)] +fn moved() -> impl AsyncIterator { + let mut x = "foo".to_string(); + + async gen move { //~ ERROR + x.clear(); + for x in 3..6 { yield x } + } +} + +#[allow(dead_code)] +fn check_with_whitespace_chars() -> impl AsyncIterator { + let mut x = "foo".to_string(); + + async // Just to check that whitespace characters are correctly handled + gen move { //~^ ERROR + x.clear(); + for x in 3..6 { yield x } + } +} + +fn main() { +} diff --git a/tests/ui/async-await/async-gen-move-suggestion.rs b/tests/ui/async-await/async-gen-move-suggestion.rs new file mode 100644 index 000000000000..825fb0fd1898 --- /dev/null +++ b/tests/ui/async-await/async-gen-move-suggestion.rs @@ -0,0 +1,35 @@ +// This is a regression test for . +// It ensures that the "add `move` keyword" suggestion is valid. + +//@ run-rustfix +//@ edition:2024 + +#![feature(coroutines)] +#![feature(gen_blocks)] +#![feature(async_iterator)] + +use std::async_iter::AsyncIterator; + +#[allow(dead_code)] +fn moved() -> impl AsyncIterator { + let mut x = "foo".to_string(); + + async gen { //~ ERROR + x.clear(); + for x in 3..6 { yield x } + } +} + +#[allow(dead_code)] +fn check_with_whitespace_chars() -> impl AsyncIterator { + let mut x = "foo".to_string(); + + async // Just to check that whitespace characters are correctly handled + gen { //~^ ERROR + x.clear(); + for x in 3..6 { yield x } + } +} + +fn main() { +} diff --git a/tests/ui/async-await/async-gen-move-suggestion.stderr b/tests/ui/async-await/async-gen-move-suggestion.stderr new file mode 100644 index 000000000000..b8cdb8be7a4a --- /dev/null +++ b/tests/ui/async-await/async-gen-move-suggestion.stderr @@ -0,0 +1,47 @@ +error[E0373]: async gen block may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-gen-move-suggestion.rs:17:5 + | +LL | async gen { + | ^^^^^^^^^ may outlive borrowed value `x` +LL | x.clear(); + | - `x` is borrowed here + | +note: async gen block is returned here + --> $DIR/async-gen-move-suggestion.rs:17:5 + | +LL | / async gen { +LL | | x.clear(); +LL | | for x in 3..6 { yield x } +LL | | } + | |_____^ +help: to force the async gen block to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | async gen move { + | ++++ + +error[E0373]: async gen block may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-gen-move-suggestion.rs:27:5 + | +LL | / async // Just to check that whitespace characters are correctly handled +LL | | gen { + | |_______^ may outlive borrowed value `x` +LL | x.clear(); + | - `x` is borrowed here + | +note: async gen block is returned here + --> $DIR/async-gen-move-suggestion.rs:27:5 + | +LL | / async // Just to check that whitespace characters are correctly handled +LL | | gen { +LL | | x.clear(); +LL | | for x in 3..6 { yield x } +LL | | } + | |_____^ +help: to force the async gen block to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | gen move { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0373`. From 90aec1367481ab05c78fefad314e03b26e84564f Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 15 Apr 2025 14:06:51 +0200 Subject: [PATCH 190/222] commit rustfmt stump in `x t tidy` even on `check` If checking succeeded, it's equivalent to successfully formatting. --- src/bootstrap/src/core/build_steps/format.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 6641c4b4e139..9da8b27a9177 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -336,7 +336,10 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { crate::exit!(1); } - if !check { - update_rustfmt_version(build); - } + // Update `build/.rustfmt-stamp`, allowing this code to ignore files which have not been changed + // since last merge. + // + // NOTE: Because of the exit above, this is only reachable if formatting / format checking + // succeeded. So we are not commiting the version if formatting was not good. + update_rustfmt_version(build); } From 89b4eba49cc15e0a4e53f7816473201d12be5f4f Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 15 Apr 2025 10:09:31 +0200 Subject: [PATCH 191/222] normalize canonical and non-canonical paths in compiletest Apparently there are tests that print canonical paths *and* tests which print non-canonical paths. An example of the latter is `tests/ui/type_length_limit.rs`. --- src/tools/compiletest/src/runtest.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index fc83ea420430..eb298060b2ec 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2375,13 +2375,16 @@ impl<'test> TestCx<'test> { let rust_src_dir = rust_src_dir.read_link_utf8().unwrap_or(rust_src_dir.to_path_buf()); normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); - // Canonicalize test build directory path. - // Without this some tests fail if build directory is a symlink. - let output_base_dir = self.output_base_dir().canonicalize_utf8().unwrap(); - // eg. // /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui//$name.$revision.$mode/ - normalize_path(&output_base_dir, "$TEST_BUILD_DIR"); + normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR"); + // Same as above, but with a canonicalized path. + // This is required because some tests print canonical paths inside test build directory, + // so if the build directory is a symlink, normalization doesn't help. + // + // NOTE: There are also tests which print the non-canonical name, so we need both this and + // the above normalizations. + normalize_path(&self.output_base_dir().canonicalize_utf8().unwrap(), "$TEST_BUILD_DIR"); // eg. /home/user/rust/build normalize_path(&self.config.build_root, "$BUILD_DIR"); From f35c85f72fc1249f0553d97482ca29fe3fa0a165 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 8 Apr 2025 16:11:28 -0700 Subject: [PATCH 192/222] Add unstable foo::bar extern command line arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also refactors some of the crate name parsing code and adds unit tests Issue #122349 Co-authored-by: León Orell Valerian Liehr --- compiler/rustc_session/src/config.rs | 39 +------- compiler/rustc_session/src/config/externs.rs | 79 ++++++++++++++++ .../rustc_session/src/config/externs/tests.rs | 92 +++++++++++++++++++ compiler/rustc_session/src/options.rs | 2 + 4 files changed, 178 insertions(+), 34 deletions(-) create mode 100644 compiler/rustc_session/src/config/externs.rs create mode 100644 compiler/rustc_session/src/config/externs/tests.rs diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index fc05470d941c..202378560eed 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -14,6 +14,7 @@ use std::str::{self, FromStr}; use std::sync::LazyLock; use std::{cmp, fmt, fs, iter}; +use externs::{ExternOpt, split_extern_opt}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_errors::emitter::HumanReadableErrorType; @@ -39,6 +40,7 @@ use crate::utils::CanonicalizedPath; use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint}; mod cfg; +mod externs; mod native_libs; pub mod sigpipe; @@ -2205,44 +2207,13 @@ pub fn parse_externs( matches: &getopts::Matches, unstable_opts: &UnstableOptions, ) -> Externs { - fn is_ascii_ident(string: &str) -> bool { - let mut chars = string.chars(); - if let Some(start) = chars.next() - && (start.is_ascii_alphabetic() || start == '_') - { - chars.all(|char| char.is_ascii_alphanumeric() || char == '_') - } else { - false - } - } - let is_unstable_enabled = unstable_opts.unstable_options; let mut externs: BTreeMap = BTreeMap::new(); for arg in matches.opt_strs("extern") { - let (name, path) = match arg.split_once('=') { - None => (arg, None), - Some((name, path)) => (name.to_string(), Some(Path::new(path))), - }; - let (options, name) = match name.split_once(':') { - None => (None, name), - Some((opts, name)) => (Some(opts), name.to_string()), - }; + let ExternOpt { crate_name: name, path, options } = + split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit()); - if !is_ascii_ident(&name) { - let mut error = early_dcx.early_struct_fatal(format!( - "crate name `{name}` passed to `--extern` is not a valid ASCII identifier" - )); - let adjusted_name = name.replace('-', "_"); - if is_ascii_ident(&adjusted_name) { - #[allow(rustc::diagnostic_outside_of_impl)] // FIXME - error.help(format!( - "consider replacing the dashes with underscores: `{adjusted_name}`" - )); - } - error.emit(); - } - - let path = path.map(|p| CanonicalizedPath::new(p)); + let path = path.map(|p| CanonicalizedPath::new(p.as_path())); let entry = externs.entry(name.to_owned()); diff --git a/compiler/rustc_session/src/config/externs.rs b/compiler/rustc_session/src/config/externs.rs new file mode 100644 index 000000000000..1420ee38bf21 --- /dev/null +++ b/compiler/rustc_session/src/config/externs.rs @@ -0,0 +1,79 @@ +//! This module contains code to help parse and manipulate `--extern` arguments. + +use std::path::PathBuf; + +use rustc_errors::{Diag, FatalAbort}; + +use super::UnstableOptions; +use crate::EarlyDiagCtxt; + +#[cfg(test)] +mod tests; + +/// Represents the pieces of an `--extern` argument. +pub(crate) struct ExternOpt { + pub(crate) crate_name: String, + pub(crate) path: Option, + pub(crate) options: Option, +} + +/// Breaks out the major components of an `--extern` argument. +/// +/// The options field will be a string containing comma-separated options that will need further +/// parsing and processing. +pub(crate) fn split_extern_opt<'a>( + early_dcx: &'a EarlyDiagCtxt, + unstable_opts: &UnstableOptions, + extern_opt: &str, +) -> Result> { + let (name, path) = match extern_opt.split_once('=') { + None => (extern_opt.to_string(), None), + Some((name, path)) => (name.to_string(), Some(PathBuf::from(path))), + }; + let (options, crate_name) = match name.split_once(':') { + None => (None, name), + Some((opts, crate_name)) => { + if unstable_opts.namespaced_crates && crate_name.starts_with(':') { + // If the name starts with `:`, we know this was actually something like `foo::bar` and + // not a set of options. We can just use the original name as the crate name. + (None, name) + } else { + (Some(opts.to_string()), crate_name.to_string()) + } + } + }; + + if !valid_crate_name(&crate_name, unstable_opts) { + let mut error = early_dcx.early_struct_fatal(format!( + "crate name `{crate_name}` passed to `--extern` is not a valid ASCII identifier" + )); + let adjusted_name = crate_name.replace('-', "_"); + if is_ascii_ident(&adjusted_name) { + #[allow(rustc::diagnostic_outside_of_impl)] // FIXME + error + .help(format!("consider replacing the dashes with underscores: `{adjusted_name}`")); + } + return Err(error); + } + + Ok(ExternOpt { crate_name, path, options }) +} + +fn valid_crate_name(name: &str, unstable_opts: &UnstableOptions) -> bool { + match name.split_once("::") { + Some((a, b)) if unstable_opts.namespaced_crates => is_ascii_ident(a) && is_ascii_ident(b), + Some(_) => false, + None => is_ascii_ident(name), + } +} + +fn is_ascii_ident(string: &str) -> bool { + let mut chars = string.chars(); + if let Some(start) = chars.next() + && (start.is_ascii_alphabetic() || start == '_') + { + chars.all(|char| char.is_ascii_alphanumeric() || char == '_') + } else { + false + } +} diff --git a/compiler/rustc_session/src/config/externs/tests.rs b/compiler/rustc_session/src/config/externs/tests.rs new file mode 100644 index 000000000000..654488695157 --- /dev/null +++ b/compiler/rustc_session/src/config/externs/tests.rs @@ -0,0 +1,92 @@ +use std::path::PathBuf; + +use super::split_extern_opt; +use crate::EarlyDiagCtxt; +use crate::config::UnstableOptions; + +/// Verifies split_extern_opt handles the supported cases. +#[test] +fn test_split_extern_opt() { + let early_dcx = EarlyDiagCtxt::new(<_>::default()); + let unstable_opts = &UnstableOptions::default(); + + let extern_opt = + split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo=libbar.rlib").unwrap(); + assert_eq!(extern_opt.crate_name, "foo"); + assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib"))); + assert_eq!(extern_opt.options, Some("priv,noprelude".to_string())); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo").unwrap(); + assert_eq!(extern_opt.crate_name, "foo"); + assert_eq!(extern_opt.path, None); + assert_eq!(extern_opt.options, Some("priv,noprelude".to_string())); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo=libbar.rlib").unwrap(); + assert_eq!(extern_opt.crate_name, "foo"); + assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib"))); + assert_eq!(extern_opt.options, None); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo").unwrap(); + assert_eq!(extern_opt.crate_name, "foo"); + assert_eq!(extern_opt.path, None); + assert_eq!(extern_opt.options, None); +} + +/// Tests some invalid cases for split_extern_opt. +#[test] +fn test_split_extern_opt_invalid() { + let early_dcx = EarlyDiagCtxt::new(<_>::default()); + let unstable_opts = &UnstableOptions::default(); + + // too many `:`s + let result = split_extern_opt(&early_dcx, unstable_opts, "priv:noprelude:foo=libbar.rlib"); + assert!(result.is_err()); + let _ = result.map_err(|e| e.cancel()); + + // can't nest externs without the unstable flag + let result = split_extern_opt(&early_dcx, unstable_opts, "noprelude:foo::bar=libbar.rlib"); + assert!(result.is_err()); + let _ = result.map_err(|e| e.cancel()); +} + +/// Tests some cases for split_extern_opt with nested crates like `foo::bar`. +#[test] +fn test_split_extern_opt_nested() { + let early_dcx = EarlyDiagCtxt::new(<_>::default()); + let unstable_opts = &UnstableOptions { namespaced_crates: true, ..Default::default() }; + + let extern_opt = + split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar=libbar.rlib").unwrap(); + assert_eq!(extern_opt.crate_name, "foo::bar"); + assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib"))); + assert_eq!(extern_opt.options, Some("priv,noprelude".to_string())); + + let extern_opt = + split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar").unwrap(); + assert_eq!(extern_opt.crate_name, "foo::bar"); + assert_eq!(extern_opt.path, None); + assert_eq!(extern_opt.options, Some("priv,noprelude".to_string())); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo::bar=libbar.rlib").unwrap(); + assert_eq!(extern_opt.crate_name, "foo::bar"); + assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib"))); + assert_eq!(extern_opt.options, None); + + let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo::bar").unwrap(); + assert_eq!(extern_opt.crate_name, "foo::bar"); + assert_eq!(extern_opt.path, None); + assert_eq!(extern_opt.options, None); +} + +/// Tests some invalid cases for split_extern_opt with nested crates like `foo::bar`. +#[test] +fn test_split_extern_opt_nested_invalid() { + let early_dcx = EarlyDiagCtxt::new(<_>::default()); + let unstable_opts = &UnstableOptions { namespaced_crates: true, ..Default::default() }; + + // crates can only be nested one deep. + let result = + split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar::baz=libbar.rlib"); + assert!(result.is_err()); + let _ = result.map_err(|e| e.cancel()); +} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c70f1500d393..bd66f835f120 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2331,6 +2331,8 @@ options! { "the size at which the `large_assignments` lint starts to be emitted"), mutable_noalias: bool = (true, parse_bool, [TRACKED], "emit noalias metadata for mutable references (default: yes)"), + namespaced_crates: bool = (false, parse_bool, [TRACKED], + "allow crates to be namespaced by other crates (default: no)"), next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED], "enable and configure the next generation trait solver used by rustc"), nll_facts: bool = (false, parse_bool, [UNTRACKED], From f3f53d2183a4980f36ee6836f172a01a8b92c44a Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Tue, 15 Apr 2025 22:48:28 +0200 Subject: [PATCH 193/222] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/book b/src/doc/book index 45f05367360f..d33916341d48 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 45f05367360f033f89235eacbbb54e8d73ce6b70 +Subproject commit d33916341d480caede1d0ae57cbeae23aab23e88 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 1e27e5e6d513..467f45637b73 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 1e27e5e6d5133ae4612f5cc195c15fc8d51b1c9c +Subproject commit 467f45637b73ec6aa70fb36bc3054bb50b8967ea diff --git a/src/doc/nomicon b/src/doc/nomicon index b4448fa406a6..0c10c30cc547 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit b4448fa406a6dccde62d1e2f34f70fc51814cdcc +Subproject commit 0c10c30cc54736c5c194ce98c50e2de84eeb6e79 diff --git a/src/doc/reference b/src/doc/reference index 46435cd4eba1..3340922df189 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 46435cd4eba11b66acaa42c01da5c80ad88aee4b +Subproject commit 3340922df189bddcbaad17dc3927d51a76bcd5ed From fe882bf330f00f7bc07327430fdded4164dac25e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Mar 2025 15:52:33 +1100 Subject: [PATCH 194/222] Rename `LifetimeName` as `LifetimeKind`. It's a much better name, more consistent with how we name such things. Also rename `Lifetime::res` as `Lifetime::kind` to match. I suspect this field used to have the type `LifetimeRes` and then the type was changed but the field name remained the same. --- compiler/rustc_ast_lowering/src/lib.rs | 12 ++--- .../src/diagnostics/region_errors.rs | 2 +- compiler/rustc_hir/src/hir.rs | 20 ++++---- compiler/rustc_hir/src/hir/tests.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 46 +++++++++---------- .../src/hir_ty_lowering/dyn_compatibility.rs | 2 +- compiler/rustc_middle/src/ty/diagnostics.rs | 4 +- .../nice_region_error/static_impl_trait.rs | 8 ++-- .../src/error_reporting/infer/region.rs | 6 +-- src/doc/rustc-dev-guide/src/ty.md | 8 ++-- .../clippy/clippy_lints/src/lifetimes.rs | 14 +++--- src/tools/clippy/clippy_lints/src/ptr.rs | 4 +- .../clippy/clippy_utils/src/hir_utils.rs | 8 ++-- 13 files changed, 68 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b1d1c35e64a1..b091847fa7e2 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1768,21 +1768,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug_assert_ne!(ident.name, kw::Empty); let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); let res = match res { - LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param), + LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param), LifetimeRes::Fresh { param, .. } => { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); let param = self.local_def_id(param); - hir::LifetimeName::Param(param) + hir::LifetimeKind::Param(param) } LifetimeRes::Infer => { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); - hir::LifetimeName::Infer + hir::LifetimeKind::Infer } LifetimeRes::Static { .. } => { debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); - hir::LifetimeName::Static + hir::LifetimeKind::Static } - LifetimeRes::Error => hir::LifetimeName::Error, + LifetimeRes::Error => hir::LifetimeKind::Error, LifetimeRes::ElidedAnchor { .. } => { panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span); } @@ -2389,7 +2389,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let r = hir::Lifetime::new( self.next_id(), Ident::new(kw::UnderscoreLifetime, self.lower_span(span)), - hir::LifetimeName::ImplicitObjectLifetimeDefault, + hir::LifetimeKind::ImplicitObjectLifetimeDefault, IsAnonInPath::No, ); debug!("elided_dyn_bound: r={:?}", r); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 8d530b51636a..4423edb06051 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -888,7 +888,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Skip `async` desugaring `impl Future`. } if let TyKind::TraitObject(_, lt) = alias_ty.kind { - if lt.res == hir::LifetimeName::ImplicitObjectLifetimeDefault { + if lt.kind == hir::LifetimeKind::ImplicitObjectLifetimeDefault { spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string())); } else { spans_suggs.push((lt.ident.span, "'a".to_string())); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6455f33b9d15..3f5269eeb9b9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -42,7 +42,7 @@ pub enum IsAnonInPath { } /// A lifetime. The valid field combinations are non-obvious. The following -/// example shows some of them. See also the comments on `LifetimeName`. +/// example shows some of them. See also the comments on `LifetimeKind`. /// ``` /// #[repr(C)] /// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No @@ -84,7 +84,7 @@ pub struct Lifetime { pub ident: Ident, /// Semantics of this lifetime. - pub res: LifetimeName, + pub kind: LifetimeKind, /// Is the lifetime anonymous and in a path? Used only for error /// suggestions. See `Lifetime::suggestion` for example use. @@ -130,7 +130,7 @@ impl ParamName { } #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] -pub enum LifetimeName { +pub enum LifetimeKind { /// User-given names or fresh (synthetic) names. Param(LocalDefId), @@ -160,16 +160,16 @@ pub enum LifetimeName { Static, } -impl LifetimeName { +impl LifetimeKind { fn is_elided(&self) -> bool { match self { - LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true, + LifetimeKind::ImplicitObjectLifetimeDefault | LifetimeKind::Infer => true, // It might seem surprising that `Fresh` counts as not *elided* // -- but this is because, as far as the code in the compiler is // concerned -- `Fresh` variants act equivalently to "some fresh name". // They correspond to early-bound regions on an impl, in other words. - LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false, + LifetimeKind::Error | LifetimeKind::Param(..) | LifetimeKind::Static => false, } } } @@ -184,10 +184,10 @@ impl Lifetime { pub fn new( hir_id: HirId, ident: Ident, - res: LifetimeName, + kind: LifetimeKind, is_anon_in_path: IsAnonInPath, ) -> Lifetime { - let lifetime = Lifetime { hir_id, ident, res, is_anon_in_path }; + let lifetime = Lifetime { hir_id, ident, kind, is_anon_in_path }; // Sanity check: elided lifetimes form a strict subset of anonymous lifetimes. #[cfg(debug_assertions)] @@ -202,7 +202,7 @@ impl Lifetime { } pub fn is_elided(&self) -> bool { - self.res.is_elided() + self.kind.is_elided() } pub fn is_anonymous(&self) -> bool { @@ -1014,7 +1014,7 @@ pub struct WhereRegionPredicate<'hir> { impl<'hir> WhereRegionPredicate<'hir> { /// Returns `true` if `param_def_id` matches the `lifetime` of this predicate. fn is_param_bound(&self, param_def_id: LocalDefId) -> bool { - self.lifetime.res == LifetimeName::Param(param_def_id) + self.lifetime.kind == LifetimeKind::Param(param_def_id) } } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index 62ef02d2f500..fcd0eafa4613 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -57,7 +57,7 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) { Lifetime { hir_id: HirId::INVALID, ident: Ident::new(sym::name, DUMMY_SP), - res: LifetimeName::Static, + kind: LifetimeKind::Static, is_anon_in_path: IsAnonInPath::No, } }, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 1c477755e5ac..59ab36d98fda 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -16,7 +16,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt}; use rustc_hir::{ - self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeName, Node, + self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node, }; use rustc_macros::extension; use rustc_middle::hir::nested_filter; @@ -646,14 +646,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { arg: &'tcx hir::PreciseCapturingArg<'tcx>, ) -> Self::Result { match *arg { - hir::PreciseCapturingArg::Lifetime(lt) => match lt.res { - LifetimeName::Param(def_id) => { + hir::PreciseCapturingArg::Lifetime(lt) => match lt.kind { + LifetimeKind::Param(def_id) => { self.resolve_lifetime_ref(def_id, lt); } - LifetimeName::Error => {} - LifetimeName::ImplicitObjectLifetimeDefault - | LifetimeName::Infer - | LifetimeName::Static => { + LifetimeKind::Error => {} + LifetimeKind::ImplicitObjectLifetimeDefault + | LifetimeKind::Infer + | LifetimeKind::Static => { self.tcx.dcx().emit_err(errors::BadPreciseCapture { span: lt.ident.span, kind: "lifetime", @@ -774,26 +774,26 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { ); } }); - match lifetime.res { - LifetimeName::ImplicitObjectLifetimeDefault => { + match lifetime.kind { + LifetimeKind::ImplicitObjectLifetimeDefault => { // If the user does not write *anything*, we // use the object lifetime defaulting // rules. So e.g., `Box` becomes // `Box`. self.resolve_object_lifetime_default(&*lifetime) } - LifetimeName::Infer => { + LifetimeKind::Infer => { // If the user writes `'_`, we use the *ordinary* elision // rules. So the `'_` in e.g., `Box` will be // resolved the same as the `'_` in `&'_ Foo`. // // cc #48468 } - LifetimeName::Param(..) | LifetimeName::Static => { + LifetimeKind::Param(..) | LifetimeKind::Static => { // If the user wrote an explicit name, use that. self.visit_lifetime(&*lifetime); } - LifetimeName::Error => {} + LifetimeKind::Error => {} } } hir::TyKind::Ref(lifetime_ref, ref mt) => { @@ -873,17 +873,17 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - match lifetime_ref.res { - hir::LifetimeName::Static => { + match lifetime_ref.kind { + hir::LifetimeKind::Static => { self.insert_lifetime(lifetime_ref, ResolvedArg::StaticLifetime) } - hir::LifetimeName::Param(param_def_id) => { + hir::LifetimeKind::Param(param_def_id) => { self.resolve_lifetime_ref(param_def_id, lifetime_ref) } // If we've already reported an error, just ignore `lifetime_ref`. - hir::LifetimeName::Error => {} + hir::LifetimeKind::Error => {} // Those will be resolved by typechecking. - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Infer => {} + hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Infer => {} } } @@ -1063,15 +1063,15 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectL for bound in bound.bounds { if let hir::GenericBound::Outlives(lifetime) = bound { - set.insert(lifetime.res); + set.insert(lifetime.kind); } } } match set { Set1::Empty => ObjectLifetimeDefault::Empty, - Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, - Set1::One(hir::LifetimeName::Param(param_def_id)) => { + Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, + Set1::One(hir::LifetimeKind::Param(param_def_id)) => { ObjectLifetimeDefault::Param(param_def_id.to_def_id()) } _ => ObjectLifetimeDefault::Ambiguous, @@ -1241,7 +1241,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // Fresh lifetimes in APIT used to be allowed in async fns and forbidden in // regular fns. if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin - && let hir::LifetimeName::Param(param_id) = lifetime_ref.res + && let hir::LifetimeKind::Param(param_id) = lifetime_ref.kind && let Some(generics) = self.tcx.hir_get_generics(self.tcx.local_parent(param_id)) && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) @@ -2440,7 +2440,7 @@ fn is_late_bound_map( } fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - if let hir::LifetimeName::Param(def_id) = lifetime_ref.res { + if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind { self.regions.insert(def_id); } } @@ -2453,7 +2453,7 @@ fn is_late_bound_map( impl<'tcx> Visitor<'tcx> for AllCollector { fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - if let hir::LifetimeName::Param(def_id) = lifetime_ref.res { + if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind { self.regions.insert(def_id); } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 2e39beed8ae3..88f745892048 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -415,7 +415,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime) } else { let reason = - if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res { + if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind { if let hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(parent_lifetime, _), .. diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 09db6eee2c9e..fbb57b8df6bb 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -578,8 +578,8 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { match ty.kind { hir::TyKind::TraitObject(_, tagged_ptr) if let hir::Lifetime { - res: - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static, + kind: + hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Static, .. } = tagged_ptr.pointer() => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 3559c660ee27..eaa06d8e8b0a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; use rustc_hir::{ self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime, - LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind, + LifetimeKind, LifetimeParamKind, MissingLifetimeKind, Node, TyKind, }; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; @@ -165,7 +165,7 @@ pub fn suggest_new_region_bound( if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg { GenericBound::Outlives(Lifetime { - res: LifetimeName::Static, ident, .. + kind: LifetimeKind::Static, ident, .. }) => Some(ident.span), _ => None, }) { @@ -253,7 +253,7 @@ pub fn suggest_new_region_bound( } } TyKind::TraitObject(_, lt) => { - if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res { + if let LifetimeKind::ImplicitObjectLifetimeDefault = lt.kind { err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), format!("{declare} the trait object {captures}, {explicit}",), @@ -414,7 +414,7 @@ pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec, pub DefId); impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> { fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) { if let TyKind::TraitObject(poly_trait_refs, lifetime_ptr) = t.kind - && let Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. } = + && let Lifetime { kind: LifetimeKind::ImplicitObjectLifetimeDefault, .. } = lifetime_ptr.pointer() { for ptr in poly_trait_refs { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index df3cce880dd4..1cf1ac5403f0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -850,14 +850,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { add_lt_suggs: &mut Vec<(Span, String)>, ) -> String { struct LifetimeReplaceVisitor<'a> { - needle: hir::LifetimeName, + needle: hir::LifetimeKind, new_lt: &'a str, add_lt_suggs: &'a mut Vec<(Span, String)>, } impl<'hir> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_> { fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) { - if lt.res == self.needle { + if lt.kind == self.needle { self.add_lt_suggs.push(lt.suggestion(self.new_lt)); } } @@ -894,7 +894,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let mut visitor = LifetimeReplaceVisitor { - needle: hir::LifetimeName::Param(lifetime_def_id), + needle: hir::LifetimeKind::Param(lifetime_def_id), add_lt_suggs, new_lt: &new_lt, }; diff --git a/src/doc/rustc-dev-guide/src/ty.md b/src/doc/rustc-dev-guide/src/ty.md index b33d54035864..ce6cffec1adb 100644 --- a/src/doc/rustc-dev-guide/src/ty.md +++ b/src/doc/rustc-dev-guide/src/ty.md @@ -61,11 +61,11 @@ Here is a summary: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Describe the *syntax* of a type: what the user wrote (with some desugaring). | Describe the *semantics* of a type: the meaning of what the user wrote. | | Each `rustc_hir::Ty` has its own spans corresponding to the appropriate place in the program. | Doesn’t correspond to a single place in the user’s program. | -| `rustc_hir::Ty` has generics and lifetimes; however, some of those lifetimes are special markers like [`LifetimeName::Implicit`][implicit]. | `ty::Ty` has the full type, including generics and lifetimes, even if the user left them out | +| `rustc_hir::Ty` has generics and lifetimes; however, some of those lifetimes are special markers like [`LifetimeKind::Implicit`][implicit]. | `ty::Ty` has the full type, including generics and lifetimes, even if the user left them out | | `fn foo(x: u32) → u32 { }` - Two `rustc_hir::Ty` representing each usage of `u32`, each has its own `Span`s, and `rustc_hir::Ty` doesn’t tell us that both are the same type | `fn foo(x: u32) → u32 { }` - One `ty::Ty` for all instances of `u32` throughout the program, and `ty::Ty` tells us that both usages of `u32` mean the same type. | -| `fn foo(x: &u32) -> &u32)` - Two `rustc_hir::Ty` again. Lifetimes for the references show up in the `rustc_hir::Ty`s using a special marker, [`LifetimeName::Implicit`][implicit]. | `fn foo(x: &u32) -> &u32)`- A single `ty::Ty`. The `ty::Ty` has the hidden lifetime param. | +| `fn foo(x: &u32) -> &u32)` - Two `rustc_hir::Ty` again. Lifetimes for the references show up in the `rustc_hir::Ty`s using a special marker, [`LifetimeKind::Implicit`][implicit]. | `fn foo(x: &u32) -> &u32)`- A single `ty::Ty`. The `ty::Ty` has the hidden lifetime param. | -[implicit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.LifetimeName.html#variant.Implicit +[implicit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.LifetimeKind.html#variant.Implicit **Order** @@ -323,4 +323,4 @@ When looking at the debug output of `Ty` or simply talking about different types - Generic parameters: `{name}/#{index}` e.g. `T/#0`, where `index` corresponds to its position in the list of generic parameters - Inference variables: `?{id}` e.g. `?x`/`?0`, where `id` identifies the inference variable - Variables from binders: `^{binder}_{index}` e.g. `^0_x`/`^0_2`, where `binder` and `index` identify which variable from which binder is being referred to -- Placeholders: `!{id}` or `!{id}_{universe}` e.g. `!x`/`!0`/`!x_2`/`!0_2`, representing some unique type in the specified universe. The universe is often elided when it is `0` \ No newline at end of file +- Placeholders: `!{id}` or `!{id}_{universe}` e.g. `!x`/`!0`/`!x_2`/`!0_2`, representing some unique type in the specified universe. The universe is often elided when it is `0` diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 8d47c756fc53..dabef18b98a9 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -14,7 +14,7 @@ use rustc_hir::intravisit::{ }; use rustc_hir::{ AmbigArg, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, - Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, + Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeKind, LifetimeParamKind, Node, PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate, WherePredicateKind, lang_items, }; @@ -218,7 +218,7 @@ fn check_fn_inner<'tcx>( for bound in pred.bounds { let mut visitor = RefVisitor::new(cx); walk_param_bound(&mut visitor, bound); - if visitor.lts.iter().any(|lt| matches!(lt.res, LifetimeName::Param(_))) { + if visitor.lts.iter().any(|lt| matches!(lt.kind, LifetimeKind::Param(_))) { return; } if let GenericBound::Trait(ref trait_ref) = *bound { @@ -235,7 +235,7 @@ fn check_fn_inner<'tcx>( _ => None, }); for bound in lifetimes { - if bound.res != LifetimeName::Static && !bound.is_elided() { + if bound.kind != LifetimeKind::Static && !bound.is_elided() { return; } } @@ -421,8 +421,8 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> { } fn named_lifetime(lt: &Lifetime) -> Option { - match lt.res { - LifetimeName::Param(id) if !lt.is_anonymous() => Some(id), + match lt.kind { + LifetimeKind::Param(id) if !lt.is_anonymous() => Some(id), _ => None, } } @@ -614,7 +614,7 @@ where // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - if let LifetimeName::Param(def_id) = lifetime.res + if let LifetimeKind::Param(def_id) = lifetime.kind && let Some(usages) = self.map.get_mut(&def_id) { usages.push(Usage { @@ -826,7 +826,7 @@ fn report_elidable_lifetimes( .iter() .map(|<| cx.tcx.def_span(lt)) .chain(usages.iter().filter_map(|usage| { - if let LifetimeName::Param(def_id) = usage.res + if let LifetimeKind::Param(def_id) = usage.kind && elidable_lts.contains(&def_id) { return Some(usage.ident.span); diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 50ef56db167c..901a1634ddc8 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core}; -use hir::LifetimeName; +use hir::LifetimeKind; use rustc_abi::ExternAbi; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::hir_id::{HirId, HirIdMap}; @@ -432,7 +432,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( } None }) { - if let LifetimeName::Param(param_def_id) = lifetime.res + if let LifetimeKind::Param(param_def_id) = lifetime.kind && !lifetime.is_anonymous() && fn_sig .output() diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index b813cd361ed8..be295b59f609 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -8,7 +8,7 @@ use rustc_hir::MatchSource::TryDesugar; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, - ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, + ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeKind, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind, }; @@ -483,7 +483,7 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool { - left.res == right.res + left.kind == right.kind } fn eq_pat_field(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool { @@ -1245,8 +1245,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_lifetime(&mut self, lifetime: &Lifetime) { lifetime.ident.name.hash(&mut self.s); - std::mem::discriminant(&lifetime.res).hash(&mut self.s); - if let LifetimeName::Param(param_id) = lifetime.res { + std::mem::discriminant(&lifetime.kind).hash(&mut self.s); + if let LifetimeKind::Param(param_id) = lifetime.kind { param_id.hash(&mut self.s); } } From c4d35635545ba9fb6d5f4a1652b4520c7da3fca0 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Wed, 16 Apr 2025 00:14:10 +0200 Subject: [PATCH 195/222] Also remove the no_sanitize feature for std --- library/std/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5c381181218d..3a52b7790376 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -312,7 +312,6 @@ #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] -#![feature(no_sanitize)] #![feature(optimize_attribute)] #![feature(prelude_import)] #![feature(rustc_attrs)] From ea1b230170c36ddf95cb24a8542316df9f786e5a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 15 Apr 2025 15:20:27 -0700 Subject: [PATCH 196/222] Update Cargo.lock for rustbook --- src/tools/rustbook/Cargo.lock | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index e0939afc09bb..c14372dd6aec 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -951,6 +951,7 @@ dependencies = [ "once_cell", "pathdiff", "pulldown-cmark 0.10.3", + "railroad", "regex", "semver", "serde_json", @@ -1300,6 +1301,15 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +[[package]] +name = "railroad" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ecedffc46c1b2cb04f4b80e094eae6b3f3f470a9635f1f396dd5206428f6b58" +dependencies = [ + "unicode-width", +] + [[package]] name = "rand" version = "0.8.5" From 766cd3a58320f2ec9e30573f39e377513f1a4443 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 16 Apr 2025 08:35:34 +1000 Subject: [PATCH 197/222] Remove support for `#[rustc_mir(borrowck_graphviz_format="gen_kill")]`. Because it's equivalent to `#[rustc_mir(borrowck_graphviz_format)]`. It used to be distinct, but the distinction was removed in https://github.com/rust-lang/rust/pull/76044/commits/3233fb18a891363a2da36ce69ca16fbb219c96be. --- compiler/rustc_mir_dataflow/src/framework/graphviz.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 448fad2dc3ec..c436b8c0fb01 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -122,7 +122,7 @@ impl RustcMirAttrs { }) } else if attr.has_name(sym::borrowck_graphviz_format) { Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s { - sym::gen_kill | sym::two_phase => Ok(s), + sym::two_phase => Ok(s), _ => { tcx.dcx().emit_err(UnknownFormatter { span: attr.span() }); Err(()) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d1f3eb16e4e4..2af567f2ec50 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1068,7 +1068,6 @@ symbols! { ge, gen_blocks, gen_future, - gen_kill, generator_clone, generators, generic_arg_infer, From 62882f355e50f9af3ddb84661dfad0559848a3f5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 16 Apr 2025 08:57:15 +1000 Subject: [PATCH 198/222] Improve `borrowck_graphviz_*` documentation. In particular, `borrowck_graphviz_preflow` no longer exists. --- src/doc/rustc-dev-guide/src/compiler-debugging.md | 3 ++- tests/ui/mir-dataflow/README.md | 9 --------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index 47f397620222..102e20207792 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -301,7 +301,8 @@ Right below you can find elaborate explainers on a selected few. Some compiler options for debugging specific features yield graphviz graphs - e.g. the `#[rustc_mir(borrowck_graphviz_postflow="suffix.dot")]` attribute -dumps various borrow-checker dataflow graphs. +on a function dumps various borrow-checker dataflow graphs in conjunction with +`-Zdump-mir-dataflow`. These all produce `.dot` files. To view these files, install graphviz (e.g. `apt-get install graphviz`) and then run the following commands: diff --git a/tests/ui/mir-dataflow/README.md b/tests/ui/mir-dataflow/README.md index a3ab14b23c7d..886020226d03 100644 --- a/tests/ui/mir-dataflow/README.md +++ b/tests/ui/mir-dataflow/README.md @@ -42,12 +42,3 @@ each generated output path. on *entry* to each block, as well as the gen- and kill-sets that were so-called "transfer functions" summarizing the effect of each basic block. - - * (In addition to the `borrowck_graphviz_postflow` attribute-key - noted above, there is also `borrowck_graphviz_preflow`; it has the - same interface and generates the same set of files, but it renders - the dataflow state after building the gen- and kill-sets but - *before* running the dataflow analysis itself, so each entry-set is - just the initial default state for that dataflow analysis. This is - less useful for understanding the error message output in these - tests.) From 6999305926b4199d6a33ae4f82002e72115223a8 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 15 Apr 2025 19:01:35 +0200 Subject: [PATCH 199/222] Make CodeStat's type sizes a public field --- compiler/rustc_session/src/code_stats.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs index b4597ae2515d..6b18d450e9e5 100644 --- a/compiler/rustc_session/src/code_stats.rs +++ b/compiler/rustc_session/src/code_stats.rs @@ -72,7 +72,7 @@ pub struct TypeSizeInfo { #[derive(Default)] pub struct CodeStats { - type_sizes: Lock>, + pub type_sizes: Lock>, } impl CodeStats { From b084603c631cf4cea540a35aca0ad7b2d8599ef2 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 6 Apr 2025 03:36:45 +0000 Subject: [PATCH 200/222] rustc_target: RISC-V: feature addition batch 2 This commit adds unprivileged ratified extensions that are either dicoverable from the `riscv_hwprobe` syscall of the Linux kernel (as of version 6.14) plus 1 minus 3 extensions. Plus 1: * "B" This is a combination of "Zba", "Zbb" and "Zbs". Note: Although not required by the RISC-V specification, it is convenient to imply "B" from its three members (will be implemented in LLVM 21/22) but this is not yet implemented in Rust due to current implication handling. It still implies three members *from* "B". Minus 2: * "Zcf" (target_arch = "riscv32" only) This is the compression instruction subset corresponding "F". This is implied from RV32 + "C" + "F" but this complex handling is not yet supported by Rust's feature handling. * "Zcd" This is the compression instruction subset corresponding "D". This is implied from "C" + "D" but this complex handling is not yet supported by Rust's feature handling. * "Supm" Unlike regular RISC-V extensions, "Supm" and "Sspm" extensions do not provide any specific architectural features / constraints but requires *some* mechanisms to control pointer masking for the current mode. For instance, reported existence of the "Supm" extension in Linux means that `prctl` system call to control pointer masking is available and there are alternative ways to detect the existence. Notes: * Because this commit adds the "Zca" extension (an integer subset of the "C" extension), the "C" extension is modified to imply "Zca". --- compiler/rustc_target/src/target_features.rs | 12 +++++++++++- tests/ui/check-cfg/target_feature.stderr | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b4ec1879fed5..aeace6a40c72 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -491,7 +491,8 @@ const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("a", Stable, &["zaamo", "zalrsc"]), - ("c", Stable, &[]), + ("b", Unstable(sym::riscv_target_feature), &["zba", "zbb", "zbs"]), + ("c", Stable, &["zca"]), ("d", Unstable(sym::riscv_target_feature), &["f"]), ("e", Unstable(sym::riscv_target_feature), &[]), ("f", Unstable(sym::riscv_target_feature), &["zicsr"]), @@ -520,17 +521,25 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zbkc", Stable, &[]), ("zbkx", Stable, &[]), ("zbs", Stable, &[]), + ("zca", Unstable(sym::riscv_target_feature), &[]), + ("zcb", Unstable(sym::riscv_target_feature), &["zca"]), + ("zcmop", Unstable(sym::riscv_target_feature), &["zca"]), ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zfa", Unstable(sym::riscv_target_feature), &["f"]), ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]), ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]), ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zicboz", Unstable(sym::riscv_target_feature), &[]), ("zicntr", Unstable(sym::riscv_target_feature), &["zicsr"]), + ("zicond", Unstable(sym::riscv_target_feature), &[]), ("zicsr", Unstable(sym::riscv_target_feature), &[]), ("zifencei", Unstable(sym::riscv_target_feature), &[]), + ("zihintntl", Unstable(sym::riscv_target_feature), &[]), ("zihintpause", Unstable(sym::riscv_target_feature), &[]), ("zihpm", Unstable(sym::riscv_target_feature), &["zicsr"]), + ("zimop", Unstable(sym::riscv_target_feature), &[]), ("zk", Stable, &["zkn", "zkr", "zkt"]), ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), ("zknd", Stable, &[]), @@ -541,6 +550,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zksed", Stable, &[]), ("zksh", Stable, &[]), ("zkt", Stable, &[]), + ("ztso", Unstable(sym::riscv_target_feature), &[]), ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]), ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]), diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index aa5fd09c0c7b..4f7b8345e86a 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -49,6 +49,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `avxvnni` `avxvnniint16` `avxvnniint8` +`b` `backchain` `bf16` `bmi1` @@ -318,17 +319,25 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zbkc` `zbkx` `zbs` +`zca` +`zcb` +`zcmop` `zdinx` +`zfa` `zfh` `zfhmin` `zfinx` `zhinx` `zhinxmin` +`zicboz` `zicntr` +`zicond` `zicsr` `zifencei` +`zihintntl` `zihintpause` `zihpm` +`zimop` `zk` `zkn` `zknd` @@ -339,6 +348,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zksed` `zksh` `zkt` +`ztso` `zvbb` `zvbc` `zve32f` From 52392ec9e1ebc5bf794583e2b2b146367d36b663 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 6 Apr 2025 04:21:01 +0000 Subject: [PATCH 201/222] rustc_target: Use "B" shorthand on the RISC-V Android target The "B" extension is ratified as a combination of three extensions: "Zba", "Zbb" and "Zbs". To maximize discoverability of the RISC-V target features, this commit makes use of the "B" extension instead of its three members. This way, `#[cfg(target_feature = "b")]` can also be used instead of: `#[cfg(all(target_feature = "zba", target_feature = "zbb", target_feature = "zbs"))]` --- compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs index 9f02ed4bcbe9..b9176c939f80 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), - features: "+m,+a,+f,+d,+c,+zicsr,+zifencei,+zba,+zbb,+zbs,+v".into(), + features: "+m,+a,+f,+d,+c,+b,+v,+zicsr,+zifencei".into(), llvm_abiname: "lp64d".into(), supported_sanitizers: SanitizerSet::ADDRESS, max_atomic_width: Some(64), From 9dbd2bb85cd0de44b4cec80c17b5c767e960553d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 15 Apr 2025 22:18:10 -0500 Subject: [PATCH 202/222] Include optional dso_local marker for functions in `enum-match.rs` --- tests/codegen/enum/enum-match.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs index 6e185cf89329..6da6ad1f078d 100644 --- a/tests/codegen/enum/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs @@ -15,7 +15,7 @@ pub enum Enum0 { B, } -// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0) +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[IS_B:.+]] = icmp eq i8 %0, 2 // CHECK-NEXT: %[[TRUNC:.+]] = and i8 %0, 1 @@ -37,7 +37,7 @@ pub enum Enum1 { C, } -// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0) +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 @@ -98,7 +98,7 @@ pub enum Enum2 { E, } -// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0) +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 @@ -121,7 +121,7 @@ pub fn match2(e: Enum2) -> u8 { // And make sure it works even if the niched scalar is a pointer. // (For example, that we don't try to `sub` on pointers.) -// CHECK-LABEL: define noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0) +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[IS_NULL:.+]] = icmp eq ptr %0, null // CHECK-NEXT: br i1 %[[IS_NULL]] @@ -145,7 +145,7 @@ pub enum MiddleNiche { E, } -// CHECK-LABEL: define noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0) +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 // CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 5 @@ -449,7 +449,7 @@ pub enum HugeVariantIndex { Possible259, } -// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0) +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 From bd9bd388fcba2d68b9eab6ff8a051bd07bcde525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 16 Apr 2025 08:14:36 +0200 Subject: [PATCH 203/222] Allow disabling `--llvm-shared` in opt-dist --- src/tools/opt-dist/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index ac5d294f07ed..ff4ddbaea49b 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -76,7 +76,7 @@ enum EnvironmentCmd { rustc_perf_checkout_dir: Option, /// Is LLVM for `rustc` built in shared library mode? - #[arg(long, default_value_t = true)] + #[arg(long, default_value_t = true, action(clap::ArgAction::Set))] llvm_shared: bool, /// Should BOLT optimization be used? If yes, host LLVM must have BOLT binaries From 6f386e7a9c5224a37e02d627c3e12bee59dee519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 16 Apr 2025 08:15:04 +0200 Subject: [PATCH 204/222] Only delete the lld directory if it exists --- src/tools/opt-dist/src/utils/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/opt-dist/src/utils/mod.rs b/src/tools/opt-dist/src/utils/mod.rs index 32d88a59af92..fb4f14ea41ae 100644 --- a/src/tools/opt-dist/src/utils/mod.rs +++ b/src/tools/opt-dist/src/utils/mod.rs @@ -36,7 +36,9 @@ pub fn clear_llvm_files(env: &Environment) -> anyhow::Result<()> { // directories ourselves. log::info!("Clearing LLVM build files"); delete_directory(&env.build_artifacts().join("llvm"))?; - delete_directory(&env.build_artifacts().join("lld"))?; + if env.build_artifacts().join("lld").is_dir() { + delete_directory(&env.build_artifacts().join("lld"))?; + } Ok(()) } From 48e119ef5a8b46ce8db8d362a6d94668c6deb541 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 16 Apr 2025 10:19:14 +0200 Subject: [PATCH 205/222] stepping into impls for norm is unproductive --- .../src/solve/eval_ctxt/mod.rs | 21 +++++--- .../normalizes-to-is-not-productive-2.rs | 24 +++++++++ ...alizes-to-is-not-productive.current.stderr | 48 +++++++++++++++++ ...ormalizes-to-is-not-productive.next.stderr | 31 +++++++++++ .../cycles/normalizes-to-is-not-productive.rs | 54 +++++++++++++++++++ .../normalizes-to-is-not-productive.stderr | 31 +++++++++++ 6 files changed, 201 insertions(+), 8 deletions(-) create mode 100644 tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs create mode 100644 tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr create mode 100644 tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr create mode 100644 tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs create mode 100644 tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 148ba02252d9..9994c85d0d0d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -286,18 +286,23 @@ where // fixing it may cause inference breakage or introduce ambiguity. GoalSource::Misc => PathKind::Unknown, GoalSource::NormalizeGoal(path_kind) => path_kind, - GoalSource::ImplWhereBound => { + GoalSource::ImplWhereBound => match self.current_goal_kind { // We currently only consider a cycle coinductive if it steps // into a where-clause of a coinductive trait. + CurrentGoalKind::CoinductiveTrait => PathKind::Coinductive, + // While normalizing via an impl does step into a where-clause of + // an impl, accessing the associated item immediately steps out of + // it again. This means cycles/recursive calls are not guarded + // by impls used for normalization. // + // See tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs + // for how this can go wrong. + CurrentGoalKind::NormalizesTo => PathKind::Inductive, // We probably want to make all traits coinductive in the future, - // so we treat cycles involving their where-clauses as ambiguous. - if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind { - PathKind::Coinductive - } else { - PathKind::Unknown - } - } + // so we treat cycles involving where-clauses of not-yet coinductive + // traits as ambiguous for now. + CurrentGoalKind::Misc => PathKind::Unknown, + }, // Relating types is always unproductive. If we were to map proof trees to // corecursive functions as explained in #136824, relating types never // introduces a constructor which could cause the recursion to be guarded. diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs new file mode 100644 index 000000000000..bb3540f9a214 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs @@ -0,0 +1,24 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#176. +// +// Normalizing ` as IntoIterator>::IntoIter` has two candidates +// inside of the function: +// - `impl IntoIterator for Vec` which trivially applies +// - `impl IntoIterator for I` +// - requires `Vec: Iterator` +// - where-clause requires ` as IntoIterator>::IntoIter eq Vec` +// - normalize ` as IntoIterator>::IntoIter` again, cycle +// +// We need to treat this cycle as an error to be able to use the actual impl. + +fn test() +where + as IntoIterator>::IntoIter: Iterator, +{ +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr new file mode 100644 index 000000000000..0a5b90f3d12b --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr @@ -0,0 +1,48 @@ +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:41:1 + | +LL | / fn generic() +LL | | where +LL | | >::Assoc: Bound, + | |____________________________________^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required for `Foo` to implement `Trait` + --> $DIR/normalizes-to-is-not-productive.rs:24:19 + | +LL | impl Trait for T { + | ----- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:41:4 + | +LL | fn generic() + | ^^^^^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required for `Foo` to implement `Trait` + --> $DIR/normalizes-to-is-not-productive.rs:24:19 + | +LL | impl Trait for T { + | ----- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:48:19 + | +LL | impls_bound::(); + | ^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required by a bound in `impls_bound` + --> $DIR/normalizes-to-is-not-productive.rs:28:19 + | +LL | fn impls_bound() { + | ^^^^^ required by this bound in `impls_bound` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr new file mode 100644 index 000000000000..d888fbf9db18 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:43:31 + | +LL | >::Assoc: Bound, + | ^^^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required for `Foo` to implement `Trait` + --> $DIR/normalizes-to-is-not-productive.rs:24:19 + | +LL | impl Trait for T { + | ----- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:48:19 + | +LL | impls_bound::(); + | ^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required by a bound in `impls_bound` + --> $DIR/normalizes-to-is-not-productive.rs:28:19 + | +LL | fn impls_bound() { + | ^^^^^ required by this bound in `impls_bound` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs new file mode 100644 index 000000000000..ffbbecaf8957 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs @@ -0,0 +1,54 @@ +//@ ignore-compare-mode-next-solver (explicit) +//@ compile-flags: -Znext-solver + +// Make sure that stepping into impl where-clauses of `NormalizesTo` +// goals is unproductive. This must not compile, see the inline +// comments. + +trait Bound { + fn method(); +} +impl Bound for u32 { + fn method() {} +} +trait Trait { + type Assoc: Bound; +} + +struct Foo; + +impl Trait for Foo { + type Assoc = u32; +} +impl Trait for T { + type Assoc = T; +} + +fn impls_bound() { + T::method(); +} + +// The where-clause requires `Foo: Trait` to hold to be wf. +// If stepping into where-clauses during normalization is considered +// to be productive, this would be the case: +// +// - `Foo: Trait` +// - via blanket impls, requires `Foo: Bound` +// - via where-bound, requires `Foo eq >::Assoc` +// - normalize `>::Assoc` +// - via blanket impl, requires where-clause `Foo: Bound` -> cycle +fn generic() +where + >::Assoc: Bound, + //~^ ERROR the trait bound `Foo: Bound` is not satisfied +{ + // Requires proving `Foo: Bound` by normalizing + // `>::Assoc` to `Foo`. + impls_bound::(); + //~^ ERROR the trait bound `Foo: Bound` is not satisfied +} +fn main() { + // Requires proving `>::Assoc: Bound`. + // This is trivially true. + generic::(); +} diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr new file mode 100644 index 000000000000..8901805a20f5 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:42:31 + | +LL | >::Assoc: Bound, + | ^^^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required for `Foo` to implement `Trait` + --> $DIR/normalizes-to-is-not-productive.rs:23:19 + | +LL | impl Trait for T { + | ----- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `Foo: Bound` is not satisfied + --> $DIR/normalizes-to-is-not-productive.rs:47:19 + | +LL | impls_bound::(); + | ^^^ the trait `Bound` is not implemented for `Foo` + | + = help: the trait `Bound` is implemented for `u32` +note: required by a bound in `impls_bound` + --> $DIR/normalizes-to-is-not-productive.rs:27:19 + | +LL | fn impls_bound() { + | ^^^^^ required by this bound in `impls_bound` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 20ab952b4dd994aa6e22ff56df5314eee5ff415c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 16 Apr 2025 10:45:03 +0200 Subject: [PATCH 206/222] Explicitly annotate edition for `unpretty=expanded` and `unpretty=hir` tests These emit prelude imports which means they are always edition dependent --- diff | 0 tests/ui/asm/unpretty-expanded.rs | 1 + tests/ui/asm/unpretty-expanded.stdout | 1 + tests/ui/codemap_tests/unicode.expanded.stdout | 1 + tests/ui/codemap_tests/unicode.normal.stderr | 2 +- tests/ui/codemap_tests/unicode.rs | 1 + tests/ui/const-generics/defaults/pretty-printing-ast.rs | 1 + .../const-generics/defaults/pretty-printing-ast.stdout | 1 + tests/ui/deriving/built-in-proc-macro-scope.rs | 1 + tests/ui/deriving/built-in-proc-macro-scope.stdout | 1 + tests/ui/deriving/deriving-coerce-pointee-expanded.rs | 1 + .../ui/deriving/deriving-coerce-pointee-expanded.stdout | 1 + tests/ui/deriving/proc-macro-attribute-mixing.rs | 1 + tests/ui/deriving/proc-macro-attribute-mixing.stdout | 1 + .../no_ice_for_partial_compiler_runs.rs | 1 + .../no_ice_for_partial_compiler_runs.stdout | 1 + tests/ui/macros/genercs-in-path-with-prettry-hir.rs | 1 + tests/ui/macros/genercs-in-path-with-prettry-hir.stderr | 2 +- tests/ui/macros/genercs-in-path-with-prettry-hir.stdout | 1 + .../non-consuming-methods-have-optimized-codegen.rs | 1 + .../non-consuming-methods-have-optimized-codegen.stdout | 1 + tests/ui/match/issue-82392.rs | 1 + tests/ui/match/issue-82392.stdout | 1 + tests/ui/proc-macro/nonterminal-token-hygiene.rs | 1 + tests/ui/proc-macro/nonterminal-token-hygiene.stdout | 9 +++++---- tests/ui/proc-macro/quote/debug.rs | 1 + tests/ui/proc-macro/quote/debug.stdout | 1 + tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs | 1 + .../rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout | 1 + tests/ui/type-alias-impl-trait/issue-60662.rs | 1 + tests/ui/type-alias-impl-trait/issue-60662.stdout | 1 + tests/ui/unpretty/bad-literal.rs | 1 + tests/ui/unpretty/bad-literal.stderr | 2 +- tests/ui/unpretty/bad-literal.stdout | 1 + tests/ui/unpretty/debug-fmt-hir.rs | 1 + tests/ui/unpretty/debug-fmt-hir.stdout | 1 + tests/ui/unpretty/deprecated-attr.rs | 1 + tests/ui/unpretty/deprecated-attr.stdout | 1 + tests/ui/unpretty/diagnostic-attr.rs | 1 + tests/ui/unpretty/diagnostic-attr.stdout | 1 + tests/ui/unpretty/expanded-interpolation.rs | 1 + tests/ui/unpretty/expanded-interpolation.stdout | 1 + tests/ui/unpretty/flattened-format-args.rs | 1 + tests/ui/unpretty/flattened-format-args.stdout | 1 + tests/ui/unpretty/let-else-hir.rs | 1 + tests/ui/unpretty/let-else-hir.stdout | 1 + tests/ui/unpretty/self-hir.rs | 1 + tests/ui/unpretty/self-hir.stdout | 1 + tests/ui/unpretty/unpretty-expr-fn-arg.rs | 1 + tests/ui/unpretty/unpretty-expr-fn-arg.stdout | 1 + 50 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 diff diff --git a/diff b/diff new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/ui/asm/unpretty-expanded.rs b/tests/ui/asm/unpretty-expanded.rs index 1da2c7704f41..3eb46fe4889c 100644 --- a/tests/ui/asm/unpretty-expanded.rs +++ b/tests/ui/asm/unpretty-expanded.rs @@ -1,4 +1,5 @@ //@ needs-asm-support //@ check-pass //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 core::arch::global_asm!("x: .byte 42"); diff --git a/tests/ui/asm/unpretty-expanded.stdout b/tests/ui/asm/unpretty-expanded.stdout index 80ccd127d506..7ba1702dfed8 100644 --- a/tests/ui/asm/unpretty-expanded.stdout +++ b/tests/ui/asm/unpretty-expanded.stdout @@ -7,4 +7,5 @@ extern crate std; //@ needs-asm-support //@ check-pass //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 global_asm! ("x: .byte 42"); diff --git a/tests/ui/codemap_tests/unicode.expanded.stdout b/tests/ui/codemap_tests/unicode.expanded.stdout index eb53d12e94f3..c88035de0449 100644 --- a/tests/ui/codemap_tests/unicode.expanded.stdout +++ b/tests/ui/codemap_tests/unicode.expanded.stdout @@ -7,6 +7,7 @@ extern crate std; //@ revisions: normal expanded //@[expanded] check-pass //@[expanded]compile-flags: -Zunpretty=expanded +//@ edition: 2015 extern "路濫狼á́́" fn foo() {} diff --git a/tests/ui/codemap_tests/unicode.normal.stderr b/tests/ui/codemap_tests/unicode.normal.stderr index 0f254e0246f4..10cb34f48326 100644 --- a/tests/ui/codemap_tests/unicode.normal.stderr +++ b/tests/ui/codemap_tests/unicode.normal.stderr @@ -1,5 +1,5 @@ error[E0703]: invalid ABI: found `路濫狼á́́` - --> $DIR/unicode.rs:5:8 + --> $DIR/unicode.rs:6:8 | LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI diff --git a/tests/ui/codemap_tests/unicode.rs b/tests/ui/codemap_tests/unicode.rs index 73023e3c669d..4b93ef094069 100644 --- a/tests/ui/codemap_tests/unicode.rs +++ b/tests/ui/codemap_tests/unicode.rs @@ -1,6 +1,7 @@ //@ revisions: normal expanded //@[expanded] check-pass //@[expanded]compile-flags: -Zunpretty=expanded +//@ edition: 2015 extern "路濫狼á́́" fn foo() {} //[normal]~ ERROR invalid ABI diff --git a/tests/ui/const-generics/defaults/pretty-printing-ast.rs b/tests/ui/const-generics/defaults/pretty-printing-ast.rs index 20bf900d9f3e..f7a166d00d55 100644 --- a/tests/ui/const-generics/defaults/pretty-printing-ast.rs +++ b/tests/ui/const-generics/defaults/pretty-printing-ast.rs @@ -1,6 +1,7 @@ // Test the AST pretty printer correctly handles default values for const generics //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 #![crate_type = "lib"] diff --git a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout index f1cd1451700f..b6cb7fa09c88 100644 --- a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout +++ b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout @@ -3,6 +3,7 @@ // Test the AST pretty printer correctly handles default values for const generics //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 #![crate_type = "lib"] #[prelude_import] diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/deriving/built-in-proc-macro-scope.rs index e67197b7e205..69128a08b997 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.rs +++ b/tests/ui/deriving/built-in-proc-macro-scope.rs @@ -1,6 +1,7 @@ //@ check-pass //@ proc-macro: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded +//@ edition:2015 #![feature(derive_coerce_pointee)] diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout index fa4e50968f4d..2697618ab003 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.stdout +++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout @@ -3,6 +3,7 @@ //@ check-pass //@ proc-macro: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded +//@ edition:2015 #![feature(derive_coerce_pointee)] #[prelude_import] diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.rs b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs index 94be7031fb77..9394ae4efe5a 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-expanded.rs +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 #![feature(derive_coerce_pointee)] use std::marker::CoercePointee; diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout index a774efbbe354..84f8e9a3195a 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout @@ -2,6 +2,7 @@ #![no_std] //@ check-pass //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 #![feature(derive_coerce_pointee)] #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/deriving/proc-macro-attribute-mixing.rs index 2c11c3f72ca5..c9e123d7e8a1 100644 --- a/tests/ui/deriving/proc-macro-attribute-mixing.rs +++ b/tests/ui/deriving/proc-macro-attribute-mixing.rs @@ -7,6 +7,7 @@ //@ check-pass //@ proc-macro: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 #![feature(derive_coerce_pointee)] diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout index ad743d013d25..faa9c0218a33 100644 --- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout +++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout @@ -9,6 +9,7 @@ //@ check-pass //@ proc-macro: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded +//@ edition: 2015 #![feature(derive_coerce_pointee)] #[prelude_import] diff --git a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs index 9e38b94b76ce..11ee2bc852ab 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs @@ -1,6 +1,7 @@ // This ensures that ICEs like rust#94953 don't happen //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 // This `expect` will create an expectation with an unstable expectation id #[expect(while_true)] diff --git a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout index d804c1d2d200..d63abea92302 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout +++ b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout @@ -7,6 +7,7 @@ extern crate std; // This ensures that ICEs like rust#94953 don't happen //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 // This `expect` will create an expectation with an unstable expectation id #[expect(while_true)] diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.rs b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs index 84370fcebbcb..e6773f610da3 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.rs +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Zunpretty=hir +//@ edition: 2015 // issue#97006 diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr index 8fcc7c6fbff0..173e77569a80 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr @@ -1,5 +1,5 @@ error: unexpected generic arguments in path - --> $DIR/genercs-in-path-with-prettry-hir.rs:12:10 + --> $DIR/genercs-in-path-with-prettry-hir.rs:13:10 | LL | m!(inline); | ^^^^ diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout index e8c88d2dcdf2..6b41eb530dbc 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout @@ -3,6 +3,7 @@ use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; //@ compile-flags: -Zunpretty=hir +//@ edition: 2015 // issue#97006 diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs index cf47a1e67aed..29f71d10719b 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 #![feature(core_intrinsics, generic_assert)] diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout index 8065d0dff8fc..9300f610f8e2 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -2,6 +2,7 @@ #![no_std] //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 #![feature(core_intrinsics, generic_assert)] #[prelude_import] diff --git a/tests/ui/match/issue-82392.rs b/tests/ui/match/issue-82392.rs index 6f9527fb337b..4ae08fed93a2 100644 --- a/tests/ui/match/issue-82392.rs +++ b/tests/ui/match/issue-82392.rs @@ -1,6 +1,7 @@ // https://github.com/rust-lang/rust/issues/82329 //@ compile-flags: -Zunpretty=hir,typed //@ check-pass +//@ edition:2015 pub fn main() { if true { diff --git a/tests/ui/match/issue-82392.stdout b/tests/ui/match/issue-82392.stdout index 8949611ac12f..8b7edabf004e 100644 --- a/tests/ui/match/issue-82392.stdout +++ b/tests/ui/match/issue-82392.stdout @@ -5,6 +5,7 @@ extern crate std; // https://github.com/rust-lang/rust/issues/82329 //@ compile-flags: -Zunpretty=hir,typed //@ check-pass +//@ edition:2015 fn main() ({ (if (true as bool) diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.rs b/tests/ui/proc-macro/nonterminal-token-hygiene.rs index e2aedb245d07..b7b0d1ea3dd7 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.rs +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.rs @@ -8,6 +8,7 @@ //@ normalize-stdout: "expn\d{3,}" -> "expnNNN" //@ normalize-stdout: "extern crate compiler_builtins /\* \d+ \*/" -> "extern crate compiler_builtins /* NNN */" //@ proc-macro: test-macros.rs +//@ edition: 2015 #![feature(decl_macro)] #![no_std] // Don't load unnecessary hygiene information from std diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 6fd6cb474693..2ebfb47d9815 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -5,19 +5,19 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "struct", - span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#5), + span: $DIR/nonterminal-token-hygiene.rs:33:5: 33:11 (#5), }, Ident { ident: "S", - span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#5), + span: $DIR/nonterminal-token-hygiene.rs:33:12: 33:13 (#5), }, Punct { ch: ';', spacing: Alone, - span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#5), + span: $DIR/nonterminal-token-hygiene.rs:33:13: 33:14 (#5), }, ], - span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#4), + span: $DIR/nonterminal-token-hygiene.rs:23:27: 23:32 (#4), }, ] #![feature /* 0#0 */(prelude_import)] @@ -32,6 +32,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ //@ normalize-stdout: "expn\d{3,}" -> "expnNNN" //@ normalize-stdout: "extern crate compiler_builtins /\* \d+ \*/" -> "extern crate compiler_builtins /* NNN */" //@ proc-macro: test-macros.rs +//@ edition: 2015 #![feature /* 0#0 */(decl_macro)] #![no_std /* 0#0 */] diff --git a/tests/ui/proc-macro/quote/debug.rs b/tests/ui/proc-macro/quote/debug.rs index ce113079e567..ce1ef81bedaf 100644 --- a/tests/ui/proc-macro/quote/debug.rs +++ b/tests/ui/proc-macro/quote/debug.rs @@ -3,6 +3,7 @@ //@ no-prefer-dynamic //@ compile-flags: -Z unpretty=expanded //@ needs-unwind compiling proc macros with panic=abort causes a warning +//@ edition: 2015 // // This file is not actually used as a proc-macro - instead, // it's just used to show the output of the `quote!` macro diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout index 3eaad9eb9699..6ebb3a379511 100644 --- a/tests/ui/proc-macro/quote/debug.stdout +++ b/tests/ui/proc-macro/quote/debug.stdout @@ -5,6 +5,7 @@ //@ no-prefer-dynamic //@ compile-flags: -Z unpretty=expanded //@ needs-unwind compiling proc macros with panic=abort causes a warning +//@ edition: 2015 // // This file is not actually used as a proc-macro - instead, // it's just used to show the output of the `quote!` macro diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs index 8d7826463336..16165c4a42cc 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 fn main() { if let 0 = 1 {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout index 1c103f03c354..e2e45ae94ea6 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout @@ -6,5 +6,6 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ check-pass //@ compile-flags: -Z unpretty=expanded +//@ edition: 2015 fn main() { if let 0 = 1 {} } diff --git a/tests/ui/type-alias-impl-trait/issue-60662.rs b/tests/ui/type-alias-impl-trait/issue-60662.rs index 35d96e52fd61..7ecdd2647355 100644 --- a/tests/ui/type-alias-impl-trait/issue-60662.rs +++ b/tests/ui/type-alias-impl-trait/issue-60662.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Z unpretty=hir +//@ edition: 2015 #![feature(type_alias_impl_trait)] diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout index b541cbeb2279..56fef852e37b 100644 --- a/tests/ui/type-alias-impl-trait/issue-60662.stdout +++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Z unpretty=hir +//@ edition: 2015 #![feature(type_alias_impl_trait)] #[prelude_import] diff --git a/tests/ui/unpretty/bad-literal.rs b/tests/ui/unpretty/bad-literal.rs index 37377898b14f..0ec1d7b07f1f 100644 --- a/tests/ui/unpretty/bad-literal.rs +++ b/tests/ui/unpretty/bad-literal.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-fail +//@ edition: 2015 // In #100948 this caused an ICE with -Zunpretty=hir. fn main() { diff --git a/tests/ui/unpretty/bad-literal.stderr b/tests/ui/unpretty/bad-literal.stderr index b6259484f67d..fd1801a87f20 100644 --- a/tests/ui/unpretty/bad-literal.stderr +++ b/tests/ui/unpretty/bad-literal.stderr @@ -1,5 +1,5 @@ error: invalid suffix `u` for number literal - --> $DIR/bad-literal.rs:6:5 + --> $DIR/bad-literal.rs:7:5 | LL | 1u; | ^^ invalid suffix `u` diff --git a/tests/ui/unpretty/bad-literal.stdout b/tests/ui/unpretty/bad-literal.stdout index c5272711d6e9..06116a4ab553 100644 --- a/tests/ui/unpretty/bad-literal.stdout +++ b/tests/ui/unpretty/bad-literal.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-fail +//@ edition: 2015 // In #100948 this caused an ICE with -Zunpretty=hir. fn main() { diff --git a/tests/ui/unpretty/debug-fmt-hir.rs b/tests/ui/unpretty/debug-fmt-hir.rs index c19f3c4c0c57..c79349de4442 100644 --- a/tests/ui/unpretty/debug-fmt-hir.rs +++ b/tests/ui/unpretty/debug-fmt-hir.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 use std::fmt; diff --git a/tests/ui/unpretty/debug-fmt-hir.stdout b/tests/ui/unpretty/debug-fmt-hir.stdout index 2c9c96de9d14..dc18675ea803 100644 --- a/tests/ui/unpretty/debug-fmt-hir.stdout +++ b/tests/ui/unpretty/debug-fmt-hir.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 use std::fmt; diff --git a/tests/ui/unpretty/deprecated-attr.rs b/tests/ui/unpretty/deprecated-attr.rs index dda362a595e2..0c80203e9652 100644 --- a/tests/ui/unpretty/deprecated-attr.rs +++ b/tests/ui/unpretty/deprecated-attr.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 #[deprecated] pub struct PlainDeprecated; diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout index 42de7b4533e5..97d863b2e943 100644 --- a/tests/ui/unpretty/deprecated-attr.stdout +++ b/tests/ui/unpretty/deprecated-attr.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] struct PlainDeprecated; diff --git a/tests/ui/unpretty/diagnostic-attr.rs b/tests/ui/unpretty/diagnostic-attr.rs index 27f5b693e691..4ef85c71f90e 100644 --- a/tests/ui/unpretty/diagnostic-attr.rs +++ b/tests/ui/unpretty/diagnostic-attr.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 #[diagnostic::on_unimplemented( message = "My Message for `ImportantTrait<{A}>` implemented for `{Self}`", diff --git a/tests/ui/unpretty/diagnostic-attr.stdout b/tests/ui/unpretty/diagnostic-attr.stdout index e8696d04d38a..81d71b91d815 100644 --- a/tests/ui/unpretty/diagnostic-attr.stdout +++ b/tests/ui/unpretty/diagnostic-attr.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 #[diagnostic::on_unimplemented(message = "My Message for `ImportantTrait<{A}>` implemented for `{Self}`", label = diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/expanded-interpolation.rs index 1dc72c67f511..0c447ae669dd 100644 --- a/tests/ui/unpretty/expanded-interpolation.rs +++ b/tests/ui/unpretty/expanded-interpolation.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=expanded //@ check-pass +//@ edition: 2015 // This test covers the AST pretty-printer's insertion of parentheses in some // macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout index 556e57dbd921..10729a96ef59 100644 --- a/tests/ui/unpretty/expanded-interpolation.stdout +++ b/tests/ui/unpretty/expanded-interpolation.stdout @@ -2,6 +2,7 @@ #![no_std] //@ compile-flags: -Zunpretty=expanded //@ check-pass +//@ edition: 2015 // This test covers the AST pretty-printer's insertion of parentheses in some // macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in diff --git a/tests/ui/unpretty/flattened-format-args.rs b/tests/ui/unpretty/flattened-format-args.rs index 772f44cc268e..ab065f494dc0 100644 --- a/tests/ui/unpretty/flattened-format-args.rs +++ b/tests/ui/unpretty/flattened-format-args.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir -Zflatten-format-args=yes //@ check-pass +//@ edition: 2015 fn main() { let x = 1; diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout index 2de1cdd96b5b..a5d943281ad8 100644 --- a/tests/ui/unpretty/flattened-format-args.stdout +++ b/tests/ui/unpretty/flattened-format-args.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir -Zflatten-format-args=yes //@ check-pass +//@ edition: 2015 fn main() { let x = 1; diff --git a/tests/ui/unpretty/let-else-hir.rs b/tests/ui/unpretty/let-else-hir.rs index 9c231189659a..786c84a09ddd 100644 --- a/tests/ui/unpretty/let-else-hir.rs +++ b/tests/ui/unpretty/let-else-hir.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 diff --git a/tests/ui/unpretty/let-else-hir.stdout b/tests/ui/unpretty/let-else-hir.stdout index a2ffa5de5673..a6dd943ec1b7 100644 --- a/tests/ui/unpretty/let-else-hir.stdout +++ b/tests/ui/unpretty/let-else-hir.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 diff --git a/tests/ui/unpretty/self-hir.rs b/tests/ui/unpretty/self-hir.rs index 448d828d4446..70e0ba589fb8 100644 --- a/tests/ui/unpretty/self-hir.rs +++ b/tests/ui/unpretty/self-hir.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 pub struct Bar { a: String, diff --git a/tests/ui/unpretty/self-hir.stdout b/tests/ui/unpretty/self-hir.stdout index 4da080dc611e..a9e80b1f5920 100644 --- a/tests/ui/unpretty/self-hir.stdout +++ b/tests/ui/unpretty/self-hir.stdout @@ -4,6 +4,7 @@ use ::std::prelude::rust_2015::*; extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass +//@ edition: 2015 struct Bar { a: String, diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.rs b/tests/ui/unpretty/unpretty-expr-fn-arg.rs index 7f496e773c28..b2ab2e0911e5 100644 --- a/tests/ui/unpretty/unpretty-expr-fn-arg.rs +++ b/tests/ui/unpretty/unpretty-expr-fn-arg.rs @@ -6,6 +6,7 @@ //@ check-pass //@ compile-flags: -Zunpretty=hir,typed +//@ edition: 2015 #![allow(dead_code)] fn main() {} diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout index 43aa93c83bd3..fd2e794fcac8 100644 --- a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout +++ b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout @@ -6,6 +6,7 @@ //@ check-pass //@ compile-flags: -Zunpretty=hir,typed +//@ edition: 2015 #![allow(dead_code)] #[prelude_import] use ::std::prelude::rust_2015::*; From a6dcd519f325e8e3bce6b59461d6f073a9f5c18b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 16 Apr 2025 12:16:40 +0200 Subject: [PATCH 207/222] fix multiple `#[repr(align(N))]` on functions --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 3 ++- tests/codegen/align-fn.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index ddb611889833..8f23a5f21cdf 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -114,7 +114,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { AttributeKind::Repr(reprs) => { codegen_fn_attrs.alignment = reprs .iter() - .find_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None }); + .filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None }) + .max(); } _ => {} diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs index 97f23cc04230..660d8cd2bbf4 100644 --- a/tests/codegen/align-fn.rs +++ b/tests/codegen/align-fn.rs @@ -47,3 +47,22 @@ impl T for () {} pub fn foo() { ().trait_method(); } + +// CHECK-LABEL: align_specified_twice_1 +// CHECK-SAME: align 64 +#[no_mangle] +#[repr(align(32), align(64))] +pub fn align_specified_twice_1() {} + +// CHECK-LABEL: align_specified_twice_2 +// CHECK-SAME: align 128 +#[no_mangle] +#[repr(align(128), align(32))] +pub fn align_specified_twice_2() {} + +// CHECK-LABEL: align_specified_twice_3 +// CHECK-SAME: align 256 +#[no_mangle] +#[repr(align(32))] +#[repr(align(256))] +pub fn align_specified_twice_3() {} From 4d6ae78fa22d04b2c255cb43faabc1ada36cd2c1 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 16 Apr 2025 20:03:18 +1000 Subject: [PATCH 208/222] Remove old diagnostic notes for type ascription syntax Type ascription syntax was removed in 2023. --- compiler/rustc_parse/messages.ftl | 3 --- compiler/rustc_parse/src/errors.rs | 6 ------ compiler/rustc_parse/src/parser/diagnostics.rs | 5 +---- compiler/rustc_parse/src/parser/path.rs | 2 -- compiler/rustc_parse/src/parser/stmt.rs | 4 ---- ...492-tuple-destructure-missing-parens.stderr | 1 - ...single-colon-path-not-const-generics.stderr | 1 - .../or-patterns-syntactic-fail.stderr | 1 - .../issue-35813-postfix-after-cast.stderr | 18 ------------------ .../turbofish-arg-with-stray-colon.stderr | 1 - tests/ui/parser/ternary_operator.stderr | 2 -- ...ype-ascription-syntactically-invalid.stderr | 2 -- ...ment-list-from-path-sep-error-129273.stderr | 1 - .../ui/suggestions/many-type-ascription.stderr | 2 -- ...ct-field-type-including-single-colon.stderr | 2 -- .../type-ascription-instead-of-method.stderr | 1 - .../type-ascription-instead-of-path-2.stderr | 1 - .../type-ascription-instead-of-path.stderr | 1 - .../type-ascription-instead-of-variant.stderr | 1 - tests/ui/type/ascription/issue-47666.stderr | 1 - tests/ui/type/ascription/issue-54516.stderr | 1 - tests/ui/type/ascription/issue-60933.stderr | 1 - tests/ui/type/missing-let-in-binding.stderr | 1 - ...-ascription-instead-of-statement-end.stderr | 1 - .../ui/type/type-ascription-precedence.stderr | 2 -- .../type/type-ascription-with-fn-call.stderr | 1 - 26 files changed, 1 insertion(+), 62 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 93fa89b68b97..5837f5de5ee8 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -806,9 +806,6 @@ parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before .suggestion = move `{$kw}` before the `for<...>` -parse_type_ascription_removed = - if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 - parse_unclosed_unicode_escape = unterminated unicode escape .label = missing a closing `{"}"}` .terminate = terminate the unicode escape diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index dfdef018bc37..bca2f1daaf62 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1598,9 +1598,6 @@ pub(crate) struct PathSingleColon { #[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")] pub suggestion: Span, - - #[note(parse_type_ascription_removed)] - pub type_ascription: bool, } #[derive(Diagnostic)] @@ -1617,9 +1614,6 @@ pub(crate) struct ColonAsSemi { #[primary_span] #[suggestion(applicability = "machine-applicable", code = ";", style = "verbose")] pub span: Span, - - #[note(parse_type_ascription_removed)] - pub type_ascription: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a4978b5a0fe1..b6945c6f7dbd 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1943,10 +1943,7 @@ impl<'a> Parser<'a> { && self.token == token::Colon && self.look_ahead(1, |next| line_idx(self.token.span) < line_idx(next.span)) { - self.dcx().emit_err(ColonAsSemi { - span: self.token.span, - type_ascription: self.psess.unstable_features.is_nightly_build(), - }); + self.dcx().emit_err(ColonAsSemi { span: self.token.span }); self.bump(); return true; } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 30fb96c6ea90..028836556623 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -273,7 +273,6 @@ impl<'a> Parser<'a> { self.dcx().emit_err(PathSingleColon { span: self.prev_token.span, suggestion: self.prev_token.span.shrink_to_hi(), - type_ascription: self.psess.unstable_features.is_nightly_build(), }); } continue; @@ -348,7 +347,6 @@ impl<'a> Parser<'a> { err = self.dcx().create_err(PathSingleColon { span: self.token.span, suggestion: self.prev_token.span.shrink_to_hi(), - type_ascription: self.psess.unstable_features.is_nightly_build(), }); } // Attempt to find places where a missing `>` might belong. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 551b9e2f1371..0cc8b6050186 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -771,10 +771,6 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - if self.psess.unstable_features.is_nightly_build() { - // FIXME(Nilstrieb): Remove this again after a few months. - err.note("type ascription syntax has been removed, see issue #101728 "); - } } } diff --git a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr index d4812d4831b0..c74cb89f85cb 100644 --- a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr +++ b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr @@ -66,7 +66,6 @@ error: unexpected `,` in pattern LL | let women, men: (Vec, Vec) = genomes.iter().cloned() | ^ | - = note: type ascription syntax has been removed, see issue #101728 help: try adding parentheses to match on a tuple | LL | let (women, men): (Vec, Vec) = genomes.iter().cloned() diff --git a/tests/ui/generics/single-colon-path-not-const-generics.stderr b/tests/ui/generics/single-colon-path-not-const-generics.stderr index c14a5e62a0c8..9eb62de27561 100644 --- a/tests/ui/generics/single-colon-path-not-const-generics.stderr +++ b/tests/ui/generics/single-colon-path-not-const-generics.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | a: Vec, | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | a: Vec, diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr index 5608138078fb..74e4ceab80e8 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -6,7 +6,6 @@ LL | let _ = |A | B: E| (); | | | while parsing the body of this closure | - = note: type ascription syntax has been removed, see issue #101728 help: you might have meant to open the body of the closure | LL | let _ = |A | { B: E| (); diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr index e34371be3d26..64cf8baf9a5d 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr @@ -49,24 +49,18 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let _ = 0i32: i32: i32.count_ones(); | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `!`, `(`, `.`, `::`, `;`, `<`, `?`, or `else`, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:43:21 | LL | let _ = 0 as i32: i32.count_ones(); | ^ expected one of 8 possible tokens - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:47:17 | LL | let _ = 0i32: i32 as i32.count_ones(); | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: cast cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:51:13 @@ -84,16 +78,12 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let _ = 0i32: i32: i32 as u32 as i32.count_ones(); | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:60:17 | LL | let _ = 0i32: i32.count_ones(): u32; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: cast cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:64:13 @@ -111,16 +101,12 @@ error: expected one of `.`, `;`, `?`, or `else`, found `:` | LL | let _ = 0 as i32.count_ones(): u32; | ^ expected one of `.`, `;`, `?`, or `else` - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:69:17 | LL | let _ = 0i32: i32.count_ones() as u32; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: cast cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:73:13 @@ -138,8 +124,6 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let _ = 0i32: i32: i32.count_ones() as u32 as i32; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: cast cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:82:13 @@ -262,8 +246,6 @@ error: expected identifier, found `:` | LL | drop_ptr: F(); | ^ expected identifier - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` --> $DIR/issue-35813-postfix-after-cast.rs:160:13 diff --git a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr index 583b98c650f0..c0f9db9184c0 100644 --- a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr +++ b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr @@ -4,7 +4,6 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, fo LL | let x = Tr; | ^ expected one of 8 possible tokens | - = note: type ascription syntax has been removed, see issue #101728 help: maybe write a path separator here | LL | let x = Tr; diff --git a/tests/ui/parser/ternary_operator.stderr b/tests/ui/parser/ternary_operator.stderr index 6635e1672f78..e12a7ff3718e 100644 --- a/tests/ui/parser/ternary_operator.stderr +++ b/tests/ui/parser/ternary_operator.stderr @@ -33,8 +33,6 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: Rust has no ternary operator --> $DIR/ternary_operator.rs:26:19 diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr index 6ce8f6d31a03..1847e407f6ba 100644 --- a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr +++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr @@ -11,8 +11,6 @@ error: expected one of `)`, `,`, `@`, `if`, or `|`, found `:` | LL | let a @ (b: u8); | ^ expected one of `)`, `,`, `@`, `if`, or `|` - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@` --> $DIR/nested-type-ascription-syntactically-invalid.rs:30:15 diff --git a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr index 92947e3b177f..713b071a625a 100644 --- a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr +++ b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | fn fmt(&self, f: &mut fmt:Formatter) -> fmt::Result { | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/tests/ui/suggestions/many-type-ascription.stderr b/tests/ui/suggestions/many-type-ascription.stderr index feddc7d62a75..47e19c508ef9 100644 --- a/tests/ui/suggestions/many-type-ascription.stderr +++ b/tests/ui/suggestions/many-type-ascription.stderr @@ -3,8 +3,6 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` | LL | let _ = 0: i32; | ^ expected one of `.`, `;`, `?`, `else`, or an operator - | - = note: type ascription syntax has been removed, see issue #101728 error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr index ce16aca1e14a..b9302b0453d5 100644 --- a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr +++ b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | a: foo:A, | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | a: foo::A, @@ -16,7 +15,6 @@ error: path separator must be a double colon LL | b: foo::bar:B, | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | b: foo::bar::B, diff --git a/tests/ui/suggestions/type-ascription-instead-of-method.stderr b/tests/ui/suggestions/type-ascription-instead-of-method.stderr index 0bef1c185db6..6dc7b5e18ef8 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-method.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-method.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | let _ = Box:new("foo".to_string()); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | let _ = Box::new("foo".to_string()); diff --git a/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr b/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr index 0b37bf9a57bb..79dffc0cf9b0 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr @@ -4,7 +4,6 @@ error: expected one of `(`, `.`, `::`, `;`, `?`, `else`, or an operator, found ` LL | let _ = vec![Ok(2)].into_iter().collect:,_>>()?; | ^ expected one of 7 possible tokens | - = note: type ascription syntax has been removed, see issue #101728 help: maybe write a path separator here | LL | let _ = vec![Ok(2)].into_iter().collect::,_>>()?; diff --git a/tests/ui/suggestions/type-ascription-instead-of-path.stderr b/tests/ui/suggestions/type-ascription-instead-of-path.stderr index 8c16acff7994..a8364611b50c 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-path.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-path.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | std:io::stdin(); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | std::io::stdin(); diff --git a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr index f0b31722e40e..e836b37c100d 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | let _ = Option:Some(""); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | let _ = Option::Some(""); diff --git a/tests/ui/type/ascription/issue-47666.stderr b/tests/ui/type/ascription/issue-47666.stderr index fd825e86675d..6568845fe5de 100644 --- a/tests/ui/type/ascription/issue-47666.stderr +++ b/tests/ui/type/ascription/issue-47666.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | let _ = Option:Some(vec![0, 1]); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | let _ = Option::Some(vec![0, 1]); diff --git a/tests/ui/type/ascription/issue-54516.stderr b/tests/ui/type/ascription/issue-54516.stderr index 64fdc1fa24a6..925080e9050b 100644 --- a/tests/ui/type/ascription/issue-54516.stderr +++ b/tests/ui/type/ascription/issue-54516.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | println!("{}", std::mem:size_of::>()); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | println!("{}", std::mem::size_of::>()); diff --git a/tests/ui/type/ascription/issue-60933.stderr b/tests/ui/type/ascription/issue-60933.stderr index c68394d0504a..7b55935b35ba 100644 --- a/tests/ui/type/ascription/issue-60933.stderr +++ b/tests/ui/type/ascription/issue-60933.stderr @@ -4,7 +4,6 @@ error: path separator must be a double colon LL | let _: usize = std::mem:size_of::(); | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a double colon instead | LL | let _: usize = std::mem::size_of::(); diff --git a/tests/ui/type/missing-let-in-binding.stderr b/tests/ui/type/missing-let-in-binding.stderr index a9d766e4c3cf..dee3d56dc51e 100644 --- a/tests/ui/type/missing-let-in-binding.stderr +++ b/tests/ui/type/missing-let-in-binding.stderr @@ -4,7 +4,6 @@ error: expected identifier, found `:` LL | _foo: i32 = 4; | ^ expected identifier | - = note: type ascription syntax has been removed, see issue #101728 help: you might have meant to introduce a new binding | LL | let _foo: i32 = 4; diff --git a/tests/ui/type/type-ascription-instead-of-statement-end.stderr b/tests/ui/type/type-ascription-instead-of-statement-end.stderr index 34759b413d89..82b7fd23a4d9 100644 --- a/tests/ui/type/type-ascription-instead-of-statement-end.stderr +++ b/tests/ui/type/type-ascription-instead-of-statement-end.stderr @@ -4,7 +4,6 @@ error: statements are terminated with a semicolon LL | println!("test"): | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a semicolon instead | LL - println!("test"): diff --git a/tests/ui/type/type-ascription-precedence.stderr b/tests/ui/type/type-ascription-precedence.stderr index 09cdc370309d..f7ae612ef60f 100644 --- a/tests/ui/type/type-ascription-precedence.stderr +++ b/tests/ui/type/type-ascription-precedence.stderr @@ -33,8 +33,6 @@ error: expected identifier, found `:` | LL | S .. S: S; | ^ expected identifier - | - = note: type ascription syntax has been removed, see issue #101728 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` --> $DIR/type-ascription-precedence.rs:53:13 diff --git a/tests/ui/type/type-ascription-with-fn-call.stderr b/tests/ui/type/type-ascription-with-fn-call.stderr index 4222762373dc..803c9f1c302e 100644 --- a/tests/ui/type/type-ascription-with-fn-call.stderr +++ b/tests/ui/type/type-ascription-with-fn-call.stderr @@ -4,7 +4,6 @@ error: statements are terminated with a semicolon LL | f() : | ^ | - = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 help: use a semicolon instead | LL - f() : From face4716ee0015c489c3108b9180d81865aca4b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Apr 2025 14:48:20 +0200 Subject: [PATCH 209/222] replace some #[rustc_intrinsic] usage with use of the libcore declarations --- tests/codegen/intrinsic-no-unnamed-attr.rs | 5 +-- tests/ui/intrinsics/intrinsic-atomics.rs | 51 +--------------------- 2 files changed, 4 insertions(+), 52 deletions(-) diff --git a/tests/codegen/intrinsic-no-unnamed-attr.rs b/tests/codegen/intrinsic-no-unnamed-attr.rs index 35eb025ab6bb..4bec579831dc 100644 --- a/tests/codegen/intrinsic-no-unnamed-attr.rs +++ b/tests/codegen/intrinsic-no-unnamed-attr.rs @@ -1,9 +1,8 @@ //@ compile-flags: -C no-prepopulate-passes -#![feature(intrinsics)] +#![feature(core_intrinsics)] -#[rustc_intrinsic] -unsafe fn sqrtf32(x: f32) -> f32; +use std::intrinsics::sqrtf32; // CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}} diff --git a/tests/ui/intrinsics/intrinsic-atomics.rs b/tests/ui/intrinsics/intrinsic-atomics.rs index 6bc3f8d884db..9127cc649e66 100644 --- a/tests/ui/intrinsics/intrinsic-atomics.rs +++ b/tests/ui/intrinsics/intrinsic-atomics.rs @@ -1,53 +1,6 @@ //@ run-pass -#![feature(intrinsics)] - -mod rusti { - - #[rustc_intrinsic] - pub unsafe fn atomic_cxchg_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - #[rustc_intrinsic] - pub unsafe fn atomic_cxchg_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - #[rustc_intrinsic] - pub unsafe fn atomic_cxchg_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - - #[rustc_intrinsic] - pub unsafe fn atomic_cxchgweak_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - #[rustc_intrinsic] - pub unsafe fn atomic_cxchgweak_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - #[rustc_intrinsic] - pub unsafe fn atomic_cxchgweak_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - - #[rustc_intrinsic] - pub unsafe fn atomic_load_seqcst(src: *const T) -> T; - #[rustc_intrinsic] - pub unsafe fn atomic_load_acquire(src: *const T) -> T; - - #[rustc_intrinsic] - pub unsafe fn atomic_store_seqcst(dst: *mut T, val: T); - #[rustc_intrinsic] - pub unsafe fn atomic_store_release(dst: *mut T, val: T); - - #[rustc_intrinsic] - pub unsafe fn atomic_xchg_seqcst(dst: *mut T, src: T) -> T; - #[rustc_intrinsic] - pub unsafe fn atomic_xchg_acquire(dst: *mut T, src: T) -> T; - #[rustc_intrinsic] - pub unsafe fn atomic_xchg_release(dst: *mut T, src: T) -> T; - - #[rustc_intrinsic] - pub unsafe fn atomic_xadd_seqcst(dst: *mut T, src: T) -> T; - #[rustc_intrinsic] - pub unsafe fn atomic_xadd_acquire(dst: *mut T, src: T) -> T; - #[rustc_intrinsic] - pub unsafe fn atomic_xadd_release(dst: *mut T, src: T) -> T; - - #[rustc_intrinsic] - pub unsafe fn atomic_xsub_seqcst(dst: *mut T, src: T) -> T; - #[rustc_intrinsic] - pub unsafe fn atomic_xsub_acquire(dst: *mut T, src: T) -> T; - #[rustc_intrinsic] - pub unsafe fn atomic_xsub_release(dst: *mut T, src: T) -> T; -} +#![feature(core_intrinsics)] +use std::intrinsics as rusti; pub fn main() { unsafe { From 299877e280bbe02f0170742396c38ab0b20bab59 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 16 Apr 2025 14:52:08 +0200 Subject: [PATCH 210/222] Update stdarch submodule --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index 9426bb56586c..4666c7376f25 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 9426bb56586c6ae4095a2dcbd66c570253e6fb32 +Subproject commit 4666c7376f25a265c74535585d622da3da6dfeb1 From 7ce21e4fb39e9d288f3fe96ad48f8bc8ec973588 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 15 Apr 2025 20:04:04 -0600 Subject: [PATCH 211/222] Cleaned up base tests for `isize` and `usize` in `tests/ui/numbers-arithmetic` --- tests/ui/numbers-arithmetic/int.rs | 6 ------ tests/ui/numbers-arithmetic/isize-base.rs | 25 +++++++++++++++++++++++ tests/ui/numbers-arithmetic/uint.rs | 6 ------ tests/ui/numbers-arithmetic/usize-base.rs | 25 +++++++++++++++++++++++ 4 files changed, 50 insertions(+), 12 deletions(-) delete mode 100644 tests/ui/numbers-arithmetic/int.rs create mode 100644 tests/ui/numbers-arithmetic/isize-base.rs delete mode 100644 tests/ui/numbers-arithmetic/uint.rs create mode 100644 tests/ui/numbers-arithmetic/usize-base.rs diff --git a/tests/ui/numbers-arithmetic/int.rs b/tests/ui/numbers-arithmetic/int.rs deleted file mode 100644 index 42f8e50d6efa..000000000000 --- a/tests/ui/numbers-arithmetic/int.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass - - - - -pub fn main() { let _x: isize = 10; } diff --git a/tests/ui/numbers-arithmetic/isize-base.rs b/tests/ui/numbers-arithmetic/isize-base.rs new file mode 100644 index 000000000000..412e7ac7a2e9 --- /dev/null +++ b/tests/ui/numbers-arithmetic/isize-base.rs @@ -0,0 +1,25 @@ +//! Tests basic `isize` functionality + +//@ run-pass + +pub fn main() { + // Literal matches assignment type + let a: isize = 42isize; + // Literal cast + let b: isize = 42 as isize; + // Literal type inference from assignment type + let c: isize = 42; + // Assignment type inference from literal (and later comparison) + let d = 42isize; + // Function return value type inference + let e = return_val(); + + assert_eq!(a, b); + assert_eq!(a, c); + assert_eq!(a, d); + assert_eq!(a, e); +} + +fn return_val() -> isize { + 42 +} diff --git a/tests/ui/numbers-arithmetic/uint.rs b/tests/ui/numbers-arithmetic/uint.rs deleted file mode 100644 index c2087b5a06c6..000000000000 --- a/tests/ui/numbers-arithmetic/uint.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass - - - - -pub fn main() { let _x: usize = 10 as usize; } diff --git a/tests/ui/numbers-arithmetic/usize-base.rs b/tests/ui/numbers-arithmetic/usize-base.rs new file mode 100644 index 000000000000..833fc0497989 --- /dev/null +++ b/tests/ui/numbers-arithmetic/usize-base.rs @@ -0,0 +1,25 @@ +//! Tests basic `usize` functionality + +//@ run-pass + +pub fn main() { + // Literal matches assignment type + let a: usize = 42usize; + // Literal cast + let b: usize = 42 as usize; + // Literal type inference from assignment type + let c: usize = 42; + // Assignment type inference from literal (and later comparison) + let d = 42usize; + // Function return value type inference + let e = return_val(); + + assert_eq!(a, b); + assert_eq!(a, c); + assert_eq!(a, d); + assert_eq!(a, e); +} + +fn return_val() -> usize { + 42 +} From 01cfa9aad5d8de34f968f41ef196e0cb0292a942 Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Tue, 8 Apr 2025 05:30:21 +0300 Subject: [PATCH 212/222] Add hard error for `extern` without explicit ABI --- compiler/rustc_ast_passes/messages.ftl | 4 ++++ compiler/rustc_ast_passes/src/ast_validation.rs | 12 +++++++----- compiler/rustc_ast_passes/src/errors.rs | 9 +++++++++ compiler/rustc_lint/messages.ftl | 2 +- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 25944392a52a..80754a8f65a6 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -79,6 +79,10 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de .suggestion = remove the {$remove_descr} .label = `extern` block begins here +ast_passes_extern_without_abi = `extern` declarations without an explicit ABI are disallowed + .suggestion = specify an ABI + .help = prior to Rust 2024, a default ABI was inferred + ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel .suggestion = remove the attribute .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dc77e7b28344..9a7b7daabbf1 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -684,7 +684,7 @@ impl<'a> AstValidator<'a> { self.dcx().emit_err(errors::PatternFnPointer { span }); }); if let Extern::Implicit(extern_span) = bfty.ext { - self.maybe_lint_missing_abi(extern_span, ty.id); + self.handle_missing_abi(extern_span, ty.id); } } TyKind::TraitObject(bounds, ..) => { @@ -717,10 +717,12 @@ impl<'a> AstValidator<'a> { } } - fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) { + fn handle_missing_abi(&mut self, span: Span, id: NodeId) { // FIXME(davidtwco): This is a hack to detect macros which produce spans of the // call site which do not have a macro backtrace. See #61963. - if self + if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() { + self.dcx().emit_err(errors::MissingAbi { span }); + } else if self .sess .source_map() .span_to_snippet(span) @@ -996,7 +998,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } if abi.is_none() { - self.maybe_lint_missing_abi(*extern_span, item.id); + self.handle_missing_abi(*extern_span, item.id); } self.with_in_extern_mod(*safety, |this| { visit::walk_item(this, item); @@ -1370,7 +1372,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }, ) = fk { - self.maybe_lint_missing_abi(*extern_span, id); + self.handle_missing_abi(*extern_span, id); } // Functions without bodies cannot have patterns. diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 8e53e600f7ac..2373a7d223e8 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -823,3 +823,12 @@ pub(crate) struct DuplicatePreciseCapturing { #[label] pub bound2: Span, } + +#[derive(Diagnostic)] +#[diag(ast_passes_extern_without_abi)] +#[help] +pub(crate) struct MissingAbi { + #[primary_span] + #[suggestion(code = "extern \"\"", applicability = "has-placeholders")] + pub span: Span, +} diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 782d328a9510..60c183bd56b1 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -271,7 +271,7 @@ lint_expectation = this lint expectation is unfulfilled lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition .suggestion = convert it to a `use` -lint_extern_without_abi = extern declarations without an explicit ABI are deprecated +lint_extern_without_abi = `extern` declarations without an explicit ABI are deprecated .label = ABI should be specified here .suggestion = explicitly specify the {$default_abi} ABI From d17c04e4a220d6f7bf170eeb0f90498e215555fa Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Tue, 8 Apr 2025 05:31:24 +0300 Subject: [PATCH 213/222] Add test for `extern` without explicit ABI --- ...re-gate-explicit-extern-abis.current.fixed | 45 +++++++++++++++++++ ...e-gate-explicit-extern-abis.current.stderr | 22 +++++++++ ...explicit-extern-abis.current_feature.fixed | 45 +++++++++++++++++++ ...xplicit-extern-abis.current_feature.stderr | 22 +++++++++ ...ure-gate-explicit-extern-abis.future.fixed | 45 +++++++++++++++++++ ...re-gate-explicit-extern-abis.future.stderr | 22 +++++++++ ...explicit-extern-abis.future_feature.stderr | 26 +++++++++++ .../feature-gate-explicit-extern-abis.rs | 45 +++++++++++++++++++ .../suggest-libname-only-1.rs | 2 +- .../suggest-libname-only-1.stderr | 2 +- .../suggest-libname-only-2.rs | 2 +- .../suggest-libname-only-2.stderr | 2 +- .../lint/cli-lint-override.forbid_warn.stderr | 2 +- .../cli-lint-override.force_warn_deny.stderr | 2 +- tests/ui/lint/cli-lint-override.rs | 6 +-- .../lint/cli-lint-override.warn_deny.stderr | 2 +- tests/ui/parser/bad-lit-suffixes.stderr | 4 +- tests/ui/parser/lit-err-in-macro.stderr | 2 +- tests/ui/proc-macro/inner-attrs.rs | 2 +- tests/ui/proc-macro/inner-attrs.stderr | 2 +- 20 files changed, 287 insertions(+), 15 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed create mode 100644 tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr create mode 100644 tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed create mode 100644 tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr create mode 100644 tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed create mode 100644 tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr create mode 100644 tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr create mode 100644 tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed new file mode 100644 index 000000000000..525f78d162fc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed @@ -0,0 +1,45 @@ +// The purpose of this feature gate is to make something into a hard error in a +// future edition. Consequently, this test differs from most other feature gate +// tests. Instead of verifying that an error occurs when the feature gate is +// missing, it ensures that the hard error is only produced with the feature +// gate is present in the `future` edition -- and otherwise that only a warning +// is emitted. + +//@ revisions: current current_feature future future_feature + +//@ [current] run-rustfix +//@ [current] check-pass + +//@ [current_feature] run-rustfix +//@ [current_feature] check-pass + +//@ [future] edition: future +//@ [future] compile-flags: -Z unstable-options +//@ [future] run-rustfix +//@ [future] check-pass + +//@ [future_feature] edition: future +//@ [future_feature] compile-flags: -Z unstable-options + +#![cfg_attr(future_feature, feature(explicit_extern_abis))] +#![cfg_attr(current_feature, feature(explicit_extern_abis))] + +extern "C" fn _foo() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" fn _bar() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr new file mode 100644 index 000000000000..cf927807c7c3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr @@ -0,0 +1,22 @@ +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + | +LL | extern fn _foo() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + | + = note: `#[warn(missing_abi)]` on by default + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + | +LL | unsafe extern fn _bar() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + | +LL | unsafe extern {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: 3 warnings emitted + diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed new file mode 100644 index 000000000000..525f78d162fc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed @@ -0,0 +1,45 @@ +// The purpose of this feature gate is to make something into a hard error in a +// future edition. Consequently, this test differs from most other feature gate +// tests. Instead of verifying that an error occurs when the feature gate is +// missing, it ensures that the hard error is only produced with the feature +// gate is present in the `future` edition -- and otherwise that only a warning +// is emitted. + +//@ revisions: current current_feature future future_feature + +//@ [current] run-rustfix +//@ [current] check-pass + +//@ [current_feature] run-rustfix +//@ [current_feature] check-pass + +//@ [future] edition: future +//@ [future] compile-flags: -Z unstable-options +//@ [future] run-rustfix +//@ [future] check-pass + +//@ [future_feature] edition: future +//@ [future_feature] compile-flags: -Z unstable-options + +#![cfg_attr(future_feature, feature(explicit_extern_abis))] +#![cfg_attr(current_feature, feature(explicit_extern_abis))] + +extern "C" fn _foo() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" fn _bar() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr new file mode 100644 index 000000000000..cf927807c7c3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr @@ -0,0 +1,22 @@ +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + | +LL | extern fn _foo() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + | + = note: `#[warn(missing_abi)]` on by default + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + | +LL | unsafe extern fn _bar() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + | +LL | unsafe extern {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: 3 warnings emitted + diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed new file mode 100644 index 000000000000..525f78d162fc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed @@ -0,0 +1,45 @@ +// The purpose of this feature gate is to make something into a hard error in a +// future edition. Consequently, this test differs from most other feature gate +// tests. Instead of verifying that an error occurs when the feature gate is +// missing, it ensures that the hard error is only produced with the feature +// gate is present in the `future` edition -- and otherwise that only a warning +// is emitted. + +//@ revisions: current current_feature future future_feature + +//@ [current] run-rustfix +//@ [current] check-pass + +//@ [current_feature] run-rustfix +//@ [current_feature] check-pass + +//@ [future] edition: future +//@ [future] compile-flags: -Z unstable-options +//@ [future] run-rustfix +//@ [future] check-pass + +//@ [future_feature] edition: future +//@ [future_feature] compile-flags: -Z unstable-options + +#![cfg_attr(future_feature, feature(explicit_extern_abis))] +#![cfg_attr(current_feature, feature(explicit_extern_abis))] + +extern "C" fn _foo() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" fn _bar() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern "C" {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr new file mode 100644 index 000000000000..cf927807c7c3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr @@ -0,0 +1,22 @@ +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + | +LL | extern fn _foo() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + | + = note: `#[warn(missing_abi)]` on by default + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + | +LL | unsafe extern fn _bar() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + | +LL | unsafe extern {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + +warning: 3 warnings emitted + diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr new file mode 100644 index 000000000000..096a6f434169 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr @@ -0,0 +1,26 @@ +error: `extern` declarations without an explicit ABI are disallowed + --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + | +LL | extern fn _foo() {} + | ^^^^^^ help: specify an ABI: `extern ""` + | + = help: prior to Rust 2024, a default ABI was inferred + +error: `extern` declarations without an explicit ABI are disallowed + --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + | +LL | unsafe extern fn _bar() {} + | ^^^^^^ help: specify an ABI: `extern ""` + | + = help: prior to Rust 2024, a default ABI was inferred + +error: `extern` declarations without an explicit ABI are disallowed + --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + | +LL | unsafe extern {} + | ^^^^^^ help: specify an ABI: `extern ""` + | + = help: prior to Rust 2024, a default ABI was inferred + +error: aborting due to 3 previous errors + diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs new file mode 100644 index 000000000000..379c45f58990 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs @@ -0,0 +1,45 @@ +// The purpose of this feature gate is to make something into a hard error in a +// future edition. Consequently, this test differs from most other feature gate +// tests. Instead of verifying that an error occurs when the feature gate is +// missing, it ensures that the hard error is only produced with the feature +// gate is present in the `future` edition -- and otherwise that only a warning +// is emitted. + +//@ revisions: current current_feature future future_feature + +//@ [current] run-rustfix +//@ [current] check-pass + +//@ [current_feature] run-rustfix +//@ [current_feature] check-pass + +//@ [future] edition: future +//@ [future] compile-flags: -Z unstable-options +//@ [future] run-rustfix +//@ [future] check-pass + +//@ [future_feature] edition: future +//@ [future_feature] compile-flags: -Z unstable-options + +#![cfg_attr(future_feature, feature(explicit_extern_abis))] +#![cfg_attr(current_feature, feature(explicit_extern_abis))] + +extern fn _foo() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern fn _bar() {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +unsafe extern {} +//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated +//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated +//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed + +fn main() {} diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.rs b/tests/ui/link-native-libs/suggest-libname-only-1.rs index c69949d1fdb3..8699e4819e62 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-1.rs +++ b/tests/ui/link-native-libs/suggest-libname-only-1.rs @@ -2,7 +2,7 @@ //@ compile-flags: --crate-type rlib #[link(name = "libfoo.a", kind = "static")] -extern { } //~ WARN extern declarations without an explicit ABI are deprecated +extern { } //~ WARN `extern` declarations without an explicit ABI are deprecated //~| HELP explicitly specify the "C" ABI pub fn main() { } diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.stderr b/tests/ui/link-native-libs/suggest-libname-only-1.stderr index 0320294a8004..59bd99f619a0 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-1.stderr +++ b/tests/ui/link-native-libs/suggest-libname-only-1.stderr @@ -1,4 +1,4 @@ -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/suggest-libname-only-1.rs:5:1 | LL | extern { } diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.rs b/tests/ui/link-native-libs/suggest-libname-only-2.rs index d5150c327cd5..87373f563d09 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-2.rs +++ b/tests/ui/link-native-libs/suggest-libname-only-2.rs @@ -2,7 +2,7 @@ //@ compile-flags: --crate-type rlib #[link(name = "bar.lib", kind = "static")] -extern { } //~ WARN extern declarations without an explicit ABI are deprecated +extern { } //~ WARN `extern` declarations without an explicit ABI are deprecated //~| HELP explicitly specify the "C" ABI pub fn main() { } diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.stderr b/tests/ui/link-native-libs/suggest-libname-only-2.stderr index e492aea27b45..298a9ced1707 100644 --- a/tests/ui/link-native-libs/suggest-libname-only-2.stderr +++ b/tests/ui/link-native-libs/suggest-libname-only-2.stderr @@ -1,4 +1,4 @@ -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/suggest-libname-only-2.rs:5:1 | LL | extern { } diff --git a/tests/ui/lint/cli-lint-override.forbid_warn.stderr b/tests/ui/lint/cli-lint-override.forbid_warn.stderr index fb8779ad4f15..fe3437ae3d75 100644 --- a/tests/ui/lint/cli-lint-override.forbid_warn.stderr +++ b/tests/ui/lint/cli-lint-override.forbid_warn.stderr @@ -1,4 +1,4 @@ -error: extern declarations without an explicit ABI are deprecated +error: `extern` declarations without an explicit ABI are deprecated --> $DIR/cli-lint-override.rs:12:1 | LL | extern fn foo() {} diff --git a/tests/ui/lint/cli-lint-override.force_warn_deny.stderr b/tests/ui/lint/cli-lint-override.force_warn_deny.stderr index 10fc13e3f52f..f48fca4bd9f3 100644 --- a/tests/ui/lint/cli-lint-override.force_warn_deny.stderr +++ b/tests/ui/lint/cli-lint-override.force_warn_deny.stderr @@ -1,4 +1,4 @@ -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/cli-lint-override.rs:12:1 | LL | extern fn foo() {} diff --git a/tests/ui/lint/cli-lint-override.rs b/tests/ui/lint/cli-lint-override.rs index 4b3fd0d9c01c..b733872166aa 100644 --- a/tests/ui/lint/cli-lint-override.rs +++ b/tests/ui/lint/cli-lint-override.rs @@ -10,8 +10,8 @@ extern fn foo() {} -//[warn_deny]~^ ERROR extern declarations without an explicit ABI are deprecated -//[forbid_warn]~^^ ERROR extern declarations without an explicit ABI are deprecated -//[force_warn_deny]~^^^ WARN extern declarations without an explicit ABI are deprecated +//[warn_deny]~^ ERROR `extern` declarations without an explicit ABI are deprecated +//[forbid_warn]~^^ ERROR `extern` declarations without an explicit ABI are deprecated +//[force_warn_deny]~^^^ WARN `extern` declarations without an explicit ABI are deprecated fn main() {} diff --git a/tests/ui/lint/cli-lint-override.warn_deny.stderr b/tests/ui/lint/cli-lint-override.warn_deny.stderr index 979ca22324f1..91baad1f9f87 100644 --- a/tests/ui/lint/cli-lint-override.warn_deny.stderr +++ b/tests/ui/lint/cli-lint-override.warn_deny.stderr @@ -1,4 +1,4 @@ -error: extern declarations without an explicit ABI are deprecated +error: `extern` declarations without an explicit ABI are deprecated --> $DIR/cli-lint-override.rs:12:1 | LL | extern fn foo() {} diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index d6b50b0e0d1f..86ef35bf7833 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -51,7 +51,7 @@ LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/bad-lit-suffixes.rs:3:1 | LL | extern @@ -59,7 +59,7 @@ LL | extern | = note: `#[warn(missing_abi)]` on by default -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/bad-lit-suffixes.rs:7:1 | LL | extern diff --git a/tests/ui/parser/lit-err-in-macro.stderr b/tests/ui/parser/lit-err-in-macro.stderr index 9422f22f9c8f..08fe58643d40 100644 --- a/tests/ui/parser/lit-err-in-macro.stderr +++ b/tests/ui/parser/lit-err-in-macro.stderr @@ -4,7 +4,7 @@ error: suffixes on string literals are invalid LL | f!("Foo"__); | ^^^^^^^ invalid suffix `__` -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/lit-err-in-macro.rs:3:9 | LL | extern $abi fn f() {} diff --git a/tests/ui/proc-macro/inner-attrs.rs b/tests/ui/proc-macro/inner-attrs.rs index c541e93f9041..ca4b2029a338 100644 --- a/tests/ui/proc-macro/inner-attrs.rs +++ b/tests/ui/proc-macro/inner-attrs.rs @@ -82,7 +82,7 @@ fn bar() { } -extern { //~ WARN extern declarations without an explicit ABI are deprecated +extern { //~ WARN `extern` declarations without an explicit ABI are deprecated fn weird_extern() { #![print_target_and_args_consume(tenth)] } diff --git a/tests/ui/proc-macro/inner-attrs.stderr b/tests/ui/proc-macro/inner-attrs.stderr index 4e7825c0d007..54cccae8da08 100644 --- a/tests/ui/proc-macro/inner-attrs.stderr +++ b/tests/ui/proc-macro/inner-attrs.stderr @@ -22,7 +22,7 @@ error: expected non-macro inner attribute, found attribute macro `print_attr` LL | #![print_attr] | ^^^^^^^^^^ not a non-macro inner attribute -warning: extern declarations without an explicit ABI are deprecated +warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/inner-attrs.rs:85:1 | LL | extern { From bb3c98165cca752ba93927f19fa3f78c48caccc7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 16 Apr 2025 18:30:33 +0000 Subject: [PATCH 214/222] Don't require rigid alias's trait to hold --- .../src/solve/normalizes_to/mod.rs | 1 - tests/ui/coroutine/higher-ranked-rigid.rs | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/ui/coroutine/higher-ranked-rigid.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 2d027f16e5d9..fdeb276a58e6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -45,7 +45,6 @@ where goal, goal.predicate.alias, ); - this.add_goal(GoalSource::AliasWellFormed, goal.with(cx, trait_ref)); this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) }) diff --git a/tests/ui/coroutine/higher-ranked-rigid.rs b/tests/ui/coroutine/higher-ranked-rigid.rs new file mode 100644 index 000000000000..23a7d51300c9 --- /dev/null +++ b/tests/ui/coroutine/higher-ranked-rigid.rs @@ -0,0 +1,41 @@ +//@ edition: 2024 +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for . +// Coroutines erase all free lifetimes from their interior types, replacing them with higher- +// ranked regions which act as universals, to properly represent the fact that we don't know what +// the value of the region is within the coroutine. +// +// In the future in `from_request`, that means that the `'r` lifetime is being replaced in +// `>::Assoc`, which is in present in the existential bounds of the +// `dyn Future` that it's awaiting. Normalizing this associated type, with its free lifetimes +// replaced, means proving `T: FromRequest<'!0>`, which doesn't hold without constraining the +// `'!0` lifetime, which we don't do today. + +// Proving `T: Trait` holds when `::Assoc` is rigid is not necessary for soundness, +// at least not *yet*, and it's not even necessary for diagnostics since we have other special +// casing for, e.g., AliasRelate goals failing in the BestObligation folder. + +// The old solver unintentioanlly avoids this by never checking that `T: Trait` holds when +// `::Assoc` is rigid. Introducing this additional requirement when projecting rigidly +// in the old solver causes this (and tons of production crates) to fail. See the fallout from the +// crater run at . + +use std::future::Future; +use std::pin::Pin; + +pub trait FromRequest<'r> { + type Assoc; + fn from_request() -> Pin + Send>>; +} + +fn test<'r, T: FromRequest<'r>>() -> Pin + Send>> { + Box::pin(async move { + T::from_request().await; + }) +} + +fn main() {} From b7fbf20fe1a46c1d5443399f9c624abf00cfb021 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 11 Apr 2025 16:16:12 -0700 Subject: [PATCH 215/222] transmutability: Refactor tests for simplicity --- .../src/maybe_transmutable/tests.rs | 140 +++++++++--------- 1 file changed, 74 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index 4d81382eba02..69a6b1b77f4b 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -1,93 +1,115 @@ use itertools::Itertools; use super::query_context::test::{Def, UltraMinimal}; -use crate::maybe_transmutable::MaybeTransmutableQuery; -use crate::{Reason, layout}; +use crate::{Answer, Assume, Reason, layout}; + +type Tree = layout::Tree; +type Dfa = layout::Dfa; + +trait Representation { + fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer; +} + +impl Representation for Tree { + fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer { + crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal) + .answer() + } +} + +impl Representation for Dfa { + fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer { + crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal) + .answer() + } +} + +fn is_transmutable( + src: &R, + dst: &R, + assume: Assume, +) -> crate::Answer { + let src = src.clone(); + let dst = dst.clone(); + // The only dimension of the transmutability analysis we want to test + // here is the safety analysis. To ensure this, we disable all other + // toggleable aspects of the transmutability analysis. + R::is_transmutable(src, dst, assume) +} mod safety { use super::*; use crate::Answer; - type Tree = layout::Tree; - const DST_HAS_SAFETY_INVARIANTS: Answer = Answer::No(crate::Reason::DstMayHaveSafetyInvariants); - fn is_transmutable(src: &Tree, dst: &Tree, assume_safety: bool) -> crate::Answer { - let src = src.clone(); - let dst = dst.clone(); - // The only dimension of the transmutability analysis we want to test - // here is the safety analysis. To ensure this, we disable all other - // toggleable aspects of the transmutability analysis. - let assume = crate::Assume { - alignment: true, - lifetimes: true, - validity: true, - safety: assume_safety, - }; - crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal) - .answer() - } - #[test] fn src_safe_dst_safe() { let src = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8()); let dst = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8()); - assert_eq!(is_transmutable(&src, &dst, false), Answer::Yes); - assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes); + assert_eq!(is_transmutable(&src, &dst, Assume::default()), Answer::Yes); + assert_eq!( + is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }), + Answer::Yes + ); } #[test] fn src_safe_dst_unsafe() { let src = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8()); let dst = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8()); - assert_eq!(is_transmutable(&src, &dst, false), DST_HAS_SAFETY_INVARIANTS); - assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes); + assert_eq!(is_transmutable(&src, &dst, Assume::default()), DST_HAS_SAFETY_INVARIANTS); + assert_eq!( + is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }), + Answer::Yes + ); } #[test] fn src_unsafe_dst_safe() { let src = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8()); let dst = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8()); - assert_eq!(is_transmutable(&src, &dst, false), Answer::Yes); - assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes); + assert_eq!(is_transmutable(&src, &dst, Assume::default()), Answer::Yes); + assert_eq!( + is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }), + Answer::Yes + ); } #[test] fn src_unsafe_dst_unsafe() { let src = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8()); let dst = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8()); - assert_eq!(is_transmutable(&src, &dst, false), DST_HAS_SAFETY_INVARIANTS); - assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes); + assert_eq!(is_transmutable(&src, &dst, Assume::default()), DST_HAS_SAFETY_INVARIANTS); + assert_eq!( + is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }), + Answer::Yes + ); } } mod bool { use super::*; - use crate::Answer; #[test] fn should_permit_identity_transmutation_tree() { - let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( - layout::Tree::::bool(), - layout::Tree::::bool(), - crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false }, - UltraMinimal, - ) - .answer(); - assert_eq!(answer, Answer::Yes); + let src = Tree::bool(); + assert_eq!(is_transmutable(&src, &src, Assume::default()), Answer::Yes); + assert_eq!( + is_transmutable(&src, &src, Assume { validity: true, ..Assume::default() }), + Answer::Yes + ); } #[test] fn should_permit_identity_transmutation_dfa() { - let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( - layout::Dfa::::bool(), - layout::Dfa::::bool(), - crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false }, - UltraMinimal, - ) - .answer(); - assert_eq!(answer, Answer::Yes); + let src = Dfa::bool(); + assert_eq!(is_transmutable(&src, &src, Assume::default()), Answer::Yes); + assert_eq!( + is_transmutable(&src, &src, Assume { validity: true, ..Assume::default() }), + Answer::Yes + ); } #[test] @@ -122,13 +144,7 @@ mod bool { if src_set.is_subset(&dst_set) { assert_eq!( Answer::Yes, - MaybeTransmutableQuery::new( - src_layout.clone(), - dst_layout.clone(), - crate::Assume { validity: false, ..crate::Assume::default() }, - UltraMinimal, - ) - .answer(), + is_transmutable(&src_layout, &dst_layout, Assume::default()), "{:?} SHOULD be transmutable into {:?}", src_layout, dst_layout @@ -136,13 +152,11 @@ mod bool { } else if !src_set.is_disjoint(&dst_set) { assert_eq!( Answer::Yes, - MaybeTransmutableQuery::new( - src_layout.clone(), - dst_layout.clone(), - crate::Assume { validity: true, ..crate::Assume::default() }, - UltraMinimal, - ) - .answer(), + is_transmutable( + &src_layout, + &dst_layout, + Assume { validity: true, ..Assume::default() } + ), "{:?} SHOULD be transmutable (assuming validity) into {:?}", src_layout, dst_layout @@ -150,13 +164,7 @@ mod bool { } else { assert_eq!( Answer::No(Reason::DstIsBitIncompatible), - MaybeTransmutableQuery::new( - src_layout.clone(), - dst_layout.clone(), - crate::Assume { validity: false, ..crate::Assume::default() }, - UltraMinimal, - ) - .answer(), + is_transmutable(&src_layout, &dst_layout, Assume::default()), "{:?} should NOT be transmutable into {:?}", src_layout, dst_layout From 8b09cbba210741a16bedb60d54b7b06b78021ba8 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 15 Apr 2025 16:27:14 -0400 Subject: [PATCH 216/222] Update cargo * The license exception of sha1_smol with BSD-3-Clause is no longer needed, as `gix-*` doesn't depend on it. * Cargo depends on zlib-rs, which is distributed under Zlib license --- src/tools/cargo | 2 +- src/tools/tidy/src/deps.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/cargo b/src/tools/cargo index 864f74d4eadc..d811228b14ae 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 864f74d4eadcaea3eeda37a2e7f4d34de233d51e +Subproject commit d811228b14ae2707323f37346aee3f4147e247e6 diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 88c2a02798ac..8eca2eb45039 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -132,15 +132,16 @@ const EXCEPTIONS_CARGO: ExceptionList = &[ ("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"), ("foldhash", "Zlib"), ("im-rc", "MPL-2.0+"), + ("libz-rs-sys", "Zlib"), ("normalize-line-endings", "Apache-2.0"), ("openssl", "Apache-2.0"), ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 - ("sha1_smol", "BSD-3-Clause"), ("similar", "Apache-2.0"), ("sized-chunks", "MPL-2.0+"), ("subtle", "BSD-3-Clause"), ("supports-hyperlinks", "Apache-2.0"), ("unicode-bom", "Apache-2.0"), + ("zlib-rs", "Zlib"), // tidy-alphabetical-end ]; From a114bcffe7c6cd4c7cf6dccac0a47ed49894ed2f Mon Sep 17 00:00:00 2001 From: jyn Date: Tue, 15 Apr 2025 17:01:58 -0400 Subject: [PATCH 217/222] document RUSTC_BOOTSTRAP, RUSTC_OVERRIDE_VERSION_STRING, and -Z allow-features in the unstable book --- .../src/compiler-flags/allow-features.md | 14 +++++ .../src/compiler-flags/rustc-bootstrap.md | 56 +++++++++++++++++++ .../rustc-override-version-string.md | 39 +++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/allow-features.md create mode 100644 src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md create mode 100644 src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md diff --git a/src/doc/unstable-book/src/compiler-flags/allow-features.md b/src/doc/unstable-book/src/compiler-flags/allow-features.md new file mode 100644 index 000000000000..84fa465c89b4 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/allow-features.md @@ -0,0 +1,14 @@ +# `allow-features` + +This feature is perma-unstable and has no tracking issue. + +---- + +This flag allows limiting the features which can be enabled with `#![feature(...)]` attributes. +By default, all features are allowed on nightly and no features are allowed on stable or beta (but see [`RUSTC_BOOTSTRAP`]). + +Features are comma-separated, for example `-Z allow-features=ffi_pure,f16`. +If the flag is present, any feature listed will be allowed and any feature not listed will be disallowed. +Any unrecognized feature is ignored. + +[`RUSTC_BOOTSTRAP`]: ./rustc-bootstrap.html diff --git a/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md b/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md new file mode 100644 index 000000000000..6895f2322386 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md @@ -0,0 +1,56 @@ +# `RUSTC_BOOTSTRAP` + +This feature is perma-unstable and has no tracking issue. + +---- + +The `RUSTC_BOOTSTRAP` environment variable tells rustc to act as if it is a nightly compiler; +in particular, it allows `#![feature(...)]` attributes and `-Z` flags even on the stable release channel. + +Setting `RUSTC_BOOTSTRAP=1` instructs rustc to enable this for all crates. +Setting `RUSTC_BOOTSTRAP=crate_name` instructs rustc to only apply this to crates named `crate_name`. +Setting `RUSTC_BOOTSTRAP=-1` instructs rustc to act as if it is a stable compiler, even on the nightly release channel. +Cargo disallows setting `cargo::rustc-env=RUSTC_BOOTSTRAP` in build scripts. +Build systems can limit the features they enable with [`-Z allow-features=feature1,feature2`][Z-allow-features]. +Crates can fully opt out of unstable features by using [`#![forbid(unstable_features)]`][unstable-features] at the crate root (or any other way of enabling lints, such as `-F unstable-features`). + +[Z-allow-features]: ./allow-features.html +[unstable-features]: ../../rustc/lints/listing/allowed-by-default.html#unstable-features + +## Why does this environment variable exist? + +`RUSTC_BOOTSTRAP`, as the name suggests, is used for bootstrapping the compiler from an earlier version. +In particular, nightly is built with beta, and beta is built with stable. +Since the standard library and compiler both use unstable features, `RUSTC_BOOTSTRAP` is required so that we can use the previous version to build them. + +## Why is this environment variable so easy to use for people not in the rust project? + +Originally, `RUSTC_BOOTSTRAP` required passing in a hash of the previous compiler version, to discourage using it for any purpose other than bootstrapping. +That constraint was later relaxed; see for the discussion that happened at that time. + +People have at various times proposed re-adding the technical constraints. +However, doing so is extremely disruptive for several major projects that we very much want to keep using the latest stable toolchain version, such as Firefox, Rust for Linux, and Chromium. +We continue to allow `RUSTC_BOOTSTRAP` until we can come up with an alternative that does not disrupt our largest constituents. + +## Stability policy + +Despite being usable on stable, this is an unstable feature. +Like any other unstable feature, we reserve the right to change or remove this feature in the future, as well as any other unstable feature that it enables. +Using this feature opts you out of the normal stability/backwards compatibility guarantee of stable. + +Although we do not take technical measures to prevent it from being used, we strongly discourage using this feature. +If at all possible, please contribute to stabilizing the features you care about instead of bypassing the Rust project's stability policy. + +For library crates, we especially discourage the use of this feature. +The crates depending on you do not know that you use this feature, have little recourse if it breaks, and can be used in contexts that are hard to predict. + +For libraries that do use this feature, please document the versions you support (including a *maximum* as well as minimum version), and a mechanism to disable it. +If you do not have a mechanism to disable the use of `RUSTC_BOOTSTRAP`, consider removing its use altogether, such that people can only use your library if they are already using a nightly toolchain. +This leaves the choice of whether to opt-out of Rust's stability guarantees up to the end user building their code. + +## History + +- [Allowed without a hash](https://github.com/rust-lang/rust/pull/37265) ([discussion](https://github.com/rust-lang/rust/issues/36548)) +- [Extended to crate names](https://github.com/rust-lang/rust/pull/77802) ([discussion](https://github.com/rust-lang/cargo/issues/7088)) +- [Disallowed for build scripts](https://github.com/rust-lang/cargo/pull/9181) ([discussion](https://github.com/rust-lang/compiler-team/issues/350)) +- [Extended to emulate stable](https://github.com/rust-lang/rust/pull/132993) ([discussion](https://github.com/rust-lang/rust/issues/123404)) diff --git a/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md b/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md new file mode 100644 index 000000000000..3d867b5f7146 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md @@ -0,0 +1,39 @@ +# `RUSTC_OVERRIDE_VERSION_STRING` + +This feature is perma-unstable and has no tracking issue. + +---- + +The `RUSTC_OVERRIDE_VERSION_STRING` environment variable overrides the version reported by `rustc --version`. For example: + +```console +$ rustc --version +rustc 1.87.0-nightly (43f0014ef 2025-03-25) +$ env RUSTC_OVERRIDE_VERSION_STRING=1.81.0-nightly rustc --version +rustc 1.81.0-nightly +``` + +Note that the version string is completely overwritten; i.e. rustc discards commit hash and commit date information unless it is explicitly included in the environment variable. The string only applies to the "release" part of the version; for example: +```console +$ RUSTC_OVERRIDE_VERSION_STRING="1.81.0-nightly (aaaaaaaaa 2025-03-22)" rustc -vV +rustc 1.81.0-nightly (aaaaaaaaa 2025-03-22) +binary: rustc +commit-hash: 43f0014ef0f242418674f49052ed39b70f73bc1c +commit-date: 2025-03-25 +host: x86_64-unknown-linux-gnu +release: 1.81.0-nightly (aaaaaaaaa 2025-03-22) +LLVM version: 20.1.1 +``` + +Note here that `commit-hash` and `commit-date` do not match the values in the string, and `release` includes the fake hash and date. + +This variable has no effect on whether or not unstable features are allowed to be used. It only affects the output of `--version`. + +## Why does this environment variable exist? + +Various library crates have incomplete or incorrect feature detection. +This environment variable allows bisecting crates that do incorrect detection with `version_check::supports_feature`. + +This is not intended to be used for any other case (and, except for bisection, is not particularly useful). + +See for further discussion. From 01178849174bdff3e3e951827d9ea4884c23b758 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Fri, 21 Mar 2025 10:09:17 -0400 Subject: [PATCH 218/222] Move eager translation to a method on `Diag` This will allow us to eagerly translate messages on a top-level diagnostic, such as a `LintDiagnostic`. As a bonus, we can remove the awkward closure passed into Subdiagnostic and make better use of `Into`. --- compiler/rustc_ast_passes/src/errors.rs | 14 +--- compiler/rustc_builtin_macros/src/errors.rs | 10 +-- compiler/rustc_const_eval/src/errors.rs | 10 +-- compiler/rustc_errors/src/diagnostic.rs | 33 ++++---- compiler/rustc_errors/src/diagnostic_impls.rs | 8 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/errors.rs | 32 ++------ compiler/rustc_lint/src/errors.rs | 8 +- compiler/rustc_lint/src/if_let_rescope.rs | 12 +-- compiler/rustc_lint/src/lints.rs | 44 ++--------- .../src/diagnostics/subdiagnostic.rs | 15 +--- compiler/rustc_mir_build/src/errors.rs | 20 +---- .../src/lint_tail_expr_drop_order.rs | 16 ++-- compiler/rustc_parse/src/errors.rs | 9 +-- compiler/rustc_passes/src/errors.rs | 8 +- compiler/rustc_pattern_analysis/src/errors.rs | 14 +--- compiler/rustc_trait_selection/src/errors.rs | 78 ++++--------------- .../src/errors/note_and_explain.rs | 10 +-- .../ui-fulldeps/internal-lints/diagnostics.rs | 8 +- .../internal-lints/diagnostics.stderr | 18 ++--- 20 files changed, 98 insertions(+), 271 deletions(-) diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 8e53e600f7ac..bd139e2eb3f1 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -2,7 +2,7 @@ use rustc_ast::ParamKindOrd; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -394,11 +394,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec); // The derive for `Vec` does multiple calls to `span_label`, adding commas between each impl Subdiagnostic for EmptyLabelManySpans { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.0, ""); } } @@ -749,11 +745,7 @@ pub(crate) struct StableFeature { } impl Subdiagnostic for StableFeature { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("name", self.name); diag.arg("since", self.since); diag.help(fluent::ast_passes_stable_since); diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index c2b1dff4cf1f..d14ad8f40144 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,7 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans, - SubdiagMessageOp, Subdiagnostic, + Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -684,13 +684,9 @@ pub(crate) struct FormatUnusedArg { // Allow the singular form to be a subdiagnostic of the multiple-unused // form of diagnostic. impl Subdiagnostic for FormatUnusedArg { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("named", self.named); - let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); + let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg); diag.span_label(self.span, msg); } } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index e2675e2f4c90..6472aaa57581 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -6,7 +6,7 @@ use rustc_abi::WrappingRange; use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, + MultiSpan, Subdiagnostic, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -290,11 +290,7 @@ pub struct FrameNote { } impl Subdiagnostic for FrameNote { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("times", self.times); diag.arg("where_", self.where_); diag.arg("instance", self.instance); @@ -302,7 +298,7 @@ impl Subdiagnostic for FrameNote { if self.has_label && !self.span.is_dummy() { span.push_span_label(self.span, fluent::const_eval_frame_note_last); } - let msg = f(diag, fluent::const_eval_frame_note.into()); + let msg = diag.eagerly_translate(fluent::const_eval_frame_note); diag.span_note(span, msg); } } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index bd13c413a4df..539ecfbb42e2 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -181,22 +181,9 @@ where Self: Sized, { /// Add a subdiagnostic to an existing diagnostic. - fn add_to_diag(self, diag: &mut Diag<'_, G>) { - self.add_to_diag_with(diag, &|_, m| m); - } - - /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used - /// (to optionally perform eager translation). - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ); + fn add_to_diag(self, diag: &mut Diag<'_, G>); } -pub trait SubdiagMessageOp = - Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage; - /// Trait implemented by lint types. This should not be implemented manually. Instead, use /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. #[rustc_diagnostic_item = "LintDiagnostic"] @@ -1227,15 +1214,21 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// interpolated variables). #[rustc_lint_diagnostics] pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self { - let dcx = self.dcx; - subdiagnostic.add_to_diag_with(self, &|diag, msg| { - let args = diag.args.iter(); - let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); - dcx.eagerly_translate(msg, args) - }); + subdiagnostic.add_to_diag(self); self } + /// Fluent variables are not namespaced from each other, so when + /// `Diagnostic`s and `Subdiagnostic`s use the same variable name, + /// one value will clobber the other. Eagerly translating the + /// diagnostic uses the variables defined right then, before the + /// clobbering occurs. + pub fn eagerly_translate(&self, msg: impl Into) -> SubdiagMessage { + let args = self.args.iter(); + let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into()); + self.dcx.eagerly_translate(msg, args) + } + with_fn! { with_span, /// Add a span. #[rustc_lint_diagnostics] diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index cb2e1769fa1c..8b59ba9984c1 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -19,7 +19,7 @@ use {rustc_ast as ast, rustc_hir as hir}; use crate::diagnostic::DiagLocation; use crate::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level, - SubdiagMessageOp, Subdiagnostic, fluent_generated as fluent, + Subdiagnostic, fluent_generated as fluent, }; pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display); @@ -384,11 +384,7 @@ pub struct SingleLabelManySpans { pub label: &'static str, } impl Subdiagnostic for SingleLabelManySpans { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.spans, self.label); } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 75bb0e8e7b43..c0c5dba46772 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -47,7 +47,7 @@ pub use codes::*; pub use diagnostic::{ BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag, - SubdiagMessageOp, Subdiagnostic, + Subdiagnostic, }; pub use diagnostic_impls::{ DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index dfaa374592bc..9e7305430e5f 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan, - SubdiagMessageOp, Subdiagnostic, + Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -270,11 +270,7 @@ pub(crate) struct SuggestAnnotations { pub suggestions: Vec, } impl Subdiagnostic for SuggestAnnotations { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { if self.suggestions.is_empty() { return; } @@ -337,11 +333,7 @@ pub(crate) struct TypeMismatchFruTypo { } impl Subdiagnostic for TypeMismatchFruTypo { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("expr", self.expr.as_deref().unwrap_or("NONE")); // Only explain that `a ..b` is a range if it's split up @@ -599,11 +591,7 @@ pub(crate) struct RemoveSemiForCoerce { } impl Subdiagnostic for RemoveSemiForCoerce { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multispan: MultiSpan = self.semi.into(); multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr); multispan.push_span_label(self.ret, fluent::hir_typeck_remove_semi_for_coerce_ret); @@ -778,20 +766,16 @@ pub(crate) enum CastUnknownPointerSub { } impl rustc_errors::Subdiagnostic for CastUnknownPointerSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { CastUnknownPointerSub::To(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_to); + let msg = diag.eagerly_translate(fluent::hir_typeck_label_to); diag.span_label(span, msg); - let msg = f(diag, crate::fluent_generated::hir_typeck_note); + let msg = diag.eagerly_translate(fluent::hir_typeck_note); diag.note(msg); } CastUnknownPointerSub::From(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_from); + let msg = diag.eagerly_translate(fluent::hir_typeck_label_from); diag.span_label(span, msg); } } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index d109a5c90305..586e55c8055c 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::codes::*; -use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; @@ -26,11 +26,7 @@ pub(crate) enum OverruledAttributeSub { } impl Subdiagnostic for OverruledAttributeSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { OverruledAttributeSub::DefaultSource { id } => { diag.note(fluent::lint_default_source); diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 39ea8d8e3246..a9b04511c6b4 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -3,9 +3,7 @@ use std::ops::ControlFlow; use hir::intravisit::{self, Visitor}; use rustc_ast::Recovered; -use rustc_errors::{ - Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, -}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle}; use rustc_hir::{self as hir, HirIdSet}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::adjustment::Adjust; @@ -327,11 +325,7 @@ struct IfLetRescopeRewrite { } impl Subdiagnostic for IfLetRescopeRewrite { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut suggestions = vec![]; for match_head in self.match_heads { match match_head { @@ -360,7 +354,7 @@ impl Subdiagnostic for IfLetRescopeRewrite { .chain(repeat('}').take(closing_brackets.count)) .collect(), )); - let msg = f(diag, crate::fluent_generated::lint_suggestion); + let msg = diag.eagerly_translate(crate::fluent_generated::lint_suggestion); diag.multipart_suggestion_with_style( msg, suggestions, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 51214c8e8a4c..8ab64fbd127a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -6,7 +6,7 @@ use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, - EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, + EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle, }; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; @@ -449,11 +449,7 @@ pub(crate) struct BuiltinUnpermittedTypeInitSub { } impl Subdiagnostic for BuiltinUnpermittedTypeInitSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut err = self.err; loop { if let Some(span) = err.span { @@ -504,11 +500,7 @@ pub(crate) struct BuiltinClashingExternSub<'a> { } impl Subdiagnostic for BuiltinClashingExternSub<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut expected_str = DiagStyledString::new(); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); let mut found_str = DiagStyledString::new(); @@ -824,11 +816,7 @@ pub(crate) struct HiddenUnicodeCodepointsDiagLabels { } impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { for (c, span) in self.spans { diag.span_label(span, format!("{c:?}")); } @@ -842,11 +830,7 @@ pub(crate) enum HiddenUnicodeCodepointsDiagSub { // Used because of multiple multipart_suggestion and note impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { diag.multipart_suggestion_with_style( @@ -1015,11 +999,7 @@ pub(crate) struct NonBindingLetSub { } impl Subdiagnostic for NonBindingLetSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar; if can_suggest_binding { @@ -1303,11 +1283,7 @@ pub(crate) enum NonSnakeCaseDiagSub { } impl Subdiagnostic for NonSnakeCaseDiagSub { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { NonSnakeCaseDiagSub::Label { span } => { diag.span_label(span, fluent::lint_label); @@ -1629,11 +1605,7 @@ pub(crate) enum OverflowingBinHexSign { } impl Subdiagnostic for OverflowingBinHexSign { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { OverflowingBinHexSign::Positive => { diag.note(fluent::lint_positive_note); diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 909083d5e865..bc9516b2e0c6 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -20,14 +20,12 @@ use crate::diagnostics::utils::{ /// The central struct for constructing the `add_to_diag` method from an annotated struct. pub(crate) struct SubdiagnosticDerive { diag: syn::Ident, - f: syn::Ident, } impl SubdiagnosticDerive { pub(crate) fn new() -> Self { let diag = format_ident!("diag"); - let f = format_ident!("f"); - Self { diag, f } + Self { diag } } pub(crate) fn into_tokens(self, mut structure: Structure<'_>) -> TokenStream { @@ -86,19 +84,16 @@ impl SubdiagnosticDerive { }; let diag = &self.diag; - let f = &self.f; // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? #[allow(keyword_idents_2024)] let ret = structure.gen_impl(quote! { gen impl rustc_errors::Subdiagnostic for @Self { - fn add_to_diag_with<__G, __F>( + fn add_to_diag<__G>( self, #diag: &mut rustc_errors::Diag<'_, __G>, - #f: &__F ) where __G: rustc_errors::EmissionGuarantee, - __F: rustc_errors::SubdiagMessageOp<__G>, { #implementation } @@ -384,11 +379,10 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { Ok(quote! {}) } "subdiagnostic" => { - let f = &self.parent.f; let diag = &self.parent.diag; let binding = &info.binding; self.has_subdiagnostic = true; - Ok(quote! { #binding.add_to_diag_with(#diag, #f); }) + Ok(quote! { #binding.add_to_diag(#diag); }) } _ => { let mut span_attrs = vec![]; @@ -531,12 +525,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let span_field = self.span_field.value_ref(); let diag = &self.parent.diag; - let f = &self.parent.f; let mut calls = TokenStream::new(); for (kind, slug, no_span) in kind_slugs { let message = format_ident!("__message"); calls.extend( - quote! { let #message = #f(#diag, crate::fluent_generated::#slug.into()); }, + quote! { let #message = #diag.eagerly_translate(crate::fluent_generated::#slug); }, ); let name = format_ident!( diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 0e16f871b16f..ae09db502352 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, pluralize, + MultiSpan, Subdiagnostic, pluralize, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -546,11 +546,7 @@ pub(crate) struct UnsafeNotInheritedLintNote { } impl Subdiagnostic for UnsafeNotInheritedLintNote { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body); let body_start = self.body_span.shrink_to_lo(); let body_end = self.body_span.shrink_to_hi(); @@ -1031,11 +1027,7 @@ pub(crate) struct Variant { } impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); @@ -1117,11 +1109,7 @@ pub(crate) struct Rust2024IncompatiblePatSugg { } impl Subdiagnostic for Rust2024IncompatiblePatSugg { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { // Format and emit explanatory notes about default binding modes. Reversing the spans' order // means if we have nested spans, the innermost ones will be visited first. for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() { diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 29a9133abe93..537f152938ef 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -512,23 +512,17 @@ struct LocalLabel<'a> { /// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order impl Subdiagnostic for LocalLabel<'_> { - fn add_to_diag_with< - G: rustc_errors::EmissionGuarantee, - F: rustc_errors::SubdiagMessageOp, - >( - self, - diag: &mut rustc_errors::Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut rustc_errors::Diag<'_, G>) { diag.arg("name", self.name); diag.arg("is_generated_name", self.is_generated_name); diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024); - let msg = f(diag, crate::fluent_generated::mir_transform_tail_expr_local.into()); + let msg = diag.eagerly_translate(crate::fluent_generated::mir_transform_tail_expr_local); diag.span_label(self.span, msg); for dtor in self.destructors { - dtor.add_to_diag_with(diag, f); + dtor.add_to_diag(diag); } - let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue); + let msg = + diag.eagerly_translate(crate::fluent_generated::mir_transform_label_local_epilogue); diag.span_label(self.span, msg); } } diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index dfdef018bc37..57534bc8c318 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -7,8 +7,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{Path, Visibility}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp, - Subdiagnostic, + Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; @@ -1551,11 +1550,7 @@ pub(crate) struct FnTraitMissingParen { } impl Subdiagnostic for FnTraitMissingParen { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren); diag.span_suggestion_short( self.span.shrink_to_hi(), diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 85eddafefcd5..995fc85676e8 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -5,7 +5,7 @@ use rustc_ast::Label; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, + MultiSpan, Subdiagnostic, }; use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -1852,11 +1852,7 @@ pub(crate) struct UnusedVariableStringInterp { } impl Subdiagnostic for UnusedVariableStringInterp { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation); diag.multipart_suggestion( crate::fluent_generated::passes_string_interpolation_only_works, diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 1f7852e5190d..e60930d6cd21 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -55,11 +55,7 @@ pub struct Overlap { } impl Subdiagnostic for Overlap { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let Overlap { span, range } = self; // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` @@ -103,11 +99,7 @@ pub struct GappedRange { } impl Subdiagnostic for GappedRange { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let GappedRange { span, gap, first_range } = self; // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 4e5581fb1da0..756d9a57b935 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, - EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, + EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -107,11 +107,7 @@ pub enum AdjustSignatureBorrow { } impl Subdiagnostic for AdjustSignatureBorrow { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { AdjustSignatureBorrow::Borrow { to_borrow } => { diag.arg("len", to_borrow.len()); @@ -381,11 +377,7 @@ pub enum RegionOriginNote<'a> { } impl Subdiagnostic for RegionOriginNote<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut label_or_note = |span, msg: DiagMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); @@ -446,11 +438,7 @@ pub enum LifetimeMismatchLabels { } impl Subdiagnostic for LifetimeMismatchLabels { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { diag.span_label(param_span, fluent::trait_selection_declared_different); @@ -495,11 +483,7 @@ pub struct AddLifetimeParamsSuggestion<'a> { } impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut mk_suggestion = || { let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) else { @@ -689,11 +673,7 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq { } impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diag_with>( - mut self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { self.unmet_requirements .push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static); diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req); @@ -1008,17 +988,13 @@ pub struct ConsiderBorrowingParamHelp { } impl Subdiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { // Seems like we can't call f() here as Into is required type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing); } - let msg = f(diag, fluent::trait_selection_tid_param_help.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_tid_param_help); diag.span_help(type_param_span, msg); } } @@ -1053,18 +1029,14 @@ pub struct DynTraitConstraintSuggestion { } impl Subdiagnostic for DynTraitConstraintSuggestion { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label); multi_span .push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement); - let msg = f(diag, fluent::trait_selection_dtcs_has_req_note.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_has_req_note); diag.span_note(multi_span, msg); - let msg = f(diag, fluent::trait_selection_dtcs_suggestion.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_suggestion); diag.span_suggestion_verbose( self.span.shrink_to_hi(), msg, @@ -1101,11 +1073,7 @@ pub struct ReqIntroducedLocations { } impl Subdiagnostic for ReqIntroducedLocations { - fn add_to_diag_with>( - mut self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { for sp in self.spans { self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here); } @@ -1114,7 +1082,7 @@ impl Subdiagnostic for ReqIntroducedLocations { self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by); } self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of); - let msg = f(diag, fluent::trait_selection_ril_static_introduced_by.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_ril_static_introduced_by); diag.span_note(self.span, msg); } } @@ -1513,13 +1481,9 @@ pub struct SuggestTuplePatternMany { } impl Subdiagnostic for SuggestTuplePatternMany { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("path", self.path); - let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into()); + let message = diag.eagerly_translate(fluent::trait_selection_stp_wrap_many); diag.multipart_suggestions( message, self.compatible_variants.into_iter().map(|variant| { @@ -1752,11 +1716,7 @@ pub struct AddPreciseCapturingAndParams { } impl Subdiagnostic for AddPreciseCapturingAndParams { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("new_lifetime", self.new_lifetime); diag.multipart_suggestion_verbose( fluent::trait_selection_precise_capturing_new_but_apit, @@ -1896,11 +1856,7 @@ pub struct AddPreciseCapturingForOvercapture { } impl Subdiagnostic for AddPreciseCapturingForOvercapture { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let applicability = if self.apit_spans.is_empty() { Applicability::MachineApplicable } else { diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index e4ab78b62477..84e7686fdd3f 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic}; use rustc_hir::def_id::LocalDefId; use rustc_middle::bug; use rustc_middle::ty::{self, TyCtxt}; @@ -162,17 +162,13 @@ impl RegionExplanation<'_> { } impl Subdiagnostic for RegionExplanation<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diag.arg("desc_kind", self.desc.kind); diag.arg("desc_arg", self.desc.arg); - let msg = f(diag, fluent::trait_selection_region_explanation.into()); + let msg = diag.eagerly_translate(fluent::trait_selection_region_explanation); if let Some(span) = self.desc.span { diag.span_note(span, msg); } else { diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 442f9d72c3f1..1238fefd5bc0 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -15,7 +15,7 @@ extern crate rustc_span; use rustc_errors::{ Diag, DiagCtxtHandle, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level, - LintDiagnostic, SubdiagMessage, SubdiagMessageOp, Subdiagnostic, + LintDiagnostic, SubdiagMessage, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -56,10 +56,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for TranslatableInDiagnostic { pub struct UntranslatableInAddtoDiag; impl Subdiagnostic for UntranslatableInAddtoDiag { - fn add_to_diag_with>( + fn add_to_diag( self, diag: &mut Diag<'_, G>, - f: &F, ) { diag.note("untranslatable diagnostic"); //~^ ERROR diagnostics should be created using translatable messages @@ -69,10 +68,9 @@ impl Subdiagnostic for UntranslatableInAddtoDiag { pub struct TranslatableInAddtoDiag; impl Subdiagnostic for TranslatableInAddtoDiag { - fn add_to_diag_with>( + fn add_to_diag( self, diag: &mut Diag<'_, G>, - f: &F, ) { diag.note(crate::fluent_generated::no_crate_note); } diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr index 36dd3cf4be79..b260c4b7afef 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr @@ -11,19 +11,19 @@ LL | #![deny(rustc::untranslatable_diagnostic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:64:19 + --> $DIR/diagnostics.rs:63:19 | LL | diag.note("untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:85:19 + --> $DIR/diagnostics.rs:83:19 | LL | diag.note("untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls - --> $DIR/diagnostics.rs:99:21 + --> $DIR/diagnostics.rs:97:21 | LL | let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example); | ^^^^^^^^^^ @@ -35,37 +35,37 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls - --> $DIR/diagnostics.rs:102:21 + --> $DIR/diagnostics.rs:100:21 | LL | let _diag = dcx.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:102:32 + --> $DIR/diagnostics.rs:100:32 | LL | let _diag = dcx.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:120:7 + --> $DIR/diagnostics.rs:118:7 | LL | f("untranslatable diagnostic", crate::fluent_generated::no_crate_example); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:122:50 + --> $DIR/diagnostics.rs:120:50 | LL | f(crate::fluent_generated::no_crate_example, "untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:124:7 + --> $DIR/diagnostics.rs:122:7 | LL | f("untranslatable diagnostic", "untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:124:36 + --> $DIR/diagnostics.rs:122:36 | LL | f("untranslatable diagnostic", "untranslatable diagnostic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 5636312c71e3e4eb7f1afc3e945bd7dc11697d4c Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 17 Apr 2025 11:50:24 +0800 Subject: [PATCH 219/222] git: ignore `60600a6fa403216bfd66e04f948b1822f6450af7` for blame purposes It was simply breaking up compiletest's `runtest.rs` and isn't very useful in git blame. --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d2a017bd2a02..af071c706856 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -31,3 +31,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8 c682aa162b0d41e21cc6748f4fecfe01efb69d1f # reformat with updated edition 2024 1fcae03369abb4c2cc180cd5a49e1f4440a81300 +# Breaking up of compiletest runtest.rs +60600a6fa403216bfd66e04f948b1822f6450af7 From edb3aaf655f1a7a766c5d37eacbf7931c087130b Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 17 Apr 2025 17:50:48 +0000 Subject: [PATCH 220/222] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index d1107e515090..ed2e4474adda 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -1bc56185ee257ed829a0aea7abdc3b03c5fed887 +883f9f72e87ccb6838d528d8158ea6323baacc65 From 11f7290c9f9122c5f2c47802c1883b2a0a04aed9 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 Jan 2025 13:49:28 -0600 Subject: [PATCH 221/222] refactor(test): Decouple parsing from help generation This will help with hiding some options in `--help` --- library/test/src/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index ef6786f43167..b532bfbea4d7 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -210,7 +210,7 @@ pub fn parse_opts(args: &[String]) -> Option { // Check if help was requested. if matches.opt_present("h") { // Show help and do nothing more. - usage(binary, &opts); + usage(binary, &optgroups()); return None; } From aa8670f6f81dac097d24277e7559ce5abf5d5183 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 Jan 2025 14:04:49 -0600 Subject: [PATCH 222/222] fix(test): Expose '--no-capture', deprecating '--nocapture' This improves consistency with commonly expected CLI conventions, avoiding a common stutter people make when running tests (trying what they expect and then having to check the docs to then user whats accepted). An alternative could have been to take a value, like `--capture ` (e.g. `pytest` does this). Overall, we're shifting focus for features to custom test harnesses (see #134283). Most of `pytest`s modes will likely be irrelevant in that situation. As for the rest, its too early to tell which, if any, may be relevant, so we're sticking with this small, quality of life improvement. By deprecating `--nocapture`, we intend that custom test harnesses do not need to support it for reasons outside of their own compatibility requirements, much like the deprecation in #134283 I'm punting for now on the naming of `RUST_TEST_NOCAPTURE`. I feel like T-testing-devex should do a wider look at environment variables role in lib`test` before evaluating whether to - Deprecate it in favor of the user passing CLI flags or the test runner providing its own config - Deprecate in favor of `RUST_TEST_NO_CAPTURE` - Deprecate in favor of `RUST_TEST_CAPTURE` Other CLI flags were evaluated for casing consistency: - `--logfile` has the same problem but was deprecated in #134283 Fixes #133073 --- library/test/src/cli.rs | 11 +++++++---- src/doc/rustc/src/tests/index.md | 10 ++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index b532bfbea4d7..8840714a6623 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -61,7 +61,7 @@ fn optgroups() -> getopts::Options { .optopt("", "logfile", "Write logs to the specified file (deprecated)", "PATH") .optflag( "", - "nocapture", + "no-capture", "don't capture stdout/stderr of each \ task, allow printing directly", ) @@ -172,7 +172,7 @@ tests in the same order again. Note that --shuffle and --shuffle-seed do not affect whether the tests are run in parallel. All tests have their standard output and standard error captured by default. -This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE +This can be overridden with the --no-capture flag or setting RUST_TEST_NOCAPTURE environment variable to a value other than "0". Logging is not captured by default. Test Attributes: @@ -199,7 +199,10 @@ Test Attributes: /// otherwise creates a `TestOpts` object and returns it. pub fn parse_opts(args: &[String]) -> Option { // Parse matches. - let opts = optgroups(); + let mut opts = optgroups(); + // Flags hidden from `usage` + opts.optflag("", "nocapture", "Deprecated, use `--no-capture`"); + let binary = args.first().map(|c| &**c).unwrap_or("..."); let args = args.get(1..).unwrap_or(args); let matches = match opts.parse(args) { @@ -447,7 +450,7 @@ fn get_color_config(matches: &getopts::Matches) -> OptPartRes { } fn get_nocapture(matches: &getopts::Matches) -> OptPartRes { - let mut nocapture = matches.opt_present("nocapture"); + let mut nocapture = matches.opt_present("nocapture") || matches.opt_present("no-capture"); if !nocapture { nocapture = match env::var("RUST_TEST_NOCAPTURE") { Ok(val) => &val != "0", diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md index d2026513d2f0..12de69a4c9ee 100644 --- a/src/doc/rustc/src/tests/index.md +++ b/src/doc/rustc/src/tests/index.md @@ -81,7 +81,7 @@ behavior. > Note: When running with [`cargo test`], the libtest CLI arguments must be > passed after the `--` argument to differentiate between flags for Cargo and -> those for the harness. For example: `cargo test -- --nocapture` +> those for the harness. For example: `cargo test -- --no-capture` ### Filters @@ -225,7 +225,7 @@ The following options affect the output behavior. Displays one character per test instead of one line per test. This is an alias for [`--format=terse`](#--format-format). -#### `--nocapture` +#### `--no-capture` Does not capture the stdout and stderr of the test, and allows tests to print to the console. Usually the output is captured, and only displayed if the test @@ -234,11 +234,13 @@ fails. This may also be specified by setting the `RUST_TEST_NOCAPTURE` environment variable to anything but `0`. +`--nocapture` is a deprecated alias for `--no-capture`. + #### `--show-output` Displays the stdout and stderr of successful tests after all tests have run. -Contrast this with [`--nocapture`](#--nocapture) which allows tests to print +Contrast this with [`--no-capture`](#--no-capture) which allows tests to print *while they are running*, which can cause interleaved output if there are multiple tests running in parallel, `--show-output` ensures the output is contiguous, but requires waiting for all tests to finish. @@ -247,7 +249,7 @@ contiguous, but requires waiting for all tests to finish. Control when colored terminal output is used. Valid options: -* `auto`: Colorize if stdout is a tty and [`--nocapture`](#--nocapture) is not +* `auto`: Colorize if stdout is a tty and [`--no-capture`](#--no-capture) is not used. This is the default. * `always`: Always colorize the output. * `never`: Never colorize the output.