From 1e4cab77adc1f10e8b2a74a898d3cce030011298 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Tue, 15 Sep 2026 04:32:00 -0500 Subject: [PATCH 01/71] update debuginfo testing information w/ GDB changes --- .../rustc-dev-guide/src/debuginfo/testing.md | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/testing.md b/src/doc/rustc-dev-guide/src/debuginfo/testing.md index bcbe960034b02..5b80c42afc3de 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/testing.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/testing.md @@ -36,9 +36,8 @@ To help remedy this: # The `repr` directive > [!IMPORTANT] -> As of July 2026, this command is only supported by LLDB. GDB support is planned, but -> has not been implemented. It is unclear whether this directive will ever be suited for use with -> CDB. +> As of September 2026, this command is only supported for LLDB and GDB. +> It is unclear whether this directive will ever be suited for use with CDB. In short, `$DEBUGGER-repr` commands are desugared to: @@ -53,7 +52,7 @@ and runs special logic on them, testing against data stored in "Target groups" cover the set of targets where we cannot guarantee identical output. Those targets are defined by the - [`Target` enum in `common.py`](https://github.com/rust-lang/rust/blob/bf9944f0b8006b152ef4d5f408ae75a0dde3d044/src/etc/lldb_batchmode/common.py#L54). + [`Target` enum in `common.py`](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py#L54). As of Jul 2026, this list includes `non_windows`, `windows_gnu`, and `windows_msvc`. It is intentionally kept as short as possible, since each target is a new set of test data that must be updated when changes are made. @@ -66,7 +65,7 @@ invocation (e.g. `./x test tests/debuginfo/basic-types/main.rs --bless`). and if no errors occur, saves the data back to the target file (or creates a new file if necessary). The schema of the input data is defined by the classes in -[`common.py`](https://github.com/rust-lang/rust/blob/be3d26db984c6f96335faca1f254dc04873cb1c1/src/etc/lldb_batchmode/common.py). +[`common.py`](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py). The top-level container is `TargetData`. This schema is identical for all debuggers. @@ -98,6 +97,13 @@ as well (e.g. if you are on a Windows machine, bless once for `x86_64-pc-windows ## Implementation +Many of the details of the implementation are shared between LLDB and GDB, +and live in `src/etc/debugger_tester/common.py`. +Notably, LLDB's batch execution features execute commands without waiting for breakpoints to be reached, +making it generally unsuited for our purposes. +As such, `debugger_tester/lldb/lldb_batchmode.py` simulates GDB's batchmode behavior by manually +invoking the test script's commands via `lldb.SBDebugger` and `lldb.SBCommandInterpreter` objects. + ### Ser/De `TargetData` is converted to a dictionary with `dataclasses.asdict`, and is serialized with Python's @@ -108,7 +114,7 @@ The current deserialization logic should be resilient to changes in the schema, but requires that all fields contain ONLY types that can be directly serialized/deserialized by `json.dumps`. The acceptable types are those that make up -[`common.JsonType`](https://github.com/rust-lang/rust/blob/bf9944f0b8006b152ef4d5f408ae75a0dde3d044/src/etc/lldb_batchmode/common.py#L17) +[`common.JsonType`](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py#L17) Since the serialization/deserialization is decoupled from the debugger logic, we can easily switch to an alternative format if we find a better alternative to json. @@ -117,11 +123,11 @@ The conversion logic from the debugger's internal representation to our schema c `from_$DEBUGGER.py`. Once imported, `common` automatically deserializes any existing input data and [stores it in the -global variable `INPUT_DATA`](https://github.com/rust-lang/rust/blob/bf9944f0b8006b152ef4d5f408ae75a0dde3d044/src/etc/lldb_batchmode/common.py#L523). +global variable `INPUT_DATA`](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py#L601). This data is what we test against. > [!NOTE] -> Special care was taken to prevent `lldb_batchmode` from importing `common` unless a `repr` command +> Special care was taken to prevent `debugger_tester` from importing `common` unless a `repr` command > was actually processed. This saves us from reading/writing input data for tests that don't need > it. @@ -140,18 +146,27 @@ to help in diagnosing issues that may occur due to Python or the debugger changi ### Entry point and `--bless` -Upon encountering a `repr` pseudo-command, `lldb_batchmode.main` dispatches to -`check_$DEBUGGER.check()`. +* GDB: Upon import, the `repr` command is registered via the Python API in +[`debugger_tester/gdb/gdb_commands.py](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/gdb/gdb_commands.py). +`ReprCommand.invoke` initiates the check logic with the given variable, and handles top-level error reporting. + +* LLDB: Upon encountering a `repr` pseudo-command, `lldb_batchmode.main` dispatches to `check_lldb.check()`. + +> [!Note] +> LLDB also supports registering +> [custom CLI commands via the Python API](https://lldb.llvm.org/use/tutorials/writing-custom-commands.html). +> In the future, LLDB's `repr` logic may be refactored to behave more similarly to GDB's. + If the `--bless` option was specified, the variable is converted from the in-memory representation to our equivalent schema class. This includes the variable's type, visualizers, children, the children's types, etc. Once inserted into `TargetData`, -the variable is tested against the data that was just saved to `TargetData`. +the debugger's variable object is sanity-tested against the data that was just added to `TargetData`. If no exception or errors occurred and the `--bless` option was specified, `INPUT_DATA` is written -to the appropriate file just before `lldb_batchmode` exits. -If errors occur, `INPUT_DATA` is simply discarded. +to the appropriate file just before `debugger_tester` exits. +If errors occur, the blessed data is simply discarded. Currently, the `repr` pseudo-command is checked for directly. GDB and LLDB both support creating custom CLI commands via Python code. @@ -170,7 +185,7 @@ to provide more useful error messages. For example, LLDB can be a bit coy when it comes to reporting errors that occur within synthetic/summary provider calls. This is especially true when running the command within another -command, as the tests do by calling `script import lldb_batchmode; lldb_batchmode.main()` and +command, as the tests do by calling `script import debugger_tester; debugger_tester.main()` and executing commands in that context. When we encounter an error, we can import the appropriate summary provider, pass the variable object @@ -186,7 +201,7 @@ We absolutely do not want people accidentally blessing bad data purely because the first error happened to be an expected change. Errors are printed directly to `stdout` to appear as visible output from the `repr` pseudo command. -There are [several error helper functions](https://github.com/rust-lang/rust/blob/e7b595554e664e6bd281c8cf881093d6c71bc0e1/src/etc/lldb_batchmode/common.py#L35-L51) +There are [several error helper functions](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py#L35-L51) to keep formatting consistent. > [!NOTE] @@ -198,7 +213,7 @@ to keep formatting consistent. If no errors occurred for a given variable, `$VAR_NAME ok` is printed to `stdout` for `compiletest` to match against. -Before `lldb_batchmode` exits, one last check is done to ensure that all the types and variables +Before `debugger_tester` exits, one last check is done to ensure that all the types and variables that were present in `INPUT_DATA` have been checked against. If this check fails, the script reports the untested types/variables and exits with an error code. From 4778ae5040c10568d98e9bff8283057d9cd8ac3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 23 Sep 2026 14:09:50 +0200 Subject: [PATCH 02/71] Mark `rustfmt` as being managed by Josh --- src/doc/rustc-dev-guide/src/external-repos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 26c7e2e02bd56..fe0c0385d5f63 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -42,13 +42,13 @@ you should include fixes for those in the rustc PR as well. * Using `git subtree` * `clippy` ([sync guide](https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html#performing-the-sync-from-rust-langrust-to-clippy)) * `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh)) - * `rustfmt` * `rustc_codegen_gcc` ([sync guide](https://github.com/rust-lang/rustc_codegen_gcc/blob/master/doc/subtree.md)) * Using the [josh](#synchronizing-a-josh-subtree) tool * `miri` * `rust-analyzer` * `rustc_codegen_cranelift` * `rustc-dev-guide` + * `rustfmt` * `compiler-builtins` * `stdarch` From dc39f011b8ebb2ee32511de7ffca1b47ad3454fd Mon Sep 17 00:00:00 2001 From: eleocraft Date: Thu, 24 Sep 2026 05:01:45 +0200 Subject: [PATCH 03/71] making clamp_magnitude functions const + adding clamp_magnitude to NonZero --- library/core/src/num/f128.rs | 5 ++-- library/core/src/num/f16.rs | 5 ++-- library/core/src/num/f32.rs | 6 ++--- library/core/src/num/f64.rs | 6 ++--- library/core/src/num/int_macros.rs | 7 ++--- library/core/src/num/nonzero.rs | 26 +++++++++++++++++++ .../coretests/tests/num/clamp_magnitude.rs | 8 +++--- 7 files changed, 46 insertions(+), 17 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index db05d7fdc5087..e53e4df1ea43d 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1544,9 +1544,10 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "clamp_magnitude", issue = "148519")] - #[must_use = "this returns the clamped value and does not modify the original"] + #[rustc_const_unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "method returns a new number and does not mutate the original value"] #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] - pub fn clamp_magnitude(self, limit: f128) -> f128 { + pub const fn clamp_magnitude(self, limit: f128) -> f128 { assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 273ef3688ca5f..4ad41bd6cfa4b 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1530,9 +1530,10 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "clamp_magnitude", issue = "148519")] - #[must_use = "this returns the clamped value and does not modify the original"] + #[rustc_const_unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "method returns a new number and does not mutate the original value"] #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] - pub fn clamp_magnitude(self, limit: f16) -> f16 { + pub const fn clamp_magnitude(self, limit: f16) -> f16 { assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index d3dea38dc2fcf..2dc3ddf31cac5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1699,11 +1699,11 @@ impl f32 { /// assert_eq!(2.0f32.clamp_magnitude(3.0), 2.0); /// assert_eq!((-2.0f32).clamp_magnitude(3.0), -2.0); /// ``` - #[must_use = "this returns the clamped value and does not modify the original"] - #[unstable(feature = "clamp_magnitude", issue = "148519")] #[inline] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "method returns a new number and does not mutate the original value"] #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] - pub fn clamp_magnitude(self, limit: f32) -> f32 { + pub const fn clamp_magnitude(self, limit: f32) -> f32 { assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 7c5082749cd11..cd3cfe1bd4c60 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1677,11 +1677,11 @@ impl f64 { /// assert_eq!(2.0f64.clamp_magnitude(3.0), 2.0); /// assert_eq!((-2.0f64).clamp_magnitude(3.0), -2.0); /// ``` - #[must_use = "this returns the clamped value and does not modify the original"] - #[unstable(feature = "clamp_magnitude", issue = "148519")] #[inline] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "method returns a new number and does not mutate the original value"] #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] - pub fn clamp_magnitude(self, limit: f64) -> f64 { + pub const fn clamp_magnitude(self, limit: f64) -> f64 { assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index bb37a734824fa..2328fb1e03a31 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3968,10 +3968,11 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(80", stringify!($SelfT), ".clamp_magnitude(100), 80);")] #[doc = concat!("assert_eq!(-80", stringify!($SelfT), ".clamp_magnitude(100), -80);")] /// ``` - #[must_use = "this returns the clamped value and does not modify the original"] - #[unstable(feature = "clamp_magnitude", issue = "148519")] #[inline] - pub fn clamp_magnitude(self, limit: $UnsignedT) -> Self { + #[must_use = "method returns a new number and does not mutate the original value"] + #[rustc_const_unstable(feature = "clamp_magnitude", issue = "148519")] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + pub const fn clamp_magnitude(self, limit: $UnsignedT) -> Self { if let Ok(limit) = core::convert::TryInto::<$SelfT>::try_into(limit) { self.clamp(-limit, limit) } else { diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index d0ae6c31267f3..37223932a0b0f 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -2454,6 +2454,32 @@ macro_rules! nonzero_integer_signedness_dependent_methods { unsafe { NonZero::new_unchecked(self.get().cast_unsigned()) } } + /// clamps this number to a symmetric range centred around zero. the method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// this is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_magnitude)] + /// # use std::num::NonZero; + /// # + #[doc = concat!("let limit = NonZero::<", stringify!($Uint), ">::new(100).unwrap();")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(120).unwrap().clamp_magnitude(limit), NonZero::new(100).unwrap());")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(-120).unwrap().clamp_magnitude(limit), NonZero::new(-100).unwrap());")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(80).unwrap().clamp_magnitude(limit), NonZero::new(80).unwrap());")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(-80).unwrap().clamp_magnitude(limit), NonZero::new(-80).unwrap());")] + /// ``` + #[inline] + #[must_use = "method returns a new number and does not mutate the original value"] + #[rustc_const_unstable(feature = "clamp_magnitude", issue = "148519")] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + pub const fn clamp_magnitude(self, limit: NonZero<$Uint>) -> Self { + // SAFETY: a non-zero value clamped to the magnitude of a non-zero value is still non-zero. + unsafe { Self::new_unchecked(self.get().clamp_magnitude(limit.get())) } + } + }; } diff --git a/library/coretests/tests/num/clamp_magnitude.rs b/library/coretests/tests/num/clamp_magnitude.rs index 0f96e55f6914e..b8ba402a6660a 100644 --- a/library/coretests/tests/num/clamp_magnitude.rs +++ b/library/coretests/tests/num/clamp_magnitude.rs @@ -115,25 +115,25 @@ fn test_clamp_magnitude_f64() { } #[test] -#[should_panic(expected = "limit must be non-negative")] +#[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f32_panic_negative_limit() { let _ = 1.0f32.clamp_magnitude(-1.0); } #[test] -#[should_panic(expected = "limit must be non-negative")] +#[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f64_panic_negative_limit() { let _ = 1.0f64.clamp_magnitude(-1.0); } #[test] -#[should_panic] +#[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f32_panic_nan_limit() { let _ = 1.0f32.clamp_magnitude(f32::NAN); } #[test] -#[should_panic] +#[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f64_panic_nan_limit() { let _ = 1.0f64.clamp_magnitude(f64::NAN); } From d6d250c7dd35b423f519e0948f373ab279f8276c Mon Sep 17 00:00:00 2001 From: eleocraft Date: Thu, 24 Sep 2026 21:27:29 +0200 Subject: [PATCH 04/71] adding coretests and fixing docs Adding tests addressing the changes in coretests/tests/num/clamp_magnitude.rs --- library/core/src/num/nonzero.rs | 6 +- .../coretests/tests/num/clamp_magnitude.rs | 95 +++++++++++++++++++ 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 37223932a0b0f..513166bf12cae 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -2454,9 +2454,11 @@ macro_rules! nonzero_integer_signedness_dependent_methods { unsafe { NonZero::new_unchecked(self.get().cast_unsigned()) } } - /// clamps this number to a symmetric range centred around zero. the method clamps the number's magnitude (absolute value) to be at most `limit`. + /// Clamps this number to a symmetric range centred around zero. /// - /// this is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more /// explicit about the intent. /// /// # Examples diff --git a/library/coretests/tests/num/clamp_magnitude.rs b/library/coretests/tests/num/clamp_magnitude.rs index b8ba402a6660a..11ae7a7549111 100644 --- a/library/coretests/tests/num/clamp_magnitude.rs +++ b/library/coretests/tests/num/clamp_magnitude.rs @@ -1,3 +1,5 @@ +use core::num::*; + macro_rules! check_int_clamp { ($t:ty, $ut:ty) => { let min = <$t>::MIN; @@ -32,6 +34,16 @@ macro_rules! check_int_clamp { // Limit larger than type max (uN > iN::MAX) assert_eq!(max.clamp_magnitude(max_u), max); assert_eq!(min.clamp_magnitude(max_u), min); + + // Const clamping + const C1: $t = (100 as $t).clamp_magnitude(50); + assert_eq!(C1, 50); + const C2: $t = (-100 as $t).clamp_magnitude(50); + assert_eq!(C2, -50); + const C3: $t = (30 as $t).clamp_magnitude(50); + assert_eq!(C3, 30); + const C4: $t = (-30 as $t).clamp_magnitude(50); + assert_eq!(C4, -30); }; } @@ -65,6 +77,79 @@ fn test_clamp_magnitude_isize() { check_int_clamp!(isize, usize); } +macro_rules! check_nonzero_clamp { + ($t:ty, $ut:ty) => { + let min = <$t>::MIN; + let max = <$t>::MAX; + let max_u = <$ut>::MAX; + + // Basic clamping + let lim = <$ut>::new(50).unwrap(); + assert_eq!(<$t>::new(100).unwrap().clamp_magnitude(lim), <$t>::new(50).unwrap()); + assert_eq!(<$t>::new(-100).unwrap().clamp_magnitude(lim), <$t>::new(-50).unwrap()); + assert_eq!(<$t>::new(30).unwrap().clamp_magnitude(lim), <$t>::new(30).unwrap()); + assert_eq!(<$t>::new(-30).unwrap().clamp_magnitude(lim), <$t>::new(-30).unwrap()); + + // Exact boundary + assert_eq!(<$t>::new(50).unwrap().clamp_magnitude(lim), <$t>::new(50).unwrap()); + assert_eq!(<$t>::new(-50).unwrap().clamp_magnitude(lim), <$t>::new(-50).unwrap()); + + // MIN/MAX values + // Symmetric range [-MAX, MAX] + assert_eq!(max.clamp_magnitude(max.try_into().unwrap()), max); + assert_eq!(min.clamp_magnitude(max.try_into().unwrap()), -max); + + // Full range (limit covers MIN) + let min_abs = min.unsigned_abs(); + assert_eq!(min.clamp_magnitude(min_abs), min); + + // Limit larger than type max (uN > iN::MAX) + assert_eq!(max.clamp_magnitude(max_u), max); + assert_eq!(min.clamp_magnitude(max_u), min); + + // Const clamping + const LIM: $ut = <$ut>::new(50).unwrap(); + const C1: $t = <$t>::new(100).unwrap().clamp_magnitude(LIM); + assert_eq!(C1, <$t>::new(50).unwrap()); + const C2: $t = <$t>::new(-100).unwrap().clamp_magnitude(LIM); + assert_eq!(C2, <$t>::new(-50).unwrap()); + const C3: $t = <$t>::new(30).unwrap().clamp_magnitude(LIM); + assert_eq!(C3, <$t>::new(30).unwrap()); + const C4: $t = <$t>::new(-30).unwrap().clamp_magnitude(LIM); + assert_eq!(C4, <$t>::new(-30).unwrap()); + }; +} + +#[test] +fn test_clamp_magnitude_nonzero_i8() { + check_nonzero_clamp!(NonZeroI8, NonZeroU8); +} + +#[test] +fn test_clamp_magnitude_nonzero_i16() { + check_nonzero_clamp!(NonZeroI16, NonZeroU16); +} + +#[test] +fn test_clamp_magnitude_nonzero_i32() { + check_nonzero_clamp!(NonZeroI32, NonZeroU32); +} + +#[test] +fn test_clamp_magnitude_nonzero_i64() { + check_nonzero_clamp!(NonZeroI64, NonZeroU64); +} + +#[test] +fn test_clamp_magnitude_nonzero_i128() { + check_nonzero_clamp!(NonZeroI128, NonZeroU128); +} + +#[test] +fn test_clamp_magnitude_nonzero_isize() { + check_nonzero_clamp!(NonZeroIsize, NonZeroUsize); +} + macro_rules! check_float_clamp { ($t:ty) => { // Basic clamping @@ -101,6 +186,16 @@ macro_rules! check_float_clamp { let huge = 1e30; assert_eq!(max.clamp_magnitude(huge), huge); assert_eq!(min.clamp_magnitude(huge), -huge); + + // Const clamping + const C1: $t = (5.0 as $t).clamp_magnitude(3.0); + assert_eq!(C1, 3.0); + const C2: $t = (-5.0 as $t).clamp_magnitude(3.0); + assert_eq!(C2, -3.0); + const C3: $t = (2.0 as $t).clamp_magnitude(3.0); + assert_eq!(C3, 2.0); + const C4: $t = (-2.0 as $t).clamp_magnitude(3.0); + assert_eq!(C4, -2.0); }; } From 3f2e9ee8614715d3579ae7571985663e6de8f4e3 Mon Sep 17 00:00:00 2001 From: eleocraft Date: Fri, 25 Sep 2026 15:26:40 +0200 Subject: [PATCH 05/71] Applying requested changes Adding mod clamp_magnitude in coretests/num/mod.rs Activating feature(clamp_magnitude) in coretests/lib.rs Adding test coverage for f16, f128, and NaN as well as zero cases Modifying nonzero and int_macros documentation for better readablity --- library/core/src/num/int_macros.rs | 6 +- library/core/src/num/nonzero.rs | 26 ++++++-- library/coretests/tests/lib.rs | 1 + .../coretests/tests/num/clamp_magnitude.rs | 62 ++++++++++++++++--- library/coretests/tests/num/mod.rs | 1 + 5 files changed, 78 insertions(+), 18 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 2328fb1e03a31..1d272c0e5632e 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3964,13 +3964,13 @@ macro_rules! int_impl { /// ``` /// #![feature(clamp_magnitude)] #[doc = concat!("assert_eq!(120", stringify!($SelfT), ".clamp_magnitude(100), 100);")] - #[doc = concat!("assert_eq!(-120", stringify!($SelfT), ".clamp_magnitude(100), -100);")] + #[doc = concat!("assert_eq!((-120", stringify!($SelfT), ").clamp_magnitude(100), -100);")] #[doc = concat!("assert_eq!(80", stringify!($SelfT), ".clamp_magnitude(100), 80);")] - #[doc = concat!("assert_eq!(-80", stringify!($SelfT), ".clamp_magnitude(100), -80);")] + #[doc = concat!("assert_eq!((-80", stringify!($SelfT), ").clamp_magnitude(100), -80);")] /// ``` #[inline] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "clamp_magnitude", issue = "148519")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] #[unstable(feature = "clamp_magnitude", issue = "148519")] pub const fn clamp_magnitude(self, limit: $UnsignedT) -> Self { if let Ok(limit) = core::convert::TryInto::<$SelfT>::try_into(limit) { diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 513166bf12cae..d7b451c53f059 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -2468,14 +2468,30 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # use std::num::NonZero; /// # #[doc = concat!("let limit = NonZero::<", stringify!($Uint), ">::new(100).unwrap();")] - #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(120).unwrap().clamp_magnitude(limit), NonZero::new(100).unwrap());")] - #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(-120).unwrap().clamp_magnitude(limit), NonZero::new(-100).unwrap());")] - #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(80).unwrap().clamp_magnitude(limit), NonZero::new(80).unwrap());")] - #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(-80).unwrap().clamp_magnitude(limit), NonZero::new(-80).unwrap());")] + /// + /// assert_eq!( + #[doc = concat!("\tNonZero::<", stringify!($Int), ">::new(120).unwrap().clamp_magnitude(limit),")] + #[doc = "\tNonZero::new(100).unwrap(),"] + /// ); + /// + /// assert_eq!( + #[doc = concat!("\tNonZero::<", stringify!($Int), ">::new(-120).unwrap().clamp_magnitude(limit),")] + #[doc = "\tNonZero::new(-100).unwrap(),"] + /// ); + /// + /// assert_eq!( + #[doc = concat!("\tNonZero::<", stringify!($Int), ">::new(80).unwrap().clamp_magnitude(limit),")] + #[doc = "\tNonZero::new(80).unwrap(),"] + /// ); + /// + /// assert_eq!( + #[doc = concat!("\tNonZero::<", stringify!($Int), ">::new(-80).unwrap().clamp_magnitude(limit),")] + #[doc = "\tNonZero::new(-80).unwrap(),"] + /// ); /// ``` #[inline] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "clamp_magnitude", issue = "148519")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] #[unstable(feature = "clamp_magnitude", issue = "148519")] pub const fn clamp_magnitude(self, limit: NonZero<$Uint>) -> Self { // SAFETY: a non-zero value clamped to the magnitude of a non-zero value is still non-zero. diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 69bc6edd1b833..40543ee794ee7 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -15,6 +15,7 @@ #![feature(cfg_overflow_checks)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_internals)] +#![feature(clamp_magnitude)] #![feature(clamp_to)] #![feature(clone_to_uninit)] #![feature(cmp_minmax)] diff --git a/library/coretests/tests/num/clamp_magnitude.rs b/library/coretests/tests/num/clamp_magnitude.rs index 11ae7a7549111..5bccc4ad45e20 100644 --- a/library/coretests/tests/num/clamp_magnitude.rs +++ b/library/coretests/tests/num/clamp_magnitude.rs @@ -1,5 +1,7 @@ use core::num::*; +use crate::num::assert_biteq; + macro_rules! check_int_clamp { ($t:ty, $ut:ty) => { let min = <$t>::MIN; @@ -151,7 +153,7 @@ fn test_clamp_magnitude_nonzero_isize() { } macro_rules! check_float_clamp { - ($t:ty) => { + ($t:ty, $huge: expr) => { // Basic clamping assert_eq!((5.0 as $t).clamp_magnitude(3.0), 3.0); assert_eq!((-5.0 as $t).clamp_magnitude(3.0), -3.0); @@ -163,10 +165,13 @@ macro_rules! check_float_clamp { assert_eq!((-3.0 as $t).clamp_magnitude(3.0), -3.0); // Zero cases - assert_eq!((0.0 as $t).clamp_magnitude(1.0), 0.0); - assert_eq!((-0.0 as $t).clamp_magnitude(1.0), 0.0); - assert_eq!((5.0 as $t).clamp_magnitude(0.0), 0.0); - assert_eq!((-5.0 as $t).clamp_magnitude(0.0), 0.0); + type Float = $t; + assert_biteq!((0.0 as $t).clamp_magnitude(1.0), 0.0); + assert_biteq!((-0.0 as $t).clamp_magnitude(1.0), -0.0); + assert_biteq!((5.0 as $t).clamp_magnitude(0.0), 0.0); + assert_biteq!((-5.0 as $t).clamp_magnitude(0.0), -0.0); + assert_biteq!((5.0 as $t).clamp_magnitude(-0.0), 0.0); + assert_biteq!((-5.0 as $t).clamp_magnitude(-0.0), -0.0); // Special values - Infinity let inf = <$t>::INFINITY; @@ -183,9 +188,12 @@ macro_rules! check_float_clamp { let max = <$t>::MAX; let min = <$t>::MIN; // Large limit - let huge = 1e30; - assert_eq!(max.clamp_magnitude(huge), huge); - assert_eq!(min.clamp_magnitude(huge), -huge); + assert_eq!(max.clamp_magnitude($huge), $huge); + assert_eq!(min.clamp_magnitude($huge), -$huge); + + // NaN + let nan = <$t>::NAN; + assert!(nan.clamp_magnitude(1.0).is_nan()); // Const clamping const C1: $t = (5.0 as $t).clamp_magnitude(3.0); @@ -199,14 +207,30 @@ macro_rules! check_float_clamp { }; } +#[test] +fn test_clamp_magnitude_f16() { + check_float_clamp!(f16, 1e3); +} + #[test] fn test_clamp_magnitude_f32() { - check_float_clamp!(f32); + check_float_clamp!(f32, 1e30); } #[test] fn test_clamp_magnitude_f64() { - check_float_clamp!(f64); + check_float_clamp!(f64, 1e300); +} + +#[test] +fn test_clamp_magnitude_f128() { + check_float_clamp!(f128, 1e3000); +} + +#[test] +#[should_panic(expected = "limit must be non-negative and not NaN")] +fn test_clamp_magnitude_f16_panic_negative_limit() { + let _ = 1.0f16.clamp_magnitude(-1.0); } #[test] @@ -221,6 +245,18 @@ fn test_clamp_magnitude_f64_panic_negative_limit() { let _ = 1.0f64.clamp_magnitude(-1.0); } +#[test] +#[should_panic(expected = "limit must be non-negative and not NaN")] +fn test_clamp_magnitude_f128_panic_negative_limit() { + let _ = 1.0f128.clamp_magnitude(-1.0); +} + +#[test] +#[should_panic(expected = "limit must be non-negative and not NaN")] +fn test_clamp_magnitude_f16_panic_nan_limit() { + let _ = 1.0f16.clamp_magnitude(f16::NAN); +} + #[test] #[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f32_panic_nan_limit() { @@ -232,3 +268,9 @@ fn test_clamp_magnitude_f32_panic_nan_limit() { fn test_clamp_magnitude_f64_panic_nan_limit() { let _ = 1.0f64.clamp_magnitude(f64::NAN); } + +#[test] +#[should_panic(expected = "limit must be non-negative and not NaN")] +fn test_clamp_magnitude_f128_panic_nan_limit() { + let _ = 1.0f128.clamp_magnitude(f128::NAN); +} diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index b1c3001790f07..f892734d8b95d 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -24,6 +24,7 @@ mod u8; mod bignum; mod carryless_mul; mod cast; +mod clamp_magnitude; mod complex; mod const_from; mod dec2flt; From c89c55dd149a01e7192a1b3cb49409d1949db1be Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 25 Sep 2026 18:35:56 +0200 Subject: [PATCH 06/71] sanitizers.md: improve text --- src/doc/rustc-dev-guide/src/sanitizers.md | 40 +++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/sanitizers.md b/src/doc/rustc-dev-guide/src/sanitizers.md index 65e1c0c705057..5d242b8ac5d4a 100644 --- a/src/doc/rustc-dev-guide/src/sanitizers.md +++ b/src/doc/rustc-dev-guide/src/sanitizers.md @@ -1,33 +1,33 @@ # Sanitizers support -The rustc compiler contains support for following sanitizers: +The Rust compiler contains support for following sanitizers: -* [AddressSanitizer][clang-asan] a faster memory error detector. - Can detect out-of-bounds access to heap, stack, and globals, use after free, use - after return, double free, invalid free, memory leaks. -* [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides +* [AddressSanitizer][clang-asan], a faster memory error detector. + It can detect out-of-bounds access to heap, stack, and globals, use after free, use + after return, double free, invalid free, and memory leaks. +* [ControlFlowIntegrity][clang-cfi], LLVM Control Flow Integrity (CFI), provides forward-edge control flow protection. -* [Hardware-assisted AddressSanitizer][clang-hwasan] a tool similar to - AddressSanitizer but based on partial hardware assistance. -* [KernelControlFlowIntegrity][clang-kcfi] LLVM Kernel Control Flow Integrity - (KCFI) provides forward-edge control flow protection for operating systems kernels. -* [LeakSanitizer][clang-lsan] a run-time memory leak detector. -* [MemorySanitizer][clang-msan] a detector of uninitialized reads. -* [ThreadSanitizer][clang-tsan] a fast data race detector. +* [Hardware-assisted AddressSanitizer][clang-hwasan] is similar to + AddressSanitizer, but is based on partial hardware assistance. +* [KernelControlFlowIntegrity][clang-kcfi], LLVM Kernel Control Flow Integrity + (KCFI), provides forward-edge control flow protection for operating system kernels. +* [LeakSanitizer][clang-lsan], a run-time memory leak detector. +* [MemorySanitizer][clang-msan], a detector of uninitialized reads. +* [ThreadSanitizer][clang-tsan], a fast data race detector. ## How to use the sanitizers? -To enable a sanitizer compile with `-Z sanitizer=...` option, where value is one -of `address`, `cfi`, `hwaddress`, `kcfi`, `leak`, `memory` or `thread`. +To enable a sanitizer, compile with `-Z sanitizer=...` option, where value is one +of `address`, `cfi`, `hwaddress`, `kcfi`, `leak`, `memory`, or `thread`. For more details on how to use sanitizers, -please refer to the sanitizer flag in [The Unstable Book]. +refer to the sanitizer flag in [The Unstable Book]. [The Unstable Book]: https://doc.rust-lang.org/unstable-book -## How are sanitizers implemented in rustc? +## How sanitizers are implemented in rustc The implementation of sanitizers (except CFI) relies almost entirely on LLVM. -The rustc is an integration point for LLVM compile time instrumentation passes +The Rust compiler is an integration point for LLVM compile time instrumentation passes and runtime libraries. Highlight of the most important aspects of the implementation: @@ -42,7 +42,7 @@ Highlight of the most important aspects of the implementation: The runtimes are [placed into target libdir][sanitizer-copy]. * During LLVM code generation, the functions intended for instrumentation are - [marked][sanitizer-attribute] with appropriate LLVM attribute: + [marked][sanitizer-attribute] with an appropriate LLVM attribute: `SanitizeAddress`, `SanitizeHWAddress`, `SanitizeMemory`, or `SanitizeThread`. By default, all functions are instrumented, but this behaviour can be changed with `#[sanitize(xyz = "on|off|")]`. @@ -57,7 +57,7 @@ Highlight of the most important aspects of the implementation: passes][sanitizer-pass], different for each sanitizer. Instrumentation passes are invoked after optimization passes. -* When producing an executable, the sanitizer specific runtime library is +* When producing an executable, the sanitizer-specific runtime library is [linked in][sanitizer-link]. The libraries are searched for in the target libdir. First, the search is relative to the overridden system root, and subsequently, @@ -83,7 +83,7 @@ Sanitizers are validated by code generation tests in [`tests/ui/sanitizer/`][test-ui] directory. Testing sanitizer functionality requires the sanitizer runtimes (built when -`build.sanitizer = true` in `bootstrap.toml`) and target providing support for particular a sanitizer. +`build.sanitizer = true` in `bootstrap.toml`) and a target providing support for particular a sanitizer. When a sanitizer is unsupported on a given target, sanitizer tests will be ignored. This behaviour is controlled by compiletest `needs-sanitizer-*` directives. From 8c3ae6023e42df78c644e4040fd3a8bb15cd4616 Mon Sep 17 00:00:00 2001 From: Kurashina Hinata Date: Sat, 26 Sep 2026 18:07:13 +0900 Subject: [PATCH 07/71] Don't build format string suggestions from `concat!` offsets When a format string does not come directly from a string literal in the source, e.g. when it is produced by `concat!`, the parser's inner offsets are relative to the expanded string rather than to the source. The primary error span and the `RemoveRawIdent` suggestion already check `is_source_literal` before calling `fmt_span.from_inner`, but the `UsePositional`, `ReorderFormatParameter` and `AddMissingColon` suggestions did not. As a result, these suggestions could point into the middle of a multibyte character and ICE when rendered, or suggest a bogus argument copied from unrelated source text. Only emit them when the format string is a source literal, like the other suggestions do. The crash test is moved to `tests/ui/fmt`, with cases covering each of these suggestions. --- compiler/rustc_builtin_macros/src/format.rs | 26 ++++++---- tests/crashes/156101.rs | 4 -- ...format-args-concat-multibyte-suggestion.rs | 38 ++++++++++++++ ...at-args-concat-multibyte-suggestion.stderr | 52 +++++++++++++++++++ 4 files changed, 106 insertions(+), 14 deletions(-) delete mode 100644 tests/crashes/156101.rs create mode 100644 tests/ui/fmt/format-args-concat-multibyte-suggestion.rs create mode 100644 tests/ui/fmt/format-args-concat-multibyte-suggestion.stderr diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index e23c057f8a651..c58b7e234d4d6 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -339,7 +339,9 @@ fn make_format_args( parse::Suggestion::UsePositional => { let captured_arg_span = fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); - if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) { + if is_source_literal + && let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) + { let span = match args.unnamed_args().last() { Some(arg) => arg.expr.span, None => fmt_span, @@ -360,17 +362,21 @@ fn make_format_args( } } parse::Suggestion::ReorderFormatParameter(span, replacement) => { - let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); - e.sugg_ = - Some(diagnostics::InvalidFormatStringSuggestion::ReorderFormatParameter { - span, - replacement, - }); + if is_source_literal { + let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); + e.sugg_ = + Some(diagnostics::InvalidFormatStringSuggestion::ReorderFormatParameter { + span, + replacement, + }); + } } parse::Suggestion::AddMissingColon(span) => { - let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); - e.sugg_ = - Some(diagnostics::InvalidFormatStringSuggestion::AddMissingColon { span }); + if is_source_literal { + let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); + e.sugg_ = + Some(diagnostics::InvalidFormatStringSuggestion::AddMissingColon { span }); + } } parse::Suggestion::UseRustDebugPrintingMacro => { // This targets `println!("{=}", x);` and `println!("{0=}", x);` diff --git a/tests/crashes/156101.rs b/tests/crashes/156101.rs deleted file mode 100644 index c95361fab2ecc..0000000000000 --- a/tests/crashes/156101.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #156101 -fn main() { - format_args!(concat!("𐏿", "{f:?#}")); -} diff --git a/tests/ui/fmt/format-args-concat-multibyte-suggestion.rs b/tests/ui/fmt/format-args-concat-multibyte-suggestion.rs new file mode 100644 index 0000000000000..51504607d2b61 --- /dev/null +++ b/tests/ui/fmt/format-args-concat-multibyte-suggestion.rs @@ -0,0 +1,38 @@ +// Regression test for #156101. +// +// When the format string comes from `concat!`, the parser's inner offsets are relative to the +// expanded string, not to the source, so they must not be turned into spans in the source. +// Before the fix, suggestions built from those offsets went wrong in two ways: +// +// - If the span landed inside a multibyte character, rendering the suggestion caused an ICE. +// The `ReorderFormatParameter` and `AddMissingColon` cases below are padded so that the span +// falls inside `é` (2 bytes) or `𐏿` (4 bytes). +// - If the span landed on unrelated source text, `UsePositional` suggested a bogus argument +// copied from that text. +// +// After the fix, no suggestion is emitted for these format strings. + +fn main() { + // The original reproducer from the issue. + format_args!(concat!("𐏿", "{f:?#}")); + //~^ ERROR invalid format string + + // `Suggestion::ReorderFormatParameter` + format_args!(concat!("é", "aaa{:?#}"), 1); + //~^ ERROR invalid format string + format_args!(concat!("𐏿", "a{:?#}"), 1); + //~^ ERROR invalid format string + + // `Suggestion::AddMissingColon` + format_args!(concat!("é", "aaaa{x?}")); + //~^ ERROR invalid format string + format_args!(concat!("𐏿", "aa{x?}")); + //~^ ERROR invalid format string + + // `Suggestion::UsePositional`: these did not ICE, but before the fix they suggested a bogus + // argument taken from the `concat!` invocation instead of from the format string. + format_args!(concat!("{}{a.b}", "")); + //~^ ERROR invalid format string + format_args!(concat!("{}{a.0}", "")); + //~^ ERROR invalid format string +} diff --git a/tests/ui/fmt/format-args-concat-multibyte-suggestion.stderr b/tests/ui/fmt/format-args-concat-multibyte-suggestion.stderr new file mode 100644 index 0000000000000..5eb8a4848a612 --- /dev/null +++ b/tests/ui/fmt/format-args-concat-multibyte-suggestion.stderr @@ -0,0 +1,52 @@ +error: invalid format string: expected `}`, found `#` + --> $DIR/format-args-concat-multibyte-suggestion.rs:17:18 + | +LL | format_args!(concat!("𐏿", "{f:?#}")); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string + +error: invalid format string: expected `}`, found `#` + --> $DIR/format-args-concat-multibyte-suggestion.rs:21:18 + | +LL | format_args!(concat!("é", "aaa{:?#}"), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string + +error: invalid format string: expected `}`, found `#` + --> $DIR/format-args-concat-multibyte-suggestion.rs:23:18 + | +LL | format_args!(concat!("𐏿", "a{:?#}"), 1); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string + +error: invalid format string: expected `}`, found `?` + --> $DIR/format-args-concat-multibyte-suggestion.rs:27:18 + | +LL | format_args!(concat!("é", "aaaa{x?}")); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `:` before `?` to format with `Debug` in format string + | + = note: to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `?` + --> $DIR/format-args-concat-multibyte-suggestion.rs:29:18 + | +LL | format_args!(concat!("𐏿", "aa{x?}")); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `:` before `?` to format with `Debug` in format string + | + = note: to print `{`, you can escape it using `{{` + +error: invalid format string: field access isn't supported + --> $DIR/format-args-concat-multibyte-suggestion.rs:34:18 + | +LL | format_args!(concat!("{}{a.b}", "")); + | ^^^^^^^^^^^^^^^^^^^^^^ not supported in format string + | + = note: consider moving this expression to a local variable and then using the local here instead + +error: invalid format string: tuple index access isn't supported + --> $DIR/format-args-concat-multibyte-suggestion.rs:36:18 + | +LL | format_args!(concat!("{}{a.0}", "")); + | ^^^^^^^^^^^^^^^^^^^^^^ not supported in format string + | + = note: consider moving this expression to a local variable and then using the local here instead + +error: aborting due to 7 previous errors + From 36c3cb96f64bd69cccb70b03afad4d1b30f0f36d Mon Sep 17 00:00:00 2001 From: Redddy Date: Sat, 26 Sep 2026 10:38:45 +0000 Subject: [PATCH 08/71] ConstKind::Unevaluated -> ConstKind::Alias --- src/doc/rustc-dev-guide/src/const-generics.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index 9e26a174d8cf6..718c3d4014aa9 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -5,7 +5,7 @@ Most of the kinds of `ty::Const` that exist have direct parallels to kinds of types that exist, for example `ConstKind::Param` is equivalent to `TyKind::Param`. The main interesting points here are: -- [`ConstKind::Unevaluated`], which is equivalent to `TyKind::Alias` and in the long term should be renamed (as well as introducing an `AliasConstKind` to parallel `ty::AliasKind`). +- [`ConstKind::Alias`], which is equivalent to `TyKind::Alias`. - [`ConstKind::Value`], which is the final value of a `ty::Const` after monomorphization. This is somewhat similar to fully concrete things like `TyKind::Str` or `TyKind::ADT`. @@ -35,7 +35,7 @@ const ANON: usize = 1 + 1; type Alias = [u8; ANON]; ``` -Where the array length in `[u8; ANON]` isn't itself an anon const containing a usage of `ANON`, but a kind of "direct" usage of the `ANON` const item ([`ConstKind::Unevaluated`]). +Where the array length in `[u8; ANON]` isn't itself an anon const containing a usage of `ANON`, but a kind of "direct" usage of the `ANON` const item ([`ConstKind::Alias`]). Anon consts do not inherit any generic parameters of the item they are inside of: ```rust @@ -81,7 +81,7 @@ type Alias = [u8; ANON]; When we go through HIR ty lowering for the array type in `Alias`, we will lower the array length too, and feed `type_of(ANON) -> usize`. This will effectively set the type of the `ANON` const item during some later part of the compiler rather than when constructing the HIR. -After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Unevaluated` with the `DefId` of the `AnonConst`. This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `min_generic_const_args` is enabled). +After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Alias` with the `DefId` of the `AnonConst`. This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `min_generic_const_args` is enabled). This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. @@ -215,7 +215,7 @@ Proving `ConstArgHasType` goals is implemented by first computing the type of th A rough outline of how the type of a Const Argument may be computed: - [`ConstKind::Param(N)`][`ConstKind::Param`] can be looked up in the [`ParamEnv`] to find a `ConstArgHasType(N, ty)` clause - [`ConstKind::Value`] stores the type of the value inside itself so can trivially be accessed -- [`ConstKind::Unevaluated`] can have its type computed by calling the `type_of` query +- [`ConstKind::Alias`] can have its type computed by calling the `type_of` query - See the implementation of proving `ConstArgHasType` goals for more detailed information `ConstArgHasType` is *the* soundness critical way that we check Const Arguments have the correct type. @@ -241,7 +241,7 @@ Looking at the above example, this corresponds to `[u8; ANON]` being a well form [`ConstKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html [`ConstKind::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Infer [`ConstKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Param -[`ConstKind::Unevaluated`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Unevaluated +[`ConstKind::Alias`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html#variant.Alias [`ConstKind::Value`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Value [const_arg_has_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ClauseKind.html#variant.ConstArgHasType [`ParamEnv`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html From 5e11a2644c55d84f5fc90a9c2b64795c5c6714e1 Mon Sep 17 00:00:00 2001 From: Redddy Date: Sat, 26 Sep 2026 10:58:40 +0000 Subject: [PATCH 09/71] fix ConstKind link --- src/doc/rustc-dev-guide/src/const-generics.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index 718c3d4014aa9..e8aa118337b64 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -238,11 +238,11 @@ what actually happens is a *type checking* error when type checking the anon con Looking at the above example, this corresponds to `[u8; ANON]` being a well formed type because `ANON` has type `usize`, but the *body* of `ANON` being illformed and resulting in a type checking error because `true` can't be returned from a const item of type `usize`. [ambig-unambig-ty-and-consts]: ./ambig-unambig-ty-and-consts.md -[`ConstKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html -[`ConstKind::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Infer -[`ConstKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Param +[`ConstKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html +[`ConstKind::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html#variant.Infer +[`ConstKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html#variant.Param [`ConstKind::Alias`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html#variant.Alias -[`ConstKind::Value`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Value +[`ConstKind::Value`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html#variant.Value [const_arg_has_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ClauseKind.html#variant.ConstArgHasType [`ParamEnv`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html [`generics_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#impl-TyCtxt%3C'tcx%3E/method.generics_of From b9e7e711bc293c5757150cf6d32fd1d8015fd391 Mon Sep 17 00:00:00 2001 From: eleocraft Date: Mon, 28 Sep 2026 14:02:16 +0200 Subject: [PATCH 10/71] nonzero doc: replacing tabs with spaces --- library/core/src/num/nonzero.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index d7b451c53f059..cdfda32bad43a 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -2470,23 +2470,23 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[doc = concat!("let limit = NonZero::<", stringify!($Uint), ">::new(100).unwrap();")] /// /// assert_eq!( - #[doc = concat!("\tNonZero::<", stringify!($Int), ">::new(120).unwrap().clamp_magnitude(limit),")] - #[doc = "\tNonZero::new(100).unwrap(),"] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(120).unwrap().clamp_magnitude(limit),")] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(100).unwrap(),")] /// ); /// /// assert_eq!( - #[doc = concat!("\tNonZero::<", stringify!($Int), ">::new(-120).unwrap().clamp_magnitude(limit),")] - #[doc = "\tNonZero::new(-100).unwrap(),"] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(-120).unwrap().clamp_magnitude(limit),")] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(-100).unwrap(),")] /// ); /// /// assert_eq!( - #[doc = concat!("\tNonZero::<", stringify!($Int), ">::new(80).unwrap().clamp_magnitude(limit),")] - #[doc = "\tNonZero::new(80).unwrap(),"] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(80).unwrap().clamp_magnitude(limit),")] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(80).unwrap(),")] /// ); /// /// assert_eq!( - #[doc = concat!("\tNonZero::<", stringify!($Int), ">::new(-80).unwrap().clamp_magnitude(limit),")] - #[doc = "\tNonZero::new(-80).unwrap(),"] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(-80).unwrap().clamp_magnitude(limit),")] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(-80).unwrap(),")] /// ); /// ``` #[inline] From d10b01c846c0dc222d9fcf36efdb2cc0fc0c2d9f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Sep 2026 13:45:01 +1000 Subject: [PATCH 11/71] Use `{IntTy,UintTy}::name` in `Ty::primitive_symbol` --- compiler/rustc_middle/src/ty/sty.rs | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 243ad73e3dfb8..925915c88cdb4 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2115,28 +2115,9 @@ impl<'tcx> Ty<'tcx> { match self.kind() { ty::Bool => Some(sym::bool), ty::Char => Some(sym::char), - ty::Float(f) => match f { - ty::FloatTy::F16 => Some(sym::f16), - ty::FloatTy::F32 => Some(sym::f32), - ty::FloatTy::F64 => Some(sym::f64), - ty::FloatTy::F128 => Some(sym::f128), - }, - ty::Int(f) => match f { - ty::IntTy::Isize => Some(sym::isize), - ty::IntTy::I8 => Some(sym::i8), - ty::IntTy::I16 => Some(sym::i16), - ty::IntTy::I32 => Some(sym::i32), - ty::IntTy::I64 => Some(sym::i64), - ty::IntTy::I128 => Some(sym::i128), - }, - ty::Uint(f) => match f { - ty::UintTy::Usize => Some(sym::usize), - ty::UintTy::U8 => Some(sym::u8), - ty::UintTy::U16 => Some(sym::u16), - ty::UintTy::U32 => Some(sym::u32), - ty::UintTy::U64 => Some(sym::u64), - ty::UintTy::U128 => Some(sym::u128), - }, + ty::Int(i) => Some(i.name()), + ty::Uint(u) => Some(u.name()), + ty::Float(f) => Some(f.name()), ty::Str => Some(sym::str), _ => None, } From 935c565a18c3768389877b116000baad08649dd8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 27 Jul 2026 16:38:02 +1000 Subject: [PATCH 12/71] Factor out repeated `get_normal_item` calls --- .../rustc_attr_parsing/src/attributes/cfg.rs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 8102208ec519d..d244e6c59e5f9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -306,7 +306,8 @@ pub fn parse_cfg_attr( features: Option<&Features>, lint_node_id: ast::NodeId, ) -> Option<(CfgEntry, Vec<(WithTokens, Span)>)> { - match &cfg_attr.get_normal_item().args { + let item = cfg_attr.get_normal_item(); + match &item.args { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => { check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim); match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| { @@ -316,11 +317,11 @@ pub fn parse_cfg_attr( Err(e) => { let suggestions = CFG_ATTR_TEMPLATE.suggestions( ParsedDescription::Attribute, - cfg_attr.get_normal_item().unsafety, + item.unsafety, sym::cfg_attr, ); e.with_span_suggestions( - cfg_attr.get_normal_item().span, + item.span, "must be of the form", suggestions, Applicability::HasPlaceholders, @@ -334,25 +335,24 @@ pub fn parse_cfg_attr( } } _ => { - let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) = - cfg_attr.get_normal_item().args - { - (dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument) - } else { - (cfg_attr.get_normal_item().span, AttributeParseErrorReason::ExpectedList) - }; + let (span, reason) = + if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) = item.args { + (dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument) + } else { + (item.span, AttributeParseErrorReason::ExpectedList) + }; sess.dcx().emit_err(AttributeParseError { span, - inner_span: cfg_attr.get_normal_item().span, + inner_span: item.span, template: CFG_ATTR_TEMPLATE, - path: AttrPath::from_ast(&cfg_attr.get_normal_item().path, identity), + path: AttrPath::from_ast(&item.path, identity), description: ParsedDescription::Attribute, reason, suggestions: diagnostics::AttributeParseErrorSuggestions::CreatedByTemplate( CFG_ATTR_TEMPLATE.suggestions( ParsedDescription::Attribute, - cfg_attr.get_normal_item().unsafety, + item.unsafety, sym::cfg_attr, ), ), @@ -389,13 +389,14 @@ fn parse_cfg_attr_internal<'a>( )?; let pred_span = pred_start.with_hi(parser.token.span.hi()); + let item = attribute.get_normal_item(); let cfg_predicate = AttributeParser::parse_single_args( sess, attribute.span, - attribute.get_normal_item().span, + item.span, attribute.style, AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span }, - Some(attribute.get_normal_item().unsafety), + Some(item.unsafety), AttributeSafety::Normal, ParsedDescription::Attribute, pred_span, From bc7618a8dab2415ec18057b4243fba6f3c665ee1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 27 Jul 2026 19:03:15 +1000 Subject: [PATCH 13/71] Add test case for an invalid attribute with nested `cfg_attr` Prior to #159633, the compiler made an invalid suggestion: ``` help: must be of the form | 1 - #[cfg_attr(true, cfg_attr(true, 3))] 1 + #[cfg_attr(true, #[cfg_attr(predicate, attr1, attr2, ...)])] ``` Now it is correct: ``` help: must be of the form | 1 - #[cfg_attr(true, cfg_attr(true, 3))] 1 + #[cfg_attr(true, cfg_attr(predicate, attr1, attr2, ...))] ``` But there was no test for it. This commit adds one. --- .../cfg_attr-attr-syntax-validation.rs | 3 +++ .../cfg_attr-attr-syntax-validation.stderr | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs index 907e1b966766f..508b449358964 100644 --- a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs @@ -46,6 +46,9 @@ struct S12; //~| WARN previously accepted struct S13; +#[cfg_attr(true, cfg_attr(true, 3))] //~ ERROR expected identifier, found `3` +struct S14; + #[cfg_attr(true, inline())] //~ ERROR malformed `inline` attribute input fn f1() {} diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr index e901460a4eb88..048affd1c4191 100644 --- a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr @@ -120,6 +120,19 @@ LL - #[cfg_attr(true)] LL + #[cfg_attr(predicate, attr1, attr2, ...)] | +error: expected identifier, found `3` + --> $DIR/cfg_attr-attr-syntax-validation.rs:49:33 + | +LL | #[cfg_attr(true, cfg_attr(true, 3))] + | ^ expected identifier + | + = note: for more information, visit +help: must be of the form + | +LL - #[cfg_attr(true, cfg_attr(true, 3))] +LL + #[cfg_attr(true, cfg_attr(predicate, attr1, attr2, ...))] + | + error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable --> $DIR/cfg_attr-attr-syntax-validation.rs:30:30 | @@ -157,7 +170,7 @@ LL | #[cfg_attr(true, link_section = "name")] | ++++++++ error[E0805]: malformed `inline` attribute input - --> $DIR/cfg_attr-attr-syntax-validation.rs:49:18 + --> $DIR/cfg_attr-attr-syntax-validation.rs:52:18 | LL | #[cfg_attr(true, inline())] | ^^^^^^-- @@ -185,7 +198,7 @@ LL | #[cfg_attr(true, link_section)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: requested on the command line with `-W unused-attributes` -error: aborting due to 13 previous errors; 1 warning emitted +error: aborting due to 14 previous errors; 1 warning emitted Some errors have detailed explanations: E0539, E0565, E0805. For more information about an error, try `rustc --explain E0539`. From 7af2cce3b04ebe3cb42807d7e75520888021aefc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Sep 2026 14:25:40 +1000 Subject: [PATCH 14/71] Remove unused `rustc_middle::ty::cast::IntTy::is_signed` --- compiler/rustc_middle/src/ty/cast.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index 25fc0775b1a32..e53f53d5e5648 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -17,12 +17,6 @@ pub enum IntTy { Char, } -impl IntTy { - pub fn is_signed(self) -> bool { - matches!(self, Self::I) - } -} - // Valid types for the result of a non-coercion cast #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum CastTy<'tcx> { From 3e5b244994234f4144b3c11fa590a1e1b2834f18 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 28 Jul 2026 11:20:23 +1000 Subject: [PATCH 15/71] Mark duplicate attr messages as not machine applicable This commit adds a new test for some uncovered cases. The thing to note here is the varying correctness of the `help:` lines. This is correct: ``` LL | #[inline] | ^^^^^^^^^ help: remove this attribute ``` The following two are half correct. They give the right idea but if applied literally they will produce syntax that triggers either a warning (the former) or an error (the latter). ``` LL | #[cfg_attr(true, inline)] | ^^^^^^ help: remove this attribute LL | #[cfg_attr(true, inline, deprecated)] | ^^^^^^ help: remove this attribute ``` For this reason, this commit also marks these help messages as not machine-applicable. This means we lose the machine applicability on some cases where it's correct, but it seems better to be conservative. --- .../rustc_attr_parsing/src/diagnostics.rs | 4 +- .../cfg-attr-duplicate-attrs.rs | 34 ++++++++ .../cfg-attr-duplicate-attrs.stderr | 78 +++++++++++++++++++ 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.rs create mode 100644 tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.stderr diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index fb4a32d864fbe..a43cd918c8f35 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1235,7 +1235,7 @@ pub(crate) struct UnknownVersionLiteral { #[diag("multiple `{$name}` attributes")] pub(crate) struct UnusedMultiple { #[primary_span] - #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] + #[suggestion("remove this attribute", code = "", applicability = "unspecified")] pub this: Span, #[note("attribute also specified here")] pub other: Span, @@ -2061,7 +2061,7 @@ pub(crate) struct AdditionalCommaSuggestion { #[derive(Diagnostic)] #[diag("unused attribute")] pub(crate) struct UnusedDuplicate { - #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] + #[suggestion("remove this attribute", code = "", applicability = "unspecified")] pub this: Span, #[note("attribute also specified here")] pub other: Span, diff --git a/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.rs b/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.rs new file mode 100644 index 0000000000000..30434569dbe73 --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.rs @@ -0,0 +1,34 @@ +// Test for handling of duplicated attributes within `cfg_attr`, in particular the suggestions of +// what to remove. + +#[inline] +#[inline] +//~^ WARN unused attribute +//~| WARN this was previously accepted +fn f1() {} + +#[deprecated] +#[deprecated] +//~^ ERROR multiple `deprecated` attributes +fn f2() {} + +#[inline] +#[cfg_attr(true, inline)] +//~^ WARN unused attribute +//~| WARN this was previously accepted +fn f3() {} + +#[deprecated] +#[cfg_attr(true, deprecated)] +//~^ ERROR multiple `deprecated` attributes +fn f4() {} + +#[inline] +#[deprecated] +#[cfg_attr(true, inline, deprecated)] +//~^ WARN unused attribute +//~| WARN this was previously accepted +//~| ERROR multiple `deprecated` attributes +fn f5() {} + +fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.stderr b/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.stderr new file mode 100644 index 0000000000000..c30bc26b22ce7 --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.stderr @@ -0,0 +1,78 @@ +error: multiple `deprecated` attributes + --> $DIR/cfg-attr-duplicate-attrs.rs:11:1 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:10:1 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ + +error: multiple `deprecated` attributes + --> $DIR/cfg-attr-duplicate-attrs.rs:22:18 + | +LL | #[cfg_attr(true, deprecated)] + | ^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:21:1 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ + +error: multiple `deprecated` attributes + --> $DIR/cfg-attr-duplicate-attrs.rs:28:26 + | +LL | #[cfg_attr(true, inline, deprecated)] + | ^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:27:1 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ + +warning: unused attribute + --> $DIR/cfg-attr-duplicate-attrs.rs:5:1 + | +LL | #[inline] + | ^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:4:1 + | +LL | #[inline] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: requested on the command line with `-W unused-attributes` + +warning: unused attribute + --> $DIR/cfg-attr-duplicate-attrs.rs:16:18 + | +LL | #[cfg_attr(true, inline)] + | ^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:15:1 + | +LL | #[inline] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: unused attribute + --> $DIR/cfg-attr-duplicate-attrs.rs:28:18 + | +LL | #[cfg_attr(true, inline, deprecated)] + | ^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:26:1 + | +LL | #[inline] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: aborting due to 3 previous errors; 3 warnings emitted + From b2c20770a2dd0db94eac6e954fe9b208c68e68a4 Mon Sep 17 00:00:00 2001 From: Davlat Davydov Date: Sat, 26 Sep 2026 15:23:30 +0300 Subject: [PATCH 16/71] Update expect messages in library/std/src/os/unix/net/ following style guide review changes --- library/std/src/os/unix/net/addr.rs | 10 ++++---- library/std/src/os/unix/net/datagram.rs | 34 ++++++++++++------------- library/std/src/os/unix/net/listener.rs | 6 ++--- library/std/src/os/unix/net/stream.rs | 22 ++++++++-------- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 3daddc2d34323..a0a229704911e 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -87,7 +87,7 @@ enum AddressKind<'a> { /// return /// } /// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// ``` #[derive(Clone)] #[stable(feature = "unix_socket", since = "1.10.0")] @@ -186,7 +186,7 @@ impl SocketAddr { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// assert_eq!(addr.is_unnamed(), false); /// Ok(()) /// } @@ -200,7 +200,7 @@ impl SocketAddr { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// assert_eq!(addr.is_unnamed(), true); /// Ok(()) /// } @@ -224,7 +224,7 @@ impl SocketAddr { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); /// Ok(()) /// } @@ -238,7 +238,7 @@ impl SocketAddr { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// assert_eq!(addr.as_pathname(), None); /// Ok(()) /// } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index e03ecd7eed9ea..f80a3a887c54d 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -273,7 +273,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let sock_copy = sock.try_clone().expect("try_clone failed"); + /// let sock_copy = sock.try_clone().expect("`UnixDatagram::try_clone` should not fail"); /// Ok(()) /// } /// ``` @@ -292,7 +292,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let addr = sock.local_addr().expect("Couldn't get local address"); + /// let addr = sock.local_addr().expect("`UnixDatagram::local_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -317,7 +317,7 @@ impl UnixDatagram { /// let sock = UnixDatagram::unbound()?; /// sock.connect("/path/to/the/socket")?; /// - /// let addr = sock.peer_addr().expect("Couldn't get peer address"); + /// let addr = sock.peer_addr().expect("`UnixDatagram::peer_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -390,7 +390,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::bind("/path/to/the/socket")?; /// let mut buf = vec![0; 10]; - /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); + /// sock.recv(buf.as_mut_slice()).expect("`UnixDatagram::recv` should not fail"); /// Ok(()) /// } /// ``` @@ -523,7 +523,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); + /// sock.send_to(b"omelette au fromage", "/some/sock").expect("`UnixDatagram::send_to` should not fail"); /// Ok(()) /// } /// ``` @@ -561,7 +561,7 @@ impl UnixDatagram { /// let addr = bound.local_addr()?; /// /// let sock = UnixDatagram::unbound()?; - /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("send_to_addr function failed"); + /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("`UnixDatagram::send_to_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -595,8 +595,8 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/some/sock").expect("Couldn't connect"); - /// sock.send(b"omelette au fromage").expect("send_to function failed"); + /// sock.connect("/some/sock").expect("`UnixDatagram::connect` should not fail"); + /// sock.send(b"omelette au fromage").expect("`UnixDatagram` is not connected"); /// Ok(()) /// } /// ``` @@ -638,7 +638,7 @@ impl UnixDatagram { /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock") - /// .expect("send_vectored_with_ancillary_to function failed"); + /// .expect("`UnixDatagram::send_vectored_with_ancillary_to` should not fail"); /// Ok(()) /// } /// ``` @@ -686,7 +686,7 @@ impl UnixDatagram { /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); /// sock.send_vectored_with_ancillary(bufs, &mut ancillary) - /// .expect("send_vectored_with_ancillary function failed"); + /// .expect("`UnixDatagram::send_vectored_with_ancillary` should not fail"); /// Ok(()) /// } /// ``` @@ -719,7 +719,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); + /// .expect("`UnixDatagram::set_read_timeout` should not fail"); /// Ok(()) /// } /// ``` @@ -765,7 +765,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); + /// .expect("`UnixDatagram::set_write_timeout` should not fail"); /// Ok(()) /// } /// ``` @@ -804,7 +804,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); + /// .expect("`UnixDatagram::set_read_timeout` should not fail"); /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); /// Ok(()) /// } @@ -826,7 +826,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); + /// .expect("`UnixDatagram::set_write_timeout` should not fail"); /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); /// Ok(()) /// } @@ -846,7 +846,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); + /// sock.set_nonblocking(true).expect("`UnixDatagram::set_nonblocking` should not fail"); /// Ok(()) /// } /// ``` @@ -914,7 +914,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// sock.shutdown(Shutdown::Both).expect("`UnixDatagram::shutdown` should not fail"); /// Ok(()) /// } /// ``` @@ -941,7 +941,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let socket = UnixDatagram::bind("/tmp/sock")?; /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); + /// let len = socket.peek(&mut buf).expect("`UnixDatagram::peek` should not fail"); /// Ok(()) /// } /// ``` diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index b7f8d25a85ae5..793e2378e716d 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -200,7 +200,7 @@ impl UnixListener { /// /// fn main() -> std::io::Result<()> { /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// let listener_copy = listener.try_clone().expect("`UnixListener::try_clone` should not fail"); /// Ok(()) /// } /// ``` @@ -219,7 +219,7 @@ impl UnixListener { /// /// fn main() -> std::io::Result<()> { /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// let addr = listener.local_addr().expect("`UnixListener::local_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -244,7 +244,7 @@ impl UnixListener { /// /// fn main() -> std::io::Result<()> { /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// listener.set_nonblocking(true).expect("`UnixListener::set_nonblocking` should not fail"); /// Ok(()) /// } /// ``` diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 31a908dfe187e..dba49d0406bf1 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -199,7 +199,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// let sock_copy = socket.try_clone().expect("`UnixStream::try_clone` should not fail"); /// Ok(()) /// } /// ``` @@ -218,7 +218,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixStream::local_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -237,7 +237,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// let addr = socket.peer_addr().expect("`UnixStream::peer_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -257,7 +257,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// let peer_cred = socket.peer_cred().expect("`UnixStream::peer_cred` should not fail"); /// Ok(()) /// } /// ``` @@ -295,7 +295,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("`UnixStream::set_read_timeout` should not fail"); /// Ok(()) /// } /// ``` @@ -340,7 +340,7 @@ impl UnixStream { /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); + /// .expect("`UnixStream::connect` should not fail"); /// Ok(()) /// } /// ``` @@ -378,7 +378,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("`UnixStream::set_read_timeout` should not fail"); /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); /// Ok(()) /// } @@ -400,7 +400,7 @@ impl UnixStream { /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); + /// .expect("`UnixStream::set_write_timeout` should not fail"); /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); /// Ok(()) /// } @@ -420,7 +420,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// socket.set_nonblocking(true).expect("`UnixStream::set_nonblocking` should not fail"); /// Ok(()) /// } /// ``` @@ -493,7 +493,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// socket.shutdown(Shutdown::Both).expect("`UnixStream::shutdown` should not fail"); /// Ok(()) /// } /// ``` @@ -520,7 +520,7 @@ impl UnixStream { /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); + /// let len = socket.peek(&mut buf).expect("`UnixStream::peek` should not fail"); /// Ok(()) /// } /// ``` From bc0240cad290c98c0ee608b08754cf61c7069c9e Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Mon, 28 Sep 2026 13:21:26 -0400 Subject: [PATCH 17/71] Don't use the metadata based crate_hash for rustdoc runs --- compiler/rustc_middle/src/ty/context.rs | 2 +- tests/run-make/metrics-dir-crate-hash/lib.rs | 4 ++ tests/run-make/metrics-dir-crate-hash/main.rs | 6 +++ .../run-make/metrics-dir-crate-hash/rmake.rs | 51 +++++++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/metrics-dir-crate-hash/lib.rs create mode 100644 tests/run-make/metrics-dir-crate-hash/main.rs create mode 100644 tests/run-make/metrics-dir-crate-hash/rmake.rs diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5cd7322ced683..8da0603715ff9 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1135,7 +1135,7 @@ impl<'tcx> TyCtxt<'tcx> { | CrateType::Cdylib | CrateType::Sdylib => false, CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true, - }) + }) && !self.sess.opts.actually_rustdoc } pub fn needs_hir_hash(self) -> bool { diff --git a/tests/run-make/metrics-dir-crate-hash/lib.rs b/tests/run-make/metrics-dir-crate-hash/lib.rs new file mode 100644 index 0000000000000..e0673f64605f5 --- /dev/null +++ b/tests/run-make/metrics-dir-crate-hash/lib.rs @@ -0,0 +1,4 @@ +#![feature(ascii_char)] // random lib feature +#![feature(test_unstable_lint)] // random lang feature + +pub fn documented() {} diff --git a/tests/run-make/metrics-dir-crate-hash/main.rs b/tests/run-make/metrics-dir-crate-hash/main.rs new file mode 100644 index 0000000000000..844b362c9f179 --- /dev/null +++ b/tests/run-make/metrics-dir-crate-hash/main.rs @@ -0,0 +1,6 @@ +#![feature(ascii_char)] // random lib feature +#![feature(test_unstable_lint)] // random lang feature + +fn main() { + println!("foobar"); +} diff --git a/tests/run-make/metrics-dir-crate-hash/rmake.rs b/tests/run-make/metrics-dir-crate-hash/rmake.rs new file mode 100644 index 0000000000000..90e0b16859c04 --- /dev/null +++ b/tests/run-make/metrics-dir-crate-hash/rmake.rs @@ -0,0 +1,51 @@ +// Verifies that when a crate hash is required solely for a metrics dir, that +// crate hash is successfully generated, either by the fallback mechanism or +// metadata generation. +// See https://github.com/rust-lang/rust/issues/163426. + +//@ ignore-cross-compile + +use std::path::{Path, PathBuf}; + +use run_make_support::rfs::create_dir_all; +use run_make_support::{ + cwd, filename_contains, has_extension, run_in_tmpdir, rustc, rustdoc, shallow_find_files, +}; + +fn find_feature_usage_metrics>(dir: P) -> Vec { + shallow_find_files(dir, |path| { + filename_contains(path, "unstable_feature_usage") && has_extension(path, "json") + }) +} + +fn main() { + let metrics_dir = "metrics-rustdoc"; + create_dir_all(&metrics_dir); + rustdoc() + .input("lib.rs") + .out_dir("doc") + .env("RUST_BACKTRACE", "short") + .arg(format!("-Zmetrics-dir={}", metrics_dir)) + .run() + .assert_stderr_not_contains("internal compiler error"); + assert_eq!( + find_feature_usage_metrics(&metrics_dir).len(), + 1, + "rustdoc should dump exactly one metrics file" + ); + + let metrics_dir = "metrics-rustc"; + create_dir_all(&metrics_dir); + rustc() + .input("main.rs") + .crate_type("bin") + .env("RUST_BACKTRACE", "short") + .arg(format!("-Zmetrics-dir={}", metrics_dir)) + .run() + .assert_stderr_not_contains("internal compiler error"); + assert_eq!( + find_feature_usage_metrics(&metrics_dir).len(), + 1, + "rustc should dump exactly one metrics file" + ); +} From 588c189ee0b9783acd3cc07892f0ff2dd6445c23 Mon Sep 17 00:00:00 2001 From: malezjaa Date: Tue, 29 Sep 2026 16:46:45 +0200 Subject: [PATCH 18/71] expose Rc::is_unique --- library/alloc/src/rcs/rc.rs | 51 ++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/rcs/rc.rs b/library/alloc/src/rcs/rc.rs index 8cca09d1d4a8c..04e08c47fb587 100644 --- a/library/alloc/src/rcs/rc.rs +++ b/library/alloc/src/rcs/rc.rs @@ -1985,10 +1985,55 @@ impl Rc { unsafe { drop(Rc::from_raw_in(ptr, alloc)) }; } - /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to - /// this allocation. + /// Determine whether this is the unique reference to the underlying data. + /// + /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to the same allocation; + /// returns `false` otherwise. + /// + /// If this function returns `true`, it is safe to call [`get_mut_unchecked`] + /// immediately afterward. + /// + /// # Examples + /// + /// ``` + /// #![feature(arc_is_unique)] + /// + /// use std::rc::Rc; + /// + /// let x = Rc::new(3); + /// assert!(Rc::is_unique(&x)); + /// + /// let y = Rc::clone(&x); + /// assert!(!Rc::is_unique(&x)); + /// drop(y); + /// + /// // Weak references also count, because they could be upgraded at any time. + /// let z = Rc::downgrade(&x); + /// assert!(!Rc::is_unique(&x)); + /// ``` + /// + /// # Pointer invalidation + /// + /// This function will always return the same value as `Rc::get_mut(rc).is_some()`. However, + /// unlike that operation it does not produce any mutable references to the underlying data, + /// meaning no pointers to the data inside the `Rc` are invalidated by the call. Thus, the + /// following code is valid, even though it would be UB if it used `Rc::get_mut`: + /// + /// ``` + /// #![feature(arc_is_unique)] + /// + /// use std::rc::Rc; + /// + /// let rc = Rc::new(5); + /// let pointer: *const i32 = &*rc; + /// assert!(Rc::is_unique(&rc)); + /// assert_eq!(unsafe { *pointer }, 5); + /// ``` + /// + /// [`get_mut_unchecked`]: Self::get_mut_unchecked #[inline] - fn is_unique(this: &Self) -> bool { + #[unstable(feature = "arc_is_unique", issue = "138938")] + pub fn is_unique(this: &Self) -> bool { Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 } From 0883f590731023f43c3108aedece437285a5e44e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 29 Sep 2026 16:52:18 +0200 Subject: [PATCH 19/71] x86_64: cleanup `reg_component` --- compiler/rustc_target/src/callconv/x86_64.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 5ab2834807d67..57e997f45d4c5 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -131,17 +131,16 @@ where } fn reg_component(cls: &[Option], i: &mut usize, size: Size) -> Option { - if *i >= cls.len() { + let Some(Some(class)) = cls.get(*i) else { return None; - } + }; - match cls[*i] { - None => None, - Some(Class::Int) => { + match class { + Class::Int => { *i += 1; Some(if size.bytes() < 8 { Reg { kind: RegKind::Integer, size } } else { Reg::i64() }) } - Some(Class::Sse) => { + Class::Sse => { let vec_len = 1 + cls[*i + 1..].iter().take_while(|&&c| c == Some(Class::SseUp)).count(); *i += vec_len; @@ -154,7 +153,7 @@ fn reg_component(cls: &[Option], i: &mut usize, size: Size) -> Option unreachable!("reg_component: unhandled class {:?}", c), + c => unreachable!("reg_component: unhandled class {:?}", c), } } From 7f5fdabc90944de7d2d38fee3d43f6ad9bbd17db Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 26 Sep 2026 13:54:41 +0200 Subject: [PATCH 20/71] x86 callconv: refactor into separate classify methods --- compiler/rustc_target/src/callconv/x86.rs | 207 ++++++++++++---------- 1 file changed, 112 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 3476f41e3bc75..6f88706dbf4b7 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -2,7 +2,7 @@ use rustc_abi::{ AddressSpace, Align, BackendRepr, Float, HasDataLayout, Primitive, Reg, RegKind, TyAndLayout, }; -use crate::callconv::{ArgAttribute, FnAbi, PassMode, TyAbiInterface}; +use crate::callconv::{ArgAbi, ArgAttribute, FnAbi, PassMode, TyAbiInterface}; use crate::spec::{HasTargetSpec, RustcAbi}; /// Is this a struct with a single float field? @@ -37,65 +37,136 @@ where } } -#[derive(PartialEq)] +#[derive(Clone, Copy, PartialEq)] pub(crate) enum Flavor { General, FastcallOrVectorcall, } +#[derive(Clone, Copy)] pub(crate) struct X86Options { pub flavor: Flavor, pub regparm: Option, pub reg_struct_return: bool, } -pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options) +fn classify_ret<'a, Ty, C>(cx: &C, opts: X86Options, ret: &mut ArgAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - if !fn_abi.ret.is_ignore() { - if fn_abi.ret.layout.is_aggregate() && fn_abi.ret.layout.is_sized() { - // Returning a structure. Most often, this will use - // a hidden first argument. On some platforms, though, - // small structs are returned as integers. - // - // Some links: - // https://www.angelcode.com/dev/callconv/callconv.html - // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp - let t = cx.target_spec(); - if let Some(Float::F16) = fn_abi.ret.layout.complex_float(cx) { - // `_Complex _Float16` is returned as `<2 x half>`. - let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) }; - fn_abi.ret.cast_to(Reg { kind, size: fn_abi.ret.layout.size }); - } else if t.abi_return_struct_as_int - || opts.reg_struct_return - || fn_abi.ret.layout.is_complex_number(cx) - { - // According to Clang, everyone but MSVC returns single-element - // float aggregates directly in a floating-point register. - if is_single_fp_element(fn_abi.ret.layout, cx) { - match fn_abi.ret.layout.size.bytes() { - 2 => fn_abi.ret.cast_to(Reg::f16()), - 4 => fn_abi.ret.cast_to(Reg::f32()), - 8 => fn_abi.ret.cast_to(Reg::f64()), - _ => fn_abi.ret.make_indirect(), - } - } else { - match fn_abi.ret.layout.size.bytes() { - 1 => fn_abi.ret.cast_to(Reg::i8()), - 2 => fn_abi.ret.cast_to(Reg::i16()), - 4 => fn_abi.ret.cast_to(Reg::i32()), - 8 => fn_abi.ret.cast_to(Reg::i64()), - _ => fn_abi.ret.make_indirect(), - } + if ret.layout.is_aggregate() && ret.layout.is_sized() { + // Returning a structure. Most often, this will use + // a hidden first argument. On some platforms, though, + // small structs are returned as integers. + // + // Some links: + // https://www.angelcode.com/dev/callconv/callconv.html + // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp + let t = cx.target_spec(); + if let Some(Float::F16) = ret.layout.complex_float(cx) { + // `_Complex _Float16` is returned as `<2 x half>`. + let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) }; + ret.cast_to(Reg { kind, size: ret.layout.size }); + } else if t.abi_return_struct_as_int + || opts.reg_struct_return + || ret.layout.is_complex_number(cx) + { + // According to Clang, everyone but MSVC returns single-element + // float aggregates directly in a floating-point register. + if is_single_fp_element(ret.layout, cx) { + match ret.layout.size.bytes() { + 2 => ret.cast_to(Reg::f16()), + 4 => ret.cast_to(Reg::f32()), + 8 => ret.cast_to(Reg::f64()), + _ => ret.make_indirect(), } } else { - fn_abi.ret.make_indirect(); + match ret.layout.size.bytes() { + 1 => ret.cast_to(Reg::i8()), + 2 => ret.cast_to(Reg::i16()), + 4 => ret.cast_to(Reg::i32()), + 8 => ret.cast_to(Reg::i64()), + _ => ret.make_indirect(), + } } } else { - fn_abi.ret.extend_integer_width_to(32); + ret.make_indirect(); + } + } else { + ret.extend_integer_width_to(32); + } +} + +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + let t = cx.target_spec(); + let align_4 = Align::from_bytes(4).unwrap(); + let align_16 = Align::from_bytes(16).unwrap(); + + if arg.layout.is_aggregate() { + // We need to compute the alignment of the `byval` argument. The rules can be found in + // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized + // here, they are: + // + // 1. If the natural alignment of the type is <= 4, the alignment is 4. + // + // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment. + // This doesn't matter here because we only pass aggregates via `byval`, not vectors. + // + // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector + // type is 16. + // + // 4. If none of these conditions are true, the alignment is 4. + + fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool + where + Ty: TyAbiInterface<'a, C> + Copy, + { + match layout.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. } => false, + BackendRepr::SimdVector { .. } => true, + BackendRepr::Memory { .. } => { + for i in 0..layout.fields.count() { + if contains_vector(cx, layout.field(cx, i)) { + return true; + } + } + false + } + BackendRepr::SimdScalableVector { .. } => { + panic!("scalable vectors are unsupported") + } + } } + + let byval_align = if arg.layout.align.abi < align_4 { + // (1.) + align_4 + } else if t.is_like_darwin && contains_vector(cx, arg.layout) { + // (3.) + align_16 + } else { + // (4.) + align_4 + }; + + arg.pass_by_stack_offset(Some(byval_align)); + } else { + arg.extend_integer_width_to(32); + } +} + +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if !fn_abi.ret.is_ignore() { + classify_ret(cx, opts, &mut fn_abi.ret); } for arg in fn_abi.args.iter_mut() { @@ -108,61 +179,7 @@ where continue; } - let t = cx.target_spec(); - let align_4 = Align::from_bytes(4).unwrap(); - let align_16 = Align::from_bytes(16).unwrap(); - - if arg.layout.is_aggregate() { - // We need to compute the alignment of the `byval` argument. The rules can be found in - // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized - // here, they are: - // - // 1. If the natural alignment of the type is <= 4, the alignment is 4. - // - // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment. - // This doesn't matter here because we only pass aggregates via `byval`, not vectors. - // - // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector - // type is 16. - // - // 4. If none of these conditions are true, the alignment is 4. - - fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool - where - Ty: TyAbiInterface<'a, C> + Copy, - { - match layout.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. } => false, - BackendRepr::SimdVector { .. } => true, - BackendRepr::Memory { .. } => { - for i in 0..layout.fields.count() { - if contains_vector(cx, layout.field(cx, i)) { - return true; - } - } - false - } - BackendRepr::SimdScalableVector { .. } => { - panic!("scalable vectors are unsupported") - } - } - } - - let byval_align = if arg.layout.align.abi < align_4 { - // (1.) - align_4 - } else if t.is_like_darwin && contains_vector(cx, arg.layout) { - // (3.) - align_16 - } else { - // (4.) - align_4 - }; - - arg.pass_by_stack_offset(Some(byval_align)); - } else { - arg.extend_integer_width_to(32); - } + classify_arg(cx, arg); } fill_inregs(cx, fn_abi, opts, false); From 457af24e1eec19ab240ecfe2047fb2b86bb03b71 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 26 Sep 2026 14:04:40 +0200 Subject: [PATCH 21/71] x86 callconv: put regparam into `Flavor::General` --- compiler/rustc_target/src/callconv/mod.rs | 10 +++++----- compiler/rustc_target/src/callconv/x86.rs | 21 ++++++++++++++------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index edc23b6c50b45..487de8f54ee62 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -733,17 +733,17 @@ impl<'a, Ty> FnAbi<'a, Ty> { let spec = cx.target_spec(); match &spec.arch { Arch::X86 => { - let (flavor, regparm) = match abi { + let flavor = match abi { ExternAbi::Fastcall { .. } | ExternAbi::Vectorcall { .. } => { - (x86::Flavor::FastcallOrVectorcall, None) + x86::Flavor::FastcallOrVectorcall } ExternAbi::C { .. } | ExternAbi::Cdecl { .. } | ExternAbi::Stdcall { .. } => { - (x86::Flavor::General, cx.x86_abi_opt().regparm) + x86::Flavor::General { regparam: cx.x86_abi_opt().regparm } } - _ => (x86::Flavor::General, None), + _ => x86::Flavor::General { regparam: None }, }; let reg_struct_return = cx.x86_abi_opt().reg_struct_return; - let opts = x86::X86Options { flavor, regparm, reg_struct_return }; + let opts = x86::X86Options { flavor, reg_struct_return }; if spec.is_like_msvc { x86_win32::compute_abi_info(cx, self, opts); } else { diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 6f88706dbf4b7..efe88bff6504c 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -39,14 +39,13 @@ where #[derive(Clone, Copy, PartialEq)] pub(crate) enum Flavor { - General, + General { regparam: Option }, FastcallOrVectorcall, } #[derive(Clone, Copy)] pub(crate) struct X86Options { pub flavor: Flavor, - pub regparm: Option, pub reg_struct_return: bool, } @@ -193,9 +192,6 @@ pub(crate) fn fill_inregs<'a, Ty, C>( ) where Ty: TyAbiInterface<'a, C> + Copy, { - if opts.flavor != Flavor::FastcallOrVectorcall && opts.regparm.is_none_or(|x| x == 0) { - return; - } // Mark arguments as InReg like clang does it, // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall. @@ -205,8 +201,19 @@ pub(crate) fn fill_inregs<'a, Ty, C>( // IsSoftFloatABI is only set to true on ARM platforms, // which in turn can't be x86? - // 2 for fastcall/vectorcall, regparm limited by 3 otherwise - let mut free_regs = opts.regparm.unwrap_or(2).into(); + // The number of registers available for argument passing. + // + // An `extern "fastcall"` and `extern "vectorcall"` function always have 2 registers available. + // Otherwise the `regparam` count (in the range 0..=3) determines the number of available + // registers. If unspecified, no registers are used for argument passing. + let mut free_regs = match opts.flavor { + Flavor::FastcallOrVectorcall => 2, + Flavor::General { regparam } => u64::from(regparam.unwrap_or(0)), + }; + + if free_regs == 0 { + return; + } // For types generating PassMode::Cast, InRegs will not be set. // Maybe, this is a FIXME From 14d09db59484630e56870e09a094254890b4b27f Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 29 Sep 2026 18:38:13 +0200 Subject: [PATCH 22/71] cycle handling: mirror old solver --- .../src/solve/eval_ctxt/mod.rs | 87 ++++++++----------- .../rustc_next_trait_solver/src/solve/mod.rs | 4 +- .../src/solve/normalizes_to.rs | 4 +- .../src/solve/project_goals/free_alias.rs | 4 +- .../src/solve/project_goals/inherent.rs | 4 +- .../src/solve/project_goals/mod.rs | 2 +- .../src/solve/project_goals/opaque_types.rs | 7 +- .../src/solve/fulfill/derive_errors.rs | 2 +- compiler/rustc_type_ir/src/solve/mod.rs | 24 ++--- .../sized-hierarchy/overflow.current.stderr | 12 +-- tests/ui/sized-hierarchy/overflow.next.stderr | 29 +++++++ tests/ui/sized-hierarchy/overflow.rs | 7 +- ...inductive-step-needed-trait.current.stderr | 6 +- ...-coinductive-step-needed-trait.next.stderr | 15 ++++ .../only-one-coinductive-step-needed-trait.rs | 4 +- ...one-coinductive-step-needed.current.stderr | 4 +- ...ly-one-coinductive-step-needed.next.stderr | 43 +++++++++ .../only-one-coinductive-step-needed.rs | 11 ++- 18 files changed, 166 insertions(+), 103 deletions(-) create mode 100644 tests/ui/sized-hierarchy/overflow.next.stderr create mode 100644 tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.next.stderr create mode 100644 tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.next.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 c841845392429..40febd26806a6 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 @@ -63,6 +63,8 @@ enum CurrentGoalKind { /// These are currently the only goals whose impl where-clauses are considered to be /// productive steps. CoinductiveTrait, + /// A `ProjectionGoal`. These are temporarily special wrt to cycle handling. + Projection, // FIXME: Consider renaming `PredicateKind::NormalizesTo` to match with this /// Unlike other goals, `NormalizesTo` goals aren't independent goals but just implementation /// details for handling projections of associated terms. When we encounter a `Projection` goal @@ -89,6 +91,7 @@ impl CurrentGoalKind { CurrentGoalKind::Misc } } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => CurrentGoalKind::Projection, ty::PredicateKind::NormalizesTo(_) => { CurrentGoalKind::ProjectionComputeAssocTermCandidate } @@ -428,46 +431,29 @@ where } /// Computes the `PathKind` for the step from the current goal to the - /// nested goal required due to `source`. + /// nested goal. See #136824 for a more detailed reasoning for this why we care about + /// the step from a goal to its nested goals. /// - /// See #136824 for a more detailed reasoning for this behavior. We - /// consider cycles to be coinductive if they 'step into' a where-clause - /// of a coinductive trait. We will likely extend this function in the future - /// and will need to clearly document it in the rustc-dev-guide before - /// stabilization. - pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind { - match source { - // We treat these goals as unknown for now. It is likely that most miscellaneous - // nested goals will be converted to an inductive variant in the future. - // - // Having unknown cycles is always the safer option, as changing that to either - // succeed or hard error is backwards compatible. If we incorrectly treat a cycle - // as inductive even though it should not be, it may be unsound during coherence and - // fixing it may cause inference breakage or introduce ambiguity. - GoalSource::Misc => PathKind::Unknown, - GoalSource::NormalizeGoal(path_kind) => path_kind, - 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, - // We probably want to make all traits coinductive in the future, - // so we treat cycles involving where-clauses of not-yet coinductive - // traits as ambiguous for now. - CurrentGoalKind::Misc | CurrentGoalKind::ProjectionComputeAssocTermCandidate => { - 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. - // - // FIXME(-Znext-solver=coinductive): For now we treat all inductive cycles as - // `Unknown`. See the comment in `fn initial_provisional_result`. - GoalSource::TypeRelating => PathKind::Unknown, - // These goal sources are likely unproductive and can be changed to - // `PathKind::Inductive`. Keeping them as unknown until we're confident - // about this and have an example where it is necessary. - GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown, + /// For now we're entirely ignoring the reason why the current goal depends on the + /// nested goal and instead only depend on the current goal itself. This closely + /// matches the old solver. This is something we'll likely improve as we go forward + /// afterwards. + // FIXME(-Znext-solver=coinductive): Nothing interesting going on here right now + // and we're ignoring the goal source. We should change this going forward. + pub(super) fn step_kind_to_nested(&self, _source: GoalSource) -> PathKind { + match self.current_goal_kind { + // We currently consider a cycle involving a trait goal for a coinductive + // trait as coinductive as long as it otherwise only includes normalization. + CurrentGoalKind::CoinductiveTrait => PathKind::Coinductive, + // We do need to treat cycles involving only coinductive trait goals + // and normalization as coinductive due to trait-system-refactor-initiative#10. + CurrentGoalKind::ProjectionComputeAssocTermCandidate | CurrentGoalKind::Projection => { + PathKind::Unknown + } + // We probably want to make all traits coinductive in the future, + // so we treat cycles involving where-clauses of not-yet coinductive + // traits as ambiguous for now. + CurrentGoalKind::Misc => PathKind::ForcedAmbiguity, } } @@ -771,7 +757,7 @@ where let (goal, opaque_types) = self.delegate.deeply_resolve_via_unification_table((goal, opaque_types)); let typing_mode = self.typing_mode(); - let step_kind = self.step_kind_for_source(source); + let step_kind = self.step_kind_to_nested(source); let tracing_span = tracing::span!( Level::DEBUG, @@ -1109,11 +1095,8 @@ where source: GoalSource, mut goal: Goal, ) -> Result<(), NoSolutionOrRerunNonErased> { - goal.predicate = self.normalize( - GoalSource::NormalizeGoal(self.step_kind_for_source(source)), - goal.param_env, - ty::Unnormalized::new_wip(goal.predicate), - )?; + goal.predicate = + self.normalize(goal.param_env, ty::Unnormalized::new_wip(goal.predicate))?; self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); if let Some(GoalEvaluation { goal, certainty, has_changed: _, stalled_on }) = @@ -1339,10 +1322,12 @@ where let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?; for &goal in goals.iter() { let source = match goal.predicate.kind().skip_binder() { - ty::PredicateKind::Subtype { .. } - | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => { - GoalSource::TypeRelating + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => { + GoalSource::Normalization } + // FIXME(-Znext-solver=coinductive): subtyping goals should + // likely be unproductive + ty::PredicateKind::Subtype { .. } => GoalSource::Misc, // FIXME(-Znext-solver=coinductive): should these WF goals also be unproductive? ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => GoalSource::Misc, p => unreachable!("unexpected nested goal in `relate`: {p:?}"), @@ -1519,9 +1504,7 @@ where match self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)? {} } - self.delegate.evaluate_const(param_env, alias_const, |ty| { - self.normalize(GoalSource::Misc, param_env, ty) - }) + self.delegate.evaluate_const(param_env, alias_const, |ty| self.normalize(param_env, ty)) } pub(super) fn evaluate_const_and_instantiate_projection_term( @@ -1803,7 +1786,6 @@ where pub(super) fn normalize>( &mut self, - source: GoalSource, param_env: I::ParamEnv, value: ty::Unnormalized, ) -> Result { @@ -1819,6 +1801,7 @@ where let infer_term = self.next_term_infer_of_alias_kind(alias_term); let pred = ty::ProjectionClause { projection_term: alias_term, term: infer_term }; let goal = Goal::new(self.cx(), param_env, pred); + let source = GoalSource::Normalization; self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); let GoalEvaluation { goal, certainty, has_changed: _, stalled_on } = self.evaluate_goal(source, goal, None)?; diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index dddc78373b1b5..9ecb7619d7c93 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -90,7 +90,7 @@ where goal: Goal>, ) -> QueryResultOrRerunNonErased { let ty::OutlivesClause(ty, lt) = goal.predicate; - let ty = self.normalize(GoalSource::Misc, goal.param_env, ty::Unnormalized::new_wip(ty))?; + let ty = self.normalize(goal.param_env, ty::Unnormalized::new_wip(ty))?; // The normalized type can still contain non-rigid higher ranked aliases if their // normalization ends up with ambiguity. Or we have non-rigid aliases inside rigid ones. @@ -405,7 +405,7 @@ where ); // We normalize the self type to be able to relate it with // types from candidates. - self.add_goal(GoalSource::TypeRelating, projection_goal)?; + self.add_goal(GoalSource::Normalization, projection_goal)?; self.try_evaluate_added_goals()?; Ok(self.deeply_resolve_ignoring_regions(normalized_term)) } else { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index 388b334ccf618..4203ae8c509cc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -439,7 +439,7 @@ where let term = match target_item_kind { ty::AliasTermKind::ProjectionTy { .. } => { let t = cx.type_of(target_item_def_id).instantiate(cx, target_args); - let t = ecx.normalize(GoalSource::Misc, goal.param_env, t)?; + let t = ecx.normalize(goal.param_env, t)?; t.into() } ty::AliasTermKind::ProjectionConst { def_id } @@ -447,7 +447,7 @@ where cx.const_of_item(ty::AliasConstKind::Projection { def_id }) => { let c = c.instantiate(cx, target_args); - let c = ecx.normalize(GoalSource::Misc, goal.param_env, c)?; + let c = ecx.normalize(goal.param_env, c)?; c.into() } ty::AliasTermKind::ProjectionConst { .. } => { diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs index 4481e1bc144ac..dfcc89b91a4f2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs @@ -34,14 +34,14 @@ where let actual = match free_alias.kind { ty::AliasTermKind::FreeTy { def_id } => { let free = cx.type_of(def_id.into()).instantiate(cx, free_alias.args); - let free = self.normalize(GoalSource::Misc, goal.param_env, free)?; + let free = self.normalize(goal.param_env, free)?; free.into() } ty::AliasTermKind::FreeConst { def_id } if let Some(free) = cx.const_of_item(ty::AliasConstKind::Free { def_id }) => { let free = free.instantiate(cx, free_alias.args); - let free = self.normalize(GoalSource::Misc, goal.param_env, free)?; + let free = self.normalize(goal.param_env, free)?; free.into() } diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs index d519d1e538f1a..45ece5a0589fb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs @@ -45,7 +45,7 @@ where let normalized: I::Term = match inherent_kind { ty::AliasTermKind::InherentTy { def_id } => { let inherent = cx.type_of(def_id.into()).instantiate(cx, inherent_args); - let inherent = self.normalize(GoalSource::Misc, goal.param_env, inherent)?; + let inherent = self.normalize(goal.param_env, inherent)?; inherent.into() } ty::AliasTermKind::InherentConstImpl { def_id } @@ -53,7 +53,7 @@ where cx.const_of_item(ty::AliasConstKind::InherentImpl { def_id }) => { let inherent = inherent.instantiate(cx, inherent_args); - let normalized_ct = self.normalize(GoalSource::Misc, goal.param_env, inherent)?; + let normalized_ct = self.normalize(goal.param_env, inherent)?; let normalized = normalized_ct.into(); let term = ty::AliasTerm::new_from_args(cx, inherent_kind, inherent_args); self.push_const_arg_has_type_goal(goal.param_env, term, normalized)?; diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs index 9d6b8875071ba..f6521e579d722 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs @@ -69,7 +69,7 @@ where let ( NestedNormalizationGoals(nested_goals), GoalEvaluation { goal: _, certainty, stalled_on: _, has_changed: _ }, - ) = self.evaluate_goal_raw(GoalSource::TypeRelating, normalizes_to)?; + ) = self.evaluate_goal_raw(GoalSource::Normalization, normalizes_to)?; trace!(?nested_goals); diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs index 2f56056449779..048c8bb45361b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs @@ -99,8 +99,7 @@ where _ => re, }) }); - let actual = - self.normalize(GoalSource::Misc, goal.param_env, actual)?; + let actual = self.normalize(goal.param_env, actual)?; self.eq(goal.param_env, expected, actual)?; } TypingMode::Coherence @@ -145,7 +144,7 @@ where _ => re, }) }); - let actual = self.normalize(GoalSource::Misc, goal.param_env, actual)?; + let actual = self.normalize(goal.param_env, actual)?; self.eq(goal.param_env, expected, actual)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into) @@ -154,7 +153,7 @@ where TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => { // FIXME: Add an assertion that opaque type storage is empty. let actual = cx.type_of(def_id.into()).instantiate(cx, opaque_ty.args); - let actual = self.normalize(GoalSource::Misc, goal.param_env, actual)?; + let actual = self.normalize(goal.param_env, actual)?; self.eq(goal.param_env, expected, actual)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index d30421a762ea9..5ccd7ff7ef55b 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -510,7 +510,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { match (child_mode, nested_goal.source()) { ( ChildMode::Trait(_) | ChildMode::Host(_), - GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_), + GoalSource::Misc | GoalSource::Normalization, ) => { continue; } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index c6d88bb6603de..5d1472d5941f2 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -16,7 +16,6 @@ use tracing::debug; use crate::inherent::*; use crate::lang_items::SolverTraitLangItem; use crate::region_constraint::RegionConstraint; -use crate::search_graph::PathKind; use crate::{ self as ty, Canonical, CanonicalVarValues, CantBeErased, Const, ConstVid, FloatVid, GenericArgKind, InferConst, IntVid, Interner, TermKind, TyVid, TypingMode, Upcast, @@ -411,22 +410,15 @@ impl Goal { /// Why a specific goal has to be proven. /// -/// This is necessary as we treat nested goals different depending on -/// their source. This is used to decide whether a cycle is coinductive. -/// See the documentation of `EvalCtxt::step_kind_for_source` for more details -/// about this. +/// This is used by proof tree visitors, especially for diagnostics purposes. /// -/// It is also used by proof tree visitors, e.g. for diagnostics purposes. +/// FIXME(-Znext-solver=coinductive): This will also matter in the future when +/// deciding whether a step in a cycle is coinductive. We're currently still +/// matching the old solver behavior here for now, so the `GoalSource` is ignored. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub enum GoalSource { Misc, - /// A nested goal required to prove that types are equal/subtypes. - /// This is always an unproductive step. - /// - /// This is also used for all `NormalizesTo` goals as we they are used - /// to relate types in `AliasRelate`. - TypeRelating, /// We're proving a where-bound of an impl. ImplWhereBound, /// Const conditions that need to hold for `[const]` alias bounds to hold. @@ -438,12 +430,8 @@ pub enum GoalSource { /// 2. for rigid projections's trait goal, /// 3. for GAT where clauses. AliasWellFormed, - /// In case normalizing aliases in nested goals cycles, eagerly normalizing these - /// aliases in the context of the parent may incorrectly change the cycle kind. - /// Normalizing aliases in goals therefore tracks the original path kind for this - /// nested goal. See the comment of the `ReplaceAliasWithInfer` visitor for more - /// details. - NormalizeGoal(PathKind), + /// Normalizing happens in the current context and is unproductive by itself. + Normalization, } #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, Goal)] diff --git a/tests/ui/sized-hierarchy/overflow.current.stderr b/tests/ui/sized-hierarchy/overflow.current.stderr index 9853be2a7f8e0..3573ee48db57c 100644 --- a/tests/ui/sized-hierarchy/overflow.current.stderr +++ b/tests/ui/sized-hierarchy/overflow.current.stderr @@ -1,11 +1,11 @@ error[E0275]: overflow evaluating the requirement `Element: MetaSized` - --> $DIR/overflow.rs:17:16 + --> $DIR/overflow.rs:15:16 | LL | struct Element(> as ParseTokens>::Output); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required for `Box` to implement `ParseTokens` - --> $DIR/overflow.rs:13:31 + --> $DIR/overflow.rs:11:31 | LL | impl ParseTokens for Box { | ------ ^^^^^^^^^^^ ^^^^^^ @@ -15,25 +15,25 @@ LL | impl ParseTokens for Box { = note: required for `Box>` to implement `ParseTokens` error[E0275]: overflow evaluating the requirement `Box: ParseTokens` - --> $DIR/overflow.rs:19:22 + --> $DIR/overflow.rs:18:22 | LL | impl ParseTokens for Element { | ^^^^^^^ | note: required for `Box>` to implement `ParseTokens` - --> $DIR/overflow.rs:13:31 + --> $DIR/overflow.rs:11:31 | LL | impl ParseTokens for Box { | ----------- ^^^^^^^^^^^ ^^^^^^ | | | unsatisfied trait bound introduced here note: required because it appears within the type `Element` - --> $DIR/overflow.rs:17:8 + --> $DIR/overflow.rs:15:8 | LL | struct Element(> as ParseTokens>::Output); | ^^^^^^^ note: required by a bound in `ParseTokens` - --> $DIR/overflow.rs:10:1 + --> $DIR/overflow.rs:8:1 | LL | / trait ParseTokens { LL | | type Output; diff --git a/tests/ui/sized-hierarchy/overflow.next.stderr b/tests/ui/sized-hierarchy/overflow.next.stderr new file mode 100644 index 0000000000000..69842a298f87f --- /dev/null +++ b/tests/ui/sized-hierarchy/overflow.next.stderr @@ -0,0 +1,29 @@ +error[E0275]: overflow evaluating the requirement `> as ParseTokens>::Output == _` + --> $DIR/overflow.rs:15:16 + | +LL | struct Element(> as ParseTokens>::Output); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating whether `> as ParseTokens>::Output` is well-formed + --> $DIR/overflow.rs:15:16 + | +LL | struct Element(> as ParseTokens>::Output); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `Element: MetaSized` + --> $DIR/overflow.rs:18:22 + | +LL | impl ParseTokens for Element { + | ^^^^^^^ + | +note: required by a bound in `ParseTokens` + --> $DIR/overflow.rs:8:1 + | +LL | / trait ParseTokens { +LL | | type Output; +LL | | } + | |_^ required by this bound in `ParseTokens` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/sized-hierarchy/overflow.rs b/tests/ui/sized-hierarchy/overflow.rs index 31c2ca8a49171..f69f56ef898e2 100644 --- a/tests/ui/sized-hierarchy/overflow.rs +++ b/tests/ui/sized-hierarchy/overflow.rs @@ -1,8 +1,6 @@ //@ compile-flags: --crate-type=lib //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) -//@[current] check-fail -//@[next] check-pass //@[next] compile-flags: -Znext-solver use std::marker::PhantomData; @@ -15,8 +13,9 @@ impl ParseTokens for Box { } struct Element(> as ParseTokens>::Output); -//[current]~^ ERROR: overflow +//~^ ERROR: overflow +//[next]~| ERROR: overflow impl ParseTokens for Element { -//[current]~^ ERROR: overflow +//~^ ERROR: overflow type Output = (); } diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.current.stderr b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.current.stderr index 89b8b53c3f4d9..d6cd080cbfd0b 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.current.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.current.stderr @@ -1,18 +1,18 @@ error[E0275]: overflow evaluating the requirement `u32: SendIndir>` - --> $DIR/only-one-coinductive-step-needed-trait.rs:24:5 + --> $DIR/only-one-coinductive-step-needed-trait.rs:25:5 | LL | is_send::>(); | ^^^^^^^^^^^^^^^^^^^^^ | note: required for `Foo` to implement `Send` - --> $DIR/only-one-coinductive-step-needed-trait.rs:17:35 + --> $DIR/only-one-coinductive-step-needed-trait.rs:18:35 | LL | unsafe impl>> Send for Foo {} | ----------------- ^^^^ ^^^^^^ | | | unsatisfied trait bound introduced here note: required by a bound in `is_send` - --> $DIR/only-one-coinductive-step-needed-trait.rs:22:15 + --> $DIR/only-one-coinductive-step-needed-trait.rs:23:15 | LL | fn is_send() {} | ^^^^ required by this bound in `is_send` diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.next.stderr b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.next.stderr new file mode 100644 index 0000000000000..40ae37e495204 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.next.stderr @@ -0,0 +1,15 @@ +error[E0275]: overflow evaluating the requirement `Foo: Send` + --> $DIR/only-one-coinductive-step-needed-trait.rs:25:15 + | +LL | is_send::>(); + | ^^^^^^^^ + | +note: required by a bound in `is_send` + --> $DIR/only-one-coinductive-step-needed-trait.rs:23:15 + | +LL | fn is_send() {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.rs b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.rs index 294156869284a..a8d23129fb87c 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.rs +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.rs @@ -1,7 +1,6 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] check-pass // #136824 changed cycles to be coinductive if they have at least // one productive step, causing this test to pass with the new solver. @@ -12,6 +11,8 @@ // - `Foo: Send` cycle // // The old solver treats this cycle as inductive due to the `T: SendIndir` step. +// We later changed the new solver to temporarily be closer to the old solver +// again, so this now errors with both solvers. struct Foo(T); unsafe impl>> Send for Foo {} @@ -23,4 +24,5 @@ fn is_send() {} fn main() { is_send::>(); //[current]~^ ERROR overflow evaluating the requirement `u32: SendIndir>` + //[next]~^^ ERROR overflow evaluating the requirement `Foo: Send` } diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.current.stderr b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.current.stderr index ec21987805869..1d7916f32b1db 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.current.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.current.stderr @@ -1,11 +1,11 @@ error[E0275]: overflow evaluating the requirement `Foo: SendIndir` - --> $DIR/only-one-coinductive-step-needed.rs:17:15 + --> $DIR/only-one-coinductive-step-needed.rs:18:15 | LL | struct Foo( as Trait>::Assoc); | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: required for `Foo` to implement `Trait` - --> $DIR/only-one-coinductive-step-needed.rs:26:20 + --> $DIR/only-one-coinductive-step-needed.rs:29:20 | LL | impl Trait for T { | --------- ^^^^^ ^ diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.next.stderr b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.next.stderr new file mode 100644 index 0000000000000..071945d760345 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.next.stderr @@ -0,0 +1,43 @@ +error[E0275]: overflow evaluating the requirement ` as Trait>::Assoc == _` + --> $DIR/only-one-coinductive-step-needed.rs:18:15 + | +LL | struct Foo( as Trait>::Assoc); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating whether ` as Trait>::Assoc` is well-formed + --> $DIR/only-one-coinductive-step-needed.rs:18:15 + | +LL | struct Foo( as Trait>::Assoc); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `Foo: Send` + --> $DIR/only-one-coinductive-step-needed.rs:36:15 + | +LL | is_send::>(); + | ^^^^^^^^ + | +note: required by a bound in `is_send` + --> $DIR/only-one-coinductive-step-needed.rs:33:15 + | +LL | fn is_send() {} + | ^^^^ required by this bound in `is_send` + +error[E0275]: overflow evaluating the requirement `Foo: Sized` + --> $DIR/only-one-coinductive-step-needed.rs:36:15 + | +LL | is_send::>(); + | ^^^^^^^^ + | +note: required by an implicit `Sized` bound in `is_send` + --> $DIR/only-one-coinductive-step-needed.rs:33:12 + | +LL | fn is_send() {} + | ^ required by the implicit `Sized` requirement on this type parameter in `is_send` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn is_send() {} + | ++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.rs b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.rs index e41f7d7f3ceb3..9a13c0e945339 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.rs +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.rs @@ -1,7 +1,6 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] check-pass // #136824 changed cycles to be coinductive if they have at least // one productive step, causing this test to pass with the new solver. @@ -12,10 +11,14 @@ // - `Foo: SendIndir`, via impl requires // - `Foo: Send` cycle // -// The old solver treats this cycle as inductive due to the `Foo: SendIndir` step. +// The old solver treats this cycle as inductive due to the `Foo: SendIndir` step. We've +// since changed the new solver to more closely match the old one here, also +// resulting in an inductive cycle for now. struct Foo( as Trait>::Assoc); -//[current]~^ ERROR overflow evaluating the requirement `Foo: SendIndir` +//[current]~^ ERROR: overflow evaluating the requirement `Foo: SendIndir` +//[next]~^^ ERROR: overflow evaluating the requirement ` as Trait>::Assoc == _` +//[next]~| ERROR: overflow evaluating whether ` as Trait>::Assoc` is well-formed trait SendIndir {} impl SendIndir for T {} @@ -31,4 +34,6 @@ fn is_send() {} fn main() { is_send::>(); + //[next]~^ ERROR: overflow evaluating the requirement `Foo: Send` + //[next]~| ERROR: overflow evaluating the requirement `Foo: Sized` } From 36358d0b2a1acaa99008ca13d1e41eac4adb1009 Mon Sep 17 00:00:00 2001 From: eleocraft Date: Tue, 29 Sep 2026 20:20:16 +0200 Subject: [PATCH 23/71] gating f16 and f128 tests behind target_has_reliable --- library/coretests/tests/num/clamp_magnitude.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/coretests/tests/num/clamp_magnitude.rs b/library/coretests/tests/num/clamp_magnitude.rs index 5bccc4ad45e20..fdb605780a2c6 100644 --- a/library/coretests/tests/num/clamp_magnitude.rs +++ b/library/coretests/tests/num/clamp_magnitude.rs @@ -208,6 +208,7 @@ macro_rules! check_float_clamp { } #[test] +#[cfg(target_has_reliable_f16)] fn test_clamp_magnitude_f16() { check_float_clamp!(f16, 1e3); } @@ -223,11 +224,13 @@ fn test_clamp_magnitude_f64() { } #[test] +#[cfg(target_has_reliable_f128)] fn test_clamp_magnitude_f128() { check_float_clamp!(f128, 1e3000); } #[test] +#[cfg(target_has_reliable_f16)] #[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f16_panic_negative_limit() { let _ = 1.0f16.clamp_magnitude(-1.0); @@ -246,12 +249,14 @@ fn test_clamp_magnitude_f64_panic_negative_limit() { } #[test] +#[cfg(target_has_reliable_f128)] #[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f128_panic_negative_limit() { let _ = 1.0f128.clamp_magnitude(-1.0); } #[test] +#[cfg(target_has_reliable_f16)] #[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f16_panic_nan_limit() { let _ = 1.0f16.clamp_magnitude(f16::NAN); @@ -270,6 +275,7 @@ fn test_clamp_magnitude_f64_panic_nan_limit() { } #[test] +#[cfg(target_has_reliable_f128)] #[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f128_panic_nan_limit() { let _ = 1.0f128.clamp_magnitude(f128::NAN); From 2eeeb39a9785812aa101e75486c88a7f5c4b0619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 29 Sep 2026 22:41:25 +0000 Subject: [PATCH 24/71] Use more default field values in `Resolver` --- compiler/rustc_data_structures/src/fx.rs | 10 ++++- compiler/rustc_middle/src/middle/privacy.rs | 6 +-- compiler/rustc_resolve/src/lib.rs | 44 +++++++-------------- 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index cad775cc98641..76b2c428ec84d 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -28,7 +28,7 @@ macro_rules! define_stable_id_collections { } pub mod default { - use super::{FxBuildHasher, FxHashMap, FxHashSet}; + use super::{FxBuildHasher, FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; // FIXME: These two functions will become unnecessary after // lands and we start using the corresponding @@ -40,4 +40,12 @@ pub mod default { pub const fn fx_hash_set() -> FxHashSet { FxHashSet::with_hasher(FxBuildHasher) } + + pub const fn fx_index_map() -> FxIndexMap { + FxIndexMap::with_hasher(FxBuildHasher) + } + + pub const fn fx_index_set() -> FxIndexSet { + FxIndexSet::with_hasher(FxBuildHasher) + } } diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 9685ac89011e5..3a008514f7d07 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -5,7 +5,7 @@ use std::cmp::Ordering; use std::hash::Hash; -use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry, default}; use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; use rustc_hir::def::DefKind; use rustc_hir::{ItemKind, Node, UseKind, UseTree}; @@ -277,9 +277,9 @@ impl EffectiveVisibilities { } } -impl Default for EffectiveVisibilities { +const impl Default for EffectiveVisibilities { fn default() -> Self { - EffectiveVisibilities { map: Default::default() } + EffectiveVisibilities { map: default::fx_index_map() } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 772fdb8c9f14d..fc151de0decf9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1417,11 +1417,11 @@ pub struct Resolver<'ra, 'tcx> { extern_module_map: RwLock>>, /// Maps glob imports to the names of items actually imported. - glob_map: FxIndexMap>, + glob_map: FxIndexMap> = default::fx_index_map(), glob_error: Option = None, visibilities_for_hashing: Vec<(LocalDefId, Visibility)> = Vec::new(), used_imports: FxHashSet = default::fx_hash_set(), - maybe_unused_trait_imports: FxIndexSet, + maybe_unused_trait_imports: FxIndexSet = default::fx_index_set(), /// Privacy errors are delayed until the end in order to deduplicate them. privacy_errors: Vec> = Vec::new(), @@ -1442,7 +1442,7 @@ pub struct Resolver<'ra, 'tcx> { builtin_macros: FxHashMap = default::fx_hash_map(), registered_attr_tools: &'tcx RegisteredTools, registered_lint_tools: &'tcx RegisteredTools, - macro_use_prelude: FxIndexMap>, + macro_use_prelude: FxIndexMap> = default::fx_index_map(), /// Eagerly populated map of all local macro definitions. local_macro_map: FxHashMap> = default::fx_hash_map(), /// Lazily populated cache of macro definitions loaded from external crates. @@ -1452,9 +1452,9 @@ pub struct Resolver<'ra, 'tcx> { non_macro_attr: &'ra Arc, local_macro_def_scopes: FxHashMap> = default::fx_hash_map(), ast_transform_scopes: FxHashMap> = default::fx_hash_map(), - unused_macros: FxIndexMap, + unused_macros: FxIndexMap = default::fx_index_map(), /// A map from the macro to all its potentially unused arms and the `LocalDefId` of the macro itself. - unused_macro_rules: FxIndexMap)>, + unused_macro_rules: FxIndexMap)> = default::fx_index_map(), proc_macro_stubs: FxHashSet = default::fx_hash_set(), /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: @@ -1521,25 +1521,25 @@ pub struct Resolver<'ra, 'tcx> { /// Generic args to suggest for required params (e.g. `<'_>`, `<_, _>`), if any. item_required_generic_args_suggestions: FxHashMap = default::fx_hash_map(), delegation_fn_sigs: LocalDefIdMap = Default::default(), - delegation_infos: FxIndexMap, - delegation_inherent_fn_map: FxIndexMap>, + delegation_infos: FxIndexMap = default::fx_index_map(), + delegation_inherent_fn_map: FxIndexMap> = default::fx_index_map(), main_def: Option = None, - trait_impls: FxIndexMap>, + trait_impls: FxIndexMap> = default::fx_index_map(), /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. proc_macros: Vec = Vec::new(), - paths_matching_assoc_types: UnordSet, - confused_type_with_std_module: FxIndexMap, + paths_matching_assoc_types: UnordSet = Default::default(), + confused_type_with_std_module: FxIndexMap = default::fx_index_map(), /// Names of items that were stripped out via cfg with their corresponding cfg meta item. stripped_cfg_items: Vec> = Vec::new(), - effective_visibilities: EffectiveVisibilities, - macro_reachable_adts: FxIndexMap>, + effective_visibilities: EffectiveVisibilities = Default::default(), + macro_reachable_adts: FxIndexMap> = default::fx_index_map(), - doc_link_resolutions: FxIndexMap, - doc_link_traits_in_scope: FxIndexMap>, + doc_link_resolutions: FxIndexMap = default::fx_index_map(), + doc_link_traits_in_scope: FxIndexMap> = default::fx_index_map(), all_macro_rules: UnordSet = Default::default(), /// Invocation ids of all glob delegations. @@ -1852,9 +1852,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { local_module_map, extern_module_map: Default::default(), - glob_map: Default::default(), - maybe_unused_trait_imports: Default::default(), - arenas, dummy_decl: arenas.new_pub_def_decl(Res::Err, DUMMY_SP, LocalExpnId::ROOT), builtin_type_decls: PrimTy::ALL @@ -1883,31 +1880,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect(), registered_attr_tools, registered_lint_tools, - macro_use_prelude: Default::default(), extern_macro_map: Default::default(), dummy_ext_bang: arenas.alloc_macro(SyntaxExtension::dummy_bang(edition)), dummy_ext_derive: arenas.alloc_macro(SyntaxExtension::dummy_derive(edition)), non_macro_attr: arenas.alloc_macro(SyntaxExtension::non_macro_attr(edition)), - unused_macros: Default::default(), - unused_macro_rules: Default::default(), single_segment_macro_resolutions: Default::default(), multi_segment_macro_resolutions: Default::default(), lint_buffer: LintBuffer::default(), owners, current_owner: PerOwnerResolverData::new(DUMMY_NODE_ID, CRATE_DEF_ID), invocation_parents, - trait_impls: Default::default(), - confused_type_with_std_module: Default::default(), - paths_matching_assoc_types: Default::default(), - stripped_cfg_items: Default::default(), - effective_visibilities: Default::default(), - macro_reachable_adts: Default::default(), - doc_link_resolutions: Default::default(), - doc_link_traits_in_scope: Default::default(), current_crate_outer_attr_insert_span, disambiguators: Default::default(), - delegation_infos: Default::default(), - delegation_inherent_fn_map: Default::default(), features: tcx.features(), .. }; From 728205bd952173da7d3dcf617205d78d7818b7f6 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 29 Sep 2026 22:55:17 -0400 Subject: [PATCH 25/71] Forbid `Reborrow` impls for types with destructors Construction of such types should never be so implicit. --- .../rustc_hir_analysis/src/coherence/builtin.rs | 15 ++++++++++++++- compiler/rustc_hir_analysis/src/diagnostics.rs | 7 ++++--- tests/ui/reborrow/reborrow-drop.rs | 14 ++++++++++++++ tests/ui/reborrow/reborrow-drop.stderr | 15 +++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 tests/ui/reborrow/reborrow-drop.rs create mode 100644 tests/ui/reborrow/reborrow-drop.stderr diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index efed5994f63fe..e7f20766bc8eb 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -115,7 +115,11 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran Err(CopyImplementationError::HasDestructor(did)) => { let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; let impl_ = tcx.def_span(did); - Err(tcx.dcx().emit_err(diagnostics::CopyImplOnTypeWithDtor { span, impl_ })) + Err(tcx.dcx().emit_err(diagnostics::TraitImplOnTypeWithDtor { + span, + impl_, + trait_name: sym::Copy, + })) } Err(CopyImplementationError::HasUnsafeFields) => { let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; @@ -537,6 +541,15 @@ pub(crate) fn reborrow_info<'tcx>( assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, field.ty, field.span)?; } + if let Some(did) = def.destructor(tcx).map(|dtor| dtor.did) { + let impl_ = tcx.def_span(did); + return Err(tcx.dcx().emit_err(diagnostics::TraitImplOnTypeWithDtor { + span, + impl_, + trait_name: sym::Reborrow, + })); + } + Ok(()) } diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index ff5f7dbb119f1..e4f7f2d9229fc 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -292,13 +292,14 @@ pub(crate) struct FieldAlreadyDeclaredNestedHelp { } #[derive(Diagnostic)] -#[diag("the trait `Copy` cannot be implemented for this type; the type has a destructor", code = E0184)] -pub(crate) struct CopyImplOnTypeWithDtor { +#[diag("the trait `{$trait_name}` cannot be implemented for this type; the type has a destructor", code = E0184)] +pub(crate) struct TraitImplOnTypeWithDtor { #[primary_span] - #[label("`Copy` not allowed on types with destructors")] + #[label("`{$trait_name}` not allowed on types with destructors")] pub span: Span, #[note("destructor declared here")] pub impl_: Span, + pub trait_name: Symbol, } #[derive(Diagnostic)] diff --git a/tests/ui/reborrow/reborrow-drop.rs b/tests/ui/reborrow/reborrow-drop.rs new file mode 100644 index 0000000000000..bc88bb79b9b4b --- /dev/null +++ b/tests/ui/reborrow/reborrow-drop.rs @@ -0,0 +1,14 @@ +//@ compile-flags: --crate-type=lib + +#![feature(reborrow)] + +use std::marker::Reborrow; + +struct MyMut<'a>(&'a mut ()); + +impl Reborrow for MyMut<'_> {} +//~^ ERROR the trait `Reborrow` cannot be implemented for this type; the type has a destructor [E0184] + +impl Drop for MyMut<'_> { + fn drop(&mut self) {} +} diff --git a/tests/ui/reborrow/reborrow-drop.stderr b/tests/ui/reborrow/reborrow-drop.stderr new file mode 100644 index 0000000000000..d35b36530d588 --- /dev/null +++ b/tests/ui/reborrow/reborrow-drop.stderr @@ -0,0 +1,15 @@ +error[E0184]: the trait `Reborrow` cannot be implemented for this type; the type has a destructor + --> $DIR/reborrow-drop.rs:9:1 + | +LL | impl Reborrow for MyMut<'_> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Reborrow` not allowed on types with destructors + | +note: destructor declared here + --> $DIR/reborrow-drop.rs:13:5 + | +LL | fn drop(&mut self) {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0184`. From a5e0df2d551723906c68eda7e0e7ce399db4629e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Sep 2026 16:47:32 +1000 Subject: [PATCH 26/71] Remove `rustc_middle::ty::cast::IntTy` Currently it covers "int-like" types: integers, integer inference variables, bools, chars, and C-like enums. It's a bit weird, especially the asymmetry between the fielded `U` and fieldless `I` variants. This commit merges it into `CastTy`, and adds an `is_int_like` method. Some of the checking is now more strict, accepting only ints where before it accepted int-likes (e.g. casting a bool to a ptr) in `TypeChecker::visit_rvalue` and `mir_cast_kind`. `CastCheck::do_check` already rejects these int-like cases, which means they can't occur in MIR built from THIR. The only way to hit the stricter checking is in custom MIR. The commit also removes some unused derives from `CastKind` and fixes a couple of stale comments. --- compiler/rustc_borrowck/src/type_check/mod.rs | 10 ++-- compiler/rustc_hir_typeck/src/cast.rs | 29 ++++----- compiler/rustc_middle/src/ty/cast.rs | 59 +++++++++---------- 3 files changed, 48 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 0a6fb9d5da47a..0e8565aef3f0b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1361,7 +1361,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (), + (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int)) => (), _ => { span_mirbug!( self, @@ -1379,7 +1379,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => (), + (Some(CastTy::Int), Some(CastTy::Ptr(_))) => (), _ => { span_mirbug!( self, @@ -1396,7 +1396,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => (), + (Some(from), Some(to)) if from.is_int_like() && to.is_int_like() => (), _ => { span_mirbug!( self, @@ -1413,7 +1413,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Int(_)), Some(CastTy::Float)) => (), + (Some(CastTy::Int), Some(CastTy::Float)) => (), _ => { span_mirbug!( self, @@ -1430,7 +1430,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Float), Some(CastTy::Int(_))) => (), + (Some(CastTy::Float), Some(CastTy::Int)) => (), _ => { span_mirbug!( self, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 02e6b8188a876..7eced89c95341 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -912,7 +912,6 @@ impl<'a, 'tcx> CastCheck<'tcx> { /// directly. coercion-cast is handled in check instead of here. fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result> { use rustc_middle::ty::cast::CastTy::*; - use rustc_middle::ty::cast::IntTy::*; let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) { @@ -947,7 +946,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // a cast. ty::Ref(_, inner_ty, mutbl) => { return match t_cast { - Int(_) | Float => match *inner_ty.kind() { + Int | CEnum | Bool | Char | Float => match *inner_ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Float(_) @@ -979,19 +978,21 @@ impl<'a, 'tcx> CastCheck<'tcx> { } match (t_from, t_cast) { // These types have invariants! can't cast into them. - (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar), + (_, CEnum | FnPtr) => Err(CastError::NonScalar), // * -> Bool - (_, Int(Bool)) => Err(CastError::CastToBool), + (_, Bool) => Err(CastError::CastToBool), // * -> Char - (Int(U(ty::UintTy::U8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast - (_, Int(Char)) => Err(CastError::CastToChar), + (Int, Char) if self.expr_ty == fcx.tcx.types.u8 => { + Ok(CastKind::U8CharCast) // u8-char-cast + } + (_, Char) => Err(CastError::CastToChar), // prim -> float,ptr - (Int(Bool) | Int(CEnum) | Int(Char), Float) => Err(CastError::NeedViaInt), + (Bool | CEnum | Char, Float) => Err(CastError::NeedViaInt), - (Int(Bool) | Int(CEnum) | Int(Char) | Float, Ptr(_)) | (Ptr(_) | FnPtr, Float) => { + (Bool | CEnum | Char | Float, Ptr(_)) | (Ptr(_) | FnPtr, Float) => { Err(CastError::IllegalCast) } @@ -999,24 +1000,24 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast // ptr-addr-cast - (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), + (Ptr(m_expr), Int) => self.check_ptr_addr_cast(fcx, m_expr), - (FnPtr, Int(_)) => { + (FnPtr, Int) => { // FIXME(#95489): there should eventually be a lint for these casts Ok(CastKind::FnPtrAddrCast) } // addr-ptr-cast - (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), + (Int, Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // fn-ptr-cast (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), // enum -> int - (Int(CEnum), Int(_)) => self.check_enum_cast(fcx), + (CEnum, Int) => self.check_enum_cast(fcx), // prim -> prim - (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), + (Char | Bool, Int) => Ok(CastKind::PrimIntCast), - (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), + (Int | Float, Int | Float) => Ok(CastKind::NumericCast), } } diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index e53f53d5e5648..32af08eaaadb3 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -1,29 +1,20 @@ -// Helpers for handling cast expressions, used in both -// typeck and codegen. +// Helpers for handling cast expressions. -use rustc_macros::{StableHash, TyDecodable, TyEncodable}; use rustc_span::bug; use crate::mir; use crate::ty::{self, Ty}; -/// Types that are represented as ints. +/// Valid types for the result of a non-coercion cast #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum IntTy { - U(ty::UintTy), - I, +pub enum CastTy<'tcx> { + /// `iN`, `uN`, and integer inference variables. + Int, + /// C-like (fieldless) enums. CEnum, Bool, Char, -} - -// Valid types for the result of a non-coercion cast -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CastTy<'tcx> { - /// Various types that are represented as ints and handled mostly - /// in the same way, merged for easier matching. - Int(IntTy), - /// Floating-point types. + /// `fN` and float inference variables. Float, /// Function pointers. FnPtr, @@ -32,8 +23,8 @@ pub enum CastTy<'tcx> { } /// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) -/// (or rustc_hir_analysis/check/cast.rs). -#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, StableHash)] +/// (or rustc_hir_typeck/src/cast.rs). +#[derive(Copy, Clone, Debug)] pub enum CastKind { PtrPtrCast, PtrAddrCast, @@ -52,19 +43,23 @@ impl<'tcx> CastTy<'tcx> { /// Casts like unsizing casts will return `None`. pub fn from_ty(t: Ty<'tcx>) -> Option> { match *t.kind() { - ty::Bool => Some(CastTy::Int(IntTy::Bool)), - ty::Char => Some(CastTy::Int(IntTy::Char)), - ty::Int(_) => Some(CastTy::Int(IntTy::I)), - ty::Infer(ty::InferTy::IntVar(_)) => Some(CastTy::Int(IntTy::I)), - ty::Infer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float), - ty::Uint(u) => Some(CastTy::Int(IntTy::U(u))), - ty::Float(_) => Some(CastTy::Float), - ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), + ty::Bool => Some(CastTy::Bool), + ty::Char => Some(CastTy::Char), + ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)) => Some(CastTy::Int), + ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float), + ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::CEnum), ty::RawPtr(ty, mutbl) => Some(CastTy::Ptr(ty::TypeAndMut { ty, mutbl })), ty::FnPtr(..) => Some(CastTy::FnPtr), _ => None, } } + + pub fn is_int_like(self) -> bool { + match self { + CastTy::Int | CastTy::CEnum | CastTy::Bool | CastTy::Char => true, + CastTy::Float | CastTy::FnPtr | CastTy::Ptr(_) => false, + } + } } /// Returns `mir::CastKind` from the given parameters. @@ -72,15 +67,17 @@ pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKin let from = CastTy::from_ty(from_ty); let cast = CastTy::from_ty(cast_ty); let cast_kind = match (from, cast) { - (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { + (Some(from), Some(cast)) if from.is_int_like() && cast.is_int_like() => { + mir::CastKind::IntToInt + } + (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int)) => { mir::CastKind::PointerExposeProvenance } - (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance, - (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt, + (Some(CastTy::Int), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance, (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr, - (Some(CastTy::Float), Some(CastTy::Int(_))) => mir::CastKind::FloatToInt, - (Some(CastTy::Int(_)), Some(CastTy::Float)) => mir::CastKind::IntToFloat, + (Some(CastTy::Float), Some(CastTy::Int)) => mir::CastKind::FloatToInt, + (Some(CastTy::Int), Some(CastTy::Float)) => mir::CastKind::IntToFloat, (Some(CastTy::Float), Some(CastTy::Float)) => mir::CastKind::FloatToFloat, (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PtrToPtr, From 9bdf58f54fc2ec1fc735276789b103c81529dba6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Sep 2026 20:45:28 +1000 Subject: [PATCH 27/71] Move `rustc_middle::ty::cast::CastKind` It's not used in `rustc_middle`, it's only used in `rustc_hir_typeck` and clippy. (It's always good to remove things from `rustc_middle`.) --- compiler/rustc_hir_typeck/src/cast.rs | 18 +++++++++++++++++- compiler/rustc_middle/src/ty/cast.rs | 16 ---------------- .../transmutes_expressible_as_ptr_casts.rs | 3 +-- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 7eced89c95341..14cb73e28c871 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -39,7 +39,7 @@ use rustc_lint_defs::builtin::{TRIVIAL_CASTS, TRIVIAL_NUMERIC_CASTS}; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; -use rustc_middle::ty::cast::{CastKind, CastTy}; +use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, Unnormalized, VariantDef, elaborate, @@ -52,6 +52,22 @@ use tracing::{debug, instrument}; use super::FnCtxt; use crate::{diagnostics, type_error_struct}; +/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) +/// (or rustc_hir_typeck/src/cast.rs). +#[derive(Copy, Clone, Debug)] +pub enum CastKind { + PtrPtrCast, + PtrAddrCast, + AddrPtrCast, + NumericCast, + EnumCast, + PrimIntCast, + U8CharCast, + ArrayPtrCast, + FnPtrPtrCast, + FnPtrAddrCast, +} + /// Reifies a cast check to be checked once we have full type information for /// a function context. #[derive(Debug)] diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index 32af08eaaadb3..fc8a6de5d232e 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -22,22 +22,6 @@ pub enum CastTy<'tcx> { Ptr(ty::TypeAndMut<'tcx>), } -/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) -/// (or rustc_hir_typeck/src/cast.rs). -#[derive(Copy, Clone, Debug)] -pub enum CastKind { - PtrPtrCast, - PtrAddrCast, - AddrPtrCast, - NumericCast, - EnumCast, - PrimIntCast, - U8CharCast, - ArrayPtrCast, - FnPtrPtrCast, - FnPtrAddrCast, -} - impl<'tcx> CastTy<'tcx> { /// Returns `Some` for integral/pointer casts. /// Casts like unsizing casts will return `None`. diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 18897fbb5b8f0..0f5adb8b983e2 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -4,10 +4,9 @@ use clippy_utils::sugg::Sugg; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::Applicability; use rustc_hir::{Expr, Node}; -use rustc_hir_typeck::cast::check_cast; +use rustc_hir_typeck::cast::{CastKind, check_cast}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_middle::ty::cast::CastKind; /// Checks for `transmutes_expressible_as_ptr_casts` lint. /// Returns `true` if it's triggered, otherwise returns `false`. From 9970383a9bece341e44dc49dc45b98e10a83e6dc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Sep 2026 11:14:08 +1000 Subject: [PATCH 28/71] Document `Result` case for the `arena_cache` query modifier --- compiler/rustc_middle/src/query/arena_cached.rs | 14 ++++++++------ compiler/rustc_middle/src/query/modifiers.rs | 9 ++++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/query/arena_cached.rs b/compiler/rustc_middle/src/query/arena_cached.rs index 4ab2fbe914965..8faf6f68f49c9 100644 --- a/compiler/rustc_middle/src/query/arena_cached.rs +++ b/compiler/rustc_middle/src/query/arena_cached.rs @@ -5,13 +5,15 @@ use rustc_span::ErrorGuaranteed; use crate::ty::TyCtxt; -/// Helper trait that allows `arena_cache` queries to return `Option<&T>` -/// instead of `&Option`, and avoid allocating `None` in the arena. +/// Helper trait that allows `arena_cache` queries to return: +/// - `Option<&T>` instead of `&Option`, and avoid allocating `None` in the arena; or +/// - `Result<&T, ErrorGuaranteed>` instead of `&Result`, and avoid allocating +/// `Err(ErrorGuaranteed)` in the arena. /// -/// An arena-cached query must be declared to return a type that implements -/// this trait, i.e. either `&'tcx T` or `Option<&'tcx T>`. This trait then -/// determines the types returned by the provider and stored in the arena, -/// and provides a function to bridge between the three types. +/// An arena-cached query must be declared to return a type that implements this trait, i.e. +/// `&'tcx T`, `Option<&'tcx T>`, or `Result<&'tcx T, ErrorGuaranteed>`. This trait then determines +/// the types returned by the provider and stored in the arena, and provides a function to bridge +/// between the three types. pub trait ArenaCached<'tcx>: Sized { /// Type that is returned by the query provider. type Provided; diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs index 4fd91caa94cd7..3e057e96ddb6b 100644 --- a/compiler/rustc_middle/src/query/modifiers.rs +++ b/compiler/rustc_middle/src/query/modifiers.rs @@ -1,4 +1,5 @@ -//! This contains documentation which is linked from query modifiers used in the `rustc_queries!` proc macro. +//! This contains documentation which is linked from query modifiers used in the `rustc_queries!` +//! proc macro. //! //! The dummy items in this module are used to enable hover documentation for //! modifier names in the query list, and to allow find-all-references to list @@ -10,10 +11,12 @@ /// # `arena_cache` query modifier /// /// Query return values must impl `Copy` and be small, but some queries must return values that -/// doesn't meet those criteria. Queries marked with this modifier have their values allocated in -/// an arena and the query returns a reference to the value. There are two cases. +/// don't meet those criteria. Queries marked with this modifier have their values allocated in +/// an arena and the query returns a reference to the value. There are three cases. /// - If the provider function returns `T` then the query will return `&'tcx T`. /// - If the provider function returns `Option` then the query will return `Option<&'tcx T>`. +/// - If the provider function returns `Result` then the query will return +/// `Result<&'tcx T, ErrorGuaranteed>`. /// /// The query plumbing takes care of the arenas and the type manipulations. pub(crate) struct arena_cache; From 424d2426b0a8c879f9f9bfe32c99064f18f27bf6 Mon Sep 17 00:00:00 2001 From: Emmanuel Ugwu Date: Mon, 3 Aug 2026 05:26:13 +0100 Subject: [PATCH 29/71] Attribute documentation for cfg_attr --- library/core/src/attribute_docs.rs | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/library/core/src/attribute_docs.rs b/library/core/src/attribute_docs.rs index 97629be8ec6ef..ead2efbcf17c6 100644 --- a/library/core/src/attribute_docs.rs +++ b/library/core/src/attribute_docs.rs @@ -707,3 +707,50 @@ const _: () = (); /// [Clippy]: https://github.com/rust-lang/rust-clippy /// [the `automatically_derived` attribute]: ../reference/attributes/derive.html#the-automatically_derived-attribute const _: () = (); + +#[doc(attribute = "cfg_attr")] +// +/// The `cfg_attr` attribute is used to conditionally apply one or more attributes to an item. +/// +/// Example: +/// +/// ```rust +/// // This function is annotated with `#[test]` only on Linux platforms. +/// #[cfg_attr(target_os = "linux", test)] +/// fn my_function() { +/// // ... +/// } +/// ``` +/// +/// You can apply multiple attributes by separating them with commas: +/// +/// ```rust +/// #[cfg_attr(feature = "nightly", allow(dead_code), deny(unused_variables))] +/// // This function only gets the `allow(dead_code)` and `deny(unused_variables)` attributes when +/// // `feature = "nightly"` is active. +/// fn nightly_only_function() { +/// let x = 42; +/// } +/// ``` +/// +/// For complex conditions, you can combine `all(...)`, `any(...)`, and `not(...)`. +/// +/// * `all`: True if all given predicates are true. +/// * `any`: True if at least one of the given predicates is true. +/// * `not`: True if the predicate is false. +/// +/// ```rust +/// #[cfg_attr( +/// all(feature = "system", feature = "disk"), +/// doc = "For module documentation, both `system`, and `disk` need to be enabled.". +/// )] +/// mod my_module { +/// // ... +/// } +/// ``` +/// +/// For more information, see the Reference on [the `cfg_attr` attribute]. +/// +/// [the `cfg` attribute]: ../reference/conditional-compilation.html#the-cfg-attribute +/// [the `cfg_attr` attribute]: ../reference/conditional-compilation.html#the-cfg_attr-attribute +const _: () = (); From 63a9c85be6a73c6f4d3b4b8668172d2beb4fd8b2 Mon Sep 17 00:00:00 2001 From: Emmanuel Ugwu Date: Mon, 3 Aug 2026 05:52:36 +0100 Subject: [PATCH 30/71] fix CI failure --- library/core/src/attribute_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/attribute_docs.rs b/library/core/src/attribute_docs.rs index ead2efbcf17c6..c5f7f80d7e1c5 100644 --- a/library/core/src/attribute_docs.rs +++ b/library/core/src/attribute_docs.rs @@ -751,6 +751,6 @@ const _: () = (); /// /// For more information, see the Reference on [the `cfg_attr` attribute]. /// -/// [the `cfg` attribute]: ../reference/conditional-compilation.html#the-cfg-attribute +/// [the `cfg` attribute]: ./attribute.cfg.html /// [the `cfg_attr` attribute]: ../reference/conditional-compilation.html#the-cfg_attr-attribute const _: () = (); From 1e418da6e6e04e21d020d5dbef0037d628d69029 Mon Sep 17 00:00:00 2001 From: Emmanuel Ugwu Date: Mon, 3 Aug 2026 08:28:44 +0100 Subject: [PATCH 31/71] fix merge conflict --- library/core/src/attribute_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/attribute_docs.rs b/library/core/src/attribute_docs.rs index c5f7f80d7e1c5..c2eb34ffa8bcb 100644 --- a/library/core/src/attribute_docs.rs +++ b/library/core/src/attribute_docs.rs @@ -751,6 +751,6 @@ const _: () = (); /// /// For more information, see the Reference on [the `cfg_attr` attribute]. /// -/// [the `cfg` attribute]: ./attribute.cfg.html +/// [`cfg`]: ./attribute.cfg.html /// [the `cfg_attr` attribute]: ../reference/conditional-compilation.html#the-cfg_attr-attribute const _: () = (); From 1850727e71e76b703665c5c0c6aebc554bf8a67b Mon Sep 17 00:00:00 2001 From: Emmanuel Ugwu Date: Wed, 30 Sep 2026 09:00:09 +0100 Subject: [PATCH 32/71] fix ci Signed-off-by: Emmanuel Ugwu --- library/core/src/attribute_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/attribute_docs.rs b/library/core/src/attribute_docs.rs index c2eb34ffa8bcb..a96c7a1388bd1 100644 --- a/library/core/src/attribute_docs.rs +++ b/library/core/src/attribute_docs.rs @@ -742,7 +742,7 @@ const _: () = (); /// ```rust /// #[cfg_attr( /// all(feature = "system", feature = "disk"), -/// doc = "For module documentation, both `system`, and `disk` need to be enabled.". +/// doc = "For module documentation, both `system`, and `disk` need to be enabled.", /// )] /// mod my_module { /// // ... From 654d6642d918149742558744798c2cdce3996999 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 08:56:04 +0200 Subject: [PATCH 33/71] add regression test --- ...-requires-resolving-regions.current.stderr | 26 +++++++++++++++ .../cycle-requires-resolving-regions.rs | 33 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.current.stderr create mode 100644 tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.rs diff --git a/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.current.stderr b/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.current.stderr new file mode 100644 index 0000000000000..477b0ba993104 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.current.stderr @@ -0,0 +1,26 @@ +error[E0275]: overflow evaluating the requirement `Foo<'_>: Send` + --> $DIR/cycle-requires-resolving-regions.rs:31:5 + | +LL | require::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_requires_resolving_regions`) +note: required for `Foo<'_>` to implement `Send` + --> $DIR/cycle-requires-resolving-regions.rs:23:17 + | +LL | unsafe impl<'a> Send for Foo<'a> + | ^^^^ ^^^^^^^ +LL | where +LL | Foo<'a>: Send, + | ---- unsatisfied trait bound introduced here + = note: 128 redundant requirements hidden + = note: required for `Foo<'static>` to implement `Send` +note: required by a bound in `require` + --> $DIR/cycle-requires-resolving-regions.rs:28:15 + | +LL | fn require() {} + | ^^^^ required by this bound in `require` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.rs b/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.rs new file mode 100644 index 0000000000000..2e1eaff4b9479 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.rs @@ -0,0 +1,33 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +// A test showcasing a behavior change in cycle detection between +// the old and new solver. The old solver detects cycles in both +// fulfill and in evaluate. The cycle detection in fulfillment +// does not resolve regions. Each occurance of the `Foo<'a>: Send` +// impl creates a fresh inference variable even if it is later +// constrainted to `'static`. This means we never detect a cycle. +// +// This is not an issue with builtin auto-trait impls as they don't +// create impl args instead, simply using the generic arguments of +// the self type directly. +// +// The new solver properly resolves regions. The old solver does resolve +// regions in `project`, so there we do detect cycles even if there are +// fresh region variables. + +struct Foo<'a>(&'a ()); + +unsafe impl<'a> Send for Foo<'a> +where + Foo<'a>: Send, +{} + +fn require() {} + +fn main() { + require::>(); + //[current]~^ ERROR: overflow evaluating the requirement `Foo<'_>: Send` +} From 8a0412044ec61eb8da030f9949862dfd66a47a03 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 10:44:19 +0200 Subject: [PATCH 34/71] replace awkward wording --- src/doc/rustc-dev-guide/src/external-repos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index fe0c0385d5f63..6f756fc8b890d 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -56,7 +56,7 @@ you should include fixes for those in the rustc PR as well. The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh. -We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree). +We provide a helper tool, [`rustc-josh-sync`][josh-sync], to help with the synchronization, described [below](#synchronizing-a-josh-subtree). ### Synchronizing a Josh subtree From 126eeb71e79efe2e2f600e12fef0254975fc0cd3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 10:45:04 +0200 Subject: [PATCH 35/71] reflow src/external-repos.md --- src/doc/rustc-dev-guide/src/external-repos.md | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 6f756fc8b890d..c4f5663871898 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -27,12 +27,12 @@ The following external projects are managed using some form of a `subtree`: * [compiler-builtins](https://github.com/rust-lang/compiler-builtins) * [stdarch](https://github.com/rust-lang/stdarch) -In contrast to `submodule` dependencies -(see below for those), the `subtree` dependencies are just regular files and directories which can +In contrast to `submodule` dependencies (see below for those), +the `subtree` dependencies are just regular files and directories which can be updated in-tree. However, if possible, enhancements, bug fixes, etc. specific to these tools should be filed against the tools directly in their respective upstream repositories. -The exception is that when rustc changes are required to -implement a new tool feature or test, that should happen in one collective rustc PR. +The exception is that when rustc changes are required to implement a new tool feature or test, +that should happen in one collective rustc PR. Similarly, if your rustc changes break the build of some subtree dependency, you should include fixes for those in the rustc PR as well. @@ -103,20 +103,20 @@ Periodically the changes made to subtree based dependencies need to be synchroni repository and the upstream tool repositories. Subtree synchronizations are typically handled by the respective tool maintainers. -Other users -are welcome to submit synchronization PRs, however, in order to do so you will need to modify +Other users are welcome to submit synchronization PRs, +however, in order to do so you will need to modify your local git installation and follow a very precise set of instructions. -These instructions are documented, along with several useful tips and tricks, in the -[syncing subtree changes][clippy-sync-docs] section in Clippy's Contributing guide. -The instructions are applicable for use with any subtree based tool, just be sure to -use the correct corresponding subtree directory and remote repository. +These instructions are documented, along with several useful tips and tricks, +in the [syncing subtree changes][clippy-sync-docs] section in Clippy's Contributing guide. +The instructions are applicable for use with any subtree based tool, +just be sure to use the correct corresponding subtree directory and remote repository. The synchronization process goes in two directions: `subtree push` and `subtree pull`. A `subtree push` takes all the changes that happened to the copy in this repo and creates commits on the remote repo that match the local changes. -Every local commit that touched the subtree causes a commit on the remote repo, but -is modified to move the files from the specified directory to the tool repo root. +Every local commit that touched the subtree causes a commit on the remote repo, +but is modified to move the files from the specified directory to the tool repo root. A `subtree pull` takes all changes since the last `subtree pull` from the tool repo and adds these commits to the rustc repo along with a merge commit that moves @@ -142,8 +142,8 @@ that this is happening because you suddenly get thousands of commits that want t ### Creating a new subtree dependency -If you want to create a new subtree dependency from an existing repository, call (from this -repository's root directory!) +If you want to create a new subtree dependency from an existing repository, +call (from this repository's root directory!) ``` git subtree add -P src/tools/clippy https://github.com/rust-lang/rust-clippy.git master @@ -152,9 +152,9 @@ git subtree add -P src/tools/clippy https://github.com/rust-lang/rust-clippy.git This will create a new commit, which you may not rebase under any circumstances! Delete the commit and redo the operation if you need to rebase. -Now you're done, the `src/tools/clippy` directory behaves as if Clippy were -part of the rustc monorepo, so no one but you (or others that synchronize -subtrees) actually needs to use `git subtree`. +Now you're done, +the `src/tools/clippy` directory behaves as if Clippy were part of the rustc monorepo, +so no one but you (or others that synchronize subtrees) actually needs to use `git subtree`. ## External dependencies (submodules) @@ -168,14 +168,14 @@ Usage of submodules is discussed more in the [Using Git chapter](git.md#git-subm Some of the submodules are allowed to be in a "broken" state where they either don't build or their tests don't pass, e.g. the documentation books like [The Rust Reference]. -Maintainers of these projects will be notified -when the project is in a broken state, and they should fix them as soon as possible. +Maintainers of these projects will be notified when the project is in a broken state, +and they should fix them as soon as possible. The current status is tracked on the [toolstate website]. More information may be found on the Forge [Toolstate chapter]. In practice, it is very rare for documentation to have broken toolstate. -Breakage is not allowed in the beta and stable channels, and must be addressed -before the PR is merged. +Breakage is not allowed in the beta and stable channels, +and must be addressed before the PR is merged. They are also not allowed to be broken on `main` in the week leading up to the beta cut. [git submodules]: https://git-scm.com/book/en/v2/Git-Tools-Submodules From 96bffc439e559cd198f4e49482d442d56f26dbf4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 10:50:03 +0200 Subject: [PATCH 36/71] improve external-repos.md --- src/doc/rustc-dev-guide/src/external-repos.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index c4f5663871898..d2c1696fb48b0 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -29,7 +29,8 @@ The following external projects are managed using some form of a `subtree`: In contrast to `submodule` dependencies (see below for those), the `subtree` dependencies are just regular files and directories which can -be updated in-tree. However, if possible, enhancements, bug fixes, etc. specific +be updated in-tree. +However, if possible, enhancements, bug fixes, etc. specific to these tools should be filed against the tools directly in their respective upstream repositories. The exception is that when rustc changes are required to implement a new tool feature or test, that should happen in one collective rustc PR. @@ -103,12 +104,12 @@ Periodically the changes made to subtree based dependencies need to be synchroni repository and the upstream tool repositories. Subtree synchronizations are typically handled by the respective tool maintainers. -Other users are welcome to submit synchronization PRs, -however, in order to do so you will need to modify +Other users are welcome to submit synchronization PRs. +However, in order to do so, you will need to modify your local git installation and follow a very precise set of instructions. These instructions are documented, along with several useful tips and tricks, in the [syncing subtree changes][clippy-sync-docs] section in Clippy's Contributing guide. -The instructions are applicable for use with any subtree based tool, +The instructions are applicable for use with any subtree-based tool; just be sure to use the correct corresponding subtree directory and remote repository. The synchronization process goes in two directions: `subtree push` and `subtree pull`. @@ -152,7 +153,7 @@ git subtree add -P src/tools/clippy https://github.com/rust-lang/rust-clippy.git This will create a new commit, which you may not rebase under any circumstances! Delete the commit and redo the operation if you need to rebase. -Now you're done, +Now you're done; the `src/tools/clippy` directory behaves as if Clippy were part of the rustc monorepo, so no one but you (or others that synchronize subtrees) actually needs to use `git subtree`. From ce15ffad43628de7030e5b66231c548bfb2d76e0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 10:50:10 +0200 Subject: [PATCH 37/71] reflow src/external-repos.md --- src/doc/rustc-dev-guide/src/external-repos.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index d2c1696fb48b0..0e23be130c403 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -28,8 +28,7 @@ The following external projects are managed using some form of a `subtree`: * [stdarch](https://github.com/rust-lang/stdarch) In contrast to `submodule` dependencies (see below for those), -the `subtree` dependencies are just regular files and directories which can -be updated in-tree. +the `subtree` dependencies are just regular files and directories which can be updated in-tree. However, if possible, enhancements, bug fixes, etc. specific to these tools should be filed against the tools directly in their respective upstream repositories. The exception is that when rustc changes are required to implement a new tool feature or test, @@ -105,8 +104,8 @@ repository and the upstream tool repositories. Subtree synchronizations are typically handled by the respective tool maintainers. Other users are welcome to submit synchronization PRs. -However, in order to do so, you will need to modify -your local git installation and follow a very precise set of instructions. +However, in order to do so, +you will need to modify your local git installation and follow a very precise set of instructions. These instructions are documented, along with several useful tips and tricks, in the [syncing subtree changes][clippy-sync-docs] section in Clippy's Contributing guide. The instructions are applicable for use with any subtree-based tool; From 5b4591290c5e1ddb005d017d48564dde515287fe Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:10:08 +0200 Subject: [PATCH 38/71] Prepare for merging from rust-lang/rust This updates the rust-version file to 7d2cd0fbc092625ea371da704f15f80216d2220e. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 6b9ce9470f137..af092f4d3417d 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -56fad885ebfb0447660870715da4dfa75deae93d +7d2cd0fbc092625ea371da704f15f80216d2220e From 57be633d8ec117a312aed9183353a64cee7e522c Mon Sep 17 00:00:00 2001 From: Emmanuel Ugwu Date: Wed, 30 Sep 2026 12:37:56 +0100 Subject: [PATCH 39/71] address feedback Signed-off-by: Emmanuel Ugwu --- library/core/src/attribute_docs.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/library/core/src/attribute_docs.rs b/library/core/src/attribute_docs.rs index a96c7a1388bd1..9a70ea74345be 100644 --- a/library/core/src/attribute_docs.rs +++ b/library/core/src/attribute_docs.rs @@ -189,7 +189,7 @@ const _: () = (); /// /// For more information, see the Reference on [the `cfg` attribute]. /// -/// [`cfg_attr`]: ../reference/conditional-compilation.html#the-cfg_attr-attribute +/// [`cfg_attr`]: ./attribute.cfg_attr.html /// [the `cfg` attribute]: ../reference/conditional-compilation.html#the-cfg-attribute /// [`if`]: ./keyword.if.html const _: () = (); @@ -715,11 +715,9 @@ const _: () = (); /// Example: /// /// ```rust -/// // This function is annotated with `#[test]` only on Linux platforms. -/// #[cfg_attr(target_os = "linux", test)] -/// fn my_function() { -/// // ... -/// } +/// // The struct derives `Debug` when the `debug_impls` feature is enabled. +/// #[cfg_attr(feature = "debug_impls", derive(Debug))] +/// struct X; /// ``` /// /// You can apply multiple attributes by separating them with commas: @@ -742,7 +740,7 @@ const _: () = (); /// ```rust /// #[cfg_attr( /// all(feature = "system", feature = "disk"), -/// doc = "For module documentation, both `system`, and `disk` need to be enabled.", +/// doc = "These docs only show up if both `system`, and `disk` are enabled.", /// )] /// mod my_module { /// // ... From 937145bcebff9cafefdbad652b7463a8ed04fe1f Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Wed, 30 Sep 2026 09:18:45 -0400 Subject: [PATCH 40/71] PassWrapper: adapt for new PassPlugin load method Used to take a string&, now takes a StringRef and is lower-case. --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index beb63ad61493c..79b590ab854f2 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -775,7 +775,11 @@ extern "C" LLVMRustResult LLVMRustOptimize( SmallVector Plugins; PluginsStr.split(Plugins, ',', -1, false); for (auto PluginPath : Plugins) { +#if LLVM_VERSION_GE(24, 0) + auto Plugin = PassPlugin::load(PluginPath); +#else auto Plugin = PassPlugin::Load(PluginPath.str()); +#endif if (!Plugin) { auto Err = Plugin.takeError(); auto ErrMsg = llvm::toString(std::move(Err)); From 1eb5c521ce0da5f66a184db06611ff41f7e28a44 Mon Sep 17 00:00:00 2001 From: Simon Sudarushkin <68971770+simonether@users.noreply.github.com> Date: Wed, 30 Sep 2026 21:41:24 +0500 Subject: [PATCH 41/71] Suggest `#[unsafe(no_mangle)]` for entry points in `no_std` binaries --- compiler/rustc_monomorphize/src/diagnostics.rs | 2 +- tests/ui/no_std/no-std-no-start-binary.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_monomorphize/src/diagnostics.rs b/compiler/rustc_monomorphize/src/diagnostics.rs index a1930dbea3cda..7635050603c41 100644 --- a/compiler/rustc_monomorphize/src/diagnostics.rs +++ b/compiler/rustc_monomorphize/src/diagnostics.rs @@ -96,7 +96,7 @@ pub(crate) struct EncounteredErrorWhileInstantiatingGlobalAsm { #[derive(Diagnostic)] #[diag("using `fn main` requires the standard library")] #[help( - "use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]`" + "use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[unsafe(no_mangle)]`" )] pub(crate) struct StartNotFound; diff --git a/tests/ui/no_std/no-std-no-start-binary.stderr b/tests/ui/no_std/no-std-no-start-binary.stderr index dd06c234da294..bc6ded80ff8fe 100644 --- a/tests/ui/no_std/no-std-no-start-binary.stderr +++ b/tests/ui/no_std/no-std-no-start-binary.stderr @@ -1,6 +1,6 @@ error: using `fn main` requires the standard library | - = help: use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]` + = help: use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[unsafe(no_mangle)]` error: aborting due to 1 previous error From dd0f941012649493d4de018135ef47d4245b962c Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 26 Jul 2026 14:02:45 +0200 Subject: [PATCH 42/71] make mips64 `Complex` ABI GCC-compatible --- compiler/rustc_target/src/callconv/mips64.rs | 65 +++++++++++++++++++- tests/codegen-llvm/complex-abi.rs | 35 ++++++++--- 2 files changed, 89 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 0e3ccf33c3ffe..e444e605d3b5a 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -1,6 +1,7 @@ use arrayvec::ArrayVec; use rustc_abi::{ - BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface, + BackendRepr, FieldsShape, Float, HasDataLayout, Integer, Numeric, Primitive, Reg, RegKind, + Size, TyAbiInterface, }; use crate::callconv::{ArgAbi, ArgAttribute, ArgExtension, CastTarget, FnAbi, PassMode, Uniform}; @@ -56,6 +57,22 @@ where let size = ret.layout.size; let bits = size.bits(); if bits <= 128 { + // NOTE: Complex is returned indirectly. + if let Some(component) = ret.layout.complex_number(cx) { + match component { + Numeric::Int(Integer::I8 | Integer::I16 | Integer::I32, _) => { + // Return a Complex<{integer}> packed into a single register when that fits. + ret.cast_to(Reg { kind: RegKind::Integer, size }); + } + _ => { + // Otherwise pass in 2 registers. + let reg = Reg { kind: component.reg_kind(), size: component.size() }; + ret.cast_to(CastTarget::pair(reg, reg)); + } + } + return; + } + // Unlike other architectures which return aggregates in registers, MIPS n64 limits the // use of float registers to structures (not unions) containing exactly one or two // float fields. @@ -103,6 +120,52 @@ where extend_integer_width_mips(arg, 64); } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { arg.make_indirect(); + } else if let Some(component) = arg.layout.complex_number(cx) + && !matches!(component, Numeric::Float(Float::F16)) + { + let slot = dl.pointer_size(); + let curr_offset = offset.align_to(align); + + const NUM_ARG_SLOTS: u64 = 8; + + match component { + Numeric::Float(Float::F16B) => unreachable!("Complex is not C-compatible"), + Numeric::Float(Float::F16) => unreachable!("not supported on mips64"), + Numeric::Float(Float::F32 | Float::F64) => { + // Only pass a Complex/Complex in FPRs when two argument slots are free. + if curr_offset.bytes() / slot.bytes() + 2 <= NUM_ARG_SLOTS { + // Both components claim a slot, even a Complex which could fit in one + // slot. + // + // FIXME(complex_numbers): c-variadic arguments are passed in GPRs, so need a + // special carve-out here and Complex is bitpacked into one 64-bit GPR. + *offset = curr_offset + slot * 2; + let unit = Reg { kind: RegKind::Float, size: component.size() }; + let cast_target = CastTarget::from(Uniform::new(unit, size)); + arg.cast_to(cast_target); + return; + } + + // Otherwise pack it into GPRs (or the stack) like an integer of the same size. + arg.cast_to_and_pad_i32(Uniform::new(Reg::i64(), size), pad_i32); + } + Numeric::Float(Float::F128) => { + // Complex is passed in 4 FPRs, but aligned to 16 so may need padding. + let reg = Reg { kind: RegKind::Float, size: arg.layout.field(cx, 0).size }; + arg.cast_to_and_pad_i32(CastTarget::pair(reg, reg), pad_i32); + } + Numeric::Int(Integer::I8 | Integer::I16 | Integer::I32, _) => { + // Cast Complex into i16, Complex to i32, etc. + let cast_target = CastTarget::from(Reg { kind: RegKind::Integer, size }); + // The inreg attribute makes the bits land in the right (upper) bits on BE targets. + arg.cast_to(cast_target.with_attrs(ArgAttribute::InReg.into())); + } + Numeric::Int(Integer::I64 | Integer::I128, _) => { + // Complex and Complex are passed as 2 separate arguments. + let cast_target = CastTarget::from(Reg { kind: RegKind::Integer, size }); + arg.cast_to(cast_target); + } + } } else { match arg.layout.fields { FieldsShape::Primitive => unreachable!(), diff --git a/tests/codegen-llvm/complex-abi.rs b/tests/codegen-llvm/complex-abi.rs index 3235627e9ca5f..c9e59f6f7eaa7 100644 --- a/tests/codegen-llvm/complex-abi.rs +++ b/tests/codegen-llvm/complex-abi.rs @@ -75,15 +75,21 @@ //@ [AIX] compile-flags: --target powerpc64-ibm-aix //@ [AIX] needs-llvm-components: powerpc +// NOTE: in clang <= 23 the Complex is passed incorrectly. +// See https://github.com/llvm/llvm-project/issues/212109. +//@ revisions: MIPS64 MIPS64EL +//@ [MIPS64] compile-flags: --target mips64-unknown-linux-gnuabi64 +//@ [MIPS64] needs-llvm-components: mips +//@ [MIPS64EL] compile-flags: --target mips64el-unknown-linux-gnuabi64 +//@ [MIPS64EL] needs-llvm-components: mips + // FIXME: the below revisions are deliberately disabled for now. // revisions: POWERPC // [POWERPC] compile-flags: --target powerpc-unknown-linux-gnu // [POWERPC] needs-llvm-components: powerpc -// revisions: MIPS64EL MIPS -// [MIPS64EL] compile-flags: --target mips64el-unknown-linux-gnuabi64 -// [MIPS64EL] needs-llvm-components: mips +// revisions: MIPS // [MIPS] compile-flags: --target mips-unknown-linux-gnu // [MIPS] needs-llvm-components: mips @@ -143,7 +149,8 @@ pub extern "C" fn cplx_f32(x: Complex) -> Complex { // I686: define{{.*}} i64 @cplx_f32(ptr {{.*}} byval([8 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) // LOONGARCH64: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) - // MIPS64EL: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // MIPS64: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) + // MIPS64EL: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) // MIPS: define{{.*}} { float, float } @cplx_f32([2 x i32] {{.*}}) // NVPTX: define{{.*}} { float, float } @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) // POWERPC64: define{{.*}} { float, float } @cplx_f32({ float, float } %0) @@ -177,7 +184,8 @@ pub extern "C" fn cplx_f64(x: Complex) -> Complex { // I686: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) // LOONGARCH64: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) - // MIPS64EL: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // MIPS64: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) + // MIPS64EL: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) // MIPS: define{{.*}} { double, double } @cplx_f64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) // NVPTX: define{{.*}} { double, double } @cplx_f64(ptr {{.*}} byval({ double, double }) {{.*}}) // POWERPC64: define{{.*}} { double, double } @cplx_f64({ double, double } %0) @@ -202,6 +210,8 @@ pub extern "C" fn cplx_f64(x: Complex) -> Complex { pub extern "C" fn cplx_f128(x: Complex) -> Complex { // AARCH64: define{{.*}} [2 x fp128] {{.*}}) // I686: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}} byval([32 x i8]) {{.*}}) + // MIPS64: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, i32 %0, { fp128, fp128 } %1) + // MIPS64EL: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, i32 %0, { fp128, fp128 } %1) // SPARC: define{{.*}} inreg { fp128, fp128 } @cplx_f128(ptr {{.*}} dereferenceable(32) {{.*}}) // WASM32: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) // WASM64: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) @@ -226,7 +236,8 @@ pub extern "C" fn cplx_i8(x: Complex) -> Complex { // I686: define{{.*}} i16 @cplx_i8(ptr {{.*}} byval([2 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} i32 @cplx_i8(i32{{.*}}) // LOONGARCH64: define{{.*}} i64 @cplx_i8(i64{{.*}}) - // MIPS64EL: define{{.*}} { i8, i8 } @cplx_i8(i16 {{.*}}) + // MIPS64: define{{.*}} i16 @cplx_i8(i16 inreg {{.*}}) + // MIPS64EL: define{{.*}} i16 @cplx_i8(i16 inreg {{.*}}) // MIPS: define{{.*}} { i8, i8 } @cplx_i8(i16 {{.*}}) // NVPTX: define{{.*}} { i8, i8 } @cplx_i8(ptr {{.*}} byval({ i8, i8 }) {{.*}}) // POWERPC64: define{{.*}} { i8, i8 } @cplx_i8({ i8, i8 } %0) @@ -260,7 +271,8 @@ pub extern "C" fn cplx_i16(x: Complex) -> Complex { // I686: define{{.*}} i32 @cplx_i16(ptr {{.*}} byval([4 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} i32 @cplx_i16(i32 {{.*}}) // LOONGARCH64: define{{.*}} i64 @cplx_i16(i64{{.*}}) - // MIPS64EL: define{{.*}} { i16, i16 } @cplx_i16(i32 {{.*}}) + // MIPS64: define{{.*}} i32 @cplx_i16(i32 inreg {{.*}}) + // MIPS64EL: define{{.*}} i32 @cplx_i16(i32 inreg {{.*}}) // MIPS: define{{.*}} { i16, i16 } @cplx_i16(i32 {{.*}}) // NVPTX: define{{.*}} { i16, i16 } @cplx_i16(ptr {{.*}} byval({ i16, i16 }) {{.*}}) // POWERPC64: define{{.*}} { i16, i16 } @cplx_i16(i16 {{.*}}, i16 {{.*}}) @@ -294,7 +306,8 @@ pub extern "C" fn cplx_i32(x: Complex) -> Complex { // I686: define{{.*}} i64 @cplx_i32(ptr {{.*}} byval([8 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} [2 x i32] @cplx_i32([2 x i32] {{.*}}) // LOONGARCH64: define{{.*}} i64 @cplx_i32(i64 {{.*}}) - // MIPS64EL: define{{.*}} { i32, i32 } @cplx_i32(i64 {{.*}}) + // MIPS64: define{{.*}} i64 @cplx_i32(i64 inreg {{.*}}) + // MIPS64EL: define{{.*}} i64 @cplx_i32(i64 inreg {{.*}}) // MIPS: define{{.*}} { i32, i32 } @cplx_i32(i32 {{.*}}, i32 {{.*}}) // NVPTX: define{{.*}} { i32, i32 } @cplx_i32(ptr {{.*}} byval({ i32, i32 }) {{.*}}) // POWERPC64: define{{.*}} { i32, i32 } @cplx_i32({ i32, i32 } %0) @@ -328,7 +341,8 @@ pub extern "C" fn cplx_i64(x: Complex) -> Complex { // I686: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // LOONGARCH64: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) - // MIPS64EL: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) + // MIPS64: define{{.*}} { i64, i64 } @cplx_i64(i128 {{.*}}) + // MIPS64EL: define{{.*}} { i64, i64 } @cplx_i64(i128 {{.*}}) // MIPS: define{{.*}} { i64, i64 } @cplx_i64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) // NVPTX: define{{.*}} { i64, i64 } @cplx_i64(ptr {{.*}} byval({ i64, i64 }) {{.*}}) // POWERPC64: define{{.*}} { i64, i64 } @cplx_i64({ i64, i64 } %0) @@ -367,7 +381,8 @@ pub extern "C" fn wrapper_cplx_i64( // I686: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // LOONGARCH64: define{{.*}} [2 x i64] @wrapper_cplx_i64([2 x i64] {{.*}}) - // MIPS64EL: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i64 {{.*}}, i64 {{.*}}) + // MIPS64: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i128 {{.*}}) + // MIPS64EL: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i128 {{.*}}) // MIPS: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) // NVPTX: define{{.*}} { i64, i64 } @wrapper_cplx_i64(ptr {{.*}} byval({ i64, i64 }) {{.*}}) // POWERPC64: define{{.*}} { i64, i64 } @wrapper_cplx_i64({ i64, i64 } %0) From f25f4eb4cc94675eec2636bc0cf5bd9c2347a5b3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:22:33 +0200 Subject: [PATCH 43/71] sembr src/const-generics.md --- src/doc/rustc-dev-guide/src/const-generics.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index 349e9de9da120..d327ad150f330 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -27,7 +27,8 @@ struct Foo; type Alias = [u8; 1 + 1]; ``` -In this example we have a const argument of `1 + 1` (the array length) which is represented as an *anon const*. The desugaring would look something like: +In this example we have a const argument of `1 + 1` (the array length) which is represented as an *anon const*. +The desugaring would look something like: ```rust struct Foo; From dd00fa81f72e740f746e0331c32534511b711c06 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:24:22 +0200 Subject: [PATCH 44/71] manual sembr --- src/doc/rustc-dev-guide/src/const-generics.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index d327ad150f330..a5c7ec506be4c 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -82,9 +82,11 @@ type Alias = [u8; ANON]; When we go through HIR ty lowering for the array type in `Alias`, we will lower the array length too, and feed `type_of(ANON) -> usize`. This will effectively set the type of the `ANON` const item during some later part of the compiler rather than when constructing the HIR. -After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Alias` with the `DefId` of the `AnonConst`. This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_min_const_items` is enabled). +After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Alias` with the `DefId` of the `AnonConst`. +This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_generic_const_args` is enabled). -This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. +This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. +Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. ### Enforcing lack of generic parameters From 25a59cb72b49469d8bfd3150ffdb6b2e3de63d8c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:28:21 +0200 Subject: [PATCH 45/71] sometimes shortens lines, for looks --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index 359deab6f6d7d..052036bb87f32 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -50,12 +50,12 @@ fn main() -> Result<()> { let old = fs::read_to_string(&path)?; let mut new = comply(&old); if cli.reflow_harder { - new = lengthen_lines(&new, cli.line_length_limit) + new = reformat_lines(&new, cli.line_length_limit) } if new == old { compliant.push(path.clone()); } else if cli.overwrite { - fs::write(&path, lengthen_lines(&new, cli.line_length_limit))?; + fs::write(&path, reformat_lines(&new, cli.line_length_limit))?; made_compliant.push(path.clone()); } else { not_compliant.push(path.clone()); @@ -133,7 +133,8 @@ fn comply(content: &str) -> String { new_content.join("\n") + "\n" } -fn lengthen_lines(content: &str, limit: usize) -> String { +// This reformats lines, so that changes of "fn comply" look more pretty +fn reformat_lines(content: &str, limit: usize) -> String { let content: Vec<_> = content.lines().map(std::borrow::ToOwned::to_owned).collect(); let mut new_content = content.clone(); let mut new_n = 0; @@ -277,7 +278,7 @@ r? @reviewer } #[test] -fn test_lengthen_lines() { +fn test_reformat_lines() { let original = "\ do not split short sentences @@ -342,7 +343,7 @@ html comment closing [a target]: https://example.com [another target]: https://example.com "; - assert_eq!(expected, lengthen_lines(original, 50)); + assert_eq!(expected, reformat_lines(original, 50)); } #[test] @@ -368,7 +369,7 @@ which could themselves be either base or derived. Each derived value has a dependency, on other values, which could themselves be either base or derived. "; - assert_eq!(expected, lengthen_lines(original, 100)) + assert_eq!(expected, reformat_lines(original, 100)) } #[test] @@ -387,7 +388,7 @@ encountering a cycle doesn't mean that we would get an infinite proof tree. Because of canonicalization of regions and inference variables, encountering a cycle doesn't mean that we would get an infinite proof tree. "; - assert_eq!(expected, lengthen_lines(original, 100)) + assert_eq!(expected, reformat_lines(original, 100)) } #[test] From 07ee9e01914150f5b81e9868fb3d63ffd2b6ee34 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:29:08 +0200 Subject: [PATCH 46/71] reflow src/building/bootstrapping/what-bootstrapping-does.md --- .../src/building/bootstrapping/what-bootstrapping-does.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md index 4572d001f12d3..fda9f29ae3ca9 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md @@ -15,8 +15,8 @@ See [bootstrap/README.md][bootstrap-internals] to read about bootstrap internals - Stage 3: the same-result test Compiling `rustc` is done in stages. -Here's a diagram, adapted from Jynn -Nelson's [talk on bootstrapping][rustconf22-talk] at RustConf 2022, +Here's a diagram, +adapted from Jynn Nelson's [talk on bootstrapping][rustconf22-talk] at RustConf 2022, with detailed explanations below. The `A`, `B`, `C`, and `D` show the ordering of the stages of bootstrapping. @@ -300,8 +300,8 @@ but `lib` will never be part of the search path. Since `lib/rustlib/` is part of the search path we have to be careful about which crates are included in it. -In particular, all crates except for the -standard library are built with the flag `-Z force-unstable-if-unmarked`, +In particular, +all crates except for the standard library are built with the flag `-Z force-unstable-if-unmarked`, which means that you have to use `#![feature(rustc_private)]` in order to load it (as opposed to the standard library, which is always available). From d3bfa9af7d334504301ea2941e07b8664cf08750 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:33:11 +0200 Subject: [PATCH 47/71] improve building/bootstrapping/what-bootstrapping-does.md --- .../bootstrapping/what-bootstrapping-does.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md index fda9f29ae3ca9..4fe42ebffd574 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md @@ -298,12 +298,12 @@ but `lib` will never be part of the search path. #### `-Z force-unstable-if-unmarked` -Since `lib/rustlib/` is part of the search path we have to be careful about -which crates are included in it. -In particular, -all crates except for the standard library are built with the flag `-Z force-unstable-if-unmarked`, -which means that you have to use `#![feature(rustc_private)]` in order to load it (as -opposed to the standard library, which is always available). +Since `lib/rustlib/` is part of the search path, +we have to be careful about which crates are included in it. +In particular, all crates, except for the standard library, +are built with the flag `-Z force-unstable-if-unmarked`, +meaning that you have to use `#![feature(rustc_private)]` in order to load it +(as opposed to the standard library, which is always available). The `-Z force-unstable-if-unmarked` flag has a variety of purposes to help enforce that the correct crates are marked as `unstable`. From bb523e8c4c51409742af9d6037cc157bab6ee7e6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 12:02:06 +0200 Subject: [PATCH 48/71] make it one big test --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 76 ++++++++------------ 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index 052036bb87f32..5ee0c3af1b4d6 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -240,6 +240,8 @@ o? whatever r? @reviewer r? @reviewer ~? diagnostic + +the queries that we do, as well as the **query DAG**. The "; let expected = " # some. heading @@ -273,6 +275,9 @@ whatever r? @reviewer r? @reviewer ~? diagnostic + +the queries that we do, as well as the **query DAG**. +The "; assert_eq!(expected, comply(original)); } @@ -309,6 +314,18 @@ html comment closing handle the indented well +split on comma (filler), of +current line + + split on comma (filler), of + current line + +split on +comma (filler), of next line + + split on + comma (filler), of next line + [a target]: https://example.com [another target]: https://example.com "; @@ -340,10 +357,22 @@ html comment closing handle the indented well +split on comma (filler), +of current line + + split on comma (filler), + of current line + +split on comma (filler), +of next line + + split on comma (filler), + of next line + [a target]: https://example.com [another target]: https://example.com "; - assert_eq!(expected, reformat_lines(original, 50)); + assert_eq!(expected, reformat_lines(original, 30)); } #[test] @@ -352,48 +381,3 @@ fn should_pass() { let original = "if you see `input isn't interesting! verify interesting-ness test`."; assert_eq!(original, comply(original)); } - -#[test] -fn split_on_comma_of_current_line() { - let original = " -Each derived value has a dependency, on other values, which could themselves be either base or -derived. - - Each derived value has a dependency, on other values, which could themselves be either base or - derived. -"; - let expected = " -Each derived value has a dependency, on other values, -which could themselves be either base or derived. - - Each derived value has a dependency, on other values, - which could themselves be either base or derived. -"; - assert_eq!(expected, reformat_lines(original, 100)) -} - -#[test] -fn split_on_comma_of_next_line() { - let original = " -Because of canonicalization of regions and -inference variables, encountering a cycle doesn't mean that we would get an infinite proof tree. - - Because of canonicalization of regions and - inference variables, encountering a cycle doesn't mean that we would get an infinite proof tree. -"; - let expected = " -Because of canonicalization of regions and inference variables, -encountering a cycle doesn't mean that we would get an infinite proof tree. - - Because of canonicalization of regions and inference variables, - encountering a cycle doesn't mean that we would get an infinite proof tree. -"; - assert_eq!(expected, reformat_lines(original, 100)) -} - -#[test] -fn should_split() { - let original = "the queries that we do, as well as the **query DAG**. The"; - let expected = "the queries that we do, as well as the **query DAG**.\nThe\n"; - assert_eq!(expected, comply(original)); -} From af57095aaaae2911a52d283c8af94e3579cdad20 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 12:02:53 +0200 Subject: [PATCH 49/71] shorten, to match the other fn, "comply" --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index 5ee0c3af1b4d6..54c716959e154 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -50,12 +50,12 @@ fn main() -> Result<()> { let old = fs::read_to_string(&path)?; let mut new = comply(&old); if cli.reflow_harder { - new = reformat_lines(&new, cli.line_length_limit) + new = reformat(&new, cli.line_length_limit) } if new == old { compliant.push(path.clone()); } else if cli.overwrite { - fs::write(&path, reformat_lines(&new, cli.line_length_limit))?; + fs::write(&path, reformat(&new, cli.line_length_limit))?; made_compliant.push(path.clone()); } else { not_compliant.push(path.clone()); @@ -134,7 +134,7 @@ fn comply(content: &str) -> String { } // This reformats lines, so that changes of "fn comply" look more pretty -fn reformat_lines(content: &str, limit: usize) -> String { +fn reformat(content: &str, limit: usize) -> String { let content: Vec<_> = content.lines().map(std::borrow::ToOwned::to_owned).collect(); let mut new_content = content.clone(); let mut new_n = 0; @@ -372,7 +372,7 @@ of next line [a target]: https://example.com [another target]: https://example.com "; - assert_eq!(expected, reformat_lines(original, 30)); + assert_eq!(expected, reformat(original, 30)); } #[test] From 788454540d39e313eb6daf063b6feb45b693c4b1 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 18:42:42 +0200 Subject: [PATCH 50/71] sembr src/diagnostics.md --- src/doc/rustc-dev-guide/src/diagnostics.md | 197 ++++++++++----------- 1 file changed, 98 insertions(+), 99 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index 0928f27940885..b807c7b381b5d 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -41,15 +41,15 @@ LL | more code - Primary and secondary spans underlying the users' code. These spans can optionally contain one or more labels. - Primary spans should have enough text to describe the problem in such a - way that if it were the only thing being displayed (for example, in an - IDE) it would still make sense. - Because it is "spatially aware" (it - points at the code), it can generally be more succinct than the error message. - - If cluttered output can be foreseen in cases when multiple span labels - overlap, it is a good idea to tweak the output appropriately. + way that if it were the only thing being displayed (for example, + in an IDE) it would still make sense. + Because it is "spatially aware" (it points at the code), + it can generally be more succinct than the error message. + - If cluttered output can be foreseen in cases when multiple span labels overlap, + it is a good idea to tweak the output appropriately. For example, the `if/else arms have incompatible types` error uses different - spans depending on whether the arms are all in the same line, if one of - the arms is empty and if none of those cases applies. + spans depending on whether the arms are all in the same line, + if one of the arms is empty and if none of those cases applies. - Sub-diagnostics. Any error can have multiple sub-diagnostics that look similar to the main part of the error. These are used for cases where the @@ -57,15 +57,15 @@ LL | more code If the order of the explanation can be "order free", leveraging secondary labels in the main diagnostic is preferred, as it is typically less verbose. -The text should be matter of fact and avoid capitalization and periods, unless -multiple sentences are _needed_: +The text should be matter of fact and avoid capitalization and periods, +unless multiple sentences are _needed_: ```txt error: the fobrulator needs to be krontrificated ``` -When code or an identifier must appear in a message or label, it should be -surrounded with backticks: +When code or an identifier must appear in a message or label, +it should be surrounded with backticks: ```txt error: the identifier `foo.bar` is invalid @@ -84,12 +84,12 @@ explanation would give more information than the error itself. A lot of the time it's better to put all the information in the emitted error itself. However, sometimes that would make the error verbose or there are too many possible -triggers to include useful information for all cases in the error, in which case -it's a good idea to add an explanation.[^estebank] +triggers to include useful information for all cases in the error, +in which case it's a good idea to add an explanation.[^estebank] As always, if you are not sure, just ask your reviewer! -If you decide to add a new error with an associated error code, please read -[this section][error-codes] for a guide and important details about the process. +If you decide to add a new error with an associated error code, +please read [this section][error-codes] for a guide and important details about the process. [^estebank]: This rule of thumb was suggested by **@estebank** [here][estebank-comment]. @@ -102,23 +102,23 @@ If you decide to add a new error with an associated error code, please read Some messages are emitted via [lints](#lints), where the user can control the level. Most diagnostics are hard-coded such that the user cannot control the level. -Usually it is obvious whether a diagnostic should be "fixed" or a lint, but -there are some grey areas. +Usually it is obvious whether a diagnostic should be "fixed" or a lint, +but there are some grey areas. Here are a few examples: - Borrow checker errors: these are fixed errors. The user cannot adjust the level of these diagnostics to silence the borrow checker. - Dead code: this is a lint. - While the user probably doesn't want dead code in - their crate, making this a hard error would make refactoring and development very painful. + While the user probably doesn't want dead code in their crate, + making this a hard error would make refactoring and development very painful. - [future-incompatible lints]: these are silenceable lints. It was decided that making them fixed errors would cause too much breakage, so warnings are instead emitted, and will eventually be turned into fixed (hard) errors. -Hard-coded warnings (those using methods like `span_warn`) should be avoided -for normal code, preferring to use lints instead. +Hard-coded warnings (those using methods like `span_warn`) should be avoided for normal code, +preferring to use lints instead. Some cases, such as warnings with CLI flags, will require the use of hard-coded warnings. See the `deny` [lint level](#diagnostic-levels) below for guidelines when to @@ -133,11 +133,11 @@ use an error-level lint instead of a fixed error. small – screen (which hasn't been cleaned for a while), cannot be understood by a normal programmer, who just came out of bed after a night partying, it's too complex. -- `Error`, `Warning`, `Note`, and `Help` messages start with a lowercase - letter and do not end with punctuation. +- `Error`, `Warning`, `Note`, + and `Help` messages start with a lowercase letter and do not end with punctuation. - Error messages should be succinct. - Users will see these error messages many - times, and more verbose descriptions can be viewed with the `--explain` flag. + Users will see these error messages many times, + and more verbose descriptions can be viewed with the `--explain` flag. That said, don't make it so terse that it's hard to understand. - The word "illegal" is illegal. Prefer "invalid" or a more specific word instead. @@ -145,8 +145,8 @@ use an error-level lint instead of a fixed error. [`rustc_errors::DiagCtxt`][DiagCtxt]'s `span_*` methods or a diagnostic struct's `#[primary_span]` to easily do this). Also `note` other spans that have contributed to the error if the span isn't too large. -- When emitting a message with span, try to reduce the span to the smallest - amount possible that still signifies the issue +- When emitting a message with span, + try to reduce the span to the smallest amount possible that still signifies the issue - Try not to emit multiple error messages for the same error. This may require detecting duplicates. - When the compiler has too little information for a specific error message, @@ -154,8 +154,8 @@ use an error-level lint instead of a fixed error. allow adding more information. For example, see [`#[rustc_on_unimplemented]`](#rustc_on_unimplemented). Use these annotations when available! -- Keep in mind that Rust's learning curve is rather steep, and that the - compiler messages are an important learning tool. +- Keep in mind that Rust's learning curve is rather steep, + and that the compiler messages are an important learning tool. - When talking about the compiler, call it `the compiler`, not `Rust` or `rustc`. - Use the [Oxford comma](https://en.wikipedia.org/wiki/Serial_comma) when writing lists of items. - When mentioning attributes, use this form whenever possible: "the `inline` attribute". @@ -168,8 +168,8 @@ From [RFC 0344], lint names should be consistent, with the following guidelines: The basic rule is: the lint name should make sense when read as "allow *lint-name*" or "allow *lint-name* items". -For example, "allow `deprecated` items" and "allow `dead_code`" makes sense, while "allow -`unsafe_block`" is ungrammatical (should be plural). +For example, "allow `deprecated` items" and "allow `dead_code`" makes sense, +while "allow `unsafe_block`" is ungrammatical (should be plural). - Lint names should state the bad thing being checked for, e.g. `deprecated`, so that `#[allow(deprecated)]` (items) reads correctly. @@ -180,8 +180,8 @@ For example, "allow `deprecated` items" and "allow `dead_code`" makes sense, whi This keeps lint names short. (Again, think "allow *lint-name* items".) -- If a lint applies to a specific grammatical class, mention that class and - use the plural form: use `unused_variables` rather than `unused_variable`. +- If a lint applies to a specific grammatical class, + mention that class and use the plural form: use `unused_variables` rather than `unused_variable`. This makes `#[allow(unused_variables)]` read correctly. - Lints that catch unnecessary, unused, or useless aspects of code should use @@ -200,12 +200,12 @@ Guidelines for different diagnostic levels: has decided to make a specific `warning` into an error. - `warning`: emitted when the compiler detects something odd about a program. - Care should be taken when adding warnings to avoid warning fatigue, and - avoid false-positives where there really isn't a problem with the code. + Care should be taken when adding warnings to avoid warning fatigue, + and avoid false-positives where there really isn't a problem with the code. Some examples of when it is appropriate to issue a warning: - - A situation where the user *should* take action, such as swap out a - deprecated item, or use a `Result`, but otherwise doesn't prevent compilation. + - A situation where the user *should* take action, such as swap out a deprecated item, + or use a `Result`, but otherwise doesn't prevent compilation. - Unnecessary syntax that can be removed without affecting the semantics of the code. For example, unused code, or unnecessary `unsafe`. - Code that is very likely to be incorrect, dangerous, or confusing, but the @@ -214,13 +214,13 @@ Guidelines for different diagnostic levels: `bindings_with_variant_name` (the user likely did not intend to create a binding in a pattern). - [Future-incompatible lints](#future-incompatible), where something was - accidentally or erroneously accepted in the past, but rejecting would - cause excessive breakage in the ecosystem. + accidentally or erroneously accepted in the past, + but rejecting would cause excessive breakage in the ecosystem. - Stylistic choices. For example, camel or snake case, or the `dyn` trait warning in the 2018 edition. These have a high bar to be added, and should only be used in exceptional circumstances. - Other stylistic choices should - either be allow-by-default lints, or part of other tools like Clippy or rustfmt. + Other stylistic choices should either be allow-by-default lints, + or part of other tools like Clippy or rustfmt. - `help`: emitted following an `error` or `warning` to give additional information to the user about how to solve their problem. @@ -247,8 +247,8 @@ Not to be confused with *lint levels*, whose guidelines are: Some examples: - A future-incompatible or edition-based lint that has graduated from the warning level. - - Something that has an extremely high confidence that is incorrect, but - still want an escape hatch to allow it to pass. + - Something that has an extremely high confidence that is incorrect, + but still want an escape hatch to allow it to pass. - `warn`: Equivalent to the `warning` diagnostic level. See `warning` above for guidelines. @@ -279,8 +279,8 @@ There are three main ways to find where a given error is emitted: constructed behind a relatively deep call-stack. Even then, it is a good way to get your bearings. - Invoking `rustc` with the nightly-only flag `-Z treat-err-as-bug=1` - will treat the first error being emitted as an Internal Compiler Error, which - allows you to get a stack trace at the point the error has been emitted. + will treat the first error being emitted as an Internal Compiler Error, + which allows you to get a stack trace at the point the error has been emitted. Change the `1` to something else if you wish to trigger on a later error. There are limitations with this approach: @@ -299,8 +299,8 @@ order things are happening. [`Span`][span] is the primary data structure in `rustc` used to represent a location in the code being compiled. -`Span`s are attached to most constructs in -HIR and MIR, allowing for more informative error reporting. +`Span`s are attached to most constructs in HIR and MIR, +allowing for more informative error reporting. [span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html @@ -320,8 +320,8 @@ The [`rustc_errors`][errors] crate defines most of the utilities used for report Diagnostics can be implemented as types which implement the `Diagnostic` trait. This is preferred for new diagnostics as it enforces a separation between diagnostic emitting logic and the main code paths. -For less-complex diagnostics, the `Diagnostic` trait can be derived -- see [Diagnostic -structs][diagnostic-structs]. +For less-complex diagnostics, +the `Diagnostic` trait can be derived -- see [Diagnostic structs][diagnostic-structs]. Within the trait implementation, the APIs described below can be used as normal. [diagnostic-structs]: ./diagnostics/diagnostic-structs.md @@ -337,12 +337,11 @@ warnings, errors, fatal errors, suggestions, etc. In general, there are two classes of such methods: ones that emit an error directly and ones that allow finer control over what to emit. For example, -[`span_err`][spanerr] emits the given error message at the given `Span`, but -[`struct_span_err`][strspanerr] instead returns a [`Diag`][diag]. +[`span_err`][spanerr] emits the given error message at the given `Span`, +but [`struct_span_err`][strspanerr] instead returns a [`Diag`][diag]. Most of these methods will accept strings, but it is recommended that typed -identifiers for translatable diagnostics be used for new diagnostics (see -[Translation]). +identifiers for translatable diagnostics be used for new diagnostics (see [Translation]). [translation]: ./diagnostics/translation.md @@ -385,8 +384,8 @@ example-example-error = oh no! this is an error! ## Suggestions -In addition to telling the user exactly _why_ their code is wrong, it's -oftentimes furthermore possible to tell them how to fix it. +In addition to telling the user exactly _why_ their code is wrong, +it's oftentimes furthermore possible to tell them how to fix it. To this end, [`Diag`][diag] offers a structured suggestions API, which formats code suggestions pleasingly in the terminal, or (when the `--error-format json` flag @@ -398,8 +397,7 @@ Not all suggestions should be applied mechanically; they have a degree of confidence in the suggested code, from high (`Applicability::MachineApplicable`) to low (`Applicability::MaybeIncorrect`). Be conservative when choosing the level. -Use the [`span_suggestion`][span_suggestion] method of `Diag` to -make a suggestion. +Use the [`span_suggestion`][span_suggestion] method of `Diag` to make a suggestion. The last argument provides a hint to tools whether the suggestion is mechanically applicable or not. Suggestions point to one or more spans with corresponding code that will @@ -515,8 +513,8 @@ Some of the passes are: - Example: [`keyword_idents`] checks for identifiers that will become keywords in future editions, but is sensitive to identifiers used in macros. -- Early lint pass: Works on [AST nodes] after [macro expansion] and name - resolution, just before [AST lowering]. +- Early lint pass: Works on [AST nodes] after [macro expansion] and name resolution, + just before [AST lowering]. These lints are for purely syntactical lints. - Example: The [`unused_parens`] lint checks for parenthesized-expressions in situations where they are not needed, like an `if` condition. @@ -534,11 +532,11 @@ Some of the passes are: - Example: The [`arithmetic_overflow`] lint is emitted when it detects a constant value that may overflow. -Most lints work well via the pass systems, and they have a fairly -straightforward interface and easy way to integrate (mostly just implementing +Most lints work well via the pass systems, +and they have a fairly straightforward interface and easy way to integrate (mostly just implementing a specific `check` function). -However, some lints are easier to write when -they live on a specific code path anywhere in the compiler. +However, +some lints are easier to write when they live on a specific code path anywhere in the compiler. For example, the [`unused_mut`] lint is implemented in the borrow checker as it requires some information and state in the borrow checker. @@ -589,8 +587,8 @@ One benefit is that it is close to the dependency root, so it can be much faster [`rustc_lint_defs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/index.html Every lint is implemented via a `struct` that implements the `LintPass` `trait` -(you can also implement one of the more specific lint pass traits, either -`EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run). +(you can also implement one of the more specific lint pass traits, +either `EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run). The trait implementation allows you to check certain syntactic constructs as the linter walks the AST. You can then choose to emit lints in a very similar way to compile errors. @@ -711,10 +709,11 @@ In general, future-incompatible code exists for two reasons: * The user has written unsound code that the compiler mistakenly accepted. While it is within Rust's backwards compatibility guarantees to fix the soundness hole (breaking the user's code), the lint is there to warn the user that this will happen -in some upcoming version of rustc *regardless of which edition the code uses*. This is the -meaning that rustc exclusively exposes to users as "future incompatible". +in some upcoming version of rustc *regardless of which edition the code uses*. +This is the meaning that rustc exclusively exposes to users as "future incompatible". * The user has written code that will either no longer compiler *or* will change -meaning in an upcoming *edition*. These are often called "edition lints" and can be +meaning in an upcoming *edition*. +These are often called "edition lints" and can be typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`) that are used to lint against code that will break if the user updates the crate's edition. See [migration lints](guides/editions.md#migration-lints) for more details. @@ -735,8 +734,8 @@ declare_lint! { Notice the `reason` field which describes why the future incompatible change is happening. This will change the diagnostic message the user receives as well as determine which lint groups the lint is added to. -In the example above, the lint is an "edition lint" -(since its "reason" is `EditionError`), signifying to the user that the use of anonymous +In the example above, the lint is an "edition lint" (since its "reason" is `EditionError`), +signifying to the user that the use of anonymous parameters will no longer compile in Rust 2018 and beyond. Inside [LintStore::register_lints][fi-lint-groupings], lints with `future_incompatible` @@ -745,16 +744,16 @@ an edition) or into the `future_incompatibility` lint group. [fi-lint-groupings]: https://github.com/rust-lang/rust/blob/51fd129ac12d5bfeca7d216c47b0e337bf13e0c2/compiler/rustc_lint/src/context.rs#L212-L237 -If you need a combination of options that's not supported by the -`declare_lint!` macro, you can always change the `declare_lint!` macro to support this. +If you need a combination of options that's not supported by the `declare_lint!` macro, +you can always change the `declare_lint!` macro to support this. ### Renaming or removing a lint If it is determined that a lint is either improperly named or no longer needed, -the lint must be registered for renaming or removal, which will trigger a warning if a user tries -to use the old lint name. -To declare a rename/remove, add a line with -[`store.register_renamed`] or [`store.register_removed`] to the code of the +the lint must be registered for renaming or removal, +which will trigger a warning if a user tries to use the old lint name. +To declare a rename/remove, +add a line with [`store.register_renamed`] or [`store.register_removed`] to the code of the [`rustc_lint::register_builtins`] function. ```rust,ignore @@ -785,15 +784,15 @@ add_lint_group!(sess, ``` This defines the `nonstandard_style` group which turns on the listed lints. -A user can turn on these lints with a `#![warn(nonstandard_style)]` attribute in -the source code, or by passing `-W nonstandard-style` on the command line. +A user can turn on these lints with a `#![warn(nonstandard_style)]` attribute in the source code, +or by passing `-W nonstandard-style` on the command line. Some lint groups are created automatically in `LintStore::register_lints`. For instance, any lint declared with `FutureIncompatibleInfo` where the reason is `FutureIncompatibilityReason::FutureReleaseError` (the default when -`@future_incompatible` is used in `declare_lint!`), will be added to -the `future_incompatible` lint group. +`@future_incompatible` is used in `declare_lint!`), +will be added to the `future_incompatible` lint group. Editions also have their own lint groups (e.g., `rust_2021_compatibility`) automatically generated for any lints signaling future-incompatible code that will break in the specified edition. @@ -813,15 +812,15 @@ The linting system automatically takes care of handling buffered lints later. [sessbl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html#method.buffer_lint [parsebl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.ParseSess.html#method.buffer_lint -Thus, to define a lint that runs early in the compilation, one defines a lint -like normal but invokes the lint with `buffer_lint`. +Thus, to define a lint that runs early in the compilation, +one defines a lint like normal but invokes the lint with `buffer_lint`. #### Linting even earlier in the compiler The parser (`rustc_ast`) is interesting in that it cannot have dependencies on any of the other `rustc*` crates. -In particular, it cannot depend on -`rustc_middle::lint` or `rustc_lint`, where all of the compiler linting infrastructure is defined. +In particular, it cannot depend on `rustc_middle::lint` or `rustc_lint`, +where all of the compiler linting infrastructure is defined. That's troublesome! To solve this, `rustc_ast` defines its own buffered lint type, which `ParseSess::buffer_lint` uses. @@ -841,20 +840,20 @@ $ rustc json_error_demo.rs --error-format json {"message":"For more information about this error, try `rustc --explain E0277`.","code":null,"level":"","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0277`.\n"} ``` -Note that the output is a series of lines, each of which is a JSON -object, but the series of lines taken together is, unfortunately, not +Note that the output is a series of lines, each of which is a JSON object, +but the series of lines taken together is, unfortunately, not valid JSON, thwarting tools and tricks (such as [piping to `python3 -m json.tool`](https://docs.python.org/3/library/json.html#module-json.tool)) that require such. -(One speculates that this was intentional for LSP -performance purposes, so that each line/object can be sent as it is flushed?) +(One speculates that this was intentional for LSP performance purposes, +so that each line/object can be sent as it is flushed?) Also note the "rendered" field, which contains the "human" output as a string; this was introduced so that UI tests could both make use of -the structured JSON and see the "human" output (well, _sans_ colors) -without having to compile everything twice. +the structured JSON and see the "human" output (well, +_sans_ colors) without having to compile everything twice. -The "human" readable and the json format emitter can be found under -`rustc_errors`, both were moved from the `rustc_ast` crate to the +The "human" readable and the json format emitter can be found under `rustc_errors`, +both were moved from the `rustc_ast` crate to the [rustc_errors crate](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html). The JSON emitter defines [its own `Diagnostic` @@ -937,16 +936,16 @@ If you can, you should use that instead. ### Filtering -To allow more targeted error messages, it is possible to filter the -application of these fields with `on`. +To allow more targeted error messages, +it is possible to filter the application of these fields with `on`. You can filter on the following boolean flags: - `crate_local`: whether the code causing the trait bound to not be fulfilled is part of the user's crate. This is used to avoid suggesting code changes that would require modifying a dependency. - `direct`: whether this is a user-specified rather than derived obligation. - - `from_desugaring`: whether we are in some kind of desugaring, like `?` - or a `try` block for example. + - `from_desugaring`: whether we are in some kind of desugaring, + like `?` or a `try` block for example. This flag can also be matched on, see below. You can match on the following names and values, using `name = "value"`: @@ -955,8 +954,8 @@ You can match on the following names and values, using `name = "value"`: - `from_desugaring`: Match against a particular variant of the `DesugaringKind` enum. The desugaring is identified by its variant name, for example `"QuestionMark"` for `?` desugaring, or `"TryBlock"` for `try` blocks. - - `Self` and any generic arguments of the trait, like `Self = "alloc::string::String"` - or `Rhs="i32"`. + - `Self` and any generic arguments of the trait, + like `Self = "alloc::string::String"` or `Rhs="i32"`. The compiler can provide several values to match on, for example: - the self_ty, pretty printed with and without type arguments resolved. From 2238f1bca22392ffa055e9f5bc06e4a8b8f0c27c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:03:37 +0200 Subject: [PATCH 51/71] improve diagnostics.md --- src/doc/rustc-dev-guide/src/diagnostics.md | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index b807c7b381b5d..661e07af7189c 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -49,7 +49,7 @@ LL | more code it is a good idea to tweak the output appropriately. For example, the `if/else arms have incompatible types` error uses different spans depending on whether the arms are all in the same line, - if one of the arms is empty and if none of those cases applies. + if one of the arms is empty, and if none of those cases applies. - Sub-diagnostics. Any error can have multiple sub-diagnostics that look similar to the main part of the error. These are used for cases where the @@ -588,7 +588,7 @@ One benefit is that it is close to the dependency root, so it can be much faster Every lint is implemented via a `struct` that implements the `LintPass` `trait` (you can also implement one of the more specific lint pass traits, -either `EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run). +either `EarlyLintPass` or `LateLintPass`, depending on when is best for your lint to run). The trait implementation allows you to check certain syntactic constructs as the linter walks the AST. You can then choose to emit lints in a very similar way to compile errors. @@ -698,25 +698,25 @@ declare_lint! { } ``` -### Future-incompatible lints +### future-incompatible lints The use of the term `future-incompatible` within the compiler has a slightly broader meaning than what rustc exposes to users of the compiler. -Inside rustc, future-incompatible lints are for signalling to the user that code they have -written may not compile in the future. +Inside rustc, +future-incompatible lints are for signalling to the user their code may not compile in the future. In general, future-incompatible code exists for two reasons: -* The user has written unsound code that the compiler mistakenly accepted. +* The code is unsound, and the compiler mistakenly accepted it. While it is within Rust's backwards compatibility guarantees to fix the soundness hole -(breaking the user's code), the lint is there to warn the user that this will happen -in some upcoming version of rustc *regardless of which edition the code uses*. -This is the meaning that rustc exclusively exposes to users as "future incompatible". -* The user has written code that will either no longer compiler *or* will change -meaning in an upcoming *edition*. -These are often called "edition lints" and can be -typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`) -that are used to lint against code that will break if the user updates the crate's edition. -See [migration lints](guides/editions.md#migration-lints) for more details. + (breaking the user's code), the lint is there to warn the user that this will happen + in some upcoming version of rustc *regardless of which edition the code uses*. + This is the meaning that rustc exclusively exposes to users as "future incompatible". +* The code will either no longer compile *or* will change + meaning in an upcoming *edition*. + These are often called "edition lints" and can be + typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`) + that are used to lint against code that will break if the user updates the crate's edition. + See [migration lints](guides/editions.md#migration-lints) for more details. A future-incompatible lint should be declared with the `@future_incompatible` additional "field": From 56a6ee6d53d58e8cc685059766fd4aabc93f99e1 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:15:00 +0200 Subject: [PATCH 52/71] sembr src/mir/index.md --- src/doc/rustc-dev-guide/src/mir/index.md | 92 ++++++++++++------------ 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/mir/index.md b/src/doc/rustc-dev-guide/src/mir/index.md index b5b5b20500f39..a4075d1eae472 100644 --- a/src/doc/rustc-dev-guide/src/mir/index.md +++ b/src/doc/rustc-dev-guide/src/mir/index.md @@ -7,18 +7,18 @@ It is a radically simplified form of Rust that is used for certain flow-sensitive safety checks – notably the borrow checker! – and also for optimization and code generation. -If you'd like a very high-level introduction to MIR, as well as some -of the compiler concepts that it relies on (such as control-flow +If you'd like a very high-level introduction to MIR, +as well as some of the compiler concepts that it relies on (such as control-flow graphs and desugaring), you may enjoy the [rust-lang blog post that introduced MIR][blog]. [blog]: https://blog.rust-lang.org/2016/04/19/MIR.html ## Introduction to MIR -MIR is defined in the [`compiler/rustc_middle/src/mir/`][mir] module, but much of the code -that manipulates it is found in [`compiler/rustc_mir_build`][mirmanip_build], -[`compiler/rustc_mir_transform`][mirmanip_transform], and -[`compiler/rustc_mir_dataflow`][mirmanip_dataflow]. +MIR is defined in the [`compiler/rustc_middle/src/mir/`][mir] module, +but much of the code that manipulates it is found in [`compiler/rustc_mir_build`][mirmanip_build], +[`compiler/rustc_mir_transform`][mirmanip_transform], +and [`compiler/rustc_mir_dataflow`][mirmanip_dataflow]. [RFC 1211]: https://rust-lang.github.io/rfcs/1211-mir.html @@ -38,22 +38,22 @@ This section introduces the key concepts of MIR, summarized here: - **statements:** actions with one successor - **terminators:** actions with potentially multiple successors; always at the end of a block - (if you're not familiar with the term *basic block*, see the [background chapter][cfg]) -- **Locals:** Memory locations allocated on the stack (conceptually, at - least), such as function arguments, local variables, and temporaries. +- **Locals:** Memory locations allocated on the stack (conceptually, at least), + such as function arguments, local variables, and temporaries. These are identified by an index, written with a leading underscore, like `_1`. There is also a special "local" (`_0`) allocated to store the return value. - **Places:** expressions that identify a location in memory, like `_1` or `_1.f`. - **Rvalues:** expressions that produce a value. The "R" stands for the fact that these are the "right-hand side" of an assignment. - - **Operands:** the arguments to an rvalue, which can either be a - constant (like `22`) or a place (like `_1`). + - **Operands:** the arguments to an rvalue, + which can either be a constant (like `22`) or a place (like `_1`). You can get a feeling for how MIR is constructed by translating simple programs into MIR and reading the pretty printed output. -In fact, the playground makes this easy, since it supplies a MIR button that will -show you the MIR for your program. -Try putting this program into play -(or [clicking on this link][sample-play]), and then clicking the "MIR" button on the top: +In fact, the playground makes this easy, +since it supplies a MIR button that will show you the MIR for your program. +Try putting this program into play (or [clicking on this link][sample-play]), +and then clicking the "MIR" button on the top: [sample-play]: https://play.rust-lang.org/?gist=30074856e62e74e91f06abd19bd72ece&version=stable&edition=2021 @@ -83,8 +83,8 @@ We can use `rustc [filename].rs -Z mir-opt-level=0 --emit mir` to view unoptimiz This requires the nightly toolchain. -**Variable declarations.** If we drill in a bit, we'll see it begins -with a bunch of variable declarations. +**Variable declarations.** If we drill in a bit, +we'll see it begins with a bunch of variable declarations. They look like this: ```mir @@ -101,8 +101,8 @@ like `_0` or `_1`. We also intermingle the user's variables (e.g., `_1`) with temporary values (e.g., `_2` or `_3`). You can tell apart user-defined variables because they have debuginfo associated to them (see below). -**User variable debuginfo.** Below the variable declarations, we find the only -hint that `_1` represents a user variable: +**User variable debuginfo.** Below the variable declarations, +we find the only hint that `_1` represents a user variable: ```mir scope 1 { debug vec => _1; // in scope 1 at src/main.rs:2:9: 2:16 @@ -130,15 +130,15 @@ bb0: { } ``` -A basic block is defined by a series of **statements** and a final -**terminator**. In this case, there is one statement: +A basic block is defined by a series of **statements** and a final **terminator**. + In this case, there is one statement: ```mir StorageLive(_1); ``` -This statement indicates that the variable `_1` is "live", meaning -that it may be used later – this will persist until we encounter a +This statement indicates that the variable `_1` is "live", +meaning that it may be used later – this will persist until we encounter a `StorageDead(_1)` statement, which indicates that the variable `_1` is done being used. These "storage statements" are used by LLVM to allocate stack space. @@ -151,8 +151,8 @@ _1 = const >::new() -> bb2; Terminators are different from statements because they can have more than one successor – that is, control may flow to different places. Function calls like the call to `Vec::new` are always -terminators because of the possibility of unwinding, although in the -case of `Vec::new` we are able to see that indeed unwinding is not +terminators because of the possibility of unwinding, +although in the case of `Vec::new` we are able to see that indeed unwinding is not possible, and hence we list only one successor block, `bb2`. If we look ahead to `bb2`, we will see it looks like this: @@ -165,8 +165,8 @@ bb2: { } ``` -Here there are two statements: another `StorageLive`, introducing the `_3` -temporary, and then an assignment: +Here there are two statements: another `StorageLive`, introducing the `_3` temporary, +and then an assignment: ```mir _3 = &mut _1; @@ -179,8 +179,8 @@ Assignments in general have the form: ``` A place is an expression like `_3`, `_3.f` or `*_3` – it denotes a location in memory. -An **Rvalue** is an expression that creates a -value: in this case, the rvalue is a mutable borrow expression, which looks like `&mut `. +An **Rvalue** is an expression that creates a value: in this case, +the rvalue is a mutable borrow expression, which looks like `&mut `. So we can kind of define a grammar for rvalues like so: ```text @@ -194,21 +194,21 @@ So we can kind of define a grammar for rvalues like so: | move Place ``` -As you can see from this grammar, rvalues cannot be nested – they can -only reference places and constants. +As you can see from this grammar, +rvalues cannot be nested – they can only reference places and constants. Moreover, when you use a place, we indicate whether we are **copying it** (which requires that the place have a type `T` where `T: Copy`) or **moving it** (which works for a place of any type). -So, for example, if we had the expression `x -= a + b + c` in Rust, that would get compiled to two statements and a temporary: +So, for example, if we had the expression `x = a + b + c` in Rust, +that would get compiled to two statements and a temporary: ```mir TMP1 = a + b x = TMP1 + c ``` -([Try it and see][play-abc], though you may want to do release mode to skip -over the overflow checks.) +([Try it and see][play-abc], +though you may want to do release mode to skip over the overflow checks.) [play-abc]: https://play.rust-lang.org/?gist=1751196d63b2a71f8208119e59d8a5b6&version=stable @@ -225,8 +225,8 @@ but [you can read about those below](#promoted-constants)). - **Basic blocks**: The basic blocks are stored in the field [`Body::basic_blocks`][basicblocks]; this is a vector of [`BasicBlockData`] structures. - Nobody ever references a basic block directly: instead, we pass around [`BasicBlock`] - values, which are [newtype'd] indices into this vector. + Nobody ever references a basic block directly: instead, we pass around [`BasicBlock`] values, + which are [newtype'd] indices into this vector. - **Statements** are represented by the type [`Statement`]. - **Terminators** are represented by the [`Terminator`]. - **Locals** are represented by a [newtype'd] index type [`Local`]. @@ -240,8 +240,8 @@ but [you can read about those below](#promoted-constants)). These are represented by the [newtype'd] type [`ProjectionElem`]. So e.g. the place `_1.f` is a projection, with `f` being the "projection element" and `_1` being the base path. - `*_1` is also a projection, with the `*` being represented - by the [`ProjectionElem::Deref`] element. + `*_1` is also a projection, + with the `*` being represented by the [`ProjectionElem::Deref`] element. - **Rvalues** are represented by the enum [`Rvalue`]. - **Operands** are represented by the enum [`Operand`]. @@ -251,8 +251,8 @@ When code has reached the MIR stage, constants can generally come in two forms: *MIR constants* ([`mir::Constant`]) and *type system constants* ([`ty::Const`]). MIR constants are used as operands: in `x + CONST`, `CONST` is a MIR constant; similarly, in `x + 2`, `2` is a MIR constant. -Type system constants are used in -the type system, in particular for array lengths but also for const generics. +Type system constants are used in the type system, +in particular for array lengths but also for const generics. Generally, both kinds of constants can be "unevaluated" or "already evaluated". An unevaluated constant simply stores the `DefId` of what needs to be evaluated @@ -270,8 +270,8 @@ parameter is used as an operand. ### MIR constant values -In general, a MIR constant value (`mir::ConstValue`) was computed by evaluating -some constant the user wrote. +In general, +a MIR constant value (`mir::ConstValue`) was computed by evaluating some constant the user wrote. This [const evaluation](../const-eval.md) produces a very low-level representation of the result in terms of individual bytes. We call this an "indirect" constant (`mir::ConstValue::Indirect`) since the value @@ -280,8 +280,8 @@ is stored in-memory. However, storing everything in-memory would be awfully inefficient. Hence there are some other variants in `mir::ConstValue` that can represent certain simple and common values more efficiently. -In particular, everything that can be -directly written as a literal in Rust (integers, floats, chars, bools, but also +In particular, everything that can be directly written as a literal in Rust (integers, +floats, chars, bools, but also `"string literals"` and `b"byte string literals"`) has an optimized variant that avoids the full overhead of the in-memory representation. @@ -301,8 +301,8 @@ In other words, a specific value must only be representable in one specific way. For example, there is only one way to represent an array of two integers as a `ValTree`: `Branch([Leaf(first_int), Leaf(second_int)])`. Even though theoretically a `[u32; 2]` could be encoded in a `u64` and thus just be a -`Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree` -(and is very complex to do, so it is unlikely anyone is tempted to do so). +`Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree` (and is very complex to do, +so it is unlikely anyone is tempted to do so). These rules also mean that some values are not representable. There can be no `union`s in type level constants, From 7710f70fce3173d176546f26fbad0ef1693797e3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:23:27 +0200 Subject: [PATCH 53/71] improve mir/index.md --- src/doc/rustc-dev-guide/src/mir/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/mir/index.md b/src/doc/rustc-dev-guide/src/mir/index.md index a4075d1eae472..6854447b66928 100644 --- a/src/doc/rustc-dev-guide/src/mir/index.md +++ b/src/doc/rustc-dev-guide/src/mir/index.md @@ -131,7 +131,7 @@ bb0: { ``` A basic block is defined by a series of **statements** and a final **terminator**. - In this case, there is one statement: +In this case, there is one statement: ```mir StorageLive(_1); @@ -252,7 +252,7 @@ When code has reached the MIR stage, constants can generally come in two forms: MIR constants are used as operands: in `x + CONST`, `CONST` is a MIR constant; similarly, in `x + 2`, `2` is a MIR constant. Type system constants are used in the type system, -in particular for array lengths but also for const generics. +in particular for array lengths, but also for const generics. Generally, both kinds of constants can be "unevaluated" or "already evaluated". An unevaluated constant simply stores the `DefId` of what needs to be evaluated From 88e8e029744220d08adf28cf9b660603940ab754 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:23:35 +0200 Subject: [PATCH 54/71] reflow src/mir/index.md --- src/doc/rustc-dev-guide/src/mir/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/mir/index.md b/src/doc/rustc-dev-guide/src/mir/index.md index 6854447b66928..005dc0cac21d9 100644 --- a/src/doc/rustc-dev-guide/src/mir/index.md +++ b/src/doc/rustc-dev-guide/src/mir/index.md @@ -152,8 +152,8 @@ Terminators are different from statements because they can have more than one successor – that is, control may flow to different places. Function calls like the call to `Vec::new` are always terminators because of the possibility of unwinding, -although in the case of `Vec::new` we are able to see that indeed unwinding is not -possible, and hence we list only one successor block, `bb2`. +although in the case of `Vec::new` we are able to see that indeed unwinding is not possible, +and hence we list only one successor block, `bb2`. If we look ahead to `bb2`, we will see it looks like this: @@ -281,8 +281,8 @@ However, storing everything in-memory would be awfully inefficient. Hence there are some other variants in `mir::ConstValue` that can represent certain simple and common values more efficiently. In particular, everything that can be directly written as a literal in Rust (integers, -floats, chars, bools, but also -`"string literals"` and `b"byte string literals"`) has an optimized variant that +floats, chars, bools, +but also `"string literals"` and `b"byte string literals"`) has an optimized variant that avoids the full overhead of the in-memory representation. ### ValTrees From 062f7aca04ec3766deac14e1b138b19136f64011 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:24:12 +0200 Subject: [PATCH 55/71] sembr src/tracing.md --- src/doc/rustc-dev-guide/src/tracing.md | 83 +++++++++++++------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md index ae819003e1f3e..811e36bb21d7a 100644 --- a/src/doc/rustc-dev-guide/src/tracing.md +++ b/src/doc/rustc-dev-guide/src/tracing.md @@ -1,9 +1,9 @@ # Using tracing to debug the compiler -The compiler has a lot of [`debug!`] (or `trace!`) calls, which print out logging information -at many points. -These are very useful to at least narrow down the location of -a bug if not to find it entirely, or just to orient yourself as to why the +The compiler has a lot of [`debug!`] (or `trace!`) calls, +which print out logging information at many points. +These are very useful to at least narrow down the location of a bug if not to find it entirely, +or just to orient yourself as to why the compiler is doing a particular thing. [`debug!`]: https://docs.rs/tracing/0.1/tracing/macro.debug.html @@ -66,8 +66,8 @@ RUSTC_LOG=rustc_borrowck[do_mir_borrowck] ### I don't want all calls -If you are compiling libcore, you likely don't want *all* borrowck dumps, but only one -for a specific function. +If you are compiling libcore, you likely don't want *all* borrowck dumps, +but only one for a specific function. You can filter function calls by their arguments by regexing them. ``` @@ -75,8 +75,8 @@ RUSTC_LOG=[do_mir_borrowck{id=\.\*from_utf8_unchecked\.\*}] ``` will only give you the logs of borrowchecking `from_utf8_unchecked`. -Note that you will -still get a short message per ignored `do_mir_borrowck`, but none of the things inside those calls. +Note that you will still get a short message per ignored `do_mir_borrowck`, +but none of the things inside those calls. This helps you in looking through the calls that are happening and helps you adjust your regex if you mistyped it. @@ -105,40 +105,41 @@ You can find a list of queries and their arguments in ## Broad module level filters -You can also use filters similar to the `log` crate's filters, which will enable -everything within a specific module. +You can also use filters similar to the `log` crate's filters, +which will enable everything within a specific module. This is often too verbose and too unstructured, so it is recommended to use function level filters. Your log filter can be just `debug` to get all `debug!` output and higher (e.g., it will also include `info!`), or `path::to::module` to get *all* -output (which will include `trace!`) from a particular module, or -`path::to::module=debug` to get `debug!` output and higher from a particular module. +output (which will include `trace!`) from a particular module, +or `path::to::module=debug` to get `debug!` output and higher from a particular module. -For example, to get the `debug!` output and higher for a specific module, you -can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs`. +For example, to get the `debug!` output and higher for a specific module, +you can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs`. All `debug!` output will then appear in standard error. Note that you can use a partial path and the filter will still work. For example, if you want to see `info!` output from only -`rustdoc::passes::collect_intra_doc_links`, you could use -`RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use +`rustdoc::passes::collect_intra_doc_links`, +you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra=info`. If you are developing rustdoc, use `RUSTDOC_LOG` instead. If you are developing Miri, use `MIRI_LOG` instead. You get the idea :) -See the [`tracing`] crate's docs, and specifically the docs for [`debug!`] to -see the full syntax you can use. -(Note: unlike the compiler, the [`tracing`] -crate and its examples use the `RUSTC_LOG` environment variable. +See the [`tracing`] crate's docs, +and specifically the docs for [`debug!`] to see the full syntax you can use. +(Note: unlike the compiler, +the [`tracing`] crate and its examples use the `RUSTC_LOG` environment variable. rustc, rustdoc, and other tools set custom environment variables.) -**Note that unless you use a very strict filter, the logger will emit a lot of -output, so use the most specific module(s) you can (comma-separated if -multiple)**. It's typically a good idea to pipe standard error to a file and +**Note that unless you use a very strict filter, the logger will emit a lot of output, +so use the most specific module(s) you can (comma-separated if +multiple)**. +It's typically a good idea to pipe standard error to a file and look at the log output with a text editor. So, to put it together: @@ -180,13 +181,13 @@ $ RUSTDOC_LOG=rustdoc=debug rustdoc +stage1 my-file.rs ## Log colors -By default, rustc (and other tools, like rustdoc and Miri) will be smart about -when to use ANSI colors in the log output. +By default, rustc (and other tools, +like rustdoc and Miri) will be smart about when to use ANSI colors in the log output. If they are outputting to a terminal, -they will use colors, and if they are outputting to a file or being piped -somewhere else, they will not. -However, it's hard to read log output in your -terminal unless you have a very strict filter, so you may want to pipe the +they will use colors, and if they are outputting to a file or being piped somewhere else, +they will not. +However, it's hard to read log output in your terminal unless you have a very strict filter, +so you may want to pipe the output to a pager like `less`. But then there won't be any colors, which makes it hard to pick out what you're looking for! @@ -201,18 +202,18 @@ So, if you want to enable colors when piping to `less`, use something similar to $ RUSTC_LOG=debug RUSTC_LOG_COLOR=always rustc +stage1 ... | less -R ``` -Note that `MIRI_LOG_COLOR` will only color logs that come from Miri, not logs -from rustc functions that Miri calls. +Note that `MIRI_LOG_COLOR` will only color logs that come from Miri, +not logs from rustc functions that Miri calls. Use `RUSTC_LOG_COLOR` to color logs from rustc. ## How to keep or remove `debug!` and `trace!` calls from the resulting binary While calls to `error!`, `warn!` and `info!` are included in every build of the compiler, calls to `debug!` and `trace!` are only included in the program if -`rust.debug-logging=true` is turned on in bootstrap.toml (it is -turned off by default), so if you don't see `DEBUG` logs, especially -if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see -`INFO` logs, make sure that `rust.debug-logging=true` is turned on in your bootstrap.toml. +`rust.debug-logging=true` is turned on in bootstrap.toml (it is turned off by default), +so if you don't see `DEBUG` logs, especially +if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see `INFO` logs, +make sure that `rust.debug-logging=true` is turned on in your bootstrap.toml. ## Logging etiquette and conventions @@ -220,11 +221,11 @@ Because calls to `debug!` are removed by default, in most cases, don't worry about the performance of adding "unnecessary" calls to `debug!` and leaving them in code you commit - they won't slow down the performance of what we ship. -That said, there can also be excessive tracing calls, especially -when they are redundant with other calls nearby or in functions called from here. +That said, there can also be excessive tracing calls, +especially when they are redundant with other calls nearby or in functions called from here. There is no perfect balance to hit here, and it is left to the reviewer's -discretion to decide whether to let you leave `debug!` statements in, or whether to ask -you to remove them before merging. +discretion to decide whether to let you leave `debug!` statements in, +or whether to ask you to remove them before merging. It may be preferable to use `trace!` over `debug!` for very noisy logs. @@ -243,8 +244,8 @@ If in the module `rustc::foo` you have a statement debug!(x = ?random_operation(tcx)); ``` -Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::foo`, then -`random_operation()` will run. +Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::foo`, +then `random_operation()` will run. `RUSTC_LOG` filters that do not enable this debug statement will not execute `random_operation`. This means that you should not put anything too expensive or likely to crash From bdd20078512c4aaf61271e050a14edf284b2dc28 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:29:23 +0200 Subject: [PATCH 56/71] improve tracing.md --- src/doc/rustc-dev-guide/src/tracing.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md index 811e36bb21d7a..e3c492bbf80e4 100644 --- a/src/doc/rustc-dev-guide/src/tracing.md +++ b/src/doc/rustc-dev-guide/src/tracing.md @@ -209,11 +209,11 @@ Use `RUSTC_LOG_COLOR` to color logs from rustc. ## How to keep or remove `debug!` and `trace!` calls from the resulting binary While calls to `error!`, `warn!` and `info!` are included in every build of the compiler, -calls to `debug!` and `trace!` are only included in the program if -`rust.debug-logging=true` is turned on in bootstrap.toml (it is turned off by default), +calls to `debug!` and `trace!` are only included in the program if you have +`rust.debug-logging = true` in bootstrap.toml (it is turned off by default), so if you don't see `DEBUG` logs, especially if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see `INFO` logs, -make sure that `rust.debug-logging=true` is turned on in your bootstrap.toml. +make sure that `rust.debug-logging` is turned on in your bootstrap.toml. ## Logging etiquette and conventions From e60b15334b90523d3167f80c897f581d040b9718 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:29:42 +0200 Subject: [PATCH 57/71] reflow src/tracing.md --- src/doc/rustc-dev-guide/src/tracing.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md index e3c492bbf80e4..0e2f29f698cba 100644 --- a/src/doc/rustc-dev-guide/src/tracing.md +++ b/src/doc/rustc-dev-guide/src/tracing.md @@ -3,8 +3,7 @@ The compiler has a lot of [`debug!`] (or `trace!`) calls, which print out logging information at many points. These are very useful to at least narrow down the location of a bug if not to find it entirely, -or just to orient yourself as to why the -compiler is doing a particular thing. +or just to orient yourself as to why the compiler is doing a particular thing. [`debug!`]: https://docs.rs/tracing/0.1/tracing/macro.debug.html @@ -120,8 +119,7 @@ you can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs All `debug!` output will then appear in standard error. Note that you can use a partial path and the filter will still work. -For example, if you want to see `info!` output from only -`rustdoc::passes::collect_intra_doc_links`, +For example, if you want to see `info!` output from only `rustdoc::passes::collect_intra_doc_links`, you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra=info`. @@ -137,8 +135,7 @@ rustc, rustdoc, and other tools set custom environment variables.) **Note that unless you use a very strict filter, the logger will emit a lot of output, -so use the most specific module(s) you can (comma-separated if -multiple)**. +so use the most specific module(s) you can (comma-separated if multiple)**. It's typically a good idea to pipe standard error to a file and look at the log output with a text editor. @@ -187,8 +184,7 @@ If they are outputting to a terminal, they will use colors, and if they are outputting to a file or being piped somewhere else, they will not. However, it's hard to read log output in your terminal unless you have a very strict filter, -so you may want to pipe the -output to a pager like `less`. +so you may want to pipe the output to a pager like `less`. But then there won't be any colors, which makes it hard to pick out what you're looking for! You can override whether to have colors in log output with the `RUSTC_LOG_COLOR` @@ -211,8 +207,8 @@ Use `RUSTC_LOG_COLOR` to color logs from rustc. While calls to `error!`, `warn!` and `info!` are included in every build of the compiler, calls to `debug!` and `trace!` are only included in the program if you have `rust.debug-logging = true` in bootstrap.toml (it is turned off by default), -so if you don't see `DEBUG` logs, especially -if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see `INFO` logs, +so if you don't see `DEBUG` logs, +especially if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see `INFO` logs, make sure that `rust.debug-logging` is turned on in your bootstrap.toml. ## Logging etiquette and conventions From 543c24d4c85f95bf8bceebeb4993feb755300f6d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:46:39 +0200 Subject: [PATCH 58/71] sembr src/debuginfo/llvm-codegen.md --- src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md index 4f5bdaa1e6795..e72b94ea5b38e 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md @@ -1,13 +1,13 @@ # LLVM codegen -When Rust calls an LLVM `DIBuilder` function, LLVM translates the given information to a -["debug record"][dbg_record] that is format-agnostic. +When Rust calls an LLVM `DIBuilder` function, +LLVM translates the given information to a ["debug record"][dbg_record] that is format-agnostic. These records can be inspected in the LLVM-IR. [dbg_record]: https://llvm.org/docs/SourceLevelDebugging.html#debug-records -It is important to note that tags within the debug records are **always stored as DWARF tags**. If -the target calls for PDB debug info, during codegen the debug records will then be passed through +It is important to note that tags within the debug records are **always stored as DWARF tags**. +If the target calls for PDB debug info, during codegen the debug records will then be passed through [a module that translates the DWARF tags to their CodeView counterparts][cv]. [cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp From 1b5002dd2c6a81f4d025e1e0c752708034417d5d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:47:40 +0200 Subject: [PATCH 59/71] improve debuginfo/llvm-codegen.md --- src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md index e72b94ea5b38e..1cdc7c0929142 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md @@ -7,7 +7,7 @@ These records can be inspected in the LLVM-IR. [dbg_record]: https://llvm.org/docs/SourceLevelDebugging.html#debug-records It is important to note that tags within the debug records are **always stored as DWARF tags**. -If the target calls for PDB debug info, during codegen the debug records will then be passed through +If the target calls for PDB debug info, during codegen, the debug records will then be passed through [a module that translates the DWARF tags to their CodeView counterparts][cv]. [cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp From 0529c625e19a43838d65cf93167b93ad7335b34c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:48:04 +0200 Subject: [PATCH 60/71] sembr src/profiling/with-perf.md --- .../src/profiling/with-perf.md | 64 +++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with-perf.md b/src/doc/rustc-dev-guide/src/profiling/with-perf.md index b55afed47fbdc..9c3cf1d88747c 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with-perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with-perf.md @@ -60,8 +60,8 @@ cargo install --locked addr2line --features="bin" ### Gathering a perf profile from a `perf.rust-lang.org` test Often we want to analyze a specific test from `perf.rust-lang.org`. -The easiest way to do that is to use the [rustc-perf] -benchmarking suite, this approach is described [here](with-rustc-perf.md). +The easiest way to do that is to use the [rustc-perf] benchmarking suite, +this approach is described [here](with-rustc-perf.md). Instead of using the benchmark suite CLI, you can also profile the benchmarks manually. First, you need to clone the [rustc-perf] repository: @@ -96,8 +96,8 @@ CARGO_INCREMENTAL=0 cargo + check Next: we want record the execution time for *just* the clap-rs crate, running cargo check. -I tend to use `cargo rustc` for this, since it -also allows me to add explicit flags, which we'll do later on. +I tend to use `cargo rustc` for this, since it also allows me to add explicit flags, +which we'll do later on. ```bash touch src/lib.rs @@ -106,8 +106,8 @@ CARGO_INCREMENTAL=0 perf record -F99 --call-graph dwarf cargo rustc --profile ch Note that final command: it's a doozy! It uses the `cargo rustc` command, which executes rustc with (potentially) additional options; -the `--profile check` and `--lib` options specify that we are doing a -`cargo check` execution, and that this is a library (not a binary). +the `--profile check` and `--lib` options specify that we are doing a `cargo check` execution, +and that this is a library (not a binary). At this point, we can use `perf` tooling to analyze the results. For example: @@ -121,14 +121,14 @@ In simple cases, that can be helpful. For more detailed examination, the [`perf-focus` tool][pf] can be helpful; it is covered below. **A note of caution.** Each of the rustc-perf tests is its own special snowflake. - In particular, some of them are not libraries, in which - case you would want to do `touch src/main.rs` and avoid passing `--lib`. + In particular, some of them are not libraries, + in which case you would want to do `touch src/main.rs` and avoid passing `--lib`. I'm not sure how best to tell which test is which to be honest. ### Gathering NLL data -If you want to profile an NLL run, you can just pass extra options to -the `cargo rustc` command, like so: +If you want to profile an NLL run, you can just pass extra options to the `cargo rustc` command, +like so: ```bash touch src/lib.rs @@ -152,8 +152,8 @@ To understand how it works, you have to know just a bit about perf. Basically, perf works by *sampling* your process on a regular basis (or whenever some event occurs). For each sample, perf gathers a backtrace. `perf focus` lets you write a regular expression that tests -which functions appear in that backtrace, and then tells you which -percentage of samples had a backtrace that met the regular expression. +which functions appear in that backtrace, +and then tells you which percentage of samples had a backtrace that met the regular expression. It's probably easiest to explain by walking through how I would analyze NLL performance. ### Installing `perf-focus` @@ -168,8 +168,7 @@ cargo install --locked perf-focus Let's say we've gathered the NLL data for a test. We'd like to know how much time it is spending in the MIR borrow-checker. -The "main" function of the MIR borrowck is called `do_mir_borrowck`, so we can do -this command: +The "main" function of the MIR borrowck is called `do_mir_borrowck`, so we can do this command: ```bash $ perf focus '{do_mir_borrowck}' @@ -179,22 +178,22 @@ Not Matches: 542 Percentage : 29% ``` -The `'{do_mir_borrowck}'` argument is called the **matcher**. It -specifies the test to be applied on the backtrace. +The `'{do_mir_borrowck}'` argument is called the **matcher**. +It specifies the test to be applied on the backtrace. In this case, the `{X}` indicates that there must be *some* function on the backtrace that meets the regular expression `X`. -In this case, that regex is just the name of the function we want -(in fact, it's a subset of the name; +In this case, that regex is just the name of the function we want (in fact, +it's a subset of the name; the full name includes a bunch of other stuff, like the module path). In this mode, perf-focus just prints out the percentage of samples where `do_mir_borrowck` was on the stack: in this case, 29%. -**A note about c++filt.** To get the data from `perf`, `perf focus` - currently executes `perf script` (perhaps there is a better way...). +**A note about c++filt.** To get the data from `perf`, + `perf focus` currently executes `perf script` (perhaps there is a better way...). I've sometimes found that `perf script` outputs C++ mangled names. This is annoying. You can tell by running `perf script | - head` yourself — if you see names like `5rustc6middle` instead of - `rustc::middle`, then you have the same problem. + head` yourself — if you see names like `5rustc6middle` instead of `rustc::middle`, + then you have the same problem. You can solve this by doing: ```bash @@ -203,10 +202,10 @@ perf script | c++filt | perf focus --from-stdin ... This will pipe the output from `perf script` through `c++filt` and should mostly convert those names into a more friendly format. -The `--from-stdin` flag to `perf focus` tells it to get its data from -stdin, rather than executing `perf focus`. -We should make this more convenient (at worst, maybe add a `c++filt` option to `perf focus`, or -just always use it — it's pretty harmless). +The `--from-stdin` flag to `perf focus` tells it to get its data from stdin, +rather than executing `perf focus`. +We should make this more convenient (at worst, maybe add a `c++filt` option to `perf focus`, +or just always use it — it's pretty harmless). ### Example: How much time does MIR borrowck spend solving traits? @@ -275,17 +274,16 @@ Usually "total" is the more interesting number, but not always. ### Relative percentages -By default, all in perf-focus are relative to the **total program -execution**. This is useful to help you keep perspective — often as -we drill down to find hot spots, we can lose sight of the fact that, +By default, all in perf-focus are relative to the **total program execution**. +This is useful to help you keep perspective — often as we drill down to find hot spots, +we can lose sight of the fact that, in terms of overall program execution, this "hot spot" is actually not important. It also ensures that percentages between different queries are easily compared against one another. -That said, sometimes it's useful to get relative percentages, so `perf -focus` offers a `--relative` option. +That said, sometimes it's useful to get relative percentages, +so `perf focus` offers a `--relative` option. In this case, the percentages are listed only for samples that match (vs all samples). -So for example we could get our percentages relative to the borrowck itself -like so: +So for example we could get our percentages relative to the borrowck itself like so: ```bash $ perf focus '{do_mir_borrowck}' --tree-callees --relative --tree-max-depth 1 --tree-min-percent 5 From b5297f7d92876e8cc848897b11028a9ba764977e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:51:12 +0200 Subject: [PATCH 61/71] missing pauses --- src/doc/rustc-dev-guide/src/profiling/with-perf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with-perf.md b/src/doc/rustc-dev-guide/src/profiling/with-perf.md index 9c3cf1d88747c..1a3b986d8213b 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with-perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with-perf.md @@ -283,7 +283,7 @@ It also ensures that percentages between different queries are easily compared a That said, sometimes it's useful to get relative percentages, so `perf focus` offers a `--relative` option. In this case, the percentages are listed only for samples that match (vs all samples). -So for example we could get our percentages relative to the borrowck itself like so: +So, for example, we could get our percentages relative to the borrowck itself like so: ```bash $ perf focus '{do_mir_borrowck}' --tree-callees --relative --tree-max-depth 1 --tree-min-percent 5 From 05c81327b84cd72c04206ffe20d22ff0cdee9b33 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:51:30 +0200 Subject: [PATCH 62/71] sembr src/effects.md --- src/doc/rustc-dev-guide/src/effects.md | 55 +++++++++++++------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/effects.md b/src/doc/rustc-dev-guide/src/effects.md index 9c54705e000fd..55e00d4acfad3 100644 --- a/src/doc/rustc-dev-guide/src/effects.md +++ b/src/doc/rustc-dev-guide/src/effects.md @@ -3,20 +3,20 @@ ## The `HostEffect` predicate [`HostEffectPredicate`]s are a kind of predicate from `[const] Tr` or `const Tr` bounds. -It has a trait reference, and a `constness` which could be `Maybe` or -`Const` depending on the bound. +It has a trait reference, +and a `constness` which could be `Maybe` or `Const` depending on the bound. Because `[const] Tr`, or rather `Maybe` bounds -apply differently based on whichever contexts they are in, they have different -behavior than normal bounds. +apply differently based on whichever contexts they are in, +they have different behavior than normal bounds. Where normal trait bounds on a function such as `T: Tr` are collected within the [`clauses_of`] query to be proven when a -function is called and to be assumed within the function, bounds such as -`T: [const] Tr` will behave as a normal trait bound and add `T: Tr` to the result +function is called and to be assumed within the function, +bounds such as `T: [const] Tr` will behave as a normal trait bound and add `T: Tr` to the result from `clauses_of`, but also adds a `HostEffectPredicate` to the [`const_conditions`] query. On the other hand, `T: const Tr` bounds do not change meaning across contexts, -therefore they will result in `HostEffect(T: Tr, const)` being added to -`clauses_of`, and not `const_conditions`. +therefore they will result in `HostEffect(T: Tr, const)` being added to `clauses_of`, +and not `const_conditions`. [`HostEffectPredicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/predicate/struct.HostEffectPredicate.html [`clauses_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.clauses_of @@ -34,14 +34,15 @@ fn foo() where T: Default {} We must be able to prove that `T` implements `Default`. In a similar vein, `const_conditions` represents a set of predicates that need to be proven to use -an item *in const contexts*. If we adjust the example above to use `const` trait bounds: +an item *in const contexts*. +If we adjust the example above to use `const` trait bounds: ```rust const fn foo() where T: [const] Default {} ``` -Then `foo` would get a `HostEffect(T: Default, maybe)` in the `const_conditions` -query, suggesting that in order to call `foo` from const contexts, one must +Then `foo` would get a `HostEffect(T: Default, maybe)` in the `const_conditions` query, +suggesting that in order to call `foo` from const contexts, one must prove that `T` has a const implementation of `Default`. ## Enforcement of `const_conditions` @@ -51,8 +52,8 @@ prove that `T` has a const implementation of `Default`. Every call in HIR from a const context (which includes `const fn` and `const` items) will check that `const_conditions` of the function we are calling hold. This is done in [`FnCtxt::enforce_context_effects`]. -Note that we don't check -if the function is only referred to but not called, as the following code needs to compile: +Note that we don't check if the function is only referred to but not called, +as the following code needs to compile: ```rust const fn hi() -> T { @@ -61,8 +62,8 @@ const fn hi() -> T { const X: fn() -> u32 = hi::; ``` -For a trait `impl` to be well-formed, we must be able to prove the -`const_conditions` of the trait from the `impl`'s environment. +For a trait `impl` to be well-formed, +we must be able to prove the `const_conditions` of the trait from the `impl`'s environment. This is checked in [`wfcheck::check_impl`]. Here's an example: @@ -79,8 +80,8 @@ impl const Foo for () {} Methods of trait impls must not have stricter bounds than the method of the trait that they are implementing. -To check that the methods are compatible, a -hybrid environment is constructed with the predicates of the `impl` plus the +To check that the methods are compatible, +a hybrid environment is constructed with the predicates of the `impl` plus the predicates of the trait method, and we attempt to prove the predicates of the impl method. We do the same for `const_conditions`: @@ -113,8 +114,8 @@ are revalidated again in [`Checker::revalidate_conditional_constness`]. ## `explicit_implied_const_bounds` on associated types and traits -Bounds on associated types, opaque types, and supertraits such as the following -have their bounds represented differently: +Bounds on associated types, opaque types, +and supertraits such as the following have their bounds represented differently: ```rust trait Foo: [const] PartialEq { @@ -132,8 +133,8 @@ bounds on functions), these bounds need to be proved at definition (at the impl, or when returning the opaque) but can be assumed for callers. The non-const equivalent of these bounds are called [`explicit_item_bounds`]. -These bounds are checked in [`compare_impl_item::check_type_bounds`] for HIR -typeck, [`evaluate_host_effect_from_item_bounds`] in the old solver and +These bounds are checked in [`compare_impl_item::check_type_bounds`] for HIR typeck, +[`evaluate_host_effect_from_item_bounds`] in the old solver and [`consider_additional_alias_assumptions`] in the new solver. [`explicit_item_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.explicit_item_bounds @@ -147,11 +148,11 @@ typeck, [`evaluate_host_effect_from_item_bounds`] in the old solver and In general, we can prove a `HostEffect` predicate when either of these conditions are met: * The predicate can be assumed from caller bounds; -* The type has a `const` `impl` for the trait, *and* that const conditions on - the impl holds, *and* that the `explicit_implied_const_bounds` on the trait holds; or +* The type has a `const` `impl` for the trait, *and* that const conditions on the impl holds, + *and* that the `explicit_implied_const_bounds` on the trait holds; or * The type has a built-in implementation for the trait in const contexts. - For example, `Fn` may be implemented by function items if their const conditions - are satisfied, or `Destruct` is implemented in const contexts if the type can + For example, `Fn` may be implemented by function items if their const conditions are satisfied, + or `Destruct` is implemented in const contexts if the type can be dropped at compile time. [old solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_trait_selection/traits/effects.rs.html @@ -164,8 +165,8 @@ To be expanded later. ### The `#[rustc_non_const_trait_method]` attribute This is intended for internal (standard library) usage only. -With this attribute applied to a trait method, the compiler will not check the default body of this -method for ability to run in compile time. +With this attribute applied to a trait method, +the compiler will not check the default body of this method for ability to run in compile time. Users of the trait will also not be allowed to use this trait method in const contexts. This attribute is primarily used for constifying large traits such as `Iterator` without having to make all From 666f6480639c7f8ac32ef18d8d8144d0101350b5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:54:41 +0200 Subject: [PATCH 63/71] missing pause --- src/doc/rustc-dev-guide/src/effects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/effects.md b/src/doc/rustc-dev-guide/src/effects.md index 55e00d4acfad3..f6a11b435ad32 100644 --- a/src/doc/rustc-dev-guide/src/effects.md +++ b/src/doc/rustc-dev-guide/src/effects.md @@ -4,7 +4,7 @@ [`HostEffectPredicate`]s are a kind of predicate from `[const] Tr` or `const Tr` bounds. It has a trait reference, -and a `constness` which could be `Maybe` or `Const` depending on the bound. +and a `constness` which could be `Maybe` or `Const`, depending on the bound. Because `[const] Tr`, or rather `Maybe` bounds apply differently based on whichever contexts they are in, they have different behavior than normal bounds. From b3bd159fb9c6e8ac2e85b2eea1c4f03c67f7c212 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:54:46 +0200 Subject: [PATCH 64/71] sembr src/query.md --- src/doc/rustc-dev-guide/src/query.md | 38 +++++++++++++++------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 471b445c14d5a..19145a5a7ad0f 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -9,16 +9,17 @@ Instead of entirely independent passes (parsing, type-checking, etc.), a set of function-like *queries* compute information about the input source. For example, -there is a query called `type_of` that, given the [`DefId`] of -some item, will compute the type of that item and return it to you. +there is a query called `type_of` that, given the [`DefId`] of some item, +will compute the type of that item and return it to you. [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.DefId.html [Overview of the compiler]: overview.md#queries -Query execution is *memoized*. The first time you invoke a -query, it will go do the computation, but the next time, the result is returned from a hashtable. -Moreover, query execution fits nicely into -*incremental computation*; the idea is roughly that, when you invoke a +Query execution is *memoized*. +The first time you invoke a query, +it will go do the computation, but the next time, the result is returned from a hashtable. +Moreover, query execution fits nicely into *incremental computation*; the idea is roughly that, +when you invoke a query, the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail] When we execute a query, @@ -39,8 +40,8 @@ For example: - That query in turn would invoke something asking for the HIR. - This keeps going further and further back until we wind up doing the actual parsing. -Although this vision is not fully realized, large sections of the -compiler (for example, generating [MIR]) currently work exactly like this. +Although this vision is not fully realized, large sections of the compiler (for example, +generating [MIR]) currently work exactly like this. [^incr-comp-detail]: The [Incremental compilation in detail] chapter gives a more in-depth description of what queries are and how they work. @@ -65,22 +66,22 @@ let ty = tcx.type_of(some_def_id); So you may be wondering what happens when you invoke a query method. The answer is that, for each query, the compiler maintains a -cache – if your query has already been executed, then, the answer is -simple: we clone the return value out of the cache and return it +cache – if your query has already been executed, then, +the answer is simple: we clone the return value out of the cache and return it (therefore, you should try to ensure that the return types of queries are cheaply cloneable; insert an `Rc` if necessary). ### Providers -If, however, the query is *not* in the cache, then the compiler will -call the corresponding **provider** function. +If, however, the query is *not* in the cache, +then the compiler will call the corresponding **provider** function. A provider is a function implemented in a specific module and **manually registered** into either the [`Providers`][providers_struct] struct (for local crate queries) or the [`ExternProviders`][extern_providers_struct] struct (for external crate queries) during compiler initialization. The macro system generates both structs, -which act as function tables for all query implementations, where each -field is a function pointer to the actual provider. +which act as function tables for all query implementations, +where each field is a function pointer to the actual provider. **Note:** Both the `Providers` and `ExternProviders` structs are generated by macros and act as function tables for all query implementations. They are **not** Rust traits, but plain structs with function pointer fields. @@ -112,10 +113,11 @@ Providers take two arguments: the `tcx` and the query key. They return the result of the query. N.B. Most of the `rustc_*` crates only provide **local -providers**. Almost all **extern providers** wind up going through the -[`rustc_metadata` crate][rustc_metadata], which loads the information from the crate metadata. -But in some cases there are crates that -provide queries for *both* local and external crates, in which case +providers**. +Almost all **extern providers** wind up going through the [`rustc_metadata` crate][rustc_metadata], +which loads the information from the crate metadata. +But in some cases there are crates that provide queries for *both* local and external crates, +in which case they define both a `provide` and a `provide_extern` function, through [`wasm_import_module_map`][wasm_import_module_map], that `rustc_driver` can invoke. From 954e7c047db10a8b0501b439a6dae5fe061fb736 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:56:54 +0200 Subject: [PATCH 65/71] reflow src/query.md --- src/doc/rustc-dev-guide/src/query.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 19145a5a7ad0f..a4b9eef02f13a 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -19,8 +19,8 @@ Query execution is *memoized*. The first time you invoke a query, it will go do the computation, but the next time, the result is returned from a hashtable. Moreover, query execution fits nicely into *incremental computation*; the idea is roughly that, -when you invoke a -query, the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail] +when you invoke a query, +the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail] When we execute a query, we also discover (at runtime!) what other queries it depends on. @@ -67,8 +67,8 @@ let ty = tcx.type_of(some_def_id); So you may be wondering what happens when you invoke a query method. The answer is that, for each query, the compiler maintains a cache – if your query has already been executed, then, -the answer is simple: we clone the return value out of the cache and return it -(therefore, you should try to ensure that the return types of queries +the answer is simple: we clone the return value out of the cache and return it (therefore, +you should try to ensure that the return types of queries are cheaply cloneable; insert an `Rc` if necessary). ### Providers @@ -117,8 +117,7 @@ providers**. Almost all **extern providers** wind up going through the [`rustc_metadata` crate][rustc_metadata], which loads the information from the crate metadata. But in some cases there are crates that provide queries for *both* local and external crates, -in which case -they define both a `provide` and a `provide_extern` function, through +in which case they define both a `provide` and a `provide_extern` function, through [`wasm_import_module_map`][wasm_import_module_map], that `rustc_driver` can invoke. [rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html From 6bc3868e7263a3602cd17364711dcf906da57ec4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:57:15 +0200 Subject: [PATCH 66/71] sembr src/ty.md --- src/doc/rustc-dev-guide/src/ty.md | 88 +++++++++++++++---------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty.md b/src/doc/rustc-dev-guide/src/ty.md index ef2ea37b7ca46..b9776523dd07f 100644 --- a/src/doc/rustc-dev-guide/src/ty.md +++ b/src/doc/rustc-dev-guide/src/ty.md @@ -1,8 +1,8 @@ # The `ty` module: representing types The `ty` module defines how the Rust compiler represents types internally. -It also defines the -*typing context* (`tcx` or `TyCtxt`), which is the central data structure in the compiler. +It also defines the *typing context* (`tcx` or `TyCtxt`), +which is the central data structure in the compiler. ## `ty::Ty` @@ -22,12 +22,13 @@ The distinction is important, so we will discuss it first before going into the The HIR in rustc can be thought of as the high-level intermediate representation. It is more or less the AST (see [this chapter](hir.md)) as it represents the -syntax that the user wrote, and is obtained after parsing and some *desugaring*. It has a -representation of types, but in reality it reflects more of what the user wrote, that is, what they +syntax that the user wrote, and is obtained after parsing and some *desugaring*. +It has a representation of types, +but in reality it reflects more of what the user wrote, that is, what they wrote so as to represent that type. -In contrast, `ty::Ty` represents the semantics of a type, that is, the *meaning* of what the user -wrote. +In contrast, `ty::Ty` represents the semantics of a type, that is, +the *meaning* of what the user wrote. For example, `rustc_hir::Ty` would record the fact that a user used the name `u32` twice in their program, but the `ty::Ty` would record the fact that both usages refer to the same type. @@ -46,16 +47,16 @@ That is, they have two different [`Span`s][span] (locations). **Example: `fn foo(x: &u32) -> &u32`** In addition, HIR might have information left out. -This type -`&u32` is incomplete, since in the full Rust type there is actually a lifetime, but we didn’t need +This type `&u32` is incomplete, +since in the full Rust type there is actually a lifetime, but we didn’t need to write those lifetimes. There are also some elision rules that insert information. The result may look like `fn foo<'a>(x: &'a u32) -> &'a u32`. In the HIR level, these things are not spelled out and you can say the picture is rather incomplete. However, at the `ty::Ty` level, these details are added and it is complete. -Moreover, we will have -exactly one `ty::Ty` for a given type, like `u32`, and that `ty::Ty` is used for all `u32`s in the +Moreover, we will have exactly one `ty::Ty` for a given type, +like `u32`, and that `ty::Ty` is used for all `u32`s in the whole program, not a specific usage, unlike `rustc_hir::Ty`. Here is a summary: @@ -74,8 +75,8 @@ Here is a summary: HIR is built directly from the AST, so it happens before any `ty::Ty` is produced. After HIR is built, some basic type inference and type checking is done. -During the type inference, we -figure out what the `ty::Ty` of everything is and we also check if the type of something is +During the type inference, +we figure out what the `ty::Ty` of everything is and we also check if the type of something is ambiguous. The `ty::Ty` is then used for type checking while making sure everything has the expected type. The [`hir_ty_lowering` module][hir_ty_lowering] is where the code responsible for @@ -102,8 +103,8 @@ Consider another example: `fn foo(x: T) -> u32`. Suppose that someone invokes `foo::(0)`. This means that `T` and `u32` (in this invocation) actually turns out to be the same type, so we would eventually end up with the same `ty::Ty` in the end, but we have distinct `rustc_hir::Ty`. -(This is a bit over-simplified, though, since during type checking, we would check the function -generically and would still have a `T` distinct from `u32`. +(This is a bit over-simplified, though, since during type checking, +we would check the function generically and would still have a `T` distinct from `u32`. Later, when doing code generation, we would always be handling "monomorphized" (fully substituted) versions of each function, and hence we would know what `T` represents (and specifically that it is `u32`).) @@ -125,8 +126,8 @@ Here the type `X` will vary depending on context, clearly. If you look at the `rustc_hir::Ty`, you will get back that `X` is an alias in both cases (though it will be mapped via name resolution to distinct aliases). -But if you look at the `ty::Ty` signature, it will be either `fn(u32) -> u32` -or `fn(i32) -> i32` (with type aliases fully expanded). +But if you look at the `ty::Ty` signature, +it will be either `fn(u32) -> u32` or `fn(i32) -> i32` (with type aliases fully expanded). ## `ty::Ty` implementation @@ -140,8 +141,7 @@ We always hide them within `Ty` and skip over it via `Deref` impls or methods. They are convenient hacks for efficiency and summarize information about the type that we may want to know, but they don’t come into the picture as much here. -Finally, [`Interned`](./memory.md) allows the `ty::Ty` to be a thin pointer-like -type. +Finally, [`Interned`](./memory.md) allows the `ty::Ty` to be a thin pointer-like type. This allows us to do cheap comparisons for equality, along with the other benefits of interning. [tykind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html @@ -170,8 +170,8 @@ You can also find various common types in the `tcx` itself by accessing its fiel ## Comparing types Because types are interned, it is possible to compare them for equality efficiently using `==` -– however, this is almost never what you want to do unless you happen to be hashing and looking -for duplicates. +– however, +this is almost never what you want to do unless you happen to be hashing and looking for duplicates. This is because often in Rust there are multiple ways to represent the same type, particularly once inference is involved. @@ -182,11 +182,11 @@ diagnostics code). `==` on them will return `false` though, since they are different types. The simplest way to compare two types correctly requires an inference context (`infcx`). -If you have one, you can use `infcx.can_eq(param_env, ty1, ty2)` -to check whether the types can be made equal. +If you have one, you can use `infcx.can_eq(param_env, ty1, +ty2)` to check whether the types can be made equal. This is typically what you want to check during diagnostics, which is concerned with questions such -as whether two types can be assigned to each other, not whether they're represented identically in -the compiler's type-checking layer. +as whether two types can be assigned to each other, +not whether they're represented identically in the compiler's type-checking layer. When working with an inference context, you have to be careful to ensure that potential inference variables inside the types actually belong to that inference context. @@ -199,24 +199,24 @@ To compare them correctly, you have to normalize the types first. This is primarily a concern during HIR type checking and with all types from a `TyCtxt` query (for example from `tcx.type_of()`). -When a `FnCtxt` or an `ObligationCtxt` is available during type checking, `.normalize(ty)` -should be used on them to normalize the type. +When a `FnCtxt` or an `ObligationCtxt` is available during type checking, +`.normalize(ty)` should be used on them to normalize the type. After type checking, diagnostics code can use `tcx.normalize_erasing_regions(ty)`. There are also cases where using `==` on `Ty` is fine. -This is, for example, the case in late lints -or after monomorphization, since type checking has been completed, meaning all inference variables +This is, for example, the case in late lints or after monomorphization, +since type checking has been completed, meaning all inference variables are resolved and all regions have been erased. -In these cases, if you know that inference variables -or normalization won't be a concern, `#[allow]` or `#[expect]`ing the lint is recommended. +In these cases, if you know that inference variables or normalization won't be a concern, +`#[allow]` or `#[expect]`ing the lint is recommended. When diagnostics code does not have access to an inference context, it should be threaded through the function calls if one is available in some place (like during type checking). -If no inference context is available at all, then one can be created as described in -[type-inference]. -But this is only useful when the involved types (for example, if -they came from a query like `tcx.type_of()`) are actually substituted with fresh +If no inference context is available at all, +then one can be created as described in [type-inference]. +But this is only useful when the involved types (for example, +if they came from a query like `tcx.type_of()`) are actually substituted with fresh inference variables using [`fresh_args_for_item`]. This can be used to answer questions like "can `Vec` for any `T` be unified with `Vec`?". @@ -237,8 +237,8 @@ fn foo(x: Ty<'tcx>) { } ``` -The `kind` field is of type `TyKind<'tcx>`, which is an enum defining all of the different kinds of -types in the compiler. +The `kind` field is of type `TyKind<'tcx>`, +which is an enum defining all of the different kinds of types in the compiler. > N.B. inspecting the `kind` field on types during type inference can be risky, as there may be > inference variables and other things to consider, or sometimes types are not yet known and will @@ -247,8 +247,8 @@ types in the compiler. There are a lot of related types, and we’ll cover them in time (e.g regions/lifetimes, “substitutions”, etc). -There are many variants on the `TyKind` enum, which you can see by looking at its -[documentation][tykind]. +There are many variants on the `TyKind` enum, +which you can see by looking at its [documentation][tykind]. Here is a sampling: - [**Algebraic Data Types (ADTs)**][kindadt] An [*algebraic data type*][wikiadt] is a `struct`, @@ -264,8 +264,8 @@ Here is a sampling: - [**Array**][kindarray] Corresponds to `[T; n]`. - [**RawPtr**][kindrawptr] Corresponds to `*mut T` or `*const T`. - [**Ref**][kindref] `Ref` stands for safe references, `&'a mut T` or `&'a T`. - `Ref` has some - associated parts, like `Ty<'tcx>` which is the type that the reference references. + `Ref` has some associated parts, + like `Ty<'tcx>` which is the type that the reference references. `Region<'tcx>` is the lifetime or region of the reference and `Mutability` if the reference is mutable or not. - [**Param**][kindparam] Represents a type parameter (e.g. the `T` in `Vec`). @@ -314,15 +314,15 @@ which case the error should've been reported when that error type was produced). It's important to maintain this invariant because the whole point of the `Error` type is to suppress other errors -- i.e., we don't report them. If we were to produce an `Error` type without actually -emitting an error to the user, then this could cause later errors to be suppressed, and the -compilation might inadvertently succeed! +emitting an error to the user, then this could cause later errors to be suppressed, +and the compilation might inadvertently succeed! Sometimes there is a third case. You believe that an error has been reported, but you believe it would've been reported earlier in the compilation, not locally. In that case, you can create a "delayed bug" with [`delayed_bug`] or [`span_delayed_bug`]. -This will make a note that you expect -compilation to yield an error -- if, however, compilation should succeed, then it will trigger a +This will make a note that you expect compilation to yield an error -- if, +however, compilation should succeed, then it will trigger a compiler bug report. [`delayed_bug`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html#method.delayed_bug From d1f4fd32329ac376362da6cb63f3bdb7450361b1 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 20:05:04 +0200 Subject: [PATCH 67/71] improve ty.md --- src/doc/rustc-dev-guide/src/ty.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty.md b/src/doc/rustc-dev-guide/src/ty.md index b9776523dd07f..887dd822e6b33 100644 --- a/src/doc/rustc-dev-guide/src/ty.md +++ b/src/doc/rustc-dev-guide/src/ty.md @@ -24,11 +24,11 @@ The HIR in rustc can be thought of as the high-level intermediate representation It is more or less the AST (see [this chapter](hir.md)) as it represents the syntax that the user wrote, and is obtained after parsing and some *desugaring*. It has a representation of types, -but in reality it reflects more of what the user wrote, that is, what they -wrote so as to represent that type. +but in reality, it reflects more of what the user wrote, +so as to represent that type. -In contrast, `ty::Ty` represents the semantics of a type, that is, -the *meaning* of what the user wrote. +In contrast, `ty::Ty` represents the semantics of a type; +that is, the *meaning* of what the user wrote. For example, `rustc_hir::Ty` would record the fact that a user used the name `u32` twice in their program, but the `ty::Ty` would record the fact that both usages refer to the same type. @@ -169,9 +169,9 @@ You can also find various common types in the `tcx` itself by accessing its fiel ## Comparing types -Because types are interned, it is possible to compare them for equality efficiently using `==` -– however, -this is almost never what you want to do unless you happen to be hashing and looking for duplicates. +Because types are interned, it is possible to compare them for equality efficiently using `==`. +However, this is almost never what you want to do, +unless you happen to be hashing and looking for duplicates. This is because often in Rust there are multiple ways to represent the same type, particularly once inference is involved. @@ -182,8 +182,8 @@ diagnostics code). `==` on them will return `false` though, since they are different types. The simplest way to compare two types correctly requires an inference context (`infcx`). -If you have one, you can use `infcx.can_eq(param_env, ty1, -ty2)` to check whether the types can be made equal. +If you have one, +you can use `infcx.can_eq(param_env, ty1, ty2)` to check whether the types can be made equal. This is typically what you want to check during diagnostics, which is concerned with questions such as whether two types can be assigned to each other, not whether they're represented identically in the compiler's type-checking layer. @@ -265,7 +265,7 @@ Here is a sampling: - [**RawPtr**][kindrawptr] Corresponds to `*mut T` or `*const T`. - [**Ref**][kindref] `Ref` stands for safe references, `&'a mut T` or `&'a T`. `Ref` has some associated parts, - like `Ty<'tcx>` which is the type that the reference references. + like `Ty<'tcx>`, which is the type that the reference references. `Region<'tcx>` is the lifetime or region of the reference and `Mutability` if the reference is mutable or not. - [**Param**][kindparam] Represents a type parameter (e.g. the `T` in `Vec`). From 96df2f56cedb8db17a70d01446d37c57559a349c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 20:11:07 +0200 Subject: [PATCH 68/71] extraneous --- src/doc/rustc-dev-guide/src/const-generics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index a5c7ec506be4c..2738782db9e48 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -83,7 +83,7 @@ When we go through HIR ty lowering for the array type in `Alias`, we will lower This will effectively set the type of the `ANON` const item during some later part of the compiler rather than when constructing the HIR. After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Alias` with the `DefId` of the `AnonConst`. -This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_generic_const_args` is enabled). +This is equivalent to how we would represent a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_generic_const_args` is enabled). This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. From 81b9a584dadce87f489ea638f77b20bb7da67307 Mon Sep 17 00:00:00 2001 From: Crystal Durham Date: Wed, 30 Sep 2026 14:43:13 -0500 Subject: [PATCH 69/71] remove dead cfg_select! arm --- library/std/src/sys/fs/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 93b05b9859d28..ca5c28dcd88bd 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -47,9 +47,6 @@ cfg_select! { mod vexos; use vexos as imp; } - target_vendor = "apple" => { - mod darwin; - } _ => { mod unsupported; use unsupported as imp; From 262fa3180187370feae0ce7b5b066fb64f65c443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 20 Sep 2026 21:55:52 +0000 Subject: [PATCH 70/71] Provide more context on "not general enough" error Point at the source bound that was unmet when a HRTB is unmet. ``` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | LL | fn tuple_one() | --------- due to a where-clause on `tuple_one`... LL | where LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, | ----------------------------------------------------------- unsatisfied where-clause on `tuple_one` ... LL | tuple_one::(); | ^^^^^^^^^^^^^^^^^^^^ | = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` ``` This increases the size of `ConstraintCategory`, which might be a perf regression. --- .../src/diagnostics/explain_borrow.rs | 2 +- .../src/diagnostics/region_errors.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- .../rustc_borrowck/src/region_infer/mod.rs | 4 +- .../src/region_infer/region_context.rs | 2 +- .../src/type_check/canonical.rs | 6 +- compiler/rustc_infer/src/infer/mod.rs | 12 +-- compiler/rustc_middle/src/mir/query.rs | 3 +- compiler/rustc_middle/src/traits/mod.rs | 6 +- .../rustc_trait_selection/src/diagnostics.rs | 2 +- .../nice_region_error/placeholder_error.rs | 43 +++++++++- .../src/error_reporting/infer/region.rs | 4 +- .../src/error_reporting/traits/suggestions.rs | 15 +++- .../traits/query/type_op/ascribe_user_type.rs | 2 +- .../associated-types-eq-hr.stderr | 81 +++++++++++++++---- ...outine-auto-trait-span-issue-155880.stderr | 9 ++- ...olved-typeck-results.no_assumptions.stderr | 18 ++++- ...ranked-auto-trait-12.no_assumptions.stderr | 9 ++- ...er-ranked-auto-trait-13.assumptions.stderr | 37 ++++++--- ...ranked-auto-trait-13.no_assumptions.stderr | 56 +++++++++---- ...ranked-auto-trait-15.no_assumptions.stderr | 18 ++++- ...er-ranked-auto-trait-16.assumptions.stderr | 18 ++++- ...ranked-auto-trait-16.no_assumptions.stderr | 18 ++++- ...-ranked-auto-trait-5.no_assumptions.stderr | 10 ++- .../issue-110963-early.no_assumptions.stderr | 20 ++++- ...ation-not-general-enough-ice-133252.stderr | 9 ++- ...n-with-leaking-placeholders.current.stderr | 10 ++- ...rtb-closure-suggest-type-annotation.stderr | 21 +++-- tests/ui/coroutine/auto-trait-regions.stderr | 18 ++++- .../ui/coroutine/resume-arg-late-bound.stderr | 9 ++- ...ot-checked-with-right-substitutions.stderr | 15 +++- ...hr-fn-ptr-trait-impl-mismatch-29061.stderr | 27 +++++-- ...tb-associated-type-leak-check-55731.stderr | 10 ++- ...n-ptr-impl-not-general-enough-57936.stderr | 9 ++- .../trait-bounds/hrtb-conflate-regions.stderr | 18 ++++- ...b-exists-forall-trait-contravariant.stderr | 10 ++- .../hrtb-exists-forall-trait-covariant.stderr | 10 ++- .../hrtb-exists-forall-trait-invariant.stderr | 10 ++- .../trait-bounds/hrtb-just-for-static.stderr | 9 ++- .../hrtb-perfect-forwarding.stderr | 10 ++- .../trait-bounds/issue-46989.stderr | 9 ++- .../trait-bounds/issue-59311.stderr | 34 ++++---- .../normalize-under-binder/issue-71955.stderr | 42 +++++++--- tests/ui/lifetimes/issue-105675.stderr | 54 ++++++++++--- tests/ui/lifetimes/issue-79187-2.stderr | 18 ++++- tests/ui/lifetimes/issue-79187.stderr | 18 ++++- .../lifetime-errors/issue_74400.stderr | 16 +++- .../closure-arg-type-mismatch.stderr | 18 ++++- .../closure-mismatch.current.stderr | 36 +++++++-- tests/ui/nll/ice-106874.stderr | 66 ++++++++++----- tests/ui/nll/issue-54302-cases.stderr | 28 +++++-- ...missing-universe-cause-issue-114907.stderr | 37 ++++++--- ...insensitive-scopes-issue-117146.nll.stderr | 18 ++++- ...sitive-scopes-issue-117146.polonius.stderr | 18 ++++- .../impl-fn-ignore-binder-via-bottom.stderr | 16 ++-- ...n-termination-lifetime-issue-148421.stderr | 5 ++ tests/ui/unboxed-closures/issue-30906.stderr | 9 ++- .../ui/where-clauses/where-for-self-2.stderr | 10 ++- 58 files changed, 793 insertions(+), 253 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 7537e2f9f1495..2bc361968a761 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -415,7 +415,7 @@ impl<'tcx> BorrowExplanation<'tcx> { let mut preds = path .iter() .filter_map(|constraint| match constraint.category { - ConstraintCategory::Predicate(pred) if !pred.is_dummy() => Some(pred), + ConstraintCategory::Predicate(pred, _) if !pred.is_dummy() => Some(pred), _ => None, }) .collect::>(); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 0b9615634fe1e..c101191102979 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -58,7 +58,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { ConstraintCategory::ClosureUpvar(_) => "closure capture ", ConstraintCategory::Usage => "this usage ", ConstraintCategory::SolverRegionConstraint(_) - | ConstraintCategory::Predicate(_) + | ConstraintCategory::Predicate(_, _) | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index c35c7ab311572..39361a886bd77 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -232,7 +232,7 @@ pub struct ClosureOutlivesRequirement<'tcx> { // Make sure this enum doesn't unintentionally grow #[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); +rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 24); /// The subject of a `ClosureOutlivesRequirement` -- that is, the thing /// that must outlive some region. diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b547d24c7198c..60b258eca80df 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -275,11 +275,11 @@ impl<'tcx> BestBlame<'tcx> { .path .iter() .find_map(|constraint| { - if let ConstraintCategory::Predicate(predicate_span) = constraint.category { + if let ConstraintCategory::Predicate(predicate_span, def_id) = constraint.category { // We currently do not store the `DefId` in the `ConstraintCategory` // for performances reasons. The error reporting code used by NLL only // uses the span, so this doesn't cause any problems at the moment. - Some(ObligationCauseCode::WhereClause(CRATE_DEF_ID.to_def_id(), predicate_span)) + Some(ObligationCauseCode::WhereClause(def_id, predicate_span)) } else { None } diff --git a/compiler/rustc_borrowck/src/region_infer/region_context.rs b/compiler/rustc_borrowck/src/region_infer/region_context.rs index a6f7c19ff0c17..327acb7da3fb8 100644 --- a/compiler/rustc_borrowck/src/region_infer/region_context.rs +++ b/compiler/rustc_borrowck/src/region_infer/region_context.rs @@ -742,7 +742,7 @@ impl<'tcx> RegionInferenceContextInner<'tcx> { // Generic arguments are unlikely to be what relates regions together ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => 3, // We handle predicates and opaque types specially; don't prioritize them here. - ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 4, + ConstraintCategory::Predicate(_, _) | ConstraintCategory::OpaqueType => 4, // `Boring` constraints can correspond to user-written code and have useful spans, // but don't provide any other useful information for diagnostics. ConstraintCategory::Boring => 5, diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 9e4a39873753c..b295a66ee74ee 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -142,15 +142,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub(super) fn normalize_and_prove_instantiated_clauses( &mut self, - // Keep this parameter for now, in case we start using - // it in `ConstraintCategory` at some point. - _def_id: DefId, + def_id: DefId, instantiated_clauses: ty::InstantiatedClauses<'tcx>, locations: Locations, ) { for (clause, span) in instantiated_clauses { debug!(?span, ?clause); - let category = ConstraintCategory::Predicate(span); + let category = ConstraintCategory::Predicate(span, def_id); let clause = self.normalize_with_category(clause, locations, category); self.prove_clause(clause, locations, category); } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e02cc9a7acd1f..a7ce6a4353b59 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -463,7 +463,7 @@ pub enum SubregionOrigin<'tcx> { trait_item_def_id: DefId, }, - AscribeUserTypeProvePredicate(Span), + AscribeUserTypeProvePredicate(Span, DefId), // FIXME(-Zassumptions-on-binders): this is a temporary hack until we support // proper diagnostics for solver region constraints. @@ -478,7 +478,9 @@ impl<'tcx> SubregionOrigin<'tcx> { pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { match self { Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(), - Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span), + Self::AscribeUserTypeProvePredicate(span, def_id) => { + ConstraintCategory::Predicate(*span, *def_id) + } Self::SolverRegionConstraint(span) => ConstraintCategory::SolverRegionConstraint(*span), _ => ConstraintCategory::BoringNoLocation, } @@ -1840,7 +1842,7 @@ impl<'tcx> SubregionOrigin<'tcx> { SubregionOrigin::Reborrow(a) => a, SubregionOrigin::ReferenceOutlivesReferent(_, a) => a, SubregionOrigin::CompareImplItemObligation { span, .. } => span, - SubregionOrigin::AscribeUserTypeProvePredicate(span) => span, + SubregionOrigin::AscribeUserTypeProvePredicate(span, _) => span, SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), SubregionOrigin::SolverRegionConstraint(a) => a, } @@ -1874,8 +1876,8 @@ impl<'tcx> SubregionOrigin<'tcx> { parent: Box::new(default()), }, - traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span) => { - SubregionOrigin::AscribeUserTypeProvePredicate(span) + traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span, def_id) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span, def_id) } traits::ObligationCauseCode::ObjectTypeBound(ty, _reg) => { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 616b1719359f1..2e84fd80f35e5 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -7,6 +7,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_index::IndexVec; use rustc_index::bit_set::BitMatrix; use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_span::def_id::DefId; use rustc_span::{Span, Symbol}; use super::{ConstValue, SourceInfo}; @@ -129,7 +130,7 @@ pub enum ConstraintCategory<'tcx> { /// A constraint from a user-written predicate /// with the provided span, written on the item /// with the given `DefId` - Predicate(Span), + Predicate(Span, DefId), /// A "boring" constraint (caused by the given location) is one that /// the user probably doesn't want to see described in diagnostics, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index a50c5226c052d..493f6989f342c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -137,8 +137,8 @@ impl<'tcx> ObligationCause<'tcx> { pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { match self.code() { ObligationCauseCode::MatchImpl(cause, _) => cause.to_constraint_category(), - ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span) => { - ConstraintCategory::Predicate(*predicate_span) + ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span, def_id) => { + ConstraintCategory::Predicate(*predicate_span, *def_id) } _ => ConstraintCategory::BoringNoLocation, } @@ -402,7 +402,7 @@ pub enum ObligationCauseCode<'tcx> { output_ty: Option>, }, - AscribeUserTypeProvePredicate(Span), + AscribeUserTypeProvePredicate(Span, DefId), RustCall, diff --git a/compiler/rustc_trait_selection/src/diagnostics.rs b/compiler/rustc_trait_selection/src/diagnostics.rs index 90f6faaad1dc1..d673b99d00d05 100644 --- a/compiler/rustc_trait_selection/src/diagnostics.rs +++ b/compiler/rustc_trait_selection/src/diagnostics.rs @@ -1166,7 +1166,7 @@ impl<'tcx> ActualImplExplNotes<'tcx> { pub(crate) struct TraitPlaceholderMismatch<'tcx> { #[primary_span] pub span: Span, - #[label("doesn't satisfy where-clause")] + #[label("unsatisfied where-clause on `{$def_id}`")] pub satisfy_span: Option, #[label("due to a where-clause on `{$def_id}`...")] pub where_span: Option, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index be5c2b3c96915..390e21e34ef4c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -255,15 +255,43 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { ) -> Diag<'tcx> { let span = cause.span; + let mut code = cause.code(); + loop { + match code { + ObligationCauseCode::MatchImpl(inner_cause, _) => { + code = inner_cause.code(); + } + ObligationCauseCode::ImplDerived(derived) => { + code = &derived.derived.parent_code; + } + ObligationCauseCode::BuiltinDerived(derived) => { + code = &derived.parent_code; + } + ObligationCauseCode::WellFormedDerived(derived) => { + code = &derived.parent_code; + } + ObligationCauseCode::ImplDerivedHost(derived) => { + code = &derived.derived.parent_code; + } + ObligationCauseCode::BuiltinDerivedHost(derived) => { + code = &derived.parent_code; + } + _ => break, + } + } let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = if let ObligationCauseCode::WhereClause(def_id, span) - | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *cause.code() + | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *code && def_id != CRATE_DEF_ID.to_def_id() { ( true, Some(span), - Some(self.tcx().def_span(def_id)), + Some( + self.tcx() + .opt_item_ident(def_id) + .map_or_else(|| self.tcx().def_span(def_id), |n| n.span), + ), None, self.tcx().def_path_str(def_id), ) @@ -356,6 +384,17 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let mut current_code = cause.code(); let mut coroutine_def_id = None; + if cause.body_def_id != CRATE_DEF_ID { + self.cx.note_obligation_cause_code( + cause.body_def_id, + &mut err, + actual_trait_ref, + self.tcx().param_env(cause.body_def_id), + cause.code(), + &mut vec![], + &mut Default::default(), + ); + } loop { match current_code { 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 e708900aad487..d356a62200cfd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -294,7 +294,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, parent); } - SubregionOrigin::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span, _) => { RegionOriginNote::Plain { span, msg: msg!("...so that the where clause holds") } .add_to_diag(err); } @@ -551,7 +551,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); err } - SubregionOrigin::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span, _) => { let instantiated = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, 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 47d2b7a8c98d5..9219c709eee83 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3832,7 +3832,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true } - pub(super) fn note_obligation_cause_code( + pub(crate) fn note_obligation_cause_code( &self, body_def_id: LocalDefId, err: &mut Diag<'_>, @@ -3903,7 +3903,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::Misc | ObligationCauseCode::WellFormed(..) - | ObligationCauseCode::MatchImpl(..) | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(..) | ObligationCauseCode::AwaitableExpr(_) @@ -4418,6 +4417,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ObligationCauseCode::SharedStatic => { err.note("shared static variables must have a type that implements `Sync`"); } + ObligationCauseCode::MatchImpl(ref cause, _) => { + self.note_obligation_cause_code_inner( + body_def_id, + err, + predicate, + param_env, + &cause.code(), + obligated_types, + seen_requirements, + closure_capture_ty, + ); + } ObligationCauseCode::BuiltinDerived(ref data) => { let parent_trait_ref = self.deeply_resolve_ignoring_regions(data.parent_trait_pred); let ty = parent_trait_ref.skip_binder().self_ty(); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index b4ab3b9729fd3..2fcb7f1741f5a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -109,7 +109,7 @@ fn relate_mir_and_user_args<'tcx>( let cause = ObligationCause::new( span, CRATE_DEF_ID, - ObligationCauseCode::AscribeUserTypeProvePredicate(clause_span), + ObligationCauseCode::AscribeUserTypeProvePredicate(clause_span, def_id), ); let instantiated_clause = ocx.normalize(&cause, param_env, instantiated_clause); diff --git a/tests/ui/associated-types/associated-types-eq-hr.stderr b/tests/ui/associated-types/associated-types-eq-hr.stderr index 40a84eb25d384..70596cbab1225 100644 --- a/tests/ui/associated-types/associated-types-eq-hr.stderr +++ b/tests/ui/associated-types/associated-types-eq-hr.stderr @@ -43,58 +43,93 @@ LL | T: for<'x> TheTrait<&'x isize, A = &'x usize>, error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | +LL | fn tuple_one() + | --------- due to a where-clause on `tuple_one`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, + | ----------------------------------------------------------- unsatisfied where-clause on `tuple_one` +... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | +LL | fn tuple_one() + | --------- due to a where-clause on `tuple_one`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, + | ----------------------------------------------------------- unsatisfied where-clause on `tuple_one` +... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | +LL | fn tuple_one() + | --------- due to a where-clause on `tuple_one`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, + | ------------- unsatisfied where-clause on `tuple_one` +... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | +LL | fn tuple_one() + | --------- due to a where-clause on `tuple_one`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, + | ------------- unsatisfied where-clause on `tuple_one` +... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:104:5 | +LL | fn tuple_two() + | --------- due to a where-clause on `tuple_two`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, + | ----------------------------------------------------------- unsatisfied where-clause on `tuple_two` +... LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:104:5 | +LL | fn tuple_two() + | --------- due to a where-clause on `tuple_two`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, + | ----------------------------------------------------------- unsatisfied where-clause on `tuple_two` +... LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -130,19 +165,31 @@ LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:116:5 | +LL | fn tuple_four() + | ---------- due to a where-clause on `tuple_four`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>, + | -------------------------------------------- unsatisfied where-clause on `tuple_four` +... LL | tuple_four::(); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:116:5 | +LL | fn tuple_four() + | ---------- due to a where-clause on `tuple_four`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>, + | -------------------------------------------- unsatisfied where-clause on `tuple_four` +... LL | tuple_four::(); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr b/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr index 3048cc1d9c1c3..e7f5413cdaaa0 100644 --- a/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr +++ b/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr @@ -7,10 +7,15 @@ LL | | std::future::ready(x).await LL | | } | |_- this async fn captures a value whose type is not `Send` ... +LL | fn is_send(_: T) {} + | ------- ---- unsatisfied where-clause on `is_send` + | | + | due to a where-clause on `is_send`... +... LL | is_send(outer()) - | ^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... + = note: ...`Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr index 5a5bba352c69b..01b99e203c426 100644 --- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr +++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr @@ -1,23 +1,33 @@ error: implementation of `FnOnce` is not general enough --> $DIR/drop-tracking-unresolved-typeck-results.rs:102:5 | +LL | fn send(_: T) {} + | ---- ---- unsatisfied where-clause on `send` + | | + | due to a where-clause on `send`... +... LL | / send(async { LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await LL | | }); - | |______^ implementation of `FnOnce` is not general enough + | |______^ | - = note: `fn(&'0 ()) -> Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... + = note: ...`fn(&'0 ()) -> Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&(),)>` error: implementation of `FnOnce` is not general enough --> $DIR/drop-tracking-unresolved-typeck-results.rs:102:5 | +LL | fn send(_: T) {} + | ---- ---- unsatisfied where-clause on `send` + | | + | due to a where-clause on `send`... +... LL | / send(async { LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await LL | | }); - | |______^ implementation of `FnOnce` is not general enough + | |______^ | - = note: `fn(&'0 ()) -> Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... + = note: ...`fn(&'0 ()) -> Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&(),)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr index 63e71cbc40c75..fd91fd659ac4d 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr @@ -1,6 +1,11 @@ error: implementation of `Robot` is not general enough --> $DIR/higher-ranked-auto-trait-12.rs:31:20 | +LL | fn this_is_send(value: T) -> T { + | ------------ ---- unsatisfied where-clause on `this_is_send` + | | + | due to a where-clause on `this_is_send`... +... LL | let _my_task = this_is_send(async move { | ____________________^ LL | | let _my_iter = IRobot { @@ -9,9 +14,9 @@ LL | | robot: source, LL | | }; LL | | yield_now().await; LL | | }); - | |______^ implementation of `Robot` is not general enough + | |______^ | - = note: `Box<(dyn Robot + Send + '0)>` must implement `Robot`, for any lifetime `'0`... + = note: ...`Box<(dyn Robot + Send + '0)>` must implement `Robot`, for any lifetime `'0`... = note: ...but `Robot` is actually implemented for the type `Box<(dyn Robot + Send + 'static)>` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr index f69218740dcca..abc8ba5e7afa3 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr @@ -1,39 +1,58 @@ error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr index cfbdaa8ad4beb..7c8edb40ac62f 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr @@ -1,60 +1,88 @@ error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Callable` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... + = note: ...`Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Callable` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... + = note: ...`Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 6 previous errors diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr index e8d1f585f0256..fa6dd575527f8 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-15.rs:20:5 | +LL | fn require_send(_x: T) {} + | ------------ ---- unsatisfied where-clause on `require_send` + | | + | due to a where-clause on `require_send`... +... LL | require_send(future); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'0 _) -> Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... + = note: ...closure with signature `fn(&'0 _) -> Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | for _ in things.iter().map(|n: &Vec| n.iter()).flatten() { error: implementation of `FnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-15.rs:20:5 | +LL | fn require_send(_x: T) {} + | ------------ ---- unsatisfied where-clause on `require_send` + | | + | due to a where-clause on `require_send`... +... LL | require_send(future); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'0 _) -> Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... + = note: ...closure with signature `fn(&'0 _) -> Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr index dc6183a45cef5..69e356703c9f0 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr @@ -1,23 +1,33 @@ error: implementation of `AsyncFnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-16.rs:18:5 | +LL | fn assert_send(_: T) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | / assert_send(async { LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; LL | | }); - | |______^ implementation of `AsyncFnOnce` is not general enough + | |______^ | - = note: `{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...`{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` error: implementation of `AsyncFnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-16.rs:18:5 | +LL | fn assert_send(_: T) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | / assert_send(async { LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; LL | | }); - | |______^ implementation of `AsyncFnOnce` is not general enough + | |______^ | - = note: `{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...`{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr index dc6183a45cef5..69e356703c9f0 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr @@ -1,23 +1,33 @@ error: implementation of `AsyncFnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-16.rs:18:5 | +LL | fn assert_send(_: T) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | / assert_send(async { LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; LL | | }); - | |______^ implementation of `AsyncFnOnce` is not general enough + | |______^ | - = note: `{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...`{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` error: implementation of `AsyncFnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-16.rs:18:5 | +LL | fn assert_send(_: T) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | / assert_send(async { LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; LL | | }); - | |______^ implementation of `AsyncFnOnce` is not general enough + | |______^ | - = note: `{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...`{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr index 8fa3c7483c89d..ef743392cb014 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr @@ -4,9 +4,15 @@ error: implementation of `Send` is not general enough LL | / assert_send(async { LL | | call_me.call().await; LL | | }); - | |______^ implementation of `Send` is not general enough + | |______^ +... +LL | pub fn assert_send(_future: F) + | ----------- due to a where-clause on `assert_send`... +LL | where +LL | F: Future + Send, + | ---- unsatisfied where-clause on `assert_send` | - = note: `Send` would have to be implemented for the type `&'0 str`, for any lifetime `'0`... + = note: ...`Send` would have to be implemented for the type `&'0 str`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 str`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr index 6b434ecca0109..be635809f1db7 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr @@ -10,9 +10,15 @@ LL | | if !hc.check().await { LL | | log_health_check_failure().await; LL | | } LL | | }); - | |______^ implementation of `Send` is not general enough + | |______^ +... +LL | fn spawn(future: F) -> JoinHandle + | ----- due to a where-clause on `spawn`... +LL | where +LL | F: Future + Send + 'static, + | ---- unsatisfied where-clause on `spawn` | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...`Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` error: implementation of `Send` is not general enough @@ -27,9 +33,15 @@ LL | | if !hc.check().await { LL | | log_health_check_failure().await; LL | | } LL | | }); - | |______^ implementation of `Send` is not general enough + | |______^ +... +LL | fn spawn(future: F) -> JoinHandle + | ----- due to a where-clause on `spawn`... +LL | where +LL | F: Future + Send + 'static, + | ---- unsatisfied where-clause on `spawn` | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...`Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr index 7b840d54ed038..b5ea0003b1d63 100644 --- a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr +++ b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr @@ -2,9 +2,14 @@ error: implementation of `LoadQuery` is not general enough --> $DIR/implementation-not-general-enough-ice-133252.rs:9:9 | LL | force_send(async_load(¬_static)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `LoadQuery` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn force_send(_: T) {} + | ---------- ---- unsatisfied where-clause on `force_send` + | | + | due to a where-clause on `force_send`... | - = note: `LoadQuery<'0>` would have to be implemented for the type `&u8`, for any lifetime `'0`... + = note: ...`LoadQuery<'0>` would have to be implemented for the type `&u8`, for any lifetime `'0`... = note: ...but `LoadQuery<'1>` is actually implemented for the type `&'1 u8`, for some specific lifetime `'1` error[E0597]: `not_static` does not live long enough diff --git a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr index cdaa16ac9e807..3de229af2a077 100644 --- a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr +++ b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr @@ -1,14 +1,20 @@ error: implementation of `Foo` is not general enough --> $DIR/obligation-with-leaking-placeholders.rs:18:5 | +LL | fn needs_foo(_: T) + | --------- due to a where-clause on `needs_foo`... +LL | where +LL | for<'a> Wrap: Foo<'a>, + | ------- unsatisfied where-clause on `needs_foo` +... LL | / needs_foo(|x| { LL | | LL | | LL | | x.to_string(); LL | | }); - | |______^ implementation of `Foo` is not general enough + | |______^ | - = note: `Wrap<{closure@...}>` must implement `Foo<'0>`, for any lifetime `'0`... + = note: ...`Wrap<{closure@...}>` must implement `Foo<'0>`, for any lifetime `'0`... = note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr index 51691c35f795b..b918a5c5179c8 100644 --- a/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr @@ -1,10 +1,16 @@ error: implementation of `FnOnce` is not general enough --> $DIR/hrtb-closure-suggest-type-annotation.rs:33:5 | +LL | fn inner(buf: &mut [u8], func: F) -> usize + | ----- due to a where-clause on `inner`... +LL | where +LL | F: FnOnce(&mut [u8]) -> Result, + | ----------------------------------------- unsatisfied where-clause on `inner` +... LL | inner(buf, outer_closure) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,12 +20,17 @@ LL | let outer_closure = |buf: &mut [u8]| { error: implementation of `FnOnce` is not general enough --> $DIR/hrtb-closure-suggest-type-annotation.rs:33:5 | +LL | fn inner(buf: &mut [u8], func: F) -> usize + | ----- due to a where-clause on `inner`... +LL | where +LL | F: FnOnce(&mut [u8]) -> Result, + | -------------------- unsatisfied where-clause on `inner` +... LL | inner(buf, outer_closure) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | let outer_closure = |buf: &mut [u8]| { diff --git a/tests/ui/coroutine/auto-trait-regions.stderr b/tests/ui/coroutine/auto-trait-regions.stderr index 75293b2f4a873..566f71d89c28d 100644 --- a/tests/ui/coroutine/auto-trait-regions.stderr +++ b/tests/ui/coroutine/auto-trait-regions.stderr @@ -1,13 +1,18 @@ error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:31:5 | +LL | fn assert_foo(f: T) {} + | ---------- --- unsatisfied where-clause on `assert_foo` + | | + | due to a where-clause on `assert_foo`... +... LL | let generator = #[coroutine] move || { | ------- this coroutine captures a value whose type is not `Foo` ... LL | assert_foo(generator); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... + = note: ...`&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` error[E0626]: borrow may still be in use when coroutine yields @@ -45,13 +50,18 @@ LL | let generator = #[coroutine] static move || { error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:51:5 | +LL | fn assert_foo(f: T) {} + | ---------- --- unsatisfied where-clause on `assert_foo` + | | + | due to a where-clause on `assert_foo`... +... LL | let generator = #[coroutine] move || { | ------- this coroutine captures a value whose type is not `Foo` ... LL | assert_foo(generator); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... + = note: ...`Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` error: aborting due to 4 previous errors diff --git a/tests/ui/coroutine/resume-arg-late-bound.stderr b/tests/ui/coroutine/resume-arg-late-bound.stderr index 0a6fb8dfcbb6c..bc1f1d29edd61 100644 --- a/tests/ui/coroutine/resume-arg-late-bound.stderr +++ b/tests/ui/coroutine/resume-arg-late-bound.stderr @@ -1,10 +1,15 @@ error: implementation of `Coroutine` is not general enough --> $DIR/resume-arg-late-bound.rs:15:5 | +LL | fn test(a: impl for<'a> Coroutine<&'a mut bool>) {} + | ---- ------------------------------- unsatisfied where-clause on `test` + | | + | due to a where-clause on `test`... +... LL | test(gen); - | ^^^^^^^^^ implementation of `Coroutine` is not general enough + | ^^^^^^^^^ | - = note: `{coroutine@...}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`... + = note: ...`{coroutine@...}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`... = note: ...but it actually implements `Coroutine<&'2 mut bool>`, for some specific lifetime `'2` error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr b/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr index 8ae308303b8a3..42aa33c0be186 100644 --- a/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr +++ b/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr @@ -1,11 +1,22 @@ error: implementation of `Lengthen` is not general enough --> $DIR/gat-bounds-not-checked-with-right-substitutions.rs:20:20 | +LL | type Gat<'a>: for<'b> Lengthen>; + | --- ------------------------------- unsatisfied where-clause on `Gat::Gat` + | | + | due to a where-clause on `Gat::Gat`... +... LL | type Gat<'a> = &'a str; - | ^^^^^^^ implementation of `Lengthen` is not general enough + | ^^^^^^^ | - = note: `Lengthen<&'0 str>` would have to be implemented for the type `&'a str`, for any lifetime `'0`... + = note: ...`Lengthen<&'0 str>` would have to be implemented for the type `&'a str`, for any lifetime `'0`... = note: ...but `Lengthen<&'1 str>` is actually implemented for the type `&'1 str`, for some specific lifetime `'1` +note: required by a bound in `Gat::Gat` + --> $DIR/gat-bounds-not-checked-with-right-substitutions.rs:12:19 + | +LL | trait Gat { +LL | type Gat<'a>: for<'b> Lengthen>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Gat::Gat` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/hr-fn-ptr-trait-impl-mismatch-29061.stderr b/tests/ui/higher-ranked/hr-fn-ptr-trait-impl-mismatch-29061.stderr index 19a63fb6fb6a6..7c3fcf47e6a40 100644 --- a/tests/ui/higher-ranked/hr-fn-ptr-trait-impl-mismatch-29061.stderr +++ b/tests/ui/higher-ranked/hr-fn-ptr-trait-impl-mismatch-29061.stderr @@ -1,28 +1,43 @@ error: implementation of `HR` is not general enough --> $DIR/hr-fn-ptr-trait-impl-mismatch-29061.rs:25:5 | +LL | fn hr(_: T) {} + | -- -- unsatisfied where-clause on `hr` + | | + | due to a where-clause on `hr`... +... LL | hr(not_hr_func); - | ^^^^^^^^^^^^^^^ implementation of `HR` is not general enough + | ^^^^^^^^^^^^^^^ | - = note: `HR` would have to be implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`... + = note: ...`HR` would have to be implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`... = note: ...but `HR` is actually implemented for the type `for<'a> fn(&'a ())` error: implementation of `NotHR` is not general enough --> $DIR/hr-fn-ptr-trait-impl-mismatch-29061.rs:27:5 | +LL | fn not_hr(_: T) {} + | ------ ----- unsatisfied where-clause on `not_hr` + | | + | due to a where-clause on `not_hr`... +... LL | not_hr(hr_func); - | ^^^^^^^^^^^^^^^ implementation of `NotHR` is not general enough + | ^^^^^^^^^^^^^^^ | - = note: `NotHR` would have to be implemented for the type `for<'a> fn(&'a ())` + = note: ...`NotHR` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `NotHR` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` error: implementation of `NotHR` is not general enough --> $DIR/hr-fn-ptr-trait-impl-mismatch-29061.rs:29:5 | +LL | fn not_hr(_: T) {} + | ------ ----- unsatisfied where-clause on `not_hr` + | | + | due to a where-clause on `not_hr`... +... LL | not_hr(hr_func2); - | ^^^^^^^^^^^^^^^^ implementation of `NotHR` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: `NotHR` would have to be implemented for the type `for<'b> fn(&'b ())` + = note: ...`NotHR` would have to be implemented for the type `for<'b> fn(&'b ())` = note: ...but `NotHR` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` error: aborting due to 3 previous errors diff --git a/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr b/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr index 40ac1d9d041be..eaa82c3f77871 100644 --- a/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr +++ b/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr @@ -1,13 +1,19 @@ error: implementation of `DistributedIteratorMulti` is not general enough --> $DIR/hrtb-associated-type-leak-check-55731.rs:49:5 | +LL | fn multi(_reducer: I) + | ----- due to a where-clause on `multi`... +LL | where +LL | I: for<'a> DistributedIteratorMulti<&'a ()>, + | ---------------------------------------- unsatisfied where-clause on `multi` +... LL | / multi(Map { LL | | i: Cloned(PhantomData), LL | | f: X, LL | | }); - | |______^ implementation of `DistributedIteratorMulti` is not general enough + | |______^ | - = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`... + = note: ...`DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`... = note: ...but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr b/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr index c8d88b6243c4f..afed0bca3fffe 100644 --- a/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr +++ b/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr @@ -14,10 +14,15 @@ LL | trait X { error: implementation of `X` is not general enough --> $DIR/hrtb-fn-ptr-impl-not-general-enough-57936.rs:26:5 | +LL | fn indirect() { + | -------- - unsatisfied where-clause on `indirect` + | | + | due to a where-clause on `indirect`... +... LL | indirect::(); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `X` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `X` would have to be implemented for the type `for<'a> fn(&'a ())` + = note: ...`X` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `X` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` error: aborting due to 2 previous errors diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr index 69c58c5919e11..830ed0638a80d 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr @@ -1,19 +1,29 @@ error: implementation of `Foo` is not general enough --> $DIR/hrtb-conflate-regions.rs:27:10 | +LL | fn want_foo2() + | --------- due to a where-clause on `want_foo2`... +LL | where T : for<'a,'b> Foo<(&'a isize, &'b isize)> + | -------------------------------------- unsatisfied where-clause on `want_foo2` +... LL | fn b() { want_foo2::(); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `Foo` is not general enough --> $DIR/hrtb-conflate-regions.rs:27:10 | +LL | fn want_foo2() + | --------- due to a where-clause on `want_foo2`... +LL | where T : for<'a,'b> Foo<(&'a isize, &'b isize)> + | -------------------------------------- unsatisfied where-clause on `want_foo2` +... LL | fn b() { want_foo2::(); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr index 9697a270b8aa0..28ae64dff3e47 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr @@ -1,10 +1,16 @@ error: implementation of `Trait` is not general enough --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5 | +LL | fn foo() + | --- due to a where-clause on `foo`... +LL | where +LL | T: Trait fn(&'b u32)>, + | -------------------------- unsatisfied where-clause on `foo` +... LL | foo::<()>(); - | ^^^^^^^^^^^ implementation of `Trait` is not general enough + | ^^^^^^^^^^^ | - = note: `()` must implement `Trait fn(&'b u32)>` + = note: ...`()` must implement `Trait fn(&'b u32)>` = note: ...but it actually implements `Trait`, for some specific lifetime `'0` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr index 385de795b18f0..4b9d7e1d7109e 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr @@ -1,10 +1,16 @@ error: implementation of `Trait` is not general enough --> $DIR/hrtb-exists-forall-trait-covariant.rs:33:5 | +LL | fn foo() + | --- due to a where-clause on `foo`... +LL | where +LL | T: Trait fn(fn(&'b u32))>, + | ------------------------------ unsatisfied where-clause on `foo` +... LL | foo::<()>(); - | ^^^^^^^^^^^ implementation of `Trait` is not general enough + | ^^^^^^^^^^^ | - = note: `()` must implement `Trait fn(fn(&'b u32))>` + = note: ...`()` must implement `Trait fn(fn(&'b u32))>` = note: ...but it actually implements `Trait`, for some specific lifetime `'0` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr index cf64c2acdbe9c..45ff3ef758713 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr @@ -1,10 +1,16 @@ error: implementation of `Trait` is not general enough --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 | +LL | fn foo() + | --- due to a where-clause on `foo`... +LL | where +LL | T: Trait fn(Cell<&'b u32>)>, + | -------------------------------- unsatisfied where-clause on `foo` +... LL | foo::<()>(); - | ^^^^^^^^^^^ implementation of `Trait` is not general enough + | ^^^^^^^^^^^ | - = note: `()` must implement `Trait fn(Cell<&'b u32>)>` + = note: ...`()` must implement `Trait fn(Cell<&'b u32>)>` = note: ...but it actually implements `Trait)>`, for some specific lifetime `'0` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr index 697e85dc8c394..6ba3d119ccb94 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr @@ -1,10 +1,15 @@ error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:24:5 | +LL | fn want_hrtb() + | --------- due to a where-clause on `want_hrtb`... +LL | where T : for<'a> Foo<&'a isize> + | ---------------------- unsatisfied where-clause on `want_hrtb` +... LL | want_hrtb::() - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... + = note: ...`StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... = note: ...but it actually implements `Foo<&'static isize>` error: lifetime may not live long enough diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr index 327c0faa48287..db22eeb46aef0 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr @@ -56,10 +56,16 @@ LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, error: implementation of `Bar` is not general enough --> $DIR/hrtb-perfect-forwarding.rs:43:5 | +LL | fn foo_hrtb_bar_not<'b, T>(mut t: T) + | ---------------- due to a where-clause on `foo_hrtb_bar_not`... +LL | where +LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, + | ---------------------- unsatisfied where-clause on `foo_hrtb_bar_not` +... LL | foo_hrtb_bar_not(&mut t); - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... + = note: ...`T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1` warning: function cannot return without recursing diff --git a/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr b/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr index c50e79dd4cc48..e1d900f20ce3b 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr @@ -1,10 +1,15 @@ error: implementation of `Foo` is not general enough --> $DIR/issue-46989.rs:38:5 | +LL | fn assert_foo() {} + | ---------- --- unsatisfied where-clause on `assert_foo` + | | + | due to a where-clause on `assert_foo`... +... LL | assert_foo::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a i32)` + = note: ...`Foo` would have to be implemented for the type `for<'a> fn(&'a i32)` = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr index f8f64dcc545bc..f7b72ec65db3f 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr @@ -1,15 +1,14 @@ error: implementation of `Trait` is not general enough --> $DIR/issue-59311.rs:17:5 | -LL | / pub fn crash(v: &V) -LL | | where -LL | | for<'a> &'a V: Trait + 'static, - | |____________________-----__________- due to a where-clause on `crash`... - | | - | doesn't satisfy where-clause -LL | { -LL | v.t(|| {}); - | ^^^^^^^^^^ +LL | pub fn crash(v: &V) + | ----- due to a where-clause on `crash`... +LL | where +LL | for<'a> &'a V: Trait + 'static, + | ----- unsatisfied where-clause on `crash` +LL | { +LL | v.t(|| {}); + | ^^^^^^^^^^ | = note: ...`Trait` would have to be implemented for the type `&'a V` = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0` @@ -17,15 +16,14 @@ LL | v.t(|| {}); error: implementation of `Trait` is not general enough --> $DIR/issue-59311.rs:17:5 | -LL | / pub fn crash(v: &V) -LL | | where -LL | | for<'a> &'a V: Trait + 'static, - | |____________________-----__________- due to a where-clause on `crash`... - | | - | doesn't satisfy where-clause -LL | { -LL | v.t(|| {}); - | ^^^^^^^^^^ +LL | pub fn crash(v: &V) + | ----- due to a where-clause on `crash`... +LL | where +LL | for<'a> &'a V: Trait + 'static, + | ----- unsatisfied where-clause on `crash` +LL | { +LL | v.t(|| {}); + | ^^^^^^^^^^ | = note: ...`Trait` would have to be implemented for the type `&'a V` = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0` diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index 3c6aab12bf137..fa524168e12e7 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -1,10 +1,16 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:45:5 | +LL | fn foo( + | --- due to a where-clause on `foo`... +... +LL | F2: FnOnce(&::Output) -> bool + | --------------------------------------- unsatisfied where-clause on `foo` +... LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,12 +20,17 @@ LL | foo(bar, "string", |s: &&str| s.len() == 5); error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:45:5 | +LL | fn foo( + | --- due to a where-clause on `foo`... +... +LL | F2: FnOnce(&::Output) -> bool + | ---- unsatisfied where-clause on `foo` +... LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | foo(bar, "string", |s: &&str| s.len() == 5); @@ -28,10 +39,16 @@ LL | foo(bar, "string", |s: &&str| s.len() == 5); error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 | +LL | fn foo( + | --- due to a where-clause on `foo`... +... +LL | F2: FnOnce(&::Output) -> bool + | --------------------------------------- unsatisfied where-clause on `foo` +... LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -41,12 +58,17 @@ LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 | +LL | fn foo( + | --- due to a where-clause on `foo`... +... +LL | F2: FnOnce(&::Output) -> bool + | ---- unsatisfied where-clause on `foo` +... LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr index db623761b268e..18960ff575a2a 100644 --- a/tests/ui/lifetimes/issue-105675.stderr +++ b/tests/ui/lifetimes/issue-105675.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:5:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` help: consider adding explicit type annotations to the closure's arguments | @@ -14,10 +19,15 @@ LL | let f = | _: &u32 , y: &u32 , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:5:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding explicit type annotations to the closure's arguments @@ -28,10 +38,15 @@ LL | let f = | _: &u32 , y: &u32 , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -41,10 +56,15 @@ LL | let f = | x: &u32, y: _ , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -54,10 +74,15 @@ LL | let f = | x: &u32, y: _ , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument @@ -68,10 +93,15 @@ LL | let f = | x: &u32, y: _ , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index 9993de99b9e48..7029eeafef0eb 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187-2.rs:8:5 | +LL | fn take_foo(_: impl Foo) {} + | -------- --- unsatisfied where-clause on `take_foo` + | | + | due to a where-clause on `take_foo`... +... LL | take_foo(|a| a); - | ^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 i32,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | take_foo(|a: &i32| a); error: implementation of `Fn` is not general enough --> $DIR/issue-79187-2.rs:8:5 | +LL | fn take_foo(_: impl Foo) {} + | -------- --- unsatisfied where-clause on `take_foo` + | | + | due to a where-clause on `take_foo`... +... LL | take_foo(|a| a); - | ^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 i32) -> &i32` must implement `Fn<(&'1 i32,)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 i32) -> &i32` must implement `Fn<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 i32,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | diff --git a/tests/ui/lifetimes/issue-79187.stderr b/tests/ui/lifetimes/issue-79187.stderr index e08400481e470..3dbb6054a7ad3 100644 --- a/tests/ui/lifetimes/issue-79187.stderr +++ b/tests/ui/lifetimes/issue-79187.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 | +LL | fn thing(x: impl FnOnce(&u32)) {} + | ----- ------------ unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | let f = |_: &u32| (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 | +LL | fn thing(x: impl FnOnce(&u32)) {} + | ----- ------------ unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr index 4dada6ff014ad..3a293cc4b2516 100644 --- a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr +++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr @@ -45,19 +45,27 @@ LL | fn g(data: &[T]) { error: implementation of `Fn` is not general enough --> $DIR/issue_74400.rs:12:5 | +LL | fn f(data: &[T], key: impl Fn(&T) -> S) { + | - ----------- unsatisfied where-clause on `f` + | | + | due to a where-clause on `f`... +... LL | f(data, identity) - | ^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^^^^^^^ | - = note: `fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `Fn<(&'1 T,)>`, for any lifetime `'1`... + = note: ...`fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `Fn<(&'1 T,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 T,)>`, for some specific lifetime `'2` error: implementation of `FnOnce` is not general enough --> $DIR/issue_74400.rs:12:5 | +LL | fn f(data: &[T], key: impl Fn(&T) -> S) { + | - due to a where-clause on `f`... - unsatisfied where-clause on `f` +... LL | f(data, identity) - | ^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^ | - = note: `fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `FnOnce<(&'1 T,)>`, for any lifetime `'1`... + = note: ...`fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `FnOnce<(&'1 T,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 T,)>`, for some specific lifetime `'2` error: aborting due to 5 previous errors diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr index ab52f3d3ee43e..856aba98d1c4c 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -66,19 +66,29 @@ LL | fn baz(_: F) {} error: implementation of `Fn` is not general enough --> $DIR/closure-arg-type-mismatch.rs:10:5 | +LL | fn baz(_: F) {} + | --- ------------- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +LL | fn _test<'a>(f: fn(*mut &'a u32)) { LL | baz(f); - | ^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^ | - = note: `fn(*mut &'2 u32)` must implement `Fn<(*mut &'1 u32,)>`, for any lifetime `'1`... + = note: ...`fn(*mut &'2 u32)` must implement `Fn<(*mut &'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(*mut &'2 u32,)>`, for some specific lifetime `'2` error: implementation of `FnOnce` is not general enough --> $DIR/closure-arg-type-mismatch.rs:10:5 | +LL | fn baz(_: F) {} + | --- ------------- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +LL | fn _test<'a>(f: fn(*mut &'a u32)) { LL | baz(f); - | ^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^ | - = note: `fn(*mut &'2 u32)` must implement `FnOnce<(*mut &'1 u32,)>`, for any lifetime `'1`... + = note: ...`fn(*mut &'2 u32)` must implement `FnOnce<(*mut &'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(*mut &'2 u32,)>`, for some specific lifetime `'2` error: aborting due to 6 previous errors diff --git a/tests/ui/mismatched_types/closure-mismatch.current.stderr b/tests/ui/mismatched_types/closure-mismatch.current.stderr index 82e3e4b0f78f2..0dbefa4b2aa19 100644 --- a/tests/ui/mismatched_types/closure-mismatch.current.stderr +++ b/tests/ui/mismatched_types/closure-mismatch.current.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/closure-mismatch.rs:12:5 | +LL | fn baz(_: T) {} + | --- --- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +... LL | baz(|_| ()); - | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | baz(|_: &()| ()); error: implementation of `Fn` is not general enough --> $DIR/closure-mismatch.rs:12:5 | +LL | fn baz(_: T) {} + | --- --- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +... LL | baz(|_| ()); - | ^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -27,10 +37,15 @@ LL | baz(|_: &()| ()); error: implementation of `FnOnce` is not general enough --> $DIR/closure-mismatch.rs:16:5 | +LL | fn baz(_: T) {} + | --- --- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +... LL | baz(|x| ()); - | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -40,10 +55,15 @@ LL | baz(|x: &()| ()); error: implementation of `Fn` is not general enough --> $DIR/closure-mismatch.rs:16:5 | +LL | fn baz(_: T) {} + | --- --- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +... LL | baz(|x| ()); - | ^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | diff --git a/tests/ui/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr index 45dd1557dd027..60f155eb45eb1 100644 --- a/tests/ui/nll/ice-106874.stderr +++ b/tests/ui/nll/ice-106874.stderr @@ -2,9 +2,14 @@ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:5 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct B(Rc); + | - - unsatisfied where-clause on `B` + | | + | due to a where-clause on `B`... | - = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... + = note: ...closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` help: consider adding an explicit type annotation to the closure's argument | @@ -15,9 +20,14 @@ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:5 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct B(Rc); + | - - unsatisfied where-clause on `B` + | | + | due to a where-clause on `B`... | - = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... + = note: ...closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument @@ -69,11 +79,17 @@ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + --> $SRC_DIR/alloc/src/rcs/rc.rs:LL:COL + | + = note: due to a where-clause on `Rc`... + ::: $SRC_DIR/alloc/src/rcs/rc.rs:LL:COL + | + = note: unsatisfied where-clause on `Rc` + | + = note: ...closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) @@ -83,11 +99,17 @@ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + --> $SRC_DIR/alloc/src/rcs/rc.rs:LL:COL + | + = note: due to a where-clause on `Rc`... + ::: $SRC_DIR/alloc/src/rcs/rc.rs:LL:COL + | + = note: unsatisfied where-clause on `Rc` + | + = note: ...closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) @@ -97,11 +119,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct B(Rc); + | - - unsatisfied where-clause on `B` + | | + | due to a where-clause on `B`... + | + = note: ...closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) @@ -111,11 +137,15 @@ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough - | - = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct B(Rc); + | - - unsatisfied where-clause on `B` + | | + | due to a where-clause on `B`... + | + = note: ...closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) diff --git a/tests/ui/nll/issue-54302-cases.stderr b/tests/ui/nll/issue-54302-cases.stderr index 6e8b69c4beebb..4c5535258f624 100644 --- a/tests/ui/nll/issue-54302-cases.stderr +++ b/tests/ui/nll/issue-54302-cases.stderr @@ -1,37 +1,49 @@ error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:63:5 | +LL | fn ref_foo(&self) -> &'static T; + | ------- due to a where-clause on `RefFoo::ref_foo`... +... LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `RefFoo::ref_foo` | - = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... + = note: ...`Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:69:5 | +LL | fn ref_foo(&self) -> &'static T; + | ------- due to a where-clause on `RefFoo::ref_foo`... +... LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `RefFoo::ref_foo` | - = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`... + = note: ...`Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`... = note: ...but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:75:5 | +LL | fn ref_foo(&self) -> &'static T; + | ------- due to a where-clause on `RefFoo::ref_foo`... +... LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `RefFoo::ref_foo` | - = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`... + = note: ...`Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`... = note: ...but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:81:5 | +LL | fn ref_foo(&self) -> &'static T; + | ------- due to a where-clause on `RefFoo::ref_foo`... +... LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `RefFoo::ref_foo` | - = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`... + = note: ...`Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`... = note: ...but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1` error: aborting due to 4 previous errors diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr index d8922ef80e813..f0f407afd7601 100644 --- a/tests/ui/nll/missing-universe-cause-issue-114907.stderr +++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 | +LL | fn accept(_: C) -> Handshake> { + | ------ ----------- unsatisfied where-clause on `accept` + | | + | due to a where-clause on `accept`... +... LL | accept(callback); - | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | let callback = |_: &()| {}; error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 | +LL | fn accept(_: C) -> Handshake> { + | ------ ----------- unsatisfied where-clause on `accept` + | | + | due to a where-clause on `accept`... +... LL | accept(callback); - | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument @@ -28,12 +38,16 @@ LL | let callback = |_: &()| {}; error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 | +LL | struct Handshake { + | --------- ---- unsatisfied where-clause on `Handshake` + | | + | due to a where-clause on `Handshake`... +... LL | accept(callback); - | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | let callback = |_: &()| {}; @@ -42,10 +56,15 @@ LL | let callback = |_: &()| {}; error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 | +LL | struct Handshake { + | --------- ---- unsatisfied where-clause on `Handshake` + | | + | due to a where-clause on `Handshake`... +... LL | accept(callback); - | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 46e4fbea0d952..2e164c9b3abb7 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -28,9 +28,14 @@ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:14:5 | LL | bad(&b); - | ^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^ +... +LL | fn bad &()>(_: F) {} + | --- -------------- unsatisfied where-clause on `bad` + | | + | due to a where-clause on `bad`... | - = note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -41,9 +46,14 @@ error: implementation of `FnOnce` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:14:5 | LL | bad(&b); - | ^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^ +... +LL | fn bad &()>(_: F) {} + | --- --- unsatisfied where-clause on `bad` + | | + | due to a where-clause on `bad`... | - = note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 46e4fbea0d952..2e164c9b3abb7 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -28,9 +28,14 @@ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:14:5 | LL | bad(&b); - | ^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^ +... +LL | fn bad &()>(_: F) {} + | --- -------------- unsatisfied where-clause on `bad` + | | + | due to a where-clause on `bad`... | - = note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -41,9 +46,14 @@ error: implementation of `FnOnce` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:14:5 | LL | bad(&b); - | ^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^ +... +LL | fn bad &()>(_: F) {} + | --- --- unsatisfied where-clause on `bad` + | | + | due to a where-clause on `bad`... | - = note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | diff --git a/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr index 804071a3e6f77..ced5c4b8058b0 100644 --- a/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr +++ b/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr @@ -1,21 +1,26 @@ error: implementation of `Y` is not general enough --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14 | +LL | fn make_f() -> Self::F; + | ------ due to a where-clause on `Y::make_f`... +... LL | let _x = ::make_f(); - | ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough + | ^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `Y::make_f` | - = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())` + = note: ...`Y` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` error: implementation of `Y` is not general enough --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14 | +LL | trait Y { + | - due to a where-clause on `Y`... +... LL | let _x = ::make_f(); - | ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough + | ^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `Y` | - = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())` + = note: ...`Y` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Y` is not general enough --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14 @@ -25,7 +30,6 @@ LL | let _x = ::make_f(); | = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr index f0bb77cfe4c8c..2703d276e41f7 100644 --- a/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr +++ b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr @@ -6,6 +6,11 @@ LL | fn main() -> Thing { Thing } | = note: `IsStatic` would have to be implemented for the type `&'0 ()`, for any lifetime `'0`... = note: ...but `IsStatic` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` +note: required for `Thing` to implement `Termination` + --> $DIR/main-termination-lifetime-issue-148421.rs:13:6 + | +LL | impl Termination for Thing where for<'a> &'a (): IsStatic { + | ^^^^^^^^^^^ ^^^^^ -------- unsatisfied trait bound introduced here error: aborting due to 1 previous error diff --git a/tests/ui/unboxed-closures/issue-30906.stderr b/tests/ui/unboxed-closures/issue-30906.stderr index 0815ae1fb5a2b..fa61b3af02cf0 100644 --- a/tests/ui/unboxed-closures/issue-30906.stderr +++ b/tests/ui/unboxed-closures/issue-30906.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-30906.rs:18:5 | +LL | fn test FnOnce<(&'x str,)>>(_: F) {} + | ---- -------------------------- unsatisfied where-clause on `test` + | | + | due to a where-clause on `test`... +... LL | test(Compose(f, |_| {})); - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `fn(&'2 str) -> T` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`... + = note: ...`fn(&'2 str) -> T` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2` error: aborting due to 1 previous error diff --git a/tests/ui/where-clauses/where-for-self-2.stderr b/tests/ui/where-clauses/where-for-self-2.stderr index f479210772194..378616d9aca57 100644 --- a/tests/ui/where-clauses/where-for-self-2.stderr +++ b/tests/ui/where-clauses/where-for-self-2.stderr @@ -1,10 +1,16 @@ error: implementation of `Bar` is not general enough --> $DIR/where-for-self-2.rs:23:5 | +LL | fn foo(x: &T) + | --- due to a where-clause on `foo`... +LL | where +LL | for<'a> &'a T: Bar, + | --- unsatisfied where-clause on `foo` +... LL | foo(&X); - | ^^^^^^^ implementation of `Bar` is not general enough + | ^^^^^^^ | - = note: `&'0 u32` must implement `Bar`, for any lifetime `'0`... + = note: ...`&'0 u32` must implement `Bar`, for any lifetime `'0`... = note: ...but `Bar` is actually implemented for the type `&'static u32` error: aborting due to 1 previous error From 3aba6fc0eb421321789fc6e9891358fc2a6d1d03 Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 30 Sep 2026 09:59:46 -0400 Subject: [PATCH 71/71] Add libs-nominated triagebot config --- triagebot.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 611f7724f5cae..77acf0edda0a6 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -707,6 +707,16 @@ message_on_remove = "Issue #{number}'s nomination has been removed. Thanks all f message_on_close = "Issue #{number} has been closed. Thanks for participating!" message_on_reopen = "Issue #{number} has been reopened. Pinging @*T-types*." +[notify-zulip."I-libs-nominated"] +zulip_stream = 639962 # #t-libs/nominated +topic = "#{number}: {title}" +message_on_add = """\ +[#{number} "{title}"](https://github.com/rust-lang/rust/pull/{number}) has been nominated for discussion. +""" +message_on_remove = """\ +#{number} is no longer nominated. +""" + # ------------------------------------------------------------------------------ # Zulip notifications