From 68cfe93c112699e0651eb54e4a4de4b3a14cb5cc Mon Sep 17 00:00:00 2001 From: Zachary S Date: Mon, 15 Jun 2026 00:47:48 -0500 Subject: [PATCH 01/71] Add comments to randomize-layout implementation documenting guaranteed ZST struct/enums. Also add tests for the guaranteed types. --- compiler/rustc_abi/src/layout.rs | 4 +++ compiler/rustc_abi/src/lib.rs | 4 +++ tests/ui/layout/randomize.rs | 43 ++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 003e811dc7855..a433761e73797 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1124,6 +1124,10 @@ impl LayoutCalculator { // If `-Z randomize-layout` was enabled for the type definition we can shuffle // the field ordering to try and catch some code making assumptions about layouts // we don't guarantee. + // In the future, we might do more than shuffle field order (e.g. introduce extra padding), + // but never for `repr(Rust)` structs with only zero-sized fields or single-variant + // `repr(Rust)` enums with only zero-sized fields, which must remain zero-sized as per + // T-lang decision https://github.com/rust-lang/reference/pull/2262 if repr.can_randomize_type_layout() && cfg!(feature = "randomize") { #[cfg(feature = "randomize")] { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index c2069432e6f8e..97bef297b6ef5 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -90,6 +90,10 @@ bitflags! { /// If true, the type's crate has opted into layout randomization. /// Other flags can still inhibit reordering and thus randomization. /// The seed stored in `ReprOptions.field_shuffle_seed`. + /// + /// `repr(Rust)` structs with only zero-sized fields and single-variant `repr(Rust)` enums with only + /// zero-sized fields must remain zero-sized as per T-lang decision + /// https://github.com/rust-lang/reference/pull/2262 const RANDOMIZE_LAYOUT = 1 << 4; /// If true, the type is always passed indirectly by non-Rustic ABIs. /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. diff --git a/tests/ui/layout/randomize.rs b/tests/ui/layout/randomize.rs index 27e99327a3196..f25ee23009049 100644 --- a/tests/ui/layout/randomize.rs +++ b/tests/ui/layout/randomize.rs @@ -49,6 +49,49 @@ const _: () = { assert!(std::mem::offset_of!(Result::<&usize, ()>, Ok.0) == 0); }; +// these types only have their size checked, they're never constructed. +// these repr(Rust) types must remain zero-sized. +#[allow(dead_code)] +pub struct UnitStruct; +#[allow(dead_code)] +pub struct EmptyTupleStruct(); +#[allow(dead_code)] +pub struct EmptyStruct {} +#[allow(dead_code)] +pub struct ZstFieldsTupleStruct((), [u64; 0], [u8; 0], [(); 42]); +#[allow(dead_code)] +pub struct ZstFieldsStruct { + a: (), + b: [u64; 0], + c: [u8; 0], + d: [(); 42], +} +#[allow(dead_code)] +pub enum SingleUnitVariantEnum { A } +#[allow(dead_code)] +pub enum SingleZstFieldTupleVariantEnum { A((), [u64; 0], [u8; 0], [(); 42]) } +#[allow(dead_code)] +pub enum SingleZstFieldVariantEnum { + A { + a: (), + b: [u64; 0], + c: [u8; 0], + d: [(); 42], + } +} + +// all these types must remain zero-sized. +const _: () = { + assert!(size_of::() == 0); + assert!(size_of::() == 0); + assert!(size_of::() == 0); + assert!(size_of::() == 0); + assert!(size_of::() == 0); + assert!(size_of::() == 0); + assert!(size_of::() == 0); + assert!(size_of::() == 0); +}; + #[allow(dead_code)] struct Unsizable(usize, T); From bec5d880be77a942f3fc88eb20732e67e029dd93 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Mon, 15 Jun 2026 00:49:32 -0500 Subject: [PATCH 02/71] Add zero-variant enums to randomize-layout comments and tests. --- compiler/rustc_abi/src/layout.rs | 7 ++++--- compiler/rustc_abi/src/lib.rs | 6 +++--- tests/ui/layout/randomize.rs | 3 +++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index a433761e73797..7f1a7021f5bcc 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1125,9 +1125,10 @@ impl LayoutCalculator { // the field ordering to try and catch some code making assumptions about layouts // we don't guarantee. // In the future, we might do more than shuffle field order (e.g. introduce extra padding), - // but never for `repr(Rust)` structs with only zero-sized fields or single-variant - // `repr(Rust)` enums with only zero-sized fields, which must remain zero-sized as per - // T-lang decision https://github.com/rust-lang/reference/pull/2262 + // but never for `repr(Rust)` structs with only zero-sized fields, single-variant + // `repr(Rust)` enums with only zero-sized fields, or zero-variant `repr(Rust)` enums, + // which must remain zero-sized as per T-lang decisions in + // https://github.com/rust-lang/reference/pull/2262 and https://github.com/rust-lang/reference/pull/2293 if repr.can_randomize_type_layout() && cfg!(feature = "randomize") { #[cfg(feature = "randomize")] { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 97bef297b6ef5..2a7dde3b8840e 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -91,9 +91,9 @@ bitflags! { /// Other flags can still inhibit reordering and thus randomization. /// The seed stored in `ReprOptions.field_shuffle_seed`. /// - /// `repr(Rust)` structs with only zero-sized fields and single-variant `repr(Rust)` enums with only - /// zero-sized fields must remain zero-sized as per T-lang decision - /// https://github.com/rust-lang/reference/pull/2262 + /// `repr(Rust)` structs with only zero-sized fields, single-variant `repr(Rust)` enums with only + /// zero-sized fields, and zero-variant `repr(Rust)` enums must remain zero-sized as per + /// T-lang decisions in https://github.com/rust-lang/reference/pull/2262 and https://github.com/rust-lang/reference/pull/2293 const RANDOMIZE_LAYOUT = 1 << 4; /// If true, the type is always passed indirectly by non-Rustic ABIs. /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. diff --git a/tests/ui/layout/randomize.rs b/tests/ui/layout/randomize.rs index f25ee23009049..eaeb527f191cb 100644 --- a/tests/ui/layout/randomize.rs +++ b/tests/ui/layout/randomize.rs @@ -67,6 +67,8 @@ pub struct ZstFieldsStruct { d: [(); 42], } #[allow(dead_code)] +pub enum EmptyEnum {} +#[allow(dead_code)] pub enum SingleUnitVariantEnum { A } #[allow(dead_code)] pub enum SingleZstFieldTupleVariantEnum { A((), [u64; 0], [u8; 0], [(); 42]) } @@ -87,6 +89,7 @@ const _: () = { assert!(size_of::() == 0); assert!(size_of::() == 0); assert!(size_of::() == 0); + assert!(size_of::() == 0); assert!(size_of::() == 0); assert!(size_of::() == 0); assert!(size_of::() == 0); From 715a61625e63c83d87141c2badf9f0cd1bdc5d94 Mon Sep 17 00:00:00 2001 From: zedddie Date: Thu, 9 Jul 2026 23:32:40 +0200 Subject: [PATCH 03/71] move batch --- .../issue-37131.rs => crate-loading/missing-target-error.rs} | 0 .../missing-target-error.stderr} | 0 .../if/mut-borrow-in-else-if-after-if-let.rs} | 0 tests/ui/{issues/issue-38556.rs => imports/macro-use-as.rs} | 0 .../lifetime-errors/iterator-next-extra-named-lifetime.rs} | 0 .../lifetime-errors/iterator-next-extra-named-lifetime.stderr} | 0 .../ambig-method-call-in-trait-impl.rs} | 0 .../ambig-method-call-in-trait-impl.stderr} | 0 .../{issues/issue-3847.rs => parser/other-module-struct-match.rs} | 0 .../issue-3753.rs => parser/pub-method-after-attribute.rs} | 0 .../issue-3702.rs => traits/object/nested-trait-method-call.rs} | 0 .../issue-37665.rs => unpretty/mir-unpretty-type-error.rs} | 0 .../mir-unpretty-type-error.stderr} | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-37131.rs => crate-loading/missing-target-error.rs} (100%) rename tests/ui/{issues/issue-37131.stderr => crate-loading/missing-target-error.stderr} (100%) rename tests/ui/{issues/issue-37510.rs => expr/if/mut-borrow-in-else-if-after-if-let.rs} (100%) rename tests/ui/{issues/issue-38556.rs => imports/macro-use-as.rs} (100%) rename tests/ui/{issues/issue-37884.rs => lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.rs} (100%) rename tests/ui/{issues/issue-37884.stderr => lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.stderr} (100%) rename tests/ui/{issues/issue-3702-2.rs => methods/ambig-method-call-in-trait-impl.rs} (100%) rename tests/ui/{issues/issue-3702-2.stderr => methods/ambig-method-call-in-trait-impl.stderr} (100%) rename tests/ui/{issues/issue-3847.rs => parser/other-module-struct-match.rs} (100%) rename tests/ui/{issues/issue-3753.rs => parser/pub-method-after-attribute.rs} (100%) rename tests/ui/{issues/issue-3702.rs => traits/object/nested-trait-method-call.rs} (100%) rename tests/ui/{issues/issue-37665.rs => unpretty/mir-unpretty-type-error.rs} (100%) rename tests/ui/{issues/issue-37665.stderr => unpretty/mir-unpretty-type-error.stderr} (100%) diff --git a/tests/ui/issues/issue-37131.rs b/tests/ui/crate-loading/missing-target-error.rs similarity index 100% rename from tests/ui/issues/issue-37131.rs rename to tests/ui/crate-loading/missing-target-error.rs diff --git a/tests/ui/issues/issue-37131.stderr b/tests/ui/crate-loading/missing-target-error.stderr similarity index 100% rename from tests/ui/issues/issue-37131.stderr rename to tests/ui/crate-loading/missing-target-error.stderr diff --git a/tests/ui/issues/issue-37510.rs b/tests/ui/expr/if/mut-borrow-in-else-if-after-if-let.rs similarity index 100% rename from tests/ui/issues/issue-37510.rs rename to tests/ui/expr/if/mut-borrow-in-else-if-after-if-let.rs diff --git a/tests/ui/issues/issue-38556.rs b/tests/ui/imports/macro-use-as.rs similarity index 100% rename from tests/ui/issues/issue-38556.rs rename to tests/ui/imports/macro-use-as.rs diff --git a/tests/ui/issues/issue-37884.rs b/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.rs similarity index 100% rename from tests/ui/issues/issue-37884.rs rename to tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.rs diff --git a/tests/ui/issues/issue-37884.stderr b/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.stderr similarity index 100% rename from tests/ui/issues/issue-37884.stderr rename to tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.stderr diff --git a/tests/ui/issues/issue-3702-2.rs b/tests/ui/methods/ambig-method-call-in-trait-impl.rs similarity index 100% rename from tests/ui/issues/issue-3702-2.rs rename to tests/ui/methods/ambig-method-call-in-trait-impl.rs diff --git a/tests/ui/issues/issue-3702-2.stderr b/tests/ui/methods/ambig-method-call-in-trait-impl.stderr similarity index 100% rename from tests/ui/issues/issue-3702-2.stderr rename to tests/ui/methods/ambig-method-call-in-trait-impl.stderr diff --git a/tests/ui/issues/issue-3847.rs b/tests/ui/parser/other-module-struct-match.rs similarity index 100% rename from tests/ui/issues/issue-3847.rs rename to tests/ui/parser/other-module-struct-match.rs diff --git a/tests/ui/issues/issue-3753.rs b/tests/ui/parser/pub-method-after-attribute.rs similarity index 100% rename from tests/ui/issues/issue-3753.rs rename to tests/ui/parser/pub-method-after-attribute.rs diff --git a/tests/ui/issues/issue-3702.rs b/tests/ui/traits/object/nested-trait-method-call.rs similarity index 100% rename from tests/ui/issues/issue-3702.rs rename to tests/ui/traits/object/nested-trait-method-call.rs diff --git a/tests/ui/issues/issue-37665.rs b/tests/ui/unpretty/mir-unpretty-type-error.rs similarity index 100% rename from tests/ui/issues/issue-37665.rs rename to tests/ui/unpretty/mir-unpretty-type-error.rs diff --git a/tests/ui/issues/issue-37665.stderr b/tests/ui/unpretty/mir-unpretty-type-error.stderr similarity index 100% rename from tests/ui/issues/issue-37665.stderr rename to tests/ui/unpretty/mir-unpretty-type-error.stderr From dd8996db14204ce70a6a016f211d51839afaace7 Mon Sep 17 00:00:00 2001 From: zedddie Date: Thu, 9 Jul 2026 23:34:43 +0200 Subject: [PATCH 04/71] bless batch --- tests/ui/crate-loading/missing-target-error.rs | 7 ++++--- .../if/mut-borrow-in-else-if-after-if-let.rs | 2 ++ tests/ui/imports/macro-use-as.rs | 3 +++ tests/ui/issues/issue-3779.rs | 8 -------- tests/ui/issues/issue-3779.stderr | 17 ----------------- .../iterator-next-extra-named-lifetime.rs | 2 ++ .../iterator-next-extra-named-lifetime.stderr | 4 ++-- .../methods/ambig-method-call-in-trait-impl.rs | 3 +++ .../ambig-method-call-in-trait-impl.stderr | 6 +++--- tests/ui/parser/other-module-struct-match.rs | 3 +++ tests/ui/parser/pub-method-after-attribute.rs | 5 ++--- .../traits/object/nested-trait-method-call.rs | 3 +++ tests/ui/unpretty/mir-unpretty-type-error.rs | 2 ++ .../ui/unpretty/mir-unpretty-type-error.stderr | 2 +- 14 files changed, 30 insertions(+), 37 deletions(-) delete mode 100644 tests/ui/issues/issue-3779.rs delete mode 100644 tests/ui/issues/issue-3779.stderr diff --git a/tests/ui/crate-loading/missing-target-error.rs b/tests/ui/crate-loading/missing-target-error.rs index 875495d08ed77..3a75d568d2c8e 100644 --- a/tests/ui/crate-loading/missing-target-error.rs +++ b/tests/ui/crate-loading/missing-target-error.rs @@ -1,8 +1,9 @@ -//~ ERROR can't find crate for `std` +//! Regression test for . +//! Tests that compiling for a target which is not installed will result in a helpful +//! error message. +//~^^^ ERROR can't find crate for `std` //~| NOTE target may not be installed //~| NOTE can't find crate -// Tests that compiling for a target which is not installed will result in a helpful -// error message. //@ compile-flags: --target=thumbv6m-none-eabi //@ ignore-arm diff --git a/tests/ui/expr/if/mut-borrow-in-else-if-after-if-let.rs b/tests/ui/expr/if/mut-borrow-in-else-if-after-if-let.rs index 62a90c5604bd9..7c95752f760c1 100644 --- a/tests/ui/expr/if/mut-borrow-in-else-if-after-if-let.rs +++ b/tests/ui/expr/if/mut-borrow-in-else-if-after-if-let.rs @@ -1,3 +1,5 @@ +//! Regression test for . +//! Test that else-if after if-let is not considered a pattern guard. //@ check-pass fn foo(_: &mut i32) -> bool { true } diff --git a/tests/ui/imports/macro-use-as.rs b/tests/ui/imports/macro-use-as.rs index b04558707e148..e26a831e74b57 100644 --- a/tests/ui/imports/macro-use-as.rs +++ b/tests/ui/imports/macro-use-as.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Reexport in macro caused ICE. //@ run-pass + #![allow(dead_code)] pub struct Foo; diff --git a/tests/ui/issues/issue-3779.rs b/tests/ui/issues/issue-3779.rs deleted file mode 100644 index 901c1be80ca06..0000000000000 --- a/tests/ui/issues/issue-3779.rs +++ /dev/null @@ -1,8 +0,0 @@ -struct S { - //~^ ERROR E0072 - element: Option -} - -fn main() { - let x = S { element: None }; -} diff --git a/tests/ui/issues/issue-3779.stderr b/tests/ui/issues/issue-3779.stderr deleted file mode 100644 index d4f4b79102d5e..0000000000000 --- a/tests/ui/issues/issue-3779.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0072]: recursive type `S` has infinite size - --> $DIR/issue-3779.rs:1:1 - | -LL | struct S { - | ^^^^^^^^ -LL | -LL | element: Option - | - recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle - | -LL | element: Option> - | ++++ + - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.rs b/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.rs index 3480942d9d282..11a1397c8ef09 100644 --- a/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.rs +++ b/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.rs @@ -1,3 +1,5 @@ +//! Regression test for . +//! This used to leak compiler data structures in error message. //@ dont-require-annotations: NOTE struct RepeatMut<'a, T>(T, &'a ()); diff --git a/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.stderr b/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.stderr index a7a19e3c6dfdc..c3e1ed6e2641e 100644 --- a/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.stderr +++ b/tests/ui/lifetimes/lifetime-errors/iterator-next-extra-named-lifetime.stderr @@ -1,5 +1,5 @@ error[E0308]: method not compatible with trait - --> $DIR/issue-37884.rs:8:5 + --> $DIR/iterator-next-extra-named-lifetime.rs:10:5 | LL | fn next(&'a mut self) -> Option | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch @@ -9,7 +9,7 @@ LL | fn next(&'a mut self) -> Option note: the anonymous lifetime as defined here... --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL note: ...does not necessarily outlive the lifetime `'a` as defined here - --> $DIR/issue-37884.rs:5:6 + --> $DIR/iterator-next-extra-named-lifetime.rs:7:6 | LL | impl<'a, T: 'a> Iterator for RepeatMut<'a, T> { | ^^ diff --git a/tests/ui/methods/ambig-method-call-in-trait-impl.rs b/tests/ui/methods/ambig-method-call-in-trait-impl.rs index d47f6d248f708..260ca0b546a3f 100644 --- a/tests/ui/methods/ambig-method-call-in-trait-impl.rs +++ b/tests/ui/methods/ambig-method-call-in-trait-impl.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! This used to trigger LLVM assertion. + pub trait ToPrimitive { fn to_int(&self) -> isize { 0 } } diff --git a/tests/ui/methods/ambig-method-call-in-trait-impl.stderr b/tests/ui/methods/ambig-method-call-in-trait-impl.stderr index 448263aafd44e..0482346d9a482 100644 --- a/tests/ui/methods/ambig-method-call-in-trait-impl.stderr +++ b/tests/ui/methods/ambig-method-call-in-trait-impl.stderr @@ -1,16 +1,16 @@ error[E0034]: multiple applicable items in scope - --> $DIR/issue-3702-2.rs:16:14 + --> $DIR/ambig-method-call-in-trait-impl.rs:19:14 | LL | self.to_int() + other.to_int() | ^^^^^^ multiple `to_int` found | note: candidate #1 is defined in an impl of the trait `Add` for the type `isize` - --> $DIR/issue-3702-2.rs:14:5 + --> $DIR/ambig-method-call-in-trait-impl.rs:17:5 | LL | fn to_int(&self) -> isize { *self } | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: candidate #2 is defined in an impl of the trait `ToPrimitive` for the type `isize` - --> $DIR/issue-3702-2.rs:2:5 + --> $DIR/ambig-method-call-in-trait-impl.rs:5:5 | LL | fn to_int(&self) -> isize { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/parser/other-module-struct-match.rs b/tests/ui/parser/other-module-struct-match.rs index 73aaab4183694..c9c7a9d52dbc1 100644 --- a/tests/ui/parser/other-module-struct-match.rs +++ b/tests/ui/parser/other-module-struct-match.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Pattern matching struct from different module caused parser to fail. //@ run-pass + mod buildings { pub struct Tower { pub height: usize } } diff --git a/tests/ui/parser/pub-method-after-attribute.rs b/tests/ui/parser/pub-method-after-attribute.rs index a243ceab83ebe..828fc52189b32 100644 --- a/tests/ui/parser/pub-method-after-attribute.rs +++ b/tests/ui/parser/pub-method-after-attribute.rs @@ -1,7 +1,6 @@ +//! Regression test for . +//! Pub keyword after attribute caused parser to fail. //@ run-pass -// Issue #3656 -// Issue Name: pub method preceded by attribute can't be parsed -// Abstract: Visibility parsing failed when compiler parsing use std::f64; diff --git a/tests/ui/traits/object/nested-trait-method-call.rs b/tests/ui/traits/object/nested-trait-method-call.rs index bb79e3a7f9384..c63671ba48a43 100644 --- a/tests/ui/traits/object/nested-trait-method-call.rs +++ b/tests/ui/traits/object/nested-trait-method-call.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Calling method of trait defined in function used to trigger LLVM assertion. //@ run-pass + #![allow(dead_code)] pub fn main() { diff --git a/tests/ui/unpretty/mir-unpretty-type-error.rs b/tests/ui/unpretty/mir-unpretty-type-error.rs index db74b1f025987..4b48a0126ac51 100644 --- a/tests/ui/unpretty/mir-unpretty-type-error.rs +++ b/tests/ui/unpretty/mir-unpretty-type-error.rs @@ -1,3 +1,5 @@ +//! Regression test for . +//! Test type error when compiling with `unpretty=mir` doesn't ICE. //@ compile-flags: -Z unpretty=mir use std::path::MAIN_SEPARATOR; diff --git a/tests/ui/unpretty/mir-unpretty-type-error.stderr b/tests/ui/unpretty/mir-unpretty-type-error.stderr index 2c404b4e74473..f0c19a23ed0e4 100644 --- a/tests/ui/unpretty/mir-unpretty-type-error.stderr +++ b/tests/ui/unpretty/mir-unpretty-type-error.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-37665.rs:9:17 + --> $DIR/mir-unpretty-type-error.rs:11:17 | LL | let x: () = 0; | -- ^ expected `()`, found integer From b1bddeba186921c7889d8343c184a551f334748a Mon Sep 17 00:00:00 2001 From: zedddie Date: Fri, 10 Jul 2026 23:23:01 +0200 Subject: [PATCH 05/71] move batch --- tests/ui/{issues/issue-3991.rs => borrowck/push-on-nested-vec.rs} | 0 .../repr-u64-enum-discriminant-cast.rs} | 0 .../issue-39827.rs => intrinsics/volatile-zst-intrinsics.rs} | 0 .../issue-39848.rs => macros/macro-adjacent-ident-on-token.rs} | 0 .../macro-adjacent-ident-on-token.stderr} | 0 .../issue-39709.rs => macros/macro-rules-def-in-block-expr.rs} | 0 tests/ui/{issues/issue-3895.rs => match/guard-arm-and-or-arm.rs} | 0 .../locally-pub-private-module-access.rs} | 0 .../locally-pub-private-module-access.stderr} | 0 .../default-method/nested-supertrait-method-in-default-body.rs} | 0 .../default-method/supertrait-method-in-default-body.rs} | 0 .../diverging-expr-unconstrained-type-param.rs} | 0 .../ui/{issues/issue-38954.rs => unsized/unsized-ref-fn-param.rs} | 0 .../issue-38954.stderr => unsized/unsized-ref-fn-param.stderr} | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-3991.rs => borrowck/push-on-nested-vec.rs} (100%) rename tests/ui/{issues/issue-38942.rs => enum-discriminant/repr-u64-enum-discriminant-cast.rs} (100%) rename tests/ui/{issues/issue-39827.rs => intrinsics/volatile-zst-intrinsics.rs} (100%) rename tests/ui/{issues/issue-39848.rs => macros/macro-adjacent-ident-on-token.rs} (100%) rename tests/ui/{issues/issue-39848.stderr => macros/macro-adjacent-ident-on-token.stderr} (100%) rename tests/ui/{issues/issue-39709.rs => macros/macro-rules-def-in-block-expr.rs} (100%) rename tests/ui/{issues/issue-3895.rs => match/guard-arm-and-or-arm.rs} (100%) rename tests/ui/{issues/issue-38857.rs => privacy/locally-pub-private-module-access.rs} (100%) rename tests/ui/{issues/issue-38857.stderr => privacy/locally-pub-private-module-access.stderr} (100%) rename tests/ui/{issues/issue-3979-2.rs => traits/default-method/nested-supertrait-method-in-default-body.rs} (100%) rename tests/ui/{issues/issue-3979.rs => traits/default-method/supertrait-method-in-default-body.rs} (100%) rename tests/ui/{issues/issue-39808.rs => type-inference/diverging-expr-unconstrained-type-param.rs} (100%) rename tests/ui/{issues/issue-38954.rs => unsized/unsized-ref-fn-param.rs} (100%) rename tests/ui/{issues/issue-38954.stderr => unsized/unsized-ref-fn-param.stderr} (100%) diff --git a/tests/ui/issues/issue-3991.rs b/tests/ui/borrowck/push-on-nested-vec.rs similarity index 100% rename from tests/ui/issues/issue-3991.rs rename to tests/ui/borrowck/push-on-nested-vec.rs diff --git a/tests/ui/issues/issue-38942.rs b/tests/ui/enum-discriminant/repr-u64-enum-discriminant-cast.rs similarity index 100% rename from tests/ui/issues/issue-38942.rs rename to tests/ui/enum-discriminant/repr-u64-enum-discriminant-cast.rs diff --git a/tests/ui/issues/issue-39827.rs b/tests/ui/intrinsics/volatile-zst-intrinsics.rs similarity index 100% rename from tests/ui/issues/issue-39827.rs rename to tests/ui/intrinsics/volatile-zst-intrinsics.rs diff --git a/tests/ui/issues/issue-39848.rs b/tests/ui/macros/macro-adjacent-ident-on-token.rs similarity index 100% rename from tests/ui/issues/issue-39848.rs rename to tests/ui/macros/macro-adjacent-ident-on-token.rs diff --git a/tests/ui/issues/issue-39848.stderr b/tests/ui/macros/macro-adjacent-ident-on-token.stderr similarity index 100% rename from tests/ui/issues/issue-39848.stderr rename to tests/ui/macros/macro-adjacent-ident-on-token.stderr diff --git a/tests/ui/issues/issue-39709.rs b/tests/ui/macros/macro-rules-def-in-block-expr.rs similarity index 100% rename from tests/ui/issues/issue-39709.rs rename to tests/ui/macros/macro-rules-def-in-block-expr.rs diff --git a/tests/ui/issues/issue-3895.rs b/tests/ui/match/guard-arm-and-or-arm.rs similarity index 100% rename from tests/ui/issues/issue-3895.rs rename to tests/ui/match/guard-arm-and-or-arm.rs diff --git a/tests/ui/issues/issue-38857.rs b/tests/ui/privacy/locally-pub-private-module-access.rs similarity index 100% rename from tests/ui/issues/issue-38857.rs rename to tests/ui/privacy/locally-pub-private-module-access.rs diff --git a/tests/ui/issues/issue-38857.stderr b/tests/ui/privacy/locally-pub-private-module-access.stderr similarity index 100% rename from tests/ui/issues/issue-38857.stderr rename to tests/ui/privacy/locally-pub-private-module-access.stderr diff --git a/tests/ui/issues/issue-3979-2.rs b/tests/ui/traits/default-method/nested-supertrait-method-in-default-body.rs similarity index 100% rename from tests/ui/issues/issue-3979-2.rs rename to tests/ui/traits/default-method/nested-supertrait-method-in-default-body.rs diff --git a/tests/ui/issues/issue-3979.rs b/tests/ui/traits/default-method/supertrait-method-in-default-body.rs similarity index 100% rename from tests/ui/issues/issue-3979.rs rename to tests/ui/traits/default-method/supertrait-method-in-default-body.rs diff --git a/tests/ui/issues/issue-39808.rs b/tests/ui/type-inference/diverging-expr-unconstrained-type-param.rs similarity index 100% rename from tests/ui/issues/issue-39808.rs rename to tests/ui/type-inference/diverging-expr-unconstrained-type-param.rs diff --git a/tests/ui/issues/issue-38954.rs b/tests/ui/unsized/unsized-ref-fn-param.rs similarity index 100% rename from tests/ui/issues/issue-38954.rs rename to tests/ui/unsized/unsized-ref-fn-param.rs diff --git a/tests/ui/issues/issue-38954.stderr b/tests/ui/unsized/unsized-ref-fn-param.stderr similarity index 100% rename from tests/ui/issues/issue-38954.stderr rename to tests/ui/unsized/unsized-ref-fn-param.stderr From b23c2ee07c39fd4a7e5bbc99604d0d05dcd31c6d Mon Sep 17 00:00:00 2001 From: zedddie Date: Fri, 10 Jul 2026 23:23:28 +0200 Subject: [PATCH 06/71] bless batch --- tests/ui/borrowck/push-on-nested-vec.rs | 4 +++- .../repr-u64-enum-discriminant-cast.rs | 3 ++- tests/ui/intrinsics/volatile-zst-intrinsics.rs | 10 +++++----- tests/ui/macros/macro-adjacent-ident-on-token.rs | 3 +++ tests/ui/macros/macro-adjacent-ident-on-token.stderr | 4 ++-- tests/ui/macros/macro-rules-def-in-block-expr.rs | 3 +++ tests/ui/match/guard-arm-and-or-arm.rs | 3 +++ tests/ui/privacy/locally-pub-private-module-access.rs | 3 +++ .../privacy/locally-pub-private-module-access.stderr | 4 ++-- .../nested-supertrait-method-in-default-body.rs | 2 ++ .../supertrait-method-in-default-body.rs | 3 +++ .../diverging-expr-unconstrained-type-param.rs | 10 +++++----- tests/ui/unsized/unsized-ref-fn-param.rs | 3 +++ tests/ui/unsized/unsized-ref-fn-param.stderr | 2 +- 14 files changed, 40 insertions(+), 17 deletions(-) diff --git a/tests/ui/borrowck/push-on-nested-vec.rs b/tests/ui/borrowck/push-on-nested-vec.rs index e69c693ed49ea..bbab952e85355 100644 --- a/tests/ui/borrowck/push-on-nested-vec.rs +++ b/tests/ui/borrowck/push-on-nested-vec.rs @@ -1,6 +1,8 @@ +//! Regression test for . +//! Test borrowck doesn't complain on nested vector mutable reference. //@ check-pass -#![allow(dead_code)] +#![allow(dead_code)] struct HasNested { nest: Vec > , diff --git a/tests/ui/enum-discriminant/repr-u64-enum-discriminant-cast.rs b/tests/ui/enum-discriminant/repr-u64-enum-discriminant-cast.rs index 3f80beb53f357..c9f6d6a65ea35 100644 --- a/tests/ui/enum-discriminant/repr-u64-enum-discriminant-cast.rs +++ b/tests/ui/enum-discriminant/repr-u64-enum-discriminant-cast.rs @@ -1,5 +1,6 @@ +//! Regression test for . +//! This used to ICE when compiling for `i686-apple-darwin`. //@ run-pass -// See https://github.com/rust-lang/rust/issues/38942 #[repr(u64)] pub enum NSEventType { diff --git a/tests/ui/intrinsics/volatile-zst-intrinsics.rs b/tests/ui/intrinsics/volatile-zst-intrinsics.rs index e3248c9e9ac72..0927442268d1f 100644 --- a/tests/ui/intrinsics/volatile-zst-intrinsics.rs +++ b/tests/ui/intrinsics/volatile-zst-intrinsics.rs @@ -1,3 +1,8 @@ +//! Regression test for . +//! This test ensures that volatile intrinsics can be specialised with +//! zero-sized types and, in case of copy/set functions, can accept +//! number of elements equal to zero. + //@ run-pass #![feature(core_intrinsics)] @@ -5,11 +10,6 @@ use std::intrinsics::{ volatile_copy_memory, volatile_store, volatile_load, volatile_copy_nonoverlapping_memory, volatile_set_memory }; -// -// This test ensures that volatile intrinsics can be specialised with -// zero-sized types and, in case of copy/set functions, can accept -// number of elements equal to zero. -// fn main () { let mut dst_pair = (1, 2); let src_pair = (3, 4); diff --git a/tests/ui/macros/macro-adjacent-ident-on-token.rs b/tests/ui/macros/macro-adjacent-ident-on-token.rs index 2a059120e8175..5e57f427724aa 100644 --- a/tests/ui/macros/macro-adjacent-ident-on-token.rs +++ b/tests/ui/macros/macro-adjacent-ident-on-token.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! This used to ice on `IllFormedSpan`. + macro_rules! get_opt { ($tgt:expr, $field:ident) => { if $tgt.has_$field() {} //~ ERROR expected `{`, found identifier `foo` diff --git a/tests/ui/macros/macro-adjacent-ident-on-token.stderr b/tests/ui/macros/macro-adjacent-ident-on-token.stderr index 1ffed2d4a1da1..b13a3d45828d3 100644 --- a/tests/ui/macros/macro-adjacent-ident-on-token.stderr +++ b/tests/ui/macros/macro-adjacent-ident-on-token.stderr @@ -1,5 +1,5 @@ error: expected `{`, found identifier `foo` - --> $DIR/issue-39848.rs:3:21 + --> $DIR/macro-adjacent-ident-on-token.rs:6:21 | LL | if $tgt.has_$field() {} | ^^^^^^ expected `{` @@ -8,7 +8,7 @@ LL | get_opt!(bar, foo); | ------------------ in this macro invocation | note: the `if` expression is missing a block after this condition - --> $DIR/issue-39848.rs:3:12 + --> $DIR/macro-adjacent-ident-on-token.rs:6:12 | LL | if $tgt.has_$field() {} | ^^^^^^^^^ diff --git a/tests/ui/macros/macro-rules-def-in-block-expr.rs b/tests/ui/macros/macro-rules-def-in-block-expr.rs index df3286721f51f..4074c6c9cac1e 100644 --- a/tests/ui/macros/macro-rules-def-in-block-expr.rs +++ b/tests/ui/macros/macro-rules-def-in-block-expr.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Macro definition inside block expression caused ICE. //@ run-pass + #![allow(unused_macros)] fn main() { println!("{}", { macro_rules! x { ($(t:tt)*) => {} } 33 }); diff --git a/tests/ui/match/guard-arm-and-or-arm.rs b/tests/ui/match/guard-arm-and-or-arm.rs index 6bd173d48785b..0296ee0d3cc3c 100644 --- a/tests/ui/match/guard-arm-and-or-arm.rs +++ b/tests/ui/match/guard-arm-and-or-arm.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Match with guard arm and or pattern used to ICE. //@ run-pass + #![allow(dead_code)] pub fn main() { diff --git a/tests/ui/privacy/locally-pub-private-module-access.rs b/tests/ui/privacy/locally-pub-private-module-access.rs index 63a0af759a3de..7939219b6a999 100644 --- a/tests/ui/privacy/locally-pub-private-module-access.rs +++ b/tests/ui/privacy/locally-pub-private-module-access.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Trying to access locally pub but inaccessible items caused ICE. + fn main() { let a = std::sys::imp::process::process_common::StdioPipes { ..panic!() }; //~^ ERROR: cannot find `imp` in `sys` [E0433] diff --git a/tests/ui/privacy/locally-pub-private-module-access.stderr b/tests/ui/privacy/locally-pub-private-module-access.stderr index 85a0c266ac657..5f69f1a660923 100644 --- a/tests/ui/privacy/locally-pub-private-module-access.stderr +++ b/tests/ui/privacy/locally-pub-private-module-access.stderr @@ -1,11 +1,11 @@ error[E0433]: cannot find `imp` in `sys` - --> $DIR/issue-38857.rs:2:23 + --> $DIR/locally-pub-private-module-access.rs:5:23 | LL | let a = std::sys::imp::process::process_common::StdioPipes { ..panic!() }; | ^^^ could not find `imp` in `sys` error[E0603]: module `sys` is private - --> $DIR/issue-38857.rs:2:18 + --> $DIR/locally-pub-private-module-access.rs:5:18 | LL | let a = std::sys::imp::process::process_common::StdioPipes { ..panic!() }; | ^^^ private module diff --git a/tests/ui/traits/default-method/nested-supertrait-method-in-default-body.rs b/tests/ui/traits/default-method/nested-supertrait-method-in-default-body.rs index 98b6e85225db5..5516b58e57624 100644 --- a/tests/ui/traits/default-method/nested-supertrait-method-in-default-body.rs +++ b/tests/ui/traits/default-method/nested-supertrait-method-in-default-body.rs @@ -1,3 +1,5 @@ +//! Regression test for . +//! Test calling nested supertrait's method in default method body works. //@ check-pass trait A { diff --git a/tests/ui/traits/default-method/supertrait-method-in-default-body.rs b/tests/ui/traits/default-method/supertrait-method-in-default-body.rs index 238df225f0f34..597ff6375c7a2 100644 --- a/tests/ui/traits/default-method/supertrait-method-in-default-body.rs +++ b/tests/ui/traits/default-method/supertrait-method-in-default-body.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Test calling supertrait's method in default method body works. //@ run-pass + #![allow(dead_code)] #![allow(non_snake_case)] diff --git a/tests/ui/type-inference/diverging-expr-unconstrained-type-param.rs b/tests/ui/type-inference/diverging-expr-unconstrained-type-param.rs index 99e3d9b4bcdfd..1e523dcc66ea0 100644 --- a/tests/ui/type-inference/diverging-expr-unconstrained-type-param.rs +++ b/tests/ui/type-inference/diverging-expr-unconstrained-type-param.rs @@ -1,10 +1,10 @@ +//! Regression test for . +//! The type parameter of `Owned` was considered to be "unconstrained" +//! because the type resulting from `format!` (`String`) was not being +//! propagated upward, owing to the fact that the expression diverges. //@ run-pass -#![allow(unreachable_code)] -// Regression test for #39808. The type parameter of `Owned` was -// considered to be "unconstrained" because the type resulting from -// `format!` (`String`) was not being propagated upward, owing to the -// fact that the expression diverges. +#![allow(unreachable_code)] use std::borrow::Cow; diff --git a/tests/ui/unsized/unsized-ref-fn-param.rs b/tests/ui/unsized/unsized-ref-fn-param.rs index 61df411b1f92b..9a36e82b049fe 100644 --- a/tests/ui/unsized/unsized-ref-fn-param.rs +++ b/tests/ui/unsized/unsized-ref-fn-param.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Test we emit helpful error message instead of silently failing. + fn _test(ref _p: str) {} //~^ ERROR the size for values of type diff --git a/tests/ui/unsized/unsized-ref-fn-param.stderr b/tests/ui/unsized/unsized-ref-fn-param.stderr index bd9c5e4197bc7..3fa5758d2083a 100644 --- a/tests/ui/unsized/unsized-ref-fn-param.stderr +++ b/tests/ui/unsized/unsized-ref-fn-param.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/issue-38954.rs:1:18 + --> $DIR/unsized-ref-fn-param.rs:4:18 | LL | fn _test(ref _p: str) {} | ^^^ doesn't have a size known at compile-time From c703f8a4e8449fafe610d1e55493f8d7db0faf1f Mon Sep 17 00:00:00 2001 From: Xuyang Zhang Date: Sat, 11 Jul 2026 23:38:43 +0800 Subject: [PATCH 07/71] doc: document wasm import symbol mangling --- src/doc/rustc/src/symbol-mangling/index.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/symbol-mangling/index.md b/src/doc/rustc/src/symbol-mangling/index.md index 3f7d55063ca6a..f1f242698602a 100644 --- a/src/doc/rustc/src/symbol-mangling/index.md +++ b/src/doc/rustc/src/symbol-mangling/index.md @@ -17,13 +17,18 @@ The [`#[export_name]`attribute][reference-export_name] can be used to specify th Items listed in an [`extern` block][reference-extern-block] use the identifier of the item without mangling to refer to the item. The [`#[link_name]` attribute][reference-link_name] can be used to change that name. - +### WebAssembly import modules + +On WebAssembly targets, foreign items in an `extern` block using +[`#[link(wasm_import_module = "...")]`][reference-link-attribute] are mangled even if +`#[no_mangle]` or `#[link_name]` is used. This distinguishes imports with the same name from +different WebAssembly modules. The requested module and import name are emitted separately in +the WebAssembly import metadata. [reference-no_mangle]: ../../reference/abi.html#the-no_mangle-attribute [reference-export_name]: ../../reference/abi.html#the-export_name-attribute [reference-link_name]: ../../reference/items/external-blocks.html#the-link_name-attribute +[reference-link-attribute]: ../../reference/items/external-blocks.html#the-link-attribute [reference-extern-block]: ../../reference/items/external-blocks.html ## Decoding From c100acadff82a6fea8660e6a9bbaf64f4d0768fa Mon Sep 17 00:00:00 2001 From: Xuyang Zhang Date: Mon, 13 Jul 2026 18:26:11 +0800 Subject: [PATCH 08/71] doc: clarify wasm import symbol mangling --- src/doc/rustc/src/symbol-mangling/index.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc/src/symbol-mangling/index.md b/src/doc/rustc/src/symbol-mangling/index.md index f1f242698602a..3bb3937f9c16e 100644 --- a/src/doc/rustc/src/symbol-mangling/index.md +++ b/src/doc/rustc/src/symbol-mangling/index.md @@ -19,11 +19,14 @@ The [`#[link_name]` attribute][reference-link_name] can be used to change that n ### WebAssembly import modules -On WebAssembly targets, foreign items in an `extern` block using -[`#[link(wasm_import_module = "...")]`][reference-link-attribute] are mangled even if -`#[no_mangle]` or `#[link_name]` is used. This distinguishes imports with the same name from -different WebAssembly modules. The requested module and import name are emitted separately in -the WebAssembly import metadata. +On WebAssembly targets, rustc currently mangles foreign items in an `extern` block using +[`#[link(wasm_import_module = "...")]`][reference-link-attribute], even if `#[no_mangle]` or +`#[link_name]` is used. + +This is an implementation detail of the current WebAssembly code generation and linking setup, +and may change. It avoids current linker and code generation behavior that can conflate +same-named imports from different WebAssembly modules. The requested module and import name are +emitted as the `wasm-import-module` and `wasm-import-name` LLVM attributes. [reference-no_mangle]: ../../reference/abi.html#the-no_mangle-attribute [reference-export_name]: ../../reference/abi.html#the-export_name-attribute From f2663375c0163972e8009725eb348a089d514e0d Mon Sep 17 00:00:00 2001 From: Xuyang Zhang Date: Mon, 13 Jul 2026 20:52:14 +0800 Subject: [PATCH 09/71] doc: describe wasm import conflict behavior --- src/doc/rustc/src/symbol-mangling/index.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/doc/rustc/src/symbol-mangling/index.md b/src/doc/rustc/src/symbol-mangling/index.md index 3bb3937f9c16e..67df4f0a9b07f 100644 --- a/src/doc/rustc/src/symbol-mangling/index.md +++ b/src/doc/rustc/src/symbol-mangling/index.md @@ -19,14 +19,9 @@ The [`#[link_name]` attribute][reference-link_name] can be used to change that n ### WebAssembly import modules -On WebAssembly targets, rustc currently mangles foreign items in an `extern` block using -[`#[link(wasm_import_module = "...")]`][reference-link-attribute], even if `#[no_mangle]` or -`#[link_name]` is used. - -This is an implementation detail of the current WebAssembly code generation and linking setup, -and may change. It avoids current linker and code generation behavior that can conflate -same-named imports from different WebAssembly modules. The requested module and import name are -emitted as the `wasm-import-module` and `wasm-import-name` LLVM attributes. +On WebAssembly targets, foreign items in `extern` blocks can use the same import name without +conflicting when they use different [`#[link(wasm_import_module = "...")]`][reference-link-attribute] +values. [reference-no_mangle]: ../../reference/abi.html#the-no_mangle-attribute [reference-export_name]: ../../reference/abi.html#the-export_name-attribute From 032d95925f7f1f8cb28be62e67d669c2d293910d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 15 Jul 2026 08:10:46 +0200 Subject: [PATCH 10/71] ensure to check that the overview is current --- src/doc/rustc-dev-guide/src/about-this-guide.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index 56fbc1f6b7a85..b716bd7184dee 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -1,5 +1,7 @@ # About this guide + + This guide is meant to help document how rustc – the Rust compiler – works, as well as to help new contributors get involved in rustc development. From a61a054a1781b7681fe7155c570a33efb2fa65a5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 15 Jul 2026 08:12:52 +0200 Subject: [PATCH 11/71] use sentence case for titles --- src/doc/rustc-dev-guide/src/SUMMARY.md | 6 +++--- src/doc/rustc-dev-guide/src/about-this-guide.md | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index bf2de84575d69..b01afcaf78496 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -86,7 +86,7 @@ - [Debugging bootstrap](./building/bootstrapping/debugging-bootstrap.md) - [cfg(bootstrap) in dependencies](./building/bootstrapping/bootstrap-in-dependencies.md) -# High-level Compiler Architecture +# High-level compiler architecture - [Prologue](./part-2-intro.md) - [Overview of the compiler](./overview.md) @@ -115,7 +115,7 @@ - [Autodiff flags](./autodiff/flags.md) - [Type Trees](./autodiff/type-trees.md) -# Source Code Representation +# Source code representation - [Prologue](./part-3-intro.md) - [Syntax and the AST](./syntax-intro.md) @@ -140,7 +140,7 @@ - [MIR queries and passes: getting the MIR](./mir/passes.md) - [Inline assembly](./asm.md) -# Supporting Infrastructure +# Supporting infrastructure - [Command-line arguments](./cli.md) - [rustc_driver and rustc_interface](./rustc-driver/intro.md) diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index b716bd7184dee..6282a66e13b07 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -16,18 +16,18 @@ There are several parts to this guide: 1. [Bootstrapping][p3]: Describes how the Rust compiler builds itself using previous versions, including an introduction to the bootstrap process and debugging methods. -1. [High-level Compiler Architecture][p4]: +1. [High-level compiler architecture][p4]: Discusses the high-level architecture of the compiler and stages of the compile process. -1. [Source Code Representation][p5]: +1. [Source code representation][p5]: Describes the process of taking raw source code from the user and transforming it into various forms that the compiler can work with easily. -1. [Supporting Infrastructure][p6]: +1. [Supporting infrastructure][p6]: Covers command-line argument conventions, compiler entry points like rustc_driver and rustc_interface, and the design and implementation of errors and lints. 1. [Analysis][p7]: Discusses the analyses that the compiler uses to check various properties of the code and inform later stages of the compile process (e.g., type checking). -1. [MIR to Binaries][p8]: How linked executable machine code is generated. +1. [Mir to binaries][p8]: How linked executable machine code is generated. 1. [Appendices][p9] at the end with useful reference information. There are a few of these with different information, including a glossary. From 821701a993edfac79bc29c0be76660bcc0d372b0 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Wed, 15 Jul 2026 16:46:52 +0800 Subject: [PATCH 12/71] fix rustup update command for autodiff --- src/doc/rustc-dev-guide/src/autodiff/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index c0da9621f9777..acbb7c9eb09f3 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -20,7 +20,7 @@ rustup +nightly component add enzyme Older rustup versions are not aware of this component, so if you run into issues try updating rustup itself: ```console -rustup update +rustup self update rustup +nightly component add enzyme ``` From 905a7e08b83e9d28d27e6336cfe05694a30ab22c Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Thu, 16 Jul 2026 10:56:16 -0300 Subject: [PATCH 13/71] Track placeholder assumptions for created universes --- .../src/canonical/mod.rs | 8 ++++++- .../src/placeholder.rs | 24 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index b2f6ac78040b6..0b98f312481da 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -160,7 +160,13 @@ where let prev_universe = delegate.universe(); let universes_created_in_query = response.max_universe.index(); for _ in 0..universes_created_in_query { - delegate.create_next_universe(); + let new_universe = delegate.create_next_universe(); + if delegate.cx().assumptions_on_binders() { + delegate.insert_placeholder_assumptions( + new_universe, + Some(rustc_type_ir::region_constraint::Assumptions::empty()), + ); + } } let var_values = response.value.var_values(); diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs index b5bb488c43b89..cc463304c5152 100644 --- a/compiler/rustc_next_trait_solver/src/placeholder.rs +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -47,6 +47,7 @@ where IndexMap, ty::BoundTy>, IndexMap, ty::BoundConst>, ) { + let old_universes = universe_indices.clone(); let mut replacer = BoundVarReplacer { infcx, mapped_regions: Default::default(), @@ -57,8 +58,29 @@ where }; let value = value.fold_with(&mut replacer); + let BoundVarReplacer { + mapped_regions, + mapped_types, + mapped_consts, + universe_indices, + infcx: _, + current_index: _, + } = replacer; + + if infcx.cx().assumptions_on_binders() { + for (old, new) in old_universes.into_iter().zip(universe_indices.iter()) { + if let (None, Some(new)) = (old, new) { + // FIXME(-Zassumptions-on-binders): `replace_bound_vars` does not have enough + // context to compute placeholder assumptions for the binders it enters. + infcx.insert_placeholder_assumptions( + *new, + Some(rustc_type_ir::region_constraint::Assumptions::empty()), + ); + } + } + } - (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts) + (value, mapped_regions, mapped_types, mapped_consts) } fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { From 8211f9061397ec204877641153254f5ac8406002 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Thu, 16 Jul 2026 10:56:31 -0300 Subject: [PATCH 14/71] Add coverage for placeholder assumption ICE --- .../placeholder-assumptions-issue-157840.rs | 17 +++++++++++++++++ .../placeholder-assumptions-issue-157840.stderr | 14 ++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/ui/assumptions_on_binders/placeholder-assumptions-issue-157840.rs create mode 100644 tests/ui/assumptions_on_binders/placeholder-assumptions-issue-157840.stderr diff --git a/tests/ui/assumptions_on_binders/placeholder-assumptions-issue-157840.rs b/tests/ui/assumptions_on_binders/placeholder-assumptions-issue-157840.rs new file mode 100644 index 0000000000000..74f0618e4291f --- /dev/null +++ b/tests/ui/assumptions_on_binders/placeholder-assumptions-issue-157840.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Znext-solver=globally -Zassumptions-on-binders + +trait Trait {} + +trait Proj<'a> { + type Assoc; +} + +fn foo<'a, T>() +where + T: Proj<'a, Assoc = fn(::Assoc)>, + (): Trait<>::Assoc>, + //~^ ERROR the trait bound `(): Trait fn(>::Assoc))>` is not satisfied +{ +} + +fn main() {} diff --git a/tests/ui/assumptions_on_binders/placeholder-assumptions-issue-157840.stderr b/tests/ui/assumptions_on_binders/placeholder-assumptions-issue-157840.stderr new file mode 100644 index 0000000000000..5e8e131addd28 --- /dev/null +++ b/tests/ui/assumptions_on_binders/placeholder-assumptions-issue-157840.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `(): Trait fn(>::Assoc))>` is not satisfied + --> $DIR/placeholder-assumptions-issue-157840.rs:12:9 + | +LL | (): Trait<>::Assoc>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait fn(>::Assoc))>` is not implemented for `()` + | +help: consider extending the `where` clause, but there might be an alternative better way to express this requirement + | +LL | (): Trait<>::Assoc>, (): Trait fn(>::Assoc))> + | +++++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 4f1921c367350d7f328667bcb79468173a56aee7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 16 Jul 2026 18:01:35 +0200 Subject: [PATCH 15/71] use sentence case for titles --- src/doc/rustc-dev-guide/src/SUMMARY.md | 6 +++--- src/doc/rustc-dev-guide/src/const-generics.md | 10 +++++----- src/doc/rustc-dev-guide/src/normalization.md | 12 ++++++------ src/doc/rustc-dev-guide/src/typing-parameter-envs.md | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index b01afcaf78496..91bb143eb318f 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -167,8 +167,8 @@ - [ADTs and Generic Arguments](./ty-module/generic-arguments.md) - [Parameter types/consts/regions](./ty-module/param-ty-const-regions.md) - [`TypeFolder` and `TypeFoldable`](./ty-fold.md) -- [Aliases and Normalization](./normalization.md) -- [Typing/Param Envs](./typing-parameter-envs.md) +- [Aliases and normalization](./normalization.md) +- [Typing/Param envs](./typing-parameter-envs.md) - [Type inference](./type-inference.md) - [Trait solving](./traits/resolution.md) - [Higher-ranked trait bounds](./traits/hrtb.md) @@ -199,7 +199,7 @@ - [HIR Type checking](./hir-typeck/summary.md) - [Coercions](./hir-typeck/coercions.md) - [Method lookup](./hir-typeck/method-lookup.md) -- [Const Generics](./const-generics.md) +- [Const generics](./const-generics.md) - [Opaque types](./opaque-types-type-alias-impl-trait.md) - [Inference details](./opaque-types-impl-trait-inference.md) - [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index 3f84b99fb637e..8e1a46a14f151 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -1,4 +1,4 @@ -# Const Generics +# Const generics ## Kinds of const arguments @@ -15,9 +15,9 @@ Inference Variables are quite boring and treated equivalently to type inference Const Parameters are also similarly boring and equivalent to uses of type parameters almost everywhere. However, there are some interesting subtleties with how they are handled during parsing, name resolution, and AST lowering: [ambig-unambig-ty-and-consts]. -## Anon Consts +## Anon consts -Anon Consts (short for anonymous const items) are how arbitrary expression are represented in const generics, for example an array length of `1 + 1` or `foo()` or even just `0`. +Anon consts (short for anonymous const items) are how arbitrary expression are represented in const generics, for example an array length of `1 + 1` or `foo()` or even just `0`. These are unique to const generics and have no real type equivalent. ### Desugaring @@ -85,7 +85,7 @@ After all of this desugaring has taken place the final representation in the typ 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 +### Enforcing lack of generic parameters There are three ways that we enforce anon consts can't use generic parameters: 1. Name Resolution will not resolve paths to generic parameters when inside of an anon const @@ -182,7 +182,7 @@ It is currently unclear what the right way to make `generic_const_parameter_type `min_generic_const_args` will allow for some expressions (for example array construction) to be representable without an anon const and therefore without running into these issues, though whether this is *enough* has yet to be determined. -## Checking types of Const Arguments +## Checking types of const arguments In order for a const argument to be well formed it must have the same type as the const parameter it is an argument to. For example, a const argument of type `bool` for an array length is not well formed, as an array's length parameter has type `usize`. diff --git a/src/doc/rustc-dev-guide/src/normalization.md b/src/doc/rustc-dev-guide/src/normalization.md index 6e98ff8f4b8a3..8c7500cb754b9 100644 --- a/src/doc/rustc-dev-guide/src/normalization.md +++ b/src/doc/rustc-dev-guide/src/normalization.md @@ -1,4 +1,4 @@ -# Aliases and Normalization +# Aliases and normalization ## Aliases @@ -17,7 +17,7 @@ so this chapter mostly discusses things in the context of types (even though the [`TyKind::Alias`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/enum.TyKind.html#variant.Alias [`AliasTyKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/enum.AliasTyKind.html -### Rigid, Ambiguous and Unnormalized Aliases +### Rigid, ambiguous and unnormalized aliases Aliases can either be "rigid", "ambiguous", or simply unnormalized. @@ -68,7 +68,7 @@ only it just hasn't been done yet. It is worth noting that Free and Inherent aliases cannot be rigid or ambiguous as naming them also implies having resolved the definition of the alias, which specifies the underlying type of the alias. -### Diverging Aliases +### Diverging aliases An alias is considered to "diverge" if its definition does not specify an underlying non-alias type to normalize to. A concrete example of diverging aliases: @@ -126,11 +126,11 @@ fn main() { In this example, we only encounter an error from the diverging alias during codegen of `foo::<()>`. If the call to `foo` is removed, then no compilation error will be emitted. -### Opaque Types +### Opaque types Opaque types are a relatively special kind of alias, and are covered in [their own chapter](opaque-types-type-alias-impl-trait.md). -### Const Aliases +### Const aliases Unlike type aliases, const aliases are not represented directly in the type system. Instead, const aliases are always an anonymous body containing a path expression to a const item. @@ -157,7 +157,7 @@ fn bar() { This is likely to change as const generics functionality is improved. For example, `feature(associated_const_equality)` and `feature(min_generic_const_args)` both require handling const aliases similarly to types (without an anonymous constant wrapping all const args). -## What is Normalization +## What is normalization ### Structural vs deep normalization diff --git a/src/doc/rustc-dev-guide/src/typing-parameter-envs.md b/src/doc/rustc-dev-guide/src/typing-parameter-envs.md index 45635ebfa15d6..db9f369d2659e 100644 --- a/src/doc/rustc-dev-guide/src/typing-parameter-envs.md +++ b/src/doc/rustc-dev-guide/src/typing-parameter-envs.md @@ -1,6 +1,6 @@ -# Typing/Parameter Environments +# Typing/Parameter environments -## Typing Environments +## Typing environments When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively). @@ -14,7 +14,7 @@ whereas different `ParamEnv`s can be used on a per-goal basis. [ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html [fnctxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html -## Parameter Environments +## Parameter environments ### What is a `ParamEnv` @@ -197,7 +197,7 @@ impl Other for T { // `foo`'s unnormalized `ParamEnv` would be: // `[T: Sized, U: Sized, U: Trait]` -fn foo(a: U) +fn foo(a: U) where U: Trait<::Bar>, { @@ -222,7 +222,7 @@ In the next-gen trait solver the requirement for all where clauses in the `Param [pe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html [normalize_env_or_error]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/fn.normalize_param_env_or_error.html -## Typing Modes +## Typing modes Depending on what context we are performing type system operations in, different behaviour may be required. From 1a180c01fbeb1ef72de0c023752f4313aed04d22 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 16 Jul 2026 18:03:20 +0200 Subject: [PATCH 16/71] reflow --- src/doc/rustc-dev-guide/src/const-generics.md | 4 +++- 1 file changed, 3 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 8e1a46a14f151..9e26a174d8cf6 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -134,7 +134,9 @@ fn foo() { } ``` -However, to avoid most of the problems involved in allowing generic parameters in anon const const arguments we require that the constant be evaluated before monomorphization (e.g. during type checking). In some sense we only allow generic parameters here when they are semantically unused. +However, to avoid most of the problems involved in allowing generic parameters in anon const const arguments, +we require that the constant be evaluated before monomorphization (e.g. during type checking). +In some sense we only allow generic parameters here when they are semantically unused. In the previous example the anon const can be evaluated for any type parameter `T` because raw pointers to sized types always have the same size (e.g. `8` on 64bit platforms). From 74c230edd24e3507d7a7212ef91b54e6e1c3457b Mon Sep 17 00:00:00 2001 From: sgasho Date: Fri, 10 Jul 2026 11:00:59 +0000 Subject: [PATCH 17/71] ci: Enable autodiff tests on x86_64 linux * Enable autodiff tests on x86_64 linux * move autodiff job def * remove redundant ./x build --- .../optional-x86_64-gnu-autodiff/Dockerfile | 37 +++++++++++++++++++ src/ci/docker/scripts/autodiff.sh | 9 +++++ src/ci/github-actions/jobs.yml | 4 ++ 3 files changed, 50 insertions(+) create mode 100644 src/ci/docker/host-x86_64/optional-x86_64-gnu-autodiff/Dockerfile create mode 100755 src/ci/docker/scripts/autodiff.sh diff --git a/src/ci/docker/host-x86_64/optional-x86_64-gnu-autodiff/Dockerfile b/src/ci/docker/host-x86_64/optional-x86_64-gnu-autodiff/Dockerfile new file mode 100644 index 0000000000000..f4633f951c645 --- /dev/null +++ b/src/ci/docker/host-x86_64/optional-x86_64-gnu-autodiff/Dockerfile @@ -0,0 +1,37 @@ +FROM ubuntu:24.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + pkg-config \ + xz-utils \ + zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +COPY scripts/autodiff.sh /scripts/ + +ENV NO_DOWNLOAD_CI_LLVM 1 +ENV CODEGEN_BACKENDS llvm + +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --enable-llvm-enzyme \ + --enable-llvm-link-shared \ + --enable-ninja \ + --enable-option-checking \ + --disable-docs \ + --set llvm.download-ci-llvm=false + +ENV SCRIPT /scripts/autodiff.sh diff --git a/src/ci/docker/scripts/autodiff.sh b/src/ci/docker/scripts/autodiff.sh new file mode 100755 index 0000000000000..90b36078faccd --- /dev/null +++ b/src/ci/docker/scripts/autodiff.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -ex + +../x.py test --stage 2 --no-fail-fast \ + tests/codegen-llvm/autodiff \ + tests/pretty/autodiff \ + tests/ui/autodiff \ + tests/ui/feature-gates/feature-gate-autodiff.rs diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index a8eebe7599fda..a6b23fe516c89 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -469,6 +469,10 @@ auto: - name: x86_64-gnu-miri <<: *job-linux-4c + - name: optional-x86_64-gnu-autodiff + continue_on_error: true + <<: *job-linux-4c + #################### # macOS Builders # #################### From 377748d2835bfa5413baa2e52bd8e42fc2358b5d Mon Sep 17 00:00:00 2001 From: zedddie Date: Sat, 18 Jul 2026 01:14:40 +0200 Subject: [PATCH 18/71] move batch --- .../issue-48728.rs => coherence/clone-impl-unsized-slice.rs} | 0 .../issue-4759-1.rs => methods/by-value-self-method-on-int.rs} | 0 .../issue-4759.rs => methods/destructure-and-call-self-method.rs} | 0 .../issue-50415.rs => range/inclusive-range-in-closure.rs} | 0 .../issue-47094.rs => repr/conflicting-repr-enum-attrs.rs} | 0 .../conflicting-repr-enum-attrs.stderr} | 0 .../tuple-struct-init-with-named-field.rs} | 0 .../tuple-struct-init-with-named-field.stderr} | 0 .../borrow-cast-or-binexpr-with-parens.fixed} | 0 .../borrow-cast-or-binexpr-with-parens.rs} | 0 .../borrow-cast-or-binexpr-with-parens.stderr} | 0 .../default-method/mono-item-collector-on-impl-with-lifetimes.rs} | 0 .../{issues/issue-46771.rs => typeck/call-unit-struct-as-fn.rs} | 0 .../issue-46771.stderr => typeck/call-unit-struct-as-fn.stderr} | 0 .../issue-48131.rs => unsafe/unused-unsafe-in-nested-fn-lint.rs} | 0 .../unused-unsafe-in-nested-fn-lint.stderr} | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-48728.rs => coherence/clone-impl-unsized-slice.rs} (100%) rename tests/ui/{issues/issue-4759-1.rs => methods/by-value-self-method-on-int.rs} (100%) rename tests/ui/{issues/issue-4759.rs => methods/destructure-and-call-self-method.rs} (100%) rename tests/ui/{issues/issue-50415.rs => range/inclusive-range-in-closure.rs} (100%) rename tests/ui/{issues/issue-47094.rs => repr/conflicting-repr-enum-attrs.rs} (100%) rename tests/ui/{issues/issue-47094.stderr => repr/conflicting-repr-enum-attrs.stderr} (100%) rename tests/ui/{issues/issue-4736.rs => structs/tuple-struct-init-with-named-field.rs} (100%) rename tests/ui/{issues/issue-4736.stderr => structs/tuple-struct-init-with-named-field.stderr} (100%) rename tests/ui/{issues/issue-46756-consider-borrowing-cast-or-binexpr.fixed => suggestions/borrow-cast-or-binexpr-with-parens.fixed} (100%) rename tests/ui/{issues/issue-46756-consider-borrowing-cast-or-binexpr.rs => suggestions/borrow-cast-or-binexpr-with-parens.rs} (100%) rename tests/ui/{issues/issue-46756-consider-borrowing-cast-or-binexpr.stderr => suggestions/borrow-cast-or-binexpr-with-parens.stderr} (100%) rename tests/ui/{issues/issue-47309.rs => traits/default-method/mono-item-collector-on-impl-with-lifetimes.rs} (100%) rename tests/ui/{issues/issue-46771.rs => typeck/call-unit-struct-as-fn.rs} (100%) rename tests/ui/{issues/issue-46771.stderr => typeck/call-unit-struct-as-fn.stderr} (100%) rename tests/ui/{issues/issue-48131.rs => unsafe/unused-unsafe-in-nested-fn-lint.rs} (100%) rename tests/ui/{issues/issue-48131.stderr => unsafe/unused-unsafe-in-nested-fn-lint.stderr} (100%) diff --git a/tests/ui/issues/issue-48728.rs b/tests/ui/coherence/clone-impl-unsized-slice.rs similarity index 100% rename from tests/ui/issues/issue-48728.rs rename to tests/ui/coherence/clone-impl-unsized-slice.rs diff --git a/tests/ui/issues/issue-4759-1.rs b/tests/ui/methods/by-value-self-method-on-int.rs similarity index 100% rename from tests/ui/issues/issue-4759-1.rs rename to tests/ui/methods/by-value-self-method-on-int.rs diff --git a/tests/ui/issues/issue-4759.rs b/tests/ui/methods/destructure-and-call-self-method.rs similarity index 100% rename from tests/ui/issues/issue-4759.rs rename to tests/ui/methods/destructure-and-call-self-method.rs diff --git a/tests/ui/issues/issue-50415.rs b/tests/ui/range/inclusive-range-in-closure.rs similarity index 100% rename from tests/ui/issues/issue-50415.rs rename to tests/ui/range/inclusive-range-in-closure.rs diff --git a/tests/ui/issues/issue-47094.rs b/tests/ui/repr/conflicting-repr-enum-attrs.rs similarity index 100% rename from tests/ui/issues/issue-47094.rs rename to tests/ui/repr/conflicting-repr-enum-attrs.rs diff --git a/tests/ui/issues/issue-47094.stderr b/tests/ui/repr/conflicting-repr-enum-attrs.stderr similarity index 100% rename from tests/ui/issues/issue-47094.stderr rename to tests/ui/repr/conflicting-repr-enum-attrs.stderr diff --git a/tests/ui/issues/issue-4736.rs b/tests/ui/structs/tuple-struct-init-with-named-field.rs similarity index 100% rename from tests/ui/issues/issue-4736.rs rename to tests/ui/structs/tuple-struct-init-with-named-field.rs diff --git a/tests/ui/issues/issue-4736.stderr b/tests/ui/structs/tuple-struct-init-with-named-field.stderr similarity index 100% rename from tests/ui/issues/issue-4736.stderr rename to tests/ui/structs/tuple-struct-init-with-named-field.stderr diff --git a/tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.fixed b/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.fixed similarity index 100% rename from tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.fixed rename to tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.fixed diff --git a/tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.rs b/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.rs similarity index 100% rename from tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.rs rename to tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.rs diff --git a/tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.stderr b/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.stderr similarity index 100% rename from tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.stderr rename to tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.stderr diff --git a/tests/ui/issues/issue-47309.rs b/tests/ui/traits/default-method/mono-item-collector-on-impl-with-lifetimes.rs similarity index 100% rename from tests/ui/issues/issue-47309.rs rename to tests/ui/traits/default-method/mono-item-collector-on-impl-with-lifetimes.rs diff --git a/tests/ui/issues/issue-46771.rs b/tests/ui/typeck/call-unit-struct-as-fn.rs similarity index 100% rename from tests/ui/issues/issue-46771.rs rename to tests/ui/typeck/call-unit-struct-as-fn.rs diff --git a/tests/ui/issues/issue-46771.stderr b/tests/ui/typeck/call-unit-struct-as-fn.stderr similarity index 100% rename from tests/ui/issues/issue-46771.stderr rename to tests/ui/typeck/call-unit-struct-as-fn.stderr diff --git a/tests/ui/issues/issue-48131.rs b/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.rs similarity index 100% rename from tests/ui/issues/issue-48131.rs rename to tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.rs diff --git a/tests/ui/issues/issue-48131.stderr b/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.stderr similarity index 100% rename from tests/ui/issues/issue-48131.stderr rename to tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.stderr From a2730fa8f0a7427cd7a276c438e1b049c667be73 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Sat, 18 Jul 2026 04:56:27 -0500 Subject: [PATCH 19/71] replace codeview.pdf with link to archived webpage --- .../rustc-dev-guide/src/debuginfo/CodeView.pdf | Bin 214354 -> 0 bytes src/doc/rustc-dev-guide/src/debuginfo/intro.md | 9 +++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) delete mode 100644 src/doc/rustc-dev-guide/src/debuginfo/CodeView.pdf diff --git a/src/doc/rustc-dev-guide/src/debuginfo/CodeView.pdf b/src/doc/rustc-dev-guide/src/debuginfo/CodeView.pdf deleted file mode 100644 index f899d25178458c24bf49cb9ab086761fbdc86f08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214354 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

Qy!5YFK=h&x?Vf?_B_Sa|t` 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 APXGV_ diff --git a/src/doc/rustc-dev-guide/src/debuginfo/intro.md b/src/doc/rustc-dev-guide/src/debuginfo/intro.md index 0f1e59fa65e26..00fc38a0f8d08 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/intro.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/intro.md @@ -63,7 +63,10 @@ Due to its proprietary nature, it is very difficult to find information about PD of the sources were made at vastly different times and contain incomplete or somewhat contradictory information. As such this page will aim to collect as many sources as possible. -* [CodeView 1.0 specification](./CodeView.pdf) +* [TIS PE specification](https://web.archive.org/web/20260315080740/http://x-ways.net/winhex/kb/ff/PE_EXE.pdf) +which includes a lengthy section titled "Microsoft Symbol and Type Information", detailing much of +the CodeView format. The document was created in 1993, but the information is still detailed, +accurate, and has useful diagrams. * LLVM * [CodeView Overview](https://llvm.org/docs/SourceLevelDebugging.html#codeview-debug-info-format) * [PDB Overview and technical details](https://llvm.org/docs/PDB/index.html) @@ -78,6 +81,8 @@ information. As such this page will aim to collect as many sources as possible. * [Debug Interface Access SDK](https://learn.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/getting-started-debug-interface-access-sdk). While it does not document the PDB format directly, details can be gleaned from the interface itself. + * [PDB-Documentation](https://github.com/PascalBeyer/PDB-Documentation) - a resource compiling + much of the plubicly available information about PDB and CodeView. # Debuggers @@ -111,4 +116,4 @@ in the future. specifically to debug Rust programs. While promising, it is still in early development. * [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) is a Windows-only GUI debugger. It has a custom debug info format that PDB is translated into. The project also includes a linker that can -generate their new debug info format during the linking phase. \ No newline at end of file +generate their new debug info format during the linking phase. From 2d0b4b3a9c4ce65b42d58a2f6059e35242a82917 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 18 Jul 2026 13:24:03 +0200 Subject: [PATCH 20/71] typo --- src/doc/rustc-dev-guide/src/debuginfo/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/intro.md b/src/doc/rustc-dev-guide/src/debuginfo/intro.md index 00fc38a0f8d08..4fcf4901beefb 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/intro.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/intro.md @@ -82,7 +82,7 @@ accurate, and has useful diagrams. While it does not document the PDB format directly, details can be gleaned from the interface itself. * [PDB-Documentation](https://github.com/PascalBeyer/PDB-Documentation) - a resource compiling - much of the plubicly available information about PDB and CodeView. + much of the publicly available information about PDB and CodeView. # Debuggers From 6d6092cd52252a7e604921eea680c3a01d632b9b Mon Sep 17 00:00:00 2001 From: zedddie Date: Sat, 18 Jul 2026 01:14:59 +0200 Subject: [PATCH 21/71] bless batch --- tests/ui/coherence/clone-impl-unsized-slice.rs | 4 ++-- tests/ui/methods/by-value-self-method-on-int.rs | 3 +++ tests/ui/methods/destructure-and-call-self-method.rs | 3 +++ tests/ui/range/inclusive-range-in-closure.rs | 3 +++ tests/ui/repr/conflicting-repr-enum-attrs.rs | 4 ++++ tests/ui/repr/conflicting-repr-enum-attrs.stderr | 8 ++++---- tests/ui/structs/tuple-struct-init-with-named-field.rs | 3 +++ .../ui/structs/tuple-struct-init-with-named-field.stderr | 2 +- .../suggestions/borrow-cast-or-binexpr-with-parens.fixed | 2 ++ .../ui/suggestions/borrow-cast-or-binexpr-with-parens.rs | 2 ++ .../suggestions/borrow-cast-or-binexpr-with-parens.stderr | 8 ++++---- .../mono-item-collector-on-impl-with-lifetimes.rs | 6 +++--- tests/ui/typeck/call-unit-struct-as-fn.rs | 3 +++ tests/ui/typeck/call-unit-struct-as-fn.stderr | 2 +- tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.rs | 2 ++ tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.stderr | 6 +++--- 16 files changed, 43 insertions(+), 18 deletions(-) diff --git a/tests/ui/coherence/clone-impl-unsized-slice.rs b/tests/ui/coherence/clone-impl-unsized-slice.rs index 8ad9289c65cf2..6a36df0166354 100644 --- a/tests/ui/coherence/clone-impl-unsized-slice.rs +++ b/tests/ui/coherence/clone-impl-unsized-slice.rs @@ -1,5 +1,5 @@ -// Regression test for #48728, an ICE that occurred computing -// coherence "help" information. +//! Regression test for . +//! ICE occurred computing coherence "help" information. //@ check-pass #[derive(Clone)] diff --git a/tests/ui/methods/by-value-self-method-on-int.rs b/tests/ui/methods/by-value-self-method-on-int.rs index 7368a7b2f845b..c27898b156d86 100644 --- a/tests/ui/methods/by-value-self-method-on-int.rs +++ b/tests/ui/methods/by-value-self-method-on-int.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! This used to trigger LLVM assertion. //@ run-pass + trait U { fn f(self); } impl U for isize { fn f(self) {} } pub fn main() { 4.f(); } diff --git a/tests/ui/methods/destructure-and-call-self-method.rs b/tests/ui/methods/destructure-and-call-self-method.rs index 4b49442b4010f..a88276ec774f1 100644 --- a/tests/ui/methods/destructure-and-call-self-method.rs +++ b/tests/ui/methods/destructure-and-call-self-method.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Destructuring a struct and calling consuming method used to segfault. //@ run-pass + #![allow(non_shorthand_field_patterns)] struct T { a: Box } diff --git a/tests/ui/range/inclusive-range-in-closure.rs b/tests/ui/range/inclusive-range-in-closure.rs index 5f6211eb149dd..b842fed586608 100644 --- a/tests/ui/range/inclusive-range-in-closure.rs +++ b/tests/ui/range/inclusive-range-in-closure.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Test inclusive ranges in closures don't ICE. //@ run-pass + fn main() { // Simplified test case let _ = || 0..=1; diff --git a/tests/ui/repr/conflicting-repr-enum-attrs.rs b/tests/ui/repr/conflicting-repr-enum-attrs.rs index c5d37feb1447f..d7e629d230c02 100644 --- a/tests/ui/repr/conflicting-repr-enum-attrs.rs +++ b/tests/ui/repr/conflicting-repr-enum-attrs.rs @@ -1,3 +1,7 @@ +//! Regression test for . +//! Test `conflicting representation hints` warning is being triggered +//! when there are multiple repr attributes. + #[repr(C, u8)] //~ ERROR conflicting representation hints //~^ WARN this was previously accepted enum Foo { diff --git a/tests/ui/repr/conflicting-repr-enum-attrs.stderr b/tests/ui/repr/conflicting-repr-enum-attrs.stderr index da414d68214a8..6810a2a2a1171 100644 --- a/tests/ui/repr/conflicting-repr-enum-attrs.stderr +++ b/tests/ui/repr/conflicting-repr-enum-attrs.stderr @@ -1,5 +1,5 @@ error[E0566]: conflicting representation hints - --> $DIR/issue-47094.rs:1:8 + --> $DIR/conflicting-repr-enum-attrs.rs:5:8 | LL | #[repr(C, u8)] | ^ ^^ @@ -9,7 +9,7 @@ LL | #[repr(C, u8)] = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default error[E0566]: conflicting representation hints - --> $DIR/issue-47094.rs:8:8 + --> $DIR/conflicting-repr-enum-attrs.rs:12:8 | LL | #[repr(C)] | ^ @@ -25,7 +25,7 @@ error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0566`. Future incompatibility report: Future breakage diagnostic: error[E0566]: conflicting representation hints - --> $DIR/issue-47094.rs:1:8 + --> $DIR/conflicting-repr-enum-attrs.rs:5:8 | LL | #[repr(C, u8)] | ^ ^^ @@ -36,7 +36,7 @@ LL | #[repr(C, u8)] Future breakage diagnostic: error[E0566]: conflicting representation hints - --> $DIR/issue-47094.rs:8:8 + --> $DIR/conflicting-repr-enum-attrs.rs:12:8 | LL | #[repr(C)] | ^ diff --git a/tests/ui/structs/tuple-struct-init-with-named-field.rs b/tests/ui/structs/tuple-struct-init-with-named-field.rs index 799d2d4809860..586d96284e170 100644 --- a/tests/ui/structs/tuple-struct-init-with-named-field.rs +++ b/tests/ui/structs/tuple-struct-init-with-named-field.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! This used to ICE. + struct NonCopyable(()); fn main() { diff --git a/tests/ui/structs/tuple-struct-init-with-named-field.stderr b/tests/ui/structs/tuple-struct-init-with-named-field.stderr index b099e528ca8a8..1fb3b0be0b02e 100644 --- a/tests/ui/structs/tuple-struct-init-with-named-field.stderr +++ b/tests/ui/structs/tuple-struct-init-with-named-field.stderr @@ -1,5 +1,5 @@ error[E0560]: struct `NonCopyable` has no field named `p` - --> $DIR/issue-4736.rs:4:26 + --> $DIR/tuple-struct-init-with-named-field.rs:7:26 | LL | struct NonCopyable(()); | ----------- `NonCopyable` defined here diff --git a/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.fixed b/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.fixed index d8402cdf07e38..157ed7e609d07 100644 --- a/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.fixed +++ b/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.fixed @@ -1,3 +1,5 @@ +//! Regression test for . +//! Test reference suggestion correctly puts cast in parentheses. //@ run-rustfix #![allow(unused)] diff --git a/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.rs b/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.rs index 0e04680911c80..3657cc67f7588 100644 --- a/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.rs +++ b/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.rs @@ -1,3 +1,5 @@ +//! Regression test for . +//! Test reference suggestion correctly puts cast in parentheses. //@ run-rustfix #![allow(unused)] diff --git a/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.stderr b/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.stderr index 211dd51289595..61b309291438c 100644 --- a/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.stderr +++ b/tests/ui/suggestions/borrow-cast-or-binexpr-with-parens.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:12:42 + --> $DIR/borrow-cast-or-binexpr-with-parens.rs:14:42 | LL | light_flows_our_war_of_mocking_words(behold as usize); | ------------------------------------ ^^^^^^^^^^^^^^^ expected `&usize`, found `usize` @@ -7,7 +7,7 @@ LL | light_flows_our_war_of_mocking_words(behold as usize); | arguments to this function are incorrect | note: function defined here - --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:5:4 + --> $DIR/borrow-cast-or-binexpr-with-parens.rs:7:4 | LL | fn light_flows_our_war_of_mocking_words(and_yet: &usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- @@ -17,7 +17,7 @@ LL | light_flows_our_war_of_mocking_words(&(behold as usize)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:14:42 + --> $DIR/borrow-cast-or-binexpr-with-parens.rs:16:42 | LL | light_flows_our_war_of_mocking_words(with_tears + 4); | ------------------------------------ ^^^^^^^^^^^^^^ expected `&usize`, found `usize` @@ -25,7 +25,7 @@ LL | light_flows_our_war_of_mocking_words(with_tears + 4); | arguments to this function are incorrect | note: function defined here - --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:5:4 + --> $DIR/borrow-cast-or-binexpr-with-parens.rs:7:4 | LL | fn light_flows_our_war_of_mocking_words(and_yet: &usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- diff --git a/tests/ui/traits/default-method/mono-item-collector-on-impl-with-lifetimes.rs b/tests/ui/traits/default-method/mono-item-collector-on-impl-with-lifetimes.rs index 99f1ccbc5758c..44c1e171835c8 100644 --- a/tests/ui/traits/default-method/mono-item-collector-on-impl-with-lifetimes.rs +++ b/tests/ui/traits/default-method/mono-item-collector-on-impl-with-lifetimes.rs @@ -1,6 +1,6 @@ -// Make sure that the mono-item collector does not crash when trying to -// instantiate a default impl of a method with lifetime parameters. -// See https://github.com/rust-lang/rust/issues/47309 +//! Regression test for . +//! Make sure that the mono-item collector does not crash when trying to +//! instantiate a default impl of a method with lifetime parameters. //@ compile-flags:-Clink-dead-code //@ build-pass diff --git a/tests/ui/typeck/call-unit-struct-as-fn.rs b/tests/ui/typeck/call-unit-struct-as-fn.rs index 22be8d6af8a7f..2fe2085dd72a9 100644 --- a/tests/ui/typeck/call-unit-struct-as-fn.rs +++ b/tests/ui/typeck/call-unit-struct-as-fn.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Test calling unit struct as fn doesn't ICE. + fn main() { struct Foo; (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `Foo` diff --git a/tests/ui/typeck/call-unit-struct-as-fn.stderr b/tests/ui/typeck/call-unit-struct-as-fn.stderr index fab55fbfd704a..8056d0df57f99 100644 --- a/tests/ui/typeck/call-unit-struct-as-fn.stderr +++ b/tests/ui/typeck/call-unit-struct-as-fn.stderr @@ -1,5 +1,5 @@ error[E0618]: expected function, found `Foo` - --> $DIR/issue-46771.rs:3:23 + --> $DIR/call-unit-struct-as-fn.rs:6:23 | LL | struct Foo; | ---------- `Foo` defined here diff --git a/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.rs b/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.rs index a1084ea243b26..92b9bbfefc88e 100644 --- a/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.rs +++ b/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.rs @@ -1,3 +1,5 @@ +//! Regression test for . + // This note is annotated because the purpose of the test // is to ensure that certain other notes are not generated. #![deny(unused_unsafe)] diff --git a/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.stderr b/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.stderr index fe0cd4efae891..cc5fab4fcdf94 100644 --- a/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.stderr +++ b/tests/ui/unsafe/unused-unsafe-in-nested-fn-lint.stderr @@ -1,17 +1,17 @@ error: unnecessary `unsafe` block - --> $DIR/issue-48131.rs:9:9 + --> $DIR/unused-unsafe-in-nested-fn-lint.rs:11:9 | LL | unsafe { /* unnecessary */ } | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/issue-48131.rs:3:9 + --> $DIR/unused-unsafe-in-nested-fn-lint.rs:5:9 | LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/issue-48131.rs:19:13 + --> $DIR/unused-unsafe-in-nested-fn-lint.rs:21:13 | LL | unsafe { /* unnecessary */ } | ^^^^^^ unnecessary `unsafe` block From fb119e011fe1295738e092956956bf889c053d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Racek?= Date: Sun, 19 Jul 2026 00:17:32 +0200 Subject: [PATCH 22/71] Clarify what to do when you break a subtree build --- src/doc/rustc-dev-guide/src/external-repos.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 7ae1c881be8f7..1aca1b2eab1c5 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -34,6 +34,9 @@ to these tools should be filed against the tools directly in their respective up 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. + `subtree` dependencies are currently managed by two distinct approaches: * Using `git subtree` From 4ee71fea02ec90e3031966ee46ea28bfabe91142 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sun, 19 Jul 2026 18:13:29 +0900 Subject: [PATCH 23/71] docs: add autodiff CI job document --- src/ci/github-actions/jobs.yml | 1 + src/doc/rustc-dev-guide/src/SUMMARY.md | 1 + .../src/tests/autodiff-ci-job.md | 45 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 src/doc/rustc-dev-guide/src/tests/autodiff-ci-job.md diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index a6b23fe516c89..706095890b114 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -471,6 +471,7 @@ auto: - name: optional-x86_64-gnu-autodiff continue_on_error: true + doc_url: https://rustc-dev-guide.rust-lang.org/tests/autodiff-ci-job.html <<: *job-linux-4c #################### diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index bf2de84575d69..6a3a5a0a936f3 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -34,6 +34,7 @@ - [Codegen backend testing](./tests/codegen-backend-tests/intro.md) - [Cranelift codegen backend](./tests/codegen-backend-tests/cg_clif.md) - [GCC codegen backend](./tests/codegen-backend-tests/cg_gcc.md) + - [Autodiff CI job](./tests/autodiff-ci-job.md) - [Performance testing](./tests/perf.md) - [Pre-stabilization CI job for the next solver and polonius alpha](./tests/x86_64-gnu-next-trait-solver-polonius-ci-job.md) - [Misc info](./tests/misc.md) diff --git a/src/doc/rustc-dev-guide/src/tests/autodiff-ci-job.md b/src/doc/rustc-dev-guide/src/tests/autodiff-ci-job.md new file mode 100644 index 0000000000000..3e5d55fbc81a9 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/tests/autodiff-ci-job.md @@ -0,0 +1,45 @@ +# Autodiff CI job + +The [`optional-x86_64-gnu-autodiff`] job provides continuous test coverage for +the experimental `autodiff` feature and its integration with LLVM Enzyme. It is +an optional [auto job](./ci.md#auto-builds), so a failure does not prevent a +pull request from being merged. + +For more context about the feature, see the [autodiff tracking issue] and the +[autodiff internals](../autodiff/internals.md) chapter. + +## What is tested + +The job checks: + +- forward- and reverse-mode macro expansion and diagnostics; +- LLVM IR generation for autodiff; +- enforcement of the `autodiff` feature gate. + +## Running the job + +To run the job in a try build, comment on a pull request: + +```text +@bors try jobs=optional-x86_64-gnu-autodiff +``` + +To run the job locally, run this command from a Rust checkout: + +```console +$ cargo run --manifest-path src/ci/citool/Cargo.toml run-local optional-x86_64-gnu-autodiff +``` + +See [Testing with Docker](./docker.md) for more information about running CI +jobs locally. + +## Point of contact + +If you have questions or need help with a failure in this job, open a new topic +in the [autodiff Zulip channel]. For suspected Enzyme backend failures, see the +[autodiff debugging guide]. + +[autodiff Zulip channel]: https://rust-lang.zulipchat.com/#narrow/channel/390790-wg-autodiff +[autodiff debugging guide]: ../autodiff/debugging.md +[autodiff tracking issue]: https://github.com/rust-lang/rust/issues/124509 +[`optional-x86_64-gnu-autodiff`]: https://github.com/rust-lang/rust/blob/HEAD/src/ci/github-actions/jobs.yml From 2851cef01a6a8cc8afc5770eba31362b944cc4e2 Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 20 Jul 2026 01:59:03 +0200 Subject: [PATCH 24/71] move batch --- .../const_in_pattern/const-bytes-slice-pattern.rs} | 0 .../auxiliary/cross-crate-multibyte-debuginfo-comments.rs} | 0 .../auxiliary/cross-crate-multibyte-debuginfo.rs} | 0 .../main.rs => debuginfo/cross-crate-multibyte-debuginfo.rs} | 0 .../fru-unknown-field-in-closure.rs} | 0 .../fru-unknown-field-in-closure.stderr} | 0 .../need_type_info/for-loop-nested-array-inference.rs} | 0 .../need_type_info/for-loop-nested-array-inference.stderr} | 0 .../repetition-matches-empty-token-tree.rs} | 0 .../repetition-matches-empty-token-tree.stderr} | 0 .../issue-52262.rs => moves/move-out-of-shared-ref-deref.rs} | 0 .../move-out-of-shared-ref-deref.stderr} | 0 .../struct-pattern-nonexistent-field.rs} | 0 .../struct-pattern-nonexistent-field.stderr} | 0 .../call-tuple-struct-ctor-as-fn.rs} | 0 .../object/extern-c-trait-object-methods.rs} | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-51655.rs => consts/const_in_pattern/const-bytes-slice-pattern.rs} (100%) rename tests/ui/{issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-mbcs-in-comments.rs => debuginfo/auxiliary/cross-crate-multibyte-debuginfo-comments.rs} (100%) rename tests/ui/{issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs => debuginfo/auxiliary/cross-crate-multibyte-debuginfo.rs} (100%) rename tests/ui/{issues/issue-24687-embed-debuginfo/main.rs => debuginfo/cross-crate-multibyte-debuginfo.rs} (100%) rename tests/ui/{issues/issue-50618.rs => functional-struct-update/fru-unknown-field-in-closure.rs} (100%) rename tests/ui/{issues/issue-50618.stderr => functional-struct-update/fru-unknown-field-in-closure.stderr} (100%) rename tests/ui/{issues/issue-51116.rs => inference/need_type_info/for-loop-nested-array-inference.rs} (100%) rename tests/ui/{issues/issue-51116.stderr => inference/need_type_info/for-loop-nested-array-inference.stderr} (100%) rename tests/ui/{issues/issue-5067.rs => macros/repetition-matches-empty-token-tree.rs} (100%) rename tests/ui/{issues/issue-5067.stderr => macros/repetition-matches-empty-token-tree.stderr} (100%) rename tests/ui/{issues/issue-52262.rs => moves/move-out-of-shared-ref-deref.rs} (100%) rename tests/ui/{issues/issue-52262.stderr => moves/move-out-of-shared-ref-deref.stderr} (100%) rename tests/ui/{issues/issue-51102.rs => pattern/struct-pattern-nonexistent-field.rs} (100%) rename tests/ui/{issues/issue-51102.stderr => pattern/struct-pattern-nonexistent-field.stderr} (100%) rename tests/ui/{issues/issue-5315.rs => structs-enums/call-tuple-struct-ctor-as-fn.rs} (100%) rename tests/ui/{issues/issue-51907.rs => traits/object/extern-c-trait-object-methods.rs} (100%) diff --git a/tests/ui/issues/issue-51655.rs b/tests/ui/consts/const_in_pattern/const-bytes-slice-pattern.rs similarity index 100% rename from tests/ui/issues/issue-51655.rs rename to tests/ui/consts/const_in_pattern/const-bytes-slice-pattern.rs diff --git a/tests/ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-mbcs-in-comments.rs b/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo-comments.rs similarity index 100% rename from tests/ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-mbcs-in-comments.rs rename to tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo-comments.rs diff --git a/tests/ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs b/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo.rs similarity index 100% rename from tests/ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs rename to tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo.rs diff --git a/tests/ui/issues/issue-24687-embed-debuginfo/main.rs b/tests/ui/debuginfo/cross-crate-multibyte-debuginfo.rs similarity index 100% rename from tests/ui/issues/issue-24687-embed-debuginfo/main.rs rename to tests/ui/debuginfo/cross-crate-multibyte-debuginfo.rs diff --git a/tests/ui/issues/issue-50618.rs b/tests/ui/functional-struct-update/fru-unknown-field-in-closure.rs similarity index 100% rename from tests/ui/issues/issue-50618.rs rename to tests/ui/functional-struct-update/fru-unknown-field-in-closure.rs diff --git a/tests/ui/issues/issue-50618.stderr b/tests/ui/functional-struct-update/fru-unknown-field-in-closure.stderr similarity index 100% rename from tests/ui/issues/issue-50618.stderr rename to tests/ui/functional-struct-update/fru-unknown-field-in-closure.stderr diff --git a/tests/ui/issues/issue-51116.rs b/tests/ui/inference/need_type_info/for-loop-nested-array-inference.rs similarity index 100% rename from tests/ui/issues/issue-51116.rs rename to tests/ui/inference/need_type_info/for-loop-nested-array-inference.rs diff --git a/tests/ui/issues/issue-51116.stderr b/tests/ui/inference/need_type_info/for-loop-nested-array-inference.stderr similarity index 100% rename from tests/ui/issues/issue-51116.stderr rename to tests/ui/inference/need_type_info/for-loop-nested-array-inference.stderr diff --git a/tests/ui/issues/issue-5067.rs b/tests/ui/macros/repetition-matches-empty-token-tree.rs similarity index 100% rename from tests/ui/issues/issue-5067.rs rename to tests/ui/macros/repetition-matches-empty-token-tree.rs diff --git a/tests/ui/issues/issue-5067.stderr b/tests/ui/macros/repetition-matches-empty-token-tree.stderr similarity index 100% rename from tests/ui/issues/issue-5067.stderr rename to tests/ui/macros/repetition-matches-empty-token-tree.stderr diff --git a/tests/ui/issues/issue-52262.rs b/tests/ui/moves/move-out-of-shared-ref-deref.rs similarity index 100% rename from tests/ui/issues/issue-52262.rs rename to tests/ui/moves/move-out-of-shared-ref-deref.rs diff --git a/tests/ui/issues/issue-52262.stderr b/tests/ui/moves/move-out-of-shared-ref-deref.stderr similarity index 100% rename from tests/ui/issues/issue-52262.stderr rename to tests/ui/moves/move-out-of-shared-ref-deref.stderr diff --git a/tests/ui/issues/issue-51102.rs b/tests/ui/pattern/struct-pattern-nonexistent-field.rs similarity index 100% rename from tests/ui/issues/issue-51102.rs rename to tests/ui/pattern/struct-pattern-nonexistent-field.rs diff --git a/tests/ui/issues/issue-51102.stderr b/tests/ui/pattern/struct-pattern-nonexistent-field.stderr similarity index 100% rename from tests/ui/issues/issue-51102.stderr rename to tests/ui/pattern/struct-pattern-nonexistent-field.stderr diff --git a/tests/ui/issues/issue-5315.rs b/tests/ui/structs-enums/call-tuple-struct-ctor-as-fn.rs similarity index 100% rename from tests/ui/issues/issue-5315.rs rename to tests/ui/structs-enums/call-tuple-struct-ctor-as-fn.rs diff --git a/tests/ui/issues/issue-51907.rs b/tests/ui/traits/object/extern-c-trait-object-methods.rs similarity index 100% rename from tests/ui/issues/issue-51907.rs rename to tests/ui/traits/object/extern-c-trait-object-methods.rs From 4e53ac1907b713026674cf110961e2f4fe844f06 Mon Sep 17 00:00:00 2001 From: Yukang Date: Tue, 14 Jul 2026 23:18:54 +0800 Subject: [PATCH 25/71] Add allow_list checking for eii implementation attributes --- .../rustc_ast_passes/src/ast_validation.rs | 46 +++++++- compiler/rustc_ast_passes/src/diagnostics.rs | 11 ++ compiler/rustc_passes/src/check_attr.rs | 16 --- compiler/rustc_passes/src/diagnostics.rs | 10 -- ...tation-attribute-allowlist-issue-159015.rs | 102 ++++++++++++++++++ ...on-attribute-allowlist-issue-159015.stderr | 67 ++++++++++++ tests/ui/eii/track_caller_errors.stderr | 3 +- 7 files changed, 226 insertions(+), 29 deletions(-) create mode 100644 tests/ui/eii/implementation-attribute-allowlist-issue-159015.rs create mode 100644 tests/ui/eii/implementation-attribute-allowlist-issue-159015.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 478dbc0dd7684..f7d9acef6eb84 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1202,6 +1202,48 @@ impl<'a> AstValidator<'a> { self.visit_vis(vis); self.visit_ident(ident); } + + // Check EII implementation attributes against an allowlist. + fn check_eii_impl_attrs(&self, attrs: &[Attribute], eii_impls: &[EiiImpl]) { + if eii_impls.is_empty() { + return; + } + + let allowed_attrs: &[Symbol] = &[ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::expect, + sym::doc, + sym::inline, + sym::cold, + sym::optimize, + sym::coverage, + sym::sanitize, + sym::must_use, + sym::deprecated, + ]; + + for attr in attrs { + let AttrKind::Normal(normal) = &attr.kind else { + continue; + }; + if attr.has_any_name(allowed_attrs) { + continue; + } + + let attr_name = pprust::path_to_string(&normal.item.path); + for eii_impl in eii_impls { + self.dcx().emit_err(diagnostics::EiiImplAttributeNotSupported { + attr_span: attr.span, + attr_name: &attr_name, + eii_span: eii_impl.span, + eii_name: pprust::path_to_string(&eii_impl.eii_macro_path), + }); + } + } + } } /// Checks that generic parameters are in the correct order, @@ -1391,6 +1433,7 @@ impl Visitor<'_> for AstValidator<'_> { for EiiImpl { eii_macro_path, .. } in eii_impls { self.visit_path(eii_macro_path); } + self.check_eii_impl_attrs(&item.attrs, eii_impls); let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); if body.is_none() && !is_intrinsic && !self.is_sdylib_interface { @@ -1566,8 +1609,9 @@ impl Visitor<'_> for AstValidator<'_> { visit::walk_item(self, item); } - ItemKind::Static(StaticItem { expr, safety, .. }) => { + ItemKind::Static(StaticItem { expr, safety, eii_impls, .. }) => { self.check_item_safety(item.span, *safety); + self.check_eii_impl_attrs(&item.attrs, eii_impls); if matches!(safety, Safety::Unsafe(_)) { self.dcx().emit_err(diagnostics::UnsafeStatic { span: item.span }); } diff --git a/compiler/rustc_ast_passes/src/diagnostics.rs b/compiler/rustc_ast_passes/src/diagnostics.rs index 0cf7ef5c1de19..5bcffe96f6086 100644 --- a/compiler/rustc_ast_passes/src/diagnostics.rs +++ b/compiler/rustc_ast_passes/src/diagnostics.rs @@ -189,6 +189,17 @@ pub(crate) struct FnParamForbiddenAttr { pub span: Span, } +#[derive(Diagnostic)] +#[diag("`#[{$eii_name}]` is not allowed to have `#[{$attr_name}]`")] +pub(crate) struct EiiImplAttributeNotSupported<'a> { + #[primary_span] + pub attr_span: Span, + pub attr_name: &'a str, + pub eii_name: String, + #[label("`#[{$eii_name}]` is not allowed to have `#[{$attr_name}]`")] + pub eii_span: Span, +} + #[derive(Diagnostic)] #[diag("`self` parameter is only allowed in associated functions")] #[note("associated functions are those in `impl` or `trait` definitions")] diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3139c8746b95a..8408b2e889063 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -791,22 +791,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sig_span: sig.span, }); } - - if let Some(impls) = find_attr!(attrs, EiiImpls(impls) => impls) { - let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); - for i in impls { - let name = match i.resolution { - EiiImplResolution::Macro(def_id) => self.tcx.item_name(def_id), - EiiImplResolution::Known(def_id) => self.tcx.item_name(def_id), - EiiImplResolution::Error(_eg) => continue, - }; - self.dcx().emit_err(diagnostics::EiiWithTrackCaller { - attr_span, - name, - sig_span: sig.span, - }); - } - } } _ => {} } diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 2589941d7dae1..860cc435db330 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -1077,16 +1077,6 @@ pub(crate) struct EiiImplRequiresUnsafeSuggestion { pub right: Span, } -#[derive(Diagnostic)] -#[diag("`#[{$name}]` is not allowed to have `#[track_caller]`")] -pub(crate) struct EiiWithTrackCaller { - #[primary_span] - pub attr_span: Span, - pub name: Symbol, - #[label("`#[{$name}]` is not allowed to have `#[track_caller]`")] - pub sig_span: Span, -} - #[derive(Diagnostic)] #[diag("`#[{$name}]` {$kind} required, but not found")] pub(crate) struct EiiWithoutImpl { diff --git a/tests/ui/eii/implementation-attribute-allowlist-issue-159015.rs b/tests/ui/eii/implementation-attribute-allowlist-issue-159015.rs new file mode 100644 index 0000000000000..d27ea2a833e0f --- /dev/null +++ b/tests/ui/eii/implementation-attribute-allowlist-issue-159015.rs @@ -0,0 +1,102 @@ +// EII implementations only accept attributes from a conservative allowlist. +// Regression test for #159015 + +//@ edition: 2024 +//@ needs-asm-support + +#![feature(coverage_attribute)] +#![feature(extern_item_impls)] +#![feature(optimize_attribute)] +#![feature(sanitize)] + +#[eii] +fn allowed(); + +/// Sugared and explicit documentation attributes are both allowed. +#[allowed] +#[allow(dead_code)] +#[warn(unreachable_code)] +#[deny(unused_mut)] +#[forbid(unsafe_code)] +#[expect(unused_variables)] +#[cfg(all())] +#[doc = "An allowed EII implementation."] +#[cold] +#[optimize(none)] +#[coverage(off)] +#[sanitize(address = "off")] +#[must_use] +#[deprecated] +fn allowed_impl() { + let unused = (); +} + +#[eii] +fn allowed_inline(); + +#[allowed_inline] +#[allow(unused_attributes)] +#[cfg_attr(all(), inline)] +fn allowed_inline_impl() {} + +#[eii] +fn foo(); + +#[foo] +#[unsafe(no_mangle)] +//~^ ERROR `#[foo]` is not allowed to have `#[no_mangle]` +fn bar() {} + +#[eii] +fn baz(); + +#[baz] +#[unsafe(export_name = "qux")] +//~^ ERROR `#[baz]` is not allowed to have `#[export_name]` +fn qux() {} + +#[eii] +fn quux(); + +#[quux] +#[unsafe(link_section = "__TEXT,__text")] +//~^ ERROR `#[quux]` is not allowed to have `#[link_section]` +fn corge() {} + +#[eii] +fn grault(); + +#[grault] +#[track_caller] +//~^ ERROR `#[grault]` is not allowed to have `#[track_caller]` +fn garply() {} + +#[eii] +extern "C" fn naked_attr(); + +#[naked_attr] +#[unsafe(naked)] +//~^ ERROR `#[naked_attr]` is not allowed to have `#[naked]` +extern "C" fn naked_attr_impl() { + core::arch::naked_asm!("") +} + +#[eii] +fn multiple_invalid_attrs(); + +#[multiple_invalid_attrs] +#[unsafe(no_mangle)] +//~^ ERROR `#[multiple_invalid_attrs]` is not allowed to have `#[no_mangle]` +#[track_caller] +//~^ ERROR `#[multiple_invalid_attrs]` is not allowed to have `#[track_caller]` +fn multiple_invalid_attrs_impl() {} + +#[eii(static_eii)] +static STATIC_EII: u8; + +#[static_eii] +#[used] +//~^ ERROR `#[static_eii]` is not allowed to have `#[used]` +static STATIC_EII_IMPL: u8 = 0; + +fn main() {} diff --git a/tests/ui/eii/implementation-attribute-allowlist-issue-159015.stderr b/tests/ui/eii/implementation-attribute-allowlist-issue-159015.stderr new file mode 100644 index 0000000000000..af9673099f20f --- /dev/null +++ b/tests/ui/eii/implementation-attribute-allowlist-issue-159015.stderr @@ -0,0 +1,67 @@ +error: `#[foo]` is not allowed to have `#[no_mangle]` + --> $DIR/implementation-attribute-allowlist-issue-159015.rs:46:1 + | +LL | #[foo] + | ------ `#[foo]` is not allowed to have `#[no_mangle]` +LL | #[unsafe(no_mangle)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `#[baz]` is not allowed to have `#[export_name]` + --> $DIR/implementation-attribute-allowlist-issue-159015.rs:54:1 + | +LL | #[baz] + | ------ `#[baz]` is not allowed to have `#[export_name]` +LL | #[unsafe(export_name = "qux")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[quux]` is not allowed to have `#[link_section]` + --> $DIR/implementation-attribute-allowlist-issue-159015.rs:62:1 + | +LL | #[quux] + | ------- `#[quux]` is not allowed to have `#[link_section]` +LL | #[unsafe(link_section = "__TEXT,__text")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[grault]` is not allowed to have `#[track_caller]` + --> $DIR/implementation-attribute-allowlist-issue-159015.rs:70:1 + | +LL | #[grault] + | --------- `#[grault]` is not allowed to have `#[track_caller]` +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: `#[naked_attr]` is not allowed to have `#[naked]` + --> $DIR/implementation-attribute-allowlist-issue-159015.rs:78:1 + | +LL | #[naked_attr] + | ------------- `#[naked_attr]` is not allowed to have `#[naked]` +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ + +error: `#[multiple_invalid_attrs]` is not allowed to have `#[no_mangle]` + --> $DIR/implementation-attribute-allowlist-issue-159015.rs:88:1 + | +LL | #[multiple_invalid_attrs] + | ------------------------- `#[multiple_invalid_attrs]` is not allowed to have `#[no_mangle]` +LL | #[unsafe(no_mangle)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `#[multiple_invalid_attrs]` is not allowed to have `#[track_caller]` + --> $DIR/implementation-attribute-allowlist-issue-159015.rs:90:1 + | +LL | #[multiple_invalid_attrs] + | ------------------------- `#[multiple_invalid_attrs]` is not allowed to have `#[track_caller]` +... +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: `#[static_eii]` is not allowed to have `#[used]` + --> $DIR/implementation-attribute-allowlist-issue-159015.rs:98:1 + | +LL | #[static_eii] + | ------------- `#[static_eii]` is not allowed to have `#[used]` +LL | #[used] + | ^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/eii/track_caller_errors.stderr b/tests/ui/eii/track_caller_errors.stderr index e096146b67830..356f86093d638 100644 --- a/tests/ui/eii/track_caller_errors.stderr +++ b/tests/ui/eii/track_caller_errors.stderr @@ -4,8 +4,7 @@ error: `#[decl1]` is not allowed to have `#[track_caller]` LL | #[track_caller] | ^^^^^^^^^^^^^^^ LL | #[decl1] -LL | fn impl1(x: u64) { - | ---------------- `#[decl1]` is not allowed to have `#[track_caller]` + | -------- `#[decl1]` is not allowed to have `#[track_caller]` error: aborting due to 1 previous error From 7726456e92260a1f3080a0a4a0cd0714684e8048 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 15:47:03 +0200 Subject: [PATCH 26/71] extraneous word --- src/doc/rustc-dev-guide/src/hir-typeck/summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/hir-typeck/summary.md b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md index 23df97a9cf833..b519e8374d768 100644 --- a/src/doc/rustc-dev-guide/src/hir-typeck/summary.md +++ b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md @@ -3,7 +3,7 @@ The [`hir_analysis`] crate contains the source for "type collection" as well as a bunch of related functionality. Checking the bodies of functions is implemented in the [`hir_typeck`] crate. -These crates draw heavily on the [type inference] and [trait solving]. +These crates draw heavily on [type inference] and [trait solving]. [`hir_analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/index.html [`hir_typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/index.html From 216b07a86c9785de2755b28ee4ef37c187bf518f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 15:50:10 +0200 Subject: [PATCH 27/71] deserves own sentence --- src/doc/rustc-dev-guide/src/hir-typeck/summary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/hir-typeck/summary.md b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md index b519e8374d768..ae84c1e676751 100644 --- a/src/doc/rustc-dev-guide/src/hir-typeck/summary.md +++ b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md @@ -14,8 +14,8 @@ These crates draw heavily on [type inference] and [trait solving]. Type "collection" is the process of converting the types found in the HIR (`hir::Ty`), which represent the syntactic things that the user wrote, into the -**internal representation** used by the compiler (`Ty<'tcx>`) – we also do -similar conversions for where-clauses and other bits of the function signature. +**internal representation** used by the compiler (`Ty<'tcx>`). +Note that we also do similar conversions for where-clauses and other bits of the function signature. To try and get a sense of the difference, consider this function: From a9d6ac19ce56eaf9be0ffbf9b69f333bf13daca0 Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 20 Jul 2026 21:28:09 +0800 Subject: [PATCH 28/71] Add test cases for a hoisting miscompilation --- ...dont_hoist_deref.EarlyOtherwiseBranch.diff | 49 +++++++++++++++++++ tests/mir-opt/early_otherwise_branch.rs | 42 ++++++++++++++++ tests/ui/mir/hoist_deref_early_else.rs | 37 ++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 tests/mir-opt/early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff create mode 100644 tests/ui/mir/hoist_deref_early_else.rs diff --git a/tests/mir-opt/early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000000..b449b7e28dd2e --- /dev/null +++ b/tests/mir-opt/early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff @@ -0,0 +1,49 @@ +- // MIR for `dont_hoist_deref` before EarlyOtherwiseBranch ++ // MIR for `dont_hoist_deref` after EarlyOtherwiseBranch + + fn dont_hoist_deref(_1: u64, _2: *const u64) -> u64 { + let mut _0: u64; ++ let mut _3: bool; + + bb0: { +- switchInt(copy _1) -> [1: bb1, 2: bb2, otherwise: bb5]; ++ _3 = Ne(copy _1, copy (*_2)); ++ switchInt(move _3) -> [0: bb5, otherwise: bb3]; + } + + bb1: { +- switchInt(copy (*_2)) -> [1: bb3, otherwise: bb5]; ++ _0 = const 100_u64; ++ goto -> bb4; + } + + bb2: { +- switchInt(copy (*_2)) -> [2: bb4, otherwise: bb5]; ++ _0 = const 200_u64; ++ goto -> bb4; + } + + bb3: { +- _0 = const 100_u64; +- goto -> bb6; ++ _0 = const 999_u64; ++ goto -> bb4; + } + + bb4: { +- _0 = const 200_u64; +- goto -> bb6; ++ return; + } + + bb5: { +- _0 = const 999_u64; +- goto -> bb6; +- } +- +- bb6: { +- return; ++ switchInt(copy _1) -> [1: bb1, 2: bb2, otherwise: bb3]; + } + } + diff --git a/tests/mir-opt/early_otherwise_branch.rs b/tests/mir-opt/early_otherwise_branch.rs index 19a5d25de2dfb..99bd0d65cf470 100644 --- a/tests/mir-opt/early_otherwise_branch.rs +++ b/tests/mir-opt/early_otherwise_branch.rs @@ -156,6 +156,47 @@ fn target_self(val: i32) { } } +// EMIT_MIR early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff +#[custom_mir(dialect = "runtime")] +fn dont_hoist_deref(q: u64, p: *const u64) -> u64 { + mir! { + { + match q { + 1 => bb1, + 2 => bb2, + _ => bb5, + } + } + bb1 = { + match *p { + 1 => bb3, + _ => bb5, + } + } + bb2 = { + match *p { + 2 => bb4, + _ => bb5, + } + } + bb3 = { + RET = 100; + Goto(bb6) + } + bb4 = { + RET = 200; + Goto(bb6) + } + bb5 = { + RET = 999; + Goto(bb6) + } + bb6 = { + Return() + } + } +} + fn main() { opt1(None, Some(0)); opt2(None, Some(0)); @@ -164,4 +205,5 @@ fn main() { opt5(0, 0); opt5_failed(0, 0); target_self(1); + dont_hoist_deref(3, std::ptr::null()); } diff --git a/tests/ui/mir/hoist_deref_early_else.rs b/tests/ui/mir/hoist_deref_early_else.rs new file mode 100644 index 0000000000000..06e31bcb0b3ad --- /dev/null +++ b/tests/ui/mir/hoist_deref_early_else.rs @@ -0,0 +1,37 @@ +//! Regression test for issue . +//! The null pointer `p` should never be dereferenced. +//@[noopt] run-pass +//@[opt] run-crash +//@ revisions: noopt opt +//@ check-run-results +//@[noopt] compile-flags: -C opt-level=0 +//@[opt] compile-flags: -C opt-level=3 + +use std::hint::black_box; + +#[inline(never)] +fn foo(q: u64, p: *const u64) -> u64 { + unsafe { + 'a: { + match q { + 1 => match *p { + 1 => break 'a 100, + _ => {} + }, + 2 => match *p { + 2 => break 'a 200, + _ => {} + }, + _ => {} + } + 999 + } + } +} + +fn main() { + let q: u64 = black_box(3); + let p: *const u64 = black_box(std::ptr::null()); + let r = foo(q, p); + assert_eq!(999, black_box(r)); +} From a22fed77686db50c1185e4267743924ac50f584a Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 20 Jul 2026 22:41:37 +0800 Subject: [PATCH 29/71] early_otherwise: Don't hoist dereferences when the otherwise branch is reachable --- .../src/early_otherwise_branch.rs | 97 ++++++++++++------- ...dont_hoist_deref.EarlyOtherwiseBranch.diff | 37 +++---- tests/mir-opt/early_otherwise_branch.rs | 9 ++ tests/ui/mir/hoist_deref_early_else.rs | 3 +- 4 files changed, 83 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 2b786b7e9e1a2..7adeebd235384 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -243,7 +243,7 @@ fn evaluate_candidate<'tcx>( return None; } - // We only handle: + // For now, we only handle: // ``` // bb4: { // _8 = discriminant((_3.1: Enum1)); @@ -262,41 +262,8 @@ fn evaluate_candidate<'tcx>( // When thie BB has exactly one statement, this statement should be discriminant. let need_hoist_discriminant = bbs[child].statements.len() == 1; + let otherwise_is_empty_unreachable = bbs[targets.otherwise()].is_empty_unreachable(); let child_place = if need_hoist_discriminant { - if !bbs[targets.otherwise()].is_empty_unreachable() { - // Someone could write code like this: - // ```rust - // let Q = val; - // if discriminant(P) == otherwise { - // let ptr = &mut Q as *mut _ as *mut u8; - // // It may be difficult for us to effectively determine whether values are valid. - // // Invalid values can come from all sorts of corners. - // unsafe { *ptr = 10; } - // } - // - // match P { - // A => match Q { - // A => { - // // code - // } - // _ => { - // // don't use Q - // } - // } - // _ => { - // // don't use Q - // } - // }; - // ``` - // - // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an - // invalid value, which is UB. - // In order to fix this, **we would either need to show that the discriminant computation of - // `place` is computed in all branches**. - // FIXME(#95162) For the moment, we adopt a conservative approach and - // consider only the `otherwise` branch has no statements and an unreachable terminator. - return None; - } // Handle: // ``` // bb4: { @@ -325,8 +292,7 @@ fn evaluate_candidate<'tcx>( }; *child_place }; - let destination = if need_hoist_discriminant || bbs[targets.otherwise()].is_empty_unreachable() - { + let destination = if otherwise_is_empty_unreachable { child_targets.otherwise() } else { targets.otherwise() @@ -340,6 +306,7 @@ fn evaluate_candidate<'tcx>( child_place, destination, need_hoist_discriminant, + otherwise_is_empty_unreachable, ) { return None; } @@ -359,11 +326,67 @@ fn verify_candidate_branch<'tcx>( place: Place<'tcx>, destination: BasicBlock, need_hoist_discriminant: bool, + otherwise_is_empty_unreachable: bool, ) -> bool { // In order for the optimization to be correct, the terminator must be a `SwitchInt`. let TerminatorKind::SwitchInt { discr: switch_op, targets } = &branch.terminator().kind else { return false; }; + if !otherwise_is_empty_unreachable { + // Someone could write code like this: + // ```rust + // let Q = val; + // if discriminant(P) == otherwise { + // let ptr = &mut Q as *mut _ as *mut u8; + // // It may be difficult for us to effectively determine whether values are valid. + // // Invalid values can come from all sorts of corners. + // unsafe { *ptr = 10; } + // } + // + // match P { + // A => match Q { + // A => { + // // code + // } + // _ => { + // // don't use Q + // } + // } + // _ => { + // // don't use Q + // } + // }; + // ``` + // + // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an + // invalid value, which is UB. + // In order to fix this, **we would either need to show that the discriminant computation of + // `place` is computed in all branches**. + // For , we adopt a conservative approach and + // consider only the `otherwise` branch has no statements and an unreachable terminator. + if need_hoist_discriminant { + return false; + } + // For : + // ``` + // bb0: { + // switchInt(copy _1) -> [1: bb1, 2: bb2, otherwise: bb5]; + // } + // bb1: { + // switchInt(copy (*_2)) -> [1: bb3, otherwise: bb5]; + // } + // bb2: { + // switchInt(copy (*_2)) -> [2: bb4, otherwise: bb5]; + // } + // ``` + // We cannot hoist the dereference of `_2` to `bb0`, + // because execution can reach `bb5` without dereferencing `_2`. + if let Some(place) = switch_op.place() + && !place.is_stable_offset() + { + return false; + } + } if need_hoist_discriminant { // If we need hoist discriminant, the branch must have exactly one statement. let [statement] = branch.statements.as_slice() else { diff --git a/tests/mir-opt/early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff index b449b7e28dd2e..66891f818a6cf 100644 --- a/tests/mir-opt/early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff @@ -3,47 +3,36 @@ fn dont_hoist_deref(_1: u64, _2: *const u64) -> u64 { let mut _0: u64; -+ let mut _3: bool; bb0: { -- switchInt(copy _1) -> [1: bb1, 2: bb2, otherwise: bb5]; -+ _3 = Ne(copy _1, copy (*_2)); -+ switchInt(move _3) -> [0: bb5, otherwise: bb3]; + switchInt(copy _1) -> [1: bb1, 2: bb2, otherwise: bb5]; } bb1: { -- switchInt(copy (*_2)) -> [1: bb3, otherwise: bb5]; -+ _0 = const 100_u64; -+ goto -> bb4; + switchInt(copy (*_2)) -> [1: bb3, otherwise: bb5]; } bb2: { -- switchInt(copy (*_2)) -> [2: bb4, otherwise: bb5]; -+ _0 = const 200_u64; -+ goto -> bb4; + switchInt(copy (*_2)) -> [2: bb4, otherwise: bb5]; } bb3: { -- _0 = const 100_u64; -- goto -> bb6; -+ _0 = const 999_u64; -+ goto -> bb4; + _0 = const 100_u64; + goto -> bb6; } bb4: { -- _0 = const 200_u64; -- goto -> bb6; -+ return; + _0 = const 200_u64; + goto -> bb6; } bb5: { -- _0 = const 999_u64; -- goto -> bb6; -- } -- -- bb6: { -- return; -+ switchInt(copy _1) -> [1: bb1, 2: bb2, otherwise: bb3]; + _0 = const 999_u64; + goto -> bb6; + } + + bb6: { + return; } } diff --git a/tests/mir-opt/early_otherwise_branch.rs b/tests/mir-opt/early_otherwise_branch.rs index 99bd0d65cf470..54406f41f8fc1 100644 --- a/tests/mir-opt/early_otherwise_branch.rs +++ b/tests/mir-opt/early_otherwise_branch.rs @@ -159,6 +159,15 @@ fn target_self(val: i32) { // EMIT_MIR early_otherwise_branch.dont_hoist_deref.EarlyOtherwiseBranch.diff #[custom_mir(dialect = "runtime")] fn dont_hoist_deref(q: u64, p: *const u64) -> u64 { + // The dereference of `p` cannot be hoisted because the `otherwise` branch + // can be taken without dereferencing `p`. + // Hoisting the dereference could therefore cause UB when `p` is null. + // Hoisting a dereference also requires proving that the dereference is safe to reorder. + // CHECK-LABEL: fn dont_hoist_deref( + // CHECK: bb0: { + // CHECK-NEXT: switchInt(copy _1) + // CHECK: switchInt(copy (*_2)) + // CHECK: switchInt(copy (*_2)) mir! { { match q { diff --git a/tests/ui/mir/hoist_deref_early_else.rs b/tests/ui/mir/hoist_deref_early_else.rs index 06e31bcb0b3ad..fb749e96d7c08 100644 --- a/tests/ui/mir/hoist_deref_early_else.rs +++ b/tests/ui/mir/hoist_deref_early_else.rs @@ -1,7 +1,6 @@ //! Regression test for issue . //! The null pointer `p` should never be dereferenced. -//@[noopt] run-pass -//@[opt] run-crash +//@ run-pass //@ revisions: noopt opt //@ check-run-results //@[noopt] compile-flags: -C opt-level=0 From 6c5df713317b31612051b9f741d7d8b236a2aab6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 18:47:13 +0200 Subject: [PATCH 30/71] update thir output --- src/doc/rustc-dev-guide/src/thir.md | 191 +++++++++++----------------- 1 file changed, 73 insertions(+), 118 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/thir.md b/src/doc/rustc-dev-guide/src/thir.md index 802df2286095d..1ba30d86a6913 100644 --- a/src/doc/rustc-dev-guide/src/thir.md +++ b/src/doc/rustc-dev-guide/src/thir.md @@ -48,7 +48,7 @@ which is useful to keep peak memory in check. Having a THIR representation of all bodies of a crate in memory at the same time would be very heavy. -You can get a debug representation of the THIR by passing the `-Zunpretty=thir-tree` flag +You can get a debug representation of the THIR by passing the `-Zunpretty=thir-flat` flag to `rustc`. To demonstrate, let's use the following example: @@ -59,213 +59,168 @@ fn main() { } ``` -Here is how that gets represented in THIR (as of Aug 2022): +Here is how that gets represented in THIR (as of Jul 2026): ```rust,no_run +DefId(0:3 ~ main[26fd]::main): Thir { + body_type: Fn( + fn(), + ), + attributes: {}, // no match arms arms: [], + blocks: [ + Block { + targeted_by_break: false, + region_scope: Node(1), + span: main.rs:1:11: 3:2 (#0), + stmts: [ + s0, + ], + expr: None, + safety_mode: Safe, + }, + ], exprs: [ // expression 0, a literal with a value of 1 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:13: 2:14 (#0), kind: Literal { lit: Spanned { node: Int( - 1, + Pu128( + 1, + ), Unsuffixed, ), - span: oneplustwo.rs:2:13: 2:14 (#0), + span: main.rs:2:13: 2:14 (#0), }, neg: false, }, + ty: i32, + temp_scope_id: 4, + span: main.rs:2:13: 2:14 (#0), }, // expression 1, scope surrounding literal 1 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:13: 2:14 (#0), kind: Scope { + region_scope: Node(4), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).4), // reference to expression 0 above - region_scope: Node(3), - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 3, - }, - ), value: e0, }, + ty: i32, + temp_scope_id: 4, + span: main.rs:2:13: 2:14 (#0), }, // expression 2, literal 2 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:17: 2:18 (#0), kind: Literal { lit: Spanned { node: Int( - 2, + Pu128( + 2, + ), Unsuffixed, ), - span: oneplustwo.rs:2:17: 2:18 (#0), + span: main.rs:2:17: 2:18 (#0), }, neg: false, }, + ty: i32, + temp_scope_id: 5, + span: main.rs:2:17: 2:18 (#0), }, // expression 3, scope surrounding literal 2 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:17: 2:18 (#0), kind: Scope { - region_scope: Node(4), - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 4, - }, - ), - // reference to expression 2 above + region_scope: Node(5), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).5), + // reference to expression 0 above value: e2, }, + ty: i32, + temp_scope_id: 5, + span: main.rs:2:17: 2:18 (#0), }, // expression 4, represents 1 + 2 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:13: 2:18 (#0), kind: Binary { op: Add, // references to scopes surrounding literals above lhs: e1, rhs: e3, }, + ty: i32, + temp_scope_id: 3, + span: main.rs:2:13: 2:18 (#0), }, // expression 5, scope surrounding expression 4 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:13: 2:18 (#0), kind: Scope { - region_scope: Node(5), - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 5, - }, - ), + region_scope: Node(3), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).3), value: e4, }, + ty: i32, + temp_scope_id: 3, + span: main.rs:2:13: 2:18 (#0), }, // expression 6, block around statement Expr { - ty: (), - temp_lifetime: Some( - Node(9), - ), - span: oneplustwo.rs:1:11: 3:2 (#0), kind: Block { - body: Block { - targeted_by_break: false, - region_scope: Node(8), - opt_destruction_scope: None, - span: oneplustwo.rs:1:11: 3:2 (#0), - // reference to statement 0 below - stmts: [ - s0, - ], - expr: None, - safety_mode: Safe, - }, + block: b0, }, + ty: (), + temp_scope_id: 8, + span: main.rs:1:11: 3:2 (#0), }, // expression 7, scope around block in expression 6 Expr { - ty: (), - temp_lifetime: Some( - Node(9), - ), - span: oneplustwo.rs:1:11: 3:2 (#0), kind: Scope { - region_scope: Node(9), - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 9, - }, - ), + region_scope: Node(8), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).8), value: e6, }, - }, - // destruction scope around expression 7 - Expr { ty: (), - temp_lifetime: Some( - Node(9), - ), - span: oneplustwo.rs:1:11: 3:2 (#0), - kind: Scope { - region_scope: Destruction(9), - lint_level: Inherited, - value: e7, - }, + temp_scope_id: 8, + span: main.rs:1:11: 3:2 (#0), }, ], stmts: [ - // let statement Stmt { kind: Let { - remainder_scope: Remainder { block: 8, first_statement_index: 0}, - init_scope: Node(1), + remainder_scope: Remainder { block: 1, first_statement_index: 0}, + init_scope: Node(2), pattern: Pat { ty: i32, - span: oneplustwo.rs:2:9: 2:10 (#0), + span: main.rs:2:9: 2:10 (#0), + extra: None, kind: Binding { - mutability: Not, name: "x", - mode: ByValue, + mode: BindingMode( + No, + Not, + ), var: LocalVarId( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 7, - }, + HirId(DefId(0:3 ~ main[26fd]::main).7), ), ty: i32, subpattern: None, is_primary: true, + is_shorthand: false, }, }, initializer: Some( e5, ), else_block: None, - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 6, - }, - ), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).6), + span: main.rs:2:5: 2:18 (#0), }, - opt_destruction_scope: Some( - Destruction(1), - ), }, ], + params: [], } ``` From 4809e4c16d77f949f22546905fd465e5d982022a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 18:50:22 +0200 Subject: [PATCH 31/71] sembr src/hir-typeck/summary.md --- src/doc/rustc-dev-guide/src/hir-typeck/summary.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/hir-typeck/summary.md b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md index ae84c1e676751..a64f6c5adaf4d 100644 --- a/src/doc/rustc-dev-guide/src/hir-typeck/summary.md +++ b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md @@ -26,8 +26,9 @@ fn foo(x: Foo, y: self::Foo) { ... } ``` Those two parameters `x` and `y` each have the same type: but they will have -distinct `hir::Ty` nodes. Those nodes will have different spans, and of course -they encode the path somewhat differently. But once they are "collected" into +distinct `hir::Ty` nodes. +Those nodes will have different spans, and of course they encode the path somewhat differently. +But once they are "collected" into `Ty<'tcx>` nodes, they will be represented by the exact same internal type. Collection is defined as a bundle of [queries] for computing information about @@ -35,8 +36,7 @@ the various functions, traits, and other items in the crate being compiled. Note that each of these queries is concerned with *interprocedural* things – for example, for a function definition, collection will figure out the type and signature of the function, but it will not visit the *body* of the function in -any way, nor examine type annotations on local variables (that's the job of -type *checking*). +any way, nor examine type annotations on local variables (that's the job of type *checking*). For more details, see the [`collect`][collect] module. From 775b4799d659cb2c8fa8e81526a25ed3e9875b34 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 18:51:43 +0200 Subject: [PATCH 32/71] unusual use of colon --- src/doc/rustc-dev-guide/src/hir-typeck/summary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/hir-typeck/summary.md b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md index a64f6c5adaf4d..5fd10663694c5 100644 --- a/src/doc/rustc-dev-guide/src/hir-typeck/summary.md +++ b/src/doc/rustc-dev-guide/src/hir-typeck/summary.md @@ -25,8 +25,8 @@ fn foo(x: Foo, y: self::Foo) { ... } // ^^^ ^^^^^^^^^ ``` -Those two parameters `x` and `y` each have the same type: but they will have -distinct `hir::Ty` nodes. +Those two parameters `x` and `y` each have the same type, +but they will have distinct `hir::Ty` nodes. Those nodes will have different spans, and of course they encode the path somewhat differently. But once they are "collected" into `Ty<'tcx>` nodes, they will be represented by the exact same internal type. From ef6ce2290a02ef8974f6dff275556cfcc96ca95b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 18:52:25 +0200 Subject: [PATCH 33/71] sembr src/debuginfo/intro.md --- .../rustc-dev-guide/src/debuginfo/intro.md | 76 ++++++++++++------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/intro.md b/src/doc/rustc-dev-guide/src/debuginfo/intro.md index 4fcf4901beefb..693aa5863fba2 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/intro.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/intro.md @@ -1,13 +1,14 @@ # Debug Info Debug info is a collection of information generated by the compiler that allows debuggers to -correctly interpret the state of a program while it is running. That includes things like mapping +correctly interpret the state of a program while it is running. +That includes things like mapping instruction addresses to lines of code in the source file, and type layout information so that bytes in memory can be read and displayed in a meaningful way. Debug info can be a slightly overloaded term, covering all the layers between Rust MIR, and the -end-user seeing the output of their debugger onscreen. In brief, the stack from beginning to end is -as follows: +end-user seeing the output of their debugger onscreen. +In brief, the stack from beginning to end is as follows: 1. Rustc inspects the MIR and communicates the relevant source, symbol, and type information to LLVM 2. LLVM translates this information into a target-specific debug info format during compilation @@ -33,51 +34,62 @@ API layers (e.g. VSCode extension by way of the # DWARF -The is the primary debug info format for `*-gnu` targets. It is typically bundled in with the -binary, but it [can be generated as a separate file](https://gcc.gnu.org/wiki/DebugFission). The -DWARF standard is available [here](https://dwarfstd.org/). +The is the primary debug info format for `*-gnu` targets. +It is typically bundled in with the +binary, but it [can be generated as a separate file](https://gcc.gnu.org/wiki/DebugFission). +The DWARF standard is available [here](https://dwarfstd.org/). > NOTE: To inspect DWARF debug info, [gimli](https://crates.io/crates/gimli) can be used > programatically. If you prefer a GUI, the author recommends [DWEX](https://github.com/sevaa/dwex) # PDB/CodeView -The primary debug info format for `*-msvc` targets. PDB is a proprietary container format created by -Microsoft that, unfortunately, +The primary debug info format for `*-msvc` targets. +PDB is a proprietary container format created by Microsoft that, unfortunately, [has multiple meanings](https://docs.rs/ms-pdb/0.1.10/ms_pdb/taster/enum.Flavor.html). -We are concerned with ordinary PDB files, as Portable PDB is used mainly for .Net applications. PDB -files are separate from the compiled binary and use the `.pdb` extension. +We are concerned with ordinary PDB files, as Portable PDB is used mainly for .Net applications. +PDB files are separate from the compiled binary and use the `.pdb` extension. -PDB files contain CodeView objects, equivalent to DWARF's tags. CodeView, the debugger that +PDB files contain CodeView objects, equivalent to DWARF's tags. +CodeView, the debugger that consumed CodeView objects, was originally released in 1985. Its original intent was for C debugging, -and was later extended to support Visual C++. There are still minor alterations to the format to +and was later extended to support Visual C++. +There are still minor alterations to the format to support modern architectures and languages, but many of these changes are undocumented and/or sparsely used. -It is important to keep this context in mind when working with CodeView objects. Due to its origins, -the "feature-set" of these objects is very limited, and focused around the core features of C. It -does not have many of the convenience or features of modern DWARF standards. A fair number of +It is important to keep this context in mind when working with CodeView objects. +Due to its origins, +the "feature-set" of these objects is very limited, and focused around the core features of C. +It does not have many of the convenience or features of modern DWARF standards. +A fair number of workarounds exist within the debug info stack to compensate for CodeView's shortcomings. -Due to its proprietary nature, it is very difficult to find information about PDB and CodeView. Many +Due to its proprietary nature, it is very difficult to find information about PDB and CodeView. +Many of the sources were made at vastly different times and contain incomplete or somewhat contradictory -information. As such this page will aim to collect as many sources as possible. +information. +As such this page will aim to collect as many sources as possible. * [TIS PE specification](https://web.archive.org/web/20260315080740/http://x-ways.net/winhex/kb/ff/PE_EXE.pdf) which includes a lengthy section titled "Microsoft Symbol and Type Information", detailing much of -the CodeView format. The document was created in 1993, but the information is still detailed, +the CodeView format. +The document was created in 1993, but the information is still detailed, accurate, and has useful diagrams. * LLVM * [CodeView Overview](https://llvm.org/docs/SourceLevelDebugging.html#codeview-debug-info-format) * [PDB Overview and technical details](https://llvm.org/docs/PDB/index.html) * Microsoft * [microsoft-pdb](https://github.com/microsoft/microsoft-pdb) - A C/C++ implementation of a PDB - reader. The implementation does not contain the full PDB or CodeView specification, but does - contain enough information for other PDB consumers to be written. At time of writing (Nov 2025), + reader. + The implementation does not contain the full PDB or CodeView specification, but does + contain enough information for other PDB consumers to be written. + At time of writing (Nov 2025), this repo has been archived for several years. * [pdb-rs](https://github.com/microsoft/pdb-rs/) - A Rust-based PDB reader and writer based on - other publicly-available information. Does not guarantee stability or spec compliance. Also - contains `pdbtool`, which can dump PDB files (`cargo install pdbtool`) + other publicly-available information. + Does not guarantee stability or spec compliance. + Also contains `pdbtool`, which can dump PDB files (`cargo install pdbtool`) * [Debug Interface Access SDK](https://learn.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/getting-started-debug-interface-access-sdk). While it does not document the PDB format directly, details can be gleaned from the interface itself. @@ -86,16 +98,20 @@ accurate, and has useful diagrams. # Debuggers -Rust supports 3 major debuggers: GDB, LLDB, and CDB. Each has its own set of requirements, -limitations, and quirks. This unfortunately creates a large surface area to account for. +Rust supports 3 major debuggers: GDB, LLDB, and CDB. +Each has its own set of requirements, +limitations, and quirks. +This unfortunately creates a large surface area to account for. > NOTE: CDB is a proprietary debugger created by Microsoft. The underlying engine also powers >WinDbg, KD, the Microsoft C/C++ extension for VSCode, and part of the Visual Studio Debugger. In >these docs, it will be referred to as CDB for consistency While GDB and LLDB do offer facilities to natively support Rust's value layout, this isn't -completely necessary. Rust currently outputs debug info very similar to that of C++, allowing -debuggers without Rust support to work with a slightly degraded experience. More detail will be +completely necessary. +Rust currently outputs debug info very similar to that of C++, allowing +debuggers without Rust support to work with a slightly degraded experience. +More detail will be included in later sections, but here is a quick reference for the capabilities of each debugger: | Debugger | Debug Info Format | Native Rust support | Expression Style | Visualizer Scripts | @@ -113,7 +129,9 @@ Below, are several unsupported debuggers that are of particular note due to thei in the future. * [Bugstalker](https://github.com/godzie44/BugStalker) is an x86-64 Linux debugger written in Rust, -specifically to debug Rust programs. While promising, it is still in early development. -* [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) is a Windows-only GUI debugger. It has -a custom debug info format that PDB is translated into. The project also includes a linker that can +specifically to debug Rust programs. +While promising, it is still in early development. +* [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) is a Windows-only GUI debugger. + It has a custom debug info format that PDB is translated into. +The project also includes a linker that can generate their new debug info format during the linking phase. From c0c28290421f55efcc50d3967cc44ffd09636df7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:05:48 +0200 Subject: [PATCH 34/71] reflow --- .../rustc-dev-guide/src/debuginfo/intro.md | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/intro.md b/src/doc/rustc-dev-guide/src/debuginfo/intro.md index 693aa5863fba2..1fa0f620024a8 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/intro.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/intro.md @@ -2,9 +2,8 @@ Debug info is a collection of information generated by the compiler that allows debuggers to correctly interpret the state of a program while it is running. -That includes things like mapping -instruction addresses to lines of code in the source file, and type layout information so that -bytes in memory can be read and displayed in a meaningful way. +That includes things like mapping instruction addresses to lines of code in the source file, +and type layout information so that bytes in memory can be read and displayed in a meaningful way. Debug info can be a slightly overloaded term, covering all the layers between Rust MIR, and the end-user seeing the output of their debugger onscreen. @@ -51,25 +50,23 @@ We are concerned with ordinary PDB files, as Portable PDB is used mainly for .Ne PDB files are separate from the compiled binary and use the `.pdb` extension. PDB files contain CodeView objects, equivalent to DWARF's tags. -CodeView, the debugger that -consumed CodeView objects, was originally released in 1985. Its original intent was for C debugging, +CodeView, the debugger that consumed CodeView objects, was originally released in 1985. +Its original intent was for C debugging, and was later extended to support Visual C++. -There are still minor alterations to the format to -support modern architectures and languages, but many of these changes are undocumented and/or -sparsely used. +There are still minor alterations to the format to support modern architectures and languages, +but many of these changes are undocumented and/or sparsely used. It is important to keep this context in mind when working with CodeView objects. Due to its origins, the "feature-set" of these objects is very limited, and focused around the core features of C. It does not have many of the convenience or features of modern DWARF standards. -A fair number of -workarounds exist within the debug info stack to compensate for CodeView's shortcomings. +A fair number of workarounds exist within the debug info stack +to compensate for CodeView's shortcomings. Due to its proprietary nature, it is very difficult to find information about PDB and CodeView. -Many -of the sources were made at vastly different times and contain incomplete or somewhat contradictory -information. -As such this page will aim to collect as many sources as possible. +Many of the sources were made at vastly different times +and contain incomplete or somewhat contradictory information. +As such, this page will aim to collect as many sources as possible. * [TIS PE specification](https://web.archive.org/web/20260315080740/http://x-ways.net/winhex/kb/ff/PE_EXE.pdf) which includes a lengthy section titled "Microsoft Symbol and Type Information", detailing much of @@ -103,16 +100,17 @@ Each has its own set of requirements, limitations, and quirks. This unfortunately creates a large surface area to account for. -> NOTE: CDB is a proprietary debugger created by Microsoft. The underlying engine also powers ->WinDbg, KD, the Microsoft C/C++ extension for VSCode, and part of the Visual Studio Debugger. In ->these docs, it will be referred to as CDB for consistency +> NOTE: CDB is a proprietary debugger created by Microsoft. +> The underlying engine also powers WinDbg, KD, the Microsoft C/C++ extension for VSCode, +> and part of the Visual Studio Debugger. +> In these docs, it will be referred to as CDB for consistency While GDB and LLDB do offer facilities to natively support Rust's value layout, this isn't completely necessary. Rust currently outputs debug info very similar to that of C++, allowing debuggers without Rust support to work with a slightly degraded experience. -More detail will be -included in later sections, but here is a quick reference for the capabilities of each debugger: +More detail will be included in later sections, +but here is a quick reference for the capabilities of each debugger: | Debugger | Debug Info Format | Native Rust support | Expression Style | Visualizer Scripts | | --- | --- | --- | --- | --- | @@ -129,9 +127,9 @@ Below, are several unsupported debuggers that are of particular note due to thei in the future. * [Bugstalker](https://github.com/godzie44/BugStalker) is an x86-64 Linux debugger written in Rust, -specifically to debug Rust programs. -While promising, it is still in early development. + specifically to debug Rust programs. + While promising, it is still in early development. * [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) is a Windows-only GUI debugger. It has a custom debug info format that PDB is translated into. -The project also includes a linker that can -generate their new debug info format during the linking phase. + The project also includes a linker that can generate their new debug info format + during the linking phase. From 53e1b93c494aedf85c3009c29f6c45ce6bdec2f9 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:09:57 +0200 Subject: [PATCH 35/71] sembr src/debuginfo/rust-codegen.md --- .../src/debuginfo/rust-codegen.md | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md index 73fa68d36076a..869e209b7b0a4 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md @@ -1,8 +1,10 @@ # Rust Codegen The first phase in debug info generation requires Rust to inspect the MIR of the program and -communicate it to LLVM. This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though -some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. Rust communicates to +communicate it to LLVM. +This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though +some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. +Rust communicates to LLVM via the `DIBuilder` API - a thin wrapper around LLVM's internals that exists in [rustc_llvm][rustc_llvm]. @@ -13,31 +15,33 @@ LLVM via the `DIBuilder` API - a thin wrapper around LLVM's internals that exist # Type Information Type information typically consists of the type name, size, alignment, as well as things like -fields, generic parameters, and storage modifiers if they are relevant. Much of this work happens in -[rustc_codegen_llvm/src/debuginfo/metadata][di_metadata]. +fields, generic parameters, and storage modifiers if they are relevant. +Much of this work happens in [rustc_codegen_llvm/src/debuginfo/metadata][di_metadata]. [di_metadata]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs It is important to keep in mind that the goal is not necessarily "represent types exactly how they appear in Rust", rather it is to represent them in a way that allows debuggers to most accurately -reconstruct the data during debugging. This distinction is vital to understanding the core work that +reconstruct the data during debugging. +This distinction is vital to understanding the core work that occurs on this layer; many changes made here will be for the purpose of working around debugger limitations when no other option will work. ## Quirks -Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. This can result in -some unintuitive and non-idiomatic debug info. +Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. +This can result in some unintuitive and non-idiomatic debug info. ### Pointers and Reference Wide pointers/references/`Box` are treated as a struct with 2 fields: `data_ptr` and `length`. All non-wide pointers, references, and `Box` pointers are output as pointer nodes, and no -distinction is made between `mut` and non-`mut`. Several attempts have been made to rectify this, -but unfortunately there is not a straightforward solution. Using the `reference` DI nodes of the -respective formats has pitfalls. There is a semantic difference between C++ references and Rust -references that is unreconcilable. +distinction is made between `mut` and non-`mut`. +Several attempts have been made to rectify this, +but unfortunately there is not a straightforward solution. +Using the `reference` DI nodes of the respective formats has pitfalls. +There is a semantic difference between C++ references and Rust references that is unreconcilable. >From [cppreference](https://en.cppreference.com/w/cpp/language/reference.html): > @@ -54,16 +58,19 @@ The current proposed solution is to simply [typedef the pointer nodes][issue_144 Using the `const` qualifier to denote non-`mut` poses potential issues due to LLDB's internal optimizations. In short, LLDB attempts to cache the child-values of variables (e.g. struct fields, -array elements) when stepping through code. A heuristic is used to determine which values are safely -cache-able, and `const` is part of that heuristic. Research has not been done into how this would +array elements) when stepping through code. +A heuristic is used to determine which values are safely +cache-able, and `const` is part of that heuristic. +Research has not been done into how this would interact with things like Rust's interior mutability constructs. ### DWARF vs PDB While most of the type information is fairly straight forward, one notable issue is the debug info -format of the target. Each format has different semantics and limitations, as such they require -slightly different debug info in some cases. This is gated by calls to -[`cpp_like_debuginfo`][cpp_like]. +format of the target. +Each format has different semantics and limitations, as such they require +slightly different debug info in some cases. +This is gated by calls to [`cpp_like_debuginfo`][cpp_like]. [cpp_like]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs#L813 @@ -97,7 +104,8 @@ consecutive `>`'s with a space (`> >`) in type names. [^2]: While these type names are generated as part of the debug info node (which is then wrapped in a typedef node with the Rust name), once the LLVM-IR node is converted to a CodeView node, the type -name information is lost. This is because CodeView has special shorthand nodes for primitive types, +name information is lost. +This is because CodeView has special shorthand nodes for primitive types, and those shorthand nodes to not have a "name" field. ### Generics @@ -106,8 +114,10 @@ Rust outputs generic *type* information (`T` in `ArrayVec`), but no information (`N` in `ArrayVec`). CodeView does not have a leaf node for generics/C++ templates, so all generic information is lost -when generating PDB debug info. There are workarounds that allow the debugger to retrieve the -generic arguments via the type name, but it is fragile solution at best. Efforts are being made to +when generating PDB debug info. +There are workarounds that allow the debugger to retrieve the +generic arguments via the type name, but it is fragile solution at best. +Efforts are being made to contact Microsoft to correct this deficiency, and/or to use one of the unused CodeView node types as a suitable equivalent. @@ -126,9 +136,10 @@ Enum DI nodes are generated in [rustc_codegen_llvm/src/debuginfo/metadata/enums] #### DWARF -DWARF has a dedicated node for discriminated unions: `DW_TAG_variant`. It is a container that -references `DW_TAG_variant_part` nodes that may or may not contain a discriminant value. The -hierarchy looks as follows: +DWARF has a dedicated node for discriminated unions: `DW_TAG_variant`. +It is a container that +references `DW_TAG_variant_part` nodes that may or may not contain a discriminant value. +The hierarchy looks as follows: ```txt DW_TAG_structure_type (top-level type for the coroutine) @@ -175,9 +186,10 @@ union enum2$ { ``` An important note is that due to limitations in LLDB, the `DISCR_*` value generated is always a -`u64` even if the value is not `#[repr(u64)]`. This is largely a non-issue for LLDB because the +`u64` even if the value is not `#[repr(u64)]`. +This is largely a non-issue for LLDB because the `DISCR_*` value and the `tag` are read into `uint64_t` values regardless of their type. # Source Information -TODO \ No newline at end of file +TODO From ff8c0c5d8fa4773313b7d5ae8262ea313be61925 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:20:57 +0200 Subject: [PATCH 36/71] reflow --- .../rustc-dev-guide/src/debuginfo/rust-codegen.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md index 869e209b7b0a4..2228007f9bcd1 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md @@ -4,9 +4,8 @@ The first phase in debug info generation requires Rust to inspect the MIR of the communicate it to LLVM. This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. -Rust communicates to -LLVM via the `DIBuilder` API - a thin wrapper around LLVM's internals that exists in -[rustc_llvm][rustc_llvm]. +Rust communicates to LLVM via the `DIBuilder` API, +a thin wrapper around LLVM's internals that exists in [rustc_llvm][rustc_llvm]. [llvm_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_llvm/src/debuginfo [ssa_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_ssa/src/debuginfo @@ -117,9 +116,8 @@ CodeView does not have a leaf node for generics/C++ templates, so all generic in when generating PDB debug info. There are workarounds that allow the debugger to retrieve the generic arguments via the type name, but it is fragile solution at best. -Efforts are being made to -contact Microsoft to correct this deficiency, and/or to use one of the unused CodeView node types as -a suitable equivalent. +Efforts are being made to contact Microsoft to correct this deficiency, +and/or to use one of the unused CodeView node types as a suitable equivalent. ### Type aliases @@ -137,8 +135,8 @@ Enum DI nodes are generated in [rustc_codegen_llvm/src/debuginfo/metadata/enums] #### DWARF DWARF has a dedicated node for discriminated unions: `DW_TAG_variant`. -It is a container that -references `DW_TAG_variant_part` nodes that may or may not contain a discriminant value. +It is a container that references `DW_TAG_variant_part` nodes +that may or may not contain a discriminant value. The hierarchy looks as follows: ```txt From 5fab7f9448553dc5c19940bd2936a8aa6c91a4ef Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 20 Jul 2026 17:24:43 +0000 Subject: [PATCH 37/71] Prepare for merging from rust-lang/rust This updates the rust-version file to 9e71b3bc704eea68d39bd0f6a46703c7d22f5d3b. --- 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 f930573748e28..a48a44e5d15fb 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -7fb284d9037fa54f6a9b24261c82b394472cbfd7 +9e71b3bc704eea68d39bd0f6a46703c7d22f5d3b From 890741bf2600904b9adc6d5131d1a8aa8ebe98fd Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:29:46 +0200 Subject: [PATCH 38/71] lighter markup --- src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md index 2228007f9bcd1..b68536e43b6f7 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md @@ -5,7 +5,7 @@ communicate it to LLVM. This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. Rust communicates to LLVM via the `DIBuilder` API, -a thin wrapper around LLVM's internals that exists in [rustc_llvm][rustc_llvm]. +a thin wrapper around LLVM's internals that exists in [rustc_llvm]. [llvm_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_llvm/src/debuginfo [ssa_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_ssa/src/debuginfo @@ -51,9 +51,9 @@ There is a semantic difference between C++ references and Rust references that i > >Because references are not objects, **there are no arrays of references, no pointers to references, and no references to references** -The current proposed solution is to simply [typedef the pointer nodes][issue_144394]. +The current proposed solution is to simply [typedef the pointer nodes]. -[issue_144394]: https://github.com/rust-lang/rust/pull/144394 +[typedef the pointer nodes]: https://github.com/rust-lang/rust/pull/144394 Using the `const` qualifier to denote non-`mut` poses potential issues due to LLDB's internal optimizations. In short, LLDB attempts to cache the child-values of variables (e.g. struct fields, @@ -69,9 +69,9 @@ While most of the type information is fairly straight forward, one notable issue format of the target. Each format has different semantics and limitations, as such they require slightly different debug info in some cases. -This is gated by calls to [`cpp_like_debuginfo`][cpp_like]. +This is gated by calls to [`cpp_like_debuginfo`]. -[cpp_like]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs#L813 +[`cpp_like_debuginfo`]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs#L813 ### Naming From d6be727b10cbbcfffcad49814f5c758cca04133b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:33:16 +0200 Subject: [PATCH 39/71] use sentence case for titles --- src/doc/rustc-dev-guide/src/SUMMARY.md | 4 ++-- src/doc/rustc-dev-guide/src/debuginfo/intro.md | 2 +- src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 91bb143eb318f..cc3fece79dd78 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -239,8 +239,8 @@ - [Debugging LLVM](./backend/debugging.md) - [Backend Agnostic Codegen](./backend/backend-agnostic.md) - [Implicit caller location](./backend/implicit-caller-location.md) -- [Debug Info](./debuginfo/intro.md) - - [Rust Codegen](./debuginfo/rust-codegen.md) +- [Debug info](./debuginfo/intro.md) + - [Rust codegen](./debuginfo/rust-codegen.md) - [LLVM Codegen](./debuginfo/llvm-codegen.md) - [Debugger Internals](./debuginfo/debugger-internals.md) - [LLDB Internals](./debuginfo/lldb-internals.md) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/intro.md b/src/doc/rustc-dev-guide/src/debuginfo/intro.md index 1fa0f620024a8..e8c4d11d12b0a 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/intro.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/intro.md @@ -1,4 +1,4 @@ -# Debug Info +# Debug info Debug info is a collection of information generated by the compiler that allows debuggers to correctly interpret the state of a program while it is running. diff --git a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md index b68536e43b6f7..fc3b5270a2e8b 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md @@ -1,4 +1,4 @@ -# Rust Codegen +# Rust codegen The first phase in debug info generation requires Rust to inspect the MIR of the program and communicate it to LLVM. @@ -11,7 +11,7 @@ a thin wrapper around LLVM's internals that exists in [rustc_llvm]. [ssa_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_ssa/src/debuginfo [rustc_llvm]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_llvm -# Type Information +# Type information Type information typically consists of the type name, size, alignment, as well as things like fields, generic parameters, and storage modifiers if they are relevant. @@ -31,7 +31,7 @@ limitations when no other option will work. Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. This can result in some unintuitive and non-idiomatic debug info. -### Pointers and Reference +### Pointers and reference Wide pointers/references/`Box` are treated as a struct with 2 fields: `data_ptr` and `length`. @@ -188,6 +188,6 @@ An important note is that due to limitations in LLDB, the `DISCR_*` value genera This is largely a non-issue for LLDB because the `DISCR_*` value and the `tag` are read into `uint64_t` values regardless of their type. -# Source Information +# Source information TODO From 147ffe4a55bf32f7d1c1a27ec40b35587c3c4be3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:33:41 +0200 Subject: [PATCH 40/71] fix section title --- src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md index fc3b5270a2e8b..f879579de9907 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md @@ -31,7 +31,7 @@ limitations when no other option will work. Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. This can result in some unintuitive and non-idiomatic debug info. -### Pointers and reference +### Pointers and references Wide pointers/references/`Box` are treated as a struct with 2 fields: `data_ptr` and `length`. From 1064b07aafff40e0d326c0f9c44be850088ac612 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:36:58 +0200 Subject: [PATCH 41/71] it will happen when it does --- src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md | 2 +- src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md | 2 +- src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md | 2 +- src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md | 2 +- src/doc/rustc-dev-guide/src/debuginfo/testing.md | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md index 95f543c8e94a0..619fb86e158a7 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md @@ -1,4 +1,4 @@ -# (WIP) GDB Internals +# GDB internals GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. The expression parsing support can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md index 4027ef897f28a..3f8fb3bf439a5 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md @@ -1,4 +1,4 @@ -# (WIP) GDB - Python Providers +# GDB - Python Providers Below are links to relevant parts of the GDB documentation 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 cc052b6b965f1..67df1092bd3ba 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md @@ -1,4 +1,4 @@ -# (WIP) LLVM Codegen +# LLVM codegen 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. diff --git a/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md index 653e7d5d65555..1b156465f4f85 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md @@ -1,3 +1,3 @@ -# (WIP) CDB - Natvis +# CDB - Natvis Official documentation for Natvis can be found [here](https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects) and [here](https://code.visualstudio.com/docs/cpp/natvis) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/testing.md b/src/doc/rustc-dev-guide/src/debuginfo/testing.md index f58050875e1a0..7aec83aa97ac6 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/testing.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/testing.md @@ -1,8 +1,8 @@ -# (WIP) Testing +# Testing The debug info test suite is undergoing a substantial rewrite. This section will be filled out as the rewrite makes progress. Please see [this tracking issue][148483] for more information. -[148483]: https://github.com/rust-lang/rust/issues/148483 \ No newline at end of file +[148483]: https://github.com/rust-lang/rust/issues/148483 From 6af61079b4a73e6274fb5b8490394ebc64ef752b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:44:50 +0200 Subject: [PATCH 42/71] use sentence case for titles --- src/doc/rustc-dev-guide/src/SUMMARY.md | 12 ++++++------ .../src/debuginfo/debugger-internals.md | 4 ++-- .../src/debuginfo/debugger-visualizers.md | 4 ++-- .../rustc-dev-guide/src/debuginfo/gdb-internals.md | 2 +- .../rustc-dev-guide/src/debuginfo/lldb-internals.md | 12 ++++++------ .../src/debuginfo/lldb-visualizers.md | 4 ++-- .../rustc-dev-guide/src/debuginfo/llvm-codegen.md | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index cc3fece79dd78..3b6d0a5032974 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -241,16 +241,16 @@ - [Implicit caller location](./backend/implicit-caller-location.md) - [Debug info](./debuginfo/intro.md) - [Rust codegen](./debuginfo/rust-codegen.md) - - [LLVM Codegen](./debuginfo/llvm-codegen.md) - - [Debugger Internals](./debuginfo/debugger-internals.md) - - [LLDB Internals](./debuginfo/lldb-internals.md) - - [GDB Internals](./debuginfo/gdb-internals.md) - - [Debugger Visualizers](./debuginfo/debugger-visualizers.md) + - [LLVM codegen](./debuginfo/llvm-codegen.md) + - [Debugger internals](./debuginfo/debugger-internals.md) + - [LLDB internals](./debuginfo/lldb-internals.md) + - [GDB internals](./debuginfo/gdb-internals.md) + - [Debugger visualizers](./debuginfo/debugger-visualizers.md) - [LLDB - Python Providers](./debuginfo/lldb-visualizers.md) - [GDB - Python Providers](./debuginfo/gdb-visualizers.md) - [CDB - Natvis](./debuginfo/natvis-visualizers.md) - [Testing](./debuginfo/testing.md) - - [(Lecture Notes) Debugging support in the Rust compiler](./debugging-support-in-rustc.md) + - [(Lecture notes) Debugging support in the Rust compiler](./debugging-support-in-rustc.md) - [Libraries and metadata](./backend/libs-and-metadata.md) - [Profile-guided optimization](./profile-guided-optimization.md) - [LLVM source-based code coverage](./llvm-coverage-instrumentation.md) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md index 114ce8a998c58..4aec0befcf76c 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md @@ -1,4 +1,4 @@ -# Debugger Internals +# Debugger internals It is the debugger's job to convert the debug info into an in-memory representation. Both the interpretation of the debug info and the in-memory representation are arbitrary; anything will do @@ -11,4 +11,4 @@ interpret and display the data, a way for users to interact with it, and an API Debuggers are vast systems and cannot be covered completely here. This section will provide a brief overview of the subsystems directly relevant to the Rust debugging experience. -Microsoft's debugging engine is closed source, so it will not be covered here. \ No newline at end of file +Microsoft's debugging engine is closed source, so it will not be covered here. diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md index 831acbd2f8f8e..e3b82b1d4a421 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md @@ -1,4 +1,4 @@ -# Debugger Visualizers +# Debugger visualizers These are typically the last step before the debugger displays the information, but the results may be piped through a debug adapter such as an IDE's debugger API. @@ -108,4 +108,4 @@ noticable amount. This does require you to name your fields in advance and initi * List comprehensions are typically faster than loops, generator comprehensions are a bit slower than list comprehensions, but use less memory. You can think of comprehensions as equivalent to Rust's `iter.map()`. List comprehensions effectively call `collect::>` at the end, whereas -generator comprehensions do not. \ No newline at end of file +generator comprehensions do not. diff --git a/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md index 619fb86e158a7..8959f5d719c4e 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md @@ -1,4 +1,4 @@ # GDB internals GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. The expression parsing support -can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` \ No newline at end of file +can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` diff --git a/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md index e104f1d245327..8119662b3d791 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md @@ -1,4 +1,4 @@ -# LLDB Internals +# LLDB internals LLDB's debug info processing relies on a set of extensible interfaces largely defined in [lldb/src/Plugins][lldb_plugins]. These are meant to allow third-party compiler developers to add @@ -19,7 +19,7 @@ Here are some existing implementations of LLDB's plugin API: This was written before the `TypeSystem` API was created. Due to the freeform nature of expression parsing, the underlyng lexing, parsing, function calling, etc. should still offer valuable insights. -## Rust Support and TypeSystemClang +## Rust support and TypeSystemClang As mentioned in the debug info overview, LLDB has partial Rust support. To further clarify, Rust uses the plugin-pipeline that was built for C/C++ (though it contains some helpers for Rust enum @@ -63,7 +63,7 @@ from scratch using publicly available information about the PDB format. [dia_discourse]: https://discourse.llvm.org/t/rfc-removing-the-dia-pdb-plugin-from-lldb/87827 [dia_tracking]: https://github.com/llvm/llvm-project/issues/114906 -## Debug Node Parsing +## Debug node parsing The first step is to process the raw debug nodes into something usable. This primarily occurs in the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. These classes are fed a @@ -135,7 +135,7 @@ impl TypeSystem for TypeSystemLang { } ``` -## Type Systems +## Type systems The [`TypeSystem` interface][ts_interface] has 3 major purposes: @@ -172,7 +172,7 @@ alterations as possible. LLDB's synthetics and frontend can handle making the ty piece of information is useless, the Rust compiler should be altered to not output that debug info in the first place. -## Expression Parsing +## Expression parsing The `TypeSystem` is typically written to have a counterpart that can handle expression parsing. It requires implementing a few extra functions in the `TypeSystem` interface. The bulk of the @@ -205,4 +205,4 @@ may be a good stepping stone towards full language support in LLDB. ## Visualizers -WIP \ No newline at end of file +WIP diff --git a/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md index 83e2b0d5794e8..58d4bd068f5bb 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md @@ -330,7 +330,7 @@ of the synthetic. By implementing an instance summary, we can retrieve the variant name via `self.variant.GetTypeName()` and some string manipulation. -# Writing Visualizer Scripts +# Writing visualizer scripts > IMPORTANT: Unlike GDB and CDB, LLDB can debug executables with either DWARF or PDB debug info. >Visualizers must be written to account for both formats whenever possible. See: @@ -373,7 +373,7 @@ use depending on what version of LLDB the script detects. This is vital for backwards compatibility once we begin using recognizer functions, as recognizers were added in lldb 19.0. -## Visualizer Resolution +## Visualizer resolution The order that visualizers resolve in is listed [here][formatters_101]. In short: 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 67df1092bd3ba..3b6bd454b29f2 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md @@ -9,4 +9,4 @@ It is important to note that tags within the debug records are **always stored a 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 \ No newline at end of file +[cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp From df163d8428f96e5eea47d4b9ba85ca1f586b6327 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:46:38 +0200 Subject: [PATCH 43/71] sembr src/debuginfo/debugger-internals.md --- .../src/debuginfo/debugger-internals.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md index 4aec0befcf76c..574bb3be6a0d2 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md @@ -1,14 +1,16 @@ # Debugger internals -It is the debugger's job to convert the debug info into an in-memory representation. Both the +It is the debugger's job to convert the debug info into an in-memory representation. +Both the interpretation of the debug info and the in-memory representation are arbitrary; anything will do -so long as meaningful information can be reconstructed while the program is running. The pipeline -from raw debug info to usable types can be quite complicated. +so long as meaningful information can be reconstructed while the program is running. +The pipeline from raw debug info to usable types can be quite complicated. Once the information is in a workable format, the debugger front-end then must provide a way to interpret and display the data, a way for users to interact with it, and an API for extensibility. -Debuggers are vast systems and cannot be covered completely here. This section will provide a brief +Debuggers are vast systems and cannot be covered completely here. +This section will provide a brief overview of the subsystems directly relevant to the Rust debugging experience. Microsoft's debugging engine is closed source, so it will not be covered here. From 3b999caee652bc1c9c8c9fc7f59eb925fd78f3f5 Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 20 Jul 2026 01:59:14 +0200 Subject: [PATCH 44/71] bless batch --- .../const-bytes-slice-pattern.rs | 3 ++ ...ross-crate-multibyte-debuginfo-comments.rs | 11 +++--- .../cross-crate-multibyte-debuginfo.rs | 10 +++--- .../cross-crate-multibyte-debuginfo.rs | 5 +-- .../fru-unknown-field-in-closure.rs | 3 ++ .../fru-unknown-field-in-closure.stderr | 2 +- .../for-loop-nested-array-inference.rs | 3 ++ .../for-loop-nested-array-inference.stderr | 2 +- .../issue-67039-unsound-pin-partialeq.rs | 27 -------------- .../issue-67039-unsound-pin-partialeq.stderr | 13 ------- .../repetition-matches-empty-token-tree.rs | 9 ++--- ...repetition-matches-empty-token-tree.stderr | 36 +++++++++---------- .../ui/moves/move-out-of-shared-ref-deref.rs | 2 ++ .../moves/move-out-of-shared-ref-deref.stderr | 2 +- .../struct-pattern-nonexistent-field.rs | 3 ++ .../struct-pattern-nonexistent-field.stderr | 6 ++-- .../call-tuple-struct-ctor-as-fn.rs | 2 ++ .../object/extern-c-trait-object-methods.rs | 3 ++ 18 files changed, 62 insertions(+), 80 deletions(-) delete mode 100644 tests/ui/issues/issue-67039-unsound-pin-partialeq.rs delete mode 100644 tests/ui/issues/issue-67039-unsound-pin-partialeq.stderr diff --git a/tests/ui/consts/const_in_pattern/const-bytes-slice-pattern.rs b/tests/ui/consts/const_in_pattern/const-bytes-slice-pattern.rs index 05f71623d1419..028c7a74bd640 100644 --- a/tests/ui/consts/const_in_pattern/const-bytes-slice-pattern.rs +++ b/tests/ui/consts/const_in_pattern/const-bytes-slice-pattern.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! This used to ICE. //@ check-pass + #![allow(dead_code)] const PATH_DOT: &[u8] = &[b'.']; diff --git a/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo-comments.rs b/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo-comments.rs index 215145a64b177..eec8c8e1d0d4e 100644 --- a/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo-comments.rs +++ b/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo-comments.rs @@ -1,9 +1,10 @@ -use std::fmt; +//! Auxiliary file for . +//! This is a file with many multi-byte characters, to try to encourage +//! the compiler to trip on them. The Drop implementation below will +//! need to have its source location embedded into the debug info for +//! the output file. -// This ia file with many multi-byte characters, to try to encourage -// the compiler to trip on them. The Drop implementation below will -// need to have its source location embedded into the debug info for -// the output file. +use std::fmt; // αααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααα // ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ diff --git a/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo.rs b/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo.rs index 5b1b1389cebb3..695fccc4519a8 100644 --- a/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo.rs +++ b/tests/ui/debuginfo/auxiliary/cross-crate-multibyte-debuginfo.rs @@ -1,10 +1,10 @@ +//! Auxiliary file for . +//! This is a file that pulls in a separate file as a submodule, where +//! that separate file has many multi-byte characters, to try to +//! encourage the compiler to trip on them. #![crate_type="lib"] -// This is a file that pulls in a separate file as a submodule, where -// that separate file has many multi-byte characters, to try to -// encourage the compiler to trip on them. - -#[path = "issue-24687-mbcs-in-comments.rs"] +#[path = "cross-crate-multibyte-debuginfo-comments.rs"] mod issue_24687_mbcs_in_comments; pub use issue_24687_mbcs_in_comments::D; diff --git a/tests/ui/debuginfo/cross-crate-multibyte-debuginfo.rs b/tests/ui/debuginfo/cross-crate-multibyte-debuginfo.rs index d1ab717264b4c..026aecaa5f277 100644 --- a/tests/ui/debuginfo/cross-crate-multibyte-debuginfo.rs +++ b/tests/ui/debuginfo/cross-crate-multibyte-debuginfo.rs @@ -1,8 +1,9 @@ +//! Regression test for . //@ run-pass -//@ aux-build:issue-24687-lib.rs +//@ aux-build:cross-crate-multibyte-debuginfo.rs //@ compile-flags:-g -extern crate issue_24687_lib as d; +extern crate cross_crate_multibyte_debuginfo as d; fn main() { // Create a `D`, which has a destructor whose body will be codegen'ed diff --git a/tests/ui/functional-struct-update/fru-unknown-field-in-closure.rs b/tests/ui/functional-struct-update/fru-unknown-field-in-closure.rs index 5f762bc431e12..c9fb4e2774938 100644 --- a/tests/ui/functional-struct-update/fru-unknown-field-in-closure.rs +++ b/tests/ui/functional-struct-update/fru-unknown-field-in-closure.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! This used to ICE. + struct Point { pub x: u64, pub y: u64, diff --git a/tests/ui/functional-struct-update/fru-unknown-field-in-closure.stderr b/tests/ui/functional-struct-update/fru-unknown-field-in-closure.stderr index 1a3514fb715d1..990e65c87aaae 100644 --- a/tests/ui/functional-struct-update/fru-unknown-field-in-closure.stderr +++ b/tests/ui/functional-struct-update/fru-unknown-field-in-closure.stderr @@ -1,5 +1,5 @@ error[E0560]: struct `Point` has no field named `nonexistent` - --> $DIR/issue-50618.rs:14:13 + --> $DIR/fru-unknown-field-in-closure.rs:17:13 | LL | nonexistent: 0, | ^^^^^^^^^^^ `Point` does not have this field diff --git a/tests/ui/inference/need_type_info/for-loop-nested-array-inference.rs b/tests/ui/inference/need_type_info/for-loop-nested-array-inference.rs index 4c21cbfc61d43..a6f35620fcc9b 100644 --- a/tests/ui/inference/need_type_info/for-loop-nested-array-inference.rs +++ b/tests/ui/inference/need_type_info/for-loop-nested-array-inference.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! This used to leak internal `__next` ident into suggestion. + fn main() { let tiles = Default::default(); for row in &mut tiles { diff --git a/tests/ui/inference/need_type_info/for-loop-nested-array-inference.stderr b/tests/ui/inference/need_type_info/for-loop-nested-array-inference.stderr index 4839a0d46095f..75f84797cecd9 100644 --- a/tests/ui/inference/need_type_info/for-loop-nested-array-inference.stderr +++ b/tests/ui/inference/need_type_info/for-loop-nested-array-inference.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-51116.rs:5:13 + --> $DIR/for-loop-nested-array-inference.rs:8:13 | LL | *tile = 0; | ^^^^^ cannot infer type diff --git a/tests/ui/issues/issue-67039-unsound-pin-partialeq.rs b/tests/ui/issues/issue-67039-unsound-pin-partialeq.rs deleted file mode 100644 index a496e58a79bdd..0000000000000 --- a/tests/ui/issues/issue-67039-unsound-pin-partialeq.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Pin's PartialEq implementation allowed to access the pointer allowing for -// unsoundness by using Rc::get_mut to move value within Rc. -// See https://internals.rust-lang.org/t/unsoundness-in-pin/11311/73 for more details. - -use std::ops::Deref; -use std::pin::Pin; -use std::rc::Rc; - -struct Apple; - -impl Deref for Apple { - type Target = Apple; - fn deref(&self) -> &Apple { - &Apple - } -} - -impl PartialEq> for Apple { - fn eq(&self, _rc: &Rc) -> bool { - unreachable!() - } -} - -fn main() { - let _ = Pin::new(Apple) == Rc::pin(Apple); - //~^ ERROR type mismatch resolving -} diff --git a/tests/ui/issues/issue-67039-unsound-pin-partialeq.stderr b/tests/ui/issues/issue-67039-unsound-pin-partialeq.stderr deleted file mode 100644 index 9164e4696eb34..0000000000000 --- a/tests/ui/issues/issue-67039-unsound-pin-partialeq.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0271]: type mismatch resolving ` as Deref>::Target == Rc` - --> $DIR/issue-67039-unsound-pin-partialeq.rs:25:29 - | -LL | let _ = Pin::new(Apple) == Rc::pin(Apple); - | ^^ expected `Rc`, found `Apple` - | - = note: expected struct `Rc` - found struct `Apple` - = note: required for `Pin` to implement `PartialEq>>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/macros/repetition-matches-empty-token-tree.rs b/tests/ui/macros/repetition-matches-empty-token-tree.rs index 47d07f0df014c..eb722764fc63a 100644 --- a/tests/ui/macros/repetition-matches-empty-token-tree.rs +++ b/tests/ui/macros/repetition-matches-empty-token-tree.rs @@ -1,10 +1,11 @@ -#![allow(unused_macros)] - -// Tests that repetition matchers cannot match the empty token tree (since that would be -// ambiguous). +//! Regression test for . +//! Tests that repetition matchers cannot match the empty token tree (since that would be +//! ambiguous). //@ edition:2018 +#![allow(unused_macros)] + macro_rules! foo { ( $()* ) => {}; //~^ ERROR repetition matches empty token tree diff --git a/tests/ui/macros/repetition-matches-empty-token-tree.stderr b/tests/ui/macros/repetition-matches-empty-token-tree.stderr index 7ffc6071407c5..eba436c233ca7 100644 --- a/tests/ui/macros/repetition-matches-empty-token-tree.stderr +++ b/tests/ui/macros/repetition-matches-empty-token-tree.stderr @@ -1,107 +1,107 @@ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:9:8 + --> $DIR/repetition-matches-empty-token-tree.rs:10:8 | LL | ( $()* ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:11:8 + --> $DIR/repetition-matches-empty-token-tree.rs:12:8 | LL | ( $()+ ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:13:8 + --> $DIR/repetition-matches-empty-token-tree.rs:14:8 | LL | ( $()? ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:18:9 + --> $DIR/repetition-matches-empty-token-tree.rs:19:9 | LL | ( [$()*] ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:20:9 + --> $DIR/repetition-matches-empty-token-tree.rs:21:9 | LL | ( [$()+] ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:22:9 + --> $DIR/repetition-matches-empty-token-tree.rs:23:9 | LL | ( [$()?] ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:27:8 + --> $DIR/repetition-matches-empty-token-tree.rs:28:8 | LL | ( $($()* $(),* $(a)* $(a),* )* ) => {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:29:8 + --> $DIR/repetition-matches-empty-token-tree.rs:30:8 | LL | ( $($()* $(),* $(a)* $(a),* )+ ) => {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:31:8 + --> $DIR/repetition-matches-empty-token-tree.rs:32:8 | LL | ( $($()* $(),* $(a)* $(a),* )? ) => {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:33:8 + --> $DIR/repetition-matches-empty-token-tree.rs:34:8 | LL | ( $($()? $(),* $(a)? $(a),* )* ) => {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:35:8 + --> $DIR/repetition-matches-empty-token-tree.rs:36:8 | LL | ( $($()? $(),* $(a)? $(a),* )+ ) => {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:37:8 + --> $DIR/repetition-matches-empty-token-tree.rs:38:8 | LL | ( $($()? $(),* $(a)? $(a),* )? ) => {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:47:12 + --> $DIR/repetition-matches-empty-token-tree.rs:48:12 | LL | ( $(a $()+)* ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:49:12 + --> $DIR/repetition-matches-empty-token-tree.rs:50:12 | LL | ( $(a $()*)+ ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:51:12 + --> $DIR/repetition-matches-empty-token-tree.rs:52:12 | LL | ( $(a $()+)? ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:53:12 + --> $DIR/repetition-matches-empty-token-tree.rs:54:12 | LL | ( $(a $()?)+ ) => {}; | ^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:60:18 + --> $DIR/repetition-matches-empty-token-tree.rs:61:18 | LL | (a $e1:expr $($(, a $e2:expr)*)*) => ([$e1 $($(, $e2)*)*]); | ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree - --> $DIR/issue-5067.rs:71:8 + --> $DIR/repetition-matches-empty-token-tree.rs:72:8 | LL | ( $()* ) => {}; | ^^ diff --git a/tests/ui/moves/move-out-of-shared-ref-deref.rs b/tests/ui/moves/move-out-of-shared-ref-deref.rs index 547643f0d6e20..6adb7811c5d4d 100644 --- a/tests/ui/moves/move-out-of-shared-ref-deref.rs +++ b/tests/ui/moves/move-out-of-shared-ref-deref.rs @@ -1,3 +1,5 @@ +//! Regression test for . + #[derive(Debug)] enum MyError { NotFound { key: Vec }, diff --git a/tests/ui/moves/move-out-of-shared-ref-deref.stderr b/tests/ui/moves/move-out-of-shared-ref-deref.stderr index 51959f22b97a4..7a7158dfbdbef 100644 --- a/tests/ui/moves/move-out-of-shared-ref-deref.stderr +++ b/tests/ui/moves/move-out-of-shared-ref-deref.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `*key` which is behind a shared reference - --> $DIR/issue-52262.rs:15:35 + --> $DIR/move-out-of-shared-ref-deref.rs:17:35 | LL | String::from_utf8(*key).unwrap() | ^^^^ move occurs because `*key` has type `Vec`, which does not implement the `Copy` trait diff --git a/tests/ui/pattern/struct-pattern-nonexistent-field.rs b/tests/ui/pattern/struct-pattern-nonexistent-field.rs index b5ddc7221d06a..ed74bdf937145 100644 --- a/tests/ui/pattern/struct-pattern-nonexistent-field.rs +++ b/tests/ui/pattern/struct-pattern-nonexistent-field.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Test matching non-existing fields via struct pattern syntax in closures doesn't ICE. + enum SimpleEnum { NoState, } diff --git a/tests/ui/pattern/struct-pattern-nonexistent-field.stderr b/tests/ui/pattern/struct-pattern-nonexistent-field.stderr index 09c52292dccaf..4eddc55bb5490 100644 --- a/tests/ui/pattern/struct-pattern-nonexistent-field.stderr +++ b/tests/ui/pattern/struct-pattern-nonexistent-field.stderr @@ -1,5 +1,5 @@ error[E0026]: struct `SimpleStruct` does not have a field named `state` - --> $DIR/issue-51102.rs:13:17 + --> $DIR/struct-pattern-nonexistent-field.rs:16:17 | LL | state: 0, | ^^^^^ @@ -8,7 +8,7 @@ LL | state: 0, | help: `SimpleStruct` has a field named `no_state_here` error[E0025]: field `no_state_here` bound multiple times in the pattern - --> $DIR/issue-51102.rs:24:17 + --> $DIR/struct-pattern-nonexistent-field.rs:27:17 | LL | no_state_here: 0, | ---------------- first use of `no_state_here` @@ -16,7 +16,7 @@ LL | no_state_here: 1 | ^^^^^^^^^^^^^^^^ multiple uses of `no_state_here` in pattern error[E0026]: variant `SimpleEnum::NoState` does not have a field named `state` - --> $DIR/issue-51102.rs:33:17 + --> $DIR/struct-pattern-nonexistent-field.rs:36:17 | LL | state: 0 | ^^^^^ variant `SimpleEnum::NoState` does not have this field diff --git a/tests/ui/structs-enums/call-tuple-struct-ctor-as-fn.rs b/tests/ui/structs-enums/call-tuple-struct-ctor-as-fn.rs index 29a6f8f2934a1..b715c9d3eaab2 100644 --- a/tests/ui/structs-enums/call-tuple-struct-ctor-as-fn.rs +++ b/tests/ui/structs-enums/call-tuple-struct-ctor-as-fn.rs @@ -1,3 +1,5 @@ +//! Regression test for . +//! Test calling tuple struct constructor doesn't cause segfault. //@ run-pass struct A(#[allow(dead_code)] bool); diff --git a/tests/ui/traits/object/extern-c-trait-object-methods.rs b/tests/ui/traits/object/extern-c-trait-object-methods.rs index bf3f629df4970..f1ee19fc67cf2 100644 --- a/tests/ui/traits/object/extern-c-trait-object-methods.rs +++ b/tests/ui/traits/object/extern-c-trait-object-methods.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Test extern `C` trait object methods don't ICE. //@ run-pass + trait Foo { extern "C" fn borrow(&self); extern "C" fn take(self: Box); From 7ff730b2ce77db89e81d78026e1ed809ab9102fa Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 21 Jul 2026 13:12:25 +0200 Subject: [PATCH 45/71] run `tests/assembly-llvm/asm/aarch64-types.rs` for `aarch64_be` --- tests/assembly-llvm/asm/aarch64-types.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/assembly-llvm/asm/aarch64-types.rs b/tests/assembly-llvm/asm/aarch64-types.rs index fde0aad946951..47e7917c85a94 100644 --- a/tests/assembly-llvm/asm/aarch64-types.rs +++ b/tests/assembly-llvm/asm/aarch64-types.rs @@ -1,8 +1,10 @@ //@ add-minicore -//@ revisions: aarch64 arm64ec +//@ revisions: aarch64 aarch64_be arm64ec //@ assembly-output: emit-asm //@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu //@ [aarch64] needs-llvm-components: aarch64 +//@ [aarch64_be] compile-flags: --target aarch64_be-unknown-linux-gnu +//@ [aarch64_be] needs-llvm-components: aarch64 //@ [arm64ec] compile-flags: --target arm64ec-pc-windows-msvc //@ [arm64ec] needs-llvm-components: aarch64 //@ compile-flags: -Zmerge-functions=disabled From f68af893b54f5280f04fdcda2e964961b051ced1 Mon Sep 17 00:00:00 2001 From: sgasho Date: Tue, 21 Jul 2026 22:22:31 +0900 Subject: [PATCH 46/71] rdg: Move Autodiff CI job below performance testing --- src/doc/rustc-dev-guide/src/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 6a3a5a0a936f3..a2b386cc83071 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -34,8 +34,8 @@ - [Codegen backend testing](./tests/codegen-backend-tests/intro.md) - [Cranelift codegen backend](./tests/codegen-backend-tests/cg_clif.md) - [GCC codegen backend](./tests/codegen-backend-tests/cg_gcc.md) - - [Autodiff CI job](./tests/autodiff-ci-job.md) - [Performance testing](./tests/perf.md) + - [Autodiff CI job](./tests/autodiff-ci-job.md) - [Pre-stabilization CI job for the next solver and polonius alpha](./tests/x86_64-gnu-next-trait-solver-polonius-ci-job.md) - [Misc info](./tests/misc.md) - [Debugging the compiler](./compiler-debugging.md) From 2bb8a3b44ab94616e7757364c8e567f351e72de1 Mon Sep 17 00:00:00 2001 From: sgasho Date: Tue, 21 Jul 2026 22:23:34 +0900 Subject: [PATCH 47/71] Delete autodiff.sh and move the test command to the Dockerfile --- .../host-x86_64/optional-x86_64-gnu-autodiff/Dockerfile | 8 +++++--- src/ci/docker/scripts/autodiff.sh | 9 --------- 2 files changed, 5 insertions(+), 12 deletions(-) delete mode 100755 src/ci/docker/scripts/autodiff.sh diff --git a/src/ci/docker/host-x86_64/optional-x86_64-gnu-autodiff/Dockerfile b/src/ci/docker/host-x86_64/optional-x86_64-gnu-autodiff/Dockerfile index f4633f951c645..a7b6dc620e967 100644 --- a/src/ci/docker/host-x86_64/optional-x86_64-gnu-autodiff/Dockerfile +++ b/src/ci/docker/host-x86_64/optional-x86_64-gnu-autodiff/Dockerfile @@ -20,8 +20,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -COPY scripts/autodiff.sh /scripts/ - ENV NO_DOWNLOAD_CI_LLVM 1 ENV CODEGEN_BACKENDS llvm @@ -34,4 +32,8 @@ ENV RUST_CONFIGURE_ARGS \ --disable-docs \ --set llvm.download-ci-llvm=false -ENV SCRIPT /scripts/autodiff.sh +ENV SCRIPT="../x.py test --stage 2 --no-fail-fast \ + tests/codegen-llvm/autodiff \ + tests/pretty/autodiff \ + tests/ui/autodiff \ + tests/ui/feature-gates/feature-gate-autodiff.rs" diff --git a/src/ci/docker/scripts/autodiff.sh b/src/ci/docker/scripts/autodiff.sh deleted file mode 100755 index 90b36078faccd..0000000000000 --- a/src/ci/docker/scripts/autodiff.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -set -ex - -../x.py test --stage 2 --no-fail-fast \ - tests/codegen-llvm/autodiff \ - tests/pretty/autodiff \ - tests/ui/autodiff \ - tests/ui/feature-gates/feature-gate-autodiff.rs From 737220233d0c8c591b96546e83eec7b2194d555e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 21 Jul 2026 15:50:58 +0000 Subject: [PATCH 48/71] Make some parser structured suggestions verbose Replace most of the `.span_suggestion(` in `rustc_parse` with `.span_suggestion_verbose(`, as they are more readabale, if more verbose. Verbose suggestions also tend to highlight off-by-one `Span` errors better. --- compiler/rustc_parse/src/lexer/mod.rs | 2 +- .../src/lexer/unescape_error_reporting.rs | 10 ++--- .../rustc_parse/src/parser/diagnostics.rs | 16 ++++---- compiler/rustc_parse/src/parser/expr.rs | 13 ++++-- compiler/rustc_parse/src/parser/item.rs | 16 ++++---- compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse/src/parser/path.rs | 4 +- .../in-trait/bad-signatures.stderr | 11 +++-- tests/ui/async-await/no-async-const.stderr | 10 +++-- tests/ui/async-await/no-unsafe-async.stderr | 20 ++++++---- .../attribute/attr-with-a-semicolon.stderr | 8 +--- tests/ui/parser/duplicate-visibility.stderr | 10 +++-- tests/ui/parser/eq-less-to-less-eq.stderr | 10 +++-- tests/ui/parser/inverted-parameters.stderr | 33 +++++++++------ tests/ui/parser/issues/issue-113342.stderr | 11 +++-- tests/ui/parser/issues/issue-19398.stderr | 10 +++-- .../ui/parser/issues/issue-76437-async.stderr | 11 +++-- .../issue-76437-const-async-unsafe.stderr | 11 +++-- .../issues/issue-76437-const-async.stderr | 11 +++-- .../ui/parser/issues/issue-76437-const.stderr | 11 +++-- .../issue-76437-pub-crate-unsafe.stderr | 11 +++-- .../parser/issues/issue-76437-unsafe.stderr | 11 +++-- .../const-async-const.stderr | 10 +++-- .../issue-87217-keyword-order/recovery.stderr | 20 ++++++---- .../several-kw-jump.stderr | 10 +++-- .../wrong-async.stderr | 10 +++-- .../wrong-const.stderr | 10 +++-- .../wrong-unsafe-abi.stderr | 10 +++-- .../wrong-unsafe.stderr | 10 +++-- .../issues/issue-87694-duplicated-pub.stderr | 10 +++-- .../issues/issue-87694-misplaced-pub.stderr | 11 +++-- tests/ui/parser/issues/issue-89396.stderr | 21 ++++++---- .../issues/recover-ge-as-fat-arrow.stderr | 11 +++-- .../kw-in-item-pos-recovery-151238.stderr | 11 +++-- .../macro/misspelled-macro-rules.stderr | 10 +++-- .../ui/parser/range-exclusive-dotdotlt.stderr | 40 +++++++++++++------ .../ui/parser/raw/raw-byte-string-eof.stderr | 8 ++-- tests/ui/parser/raw/raw-str-unbalanced.stderr | 24 +++++++++-- tests/ui/parser/raw/raw-string-2.stderr | 6 ++- tests/ui/parser/raw/raw-string.stderr | 8 ++-- .../removed-syntax-field-let-2.stderr | 20 ++++++---- .../removed-syntax-field-let.stderr | 10 +++-- .../suggest-add-self-issue-131084.stderr | 11 +++-- .../ice-120503-async-const-method.stderr | 10 +++-- 44 files changed, 339 insertions(+), 204 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 1a30d5f1e79a0..4f7c76e7df816 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -987,7 +987,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let lo = start + BytePos(possible_offset); let hi = lo + BytePos(found_terminators); let span = self.mk_sp(lo, hi); - err.span_suggestion( + err.span_suggestion_verbose( span, "consider terminating the string here", "#".repeat(n_hashes as usize), diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 54c8f3c09ec48..9176192c95640 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -162,7 +162,7 @@ pub(crate) fn emit_unescape_error( ); } else { if mode == Mode::Str || mode == Mode::Char { - diag.span_suggestion( + diag.span_suggestion_verbose( full_lit_span, "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal", format!("r\"{lit}\""), @@ -204,7 +204,7 @@ pub(crate) fn emit_unescape_error( // Note: the \\xHH suggestions are not given for raw byte string // literals, because they are araw and so cannot use any escapes. if (c as u32) <= 0xFF && mode != Mode::RawByteStr { - err.span_suggestion( + err.span_suggestion_verbose( span, format!( "if you meant to use the unicode code point for {c:?}, use a \\xHH escape" @@ -217,7 +217,7 @@ pub(crate) fn emit_unescape_error( } else if mode != Mode::RawByteStr { let mut utf8 = String::new(); utf8.push(c); - err.span_suggestion( + err.span_suggestion_verbose( span, format!("if you meant to use the UTF-8 encoding of {c:?}, use \\xHH escapes"), utf8.as_bytes() @@ -313,7 +313,7 @@ fn foreign_escape_suggestion( err_span: Span, ) { if escaped_char == "?" { - diag.span_suggestion( + diag.span_suggestion_verbose( err_span, "if you meant to write a literal question mark, don't escape the character", "?", @@ -336,7 +336,7 @@ fn foreign_escape_suggestion( _ => return, }; - diag.span_suggestion( + diag.span_suggestion_verbose( escape_span, format!("if you meant to write {name}, use a hex escape"), format!("x{hex}"), diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e5be778458135..9ee4576e3483c 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -597,7 +597,7 @@ impl<'a> Parser<'a> { .iter() .any(|tok| matches!(tok, TokenType::FatArrow | TokenType::CloseBrace)) { - err.span_suggestion( + err.span_suggestion_verbose( self.token.span, "you might have meant to write a \"greater than or equal to\" comparison", ">=", @@ -942,7 +942,7 @@ impl<'a> Parser<'a> { count += 1; } err.span(span); - err.span_suggestion( + err.span_suggestion_verbose( span, format!("remove the extra `#`{}", pluralize!(count)), "", @@ -2062,7 +2062,7 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); } - err.span_suggestion(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable); + err.span_suggestion_verbose(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable); let guar = err.emit(); Ok(self.mk_expr_err(lo.to(hi), guar)) } else { @@ -2243,7 +2243,7 @@ impl<'a> Parser<'a> { let ident = self.parse_ident_common(true).unwrap(); let span = pat.span.with_hi(ident.span.hi()); - err.span_suggestion( + err.span_suggestion_verbose( span, "declare the type after the parameter binding", ": ", @@ -2641,7 +2641,7 @@ impl<'a> Parser<'a> { Ok((expr, _)) => { // Find a mistake like `MyTrait`. if snapshot.token == token::EqEq { - err.span_suggestion( + err.span_suggestion_verbose( snapshot.token.span, "if you meant to use an associated type binding, replace `==` with `=`", "=", @@ -2655,7 +2655,7 @@ impl<'a> Parser<'a> { && matches!(expr.kind, ExprKind::Path(..)) { // Find a mistake like "foo::var:A". - err.span_suggestion( + err.span_suggestion_verbose( snapshot.token.span, "write a path separator here", "::", @@ -2938,7 +2938,7 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); if let CommaRecoveryMode::EitherTupleOrPipe = rt { - err.span_suggestion( + err.span_suggestion_verbose( comma_span, "...or a vertical bar to match on alternatives", " |", @@ -2975,7 +2975,7 @@ impl<'a> Parser<'a> { && (self.expected_token_types.contains(TokenType::Gt) || matches!(self.token.kind, token::Literal(..))) { - err.span_suggestion( + err.span_suggestion_verbose( maybe_lt.span, "remove the `<` to write an exclusive range", "", diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 92e8f5eefadb2..a3dea980e67c2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1699,7 +1699,12 @@ impl<'a> Parser<'a> { // directly adjacent (i.e. '=<') if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() { let eq_lt = maybe_eq_tok.span.to(lt_span); - err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified); + err.span_suggestion_verbose( + eq_lt, + "did you mean", + "<=", + Applicability::Unspecified, + ); } err })?; @@ -2755,7 +2760,7 @@ impl<'a> Parser<'a> { && let maybe_let = self.look_ahead(1, |t| t.clone()) && maybe_let.is_keyword(kw::Let) { - err.span_suggestion( + err.span_suggestion_verbose( self.prev_token.span, "consider removing this semicolon to parse the `let` as part of the same chain", "", @@ -2767,7 +2772,7 @@ impl<'a> Parser<'a> { } else { // Look for usages of '=>' where '>=' might be intended if maybe_fatarrow == token::FatArrow { - err.span_suggestion( + err.span_suggestion_verbose( maybe_fatarrow.span, "you might have meant to write a \"greater than or equal to\" comparison", ">=", @@ -3381,7 +3386,7 @@ impl<'a> Parser<'a> { if let Err(mut err) = this.expect(exp!(FatArrow)) { // We might have a `=>` -> `=` or `->` typo (issue #89396). if is_almost_fat_arrow { - err.span_suggestion( + err.span_suggestion_verbose( this.token.span, "use a fat arrow to start a match arm", "=>", diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 192cd7668f518..6de9240c64a91 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -601,7 +601,7 @@ impl<'a> Parser<'a> { && let [segment] = path.segments.as_slice() && edit_distance("macro_rules", &segment.ident.to_string(), 2).is_some() { - err.span_suggestion( + err.span_suggestion_verbose( path.span, "perhaps you meant to define a macro", "macro_rules", @@ -627,7 +627,7 @@ impl<'a> Parser<'a> { if end.is_doc_comment() { err.span_label(end.span, "this doc comment doesn't document anything"); } else if self.token == TokenKind::Semi { - err.span_suggestion_verbose( + err.span_suggestion( self.token.span, "consider removing this semicolon", "", @@ -2474,7 +2474,7 @@ impl<'a> Parser<'a> { .map_err(|err| err.cancel()) && self.token == TokenKind::Colon { - err.span_suggestion( + err.span_suggestion_verbose( removal_span, "remove this `let` keyword", String::new(), @@ -2632,7 +2632,7 @@ impl<'a> Parser<'a> { vec![(open, "{".to_string()), (close, '}'.to_string())], Applicability::MaybeIncorrect, ); - err.span_suggestion( + err.span_suggestion_verbose( span.with_neighbor(self.token.span).shrink_to_hi(), "add a semicolon", ';', @@ -3248,7 +3248,7 @@ impl<'a> Parser<'a> { .span_to_snippet(original_sp) .expect("Span extracted directly from keyword should always work"); - err.span_suggestion( + err.span_suggestion_verbose( self.token_uninterpolated_span(), format!("`{original_kw}` already used earlier, remove this one"), "", @@ -3263,7 +3263,7 @@ impl<'a> Parser<'a> { let misplaced_qual_sp = self.token_uninterpolated_span(); let misplaced_qual = self.span_to_snippet(misplaced_qual_sp).unwrap(); - err.span_suggestion( + err.span_suggestion_verbose( correct_pos_sp.to(misplaced_qual_sp), format!("`{misplaced_qual}` must come before `{current_qual}`"), format!("{misplaced_qual} {current_qual}"), @@ -3287,7 +3287,7 @@ impl<'a> Parser<'a> { // There was no explicit visibility if matches!(orig_vis.kind, VisibilityKind::Inherited) { - err.span_suggestion( + err.span_suggestion_verbose( sp_start.to(self.prev_token.span), format!("visibility `{vs}` must come before `{snippet}`"), format!("{vs} {snippet}"), @@ -3296,7 +3296,7 @@ impl<'a> Parser<'a> { } // There was an explicit visibility else { - err.span_suggestion( + err.span_suggestion_verbose( current_vis.span, "there is already a visibility modifier, remove one", "", diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 09ac1acb74f51..dff6afdc893a7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1805,7 +1805,7 @@ impl<'a> Parser<'a> { format!("the {kind_desc} was parsed as having {op_desc} binary expression"), ); - err.span_suggestion( + err.span_suggestion_verbose( lhs_end_span, format!("you may have meant to write a `;` to terminate the {kind_desc} earlier"), ";", diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 2dfcbccfe60ec..8ed2734b7de9c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -817,13 +817,13 @@ impl<'a> Parser<'a> { .dcx() .struct_span_err(after_eq.to(before_next), "missing type to the right of `=`"); if matches!(self.token.kind, token::Comma | token::Gt) { - err.span_suggestion( + err.span_suggestion_verbose( self.psess.source_map().next_point(eq_span).to(before_next), "to constrain the associated type, add a type after `=`", " TheType", Applicability::HasPlaceholders, ); - err.span_suggestion( + err.span_suggestion_verbose( prev_token_span.shrink_to_hi().to(before_next), format!("remove the `=` if `{ident}` is a type"), "", diff --git a/tests/ui/async-await/in-trait/bad-signatures.stderr b/tests/ui/async-await/in-trait/bad-signatures.stderr index 127a343a93016..1f2f0537af3d1 100644 --- a/tests/ui/async-await/in-trait/bad-signatures.stderr +++ b/tests/ui/async-await/in-trait/bad-signatures.stderr @@ -8,10 +8,13 @@ error: expected one of `:`, `@`, or `|`, found keyword `self` --> $DIR/bad-signatures.rs:5:23 | LL | async fn bar(&abc self); - | -----^^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^^^^ expected one of `:`, `@`, or `|` + | +help: declare the type after the parameter binding + | +LL - async fn bar(&abc self); +LL + async fn bar(: ); + | error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/no-async-const.stderr b/tests/ui/async-await/no-async-const.stderr index d692ba8f47375..be02ba17dbe67 100644 --- a/tests/ui/async-await/no-async-const.stderr +++ b/tests/ui/async-await/no-async-const.stderr @@ -2,12 +2,14 @@ error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const --> $DIR/no-async-const.rs:4:11 | LL | pub async const fn x() {} - | ------^^^^^ - | | | - | | expected one of `extern`, `fn`, `safe`, or `unsafe` - | help: `const` must come before `async`: `const async` + | ^^^^^ expected one of `extern`, `fn`, `safe`, or `unsafe` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `const` must come before `async` + | +LL - pub async const fn x() {} +LL + pub const async fn x() {} + | error: functions cannot be both `const` and `async` --> $DIR/no-async-const.rs:4:5 diff --git a/tests/ui/async-await/no-unsafe-async.stderr b/tests/ui/async-await/no-unsafe-async.stderr index 49b112f9313d4..8db98f3c75493 100644 --- a/tests/ui/async-await/no-unsafe-async.stderr +++ b/tests/ui/async-await/no-unsafe-async.stderr @@ -2,23 +2,27 @@ error: expected one of `extern` or `fn`, found keyword `async` --> $DIR/no-unsafe-async.rs:7:12 | LL | unsafe async fn g() {} - | -------^^^^^ - | | | - | | expected one of `extern` or `fn` - | help: `async` must come before `unsafe`: `async unsafe` + | ^^^^^ expected one of `extern` or `fn` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `async` must come before `unsafe` + | +LL - unsafe async fn g() {} +LL + async unsafe fn g() {} + | error: expected one of `extern` or `fn`, found keyword `async` --> $DIR/no-unsafe-async.rs:11:8 | LL | unsafe async fn f() {} - | -------^^^^^ - | | | - | | expected one of `extern` or `fn` - | help: `async` must come before `unsafe`: `async unsafe` + | ^^^^^ expected one of `extern` or `fn` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `async` must come before `unsafe` + | +LL - unsafe async fn f() {} +LL + async unsafe fn f() {} + | error: aborting due to 2 previous errors diff --git a/tests/ui/parser/attribute/attr-with-a-semicolon.stderr b/tests/ui/parser/attribute/attr-with-a-semicolon.stderr index b77f30fdb5934..0431d3e524fe4 100644 --- a/tests/ui/parser/attribute/attr-with-a-semicolon.stderr +++ b/tests/ui/parser/attribute/attr-with-a-semicolon.stderr @@ -2,13 +2,7 @@ error: expected item after attributes --> $DIR/attr-with-a-semicolon.rs:1:1 | LL | #[derive(Debug, Clone)]; - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider removing this semicolon - | -LL - #[derive(Debug, Clone)]; -LL + #[derive(Debug, Clone)] - | + | ^^^^^^^^^^^^^^^^^^^^^^^- help: consider removing this semicolon error: aborting due to 1 previous error diff --git a/tests/ui/parser/duplicate-visibility.stderr b/tests/ui/parser/duplicate-visibility.stderr index e00ebe6a8cf6d..a7d5a36c58bfd 100644 --- a/tests/ui/parser/duplicate-visibility.stderr +++ b/tests/ui/parser/duplicate-visibility.stderr @@ -4,10 +4,7 @@ error: expected one of `(`, `async`, `const`, `default`, `extern`, `final`, `fn` LL | extern "C" { | - while parsing this item list starting here LL | pub pub fn foo(); - | ^^^ - | | - | expected one of 10 possible tokens - | help: there is already a visibility modifier, remove one + | ^^^ expected one of 10 possible tokens ... LL | } | - the item list ends here @@ -17,6 +14,11 @@ note: explicit visibility first seen here | LL | pub pub fn foo(); | ^^^ +help: there is already a visibility modifier, remove one + | +LL - pub pub fn foo(); +LL + pub fn foo(); + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/eq-less-to-less-eq.stderr b/tests/ui/parser/eq-less-to-less-eq.stderr index 4717d8287ff7b..b365aa9769470 100644 --- a/tests/ui/parser/eq-less-to-less-eq.stderr +++ b/tests/ui/parser/eq-less-to-less-eq.stderr @@ -2,9 +2,13 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{` --> $DIR/eq-less-to-less-eq.rs:4:15 | LL | if a =< b { - | -- ^ expected one of 7 possible tokens - | | - | help: did you mean: `<=` + | ^ expected one of 7 possible tokens + | +help: did you mean + | +LL - if a =< b { +LL + if a <= b { + | error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{` --> $DIR/eq-less-to-less-eq.rs:12:15 diff --git a/tests/ui/parser/inverted-parameters.stderr b/tests/ui/parser/inverted-parameters.stderr index 93b95a756087d..8eea01b19ccba 100644 --- a/tests/ui/parser/inverted-parameters.stderr +++ b/tests/ui/parser/inverted-parameters.stderr @@ -2,19 +2,25 @@ error: expected one of `:`, `@`, or `|`, found `bar` --> $DIR/inverted-parameters.rs:6:24 | LL | fn foo(&self, &str bar) {} - | -----^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^^^ expected one of `:`, `@`, or `|` + | +help: declare the type after the parameter binding + | +LL - fn foo(&self, &str bar) {} +LL + fn foo(&self, : ) {} + | error: expected one of `:`, `@`, or `|`, found `quux` --> $DIR/inverted-parameters.rs:12:10 | LL | fn baz(S quux, xyzzy: i32) {} - | --^^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^^^^ expected one of `:`, `@`, or `|` + | +help: declare the type after the parameter binding + | +LL - fn baz(S quux, xyzzy: i32) {} +LL + fn baz(: , xyzzy: i32) {} + | error: expected one of `:`, `@`, or `|`, found `a` --> $DIR/inverted-parameters.rs:17:12 @@ -47,10 +53,13 @@ error: expected one of `:`, `@`, or `|`, found `S` --> $DIR/inverted-parameters.rs:28:23 | LL | fn missing_colon(quux S) {} - | -----^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^ expected one of `:`, `@`, or `|` + | +help: declare the type after the parameter binding + | +LL - fn missing_colon(quux S) {} +LL + fn missing_colon(: ) {} + | error: aborting due to 6 previous errors diff --git a/tests/ui/parser/issues/issue-113342.stderr b/tests/ui/parser/issues/issue-113342.stderr index 6d9f22f6a7ce8..bc7aad3c03fbe 100644 --- a/tests/ui/parser/issues/issue-113342.stderr +++ b/tests/ui/parser/issues/issue-113342.stderr @@ -2,10 +2,13 @@ error: expected `fn`, found keyword `pub` --> $DIR/issue-113342.rs:7:12 | LL | extern "C" pub fn id(x: i32) -> i32 { x } - | -----------^^^ - | | | - | | expected `fn` - | help: visibility `pub` must come before `extern "C"`: `pub extern "C"` + | ^^^ expected `fn` + | +help: visibility `pub` must come before `extern "C"` + | +LL - extern "C" pub fn id(x: i32) -> i32 { x } +LL + pub extern "C" fn id(x: i32) -> i32 { x } + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-19398.stderr b/tests/ui/parser/issues/issue-19398.stderr index 2b97ec50c9172..3fd8bb40a0b8e 100644 --- a/tests/ui/parser/issues/issue-19398.stderr +++ b/tests/ui/parser/issues/issue-19398.stderr @@ -2,12 +2,14 @@ error: expected `fn`, found keyword `unsafe` --> $DIR/issue-19398.rs:2:19 | LL | extern "Rust" unsafe fn foo(); - | --------------^^^^^^ - | | | - | | expected `fn` - | help: `unsafe` must come before `extern "Rust"`: `unsafe extern "Rust"` + | ^^^^^^ expected `fn` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `unsafe` must come before `extern "Rust"` + | +LL - extern "Rust" unsafe fn foo(); +LL + unsafe extern "Rust" fn foo(); + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-async.stderr b/tests/ui/parser/issues/issue-76437-async.stderr index 483599135f566..4a02c045c7cf2 100644 --- a/tests/ui/parser/issues/issue-76437-async.stderr +++ b/tests/ui/parser/issues/issue-76437-async.stderr @@ -2,10 +2,13 @@ error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-76437-async.rs:4:11 | LL | async pub fn t() {} - | ------^^^ - | | | - | | expected one of `extern`, `fn`, `safe`, or `unsafe` - | help: visibility `pub` must come before `async`: `pub async` + | ^^^ expected one of `extern`, `fn`, `safe`, or `unsafe` + | +help: visibility `pub` must come before `async` + | +LL - async pub fn t() {} +LL + pub async fn t() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-const-async-unsafe.stderr b/tests/ui/parser/issues/issue-76437-const-async-unsafe.stderr index a703fc4e8a452..b296add2beb0a 100644 --- a/tests/ui/parser/issues/issue-76437-const-async-unsafe.stderr +++ b/tests/ui/parser/issues/issue-76437-const-async-unsafe.stderr @@ -2,10 +2,13 @@ error: expected one of `extern` or `fn`, found keyword `pub` --> $DIR/issue-76437-const-async-unsafe.rs:4:24 | LL | const async unsafe pub fn t() {} - | -------------------^^^ - | | | - | | expected one of `extern` or `fn` - | help: visibility `pub` must come before `const async unsafe`: `pub const async unsafe` + | ^^^ expected one of `extern` or `fn` + | +help: visibility `pub` must come before `const async unsafe` + | +LL - const async unsafe pub fn t() {} +LL + pub const async unsafe fn t() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-const-async.stderr b/tests/ui/parser/issues/issue-76437-const-async.stderr index 81fa8a5f557e0..3d1fc4dc4fdd8 100644 --- a/tests/ui/parser/issues/issue-76437-const-async.stderr +++ b/tests/ui/parser/issues/issue-76437-const-async.stderr @@ -2,10 +2,13 @@ error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-76437-const-async.rs:4:17 | LL | const async pub fn t() {} - | ------------^^^ - | | | - | | expected one of `extern`, `fn`, `safe`, or `unsafe` - | help: visibility `pub` must come before `const async`: `pub const async` + | ^^^ expected one of `extern`, `fn`, `safe`, or `unsafe` + | +help: visibility `pub` must come before `const async` + | +LL - const async pub fn t() {} +LL + pub const async fn t() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-const.stderr b/tests/ui/parser/issues/issue-76437-const.stderr index 005a27b7c2498..2ebf2042ebd67 100644 --- a/tests/ui/parser/issues/issue-76437-const.stderr +++ b/tests/ui/parser/issues/issue-76437-const.stderr @@ -2,10 +2,13 @@ error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keywo --> $DIR/issue-76437-const.rs:4:11 | LL | const pub fn t() {} - | ------^^^ - | | | - | | expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` - | help: visibility `pub` must come before `const`: `pub const` + | ^^^ expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` + | +help: visibility `pub` must come before `const` + | +LL - const pub fn t() {} +LL + pub const fn t() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-pub-crate-unsafe.stderr b/tests/ui/parser/issues/issue-76437-pub-crate-unsafe.stderr index 4ea76179be3f6..1cae371ae57ea 100644 --- a/tests/ui/parser/issues/issue-76437-pub-crate-unsafe.stderr +++ b/tests/ui/parser/issues/issue-76437-pub-crate-unsafe.stderr @@ -2,10 +2,13 @@ error: expected one of `extern` or `fn`, found keyword `pub` --> $DIR/issue-76437-pub-crate-unsafe.rs:4:12 | LL | unsafe pub(crate) fn t() {} - | -------^^^------- - | | | - | | expected one of `extern` or `fn` - | help: visibility `pub(crate)` must come before `unsafe`: `pub(crate) unsafe` + | ^^^ expected one of `extern` or `fn` + | +help: visibility `pub(crate)` must come before `unsafe` + | +LL - unsafe pub(crate) fn t() {} +LL + pub(crate) unsafe fn t() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-unsafe.stderr b/tests/ui/parser/issues/issue-76437-unsafe.stderr index 69f7927750bf0..fb3abb7e9a669 100644 --- a/tests/ui/parser/issues/issue-76437-unsafe.stderr +++ b/tests/ui/parser/issues/issue-76437-unsafe.stderr @@ -2,10 +2,13 @@ error: expected one of `extern` or `fn`, found keyword `pub` --> $DIR/issue-76437-unsafe.rs:4:12 | LL | unsafe pub fn t() {} - | -------^^^ - | | | - | | expected one of `extern` or `fn` - | help: visibility `pub` must come before `unsafe`: `pub unsafe` + | ^^^ expected one of `extern` or `fn` + | +help: visibility `pub` must come before `unsafe` + | +LL - unsafe pub fn t() {} +LL + pub unsafe fn t() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr index ed2e4d8154929..692fbc0350953 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr @@ -2,16 +2,18 @@ error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const --> $DIR/const-async-const.rs:5:13 | LL | const async const fn test() {} - | ^^^^^ - | | - | expected one of `extern`, `fn`, `safe`, or `unsafe` - | help: `const` already used earlier, remove this one + | ^^^^^ expected one of `extern`, `fn`, `safe`, or `unsafe` | note: `const` first seen here --> $DIR/const-async-const.rs:5:1 | LL | const async const fn test() {} | ^^^^^ +help: `const` already used earlier, remove this one + | +LL - const async const fn test() {} +LL + const async fn test() {} + | error: functions cannot be both `const` and `async` --> $DIR/const-async-const.rs:5:1 diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/recovery.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/recovery.stderr index 3f504a9ebfc49..a1b3a29c2dd27 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/recovery.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/recovery.stderr @@ -2,27 +2,31 @@ error: expected one of `extern` or `fn`, found keyword `const` --> $DIR/recovery.rs:6:12 | LL | unsafe const fn from_u32(val: u32) {} - | -------^^^^^ - | | | - | | expected one of `extern` or `fn` - | help: `const` must come before `unsafe`: `const unsafe` + | ^^^^^ expected one of `extern` or `fn` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `const` must come before `unsafe` + | +LL - unsafe const fn from_u32(val: u32) {} +LL + const unsafe fn from_u32(val: u32) {} + | error: expected one of `extern` or `fn`, found keyword `unsafe` --> $DIR/recovery.rs:14:12 | LL | unsafe unsafe fn from_u32(val: u32) {} - | ^^^^^^ - | | - | expected one of `extern` or `fn` - | help: `unsafe` already used earlier, remove this one + | ^^^^^^ expected one of `extern` or `fn` | note: `unsafe` first seen here --> $DIR/recovery.rs:14:5 | LL | unsafe unsafe fn from_u32(val: u32) {} | ^^^^^^ +help: `unsafe` already used earlier, remove this one + | +LL - unsafe unsafe fn from_u32(val: u32) {} +LL + unsafe fn from_u32(val: u32) {} + | error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr index 489e8eefb052e..ccab054540691 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr @@ -2,12 +2,14 @@ error: expected one of `extern` or `fn`, found keyword `const` --> $DIR/several-kw-jump.rs:9:14 | LL | async unsafe const fn test() {} - | -------------^^^^^ - | | | - | | expected one of `extern` or `fn` - | help: `const` must come before `async unsafe`: `const async unsafe` + | ^^^^^ expected one of `extern` or `fn` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `const` must come before `async unsafe` + | +LL - async unsafe const fn test() {} +LL + const async unsafe fn test() {} + | error: functions cannot be both `const` and `async` --> $DIR/several-kw-jump.rs:9:1 diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr index 74989502e7f5d..5423f72fc786b 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr @@ -2,12 +2,14 @@ error: expected one of `extern` or `fn`, found keyword `async` --> $DIR/wrong-async.rs:9:8 | LL | unsafe async fn test() {} - | -------^^^^^ - | | | - | | expected one of `extern` or `fn` - | help: `async` must come before `unsafe`: `async unsafe` + | ^^^^^ expected one of `extern` or `fn` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `async` must come before `unsafe` + | +LL - unsafe async fn test() {} +LL + async unsafe fn test() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr index 5958f0c7d2ddd..9d68538ec804f 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr @@ -2,12 +2,14 @@ error: expected one of `extern` or `fn`, found keyword `const` --> $DIR/wrong-const.rs:9:8 | LL | unsafe const fn test() {} - | -------^^^^^ - | | | - | | expected one of `extern` or `fn` - | help: `const` must come before `unsafe`: `const unsafe` + | ^^^^^ expected one of `extern` or `fn` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `const` must come before `unsafe` + | +LL - unsafe const fn test() {} +LL + const unsafe fn test() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.stderr index 8ed037869c829..eee9b0b8b8270 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.stderr @@ -2,12 +2,14 @@ error: expected `fn`, found keyword `unsafe` --> $DIR/wrong-unsafe-abi.rs:9:12 | LL | extern "C" unsafe fn test() {} - | -----------^^^^^^ - | | | - | | expected `fn` - | help: `unsafe` must come before `extern "C"`: `unsafe extern "C"` + | ^^^^^^ expected `fn` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `unsafe` must come before `extern "C"` + | +LL - extern "C" unsafe fn test() {} +LL + unsafe extern "C" fn test() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr index 232da9acef309..e6ea40f15ae8a 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr @@ -2,12 +2,14 @@ error: expected `fn`, found keyword `unsafe` --> $DIR/wrong-unsafe.rs:10:8 | LL | extern unsafe fn test() {} - | -------^^^^^^ - | | | - | | expected `fn` - | help: `unsafe` must come before `extern`: `unsafe extern` + | ^^^^^^ expected `fn` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `unsafe` must come before `extern` + | +LL - extern unsafe fn test() {} +LL + unsafe extern fn test() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr b/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr index dd75f32f68ff2..50d58ffb2fb35 100644 --- a/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr +++ b/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr @@ -2,16 +2,18 @@ error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keywo --> $DIR/issue-87694-duplicated-pub.rs:1:11 | LL | pub const pub fn test() {} - | ^^^ - | | - | expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` - | help: there is already a visibility modifier, remove one + | ^^^ expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` | note: explicit visibility first seen here --> $DIR/issue-87694-duplicated-pub.rs:1:1 | LL | pub const pub fn test() {} | ^^^ +help: there is already a visibility modifier, remove one + | +LL - pub const pub fn test() {} +LL + pub const fn test() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr b/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr index d35e09dceaf7f..fcdd07a91182c 100644 --- a/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr +++ b/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr @@ -2,10 +2,13 @@ error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keywo --> $DIR/issue-87694-misplaced-pub.rs:1:7 | LL | const pub fn test() {} - | ------^^^ - | | | - | | expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` - | help: visibility `pub` must come before `const`: `pub const` + | ^^^ expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` + | +help: visibility `pub` must come before `const` + | +LL - const pub fn test() {} +LL + pub const fn test() {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-89396.stderr b/tests/ui/parser/issues/issue-89396.stderr index 41ce07050746a..8773a7516ff88 100644 --- a/tests/ui/parser/issues/issue-89396.stderr +++ b/tests/ui/parser/issues/issue-89396.stderr @@ -2,19 +2,24 @@ error: expected one of `=>`, `if`, or `|`, found `=` --> $DIR/issue-89396.rs:9:17 | LL | Some(_) = true, - | ^ - | | - | expected one of `=>`, `if`, or `|` - | help: use a fat arrow to start a match arm: `=>` + | ^ expected one of `=>`, `if`, or `|` + | +help: use a fat arrow to start a match arm + | +LL | Some(_) => true, + | + error: expected one of `=>`, `@`, `if`, or `|`, found `->` --> $DIR/issue-89396.rs:12:14 | LL | None -> false, - | ^^ - | | - | expected one of `=>`, `@`, `if`, or `|` - | help: use a fat arrow to start a match arm: `=>` + | ^^ expected one of `=>`, `@`, `if`, or `|` + | +help: use a fat arrow to start a match arm + | +LL - None -> false, +LL + None => false, + | error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/recover-ge-as-fat-arrow.stderr b/tests/ui/parser/issues/recover-ge-as-fat-arrow.stderr index 997d080f1deed..2a8c78a776b9e 100644 --- a/tests/ui/parser/issues/recover-ge-as-fat-arrow.stderr +++ b/tests/ui/parser/issues/recover-ge-as-fat-arrow.stderr @@ -2,10 +2,13 @@ error: expected one of `...`, `..=`, `..`, `=>`, `if`, or `|`, found `>=` --> $DIR/recover-ge-as-fat-arrow.rs:4:11 | LL | 1 >= {} - | ^^ - | | - | expected one of `...`, `..=`, `..`, `=>`, `if`, or `|` - | help: use a fat arrow to start a match arm: `=>` + | ^^ expected one of `...`, `..=`, `..`, `=>`, `if`, or `|` + | +help: use a fat arrow to start a match arm + | +LL - 1 >= {} +LL + 1 => {} + | error[E0308]: mismatched types --> $DIR/recover-ge-as-fat-arrow.rs:5:29 diff --git a/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.stderr b/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.stderr index 81151edaf0c0c..3a7e4779aadfb 100644 --- a/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.stderr +++ b/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.stderr @@ -8,10 +8,13 @@ error: expected one of `:`, `@`, or `|`, found keyword `self` --> $DIR/kw-in-item-pos-recovery-151238.rs:7:28 | LL | trait MyTrait { fn bar(c self) } - | --^^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^^^^ expected one of `:`, `@`, or `|` + | +help: declare the type after the parameter binding + | +LL - trait MyTrait { fn bar(c self) } +LL + trait MyTrait { fn bar(: ) } + | error: expected one of `->`, `;`, `where`, or `{`, found `}` --> $DIR/kw-in-item-pos-recovery-151238.rs:7:34 diff --git a/tests/ui/parser/macro/misspelled-macro-rules.stderr b/tests/ui/parser/macro/misspelled-macro-rules.stderr index fc718d8556dfe..bf401caff318b 100644 --- a/tests/ui/parser/macro/misspelled-macro-rules.stderr +++ b/tests/ui/parser/macro/misspelled-macro-rules.stderr @@ -2,9 +2,13 @@ error: expected one of `(`, `[`, or `{`, found `thing` --> $DIR/misspelled-macro-rules.rs:7:14 | LL | marco_rules! thing { - | ----------- ^^^^^ expected one of `(`, `[`, or `{` - | | - | help: perhaps you meant to define a macro: `macro_rules` + | ^^^^^ expected one of `(`, `[`, or `{` + | +help: perhaps you meant to define a macro + | +LL - marco_rules! thing { +LL + macro_rules! thing { + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/range-exclusive-dotdotlt.stderr b/tests/ui/parser/range-exclusive-dotdotlt.stderr index af25e1df343de..9a38473b64403 100644 --- a/tests/ui/parser/range-exclusive-dotdotlt.stderr +++ b/tests/ui/parser/range-exclusive-dotdotlt.stderr @@ -2,17 +2,25 @@ error: expected type, found `10` --> $DIR/range-exclusive-dotdotlt.rs:2:17 | LL | let _ = 0..<10; - | -^^ expected type - | | - | help: remove the `<` to write an exclusive range + | ^^ expected type + | +help: remove the `<` to write an exclusive range + | +LL - let _ = 0..<10; +LL + let _ = 0..10; + | error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `;` --> $DIR/range-exclusive-dotdotlt.rs:8:20 | LL | let _ = 0.. $DIR/range-exclusive-dotdotlt.rs:14:18 @@ -24,17 +32,25 @@ error: expected type, found `1` --> $DIR/range-exclusive-dotdotlt.rs:19:26 | LL | let _ = [1, 2, 3][..<1]; - | -^ expected type - | | - | help: remove the `<` to write an exclusive range + | ^ expected type + | +help: remove the `<` to write an exclusive range + | +LL - let _ = [1, 2, 3][..<1]; +LL + let _ = [1, 2, 3][..1]; + | error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `]` --> $DIR/range-exclusive-dotdotlt.rs:25:29 | LL | let _ = [1, 2, 3][.. $DIR/range-exclusive-dotdotlt.rs:31:30 diff --git a/tests/ui/parser/raw/raw-byte-string-eof.stderr b/tests/ui/parser/raw/raw-byte-string-eof.stderr index 88fd53904c43f..96bc893a4d4cb 100644 --- a/tests/ui/parser/raw/raw-byte-string-eof.stderr +++ b/tests/ui/parser/raw/raw-byte-string-eof.stderr @@ -2,11 +2,13 @@ error[E0748]: unterminated raw string --> $DIR/raw-byte-string-eof.rs:2:5 | LL | br##"a"#; - | ^ - help: consider terminating the string here: `##` - | | - | unterminated raw string + | ^ unterminated raw string | = note: this raw string should be terminated with `"##` +help: consider terminating the string here + | +LL | br##"a"##; + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/raw/raw-str-unbalanced.stderr b/tests/ui/parser/raw/raw-str-unbalanced.stderr index eac8c06c1df5c..d957e555883b6 100644 --- a/tests/ui/parser/raw/raw-str-unbalanced.stderr +++ b/tests/ui/parser/raw/raw-str-unbalanced.stderr @@ -2,18 +2,30 @@ error: too many `#` when terminating raw string --> $DIR/raw-str-unbalanced.rs:2:10 | LL | r#""## - | -----^ help: remove the extra `#` + | -----^ | | | this raw string started with 1 `#` + | +help: remove the extra `#` + | +LL - r#""## +LL + r#""# + | error: too many `#` when terminating raw string --> $DIR/raw-str-unbalanced.rs:7:9 | LL | / r#" LL | | "#### - | | -^^^ help: remove the extra `#`s + | | -^^^ | |________| | this raw string started with 1 `#` + | +help: remove the extra `#`s + | +LL - "#### +LL + "# + | error: expected `;`, found `#` --> $DIR/raw-str-unbalanced.rs:10:28 @@ -28,9 +40,15 @@ error: too many `#` when terminating raw string --> $DIR/raw-str-unbalanced.rs:16:28 | LL | const B: &'static str = r""## - | ---^^ help: remove the extra `#`s + | ---^^ | | | this raw string started with 0 `#`s + | +help: remove the extra `#`s + | +LL - const B: &'static str = r""## +LL + const B: &'static str = r"" + | error: aborting due to 4 previous errors diff --git a/tests/ui/parser/raw/raw-string-2.stderr b/tests/ui/parser/raw/raw-string-2.stderr index 90dd9775e62e4..f390155904f69 100644 --- a/tests/ui/parser/raw/raw-string-2.stderr +++ b/tests/ui/parser/raw/raw-string-2.stderr @@ -2,9 +2,13 @@ error[E0748]: unterminated raw string --> $DIR/raw-string-2.rs:2:13 | LL | let x = r###"here's a long string"# "# "##; - | ^ unterminated raw string -- help: consider terminating the string here: `###` + | ^ unterminated raw string | = note: this raw string should be terminated with `"###` +help: consider terminating the string here + | +LL | let x = r###"here's a long string"# "# "###; + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/raw/raw-string.stderr b/tests/ui/parser/raw/raw-string.stderr index 6654ef7a75a42..07a664ef1aad3 100644 --- a/tests/ui/parser/raw/raw-string.stderr +++ b/tests/ui/parser/raw/raw-string.stderr @@ -2,11 +2,13 @@ error[E0748]: unterminated raw string --> $DIR/raw-string.rs:2:13 | LL | let x = r##"lol"#; - | ^ - help: consider terminating the string here: `##` - | | - | unterminated raw string + | ^ unterminated raw string | = note: this raw string should be terminated with `"##` +help: consider terminating the string here + | +LL | let x = r##"lol"##; + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr b/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr index fda0919b9b647..7a3561c205300 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr @@ -2,25 +2,29 @@ error: expected identifier, found keyword `let` --> $DIR/removed-syntax-field-let-2.rs:2:5 | LL | let x: i32, - | ^^^- - | | - | expected identifier, found keyword - | help: remove this `let` keyword + | ^^^ expected identifier, found keyword | = note: the `let` keyword is not allowed in `struct` fields = note: see for more information +help: remove this `let` keyword + | +LL - let x: i32, +LL + x: i32, + | error: expected identifier, found keyword `let` --> $DIR/removed-syntax-field-let-2.rs:4:5 | LL | let y: i32, - | ^^^- - | | - | expected identifier, found keyword - | help: remove this `let` keyword + | ^^^ expected identifier, found keyword | = note: the `let` keyword is not allowed in `struct` fields = note: see for more information +help: remove this `let` keyword + | +LL - let y: i32, +LL + y: i32, + | error[E0063]: missing fields `x` and `y` in initializer of `Foo` --> $DIR/removed-syntax-field-let-2.rs:9:13 diff --git a/tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr b/tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr index 339d056e6360f..48e439c8c2c34 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr @@ -2,13 +2,15 @@ error: expected identifier, found keyword `let` --> $DIR/removed-syntax-field-let.rs:2:5 | LL | let foo: (), - | ^^^- - | | - | expected identifier, found keyword - | help: remove this `let` keyword + | ^^^ expected identifier, found keyword | = note: the `let` keyword is not allowed in `struct` fields = note: see for more information +help: remove this `let` keyword + | +LL - let foo: (), +LL + foo: (), + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-add-self-issue-131084.stderr b/tests/ui/suggestions/suggest-add-self-issue-131084.stderr index 1af7eec726273..5a78b4daaefd5 100644 --- a/tests/ui/suggestions/suggest-add-self-issue-131084.stderr +++ b/tests/ui/suggestions/suggest-add-self-issue-131084.stderr @@ -41,10 +41,13 @@ error: expected one of `:`, `@`, or `|`, found `s` --> $DIR/suggest-add-self-issue-131084.rs:21:32 | LL | fn type_before_name(String s) { - | -------^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^ expected one of `:`, `@`, or `|` + | +help: declare the type after the parameter binding + | +LL - fn type_before_name(String s) { +LL + fn type_before_name(: ) { + | error[E0424]: expected value, found module `self` --> $DIR/suggest-add-self-issue-131084.rs:11:9 diff --git a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr index d2eea3a805d99..6140de3974b00 100644 --- a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr +++ b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr @@ -2,12 +2,14 @@ error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const --> $DIR/ice-120503-async-const-method.rs:6:11 | LL | async const fn bar(&self) { - | ------^^^^^ - | | | - | | expected one of `extern`, `fn`, `safe`, or `unsafe` - | help: `const` must come before `async`: `const async` + | ^^^^^ expected one of `extern`, `fn`, `safe`, or `unsafe` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `const` must come before `async` + | +LL - async const fn bar(&self) { +LL + const async fn bar(&self) { + | error[E0379]: functions in trait impls cannot be declared const --> $DIR/ice-120503-async-const-method.rs:6:11 From 1b7ae04e212b9a12b43fcf8c04c32e90d52dd581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 21 Jul 2026 16:11:09 +0000 Subject: [PATCH 49/71] Tweak code and diagnostic formatting and messages --- .../rustc_parse/src/parser/diagnostics.rs | 10 +++++- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 35 ++++++++++++------- .../ui/attributes/attr-bad-crate-attr.stderr | 2 +- .../parser/attribute/attr-before-eof.stderr | 2 +- .../attribute/attr-dangling-in-mod.stderr | 2 +- .../attribute/attr-with-a-semicolon.stderr | 8 ++++- .../attribute/attrs-after-extern-mod.stderr | 2 +- tests/ui/parser/doc-before-attr.stderr | 2 +- tests/ui/parser/eq-less-to-less-eq.stderr | 2 +- tests/ui/parser/issues/issue-20711-2.stderr | 2 +- tests/ui/parser/issues/issue-20711.stderr | 2 +- .../removed-syntax-field-let-2.stderr | 4 +-- .../removed-syntax-field-let.stderr | 2 +- 14 files changed, 50 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9ee4576e3483c..3064c0b22592d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2062,7 +2062,15 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); } - err.span_suggestion_verbose(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable); + err.span_suggestion_verbose( + lo.shrink_to_lo(), + format!( + "{prefix}you can still access the deprecated `try!()` macro using the \ + \"raw identifier\" syntax" + ), + "r#", + Applicability::MachineApplicable, + ); let guar = err.emit(); Ok(self.mk_expr_err(lo.to(hi), guar)) } else { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a3dea980e67c2..e09b7b5d1c513 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1701,7 +1701,7 @@ impl<'a> Parser<'a> { let eq_lt = maybe_eq_tok.span.to(lt_span); err.span_suggestion_verbose( eq_lt, - "did you mean", + "you might have meant to write a \"less than or equal to\" comparison", "<=", Applicability::Unspecified, ); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6de9240c64a91..1dc8823862507 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -626,13 +626,16 @@ impl<'a> Parser<'a> { let mut err = self.dcx().struct_span_err(end.span, msg); if end.is_doc_comment() { err.span_label(end.span, "this doc comment doesn't document anything"); - } else if self.token == TokenKind::Semi { - err.span_suggestion( - self.token.span, - "consider removing this semicolon", - "", - Applicability::MaybeIncorrect, - ); + } else { + err.span_label(end.span, "expected an item after this"); + if self.token == TokenKind::Semi { + err.span_suggestion_verbose( + self.token.span, + "remove the semicolon after the attribute", + "", + Applicability::MaybeIncorrect, + ); + } } if let [.., penultimate, _] = attrs { err.span_label(start.span.to(penultimate.span), "other attributes here"); @@ -2429,16 +2432,19 @@ impl<'a> Parser<'a> { &inherited_vis, Case::Insensitive, ) { - Ok(_) => { - self.dcx().struct_span_err( + Ok(_) => self + .dcx() + .struct_span_err( lo.to(self.prev_token.span), format!("functions are not allowed in {adt_ty} definitions"), ) .with_help( "unlike in C++, Java, and C#, functions are declared in `impl` blocks", ) - .with_help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information") - } + .with_help( + "see https://doc.rust-lang.org/book/ch05-03-method-syntax.html \ + for more information", + ), Err(err) => { err.cancel(); self.restore_snapshot(snapshot); @@ -2476,12 +2482,15 @@ impl<'a> Parser<'a> { { err.span_suggestion_verbose( removal_span, - "remove this `let` keyword", + "remove the `let` keyword", String::new(), Applicability::MachineApplicable, ); err.note("the `let` keyword is not allowed in `struct` fields"); - err.note("see for more information"); + err.note( + "see \ + for more information", + ); err.emit(); return Ok(ident); } else { diff --git a/tests/ui/attributes/attr-bad-crate-attr.stderr b/tests/ui/attributes/attr-bad-crate-attr.stderr index 22522896bd1a9..885afa445efbd 100644 --- a/tests/ui/attributes/attr-bad-crate-attr.stderr +++ b/tests/ui/attributes/attr-bad-crate-attr.stderr @@ -2,7 +2,7 @@ error: expected item after attributes --> $DIR/attr-bad-crate-attr.rs:7:1 | LL | #[attr = "val"] // Unterminated - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ expected an item after this error: aborting due to 1 previous error diff --git a/tests/ui/parser/attribute/attr-before-eof.stderr b/tests/ui/parser/attribute/attr-before-eof.stderr index 18a9d77bf719c..849d7881b4ed3 100644 --- a/tests/ui/parser/attribute/attr-before-eof.stderr +++ b/tests/ui/parser/attribute/attr-before-eof.stderr @@ -2,7 +2,7 @@ error: expected item after attributes --> $DIR/attr-before-eof.rs:3:1 | LL | #[derive(Debug)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ expected an item after this error: aborting due to 1 previous error diff --git a/tests/ui/parser/attribute/attr-dangling-in-mod.stderr b/tests/ui/parser/attribute/attr-dangling-in-mod.stderr index 22cc092109d1d..6ab08317a6690 100644 --- a/tests/ui/parser/attribute/attr-dangling-in-mod.stderr +++ b/tests/ui/parser/attribute/attr-dangling-in-mod.stderr @@ -2,7 +2,7 @@ error: expected item after attributes --> $DIR/attr-dangling-in-mod.rs:4:1 | LL | #[foo = "bar"] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ expected an item after this error: aborting due to 1 previous error diff --git a/tests/ui/parser/attribute/attr-with-a-semicolon.stderr b/tests/ui/parser/attribute/attr-with-a-semicolon.stderr index 0431d3e524fe4..3edc60a3cba5c 100644 --- a/tests/ui/parser/attribute/attr-with-a-semicolon.stderr +++ b/tests/ui/parser/attribute/attr-with-a-semicolon.stderr @@ -2,7 +2,13 @@ error: expected item after attributes --> $DIR/attr-with-a-semicolon.rs:1:1 | LL | #[derive(Debug, Clone)]; - | ^^^^^^^^^^^^^^^^^^^^^^^- help: consider removing this semicolon + | ^^^^^^^^^^^^^^^^^^^^^^^ expected an item after this + | +help: remove the semicolon after the attribute + | +LL - #[derive(Debug, Clone)]; +LL + #[derive(Debug, Clone)] + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/attribute/attrs-after-extern-mod.stderr b/tests/ui/parser/attribute/attrs-after-extern-mod.stderr index f2bafa54f8dfe..639c575438bf7 100644 --- a/tests/ui/parser/attribute/attrs-after-extern-mod.stderr +++ b/tests/ui/parser/attribute/attrs-after-extern-mod.stderr @@ -4,7 +4,7 @@ error: expected item after attributes LL | extern "C" { | - while parsing this item list starting here LL | #[cfg(stage37)] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ expected an item after this LL | } | - the item list ends here diff --git a/tests/ui/parser/doc-before-attr.stderr b/tests/ui/parser/doc-before-attr.stderr index 0298b9b60d2f3..3111df9187d69 100644 --- a/tests/ui/parser/doc-before-attr.stderr +++ b/tests/ui/parser/doc-before-attr.stderr @@ -4,7 +4,7 @@ error: expected item after attributes LL | /// hi | ------ other attributes here LL | #[derive(Debug)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ expected an item after this error: aborting due to 1 previous error diff --git a/tests/ui/parser/eq-less-to-less-eq.stderr b/tests/ui/parser/eq-less-to-less-eq.stderr index b365aa9769470..efed3e2096f30 100644 --- a/tests/ui/parser/eq-less-to-less-eq.stderr +++ b/tests/ui/parser/eq-less-to-less-eq.stderr @@ -4,7 +4,7 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{` LL | if a =< b { | ^ expected one of 7 possible tokens | -help: did you mean +help: you might have meant to write a "less than or equal to" comparison | LL - if a =< b { LL + if a <= b { diff --git a/tests/ui/parser/issues/issue-20711-2.stderr b/tests/ui/parser/issues/issue-20711-2.stderr index 9fb7298955b38..738675999144f 100644 --- a/tests/ui/parser/issues/issue-20711-2.stderr +++ b/tests/ui/parser/issues/issue-20711-2.stderr @@ -5,7 +5,7 @@ LL | impl Foo { | - while parsing this item list starting here ... LL | #[stable(feature = "rust1", since = "1.0.0")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an item after this LL | LL | } | - the item list ends here diff --git a/tests/ui/parser/issues/issue-20711.stderr b/tests/ui/parser/issues/issue-20711.stderr index 256fb0ade7212..e5911c033ac9d 100644 --- a/tests/ui/parser/issues/issue-20711.stderr +++ b/tests/ui/parser/issues/issue-20711.stderr @@ -4,7 +4,7 @@ error: expected item after attributes LL | impl Foo { | - while parsing this item list starting here LL | #[stable(feature = "rust1", since = "1.0.0")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an item after this LL | LL | } | - the item list ends here diff --git a/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr b/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr index 7a3561c205300..e9d6630bd629f 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-field-let-2.stderr @@ -6,7 +6,7 @@ LL | let x: i32, | = note: the `let` keyword is not allowed in `struct` fields = note: see for more information -help: remove this `let` keyword +help: remove the `let` keyword | LL - let x: i32, LL + x: i32, @@ -20,7 +20,7 @@ LL | let y: i32, | = note: the `let` keyword is not allowed in `struct` fields = note: see for more information -help: remove this `let` keyword +help: remove the `let` keyword | LL - let y: i32, LL + y: i32, diff --git a/tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr b/tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr index 48e439c8c2c34..e470031207631 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-field-let.stderr @@ -6,7 +6,7 @@ LL | let foo: (), | = note: the `let` keyword is not allowed in `struct` fields = note: see for more information -help: remove this `let` keyword +help: remove the `let` keyword | LL - let foo: (), LL + foo: (), From 6860c6b379315cb765b126c3efec0c79d6bc21c4 Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Wed, 22 Jul 2026 13:07:05 -0300 Subject: [PATCH 50/71] Drop redundant canonical universe assumptions --- compiler/rustc_next_trait_solver/src/canonical/mod.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 0b98f312481da..b2f6ac78040b6 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -160,13 +160,7 @@ where let prev_universe = delegate.universe(); let universes_created_in_query = response.max_universe.index(); for _ in 0..universes_created_in_query { - let new_universe = delegate.create_next_universe(); - if delegate.cx().assumptions_on_binders() { - delegate.insert_placeholder_assumptions( - new_universe, - Some(rustc_type_ir::region_constraint::Assumptions::empty()), - ); - } + delegate.create_next_universe(); } let var_values = response.value.var_values(); From b1342c92174f6c10795365e8b16633cfe7df59c5 Mon Sep 17 00:00:00 2001 From: Lars Schumann Date: Wed, 22 Jul 2026 22:14:58 +0000 Subject: [PATCH 51/71] constify vec![1, 2, 3] macro arm functions --- library/alloc/src/boxed.rs | 15 +- library/alloc/src/slice.rs | 3 +- library/alloctests/tests/lib.rs | 1 + library/alloctests/tests/vec.rs | 23 +++ .../min_const_fn/bad_const_fn_body_ice.rs | 7 - .../min_const_fn/bad_const_fn_body_ice.stderr | 21 --- tests/ui/statics/check-values-constraints.rs | 23 ++- .../statics/check-values-constraints.stderr | 148 ++---------------- 8 files changed, 57 insertions(+), 184 deletions(-) delete mode 100644 tests/ui/consts/min_const_fn/bad_const_fn_body_ice.rs delete mode 100644 tests/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 4ee41bc807243..58996703023ce 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -246,7 +246,8 @@ pub struct Box< #[rustc_no_mir_inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[cfg(not(no_global_oom_handling))] -fn box_new_uninit(layout: Layout) -> *mut u8 { +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +const fn box_new_uninit(layout: Layout) -> *mut u8 { match Global.allocate(layout) { Ok(ptr) => ptr.as_mut_ptr(), Err(_) => handle_alloc_error(layout), @@ -258,10 +259,11 @@ fn box_new_uninit(layout: Layout) -> *mut u8 { /// This is unsafe, but has to be marked as safe or else we couldn't use it in `vec!`. #[doc(hidden)] #[unstable(feature = "liballoc_internals", issue = "none")] +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] #[inline(always)] #[cfg(not(no_global_oom_handling))] #[rustc_diagnostic_item = "box_assume_init_into_vec_unsafe"] -pub fn box_assume_init_into_vec_unsafe( +pub const fn box_assume_init_into_vec_unsafe( b: Box>, ) -> crate::vec::Vec { unsafe { (b.assume_init() as Box<[T]>).into_vec() } @@ -307,10 +309,11 @@ impl Box { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "new_uninit", since = "1.82.0")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub fn new_uninit() -> Box> { + pub const fn new_uninit() -> Box> { // This is the same as `Self::new_uninit_in(Global)`, but manually inlined (just like // `Box::new`). @@ -1197,8 +1200,9 @@ impl Box, A> { /// assert_eq!(*five, 5) /// ``` #[stable(feature = "new_uninit", since = "1.82.0")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] #[inline(always)] - pub unsafe fn assume_init(self) -> Box { + pub const unsafe fn assume_init(self) -> Box { // This is used in the `vec!` macro, so we optimize for minimal IR generation // even in debug builds. // SAFETY: `Box` and `Box>` have the same layout. @@ -1668,8 +1672,9 @@ impl Box { /// [memory layout]: self#memory-layout #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] #[inline] - pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) { + pub const fn into_raw_with_allocator(b: Self) -> (*mut T, A) { let mut b = mem::ManuallyDrop::new(b); // We carefully get the raw pointer out in a way that Miri's aliasing model understands what // is happening: using the primitive "deref" of `Box`. In case `A` is *not* `Global`, we diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 39e72e383eacb..da9b40c2c3ce0 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -476,8 +476,9 @@ impl [T] { /// ``` #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] #[inline] - pub fn into_vec(self: Box) -> Vec { + pub const fn into_vec(self: Box) -> Vec { unsafe { let len = self.len(); let (b, alloc) = Box::into_raw_with_allocator(self); diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 96dcde71fc071..296d0708a5f0e 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -8,6 +8,7 @@ #![feature(binary_heap_pop_if)] #![feature(casefold)] #![feature(const_btree_len)] +#![feature(const_cmp)] #![feature(const_heap)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index fc58e4364fe66..4620a9f373d6c 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2807,3 +2807,26 @@ fn const_make_global_empty_or_zst_regression() { assert_eq!(ZST_SLICE, &[(), (), ()]); } + +#[test] +fn const_heap_vec_macro() { + const X: &'static [u32] = { + let x: Vec = vec![]; + assert!(x == []); + x.const_make_global() + }; + + const Y: &'static [u32] = { + let y: Vec = vec![1, 2, 3]; + assert!(y == [1, 2, 3]); + y.const_make_global() + }; + + // This arm isn't const yet. + // const Z: &'static [u32] = { + // vec![4; 2].const_make_global() + // }; + + assert_eq!(X, []); + assert_eq!(Y, [1, 2, 3]); +} diff --git a/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.rs deleted file mode 100644 index 74e0a36560b08..0000000000000 --- a/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.rs +++ /dev/null @@ -1,7 +0,0 @@ -const fn foo(a: i32) -> Vec { - vec![1, 2, 3] - //~^ ERROR cannot call non-const - //~| ERROR cannot call non-const -} - -fn main() {} diff --git a/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr deleted file mode 100644 index a7e8fdf37ae29..0000000000000 --- a/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0015]: cannot call non-const associated function `Box::<[i32; 3]>::new_uninit` in constant functions - --> $DIR/bad_const_fn_body_ice.rs:2:5 - | -LL | vec![1, 2, 3] - | ^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::` in constant functions - --> $DIR/bad_const_fn_body_ice.rs:2:5 - | -LL | vec![1, 2, 3] - | ^^^^^^^^^^^^^ - | -note: function `box_assume_init_into_vec_unsafe` is not const - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/statics/check-values-constraints.rs b/tests/ui/statics/check-values-constraints.rs index c62abd75a304b..6f1635b761b07 100644 --- a/tests/ui/statics/check-values-constraints.rs +++ b/tests/ui/statics/check-values-constraints.rs @@ -1,5 +1,6 @@ // Verifies all possible restrictions for statics values. +#![feature(const_heap)] #![allow(warnings)] use std::marker; @@ -79,8 +80,6 @@ static STATIC10: UnsafeStruct = UnsafeStruct; struct MyOwned; static STATIC11: Vec = vec![MyOwned]; -//~^ ERROR cannot call non-const function -//~| ERROR cannot call non-const static mut STATIC12: UnsafeStruct = UnsafeStruct; @@ -93,29 +92,25 @@ static mut STATIC14: SafeStruct = SafeStruct { }; static STATIC15: &'static [Vec] = &[ - vec![MyOwned], //~ ERROR cannot call non-const function - //~| ERROR cannot call non-const - vec![MyOwned], //~ ERROR cannot call non-const function - //~| ERROR cannot call non-const + vec![MyOwned], + vec![MyOwned], ]; static STATIC16: (&'static Vec, &'static Vec) = ( - &vec![MyOwned], //~ ERROR cannot call non-const function - //~| ERROR cannot call non-const - &vec![MyOwned], //~ ERROR cannot call non-const function - //~| ERROR cannot call non-const + &vec![MyOwned], + &vec![MyOwned], ); static mut STATIC17: SafeEnum = SafeEnum::Variant1; static STATIC19: Vec = vec![3]; -//~^ ERROR cannot call non-const function -//~| ERROR cannot call non-const +//~^ ERROR encountered `const_allocate` pointer in final value that was not made global + pub fn main() { let y = { - static x: Vec = vec![3]; //~ ERROR cannot call non-const function - //~| ERROR cannot call non-const + static x: Vec = vec![3]; + //~^ ERROR encountered `const_allocate` pointer in final value that was not made global x //~^ ERROR cannot move out of static }; diff --git a/tests/ui/statics/check-values-constraints.stderr b/tests/ui/statics/check-values-constraints.stderr index 94d2b8ce80641..a3d49400703be 100644 --- a/tests/ui/statics/check-values-constraints.stderr +++ b/tests/ui/statics/check-values-constraints.stderr @@ -1,5 +1,5 @@ error[E0493]: destructor of `SafeStruct` cannot be evaluated at compile-time - --> $DIR/check-values-constraints.rs:64:7 + --> $DIR/check-values-constraints.rs:65:7 | LL | ..SafeStruct { | _______^ @@ -11,28 +11,8 @@ LL | | } LL | }; | - value is dropped here -error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics - --> $DIR/check-values-constraints.rs:81:33 - | -LL | static STATIC11: Vec = vec![MyOwned]; - | ^^^^^^^^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::` in statics - --> $DIR/check-values-constraints.rs:81:33 - | -LL | static STATIC11: Vec = vec![MyOwned]; - | ^^^^^^^^^^^^^ - | -note: function `box_assume_init_into_vec_unsafe` is not const - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - error[E0015]: cannot call non-const method `::to_string` in statics - --> $DIR/check-values-constraints.rs:92:38 + --> $DIR/check-values-constraints.rs:91:38 | LL | field2: SafeEnum::Variant4("str".to_string()), | ^^^^^^^^^^^ @@ -47,128 +27,24 @@ note: method `to_string` is not const because trait `ToString` is not const = note: calls in statics are limited to constant functions, tuple structs and tuple variants = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` -error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics - --> $DIR/check-values-constraints.rs:96:5 - | -LL | vec![MyOwned], - | ^^^^^^^^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::` in statics - --> $DIR/check-values-constraints.rs:96:5 - | -LL | vec![MyOwned], - | ^^^^^^^^^^^^^ - | -note: function `box_assume_init_into_vec_unsafe` is not const - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics - --> $DIR/check-values-constraints.rs:98:5 - | -LL | vec![MyOwned], - | ^^^^^^^^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::` in statics - --> $DIR/check-values-constraints.rs:98:5 - | -LL | vec![MyOwned], - | ^^^^^^^^^^^^^ - | -note: function `box_assume_init_into_vec_unsafe` is not const - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics - --> $DIR/check-values-constraints.rs:103:6 - | -LL | &vec![MyOwned], - | ^^^^^^^^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::` in statics - --> $DIR/check-values-constraints.rs:103:6 - | -LL | &vec![MyOwned], - | ^^^^^^^^^^^^^ - | -note: function `box_assume_init_into_vec_unsafe` is not const - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const associated function `Box::<[MyOwned; 1]>::new_uninit` in statics - --> $DIR/check-values-constraints.rs:105:6 - | -LL | &vec![MyOwned], - | ^^^^^^^^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::` in statics - --> $DIR/check-values-constraints.rs:105:6 - | -LL | &vec![MyOwned], - | ^^^^^^^^^^^^^ - | -note: function `box_assume_init_into_vec_unsafe` is not const - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const associated function `Box::<[isize; 1]>::new_uninit` in statics - --> $DIR/check-values-constraints.rs:111:31 +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/check-values-constraints.rs:106:1 | LL | static STATIC19: Vec = vec![3]; - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::` in statics - --> $DIR/check-values-constraints.rs:111:31 - | -LL | static STATIC19: Vec = vec![3]; - | ^^^^^^^ - | -note: function `box_assume_init_into_vec_unsafe` is not const - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` + = note: use `const_make_global` to turn allocated pointers into immutable globals before returning -error[E0015]: cannot call non-const associated function `Box::<[isize; 1]>::new_uninit` in statics - --> $DIR/check-values-constraints.rs:117:32 +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/check-values-constraints.rs:112:9 | LL | static x: Vec = vec![3]; - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error[E0015]: cannot call non-const function `std::boxed::box_assume_init_into_vec_unsafe::` in statics - --> $DIR/check-values-constraints.rs:117:32 - | -LL | static x: Vec = vec![3]; - | ^^^^^^^ - | -note: function `box_assume_init_into_vec_unsafe` is not const - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` + = note: use `const_make_global` to turn allocated pointers into immutable globals before returning error[E0507]: cannot move out of static item `x` - --> $DIR/check-values-constraints.rs:119:9 + --> $DIR/check-values-constraints.rs:114:9 | LL | x | ^ move occurs because `x` has type `Vec`, which does not implement the `Copy` trait @@ -182,7 +58,7 @@ help: consider cloning the value if the performance cost is acceptable LL | x.clone() | ++++++++ -error: aborting due to 17 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0015, E0493, E0507. For more information about an error, try `rustc --explain E0015`. From f9d9939467a5185a72f0ee8da778a0b71fc966ae Mon Sep 17 00:00:00 2001 From: jprochazk Date: Wed, 22 Jul 2026 15:18:28 +0200 Subject: [PATCH 52/71] make `DocLinkResMap` an `FxIndexMap` also add regression test for rmeta reproducibility when unrelated `rlib` are in the search path Co-authored-by: mejrs <59372212+mejrs@users.noreply.github.com> --- compiler/rustc_hir/src/def.rs | 6 ++-- .../client.rs | 5 ++++ .../rmeta-unrelated-search-path-files/foo.rs | 1 + .../foo_bar.rs | 1 + .../rmake.rs | 30 +++++++++++++++++++ 5 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/run-make/rmeta-unrelated-search-path-files/client.rs create mode 100644 tests/run-make/rmeta-unrelated-search-path-files/foo.rs create mode 100644 tests/run-make/rmeta-unrelated-search-path-files/foo_bar.rs create mode 100644 tests/run-make/rmeta-unrelated-search-path-files/rmake.rs diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 9d1cf7046f4b0..1481cb0726082 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -4,7 +4,7 @@ use std::fmt::Debug; use rustc_ast as ast; use rustc_ast::NodeId; -use rustc_data_structures::unord::UnordMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::{DiagArgValue, IntoDiagArg}; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_span::Symbol; @@ -962,4 +962,6 @@ pub enum LifetimeRes { ElidedAnchor { start: NodeId, end: NodeId }, } -pub type DocLinkResMap = UnordMap<(Symbol, Namespace), Option>>; +// FxIndexMap is necessary because its data ends up in .rmeta files, +// so its iteration order must be consistent. See #159677 for context. +pub type DocLinkResMap = FxIndexMap<(Symbol, Namespace), Option>>; diff --git a/tests/run-make/rmeta-unrelated-search-path-files/client.rs b/tests/run-make/rmeta-unrelated-search-path-files/client.rs new file mode 100644 index 0000000000000..a0fb04732fef1 --- /dev/null +++ b/tests/run-make/rmeta-unrelated-search-path-files/client.rs @@ -0,0 +1,5 @@ +//! [crate::Client] + +extern crate foo; + +pub struct Client; diff --git a/tests/run-make/rmeta-unrelated-search-path-files/foo.rs b/tests/run-make/rmeta-unrelated-search-path-files/foo.rs new file mode 100644 index 0000000000000..4a835673a596b --- /dev/null +++ b/tests/run-make/rmeta-unrelated-search-path-files/foo.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/tests/run-make/rmeta-unrelated-search-path-files/foo_bar.rs b/tests/run-make/rmeta-unrelated-search-path-files/foo_bar.rs new file mode 100644 index 0000000000000..1c6a3b4c6cce8 --- /dev/null +++ b/tests/run-make/rmeta-unrelated-search-path-files/foo_bar.rs @@ -0,0 +1 @@ +pub struct FooBar; diff --git a/tests/run-make/rmeta-unrelated-search-path-files/rmake.rs b/tests/run-make/rmeta-unrelated-search-path-files/rmake.rs new file mode 100644 index 0000000000000..3bd402c5c6b79 --- /dev/null +++ b/tests/run-make/rmeta-unrelated-search-path-files/rmake.rs @@ -0,0 +1,30 @@ +//@ needs-target-std +// +// Regression test for . +// +// Ensures two builds of `client.rs` produce identical metadata +// even if there is an unrelated crate on the search path. + +use run_make_support::{rfs, rustc}; + +fn main() { + rustc().input("foo.rs").crate_type("rlib").run(); + rustc() + .input("client.rs") + .crate_type("rlib") + .emit("metadata") + .library_search_path(".") + .output("client1.rmeta") + .run(); + + rustc().input("foo_bar.rs").crate_type("rlib").run(); + rustc() + .input("client.rs") + .crate_type("rlib") + .emit("metadata") + .library_search_path(".") + .output("client2.rmeta") + .run(); + + assert_eq!(rfs::read("client1.rmeta"), rfs::read("client2.rmeta")); +} From 5c012f598c320ebfde4a280d93216541466ab0b9 Mon Sep 17 00:00:00 2001 From: E Shattow Date: Thu, 28 May 2026 14:23:28 -0700 Subject: [PATCH 53/71] Promote riscv64-unknown-linux-musl to tier 2 with host tools Implements MCP 982 via issue 156191 --- .../targets/riscv64gc_unknown_linux_musl.rs | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 1 + src/bootstrap/src/core/download.rs | 1 + src/ci/docker/README.md | 16 +++++++ .../Dockerfile | 2 +- .../riscv64-unknown-linux-gnu.defconfig | 0 .../dist-riscv64-linux-musl/Dockerfile | 39 ++++++++++++++++ .../riscv64-unknown-linux-musl.defconfig | 16 +++++++ src/ci/github-actions/jobs.yml | 5 +- src/doc/rustc/src/platform-support.md | 2 +- .../riscv64gc-unknown-linux-gnu.md | 15 +++--- .../riscv64gc-unknown-linux-musl.md | 46 +++++++++++-------- 12 files changed, 116 insertions(+), 29 deletions(-) rename src/ci/docker/host-x86_64/{dist-riscv64-linux => dist-riscv64-linux-gnu}/Dockerfile (92%) rename src/ci/docker/host-x86_64/{dist-riscv64-linux => dist-riscv64-linux-gnu}/riscv64-unknown-linux-gnu.defconfig (100%) create mode 100644 src/ci/docker/host-x86_64/dist-riscv64-linux-musl/Dockerfile create mode 100644 src/ci/docker/host-x86_64/dist-riscv64-linux-musl/riscv64-unknown-linux-musl.defconfig diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs index 8ed4e09adbbfe..088d4821042d8 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs @@ -10,7 +10,7 @@ pub(crate) fn target() -> Target { metadata: TargetMetadata { description: Some("RISC-V Linux (kernel 4.20, musl 1.2.5)".into()), tier: Some(2), - host_tools: Some(false), + host_tools: Some(true), std: Some(true), }, pointer_width: 64, diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 572df47d3a62c..b13759cfdaa25 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -248,6 +248,7 @@ pub(crate) fn is_ci_llvm_available_for_target( ("powerpc64le-unknown-linux-gnu", false), ("powerpc64le-unknown-linux-musl", false), ("riscv64gc-unknown-linux-gnu", false), + ("riscv64gc-unknown-linux-musl", false), ("s390x-unknown-linux-gnu", false), ("x86_64-pc-windows-gnullvm", false), ("x86_64-unknown-freebsd", false), diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 76fd2cb0bc14b..4058f1482a951 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -481,6 +481,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo "powerpc64le-unknown-linux-gnu", "powerpc64le-unknown-linux-musl", "riscv64gc-unknown-linux-gnu", + "riscv64gc-unknown-linux-musl", "s390x-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-gnu", diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 6e5a38a3c515a..b113adc2008cd 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -462,6 +462,22 @@ For targets: `riscv64-unknown-linux-gnu` - C compiler > gcc version = 8.5.0 - C compiler > C++ = ENABLE -- to cross compile LLVM +### `riscv64-unknown-linux-musl.defconfig` + +For targets: `riscv64-unknown-linux-musl` + +- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Use a mirror = ENABLE +- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc +- Target options > Target Architecture = riscv +- Target options > Bitness = 64-bit +- Operating System > Target OS = linux +- Operating System > Linux kernel version = 4.20.17 +- Binary utilities > Version of binutils = 2.40 +- C-library > musl version = 1.2.5 +- C compiler > gcc version = 8.5.0 +- C compiler > C++ = ENABLE -- to cross compile LLVM + ### `s390x-linux-gnu.defconfig` For targets: `s390x-unknown-linux-gnu` diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-riscv64-linux-gnu/Dockerfile similarity index 92% rename from src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile rename to src/ci/docker/host-x86_64/dist-riscv64-linux-gnu/Dockerfile index 5186c99c4f430..57f3b68a96e3f 100644 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux-gnu/Dockerfile @@ -12,7 +12,7 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig +COPY host-x86_64/dist-riscv64-linux-gnu/riscv64-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-riscv64-linux-gnu/riscv64-unknown-linux-gnu.defconfig similarity index 100% rename from src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig rename to src/ci/docker/host-x86_64/dist-riscv64-linux-gnu/riscv64-unknown-linux-gnu.defconfig diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-riscv64-linux-musl/Dockerfile new file mode 100644 index 0000000000000..bb7537fc7d279 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux-musl/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:22.04 + +COPY scripts/cross-apt-packages.sh /scripts/ +RUN sh /scripts/cross-apt-packages.sh + +COPY scripts/crosstool-ng.sh /scripts/ +COPY scripts/crosstool-ng-sha256-20260705.diff /scripts/ +RUN sh /scripts/crosstool-ng.sh + +COPY scripts/rustbuild-setup.sh /scripts/ +RUN sh /scripts/rustbuild-setup.sh + +WORKDIR /tmp + +COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-riscv64-linux-musl/riscv64-unknown-linux-musl.defconfig /tmp/crosstool.defconfig +RUN /scripts/crosstool-ng-build.sh + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV PATH=$PATH:/x-tools/riscv64-unknown-linux-musl/bin + +ENV CC_riscv64gc_unknown_linux_musl=riscv64-unknown-linux-musl-gcc \ + AR_riscv64gc_unknown_linux_musl=riscv64-unknown-linux-musl-ar \ + CXX_riscv64gc_unknown_linux_musl=riscv64-unknown-linux-musl-g++ + +ENV HOSTS=riscv64gc-unknown-linux-musl +ENV TARGETS=riscv64gc-unknown-linux-musl + +ENV RUST_CONFIGURE_ARGS="--enable-extended \ + --enable-full-tools \ + --enable-profiler \ + --enable-sanitizers \ + --disable-docs \ + --set target.riscv64gc-unknown-linux-musl.crt-static=false \ + --musl-root-riscv64gc=/x-tools/riscv64-unknown-linux-musl/riscv64-unknown-linux-musl/sysroot/usr" + +ENV SCRIPT="python3 ../x.py dist --target $TARGETS --host $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux-musl/riscv64-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-riscv64-linux-musl/riscv64-unknown-linux-musl.defconfig new file mode 100644 index 0000000000000..435a2bea80d36 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux-musl/riscv64-unknown-linux-musl.defconfig @@ -0,0 +1,16 @@ +CT_CONFIG_VERSION="4" +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_USE_MIRROR=y +CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_VERIFY_DOWNLOAD_DIGEST_SHA256=y +CT_ARCH_RISCV=y +CT_ARCH_USE_MMU=y +CT_ARCH_64=y +CT_ARCH_ARCH="rv64gc" +CT_KERNEL_LINUX=y +CT_LINUX_V_4_20=y +CT_LIBC_MUSL=y +CT_BINUTILS_V_2_40=y +CT_MUSL_V_1_2_5=y +CT_GCC_V_8=y +CT_CC_LANG_CXX=y diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index a236effaa9b40..c374888ac8909 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -270,7 +270,10 @@ auto: - name: dist-powerpc64le-linux-musl <<: *job-linux-4c - - name: dist-riscv64-linux + - name: dist-riscv64-linux-gnu + <<: *job-linux-4c + + - name: dist-riscv64-linux-musl <<: *job-linux-4c - name: dist-s390x-linux diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index ce4d55c2d2b00..c527911bc96a2 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -105,6 +105,7 @@ target | notes [`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10+, glibc 2.17) [`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19+, musl 1.2.5) [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20+, glibc 2.29) +[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20+, musl 1.2.5) [`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2+, glibc 2.17) [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+) [`x86_64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | 64-bit x86 MinGW (Windows 10+), LLVM ABI @@ -196,7 +197,6 @@ target | std | notes [`riscv32imafc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA) [`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA) [`riscv64a23-unknown-linux-gnu`](platform-support/riscv64a23-unknown-linux-gnu.md) | ✓ | RISC-V Linux (kernel 6.8.0+, glibc 2.39) -[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | ✓ |RISC-V Linux (kernel 4.20+, musl 1.2.5) `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) [`riscv64im-unknown-none-elf`](platform-support/riscv64im-unknown-none-elf.md) | * | Bare RISC-V (RV64IM ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md index d62a65b21904f..119c3053cda7e 100644 --- a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md +++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md @@ -2,7 +2,8 @@ **Tier: 2 (with Host Tools)** -RISC-V targets using the *RV64I* base instruction set with the *G* collection of extensions, as well as the *C* extension. +Linux GNU libc RISC-V target using the *RV64I* base instruction set with the +*G* collection of extensions, as well as the *C* extension. ## Target maintainers @@ -22,10 +23,10 @@ This target requires: ## Building the target -These targets are distributed through `rustup`, and otherwise require no +This target is distributed through `rustup`, and otherwise requires no special configuration. -If you need to build your own Rust for some reason though, the targets can be +If you need to build your own Rust for some reason though, the target can be enabled in `bootstrap.toml`. For example: ```toml @@ -37,10 +38,10 @@ target = ["riscv64gc-unknown-linux-gnu"] ## Building Rust programs -On a RISC-V host, the `riscv64gc-unknown-linux-gnu` target should be automatically -installed and used by default. +On a riscv64gc-unknown-linux-gnu host, the `riscv64gc-unknown-linux-gnu` +target should be automatically installed and used by default. -On a non-RISC-V host, add the target: +On all other hosts, add the target: ```bash rustup target add riscv64gc-unknown-linux-gnu @@ -55,7 +56,7 @@ cargo build --target riscv64gc-unknown-linux-gnu ## Testing -There are no special requirements for testing and running the targets. +There are no special requirements for testing and running the target. For testing cross builds on the host, please refer to the "Cross-compilation toolchains and C code" section below. diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md index 2e88b5aa813ff..4ac2a894117c1 100644 --- a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md +++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md @@ -1,8 +1,10 @@ # riscv64gc-unknown-linux-musl -**Tier: 2** +**Tier: 2 (with Host Tools)** + +Linux musl libc RISC-V target using the *RV64I* base instruction set with the +*G* collection of extensions, as well as the *C* extension. -Target for RISC-V Linux programs using musl libc. ## Target maintainers @@ -11,37 +13,45 @@ Target for RISC-V Linux programs using musl libc. ## Requirements -Building the target itself requires a RISC-V compiler that is supported by `cc-rs`. +This target requires: + +* Linux Kernel version 4.20 or later +* musl libc 1.2.5 or later + ## Building the target -The target can be built by enabling it for a `rustc` build. +This target is distributed through `rustup`, and otherwise requires no +special configuration. + +If you need to build your own Rust then the targets can be enabled in +`bootstrap.toml`. For example: ```toml [build] target = ["riscv64gc-unknown-linux-musl"] ``` -Make sure your C compiler is included in `$PATH`, then add it to the `bootstrap.toml`: - -```toml -[target.riscv64gc-unknown-linux-musl] -cc = "riscv64-linux-gnu-gcc" -cxx = "riscv64-linux-gnu-g++" -ar = "riscv64-linux-gnu-ar" -linker = "riscv64-linux-gnu-gcc" -``` ## Building Rust programs -This target are distributed through `rustup`, and otherwise require no -special configuration. -## Cross-compilation +On a riscv64gc-unknown-linux-musl host, the `riscv64gc-unknown-linux-musl` +target should be automatically installed and used by default. -This target can be cross-compiled from any host. +On all other hosts, add the target: + +```bash +rustup target add riscv64gc-unknown-linux-musl +``` + +Then cross compile crates with: + +```bash +cargo build --target riscv64gc-unknown-linux-musl +``` ## Testing -This target can be tested as normal with `x.py` on a RISC-V host or via QEMU +The target can be tested as normal with `x.py` on a RISC-V host or via QEMU emulation. From 3086aff340346d1ef047dd556298e66532eb4983 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Tue, 21 Jul 2026 23:50:26 +0200 Subject: [PATCH 54/71] don't build riscv64gc-unknown-linux-musl twice --- .../docker/host-x86_64/dist-various-2/Dockerfile | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index f07fb91edaf0b..12705809e4290 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -24,8 +24,7 @@ RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y --no # Needed for apt-key to work: dirmngr \ gpg-agent \ - g++-9-arm-linux-gnueabi \ - g++-11-riscv64-linux-gnu + g++-9-arm-linux-gnueabi ENV \ AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \ @@ -71,10 +70,6 @@ RUN env \ CC=arm-linux-gnueabi-gcc-9 CFLAGS="-march=armv7-a" \ CXX=arm-linux-gnueabi-g++-9 CXXFLAGS="-march=armv7-a" \ bash musl.sh armv7 && \ - env \ - CC=riscv64-linux-gnu-gcc-11 \ - CXX=riscv64-linux-gnu-g++-11 \ - bash musl.sh riscv64gc && \ rm -rf /build/* WORKDIR /tmp @@ -120,7 +115,6 @@ ENV TARGETS=$TARGETS,x86_64-unknown-none ENV TARGETS=$TARGETS,aarch64-unknown-uefi ENV TARGETS=$TARGETS,i686-unknown-uefi ENV TARGETS=$TARGETS,x86_64-unknown-uefi -ENV TARGETS=$TARGETS,riscv64gc-unknown-linux-musl ENV TARGETS_SANITIZERS=x86_64-unknown-linux-gnuasan ENV TARGETS_SANITIZERS=$TARGETS_SANITIZERS,x86_64-unknown-linux-gnumsan @@ -132,11 +126,7 @@ ENV TARGETS_SANITIZERS=$TARGETS_SANITIZERS,x86_64-unknown-linux-gnutsan # Luckily one of the folders is /usr/local/include so symlink /usr/include/x86_64-linux-gnu/asm there RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/local/include/asm -# musl-gcc can't find libgcc_s.so.1 since it doesn't use the standard search paths. -RUN ln -s /usr/riscv64-linux-gnu/lib/libgcc_s.so.1 /usr/lib/gcc-cross/riscv64-linux-gnu/11/ - ENV RUST_CONFIGURE_ARGS="--enable-extended --enable-lld --enable-llvm-bitcode-linker --disable-docs \ - --musl-root-armv7=/musl-armv7 \ - --musl-root-riscv64gc=/musl-riscv64gc" + --musl-root-armv7=/musl-armv7" ENV SCRIPT="python3 ../x.py dist --host= --target $TARGETS && python3 ../x.py dist --host= --set build.sanitizers=true --target $TARGETS_SANITIZERS" From 2af4af2fb1abcdd12eb116c3f5c451e20b8b82f1 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 23 Jul 2026 09:13:59 +0200 Subject: [PATCH 55/71] update download-ci-llvm-stamp --- src/bootstrap/download-ci-llvm-stamp | 2 +- .../rustc/src/platform-support/riscv64gc-unknown-linux-musl.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index b61c7b18bad01..ba6dcfc761c5a 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/157385 +Last change is for: https://github.com/rust-lang/rust/pull/158766 diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md index 4ac2a894117c1..12872b74b6820 100644 --- a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md +++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md @@ -35,7 +35,6 @@ target = ["riscv64gc-unknown-linux-musl"] ## Building Rust programs - On a riscv64gc-unknown-linux-musl host, the `riscv64gc-unknown-linux-musl` target should be automatically installed and used by default. From f46856816629ab21354fd766225e9dea9540c388 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 09:38:06 +0200 Subject: [PATCH 56/71] reflow --- .../rustc-dev-guide/src/debuginfo/debugger-internals.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md index 574bb3be6a0d2..3da43fe898dae 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md @@ -1,8 +1,8 @@ # Debugger internals It is the debugger's job to convert the debug info into an in-memory representation. -Both the -interpretation of the debug info and the in-memory representation are arbitrary; anything will do +Both the interpretation of the debug info and the in-memory representation are arbitrary; +anything will do, so long as meaningful information can be reconstructed while the program is running. The pipeline from raw debug info to usable types can be quite complicated. @@ -10,7 +10,7 @@ Once the information is in a workable format, the debugger front-end then must p interpret and display the data, a way for users to interact with it, and an API for extensibility. Debuggers are vast systems and cannot be covered completely here. -This section will provide a brief -overview of the subsystems directly relevant to the Rust debugging experience. +This section will provide a brief overview of the subsystems +directly relevant to the Rust debugging experience. Microsoft's debugging engine is closed source, so it will not be covered here. From 31f2f1518a59fdd67bdc763de02c137c05371458 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 09:38:59 +0200 Subject: [PATCH 57/71] sembr src/debuginfo/lldb-internals.md --- .../src/debuginfo/lldb-internals.md | 119 +++++++++++------- 1 file changed, 74 insertions(+), 45 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md index 8119662b3d791..eaa7a022762e5 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md @@ -1,7 +1,8 @@ # LLDB internals LLDB's debug info processing relies on a set of extensible interfaces largely defined in -[lldb/src/Plugins][lldb_plugins]. These are meant to allow third-party compiler developers to add +[lldb/src/Plugins][lldb_plugins]. +These are meant to allow third-party compiler developers to add language support that is loaded at run-time by LLDB, but at time of writing (Nov 2025) the public API has not been settled on, so plugins exist either in LLDB itself or in standalone forks of LLDB. @@ -16,27 +17,32 @@ Here are some existing implementations of LLDB's plugin API: * [CodeLLDB's former fork with support for Rust](https://archive.softwareheritage.org/browse/origin/directory/?branch=refs/heads/codelldb/16.x&origin_url=https://github.com/vadimcn/llvm-project&path=lldb/source/Plugins/TypeSystem/Rust×tamp=2023-09-11T04:55:10Z) * [A work in progress reimplementation of Rust support](https://github.com/Walnut356/llvm-project/tree/lldbrust/19.x) * [A Rust expression parser plugin](https://github.com/tromey/lldb/tree/a0fc10ce0dacb3038b7302fff9f6cb8cb34b37c6/source/Plugins/ExpressionParser/Rust). -This was written before the `TypeSystem` API was created. Due to the freeform nature of expression parsing, the +This was written before the `TypeSystem` API was created. +Due to the freeform nature of expression parsing, the underlyng lexing, parsing, function calling, etc. should still offer valuable insights. ## Rust support and TypeSystemClang -As mentioned in the debug info overview, LLDB has partial Rust support. To further clarify, Rust +As mentioned in the debug info overview, LLDB has partial Rust support. +To further clarify, Rust uses the plugin-pipeline that was built for C/C++ (though it contains some helpers for Rust enum -types), which relies directly on the `clang` compiler's representation of types. This imposes heavy -restrictions on how much we can change when LLDB's output doesn't match what we want. Some +types), which relies directly on the `clang` compiler's representation of types. +This imposes heavy +restrictions on how much we can change when LLDB's output doesn't match what we want. +Some workarounds can help, but at the end of the day Rust's needs are secondary compared to making sure C and C++ compilation and debugging work correctly. -LLDB is receptive to adding a `TypeSystemRust`, but it is a massive undertaking. This section serves +LLDB is receptive to adding a `TypeSystemRust`, but it is a massive undertaking. +This section serves to not only document how we currently interact with [`TypeSystemClang`][ts_clang], but also as light guidance on implementing a `TypeSystemRust` in the future. [ts_clang]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/TypeSystem/Clang It is worth noting that a `TypeSystem` directly interacting with the target language's compiler is -the intention, but it is not a requirement. One can create all the necessary supporting types within -their plugin implementation. +the intention, but it is not a requirement. +One can create all the necessary supporting types within their plugin implementation. > Note: LLDB's documentation, including comments in the source code, is pretty sparse. Trying to > understand how language support works by reading `TypeSystemClang`'s implementation is somewhat @@ -47,8 +53,9 @@ their plugin implementation. ## DWARF vs PDB -LLDB is unique in being able to handle both DWARF and PDB debug information. This does come with -some added complexity. To complicate matters further, PDB support is split between `dia`, which +LLDB is unique in being able to handle both DWARF and PDB debug information. +This does come with some added complexity. +To complicate matters further, PDB support is split between `dia`, which relies on the `msdia140.dll` library distributed with Visual Studio, and `native`, which is written from scratch using publicly available information about the PDB format. @@ -65,48 +72,59 @@ from scratch using publicly available information about the PDB format. ## Debug node parsing -The first step is to process the raw debug nodes into something usable. This primarily occurs in -the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. These classes are fed a +The first step is to process the raw debug nodes into something usable. +This primarily occurs in the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. +These classes are fed a deserialized form of the debug info generated from [`SymbolFileDWARF`][sf_dwarf] and -[`SymbolFileNativePDB`][sf_pdb] respectively. The `SymbolFile` implementers make almost no -transformations to the underlying debug info before passing it to the parsers. For both PDB and -DWARF, the debug info is read using LLVM's debug info handlers. +[`SymbolFileNativePDB`][sf_pdb] respectively. +The `SymbolFile` implementers make almost no +transformations to the underlying debug info before passing it to the parsers. +For both PDB and DWARF, the debug info is read using LLVM's debug info handlers. [dwarf_ast]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/SymbolFile/DWARF [pdb_ast]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/SymbolFile/NativePDB [sf_dwarf]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h [sf_pdb]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h -The parsers translate the nodes into more convenient formats for LLDB's purposes. For `clang`, these +The parsers translate the nodes into more convenient formats for LLDB's purposes. +For `clang`, these formats are `clang::QualType`, `clang::Decl`, and `clang::DeclContext`, which are the types `clang` -uses internally when compiling C and C++. Again, using the compiler's representation of types is not a +uses internally when compiling C and C++. +Again, using the compiler's representation of types is not a requirement, but the plugin system was built with it as a possibility. > Note: The above types will be referred to language-agnostically as `LangType`, `Decl`, and `DeclContext` when the specific implementation details of `TypeSystemClang` are not relevant. -`LangType` represents a type. This includes information such as the name of the type, the size and +`LangType` represents a type. +This includes information such as the name of the type, the size and alignment, its classification (e.g. struct, primitive, pointer), its qualifiers (e.g. `const`, `volatile`), template arguments, function argument and return types, etc. [Here][rust_type] is an example of what a `RustType` might look like. [rust_type]: https://github.com/Walnut356/llvm-project/blob/13bcfd502452606d69faeea76aec3a06db554af9/lldb/source/Plugins/TypeSystem/Rust/TypeSystemRust.h#L618 -`Decl` represents any kind of declaration. It could be a type, a variable, a static field of a +`Decl` represents any kind of declaration. +It could be a type, a variable, a static field of a struct, the value that a static or const is initialized with, etc. -`DeclContext` more or less represents a scope. `DeclContext`s typically contain `Decl`s and other -`DeclContexts`, though the relationship isn't that straight forward. For example, a function can be +`DeclContext` more or less represents a scope. +`DeclContext`s typically contain `Decl`s and other +`DeclContexts`, though the relationship isn't that straight forward. +For example, a function can be both a `Decl` (because function signatures are types), **and** a `DeclContext` (because functions contain variable declarations, nested functions declarations, etc.). -The translation process can be quite verbose, but is usually straightforward. Much of the work here +The translation process can be quite verbose, but is usually straightforward. +Much of the work here is dependant on the exact information needed to fill out `LangType`, `Decl`, and `DeclContext`. Once a node is translated, a pointer to it is type-erased (`void*`) and wrapped in `CompilerType`, -`CompilerDecl`, or `CompilerDeclContext`. These wrappers associate the them with the `TypeSystem` -that owns them. Methods on these objects delegates to the `TypeSystem`, which casts the `void*` back -to the appropriate `LangType*`/`Decl*`/`DeclContext*` and operates on the internals. In Rust terms, +`CompilerDecl`, or `CompilerDeclContext`. +These wrappers associate the them with the `TypeSystem` that owns them. +Methods on these objects delegates to the `TypeSystem`, which casts the `void*` back +to the appropriate `LangType*`/`Decl*`/`DeclContext*` and operates on the internals. +In Rust terms, the relationship looks something like this: ```Rust @@ -141,9 +159,11 @@ The [`TypeSystem` interface][ts_interface] has 3 major purposes: [ts_interface]: https://github.com/llvm/llvm-project/blob/main/lldb/include/lldb/Symbol/TypeSystem.h#L69 -1. Act as the "sole authority" of a language's types. This allows the type system to be added to -LLDB's "pool" of type systems. When an executable is loaded, the target language is determined, and -the pool is queried to find a `TypeSystem` that claims it can handle the language. One can also use +1. Act as the "sole authority" of a language's types. + This allows the type system to be added to LLDB's "pool" of type systems. +When an executable is loaded, the target language is determined, and +the pool is queried to find a `TypeSystem` that claims it can handle the language. +One can also use the `TypeSystem` to retrieve the backing `SymbolFile`, search for types, and synthesize basic types that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers-to-`T`). 2. Manage the lifetimes of the `LangType`, `Decl`, and `DeclContext` objects @@ -152,41 +172,49 @@ that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers The first two functions are pretty straightforward so we will focus on the third. Many of the functions in the `TypeSystem` interface will look familiar if you have worked with the -visualizer scripts. These functions underpin `SBType` the `SBValue` functions with matching names. +visualizer scripts. +These functions underpin `SBType` the `SBValue` functions with matching names. For example, `TypeSystem::GetFormat` returns the default format for the type if no custom formatter has been applied to it. -Of particular note are `GetIndexOfChildWithName` and `GetNumChildren`. The `TypeSystem` versions of -these functions operate on a *type*, not a value like the `SBValue` versions. The values returned +Of particular note are `GetIndexOfChildWithName` and `GetNumChildren`. +The `TypeSystem` versions of +these functions operate on a *type*, not a value like the `SBValue` versions. +The values returned from the `TypeSystem` functions dictate what parts of the struct can be interacted with *at all* by -the rest of LLDB. If a field is ommitted, that field effectively no longer exists to LLDB. +the rest of LLDB. +If a field is ommitted, that field effectively no longer exists to LLDB. Additionally, since they do not work with objects, there is no underlying memory to inspect or -interpret. Essentially, this means these functions do not have the same purpose as their equivalent -`SyntheticProvider` functions. There is no way to determine how many elements a `Vec` has or what -address those elements live at. It is also not possible to determine the value of the discriminant -of a sum-type. +interpret. +Essentially, this means these functions do not have the same purpose as their equivalent +`SyntheticProvider` functions. +There is no way to determine how many elements a `Vec` has or what address those elements live at. +It is also not possible to determine the value of the discriminant of a sum-type. Ideally, the `TypeSystem` should expose types as they appear in the debug info with as few -alterations as possible. LLDB's synthetics and frontend can handle making the type pretty. If some +alterations as possible. +LLDB's synthetics and frontend can handle making the type pretty. +If some piece of information is useless, the Rust compiler should be altered to not output that debug info in the first place. ## Expression parsing -The `TypeSystem` is typically written to have a counterpart that can handle expression parsing. It -requires implementing a few extra functions in the `TypeSystem` interface. The bulk of the -expression parsing code should live in [lldb/source/Plugins/ExpressionParser][expr]. +The `TypeSystem` is typically written to have a counterpart that can handle expression parsing. +It requires implementing a few extra functions in the `TypeSystem` interface. +The bulk of the expression parsing code should live in [lldb/source/Plugins/ExpressionParser][expr]. [expr]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/ExpressionParser -There isn't too much of note about the parser. It requires implementing a simple interpreter that -can handle (possibly simplified) Rust syntax. They operate on `lldb::ValueObject`s, which are the -objects that underpin `SBValue`. +There isn't too much of note about the parser. +It requires implementing a simple interpreter that can handle (possibly simplified) Rust syntax. +They operate on `lldb::ValueObject`s, which are the objects that underpin `SBValue`. ## Language -The [`Language` plugins][lang_plugin] are the C++ equivalent to the Python visualizer scripts. They +The [`Language` plugins][lang_plugin] are the C++ equivalent to the Python visualizer scripts. +They operate on `SBValue` objects for the same purpose: creating synthetic children and pretty-printing. The [CPlusPlusLanguage's implementations][cpp_lang] for the LibCxx types are great resources to learn how visualizers should be written. @@ -200,7 +228,8 @@ their python equivalent. While debug node parsing, type systems, and expression parsing are all closely tied to eachother, the `Language` plugin is encapsulated more and thus can be written "standalone" for any language -that an existing type system supports. Due to the lower barrier of entry, a `RustLanguage` plugin +that an existing type system supports. +Due to the lower barrier of entry, a `RustLanguage` plugin may be a good stepping stone towards full language support in LLDB. ## Visualizers From 225b77c53dcd927cbd4b0d55732d09fc49e55b70 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 09:53:35 +0200 Subject: [PATCH 58/71] reflow --- .../src/debuginfo/lldb-internals.md | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md index eaa7a022762e5..98eb1da6e77eb 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md @@ -24,21 +24,21 @@ underlyng lexing, parsing, function calling, etc. should still offer valuable in ## Rust support and TypeSystemClang As mentioned in the debug info overview, LLDB has partial Rust support. -To further clarify, Rust -uses the plugin-pipeline that was built for C/C++ (though it contains some helpers for Rust enum -types), which relies directly on the `clang` compiler's representation of types. -This imposes heavy -restrictions on how much we can change when LLDB's output doesn't match what we want. -Some -workarounds can help, but at the end of the day Rust's needs are secondary compared to making sure +To further clarify, +Rust uses the plugin-pipeline that was built for C/C++ +(though it contains some helpers for Rust enum types), +which relies directly on the `clang` compiler's representation of types. +This imposes heavy restrictions on how much we can change +when LLDB's output doesn't match what we want. +Some workarounds can help, but at the end of the day, +Rust's needs are secondary compared to making sure C and C++ compilation and debugging work correctly. LLDB is receptive to adding a `TypeSystemRust`, but it is a massive undertaking. -This section serves -to not only document how we currently interact with [`TypeSystemClang`][ts_clang], but also as light -guidance on implementing a `TypeSystemRust` in the future. +This section serves to not only document how we currently interact with [`TypeSystemClang`], +but also as light guidance on implementing a `TypeSystemRust` in the future. -[ts_clang]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/TypeSystem/Clang +[`TypeSystemClang`]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/TypeSystem/Clang It is worth noting that a `TypeSystem` directly interacting with the target language's compiler is the intention, but it is not a requirement. @@ -74,9 +74,8 @@ from scratch using publicly available information about the PDB format. The first step is to process the raw debug nodes into something usable. This primarily occurs in the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. -These classes are fed a -deserialized form of the debug info generated from [`SymbolFileDWARF`][sf_dwarf] and -[`SymbolFileNativePDB`][sf_pdb] respectively. +These classes are fed a deserialized form of the debug info +generated from [`SymbolFileDWARF`][sf_dwarf] and [`SymbolFileNativePDB`][sf_pdb] respectively. The `SymbolFile` implementers make almost no transformations to the underlying debug info before passing it to the parsers. For both PDB and DWARF, the debug info is read using LLVM's debug info handlers. @@ -87,9 +86,8 @@ For both PDB and DWARF, the debug info is read using LLVM's debug info handlers. [sf_pdb]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h The parsers translate the nodes into more convenient formats for LLDB's purposes. -For `clang`, these -formats are `clang::QualType`, `clang::Decl`, and `clang::DeclContext`, which are the types `clang` -uses internally when compiling C and C++. +For `clang`, these formats are `clang::QualType`, `clang::Decl`, and `clang::DeclContext`, +which are the types `clang` uses internally when compiling C and C++. Again, using the compiler's representation of types is not a requirement, but the plugin system was built with it as a possibility. @@ -111,13 +109,13 @@ struct, the value that a static or const is initialized with, etc. `DeclContext` more or less represents a scope. `DeclContext`s typically contain `Decl`s and other `DeclContexts`, though the relationship isn't that straight forward. -For example, a function can be -both a `Decl` (because function signatures are types), **and** a `DeclContext` (because functions -contain variable declarations, nested functions declarations, etc.). +For example, a function can be both a `Decl` (because function signatures are types), +**and** a `DeclContext` +(because functions contain variable declarations, nested functions declarations, etc.). The translation process can be quite verbose, but is usually straightforward. -Much of the work here -is dependant on the exact information needed to fill out `LangType`, `Decl`, and `DeclContext`. +Much of the work here is dependant on the exact information needed to fill out `LangType`, +`Decl`, and `DeclContext`. Once a node is translated, a pointer to it is type-erased (`void*`) and wrapped in `CompilerType`, `CompilerDecl`, or `CompilerDeclContext`. @@ -161,11 +159,11 @@ The [`TypeSystem` interface][ts_interface] has 3 major purposes: 1. Act as the "sole authority" of a language's types. This allows the type system to be added to LLDB's "pool" of type systems. -When an executable is loaded, the target language is determined, and -the pool is queried to find a `TypeSystem` that claims it can handle the language. -One can also use -the `TypeSystem` to retrieve the backing `SymbolFile`, search for types, and synthesize basic types -that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers-to-`T`). + When an executable is loaded, the target language is determined, and + the pool is queried to find a `TypeSystem` that claims it can handle the language. + One can also use the `TypeSystem` to retrieve the backing `SymbolFile`, + search for types, and synthesize basic types + that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers-to-`T`). 2. Manage the lifetimes of the `LangType`, `Decl`, and `DeclContext` objects 3. Customize the "defaults" of how those types appear and how they can be interacted with. @@ -178,11 +176,10 @@ For example, `TypeSystem::GetFormat` returns the default format for the type if has been applied to it. Of particular note are `GetIndexOfChildWithName` and `GetNumChildren`. -The `TypeSystem` versions of -these functions operate on a *type*, not a value like the `SBValue` versions. -The values returned -from the `TypeSystem` functions dictate what parts of the struct can be interacted with *at all* by -the rest of LLDB. +The `TypeSystem` versions of these functions operate on a *type*, +not a value like the `SBValue` versions. +The values returned from the `TypeSystem` functions +dictate what parts of the struct can be interacted with *at all* by the rest of LLDB. If a field is ommitted, that field effectively no longer exists to LLDB. Additionally, since they do not work with objects, there is no underlying memory to inspect or @@ -195,9 +192,8 @@ It is also not possible to determine the value of the discriminant of a sum-type Ideally, the `TypeSystem` should expose types as they appear in the debug info with as few alterations as possible. LLDB's synthetics and frontend can handle making the type pretty. -If some -piece of information is useless, the Rust compiler should be altered to not output that debug info -in the first place. +If some piece of information is useless, +the Rust compiler should be altered to not output that debug info in the first place. ## Expression parsing @@ -214,8 +210,8 @@ They operate on `lldb::ValueObject`s, which are the objects that underpin `SBVal ## Language The [`Language` plugins][lang_plugin] are the C++ equivalent to the Python visualizer scripts. -They -operate on `SBValue` objects for the same purpose: creating synthetic children and pretty-printing. +They operate on `SBValue` objects for the same purpose: +creating synthetic children and pretty-printing. The [CPlusPlusLanguage's implementations][cpp_lang] for the LibCxx types are great resources to learn how visualizers should be written. From 7b106868bf1dca0079156530fccd06a631b06683 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 09:54:35 +0200 Subject: [PATCH 59/71] sembr src/debuginfo/debugger-visualizers.md --- .../src/debuginfo/debugger-visualizers.md | 86 ++++++++++++------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md index e3b82b1d4a421..ce4835728df99 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md @@ -3,40 +3,47 @@ These are typically the last step before the debugger displays the information, but the results may be piped through a debug adapter such as an IDE's debugger API. -The term "Visualizer" is a bit of a misnomer. The real goal isn't just to prettify the output, but -to provide an interface for the user to interact with that is as useful as possible. In many cases +The term "Visualizer" is a bit of a misnomer. +The real goal isn't just to prettify the output, but +to provide an interface for the user to interact with that is as useful as possible. +In many cases this means reconstructing the original type as closely as possible to its Rust representation, but not always. The visualizer interface allows generating "synthetic children" - fields that don't exist in the -debug info, but can be derived from invariants about the language and the type itself. A simple +debug info, but can be derived from invariants about the language and the type itself. +A simple example is allowing one to interact with the elements of a `Vec` instead of just it's `*mut u8` heap pointer, length, and capacity. ## `rust-lldb`, `rust-gdb`, and `rust-windbg.cmd` -These support scripts are distributed with Rust toolchains. They locate the appropriate debugger and +These support scripts are distributed with Rust toolchains. +They locate the appropriate debugger and the toolchain's visualizer scripts, then launch the debugger with the appropriate arguments to load the visualizer scripts before a debugee is launched/attached to. ## `#![debugger_visualizer]` [This attribute][dbg_vis_attr] allows Rust library authors to include pretty printers for their -types within the library itself. These pretty printers are of the same format as typical -visualizers, but are embedded directly into the compiled binary. These scripts are loaded -automatically by the debugger, allowing a seamless experience for users. This attribute currently -works for GDB and natvis scripts. +types within the library itself. +These pretty printers are of the same format as typical +visualizers, but are embedded directly into the compiled binary. +These scripts are loaded automatically by the debugger, allowing a seamless experience for users. +This attribute currently works for GDB and natvis scripts. [dbg_vis_attr]: https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute -GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary. More information -can be found [here](https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html). Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs] +GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary. +More information +can be found [here](https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html). +Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs] [gdb_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs Natvis files can be embedded in the PDB debug info using the [`/NATVIS` linker option][linker_opt], -and have the [highest priority][priority] when a type is resolving which visualizer to use. The -files specified by the attribute are collected into +and have the [highest priority][priority] when a type is resolving which visualizer to use. +The files specified by the attribute are collected into [`CrateInfo::natvis_debugger_visualizers`][natvis] which are then added as linker arguments in [`rustc_codegen_ssa/src/back/linker.rs`][linker_rs] @@ -46,17 +53,22 @@ files specified by the attribute are collected into [linker_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/back/linker.rs#L1106 LLDB is not currently supported, but there are a few methods that could potentially allow support in -the future. Officially, the intended method is via a [formatter bytecode][bytecode]. This was +the future. +Officially, the intended method is via a [formatter bytecode][bytecode]. +This was created to offer a comparable experience to GDB's, but without the safety concerns associated with -embedding an entire python script. The opcodes are limited, but it works with `SBValue` and `SBType` -in roughly the same way as python visualizer scripts. Implementing this would require writing some -sort of DSL/mini compiler. +embedding an entire python script. +The opcodes are limited, but it works with `SBValue` and `SBType` +in roughly the same way as python visualizer scripts. +Implementing this would require writing some sort of DSL/mini compiler. [bytecode]: https://lldb.llvm.org/resources/formatterbytecode.html Alternatively, it might be possible to copy GDB's strategy entirely: create a bespoke section in the -binary and embed a python script in it. LLDB will not load it automatically, but the python API does -allow one to access the [raw sections of the debug info][SBSection]. With this, it may be possible +binary and embed a python script in it. +LLDB will not load it automatically, but the python API does +allow one to access the [raw sections of the debug info][SBSection]. +With this, it may be possible to extract the python script from our bespoke section and then load it in during the startup of Rust's visualizer scripts. @@ -65,8 +77,10 @@ Rust's visualizer scripts. ## Performance Before tackling the visualizers themselves, it's important to note that these are part of a -performance-sensitive system. Please excuse the break in formality, but: if I have to spend -significant time debugging, I'm annoyed. If I have to *wait on my debugger*, I'm pissed. +performance-sensitive system. +Please excuse the break in formality, but: if I have to spend +significant time debugging, I'm annoyed. +If I have to *wait on my debugger*, I'm pissed. Every millisecond spent in these visualizers is a millisecond longer for the user to see output. This can be especially painful for large stackframes that contain many/large container types. @@ -75,15 +89,19 @@ delays of tens of seconds (or even minutes) before being able to interact with a frame. There is a tendancy to balk at the idea of optimizing Python code, but it really can have a -substantial impact. Remember, there is no compiler to help keep the code fast. Even simple -transformations are not done for you. It can be difficult to find Python performance tips through +substantial impact. +Remember, there is no compiler to help keep the code fast. +Even simple transformations are not done for you. +It can be difficult to find Python performance tips through all the noise of people suggesting you don't bother optimizing Python, so here are some things to keep in mind that are relevant to these scripts: * Everything allocates, even `int` -* Use tuples when possible. `list` is effectively `Vec>`, whereas tuples are equivalent -to `Box<[Any]>`. They have one less layer of indirection, don't carry extra capacity and can't -grow/shrink which can be advantageous in many cases. An additional benefit is that Python caches and +* Use tuples when possible. + `list` is effectively `Vec>`, whereas tuples are equivalent to `Box<[Any]>`. +They have one less layer of indirection, don't carry extra capacity and can't +grow/shrink which can be advantageous in many cases. +An additional benefit is that Python caches and recycles the underlying allocations of all tuples up to size 20. * Regexes are slow and should be avoided when simple string manipulation will do * Strings are immutable, thus many string operations implictly copy the contents. @@ -91,21 +109,25 @@ recycles the underlying allocations of all tuples up to size 20. way to do it. * f-strings are generally the fastest way to do small, simple string transformations such as surrounding a string with parentheses. -* The act of calling a function is somewhat slow (even if the function is completely empty). If the -code section is very hot, consider inlining the function manually. +* The act of calling a function is somewhat slow (even if the function is completely empty). + If the code section is very hot, consider inlining the function manually. * Local variable access is significantly faster than global and built-in function access * Member/method access via the `.` operator is also slow, consider reassigning deeply nested values to local variables to avoid this cost (e.g. `h = a.b.c.d.e.f.g.h`). * Accessing inherited methods and fields is about 2x slower than base-class methods and fields. Avoid inheritance whenever possible. -* Use [`__slots__`](https://wiki.python.org/moin/UsingSlots) wherever possible. `__slots__` is a way +* Use [`__slots__`](https://wiki.python.org/moin/UsingSlots) wherever possible. + `__slots__` is a way to indicate to Python that your class's fields won't change and speeds up field access by a -noticable amount. This does require you to name your fields in advance and initialize them in +noticable amount. +This does require you to name your fields in advance and initialize them in `__init__`, but it's a small price to pay for the benefits. -* Match statements/if..elif..else are not optimized in any way. The conditions are checked in order, +* Match statements/if..elif..else are not optimized in any way. + The conditions are checked in order, 1 by 1. If possible, use an alternative such as dictionary dispatch or a table of values * Compute lazily when possible * List comprehensions are typically faster than loops, generator comprehensions are a bit slower -than list comprehensions, but use less memory. You can think of comprehensions as equivalent to -Rust's `iter.map()`. List comprehensions effectively call `collect::>` at the end, whereas +than list comprehensions, but use less memory. +You can think of comprehensions as equivalent to Rust's `iter.map()`. +List comprehensions effectively call `collect::>` at the end, whereas generator comprehensions do not. From 7000c2a858b3e75e178d9764b61fe24ceeb38ec7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 10:19:53 +0200 Subject: [PATCH 60/71] reflow --- .../src/debuginfo/debugger-visualizers.md | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md index ce4835728df99..10167bf69cedc 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md @@ -6,15 +6,14 @@ be piped through a debug adapter such as an IDE's debugger API. The term "Visualizer" is a bit of a misnomer. The real goal isn't just to prettify the output, but to provide an interface for the user to interact with that is as useful as possible. -In many cases -this means reconstructing the original type as closely as possible to its Rust representation, but -not always. +In many cases, +this means reconstructing the original type as closely as possible to its Rust representation, +but not always. The visualizer interface allows generating "synthetic children" - fields that don't exist in the debug info, but can be derived from invariants about the language and the type itself. -A simple -example is allowing one to interact with the elements of a `Vec` instead of just it's `*mut u8` -heap pointer, length, and capacity. +A simple example is allowing one to interact with the elements of a `Vec` +instead of just it's `*mut u8` heap pointer, length, and capacity. ## `rust-lldb`, `rust-gdb`, and `rust-windbg.cmd` @@ -34,11 +33,10 @@ This attribute currently works for GDB and natvis scripts. [dbg_vis_attr]: https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute -GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary. -More information -can be found [here](https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html). -Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs] +GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary ([more info]). +Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs]. +[more info]: https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html [gdb_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs Natvis files can be embedded in the PDB debug info using the [`/NATVIS` linker option][linker_opt], @@ -55,22 +53,20 @@ The files specified by the attribute are collected into LLDB is not currently supported, but there are a few methods that could potentially allow support in the future. Officially, the intended method is via a [formatter bytecode][bytecode]. -This was -created to offer a comparable experience to GDB's, but without the safety concerns associated with -embedding an entire python script. +This was created to offer a comparable experience to GDB's, +but without the safety concerns associated with embedding an entire Python script. The opcodes are limited, but it works with `SBValue` and `SBType` -in roughly the same way as python visualizer scripts. +in roughly the same way as Python visualizer scripts. Implementing this would require writing some sort of DSL/mini compiler. [bytecode]: https://lldb.llvm.org/resources/formatterbytecode.html Alternatively, it might be possible to copy GDB's strategy entirely: create a bespoke section in the binary and embed a python script in it. -LLDB will not load it automatically, but the python API does +LLDB will not load it automatically, but the Python API does allow one to access the [raw sections of the debug info][SBSection]. -With this, it may be possible -to extract the python script from our bespoke section and then load it in during the startup of -Rust's visualizer scripts. +With this, it may be possible to extract the Python script from our bespoke section +and then load it in during the startup of Rust's visualizer scripts. [SBSection]: https://lldb.llvm.org/python_api/lldb.SBSection.html#sbsection @@ -99,35 +95,35 @@ keep in mind that are relevant to these scripts: * Everything allocates, even `int` * Use tuples when possible. `list` is effectively `Vec>`, whereas tuples are equivalent to `Box<[Any]>`. -They have one less layer of indirection, don't carry extra capacity and can't -grow/shrink which can be advantageous in many cases. -An additional benefit is that Python caches and -recycles the underlying allocations of all tuples up to size 20. + They have one less layer of indirection, don't carry extra capacity and can't grow/shrink, + which can be advantageous in many cases. + An additional benefit is that Python caches and + recycles the underlying allocations of all tuples up to size 20. * Regexes are slow and should be avoided when simple string manipulation will do * Strings are immutable, thus many string operations implictly copy the contents. * When concatenating large lists of strings, `"".join(iterable_of_strings)` is typically the fastest -way to do it. + way to do it. * f-strings are generally the fastest way to do small, simple string transformations such as surrounding a string with parentheses. * The act of calling a function is somewhat slow (even if the function is completely empty). If the code section is very hot, consider inlining the function manually. * Local variable access is significantly faster than global and built-in function access * Member/method access via the `.` operator is also slow, consider reassigning deeply nested values -to local variables to avoid this cost (e.g. `h = a.b.c.d.e.f.g.h`). + to local variables to avoid this cost (e.g. `h = a.b.c.d.e.f.g.h`). * Accessing inherited methods and fields is about 2x slower than base-class methods and fields. -Avoid inheritance whenever possible. + Avoid inheritance whenever possible. * Use [`__slots__`](https://wiki.python.org/moin/UsingSlots) wherever possible. `__slots__` is a way -to indicate to Python that your class's fields won't change and speeds up field access by a -noticable amount. -This does require you to name your fields in advance and initialize them in -`__init__`, but it's a small price to pay for the benefits. + to indicate to Python that your class's fields won't change and speeds up field access by a + noticable amount. + This does require you to name your fields in advance and initialize them in + `__init__`, but it's a small price to pay for the benefits. * Match statements/if..elif..else are not optimized in any way. - The conditions are checked in order, -1 by 1. If possible, use an alternative such as dictionary dispatch or a table of values + The conditions are checked in order, 1 by 1. + If possible, use an alternative such as dictionary dispatch or a table of values * Compute lazily when possible * List comprehensions are typically faster than loops, generator comprehensions are a bit slower -than list comprehensions, but use less memory. -You can think of comprehensions as equivalent to Rust's `iter.map()`. -List comprehensions effectively call `collect::>` at the end, whereas -generator comprehensions do not. + than list comprehensions, but use less memory. + You can think of comprehensions as equivalent to Rust's `iter.map()`. + List comprehensions effectively call `collect::>` at the end, whereas + generator comprehensions do not. From b0f5d97555138dbfa11d7622c59e503272a2cf85 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 10:20:30 +0200 Subject: [PATCH 61/71] sembr src/debuginfo/gdb-internals.md --- src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md index 8959f5d719c4e..2b80521f4519e 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md @@ -1,4 +1,4 @@ # GDB internals -GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. The expression parsing support -can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` +GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. +The expression parsing support can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` From ca59dd78d7a5172e02c315c1d90f115656bd446d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 10:21:15 +0200 Subject: [PATCH 62/71] sembr src/debuginfo/llvm-codegen.md --- src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md | 3 ++- 1 file changed, 2 insertions(+), 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 3b6bd454b29f2..4f5bdaa1e6795 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md @@ -1,7 +1,8 @@ # LLVM codegen 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. +["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 From 1bb944b293b3c35557e1a58c42a5b0727040c909 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 23 Jul 2026 08:28:05 +0000 Subject: [PATCH 63/71] Prepare for merging from rust-lang/rust This updates the rust-version file to 390279b302ca98ae270f434100ae3730531d1246. --- 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 a48a44e5d15fb..25a5238f538ee 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -9e71b3bc704eea68d39bd0f6a46703c7d22f5d3b +390279b302ca98ae270f434100ae3730531d1246 From e9ad00c5af1c7c57e2d84c96a5b255485a0a83c7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 16 Dec 2025 20:25:58 +0000 Subject: [PATCH 64/71] Remove 'static requirement on try_as_dyn --- .../src/const_eval/eval_queries.rs | 1 + .../rustc_const_eval/src/interpret/util.rs | 5 +- compiler/rustc_const_eval/src/lib.rs | 1 + compiler/rustc_hir_analysis/src/collect.rs | 6 ++ .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 1 + compiler/rustc_hir_typeck/src/opaque_types.rs | 1 + compiler/rustc_infer/src/infer/mod.rs | 3 + .../rustc_infer/src/infer/opaque_types/mod.rs | 3 +- .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 6 ++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/queries.rs | 9 ++ .../src/ty/context/impl_interner.rs | 4 + compiler/rustc_middle/src/ty/generics.rs | 76 +++++++++++++++- compiler/rustc_middle/src/ty/mod.rs | 64 +++++++++++++- .../rustc_mir_transform/src/elaborate_drop.rs | 1 + .../src/solve/assembly/mod.rs | 2 + .../src/solve/eval_ctxt/mod.rs | 54 +++++++----- .../src/solve/normalizes_to.rs | 1 + .../src/solve/project_goals/opaque_types.rs | 4 +- .../src/solve/search_graph.rs | 1 + .../src/solve/trait_goals.rs | 11 ++- .../src/solve/delegate.rs | 1 + .../src/solve/fulfill.rs | 1 + .../src/traits/fulfill.rs | 1 + .../src/traits/normalize.rs | 4 +- .../src/traits/project.rs | 1 + .../src/traits/query/normalize.rs | 2 +- .../src/traits/select/mod.rs | 43 +++++++-- compiler/rustc_ty_utils/src/instance.rs | 1 + compiler/rustc_ty_utils/src/layout.rs | 2 + compiler/rustc_type_ir/src/infer_ctxt.rs | 29 ++++++ compiler/rustc_type_ir/src/interner.rs | 2 + .../rustc_type_ir/src/region_constraint.rs | 1 + compiler/rustc_type_ir/src/relate/combine.rs | 1 + library/core/src/any.rs | 20 ++--- library/coretests/tests/mem/trait_info_of.rs | 1 + tests/ui/any/non_static.rs | 88 +++++++++++++++++++ tests/ui/any/static_method_bound.rs | 34 +++++++ 39 files changed, 436 insertions(+), 52 deletions(-) create mode 100644 tests/ui/any/non_static.rs create mode 100644 tests/ui/any/static_method_bound.rs diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 57ccbb8ff10ea..b2c6663e41085 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -44,6 +44,7 @@ fn retry_codegen_mode_with_postanalysis<'tcx, K: TypeVisitable>, V> | ty::TypingMode::Typeck { .. } | ty::TypingMode::PostTypeckUntilBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } + | ty::TypingMode::Reflection | ty::TypingMode::PostAnalysis => {} } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index cbef1de487c43..1b23432c8c57a 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -29,7 +29,10 @@ pub(crate) fn type_implements_dyn_trait<'tcx, M: Machine<'tcx>>( ); }; - let (infcx, param_env) = ecx.tcx.infer_ctxt().build_with_typing_env(ecx.typing_env); + let (infcx, param_env) = ecx.tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::new( + ecx.typing_env.param_env, + ty::TypingMode::Reflection, + )); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| { diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 5b63379edd332..7fe32b4e75ffb 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -33,6 +33,7 @@ fn assert_typing_mode(typing_mode: ty::TypingMode<'_>) { // `InterpCx::new` for more details. ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } + | ty::TypingMode::Reflection | ty::TypingMode::PostTypeckUntilBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } => bug!( "Const eval should always happens in PostAnalysis or Codegen mode. See the comment on `assert_typing_mode` for more details." diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b520ea106dfa0..605b6e3751ef3 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -85,6 +85,7 @@ pub(crate) fn provide(providers: &mut Providers) { adt_def, fn_sig, impl_trait_header, + impl_is_fully_generic_for_reflection, coroutine_kind, coroutine_for_closure, opaque_ty_origin, @@ -1395,6 +1396,11 @@ pub fn suggest_impl_trait<'tcx>( None } +fn impl_is_fully_generic_for_reflection(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + tcx.impl_trait_header(def_id).is_fully_generic_for_reflection() + && tcx.explicit_predicates_of(def_id).is_fully_generic_for_reflection() +} + fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplTraitHeader<'_> { let icx = ItemCtxt::new(tcx, def_id); let item = tcx.hir_expect_item(def_id); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9a1b1f8300957..137351dfcdd5b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -696,6 +696,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { defining_opaque_types_and_generators } ty::TypingMode::Coherence + | ty::TypingMode::Reflection | ty::TypingMode::PostTypeckUntilBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 797077d97c133..17e193d7f44ab 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -103,6 +103,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { defining_opaque_types_and_generators } ty::TypingMode::Coherence + | ty::TypingMode::Reflection | ty::TypingMode::PostTypeckUntilBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index af1f5de717a60..72820a31a95b9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -354,6 +354,7 @@ impl<'tcx> Drop for InferCtxt<'tcx> { TypingMode::Coherence | TypingMode::Typeck { .. } | TypingMode::PostBorrowck { .. } + | TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => {} // In erased mode, the opaque type storage is always empty @@ -1171,6 +1172,7 @@ impl<'tcx> InferCtxt<'tcx> { // and post-borrowck analysis mode. We may need to modify its uses // to support PostBorrowck in the old solver as well. TypingMode::Coherence + | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen => false, @@ -1505,6 +1507,7 @@ impl<'tcx> InferCtxt<'tcx> { mode @ (ty::TypingMode::Coherence | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis + | ty::TypingMode::Reflection | ty::TypingMode::Codegen) => mode, ty::TypingMode::ErasedNotCoherence(MayBeErased) => unreachable!(), }; diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 2d05e33e44891..08c7c49417124 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -285,7 +285,8 @@ impl<'tcx> InferCtxt<'tcx> { } mode @ (ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis - | ty::TypingMode::Codegen) => { + | ty::TypingMode::Codegen + | ty::TypingMode::Reflection) => { bug!("insert hidden type in {mode:?}") } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 2a138154f7020..9acebc1a4822f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -241,6 +241,7 @@ provide! { tcx, def_id, other, cdata, fn_sig => { table } codegen_fn_attrs => { table } impl_trait_header => { table } + impl_is_fully_generic_for_reflection => { table_direct } const_param_default => { table } object_lifetime_default => { table } thir_abstract_const => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8fa0c1b2dcdd8..602c5ee0201dd 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2197,6 +2197,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let header = tcx.impl_trait_header(def_id); record!(self.tables.impl_trait_header[def_id] <- header); + let impl_is_fully_generic_for_reflection = + tcx.impl_is_fully_generic_for_reflection(def_id); + self.tables + .impl_is_fully_generic_for_reflection + .set(def_id.index, impl_is_fully_generic_for_reflection); + self.tables.defaultness.set(def_id.index, tcx.defaultness(def_id)); let trait_ref = header.trait_ref.instantiate_identity().skip_norm_wip(); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 4847ddda90fd1..237672878bb4c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -413,6 +413,7 @@ define_tables! { constness: Table, safety: Table, defaultness: Table, + impl_is_fully_generic_for_reflection: Table, - optional: attributes: Table>, diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index cbd54ec959c6a..387bf3f6f8c1f 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -1098,6 +1098,15 @@ rustc_queries! { separate_provide_extern } + /// Whether all generic parameters of the type are unique unconstrained generic parameters + /// of the impl. `Bar<'static>` or `Foo<'a, 'a>` or outlives bounds on the lifetimes cause + /// this boolean to be false and `try_as_dyn` to return `None`. + query impl_is_fully_generic_for_reflection(impl_id: DefId) -> bool { + desc { "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } + cache_on_disk + separate_provide_extern + } + /// Given an `impl_def_id`, return true if the self type is guaranteed to be unsized due /// to either being one of the built-in unsized types (str/slice/dyn) or to be a struct /// whose tail is one of those types. diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 052a937cf5017..222a70753311a 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -703,6 +703,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.impl_polarity(impl_def_id) } + fn is_fully_generic_for_reflection(self, impl_def_id: Self::ImplId) -> bool { + self.impl_is_fully_generic_for_reflection(impl_def_id) + } + fn trait_is_auto(self, trait_def_id: DefId) -> bool { self.trait_is_auto(trait_def_id) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 02ac0586c33ae..9a6b3dbea1ef3 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -1,14 +1,16 @@ +use std::ops::ControlFlow; + use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_macros::{StableHash, TyDecodable, TyEncodable}; use rustc_span::{Span, Symbol, kw}; +use rustc_type_ir::{TypeSuperVisitable as _, TypeVisitable, TypeVisitor}; use tracing::instrument; use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt, Unnormalized}; -use crate::ty; use crate::ty::region::RegionExt; -use crate::ty::{EarlyBinder, GenericArgsRef}; +use crate::ty::{self, ClauseKind, EarlyBinder, GenericArgsRef, Region, RegionKind, TyKind}; #[derive(Clone, Debug, TyEncodable, TyDecodable, StableHash)] pub enum GenericParamDefKind { @@ -456,6 +458,76 @@ impl<'tcx> GenericPredicates<'tcx> { instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| Unnormalized::new(*p))); instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s)); } + + /// Allow simple where bounds like `T: Debug`, but prevent any kind of + /// outlives bounds or uses of generic parameters on the right hand side. + /// + /// We allow simple bounds because when the `T` actually gets substituted with a concrete type + /// during monomorphization, we will be checking its `Debug` impl for fully_generic_for_reflection. + /// + /// Constants (associated or generic) are irrelevant for this analysis, as their value is neither + /// affected by lifetimes, nor do they affect lifetimes. + pub fn is_fully_generic_for_reflection(self) -> bool { + struct ParamChecker; + impl<'tcx> TypeVisitor> for ParamChecker { + type Result = ControlFlow<()>; + fn visit_region(&mut self, r: Region<'tcx>) -> Self::Result { + match r.kind() { + RegionKind::ReEarlyParam(_) | RegionKind::ReStatic | RegionKind::ReError(_) => { + ControlFlow::Break(()) + } + RegionKind::ReVar(_) + | RegionKind::RePlaceholder(_) + | RegionKind::ReErased + | RegionKind::ReLateParam(_) => { + bug!("unexpected lifetime in impl: {r:?}") + } + RegionKind::ReBound(..) => ControlFlow::Continue(()), + } + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + match t.kind() { + TyKind::Param(_p) => { + // Reject using parameters used in the type in where bounds + return ControlFlow::Break(()); + } + TyKind::Alias(..) => return ControlFlow::Break(()), + _ => (), + } + t.super_visit_with(self) + } + } + + // Pessimistic: if any of the parameters have where bounds + // don't allow this impl to be used. + self.predicates.iter().all(|(clause, _)| { + match clause.kind().skip_binder() { + ClauseKind::Trait(trait_predicate) => { + // In a `T: Trait`, if the rhs bound does not contain any generic params + // or 'static lifetimes, then it cannot transitively cause such requirements, + // considering we apply the fully-generic-for-reflection rules to any impls for + // that trait, too. + if matches!(trait_predicate.self_ty().kind(), ty::Param(_)) + && trait_predicate.trait_ref.args[1..] + .iter() + .all(|arg| arg.visit_with(&mut ParamChecker).is_continue()) + { + return true; + } + } + ClauseKind::RegionOutlives(_) + | ClauseKind::TypeOutlives(_) + | ClauseKind::Projection(_) + | ClauseKind::ConstArgHasType(_, _) + | ClauseKind::WellFormed(_) + | ClauseKind::ConstEvaluatable(_) + | ClauseKind::HostEffect(_) + | ClauseKind::UnstableFeature(_) => {} + } + clause.visit_with(&mut ParamChecker).is_continue() + }) + } } /// `[const]` bounds for a given item. This is represented using a struct much like diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9b582eeb2c520..379df48fc899f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -16,6 +16,7 @@ use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::num::NonZero; +use std::ops::ControlFlow; use std::ptr::NonNull; use std::{assert_matches, fmt, iter, str}; @@ -30,7 +31,7 @@ use rustc_abi::{ use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, NodeId}; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; use rustc_data_structures::steal::Steal; @@ -309,6 +310,65 @@ pub struct ImplTraitHeader<'tcx> { pub constness: hir::Constness, } +impl<'tcx> ImplTraitHeader<'tcx> { + /// For trait impls, checks whether + /// * the type and trait only use generic lifetime arguments (and no concrete ones like `'static`), and + /// * uses each generic param (lifetime or type) only once. + /// Pessimistic analysis, so it will reject alias types + /// and other types that may be actually ok. We can allow more in the future. + /// + /// Constants (associated or generic) are irrelevant for this analysis, as their value is neither + /// affected by lifetimes, nor do they affect lifetimes. + pub fn is_fully_generic_for_reflection(self) -> bool { + #[derive(Default)] + struct ParamFinder { + seen: FxHashSet, + } + + impl<'tcx> TypeVisitor> for ParamFinder { + type Result = ControlFlow<()>; + fn visit_region(&mut self, r: Region<'tcx>) -> Self::Result { + match r.kind() { + RegionKind::ReEarlyParam(param) => { + if self.seen.insert(param.index) { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + } + RegionKind::ReBound(..) | RegionKind::ReLateParam(_) => { + ControlFlow::Continue(()) + } + RegionKind::ReStatic + | RegionKind::ReVar(_) + | RegionKind::RePlaceholder(_) + | RegionKind::ReErased + | RegionKind::ReError(_) => ControlFlow::Break(()), + } + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + match t.kind() { + TyKind::Param(p) => { + // Reject using a parameter twice (e.g. in `Foo`) + if !self.seen.insert(p.index) { + return ControlFlow::Break(()); + } + } + TyKind::Alias(..) => return ControlFlow::Break(()), + _ => (), + } + t.super_visit_with(self) + } + } + self.trait_ref + .instantiate_identity() + .skip_norm_wip() + .visit_with(&mut ParamFinder::default()) + .is_continue() + } +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, StableHash, Debug)] #[derive(TypeFoldable, TypeVisitable, Default)] pub enum Asyncness { @@ -1178,6 +1238,7 @@ impl<'tcx> TypingEnv<'tcx> { let TypingEnv { typing_mode, param_env } = self; match typing_mode.0.assert_not_erased() { TypingMode::Coherence + | TypingMode::Reflection | TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } => {} @@ -1194,6 +1255,7 @@ impl<'tcx> TypingEnv<'tcx> { let TypingEnv { typing_mode, param_env } = self; match typing_mode.0.assert_not_erased() { TypingMode::Coherence + | TypingMode::Reflection | TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 8b21e8284476b..c2c702dbf2470 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -802,6 +802,7 @@ where match self.elaborator.typing_env().typing_mode().assert_not_erased() { ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => {} ty::TypingMode::Coherence + | ty::TypingMode::Reflection | ty::TypingMode::Typeck { .. } | ty::TypingMode::PostTypeckUntilBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } => { diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 6d111ff44d415..290e49c8a33a4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -483,6 +483,7 @@ where TypingMode::Coherence => true, TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen @@ -1066,6 +1067,7 @@ where | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis + | TypingMode::Reflection | TypingMode::Codegen => vec![], TypingMode::ErasedNotCoherence(MayBeErased) => { self.opaque_accesses 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 c3ccb46069063..16f8f3496d9e7 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 @@ -566,28 +566,34 @@ where .entered(); let (result, orig_values, canonical_goal, succeeded_in_erased) = 'retry_canonicalize: { - let skip_erased_attempt = if typing_mode.is_coherence() { - true - } else { - let mut skip = false; - if opaque_types.iter().any(|(_, ty)| ty.is_ty_var()) - && let PredicateKind::Clause(ClauseKind::Trait(..)) = + let skip_erased_attempt = match typing_mode { + TypingMode::Reflection | TypingMode::Coherence => true, + TypingMode::Typeck { .. } + | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostBorrowck { .. } + | TypingMode::Codegen + | TypingMode::PostAnalysis + | TypingMode::ErasedNotCoherence(_) => { + let mut skip = false; + if opaque_types.iter().any(|(_, ty)| ty.is_ty_var()) + && let PredicateKind::Clause(ClauseKind::Trait(..)) = + goal.predicate.kind().skip_binder() + { + skip = true; + } + + if let PredicateKind::Clause(ClauseKind::Trait(tr)) = goal.predicate.kind().skip_binder() - { - skip = true; - } + && tr.self_ty().has_coroutines() + && self.cx().trait_is_auto(tr.trait_ref.def_id) + { + // FIXME(#155443): this doesn't make a difference now, but with eager normalization + // it likely will. + // skip_erased_attempt = true; + } - if let PredicateKind::Clause(ClauseKind::Trait(tr)) = - goal.predicate.kind().skip_binder() - && tr.self_ty().has_coroutines() - && self.cx().trait_is_auto(tr.trait_ref.def_id) - { - // FIXME(#155443): this doesn't make a difference now, but with eager normalization - // it likely will. - // skip_erased_attempt = true; + skip } - - skip }; if skip_erased_attempt { @@ -1649,9 +1655,10 @@ fn should_rerun_after_erased_canonicalization( // ============================= (RerunCondition::Always, _) => RerunDecision::Yes, // ============================= - (RerunCondition::OpaqueInStorage(..), TypingMode::PostAnalysis | TypingMode::Codegen) => { - RerunDecision::Yes - } + ( + RerunCondition::OpaqueInStorage(..), + TypingMode::PostAnalysis | TypingMode::Codegen | TypingMode::Reflection, + ) => RerunDecision::Yes, ( RerunCondition::OpaqueInStorage(defids), TypingMode::PostBorrowck { defined_opaque_types: opaques } @@ -1667,12 +1674,13 @@ fn should_rerun_after_erased_canonicalization( TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen + | TypingMode::Reflection | TypingMode::PostTypeckUntilBorrowck { .. }, ) => RerunDecision::No, // ============================= ( RerunCondition::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(_), - TypingMode::PostAnalysis | TypingMode::Codegen, + TypingMode::PostAnalysis | TypingMode::Codegen | TypingMode::Reflection, ) => RerunDecision::Yes, ( RerunCondition::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(defids), 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 582cd122c8ecf..fd5f1a3f82b86 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -348,6 +348,7 @@ where | ty::TypingMode::PostTypeckUntilBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis + | ty::TypingMode::Reflection | ty::TypingMode::Codegen => { ecx.instantiate_normalizes_to_as_rigid(goal)?; return ecx.evaluate_added_goals_and_make_canonical_response( 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 7524b2021c015..3387c8599b911 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 @@ -106,6 +106,7 @@ where TypingMode::Coherence | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis + | TypingMode::Reflection | TypingMode::Codegen => unreachable!(), } } @@ -149,7 +150,8 @@ where self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into) } - TypingMode::PostAnalysis | TypingMode::Codegen => { + // FIXME(try_as_dyn): probably want to treat opaques opaquely and rigid + 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)?; diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 778826ba60aee..4918258350bf3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -70,6 +70,7 @@ where } TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 2ebea5d3eb188..50ccfa84a70be 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -87,7 +87,15 @@ where // Impl matches polarity (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive) - | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => Certainty::Yes, + | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => { + if ecx.typing_mode().is_reflection() + && !cx.is_fully_generic_for_reflection(impl_def_id) + { + return Err(NoSolution.into()); + } else { + Certainty::Yes + } + } // Impl doesn't match polarity (ty::ImplPolarity::Positive, ty::PredicatePolarity::Negative) @@ -1607,6 +1615,7 @@ where } TypingMode::Coherence | TypingMode::PostAnalysis + | TypingMode::Reflection | TypingMode::Codegen | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } => {} diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 605f4d6758a5a..f5a30d2b26563 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -384,6 +384,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< TypingMode::Coherence | TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Reflection | TypingMode::PostBorrowck { .. } => false, TypingMode::PostAnalysis | TypingMode::Codegen => { let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 8d5d8f26f9dce..a61c679c9870f 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -340,6 +340,7 @@ where TypingMode::Coherence | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } + | TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => return Default::default(), }; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 95f0c3dc9881d..4ec21b9f8a4cd 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -178,6 +178,7 @@ where TypingMode::Coherence | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } + | TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => return Default::default(), }; diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 9364482a87cb8..b822c713bfabb 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -144,7 +144,7 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( | TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE), - TypingMode::PostAnalysis | TypingMode::Codegen => {} + TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => {} } value.has_type_flags(flags) @@ -433,7 +433,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx | TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } => ty.super_fold_with(self), - TypingMode::PostAnalysis | TypingMode::Codegen => { + TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => { let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.selcx.infcx.err_ctxt().report_overflow_error( diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index e0edc76682a3b..79b531afbe2ae 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -991,6 +991,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( TypingMode::Coherence | TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Reflection | TypingMode::PostBorrowck { .. } => { debug!( assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index ac6100747970e..fb15ed8a74c07 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -220,7 +220,7 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } => ty.try_super_fold_with(self)?, - TypingMode::PostAnalysis | TypingMode::Codegen => { + TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => { let args = data.args.try_fold_with(self)?; let recursion_limit = self.cx().recursion_limit(); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 7c9ae9246c96b..f94aa9bcb754c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -17,7 +17,7 @@ use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::relate::TypeRelation; -use rustc_infer::traits::{PredicateObligations, TraitObligation}; +use rustc_infer::traits::{ImplSource, PredicateObligations, TraitObligation}; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; @@ -282,6 +282,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(SelectionError::Overflow(OverflowError::Canonical)) } Err(e) => Err(e), + Ok(ImplSource::Builtin(..)) if self.typing_mode().is_reflection() => { + // Builtin impls regularly don't satisfy the try_as_dyn requirements, so + // we just reject all of them. + Err(SelectionError::Unimplemented) + } Ok(candidate) => Ok(Some(candidate)), } } @@ -1299,6 +1304,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match this.confirm_candidate(stack.obligation, candidate.clone()) { Ok(selection) => { debug!(?selection); + if let ImplSource::Builtin(..) = selection + && this.typing_mode().is_reflection() + { + return Ok(EvaluatedToErr); + } this.evaluate_predicates_recursively( stack.list(), selection.nested_obligations().into_iter(), @@ -1485,6 +1495,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TypingMode::Coherence => {} TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen => return Ok(()), @@ -1536,6 +1547,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { defining_opaque_types.is_empty() || (!pred.has_opaque_types() && !pred.has_coroutines()) } + // Impls that are not fully generic are completely ignored as "nonexistent" + // in this mode, so the results wildly differ from normal trait solving. + TypingMode::Reflection => false, // The hidden types of `defined_opaque_types` is not local to the current // inference context, so we can freely move this to the global cache. TypingMode::PostBorrowck { .. } => true, @@ -2569,11 +2583,27 @@ impl<'tcx> SelectionContext<'_, 'tcx> { })?; nested_obligations.extend(obligations); - if impl_trait_header.polarity == ty::ImplPolarity::Reservation - && !self.typing_mode().is_coherence() - { - debug!("reservation impls only apply in intercrate mode"); - return Err(()); + match self.typing_mode() { + TypingMode::Coherence => {} + TypingMode::Reflection + if !self.tcx().impl_is_fully_generic_for_reflection(impl_def_id) => + { + debug!("reflection mode only allows fully generic impls"); + return Err(()); + } + + TypingMode::Typeck { .. } + | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostBorrowck { .. } + | TypingMode::Codegen + | TypingMode::ErasedNotCoherence(_) + | TypingMode::Reflection + | TypingMode::PostAnalysis => { + if impl_trait_header.polarity == ty::ImplPolarity::Reservation { + debug!("reservation impls only apply in intercrate mode"); + return Err(()); + } + } } Ok(Normalized { value: impl_args, obligations: nested_obligations }) @@ -2916,6 +2946,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } TypingMode::Coherence | TypingMode::PostAnalysis + | TypingMode::Reflection | TypingMode::Codegen | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } => false, diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index d9069ac127729..b5a82793dcc97 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -167,6 +167,7 @@ fn resolve_associated_item<'tcx>( ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::Reflection | ty::TypingMode::PostBorrowck { .. } => false, ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => { !trait_ref.still_further_specializable() diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index abec1850502b6..7a53fe1e0cfc8 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -87,6 +87,7 @@ fn layout_of<'tcx>( | ty::TypingMode::Typeck { .. } | ty::TypingMode::PostTypeckUntilBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } + | ty::TypingMode::Reflection | ty::TypingMode::ErasedNotCoherence(_) | ty::TypingMode::PostAnalysis => {} } @@ -552,6 +553,7 @@ fn layout_of_uncached<'tcx>( | ty::TypingMode::Typeck { .. } | ty::TypingMode::PostTypeckUntilBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } + | ty::TypingMode::Reflection | ty::TypingMode::ErasedNotCoherence(_) | ty::TypingMode::PostAnalysis => { return Err(error(cx, LayoutError::TooGeneric(ty))); diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 75f906e498eda..c652119957dd4 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -123,6 +123,10 @@ pub enum TypingMode { /// This is currently only used by the new solver, but should be implemented in /// the old solver as well. PostBorrowck { defined_opaque_types: I::LocalDefIds }, + /// During the evaluation of reflection logic that ignores lifetimes, we can only + /// handle impls that are fully generic over all lifetimes without constraints on + /// those lifetimes (other than implied bounds). + Reflection, /// After analysis, mostly during MIR optimizations, we're able to /// reveal all opaque types. As the hidden type should *never* be observable /// directly by the user, this should not be used by checks which may expose @@ -173,6 +177,7 @@ impl PartialEq for TypingModeEqWrapper { fn eq(&self, other: &Self) -> bool { match (self.0, other.0) { (TypingMode::Coherence, TypingMode::Coherence) => true, + (TypingMode::Reflection, TypingMode::Reflection) => true, ( TypingMode::Typeck { defining_opaque_types_and_generators: l }, TypingMode::Typeck { defining_opaque_types_and_generators: r }, @@ -193,6 +198,7 @@ impl PartialEq for TypingModeEqWrapper { ) => true, ( TypingMode::Coherence + | TypingMode::Reflection | TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } @@ -218,6 +224,25 @@ impl TypingMode { TypingMode::Coherence => true, TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Reflection + | TypingMode::PostBorrowck { .. } + | TypingMode::PostAnalysis + | TypingMode::Codegen + | TypingMode::ErasedNotCoherence(_) => false, + } + } + + /// There are a bunch of places in the compiler where we single out `Reflection`, + /// and alter behavior. We'd like to *always* match on `TypingMode` exhaustively, + /// but not having this method leads to a bunch of noisy code. + /// + /// See also the documentation on [`TypingMode`] about exhaustive matching. + pub fn is_reflection(&self) -> bool { + match self { + TypingMode::Reflection => true, + TypingMode::Typeck { .. } + | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Coherence | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen @@ -236,6 +261,7 @@ impl TypingMode { TypingMode::Coherence | TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen => false, @@ -262,6 +288,7 @@ impl TypingMode { } TypingMode::PostAnalysis => TypingMode::PostAnalysis, TypingMode::Codegen => TypingMode::Codegen, + TypingMode::Reflection => TypingMode::Reflection, TypingMode::ErasedNotCoherence(MayBeErased) => panic!( "Called `assert_not_erased` from a place that can be called by the trait solver in `TypingMode::ErasedNotCoherence`. `TypingMode` is `ErasedNotCoherence` in a place where that should be impossible" ), @@ -327,6 +354,7 @@ impl From> for TypingMode TypingMode::PostAnalysis, TypingMode::Codegen => TypingMode::Codegen, + TypingMode::Reflection => TypingMode::Reflection, } } } @@ -563,6 +591,7 @@ where TypingMode::Coherence | TypingMode::Typeck { .. } | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis => infcx.cx().features().feature_bound_holds_in_crate(symbol), TypingMode::Codegen => true, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 565414fdd58e3..bfa1c982bd0b7 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -423,6 +423,8 @@ pub trait Interner: fn impl_polarity(self, impl_def_id: Self::ImplId) -> ty::ImplPolarity; + fn is_fully_generic_for_reflection(self, impl_def_id: Self::ImplId) -> bool; + fn trait_is_auto(self, trait_def_id: Self::TraitId) -> bool; fn trait_is_coinductive(self, trait_def_id: Self::TraitId) -> bool; diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index b4ec6dbf5126d..e42e96901b74d 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -914,6 +914,7 @@ fn rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling< | TypingMode::ErasedNotCoherence { .. } | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } + | TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => (), }; diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 9ac4cd2dddc81..66eb27074ee30 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -180,6 +180,7 @@ where Ok(a) } TypingMode::Typeck { .. } + | TypingMode::Reflection | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 6c8cb114b9ef1..f518ec810b572 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -86,7 +86,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::intrinsics::{self, type_id_vtable}; +use crate::intrinsics::{self, type_id, type_id_vtable}; use crate::mem::transmute; use crate::mem::type_info::{TraitImpl, TypeKind}; use crate::{fmt, hash, ptr}; @@ -786,12 +786,12 @@ impl TypeId { #[unstable(feature = "type_info", issue = "146922")] #[rustc_const_unstable(feature = "type_info", issue = "146922")] #[rustc_comptime] - pub fn trait_info_of> + ?Sized + 'static>( + pub fn trait_info_of> + ?Sized>( self, ) -> Option> { // SAFETY: The vtable was obtained for `T`, so it is guaranteed to be `DynMetadata`. // The intrinsic can't infer this because it is designed to work with arbitrary TypeIds. - unsafe { transmute(self.trait_info_of_trait_type_id(const { TypeId::of::() })) } + unsafe { transmute(self.trait_info_of_trait_type_id(const { type_id::() })) } } /// Checks if the [TypeId] implements the trait of `trait_represented_by_type_id`. If it does it returns [TraitImpl] which can be used to build a fat pointer. @@ -983,17 +983,14 @@ pub const fn type_name_of_val(_val: &T) -> &'static str { /// ``` #[must_use] #[unstable(feature = "try_as_dyn", issue = "144361")] -pub const fn try_as_dyn< - T: Any + ?Sized + 'static, - U: ptr::Pointee> + ?Sized + 'static, ->( +pub const fn try_as_dyn> + ?Sized>( t: &T, ) -> Option<&U> { // For unsized `T`, `trait_info_of` always returns `None` (vtable lookup is // only supported for sized types). The function therefore unconditionally // returns `None` in that case. let vtable: Option> = - const { TypeId::of::().trait_info_of::().as_ref().map(TraitImpl::get_vtable) }; + const { type_id::().trait_info_of::().as_ref().map(TraitImpl::get_vtable) }; match vtable { Some(dyn_metadata) => { let pointer = ptr::from_raw_parts(t as *const T as *const (), dyn_metadata); @@ -1042,17 +1039,14 @@ pub const fn try_as_dyn< /// ``` #[must_use] #[unstable(feature = "try_as_dyn", issue = "144361")] -pub const fn try_as_dyn_mut< - T: Any + ?Sized + 'static, - U: ptr::Pointee> + ?Sized + 'static, ->( +pub const fn try_as_dyn_mut> + ?Sized>( t: &mut T, ) -> Option<&mut U> { // For unsized `T`, `trait_info_of` always returns `None` (vtable lookup is // only supported for sized types). The function therefore unconditionally // returns `None` in that case. let vtable: Option> = - const { TypeId::of::().trait_info_of::().as_ref().map(TraitImpl::get_vtable) }; + const { type_id::().trait_info_of::().as_ref().map(TraitImpl::get_vtable) }; match vtable { Some(dyn_metadata) => { let pointer = ptr::from_raw_parts_mut(t as *mut T as *mut (), dyn_metadata); diff --git a/library/coretests/tests/mem/trait_info_of.rs b/library/coretests/tests/mem/trait_info_of.rs index c723a96095815..4fd4a013693d9 100644 --- a/library/coretests/tests/mem/trait_info_of.rs +++ b/library/coretests/tests/mem/trait_info_of.rs @@ -10,6 +10,7 @@ impl Blah for Garlic { self.0 * 21 } } +unsafe impl Send for Garlic {} #[test] fn test_implements_trait() { diff --git a/tests/ui/any/non_static.rs b/tests/ui/any/non_static.rs new file mode 100644 index 0000000000000..ad04b7f475e0b --- /dev/null +++ b/tests/ui/any/non_static.rs @@ -0,0 +1,88 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@check-pass +#![feature(try_as_dyn)] + +trait Trait {} +const _: () = { + assert!(std::any::try_as_dyn::<_, dyn Trait>(&&42_i32).is_none()); +}; + +impl<'a> Trait for &'a [(); 1] {} +const _: () = { + let x = (); + assert!(std::any::try_as_dyn::<_, dyn Trait>(&&[x]).is_some()); +}; + +type Foo = &'static [(); 2]; + +// Ensure type aliases don't skip these checks +impl Trait for Foo {} +const _: () = { + assert!(std::any::try_as_dyn::<_, dyn Trait>(&&[(), ()]).is_none()); +}; + +impl Trait for &() {} +const _: () = { + let x = (); + assert!(std::any::try_as_dyn::<_, dyn Trait>(&&x).is_some()); +}; + +impl Trait for () {} +const _: () = { + assert!(std::any::try_as_dyn::<_, dyn Trait>(&()).is_some()); +}; + +// Not fully generic impl -> returns None even tho +// implemented for *some* lifetimes +impl<'a> Trait for (&'a (), &'a ()) {} +const _: () = { + assert!(std::any::try_as_dyn::<_, dyn Trait>(&(&(), &())).is_none()); +}; + +// Not fully generic impl -> returns None even tho +// implemented for *some* lifetimes +impl<'a, 'b: 'a> Trait for (&'a (), &'b (), ()) {} +const _: () = { + assert!(std::any::try_as_dyn::<_, dyn Trait>(&(&(), &(), ())).is_none()); +}; + +// Only valid for 'static lifetimes -> returns None +// even though we are actually using a `'static` lifetime. +// We can't know what lifetimes are there during codegen, so +// we pessimistically assume it could be a shorter one +impl Trait for &'static u32 {} +const _: () = { + assert!(std::any::try_as_dyn::<_, dyn Trait>(&&42_u32).is_none()); +}; + +trait Trait2 {} + +struct Struct(T); + +// While this is the impl for `Trait`, in `Reflection` solver mode +// we reject the impl for `Trait2` below, and thus this impl also +// doesn't match. +impl Trait for Struct {} + +impl Trait2 for &'static u32 {} +const _: () = { + assert!(std::any::try_as_dyn::<_, dyn Trait>(&Struct(&42_u32)).is_none()); +}; + +const _: () = { + trait Homo {} + impl Homo for (T, T) {} + + // Let's pick `T = &'_ i32`. + assert!(std::any::try_as_dyn::<_, dyn Homo>(&(&42_i32, &27_i32)).is_none()); +}; + +trait Trait3<'a> {} + +impl Trait3<'static> for () {} +const _: () = { + assert!(std::any::try_as_dyn::<_, dyn Trait3<'_>>(&()).is_none()); +}; + +fn main() {} diff --git a/tests/ui/any/static_method_bound.rs b/tests/ui/any/static_method_bound.rs new file mode 100644 index 0000000000000..aaab8623868f1 --- /dev/null +++ b/tests/ui/any/static_method_bound.rs @@ -0,0 +1,34 @@ +//@run-fail +#![feature(try_as_dyn)] + +use std::any::try_as_dyn; + +type Payload = Box; + +trait Trait { + fn as_static(&self) -> &'static Payload + where + Self: 'static; +} + +impl<'a> Trait for &'a Payload { + fn as_static(&self) -> &'static Payload + where + Self: 'static, + { + *self + } +} + +fn main() { + let storage: Box = Box::new(Box::new(1i32)); + let wrong: &'static Payload = extend(&*storage); + drop(storage); + println!("{wrong}"); +} + +fn extend(a: &Payload) -> &'static Payload { + // TODO: should panic at the `unwrap` here + let b: &(dyn Trait + 'static) = try_as_dyn::<&Payload, dyn Trait + 'static>(&a).unwrap(); + b.as_static() +} From b111aec99d1ca1ce4cce79406173ff76f0481754 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 13 Jan 2026 13:43:04 +0000 Subject: [PATCH 65/71] Add helper trait that restricts lifetimes and extra predicates to ensure soundness --- compiler/rustc_hir/src/lang_items.rs | 2 + compiler/rustc_middle/src/traits/select.rs | 2 + .../src/ty/context/impl_interner.rs | 1 + compiler/rustc_middle/src/ty/mod.rs | 15 ++- .../src/solve/assembly/mod.rs | 24 ++++ .../src/solve/effect_goals.rs | 7 ++ .../src/solve/normalizes_to.rs | 7 ++ .../src/solve/trait_goals.rs | 49 ++++++++- compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/select/candidate_assembly.rs | 34 +++++- .../src/traits/select/confirmation.rs | 33 ++++++ .../src/traits/select/mod.rs | 1 + compiler/rustc_type_ir/src/lang_items.rs | 1 + library/core/src/any.rs | 104 +++++++++++------- .../src/library-features/try-as-dyn.md | 90 +++++++++++++++ tests/ui/any/any_static.next.stderr | 16 +++ tests/ui/any/any_static.old.stderr | 16 +++ tests/ui/any/any_static.rs | 22 ++++ tests/ui/any/builtin_bound.rs | 23 ++++ tests/ui/any/hrtb.next.stderr | 9 ++ tests/ui/any/hrtb.old.stderr | 9 ++ tests/ui/any/hrtb.rs | 19 ++++ tests/ui/any/hrtb2.next.stderr | 9 ++ tests/ui/any/hrtb2.old.stderr | 9 ++ tests/ui/any/hrtb2.rs | 19 ++++ tests/ui/any/non_static.rs | 1 + tests/ui/any/reject_manual_impl.rs | 29 +++++ tests/ui/any/reject_manual_impl.stderr | 46 ++++++++ tests/ui/any/static_method_bound.rs | 3 +- tests/ui/any/static_method_bound.stderr | 16 +++ tests/ui/any/trait_info_of.next.stderr | 14 +++ tests/ui/any/trait_info_of.old.stderr | 14 +++ tests/ui/any/trait_info_of.rs | 45 ++++++++ tests/ui/any/try_as_dyn.rs | 7 +- tests/ui/any/try_as_dyn_assoc_ty_lifetime.rs | 27 +++++ tests/ui/any/try_as_dyn_builtin_impl.rs | 48 ++++++++ tests/ui/any/try_as_dyn_elaborated_bounds.rs | 29 +++++ tests/ui/any/try_as_dyn_generic_impl.rs | 40 +++++++ .../any/try_as_dyn_generic_trait.next.stderr | 9 ++ .../any/try_as_dyn_generic_trait.old.stderr | 9 ++ tests/ui/any/try_as_dyn_generic_trait.rs | 26 +++++ tests/ui/any/try_as_dyn_mut.rs | 5 +- tests/ui/any/try_as_dyn_soundness_test1.rs | 15 +-- tests/ui/any/try_as_dyn_soundness_test2.rs | 11 +- .../vtable-try-as-dyn.full-debuginfo.stderr | 6 +- .../vtable-try-as-dyn.no-debuginfo.stderr | 6 +- .../reflection/trait_info_of_too_big.stderr | 2 +- 47 files changed, 853 insertions(+), 77 deletions(-) create mode 100644 src/doc/unstable-book/src/library-features/try-as-dyn.md create mode 100644 tests/ui/any/any_static.next.stderr create mode 100644 tests/ui/any/any_static.old.stderr create mode 100644 tests/ui/any/any_static.rs create mode 100644 tests/ui/any/builtin_bound.rs create mode 100644 tests/ui/any/hrtb.next.stderr create mode 100644 tests/ui/any/hrtb.old.stderr create mode 100644 tests/ui/any/hrtb.rs create mode 100644 tests/ui/any/hrtb2.next.stderr create mode 100644 tests/ui/any/hrtb2.old.stderr create mode 100644 tests/ui/any/hrtb2.rs create mode 100644 tests/ui/any/reject_manual_impl.rs create mode 100644 tests/ui/any/reject_manual_impl.stderr create mode 100644 tests/ui/any/static_method_bound.stderr create mode 100644 tests/ui/any/trait_info_of.next.stderr create mode 100644 tests/ui/any/trait_info_of.old.stderr create mode 100644 tests/ui/any/trait_info_of.rs create mode 100644 tests/ui/any/try_as_dyn_assoc_ty_lifetime.rs create mode 100644 tests/ui/any/try_as_dyn_builtin_impl.rs create mode 100644 tests/ui/any/try_as_dyn_elaborated_bounds.rs create mode 100644 tests/ui/any/try_as_dyn_generic_impl.rs create mode 100644 tests/ui/any/try_as_dyn_generic_trait.next.stderr create mode 100644 tests/ui/any/try_as_dyn_generic_trait.old.stderr create mode 100644 tests/ui/any/try_as_dyn_generic_trait.rs diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 1592dfdde4e6f..92f48cda10f9f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -194,6 +194,8 @@ language_item_table! { CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1); DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1); + TryAsDyn, sym::try_as_dyn, try_as_dyn, Target::Trait, GenericRequirement::Exact(1); + // lang items relating to transmutability TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0); TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(2); diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 92f7ed0cb19f6..a2eecebcc3501 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -180,6 +180,8 @@ pub enum SelectionCandidate<'tcx> { BuiltinUnsizeCandidate, BikeshedGuaranteedNoDropCandidate, + + TryAsDynCandidate, } /// The result of trait evaluation. The order is important diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 222a70753311a..0f5ec3e04ddce 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -938,6 +938,7 @@ bidirectional_lang_item_map! { Sized, TransmuteTrait, TrivialClone, + TryAsDyn, Tuple, Unpin, Unsize, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 379df48fc899f..151ca10b85ef6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -313,8 +313,9 @@ pub struct ImplTraitHeader<'tcx> { impl<'tcx> ImplTraitHeader<'tcx> { /// For trait impls, checks whether /// * the type and trait only use generic lifetime arguments (and no concrete ones like `'static`), and - /// * uses each generic param (lifetime or type) only once. - /// Pessimistic analysis, so it will reject alias types + /// * uses any generic param (lifetime or type) only once. + /// + /// This is a pessimistic analysis, so it will reject alias types /// and other types that may be actually ok. We can allow more in the future. /// /// Constants (associated or generic) are irrelevant for this analysis, as their value is neither @@ -336,14 +337,12 @@ impl<'tcx> ImplTraitHeader<'tcx> { ControlFlow::Break(()) } } - RegionKind::ReBound(..) | RegionKind::ReLateParam(_) => { - ControlFlow::Continue(()) - } - RegionKind::ReStatic - | RegionKind::ReVar(_) + RegionKind::ReBound(..) => ControlFlow::Continue(()), + RegionKind::ReStatic | RegionKind::ReError(_) => ControlFlow::Break(()), + RegionKind::ReVar(_) | RegionKind::RePlaceholder(_) | RegionKind::ReErased - | RegionKind::ReError(_) => ControlFlow::Break(()), + | RegionKind::ReLateParam(_) => bug!("unexpected lifetime in impl: {r:?}"), } } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 290e49c8a33a4..040f98de7bcfd 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -365,6 +365,11 @@ where goal: Goal, ) -> Result, NoSolutionOrRerunNonErased>; + fn consider_builtin_try_as_dyn_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolutionOrRerunNonErased>; + /// Consider (possibly several) candidates to upcast or unsize a type to another /// type, excluding the coercion of a sized type into a `dyn Trait`. /// @@ -569,6 +574,14 @@ where let cx = self.cx(); let trait_def_id = goal.predicate.trait_def_id(cx); + // Builtin impls regularly are not `is_fully_generic_for_reflection`, so instead + // of trying to handle these manually, we just reject all builtin impls in reflection + // mode. We can probably lift this restriction for specific cases, but this is safer. + // See `try_as_dyn_builtin_impl` for how just allowing all builtin impls is unsound. + if self.typing_mode().is_reflection() { + return Ok(()); + } + // N.B. When assembling built-in candidates for lang items that are also // `auto` traits, then the auto trait candidate that is assembled in // `consider_auto_trait_candidate` MUST be disqualified to remain sound. @@ -661,6 +674,9 @@ where Some(SolverTraitLangItem::BikeshedGuaranteedNoDrop) => { G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal) } + Some(SolverTraitLangItem::TryAsDyn) => { + G::consider_builtin_try_as_dyn_candidate(self, goal) + } Some(SolverTraitLangItem::Field) => G::consider_builtin_field_candidate(self, goal), _ => Err(NoSolution.into()), } @@ -873,6 +889,14 @@ where return; } + // Builtin impls regularly are not `is_fully_generic_for_reflection`, so instead + // of trying to handle these manually, we just reject all builtin impls in reflection + // mode. We can probably lift this restriction for specific cases, but this is safer. + // See `try_as_dyn_builtin_impl` for how just allowing all builtin impls is unsound. + if self.typing_mode().is_reflection() { + return; + } + let self_ty = goal.predicate.self_ty(); let bounds = match self_ty.kind() { ty::Bool diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 1c53bc7711ed8..df9758d5d2ab7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -451,6 +451,13 @@ where unreachable!("BikeshedGuaranteedNoDrop is not const"); } + fn consider_builtin_try_as_dyn_candidate( + _ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolutionOrRerunNonErased> { + unreachable!("`TryAsDynCompat` is not const: {:?}", goal) + } + fn consider_structural_builtin_unsize_candidates( _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, 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 fd5f1a3f82b86..069102f3db50b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -1077,6 +1077,13 @@ where ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } + + fn consider_builtin_try_as_dyn_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolutionOrRerunNonErased> { + unreachable!("try_as_dyn helper trait doesn't have assoc types") + } } impl EvalCtxt<'_, D> diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 50ccfa84a70be..f29df578cd97b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -10,9 +10,9 @@ use rustc_type_ir::solve::{ RerunReason, RerunResultExt, SizedTraitKind, }; use rustc_type_ir::{ - self as ty, FieldInfo, Interner, MayBeErased, Movability, PredicatePolarity, Region, - TraitPredicate, TraitRef, TypeVisitableExt as _, TypingMode, Unnormalized, Upcast as _, - elaborate, + self as ty, ExistentialPredicate, FieldInfo, Interner, MayBeErased, Movability, + PredicatePolarity, Region, TraitPredicate, TraitRef, TypeVisitableExt as _, TypingMode, + Unnormalized, Upcast as _, elaborate, }; use tracing::{debug, instrument, trace, warn}; @@ -873,6 +873,49 @@ where } } + fn consider_builtin_try_as_dyn_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolutionOrRerunNonErased> { + if goal.predicate.polarity != ty::PredicatePolarity::Positive { + return Err(NoSolution.into()); + } + let cx = ecx.cx(); + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + let self_ty = goal.predicate.self_ty(); + let ty_lifetime = goal.predicate.trait_ref.args.region_at(1); + match self_ty.kind() { + ty::Dynamic(bounds, lifetime) => { + for bound in bounds.iter() { + match bound.skip_binder() { + ExistentialPredicate::Trait(_) => {} + // FIXME(try_as_dyn): check what kind of projections we can allow + ExistentialPredicate::Projection(_) => return Err(NoSolution.into()), + // Auto traits do not affect lifetimes outside of specialization, + // which is disabled in reflection. + ExistentialPredicate::AutoTrait(_) => {} + } + } + ecx.add_goal( + GoalSource::Misc, + goal.with(cx, ty::OutlivesPredicate(ty_lifetime, lifetime)), + )?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + + ty::Bound(..) + | ty::Infer( + ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), + ) => { + panic!("unexpected type `{self_ty:?}`") + } + + _ => Err(NoSolution.into()), + } + }) + } + fn consider_builtin_field_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7917478cc2c60..95421ba8cfdab 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2139,6 +2139,7 @@ symbols! { truncf32, truncf64, truncf128, + try_as_dyn, try_blocks, try_blocks_heterogeneous, try_capture, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index a4f751e23d799..d4027fcf388b1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -15,7 +15,8 @@ use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind}; use rustc_infer::traits::{Obligation, PolyTraitObligation, PredicateObligation, SelectionError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{ - self, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, elaborate, + self, ExistentialPredicate, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, + elaborate, }; use rustc_middle::{bug, span_bug}; use rustc_span::DUMMY_SP; @@ -132,6 +133,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut candidates, ); } + Some(LangItem::TryAsDyn) => { + self.assemble_candidates_for_try_as_dyn(obligation, &mut candidates); + } Some(LangItem::Field) => { self.assemble_candidates_for_field_trait(obligation, &mut candidates); } @@ -1457,6 +1461,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn assemble_candidates_for_try_as_dyn( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + match *obligation.predicate.self_ty().skip_binder().kind() { + ty::Dynamic(bounds, _lifetime) => { + for bound in bounds { + match bound.skip_binder() { + ExistentialPredicate::Trait(_) => {} + // FIXME(try_as_dyn): check what kind of projections we can allow + ExistentialPredicate::Projection(_) => return, + // Auto traits do not affect lifetimes outside of specialization, + // which is disabled in reflection. + ExistentialPredicate::AutoTrait(_) => {} + } + } + candidates.vec.push(TryAsDynCandidate); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + candidates.ambiguous = true; + } + + _ => {} + } + } + fn assemble_candidates_for_field_trait( &mut self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index a7c84e71a68c5..49c277b39289b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -138,6 +138,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BikeshedGuaranteedNoDropCandidate => { self.confirm_bikeshed_guaranteed_no_drop_candidate(obligation) } + + TryAsDynCandidate => self.confirm_try_as_dyn_candidate(obligation), }) } @@ -1315,4 +1317,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } + + fn confirm_try_as_dyn_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> ImplSource<'tcx, PredicateObligation<'tcx>> { + let tcx = self.tcx(); + + let mut obligations = PredicateObligations::new(); + + let self_ty = obligation.predicate.self_ty(); + let ty_lifetime = obligation.predicate.map_bound(|p| p.trait_ref.args.region_at(1)); + + match *self_ty.skip_binder().kind() { + ty::Dynamic(_bounds, lifetime) => { + obligations.push( + obligation.with( + tcx, + ty_lifetime + .map_bound(|ty_lifetime| ty::OutlivesPredicate(ty_lifetime, lifetime)), + ), + ); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + + _ => {} + } + ImplSource::Builtin(BuiltinImplSource::Misc, obligations) + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f94aa9bcb754c..58f2d0c7f33ac 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2073,6 +2073,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinObjectCandidate | BuiltinUnsizeCandidate + | TryAsDynCandidate | BikeshedGuaranteedNoDropCandidate => false, // Non-global param candidates have already been handled, global // where-bounds get ignored. diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 05f9bb382dc38..1671128e67a3a 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -54,6 +54,7 @@ pub enum SolverTraitLangItem { Sized, TransmuteTrait, TrivialClone, + TryAsDyn, Tuple, Unpin, Unsize, diff --git a/library/core/src/any.rs b/library/core/src/any.rs index f518ec810b572..85ff2fe1dd6ee 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -786,9 +786,7 @@ impl TypeId { #[unstable(feature = "type_info", issue = "146922")] #[rustc_const_unstable(feature = "type_info", issue = "146922")] #[rustc_comptime] - pub fn trait_info_of> + ?Sized>( - self, - ) -> Option> { + pub fn trait_info_of<'a, T: TryAsDynCompatible<'a> + ?Sized>(self) -> Option> { // SAFETY: The vtable was obtained for `T`, so it is guaranteed to be `DynMetadata`. // The intrinsic can't infer this because it is designed to work with arbitrary TypeIds. unsafe { transmute(self.trait_info_of_trait_type_id(const { type_id::() })) } @@ -948,12 +946,72 @@ pub const fn type_name_of_val(_val: &T) -> &'static str { type_name::() } -/// Returns `Some(&U)` if `T` can be coerced to the trait object type `U`. Otherwise, it returns `None`. +/// Trait that is automatically implemented for all `dyn Trait<'b, C> + 'a` without assoc type bounds. +/// The lifetime parameter should be the same that is used to constrain generic type parameters +/// that are turned into the dyn trait constrained by `TryAsDynCompatible`. +/// +/// This is required for `try_as_dyn` to be able to soundly convert non-static +/// types to `dyn Trait`. +/// +/// Note: these requirements are sufficient for soundness, but it is unclear +/// if they are all necessary. We may be able to lift some requirements in favor +/// of more precise ones. +/// +#[unstable(feature = "try_as_dyn", issue = "144361")] +#[lang = "try_as_dyn"] +#[rustc_deny_explicit_impl] +pub trait TryAsDynCompatible<'a>: ptr::Pointee> {} + +/// Returns `Some(&U)` if `T` can be coerced to the dyn trait type `U`. Otherwise, it returns `None`. +/// +/// # Run-time failures +/// +/// There are multiple ways to get a `None`, and you need to manually analyze which one it is, as the +/// compiler does not provide any help here. +/// +/// * `T` does not implement `Trait` at all, +/// * `T`'s impl for `Trait` is not fully generic, +/// * `T`'s impl for `Trait` is a builtin impl (e.g. `dyn Debug` implements `Debug`) +/// +/// There is some detailed documentation about this feature at +/// +/// But the gist is summarized below: +/// +/// ## Lifetime-independent impls +/// +/// `try_as_dyn` does not have access to lifetime information, thus it cannot differentiate between +/// `'static`, other lifetimes, and can't reason about outlives bounds on impls. Thus we can only accept +/// impls that do not have `'static` lifetimes, or outlives bounds of any kind. You can have simple +/// trait bounds, and the compiler will transitively only use impls of those simple trait bounds that satisfy +/// the same rules as the main trait you're converting to. +/// +/// An example of a legal impl is: +/// +/// ```rust +/// # trait Trait<'a, T> {} +/// # struct Type<'b, U>(&'b U); +/// # use std::fmt::{Debug, Display}; +/// impl<'a, 'b, T: Debug, U: Display> Trait<'a, T> for Type<'b, U> {} +/// ``` +/// +/// Impls without generic parameters at all are also legal, as long as they contain no `'static` lifetimes. +/// +/// ## Builtin impls +/// +/// Builtin impls (like `impl Debug for dyn Debug`) have various obscure rules and often are not fully generic. +/// To simplify reasoning about what is allowed and what not, all builtin impls are rejected and will neither +/// directly nor indirectly contribute to a `Some` result. /// /// # Compile-time failures -/// Determining whether `T` can be coerced to the trait object type `U` requires compiler trait resolution. +/// Determining whether `T` can be coerced to the dyn trait type `U` requires compiler trait resolution. /// In some cases, that resolution can exceed the recursion limit, /// and compilation will fail instead of this function returning `None`. +/// +/// The input type `T` must outlive the lifetime `'a` on the `dyn Trait + 'a`. +/// This is basically the same rule that forbids `let x: &dyn Trait + 'static = &&some_local_variable;` +/// So if you see borrow check errors around `try_as_dyn`, think about whether a normal unsizing +/// coercion would be possible at all if you were using concrete types or had bounds on the input type. +/// /// # Examples /// /// ```rust @@ -983,7 +1041,7 @@ pub const fn type_name_of_val(_val: &T) -> &'static str { /// ``` #[must_use] #[unstable(feature = "try_as_dyn", issue = "144361")] -pub const fn try_as_dyn> + ?Sized>( +pub const fn try_as_dyn<'a, T: ?Sized + 'a, U: TryAsDynCompatible<'a> + ?Sized>( t: &T, ) -> Option<&U> { // For unsized `T`, `trait_info_of` always returns `None` (vtable lookup is @@ -1006,40 +1064,10 @@ pub const fn try_as_dyn &'static str; -/// } -/// -/// struct Dog; -/// impl Animal for Dog { -/// fn speak(&self) -> &'static str { "woof" } -/// } -/// -/// struct Rock; // does not implement Animal -/// -/// let mut dog = Dog; -/// let mut rock = Rock; -/// -/// let as_animal: Option<&mut dyn Animal> = try_as_dyn_mut::(&mut dog); -/// assert_eq!(as_animal.unwrap().speak(), "woof"); -/// -/// let not_an_animal: Option<&mut dyn Animal> = try_as_dyn_mut::(&mut rock); -/// assert!(not_an_animal.is_none()); -/// ``` +/// See documentation of [try_as_dyn] for details about the behaviour and limitations. #[must_use] #[unstable(feature = "try_as_dyn", issue = "144361")] -pub const fn try_as_dyn_mut> + ?Sized>( +pub const fn try_as_dyn_mut<'a, T: ?Sized + 'a, U: TryAsDynCompatible<'a> + ?Sized>( t: &mut T, ) -> Option<&mut U> { // For unsized `T`, `trait_info_of` always returns `None` (vtable lookup is diff --git a/src/doc/unstable-book/src/library-features/try-as-dyn.md b/src/doc/unstable-book/src/library-features/try-as-dyn.md new file mode 100644 index 0000000000000..81abde709c6dc --- /dev/null +++ b/src/doc/unstable-book/src/library-features/try-as-dyn.md @@ -0,0 +1,90 @@ +# `try_as_dyn` + +The tracking issue for this feature is: [#144361] + +[#144361]: https://github.com/rust-lang/rust/issues/144361 + +------------------------ + +The `try_as_dyn` feature allows going from a generic `T` with no bounds +to a `dyn Trait`, if `T: Trait` and various conditions are upheld. It is +very related to specialization, as it allows you to specialize within +function bodies, but in a more general manner than `Any::downcast`. + +```rust +#![feature(try_as_dyn)] + +fn downcast_debug_format(t: &T) -> String { + match std::any::try_as_dyn::<_, dyn std::fmt::Debug>(t) { + Some(d) => format!("{d:?}"), + None => "default".to_string() + } +} +``` + + +## Rules and reasons for them + +> [!IMPORTANT] +> The main problem of **`try_as_dyn` and specialization is the compiler's inability, while trait-checking, to distinguish/_discriminate_ between any two given lifetimes**[^1]. + +[^1]: the compiler cannot _branch_ on whether "`'a : 'b` holds": for soundness, it can either choose not to know the answer, or _assume_ that it holds and produce an obligation for the borrow-checker which shall "assert this" (making compilation fail in a fatal manner if not). Most usages of Rust lie in the latter category (typical `where` clauses anywhere), whilst specialization/`try_as_dyn()` wants to support fallibility of the operation (_i.e._, being queried on a type not fulfilling the predicate without causing a compilation error). This rules out the latter, resulting in the need for the former, _i.e._, for the `try_as_dyn()` attempt to unconditionally "fail" with `None`. + +### `'static` is not mentioned anywhere in the `impl` block header. + +The most obvious one: if you have `impl IsStatic for &'static str`, then determining whether `&'? str : IsStatic` does hold amounts to discriminating `'? : 'static`. + +### Each outlives `where` bound (`Type: 'a` and `'a: 'b`) does not mention lifetime-infected parameters. + +Parameters are considered lifetime-infected if they are defined in an `impl` block's generic parameter list. +Const generics are excempt, as they can't affect lifetimes. +`for<'a>` lifetimes (and in the future types) are not lifetime-infected. + +We can create lifetime discrimination this way. For instance, given `impl<'a, 'b> Outlives<'a> for &'b str where 'b : 'a {}`, `Outlives<'static>` amounts to `IsStatic` from previous bullet. + +### Each lifetime-infected parameter is mentioned at most once in the `Self` type and the implemented trait's generic parameters, combined. + +Repetition of a parameter entails equality of those two use-sites; in lifetime-terms, this would be a double `'a : 'b` / `'b : 'a` clause, for instance. +Follow-up from the previous example: `impl<'a> Uses<'a> for &'a str {}`, and check whether `&'? str : Uses<'static>`. + +### Each individual trait where bound (`Type: Trait`) mentions each lifetime-infected parameter at most once. + +Mentioning a lifetime-infected parameter in multiple `where` bounds is allowed. + +Looking at the previous rules, which focuses on `Self : …`, this is just observing that shifting the requirements to other parameters within `where` clauses \[ought to\] boil down to the same set of issues. + +This is _unnecessarily restrictive_: we should be able to loosen it up somehow. Repetition only in `where` clauses seems fine. + + +### The `impl` block is a handwritten impl + +as opposed to a type implementing a trait automatically by the compiler (such as auto-traits, `dyn Bounds… : Bounds…`, and closures) + + +The reason for this is that some such auto-generated impls _come with hidden bounds or whatnot_, which run afoul of the previous rules, whilst also being _extremely challenging for the current compiler logic to know of such bounds_. +IIUC, this restriction could be lifted in the future should the compiler logic be better at spotting these hidden bounds, when present. + +One contrived such example being the case of `dyn 'u + for<'a> Outlives<'a>`, where the compiler-generated `impl` for it of `Outlives` is: `impl<'b, 'u> Outlives<'b> for dyn 'u + for<'a> Outlives<'a> where 'b : 'u {}` which violates the "`'a: 'b` not to mention lt-infected params" rule, whilst also being hard to detect in current compiler logic. + +### Associated type projections (`::Assoc`) are not mentioned anywhere in the `impl` block header. + +Associated-type equality bounds can very much amount to lifetime-infected parameter equality constraints, +which are problematic as per the "at most one mention of each lifetime-infected parameter in header" rule. +To illustrate, with the following definitions, `&'? str: Trait<'static>` discriminates `'?` against `'static`: +```rust +trait Trait<'x> {} +impl<'a, 'b> Trait<'b> for &'a str +where + // &'a str = &'b str, + Option<&'a str>: IntoIterator, +{} +``` + +```rust +trait Trait<'x> {} +impl<'a> Trait<'a> for &'a str {} +``` + +### Each trait `where` bound with an associated type equality (`Type: Trait`) does not mention lifetime-infected parameters. + +Checking whether `Option<&'? str>: IntoIterator` holds discriminates `'?` against `'static`. diff --git a/tests/ui/any/any_static.next.stderr b/tests/ui/any/any_static.next.stderr new file mode 100644 index 0000000000000..e57d544140980 --- /dev/null +++ b/tests/ui/any/any_static.next.stderr @@ -0,0 +1,16 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/any_static.rs:18:35 + | +LL | fn extend(a: &Payload) -> &'static Payload { + | - - let's call the lifetime of this reference `'1` + | | + | `a` is a reference that is only valid in the function body +LL | let b: &(dyn Any + 'static) = try_as_dyn::<&Payload, dyn Any + 'static>(&a).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `a` escapes the function body here + | argument requires that `'1` must outlive `'static` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/any/any_static.old.stderr b/tests/ui/any/any_static.old.stderr new file mode 100644 index 0000000000000..e57d544140980 --- /dev/null +++ b/tests/ui/any/any_static.old.stderr @@ -0,0 +1,16 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/any_static.rs:18:35 + | +LL | fn extend(a: &Payload) -> &'static Payload { + | - - let's call the lifetime of this reference `'1` + | | + | `a` is a reference that is only valid in the function body +LL | let b: &(dyn Any + 'static) = try_as_dyn::<&Payload, dyn Any + 'static>(&a).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `a` escapes the function body here + | argument requires that `'1` must outlive `'static` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/any/any_static.rs b/tests/ui/any/any_static.rs new file mode 100644 index 0000000000000..7305cabfa8c16 --- /dev/null +++ b/tests/ui/any/any_static.rs @@ -0,0 +1,22 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +#![feature(try_as_dyn)] + +use std::any::{Any, try_as_dyn}; + +type Payload = Box; + +fn main() { + let storage: Box = Box::new(Box::new(1i32)); + let wrong: &'static Payload = extend(&*storage); + drop(storage); + println!("{wrong}"); +} + +fn extend(a: &Payload) -> &'static Payload { + let b: &(dyn Any + 'static) = try_as_dyn::<&Payload, dyn Any + 'static>(&a).unwrap(); + //~^ ERROR: borrowed data escapes outside of function + let c: &&'static Payload = b.downcast_ref::<&'static Payload>().unwrap(); + *c +} diff --git a/tests/ui/any/builtin_bound.rs b/tests/ui/any/builtin_bound.rs new file mode 100644 index 0000000000000..8c4bcf7ad2e3f --- /dev/null +++ b/tests/ui/any/builtin_bound.rs @@ -0,0 +1,23 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass +#![feature(try_as_dyn)] + +trait Trait {} + +// In contrast to `T: Sized`, `Struct: Sized` does not go +// through a fast path, and is thus rejected by the builtin impl +// check that rejects all builtin impls in reflection mode. +// FIXME(try_as_dyn): should probably allow builtin impls that +// are never lifetime dependent (like Sized). +impl Trait for Struct where Struct: Sized {} + +struct Struct(T); + +const _: () = { + let x = Struct(42); + assert!(std::any::try_as_dyn::<_, dyn Trait>(&x).is_none()); +}; + +fn main() {} diff --git a/tests/ui/any/hrtb.next.stderr b/tests/ui/any/hrtb.next.stderr new file mode 100644 index 0000000000000..385b3c3cf2212 --- /dev/null +++ b/tests/ui/any/hrtb.next.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation panicked: called `Option::unwrap()` on a `None` value + --> $DIR/hrtb.rs:15:25 + | +LL | let _dy: &dyn Bar = try_as_dyn(&x).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/any/hrtb.old.stderr b/tests/ui/any/hrtb.old.stderr new file mode 100644 index 0000000000000..385b3c3cf2212 --- /dev/null +++ b/tests/ui/any/hrtb.old.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation panicked: called `Option::unwrap()` on a `None` value + --> $DIR/hrtb.rs:15:25 + | +LL | let _dy: &dyn Bar = try_as_dyn(&x).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/any/hrtb.rs b/tests/ui/any/hrtb.rs new file mode 100644 index 0000000000000..ab31529a0d207 --- /dev/null +++ b/tests/ui/any/hrtb.rs @@ -0,0 +1,19 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +#![feature(try_as_dyn)] + +use std::any::try_as_dyn; + +trait Foo<'a, 'b> {} + +trait Bar {} +impl Foo<'a, 'b> + ?Sized> Bar for Option<*const T> {} + +const _: () = { + let x: Option<*const dyn for<'a> Foo<'a, 'a>> = None; + let _dy: &dyn Bar = try_as_dyn(&x).unwrap(); + //~^ ERROR: `Option::unwrap()` on a `None` value +}; + +fn main() {} diff --git a/tests/ui/any/hrtb2.next.stderr b/tests/ui/any/hrtb2.next.stderr new file mode 100644 index 0000000000000..dfe000dc503a8 --- /dev/null +++ b/tests/ui/any/hrtb2.next.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation panicked: called `Option::unwrap()` on a `None` value + --> $DIR/hrtb2.rs:15:25 + | +LL | let _dy: &dyn Bar = try_as_dyn(&x).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/any/hrtb2.old.stderr b/tests/ui/any/hrtb2.old.stderr new file mode 100644 index 0000000000000..dfe000dc503a8 --- /dev/null +++ b/tests/ui/any/hrtb2.old.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation panicked: called `Option::unwrap()` on a `None` value + --> $DIR/hrtb2.rs:15:25 + | +LL | let _dy: &dyn Bar = try_as_dyn(&x).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/any/hrtb2.rs b/tests/ui/any/hrtb2.rs new file mode 100644 index 0000000000000..ee1bd7cde8982 --- /dev/null +++ b/tests/ui/any/hrtb2.rs @@ -0,0 +1,19 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +#![feature(try_as_dyn)] + +use std::any::try_as_dyn; + +trait Foo<'a> {} + +trait Bar {} +impl Bar for Option<*const T> where T: for<'a> Foo<'a> {} + +const _: () = { + let x: Option<*const dyn Foo<'_>> = None; + let _dy: &dyn Bar = try_as_dyn(&x).unwrap(); + //~^ ERROR: `Option::unwrap()` on a `None` value +}; + +fn main() {} diff --git a/tests/ui/any/non_static.rs b/tests/ui/any/non_static.rs index ad04b7f475e0b..40d7bb7bf5469 100644 --- a/tests/ui/any/non_static.rs +++ b/tests/ui/any/non_static.rs @@ -1,5 +1,6 @@ //@ revisions: next old //@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@check-pass #![feature(try_as_dyn)] diff --git a/tests/ui/any/reject_manual_impl.rs b/tests/ui/any/reject_manual_impl.rs new file mode 100644 index 0000000000000..590cebd48950f --- /dev/null +++ b/tests/ui/any/reject_manual_impl.rs @@ -0,0 +1,29 @@ +#![feature(try_as_dyn)] + +use std::any::TryAsDynCompatible; + +struct Foo(dyn Iterator); + +impl TryAsDynCompatible<'static> for Foo {} +//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted + +struct Bar(dyn Iterator); + +impl<'a> TryAsDynCompatible<'a> for Bar {} +//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted + +struct Baz; + +impl<'a> TryAsDynCompatible<'a> for Baz {} +//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted + +trait Trait {} + +impl<'a> TryAsDynCompatible<'a> for dyn Trait {} +//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted + +impl TryAsDynCompatible<'static> for dyn Iterator {} +//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted +//~| ERROR: only traits defined in the current crate can be implemented for arbitrary types + +fn main() {} diff --git a/tests/ui/any/reject_manual_impl.stderr b/tests/ui/any/reject_manual_impl.stderr new file mode 100644 index 0000000000000..37be37c47ea79 --- /dev/null +++ b/tests/ui/any/reject_manual_impl.stderr @@ -0,0 +1,46 @@ +error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted + --> $DIR/reject_manual_impl.rs:7:1 + | +LL | impl TryAsDynCompatible<'static> for Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed + +error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted + --> $DIR/reject_manual_impl.rs:12:1 + | +LL | impl<'a> TryAsDynCompatible<'a> for Bar {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed + +error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted + --> $DIR/reject_manual_impl.rs:17:1 + | +LL | impl<'a> TryAsDynCompatible<'a> for Baz {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed + +error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted + --> $DIR/reject_manual_impl.rs:22:1 + | +LL | impl<'a> TryAsDynCompatible<'a> for dyn Trait {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed + +error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted + --> $DIR/reject_manual_impl.rs:25:1 + | +LL | impl TryAsDynCompatible<'static> for dyn Iterator {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/reject_manual_impl.rs:25:1 + | +LL | impl TryAsDynCompatible<'static> for dyn Iterator {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------ + | | + | `dyn Iterator` is not defined in the current crate + | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + = note: define and implement a trait or new type instead + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0117, E0322. +For more information about an error, try `rustc --explain E0117`. diff --git a/tests/ui/any/static_method_bound.rs b/tests/ui/any/static_method_bound.rs index aaab8623868f1..b2cc77e4d9cfe 100644 --- a/tests/ui/any/static_method_bound.rs +++ b/tests/ui/any/static_method_bound.rs @@ -1,4 +1,3 @@ -//@run-fail #![feature(try_as_dyn)] use std::any::try_as_dyn; @@ -28,7 +27,7 @@ fn main() { } fn extend(a: &Payload) -> &'static Payload { - // TODO: should panic at the `unwrap` here let b: &(dyn Trait + 'static) = try_as_dyn::<&Payload, dyn Trait + 'static>(&a).unwrap(); + //~^ ERROR: borrowed data escapes outside of function b.as_static() } diff --git a/tests/ui/any/static_method_bound.stderr b/tests/ui/any/static_method_bound.stderr new file mode 100644 index 0000000000000..152672d024ab1 --- /dev/null +++ b/tests/ui/any/static_method_bound.stderr @@ -0,0 +1,16 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/static_method_bound.rs:30:37 + | +LL | fn extend(a: &Payload) -> &'static Payload { + | - - let's call the lifetime of this reference `'1` + | | + | `a` is a reference that is only valid in the function body +LL | let b: &(dyn Trait + 'static) = try_as_dyn::<&Payload, dyn Trait + 'static>(&a).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `a` escapes the function body here + | argument requires that `'1` must outlive `'static` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/any/trait_info_of.next.stderr b/tests/ui/any/trait_info_of.next.stderr new file mode 100644 index 0000000000000..45bbbe4892937 --- /dev/null +++ b/tests/ui/any/trait_info_of.next.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `dyn Trait>: TryAsDynCompatible<'_>` is not satisfied + --> $DIR/trait_info_of.rs:30:30 + | +LL | .trait_info_of::>() + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `TryAsDynCompatible<'_>` is not implemented for `dyn Trait>` + | | + | required by a bound introduced by this call + | +note: required by a bound in `TypeId::trait_info_of` + --> $SRC_DIR/core/src/any.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/any/trait_info_of.old.stderr b/tests/ui/any/trait_info_of.old.stderr new file mode 100644 index 0000000000000..45bbbe4892937 --- /dev/null +++ b/tests/ui/any/trait_info_of.old.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `dyn Trait>: TryAsDynCompatible<'_>` is not satisfied + --> $DIR/trait_info_of.rs:30:30 + | +LL | .trait_info_of::>() + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `TryAsDynCompatible<'_>` is not implemented for `dyn Trait>` + | | + | required by a bound introduced by this call + | +note: required by a bound in `TypeId::trait_info_of` + --> $SRC_DIR/core/src/any.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/any/trait_info_of.rs b/tests/ui/any/trait_info_of.rs new file mode 100644 index 0000000000000..5eb6742be506e --- /dev/null +++ b/tests/ui/any/trait_info_of.rs @@ -0,0 +1,45 @@ +//! Check that we can't use `TypeId::trait_info_of` to unsoundly skip +//! the try_as_dyn checks. + +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +#![feature(type_info, ptr_metadata, arbitrary_self_types_pointers)] + +use std::any::TypeId; +use std::ptr::{self, DynMetadata}; + +type Payload = Box; + +trait Trait { + type Assoc; + fn method(self: *const Self, value: Self::Assoc) -> &'static Payload; +} +struct Thing; +impl Trait for Thing { + type Assoc = &'static Payload; + fn method(self: *const Self, value: Self::Assoc) -> &'static Payload { + value + } +} + +fn extend<'a>(payload: &'a Payload) -> &'static Payload { + let metadata: DynMetadata> = const { + TypeId::of::() + .trait_info_of::>() + //~^ ERROR `dyn Trait>: TryAsDynCompatible<'_>` is not satisfied + .unwrap() + .get_vtable() + }; + let ptr: *const dyn Trait = + ptr::from_raw_parts(std::ptr::null::<()>(), metadata); + ptr.method(payload) +} + +fn main() { + let payload: Box = Box::new(Box::new(1i32)); + let wrong: &'static Payload = extend(&*payload); + drop(payload); + println!("{wrong}"); +} diff --git a/tests/ui/any/try_as_dyn.rs b/tests/ui/any/try_as_dyn.rs index ee220f797ced9..cf9ca7bd885da 100644 --- a/tests/ui/any/try_as_dyn.rs +++ b/tests/ui/any/try_as_dyn.rs @@ -1,3 +1,6 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ run-pass #![feature(try_as_dyn)] @@ -7,7 +10,7 @@ use std::fmt::Debug; fn debug_format_with_try_as_dyn(t: &T) -> String { match std::any::try_as_dyn::<_, dyn Debug>(t) { Some(d) => format!("{d:?}"), - None => "default".to_string() + None => "default".to_string(), } } @@ -16,7 +19,7 @@ fn main() { #[allow(dead_code)] #[derive(Debug)] struct A { - index: usize + index: usize, } let a = A { index: 42 }; let result = debug_format_with_try_as_dyn(&a); diff --git a/tests/ui/any/try_as_dyn_assoc_ty_lifetime.rs b/tests/ui/any/try_as_dyn_assoc_ty_lifetime.rs new file mode 100644 index 0000000000000..aa2056a7fc42c --- /dev/null +++ b/tests/ui/any/try_as_dyn_assoc_ty_lifetime.rs @@ -0,0 +1,27 @@ +//@check-pass +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +#![feature(try_as_dyn)] + +use std::any::try_as_dyn; + +trait HasAssoc<'a> { + type Assoc; +} +struct Dummy; +impl<'a> HasAssoc<'a> for Dummy { + // Changing this to &'a i64 makes try_as_dyn succeed + type Assoc = &'static i64; +} + +trait Trait {} +impl Trait for i32 where for<'a> Dummy: HasAssoc<'a, Assoc = &'a i64> {} + +const _: () = { + let x = 1i32; + assert!(try_as_dyn::<_, dyn Trait>(&x).is_none()); +}; + +fn main() {} diff --git a/tests/ui/any/try_as_dyn_builtin_impl.rs b/tests/ui/any/try_as_dyn_builtin_impl.rs new file mode 100644 index 0000000000000..4ed06a78c2e36 --- /dev/null +++ b/tests/ui/any/try_as_dyn_builtin_impl.rs @@ -0,0 +1,48 @@ +#![feature(try_as_dyn)] +//@ run-fail +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +use std::any::{Any, try_as_dyn}; + +type Payload = Box; + +trait Outlives<'b>: 'b {} + +trait WithLt { + type Ref; +} +impl<'a> WithLt for dyn for<'b> Outlives<'b> + 'a { + type Ref = &'a Payload; +} + +struct Thing(T::Ref); + +trait Trait { + fn get(&self) -> &'static Payload; +} +impl Trait for Thing +where + T: WithLt + for<'b> Outlives<'b> + ?Sized, +{ + fn get(&self) -> &'static Payload { + let x: &::Ref = &self.0; + let y: &(dyn Any + 'static) = x; + let z: &&'static Payload = y.downcast_ref().unwrap(); + *z + } +} + +fn extend<'a>(payload: &'a Payload) -> &'static Payload { + let thing: Thing Outlives<'b> + 'a> = Thing(payload); + let dy: &dyn Trait = try_as_dyn(&thing).unwrap(); + dy.get() +} + +fn main() { + let payload: Box = Box::new(Box::new(1)); + let wrong: &'static Payload = extend(&*payload); + drop(payload); + println!("{wrong}"); +} diff --git a/tests/ui/any/try_as_dyn_elaborated_bounds.rs b/tests/ui/any/try_as_dyn_elaborated_bounds.rs new file mode 100644 index 0000000000000..b0357e4fcca2c --- /dev/null +++ b/tests/ui/any/try_as_dyn_elaborated_bounds.rs @@ -0,0 +1,29 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@check-pass + +#![feature(try_as_dyn)] + +use std::any::try_as_dyn; + +trait Trait: 'static {} +trait Other {} +struct Foo(T); + +impl Trait for () {} +impl Trait for &'static () {} + +// This impl has an implied `T: 'static` bound, but that's +// not an issue, as we just ignore all `Trait` impls where +// that would be a relevant distinguisher. +impl Other for Foo {} + +const _: () = { + let foo = Foo(()); + assert!(try_as_dyn::, dyn Other>(&foo).is_some()); + let foo = Foo(&()); + assert!(try_as_dyn::, dyn Other>(&foo).is_none()); +}; + +fn main() {} diff --git a/tests/ui/any/try_as_dyn_generic_impl.rs b/tests/ui/any/try_as_dyn_generic_impl.rs new file mode 100644 index 0000000000000..21033312fe277 --- /dev/null +++ b/tests/ui/any/try_as_dyn_generic_impl.rs @@ -0,0 +1,40 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +#![feature(try_as_dyn)] +//@ check-pass + +use std::any::try_as_dyn; + +struct Thing(T); +trait Trait {} +impl Trait for Thing {} + +const _: () = { + let thing = Thing(1); + assert!(try_as_dyn::<_, dyn Trait>(&thing).is_some()); +}; + +struct Thing2(T); +impl Trait for Thing2 {} +struct NoDebug; + +const _: () = { + let thing = Thing2(1); + assert!(try_as_dyn::<_, dyn Trait>(&thing).is_some()); + let thing = Thing2(NoDebug); + assert!(try_as_dyn::<_, dyn Trait>(&thing).is_none()); +}; + +trait Trait2 {} +impl<'a, 'b> Trait2 for &'a &'b () {} + +struct Thing3(T); +impl Trait for Thing3 {} + +const _: () = { + let thing = Thing3(&&()); + assert!(try_as_dyn::<_, dyn Trait2>(&thing).is_none()); +}; + +fn main() {} diff --git a/tests/ui/any/try_as_dyn_generic_trait.next.stderr b/tests/ui/any/try_as_dyn_generic_trait.next.stderr new file mode 100644 index 0000000000000..99382f9a4032c --- /dev/null +++ b/tests/ui/any/try_as_dyn_generic_trait.next.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation panicked: called `Option::unwrap()` on a `None` value + --> $DIR/try_as_dyn_generic_trait.rs:22:51 + | +LL | let convert: &dyn Convert<&'static Payload> = try_as_dyn(&payload).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/any/try_as_dyn_generic_trait.old.stderr b/tests/ui/any/try_as_dyn_generic_trait.old.stderr new file mode 100644 index 0000000000000..99382f9a4032c --- /dev/null +++ b/tests/ui/any/try_as_dyn_generic_trait.old.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation panicked: called `Option::unwrap()` on a `None` value + --> $DIR/try_as_dyn_generic_trait.rs:22:51 + | +LL | let convert: &dyn Convert<&'static Payload> = try_as_dyn(&payload).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/any/try_as_dyn_generic_trait.rs b/tests/ui/any/try_as_dyn_generic_trait.rs new file mode 100644 index 0000000000000..630c071218fc8 --- /dev/null +++ b/tests/ui/any/try_as_dyn_generic_trait.rs @@ -0,0 +1,26 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +#![feature(try_as_dyn)] + +use std::any::try_as_dyn; + +type Payload = *const i32; + +trait Convert { + fn convert(&self) -> &T; +} + +impl Convert for T { + fn convert(&self) -> &T { + self + } +} + +const _: () = { + let payload: Payload = std::ptr::null(); + let convert: &dyn Convert<&'static Payload> = try_as_dyn(&payload).unwrap(); + //~^ ERROR: `Option::unwrap()` on a `None` value +}; + +fn main() {} diff --git a/tests/ui/any/try_as_dyn_mut.rs b/tests/ui/any/try_as_dyn_mut.rs index ff7baa32ea874..a4fadb72d2823 100644 --- a/tests/ui/any/try_as_dyn_mut.rs +++ b/tests/ui/any/try_as_dyn_mut.rs @@ -1,3 +1,6 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ run-pass #![feature(try_as_dyn)] @@ -7,7 +10,7 @@ use std::fmt::{Error, Write}; fn try_as_dyn_mut_write(t: &mut T, s: &str) -> Result<(), Error> { match std::any::try_as_dyn_mut::<_, dyn Write>(t) { Some(w) => w.write_str(s), - None => Ok(()) + None => Ok(()), } } diff --git a/tests/ui/any/try_as_dyn_soundness_test1.rs b/tests/ui/any/try_as_dyn_soundness_test1.rs index 0772e9a2d77ee..4dfb5492e3a59 100644 --- a/tests/ui/any/try_as_dyn_soundness_test1.rs +++ b/tests/ui/any/try_as_dyn_soundness_test1.rs @@ -1,19 +1,16 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ run-pass #![feature(try_as_dyn)] use std::any::try_as_dyn; -trait Trait { +trait Trait {} -} - -impl Trait for for<'a> fn(&'a Box) { - -} - -fn store(_: &'static Box) { +impl Trait for for<'a> fn(&'a Box) {} -} +fn store(_: &'static Box) {} fn main() { let fn_ptr: fn(&'static Box) = store; diff --git a/tests/ui/any/try_as_dyn_soundness_test2.rs b/tests/ui/any/try_as_dyn_soundness_test2.rs index c16b50d0261ed..a9985384cd1e6 100644 --- a/tests/ui/any/try_as_dyn_soundness_test2.rs +++ b/tests/ui/any/try_as_dyn_soundness_test2.rs @@ -1,14 +1,13 @@ +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ run-pass #![feature(try_as_dyn)] use std::any::try_as_dyn; -trait Trait { +trait Trait {} -} - -impl Trait fn(&'a Box)> for () { - -} +impl Trait fn(&'a Box)> for () {} fn main() { let dt = try_as_dyn::<_, dyn Trait)>>(&()); diff --git a/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr index c9c15e2d62c9f..c6a53d4face4f 100644 --- a/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr +++ b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr @@ -1,15 +1,15 @@ error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture --> $SRC_DIR/core/src/any.rs:LL:COL | - = note: evaluation of `std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>::{constant#0}` failed inside this call -note: inside `TypeId::trait_info_of::` + = note: evaluation of `std::any::try_as_dyn::<'_, [u8; usize::MAX], dyn Trait>::{constant#0}` failed inside this call +note: inside `TypeId::trait_info_of::<'_, dyn Trait>` --> $SRC_DIR/core/src/any.rs:LL:COL note: inside `TypeId::trait_info_of_trait_type_id` --> $SRC_DIR/core/src/any.rs:LL:COL note: inside `type_info::::size` --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL -note: the above error was encountered while instantiating `fn try_as_dyn::<[u8; usize::MAX], dyn Trait>` +note: the above error was encountered while instantiating `fn try_as_dyn::<'_, [u8; usize::MAX], dyn Trait>` --> $DIR/vtable-try-as-dyn.rs:14:13 | LL | let _ = std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>(x); diff --git a/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr index c9c15e2d62c9f..c6a53d4face4f 100644 --- a/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr +++ b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr @@ -1,15 +1,15 @@ error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture --> $SRC_DIR/core/src/any.rs:LL:COL | - = note: evaluation of `std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>::{constant#0}` failed inside this call -note: inside `TypeId::trait_info_of::` + = note: evaluation of `std::any::try_as_dyn::<'_, [u8; usize::MAX], dyn Trait>::{constant#0}` failed inside this call +note: inside `TypeId::trait_info_of::<'_, dyn Trait>` --> $SRC_DIR/core/src/any.rs:LL:COL note: inside `TypeId::trait_info_of_trait_type_id` --> $SRC_DIR/core/src/any.rs:LL:COL note: inside `type_info::::size` --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL -note: the above error was encountered while instantiating `fn try_as_dyn::<[u8; usize::MAX], dyn Trait>` +note: the above error was encountered while instantiating `fn try_as_dyn::<'_, [u8; usize::MAX], dyn Trait>` --> $DIR/vtable-try-as-dyn.rs:14:13 | LL | let _ = std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>(x); diff --git a/tests/ui/reflection/trait_info_of_too_big.stderr b/tests/ui/reflection/trait_info_of_too_big.stderr index b5dc1d3cdb44a..8d8557670e816 100644 --- a/tests/ui/reflection/trait_info_of_too_big.stderr +++ b/tests/ui/reflection/trait_info_of_too_big.stderr @@ -15,7 +15,7 @@ error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target a LL | TypeId::of::<[u8; usize::MAX]>().trait_info_of::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call | -note: inside `TypeId::trait_info_of::` +note: inside `TypeId::trait_info_of::<'_, dyn Trait>` --> $SRC_DIR/core/src/any.rs:LL:COL note: inside `TypeId::trait_info_of_trait_type_id` --> $SRC_DIR/core/src/any.rs:LL:COL From e948729d7220df1f384b714705b18a543805e9ad Mon Sep 17 00:00:00 2001 From: Yukang Date: Thu, 23 Jul 2026 17:49:19 +0800 Subject: [PATCH 66/71] the fixme is outdated as we eagerly normalize outside of the trait solver --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9a1b1f8300957..1014ce1b5d31a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -142,8 +142,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// version (resolve_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. - // FIXME(-Znext-solver): A lot of the calls to this method should - // probably be `resolve_vars_with_obligations` or `structurally_resolve_type` instead. #[instrument(skip(self), level = "debug", ret)] pub(crate) fn resolve_vars_with_obligations>>( &self, From 7490d8ef3ac20a37a761c199aa358ee693021f3d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 17 Jul 2026 19:19:31 +0200 Subject: [PATCH 67/71] add `difference` method to `range_set` --- .../rustc_data_structures/src/range_set.rs | 40 +++++ tests/assembly-llvm/cmse-clear-padding.rs | 157 ++++++++++++++++-- 2 files changed, 179 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_data_structures/src/range_set.rs b/compiler/rustc_data_structures/src/range_set.rs index 514946a0fb2de..bd18728e20da5 100644 --- a/compiler/rustc_data_structures/src/range_set.rs +++ b/compiler/rustc_data_structures/src/range_set.rs @@ -56,4 +56,44 @@ where v.insert(idx, (offset, size)); } } + + /// The ranges from `self` with any intersection with `other` removed. + pub fn difference(&self, other: &Self) -> Self { + let (a, b) = (self, other); + let mut out = Vec::new(); + + let mut j = 0; + for &(a_offset, a_size) in a.0.iter() { + let mut cursor = a_offset; + let a_end = a_offset + a_size; + + // Skip ranges of `b` that end before this range of `a` begins. + // both sequences are sorted they cannot overlap any later range of `a` either. + while let Some(&(b_offset, b_size)) = b.0.get(j) + && b_offset + b_size <= cursor + { + j += 1; + } + + // Carve out each range of `b` that overlaps this range of `a`. A range of `b` may extend + // past `a_end` and overlap the next range of `a`, so leave `j` pointing at it. + let mut k = j; + while let Some(&(b_offset, b_size)) = b.0.get(k) + && b_offset < a_end + { + if b_offset > cursor { + out.push((cursor, b_offset)); + } + cursor = Ord::max(cursor, b_offset + b_size); + k += 1; + } + + // Keep the remainder of the `a`'s range. + if cursor < a_end { + out.push((cursor, a_end)); + } + } + + Self(out) + } } diff --git a/tests/assembly-llvm/cmse-clear-padding.rs b/tests/assembly-llvm/cmse-clear-padding.rs index b092bf304dcca..7c2757c77dbad 100644 --- a/tests/assembly-llvm/cmse-clear-padding.rs +++ b/tests/assembly-llvm/cmse-clear-padding.rs @@ -123,6 +123,8 @@ struct WideU8 { a: u8, } +// `extern "C"` does not clear the padding. +// // CHECK-LABEL: c_ret_with_wide_u8: // CHECK: mov r7, sp // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 @@ -131,6 +133,8 @@ extern "C" fn c_ret_with_wide_u8(a: u8, b: u8) -> [WideU8; 2] { [WideU8 { a }, WideU8 { a: b }] } +// Upper bits are cleared by uxtb. +// // CHECK-LABEL: cmse_ret_with_wide_u8: // CHECK: mov r7, sp // CHECK-NEXT: uxtb r1, r1 @@ -141,6 +145,36 @@ extern "cmse-nonsecure-entry" fn cmse_ret_with_wide_u8(a: u8, b: u8) -> [WideU8; [WideU8 { a }, WideU8 { a: b }] } +// Same idea, the padding is recognized even through the MaybeUninit. +// +// CHECK-LABEL: cmse_ret_with_wide_u8_uninit: +// CHECK: mov r7, sp +// CHECK-NEXT: uxtb r0, r0 +// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 +// CHECK-NEXT: bic r0, r0, #-16711936 +#[no_mangle] +extern "cmse-nonsecure-entry" fn cmse_ret_with_wide_u8_uninit( + a: u16, + b: u16, +) -> [MaybeUninit; 2] { + unsafe { [mem::transmute(a), mem::transmute(b)] } +} + +// Same idea, the padding is recognized even through the MaybeUninit. +// +// CHECK-LABEL: cmse_ret_with_wide_u8_uninit_tuple: +// CHECK: mov r7, sp +// CHECK-NEXT: uxtb r0, r0 +// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 +// CHECK-NEXT: bic r0, r0, #-16711936 +#[no_mangle] +extern "cmse-nonsecure-entry" fn cmse_ret_with_wide_u8_uninit_tuple( + a: u16, + b: u16, +) -> (MaybeUninit, MaybeUninit) { + unsafe { (mem::transmute(a), mem::transmute(b)) } +} + // CHECK-LABEL: c_call_with_inner_wide_u8: // CHECK: push {r7, lr} // CHECK-NEXT: .setfp r7, sp @@ -177,28 +211,115 @@ extern "C" fn cmse_call_with_inner_wide_u8( unsafe { f(x) } } -// CHECK-LABEL: cmse_ret_with_wide_u8_uninit: +/// No variant-dependent padding. +#[repr(C)] +enum VariantsSameSize { + A(u16), + B(u16), +} +impl Copy for VariantsSameSize {} + +// CHECK-LABEL: variants_same_size: // CHECK: mov r7, sp -// CHECK-NEXT: uxtb r0, r0 +// CHECK-NEXT: ldrh r1, [r0, #2] +// CHECK-NEXT: ldrb r0, [r0] // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 -// CHECK-NEXT: bic r0, r0, #-16711936 #[no_mangle] -extern "cmse-nonsecure-entry" fn cmse_ret_with_wide_u8_uninit( - a: u16, - b: u16, -) -> [MaybeUninit; 2] { - unsafe { [mem::transmute(a), mem::transmute(b)] } +extern "cmse-nonsecure-entry" fn variants_same_size(v: &VariantsSameSize) -> VariantsSameSize { + *v } -// CHECK-LABEL: cmse_ret_with_wide_u8_uninit_tuple: -// CHECK: mov r7, sp -// CHECK-NEXT: uxtb r0, r0 -// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 -// CHECK-NEXT: bic r0, r0, #-16711936 +/// One byte of variant-dependent padding. +#[repr(C)] +enum VariantsDifferentSize { + A(u8), + B(u16), +} +impl Copy for VariantsDifferentSize {} + #[no_mangle] -extern "cmse-nonsecure-entry" fn cmse_ret_with_wide_u8_uninit_tuple( - a: u16, - b: u16, -) -> (MaybeUninit, MaybeUninit) { - unsafe { (mem::transmute(a), mem::transmute(b)) } +extern "cmse-nonsecure-entry" fn variants_different_size( + v: &VariantsDifferentSize, +) -> VariantsDifferentSize { + *v +} + +enum Void {} +impl Copy for Void {} + +#[repr(C)] +enum UninhabitedVariant { + A(Void), + B(u16), +} +impl Copy for UninhabitedVariant {} + +#[no_mangle] +extern "cmse-nonsecure-entry" fn uninhabited_variant(v: &UninhabitedVariant) -> UninhabitedVariant { + *v +} + +#[no_mangle] +#[expect(improper_ctypes_definitions)] +extern "cmse-nonsecure-entry" fn variants_same_size_array( + v: &[VariantsSameSize; 1], +) -> [VariantsSameSize; 1] { + *v +} + +#[no_mangle] +#[expect(improper_ctypes_definitions)] +extern "cmse-nonsecure-entry" fn variants_different_size_array( + v: &[VariantsDifferentSize; 1], +) -> [VariantsDifferentSize; 1] { + *v +} + +#[no_mangle] +#[expect(improper_ctypes_definitions)] +extern "cmse-nonsecure-entry" fn variants_same_size_tuple( + v: &(VariantsSameSize,), +) -> (VariantsSameSize,) { + *v +} + +#[no_mangle] +#[expect(improper_ctypes_definitions)] +extern "cmse-nonsecure-entry" fn variants_different_size_tuple( + v: &(VariantsDifferentSize,), +) -> (VariantsDifferentSize,) { + *v +} + +/// Three variants of different sizes. +#[repr(C)] +enum ThreeVariants { + A(u8), + B(u16), + C(u32), +} + +#[no_mangle] +#[expect(improper_ctypes_definitions)] +extern "C" fn cmse_call_three_variants( + f: unsafe extern "cmse-nonsecure-call" fn(ThreeVariants), + x: ThreeVariants, +) { + unsafe { f(x) } +} + +/// The tag is stored in the niche of the `bool`. +#[repr(C)] +struct BoolU32 { + flag: bool, + val: u32, +} + +#[no_mangle] +#[expect(improper_ctypes_definitions)] +extern "C" fn cmse_call_niche( + f: unsafe extern "cmse-nonsecure-call" fn(Option), + x: Option, +) { + unsafe { f(x) } } From 0d2986aaa0d66b69259d40684f1deef0f3c3f1cc Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 17 Jul 2026 19:27:33 +0200 Subject: [PATCH 68/71] add LLVM baseline test --- tests/assembly-llvm/cmse-clear-padding.rs | 39 +++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/tests/assembly-llvm/cmse-clear-padding.rs b/tests/assembly-llvm/cmse-clear-padding.rs index 7c2757c77dbad..95f3d6fe8de8c 100644 --- a/tests/assembly-llvm/cmse-clear-padding.rs +++ b/tests/assembly-llvm/cmse-clear-padding.rs @@ -221,9 +221,8 @@ impl Copy for VariantsSameSize {} // CHECK-LABEL: variants_same_size: // CHECK: mov r7, sp -// CHECK-NEXT: ldrh r1, [r0, #2] -// CHECK-NEXT: ldrb r0, [r0] -// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 +// CHECK-NEXT: ldrh r0, [r0, #2] +// CHECK-NEXT: lsls r0, r0, #16 #[no_mangle] extern "cmse-nonsecure-entry" fn variants_same_size(v: &VariantsSameSize) -> VariantsSameSize { *v @@ -237,6 +236,10 @@ enum VariantsDifferentSize { } impl Copy for VariantsDifferentSize {} +// CHECK-LABEL: variants_different_size: +// CHECK: mov r7, sp +// CHECK-NEXT: ldrh r0, [r0, #2] +// CHECK-NEXT: lsls r0, r0, #16 #[no_mangle] extern "cmse-nonsecure-entry" fn variants_different_size( v: &VariantsDifferentSize, @@ -254,11 +257,19 @@ enum UninhabitedVariant { } impl Copy for UninhabitedVariant {} +// CHECK-LABEL: uninhabited_variant: +// CHECK: mov r7, sp +// CHECK-NEXT: ldrh r0, [r0, #2] +// CHECK-NEXT: lsls r0, r0, #16 #[no_mangle] extern "cmse-nonsecure-entry" fn uninhabited_variant(v: &UninhabitedVariant) -> UninhabitedVariant { *v } +// CHECK-LABEL: variants_same_size_array: +// CHECK: mov r7, sp +// CHECK-NEXT: ldrh r0, [r0, #2] +// CHECK-NEXT: lsls r0, r0, #16 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_same_size_array( @@ -267,6 +278,10 @@ extern "cmse-nonsecure-entry" fn variants_same_size_array( *v } +// CHECK-LABEL: variants_different_size_array: +// CHECK: mov r7, sp +// CHECK-NEXT: ldrh r0, [r0, #2] +// CHECK-NEXT: lsls r0, r0, #16 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_different_size_array( @@ -275,6 +290,10 @@ extern "cmse-nonsecure-entry" fn variants_different_size_array( *v } +// CHECK-LABEL: variants_same_size_tuple: +// CHECK: mov r7, sp +// CHECK-NEXT: ldrh r0, [r0, #2] +// CHECK-NEXT: lsls r0, r0, #16 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_same_size_tuple( @@ -283,6 +302,10 @@ extern "cmse-nonsecure-entry" fn variants_same_size_tuple( *v } +// CHECK-LABEL: variants_different_size_tuple: +// CHECK: mov r7, sp +// CHECK-NEXT: ldrh r0, [r0, #2] +// CHECK-NEXT: lsls r0, r0, #16 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_different_size_tuple( @@ -299,6 +322,11 @@ enum ThreeVariants { C(u32), } +// CHECK-LABEL: cmse_call_three_variants: +// CHECK: mov r7, sp +// CHECK-NEXT: mov r1, r2 +// CHECK-NEXT: mov r2, r0 +// CHECK-NEXT: movs r0, #0 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "C" fn cmse_call_three_variants( @@ -315,6 +343,11 @@ struct BoolU32 { val: u32, } +// CHECK-LABEL: cmse_call_niche: +// CHECK: mov r7, sp +// CHECK-NEXT: mov r3, r0 +// CHECK-NEXT: uxtb r0, r1 +// CHECK-NEXT: mov r1, r2 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "C" fn cmse_call_niche( From ff3b1814d6f080d98b1c2315cb78d28f8f9c7281 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 17 Jul 2026 20:04:22 +0200 Subject: [PATCH 69/71] the tag is not padding --- compiler/rustc_abi/src/layout/ty.rs | 11 +++++++ tests/assembly-llvm/cmse-clear-padding.rs | 35 ++++++++++++----------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 9ca4aa2254547..c606319cf2a7f 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -361,6 +361,17 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { } }, Variants::Multiple { variants, .. } => { + // The variants do not contain e.g. the discriminant or coroutine upvars. + let FieldsShape::Arbitrary { offsets, in_memory_order: _ } = &self.fields else { + unreachable!("a multi-variant layout should have `Arbitrary` fields") + }; + + // So add them explicitly. + for (field, &offset) in offsets.iter_enumerated() { + let field = self.field(cx, field.as_usize()); + field.add_data_ranges(cx, base_offset + offset, out); + } + for variant in variants.indices() { let variant = self.for_variant(cx, variant); variant.add_data_ranges(cx, base_offset, out); diff --git a/tests/assembly-llvm/cmse-clear-padding.rs b/tests/assembly-llvm/cmse-clear-padding.rs index 95f3d6fe8de8c..91188c75fe01f 100644 --- a/tests/assembly-llvm/cmse-clear-padding.rs +++ b/tests/assembly-llvm/cmse-clear-padding.rs @@ -221,8 +221,9 @@ impl Copy for VariantsSameSize {} // CHECK-LABEL: variants_same_size: // CHECK: mov r7, sp -// CHECK-NEXT: ldrh r0, [r0, #2] -// CHECK-NEXT: lsls r0, r0, #16 +// CHECK-NEXT: ldrh r1, [r0, #2] +// CHECK-NEXT: ldrb r0, [r0] +// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 #[no_mangle] extern "cmse-nonsecure-entry" fn variants_same_size(v: &VariantsSameSize) -> VariantsSameSize { *v @@ -238,8 +239,8 @@ impl Copy for VariantsDifferentSize {} // CHECK-LABEL: variants_different_size: // CHECK: mov r7, sp -// CHECK-NEXT: ldrh r0, [r0, #2] -// CHECK-NEXT: lsls r0, r0, #16 +// CHECK-NEXT: ldr r0, [r0] +// CHECK-NEXT: bic r0, r0, #65280 #[no_mangle] extern "cmse-nonsecure-entry" fn variants_different_size( v: &VariantsDifferentSize, @@ -259,8 +260,9 @@ impl Copy for UninhabitedVariant {} // CHECK-LABEL: uninhabited_variant: // CHECK: mov r7, sp -// CHECK-NEXT: ldrh r0, [r0, #2] -// CHECK-NEXT: lsls r0, r0, #16 +// CHECK-NEXT: ldrh r1, [r0, #2] +// CHECK-NEXT: ldrb r0, [r0] +// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 #[no_mangle] extern "cmse-nonsecure-entry" fn uninhabited_variant(v: &UninhabitedVariant) -> UninhabitedVariant { *v @@ -268,8 +270,8 @@ extern "cmse-nonsecure-entry" fn uninhabited_variant(v: &UninhabitedVariant) -> // CHECK-LABEL: variants_same_size_array: // CHECK: mov r7, sp -// CHECK-NEXT: ldrh r0, [r0, #2] -// CHECK-NEXT: lsls r0, r0, #16 +// CHECK-NEXT: ldr r0, [r0] +// CHECK-NEXT: bic r0, r0, #65280 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_same_size_array( @@ -280,8 +282,8 @@ extern "cmse-nonsecure-entry" fn variants_same_size_array( // CHECK-LABEL: variants_different_size_array: // CHECK: mov r7, sp -// CHECK-NEXT: ldrh r0, [r0, #2] -// CHECK-NEXT: lsls r0, r0, #16 +// CHECK-NEXT: ldr r0, [r0] +// CHECK-NEXT: bic r0, r0, #65280 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_different_size_array( @@ -292,8 +294,9 @@ extern "cmse-nonsecure-entry" fn variants_different_size_array( // CHECK-LABEL: variants_same_size_tuple: // CHECK: mov r7, sp -// CHECK-NEXT: ldrh r0, [r0, #2] -// CHECK-NEXT: lsls r0, r0, #16 +// CHECK-NEXT: ldrh r1, [r0, #2] +// CHECK-NEXT: ldrb r0, [r0] +// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_same_size_tuple( @@ -304,8 +307,8 @@ extern "cmse-nonsecure-entry" fn variants_same_size_tuple( // CHECK-LABEL: variants_different_size_tuple: // CHECK: mov r7, sp -// CHECK-NEXT: ldrh r0, [r0, #2] -// CHECK-NEXT: lsls r0, r0, #16 +// CHECK-NEXT: ldr r0, [r0] +// CHECK-NEXT: bic r0, r0, #65280 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_different_size_tuple( @@ -324,9 +327,9 @@ enum ThreeVariants { // CHECK-LABEL: cmse_call_three_variants: // CHECK: mov r7, sp +// CHECK-NEXT: mov r3, r0 +// CHECK-NEXT: uxtb r0, r1 // CHECK-NEXT: mov r1, r2 -// CHECK-NEXT: mov r2, r0 -// CHECK-NEXT: movs r0, #0 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "C" fn cmse_call_three_variants( From 91fe3785d31254bb1dd8b8ad1ae8623d9c916dca Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 17 Jul 2026 20:30:18 +0200 Subject: [PATCH 70/71] refactor --- compiler/rustc_abi/src/layout/ty.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index c606319cf2a7f..2689410ad735d 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -291,7 +291,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { /// This is the "guaranteed" padding. There may be more bytes that are padding for some /// but not all variants of this type; those are not included. /// (E.g. `Option` has no guaranteed padding so the empty range set is returned, but its `None` value still has padding). - pub fn padding_ranges(&self, cx: &C) -> Vec> + pub fn variant_independent_padding_ranges(&self, cx: &C) -> Vec> where Ty: TyAbiInterface<'a, C> + Copy, { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 99075536d04a8..36e259b62fae3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -11,7 +11,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::lang_items::LangItem; use rustc_lint_defs::builtin::TAIL_CALL_TRACK_CALLER; use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason}; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; @@ -610,8 +610,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // // Returning a value with value-dependent padding will instead trigger a lint. let ret_layout = self.fn_abi.ret.layout; - let uninit_ranges = ret_layout.padding_ranges(bx.cx()); - self.zero_byte_ranges(bx, llslot, ret_layout.size, &uninit_ranges); + self.clear_cmse_padding(bx, llslot, ret_layout.size, ret_layout); } load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi) @@ -1730,6 +1729,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + fn clear_cmse_padding( + &mut self, + bx: &mut Bx, + base_ptr: Bx::Value, + limit: Size, + layout: TyAndLayout<'tcx>, + ) { + // First clear variant-independent padding, a series of memsets. + let variant_independent = layout.variant_independent_padding_ranges(self.cx); + self.zero_byte_ranges(bx, base_ptr, limit, &variant_independent); + } + fn zero_byte_ranges( &mut self, bx: &mut Bx, @@ -1887,11 +1898,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // // Passing an argument with value-dependent padding will instead trigger a lint. if conv == CanonAbi::Arm(ArmCall::CCmseNonSecureCall) { - self.zero_byte_ranges( + self.clear_cmse_padding( bx, llscratch, Size::from_bytes(copy_bytes), - &arg.layout.padding_ranges(bx.cx()), + arg.layout, ); } From 7460074ff25cd1853c16f26bac51b89134e63976 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 17 Jul 2026 22:16:31 +0200 Subject: [PATCH 71/71] clear the variant-dependent padding --- compiler/rustc_abi/src/layout/ty.rs | 126 ++++++++++----- compiler/rustc_codegen_ssa/src/mir/block.rs | 163 +++++++++++++++++--- tests/assembly-llvm/cmse-clear-padding.rs | 99 ++++++++++-- 3 files changed, 321 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 2689410ad735d..c5d8d758c4733 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -284,6 +284,27 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { found } + /// Whether this type/layout has any padding that is dependent on a variant, i.e. has bytes that + /// are padding for some, but not all, valid values of this type. + pub fn has_variant_dependent_padding(&self, cx: &C) -> bool + where + Ty: TyAbiInterface<'a, C> + Copy, + { + match self.variants { + Variants::Multiple { .. } => true, + Variants::Empty => false, + Variants::Single { .. } => match &self.fields { + FieldsShape::Primitive | FieldsShape::Union(_) => false, + FieldsShape::Array { count, .. } => { + *count > 0 && self.field(cx, 0).has_variant_dependent_padding(cx) + } + FieldsShape::Arbitrary { offsets, .. } => { + (0..offsets.len()).any(|i| self.field(cx, i).has_variant_dependent_padding(cx)) + } + }, + } + } + /// The ranges of bytes that are always ignored by the representation relation of this type. /// /// In other words, for any sequence of bytes, if we reset the these padding bytes to uninit, @@ -316,6 +337,45 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { uninit_ranges } + /// The ranges of bytes that are ignored by the representation relation of this variant. + /// + /// The result does not include variant-independent padding. + pub fn variant_dependent_padding_ranges( + &self, + cx: &C, + variant_index: VariantIdx, + ) -> Vec> + where + Ty: TyAbiInterface<'a, C> + Copy, + { + let Variants::Multiple { .. } = self.variants else { + return Vec::new(); + }; + + // Bytes that are data in some variant. + let mut any = RangeSet::new(); + self.add_data_ranges(cx, Size::ZERO, &mut any); + + // Bytes that are data in this variant. + let mut this = RangeSet::new(); + + // The variants do not contain e.g. the discriminant or coroutine upvars. + let FieldsShape::Arbitrary { offsets, in_memory_order: _ } = &self.fields else { + unreachable!("a multi-variant layout should have `Arbitrary` fields") + }; + + // So add them explicitly. + for (field, &offset) in offsets.iter_enumerated() { + let field = self.field(cx, field.as_usize()); + field.add_data_ranges(cx, offset, &mut this); + } + + self.for_variant(cx, variant_index).add_data_ranges(cx, Size::ZERO, &mut this); + + // Padding specific to this variant: data in some variant, but not in this one. + any.difference(&this).0.iter().map(|&(offset, size)| offset..offset + size).collect() + } + /// Extend `out` with all ranges of bytes that *may* carry relevant data for values of this type. /// For enums and unions there are offsets that are initialized for some /// variants but not for others; those offset *will* get added to `out`. @@ -327,51 +387,43 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { return; } - match &self.variants { - Variants::Empty => { /* done */ } - Variants::Single { index: _ } => match &self.fields { - FieldsShape::Primitive => { - out.add_range(base_offset, self.size); - } - &FieldsShape::Union(field_count) => { - for field in 0..field_count.get() { - let field = self.field(cx, field); - field.add_data_ranges(cx, base_offset, out); - } - } - &FieldsShape::Array { stride, count } => { - let elem = self.field(cx, 0); - - // For scalars we know there is no padding between the elements, - // so the entire array is a single big data range. - if elem.backend_repr.is_scalar() { - out.add_range(base_offset, elem.size * count); - } else { - // FIXME: this is really inefficient for large arrays. - for idx in 0..count { - elem.add_data_ranges(cx, base_offset + idx * stride, out); - } - } + // Visit the fields of this value. For enum values the fields include the discriminant. + match &self.fields { + FieldsShape::Primitive => { + out.add_range(base_offset, self.size); + } + &FieldsShape::Union(field_count) => { + for field in 0..field_count.get() { + let field = self.field(cx, field); + field.add_data_ranges(cx, base_offset, out); } - FieldsShape::Arbitrary { offsets, in_memory_order: _ } => { - for (field, &offset) in offsets.iter_enumerated() { - let field = self.field(cx, field.as_usize()); - field.add_data_ranges(cx, base_offset + offset, out); + } + &FieldsShape::Array { stride, count } => { + let elem = self.field(cx, 0); + + // For scalars we know there is no padding between the elements, + // so the entire array is a single big data range. + if elem.backend_repr.is_scalar() { + out.add_range(base_offset, elem.size * count); + } else { + // FIXME: this is really inefficient for large arrays. + for idx in 0..count { + elem.add_data_ranges(cx, base_offset + idx * stride, out); } } - }, - Variants::Multiple { variants, .. } => { - // The variants do not contain e.g. the discriminant or coroutine upvars. - let FieldsShape::Arbitrary { offsets, in_memory_order: _ } = &self.fields else { - unreachable!("a multi-variant layout should have `Arbitrary` fields") - }; - - // So add them explicitly. + } + FieldsShape::Arbitrary { offsets, in_memory_order: _ } => { for (field, &offset) in offsets.iter_enumerated() { let field = self.field(cx, field.as_usize()); field.add_data_ranges(cx, base_offset + offset, out); } + } + } + // Visit the fields of each variant. + match &self.variants { + Variants::Empty | Variants::Single { index: _ } => { /* done */ } + Variants::Multiple { variants, .. } => { for variant in variants.indices() { let variant = self.for_variant(cx, variant); variant.add_data_ranges(cx, base_offset, out); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 36e259b62fae3..6170f93b2451c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -2,7 +2,8 @@ use std::cmp; use std::ops::Range; use rustc_abi::{ - Align, ArmCall, BackendRepr, CanonAbi, ExternAbi, HasDataLayout, Reg, Size, WrappingRange, + Align, ArmCall, BackendRepr, CanonAbi, ExternAbi, FieldsShape, HasDataLayout, Reg, Size, + VariantIdx, Variants, WrappingRange, }; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; @@ -603,14 +604,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if self.fn_abi.conv == CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) { // The return value of an `extern "cmse-nonsecure-entry"` function crosses the - // secure boundary. Zero padding bytes so information does not leak. - // - // This only zeroes "guaranteed" padding. There may be more bytes that are - // padding for some but not all variants of this type; those are not zeroed. - // - // Returning a value with value-dependent padding will instead trigger a lint. + // secure boundary. Clear any padding bytes so information does not leak. let ret_layout = self.fn_abi.ret.layout; - self.clear_cmse_padding(bx, llslot, ret_layout.size, ret_layout); + self.clear_padding_cmse(bx, llslot, ret_layout.size, ret_layout); } load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi) @@ -1729,7 +1725,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - fn clear_cmse_padding( + /// When using CMSE, values that cross the secure boundary from secure to non-secure mode can + /// contain stale secure data in their padding bytes. This function clears that data. This is + /// required when a value is: + /// + /// - passed to an `extern "cmse-nonsecure-call"` function + /// - returned from an `extern "cmse-nonsecure-entry"` function + /// + /// This function clears both: + /// + /// - variant-independent padding, bytes that are padding for all valid values of the type + /// - variant-dependent padding, bytes that are padding for some but not all values of the type + /// + /// Clearing variant-dependent padding requires looking at the data at runtime to determine what + /// bytes to clear. + fn clear_padding_cmse( &mut self, bx: &mut Bx, base_ptr: Bx::Value, @@ -1738,25 +1748,143 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) { // First clear variant-independent padding, a series of memsets. let variant_independent = layout.variant_independent_padding_ranges(self.cx); - self.zero_byte_ranges(bx, base_ptr, limit, &variant_independent); + self.zero_byte_ranges(bx, base_ptr, Size::ZERO, limit, &variant_independent); + + // Then clear the extra padding of the active variant of any (nested) enum. + self.clear_variant_dependent_padding(bx, base_ptr, Size::ZERO, limit, layout); + } + + fn clear_variant_dependent_padding( + &mut self, + bx: &mut Bx, + base_ptr: Bx::Value, + base_offset: Size, + limit: Size, + layout: TyAndLayout<'tcx>, + ) { + let cx = self.cx; + + if !layout.has_variant_dependent_padding(cx) { + return; + } + + // Recurse into aggregate fields/elements to reach any nested enums. + match layout.fields { + FieldsShape::Array { stride, count } => { + let elem = layout.field(cx, 0); + if elem.has_variant_dependent_padding(cx) { + for idx in 0..count { + let off = base_offset + idx * stride; + self.clear_variant_dependent_padding(bx, base_ptr, off, limit, elem); + } + } + } + FieldsShape::Arbitrary { .. } => { + for i in 0..layout.fields.count() { + let field = layout.field(cx, i); + if field.has_variant_dependent_padding(cx) { + let off = base_offset + layout.fields.offset(i); + self.clear_variant_dependent_padding(bx, base_ptr, off, limit, field); + } + } + } + FieldsShape::Primitive | FieldsShape::Union(_) => { /* nothing to visit */ } + } + + // If this is not a multi-variant enum, we're done. + let Variants::Multiple { ref variants, .. } = layout.variants else { + return; + }; + + // Collect variants that will need padding cleared. + let mut work = Vec::with_capacity(variants.len()); + for i in 0..variants.len() { + let idx = VariantIdx::from_usize(i); + let variant = layout.for_variant(cx, idx); + + // Don't consider uninhabited variants. + if variant.is_uninhabited() { + continue; + } + + let variant_dependent = layout.variant_dependent_padding_ranges(cx, idx); + let has_nested_variant_dependent = (0..variant.fields.count()) + .any(|i| variant.field(cx, i).has_variant_dependent_padding(cx)); + + if !variant_dependent.is_empty() || has_nested_variant_dependent { + work.push((idx, variant, variant_dependent)); + } + } + + if work.is_empty() { + return; + } + + // Build the switch and clear the appropriate padding for each variant. + let root_block = bx.llbb(); + let join_block = bx.append_sibling_block("cmse_pad_join"); + let mut cases = Vec::with_capacity(work.len()); + + for (idx, variant, variant_dependent) in work.into_iter() { + let Some(discr) = layout.ty.discriminant_for_variant(bx.tcx(), idx) else { + bug!("multi-variant layout on a type without discriminants"); + }; + + let variant_block = bx.append_sibling_block("cmse_pad_variant"); + bx.switch_to_block(variant_block); + + // Clear the padding of this variant. + self.zero_byte_ranges(bx, base_ptr, base_offset, limit, &variant_dependent); + + // Recurse into the fields. + for i in 0..variant.fields.count() { + let field = variant.field(cx, i); + let off = base_offset + variant.fields.offset(i); + self.clear_variant_dependent_padding(bx, base_ptr, off, limit, field); + } + + bx.br(join_block); + cases.push((discr.val, variant_block)); + } + + // Construct the dispatch. + bx.switch_to_block(root_block); + + let discr_ty = layout.ty.discriminant_ty(bx.tcx()); + let enum_ptr = bx.inbounds_ptradd(base_ptr, bx.const_usize(base_offset.bytes())); + let operand = OperandRef { + val: OperandValue::Ref(PlaceValue::new_sized(enum_ptr, layout.align.abi)), + layout, + move_annotation: None, + }; + let discr = operand.codegen_get_discr(self, bx, discr_ty); + + // Default to the join block (for variants without variant-dependent padding). + bx.switch(discr, join_block, cases.into_iter()); + + bx.switch_to_block(join_block); } fn zero_byte_ranges( &mut self, bx: &mut Bx, ptr: Bx::Value, + offset: Size, limit: Size, ranges: &[Range], ) { let zero = bx.const_u8(0); for range in ranges { - let end = cmp::min(range.end, limit); + let start = range.start + offset; + let end = range.end + offset; + + let end = cmp::min(end, limit); if range.start >= end { continue; } - let offset = bx.const_usize(range.start.bytes()); - let len = bx.const_usize((end - range.start).bytes()); + let offset = bx.const_usize(start.bytes()); + let len = bx.const_usize((end - start).bytes()); let ptr = bx.inbounds_ptradd(ptr, offset); bx.memset(ptr, zero, len, Align::ONE, MemFlags::empty()); } @@ -1891,14 +2019,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ); // The arguments of an `extern "cmse-nonsecure-call"` function cross the secure - // boundary. Zero padding bytes so information does not leak. - // - // This only zeroes "guaranteed" padding. There may be more bytes that are - // padding for some but not all variants of this type; those are not zeroed. - // - // Passing an argument with value-dependent padding will instead trigger a lint. + // boundary. Clear any padding bytes so information does not leak. if conv == CanonAbi::Arm(ArmCall::CCmseNonSecureCall) { - self.clear_cmse_padding( + self.clear_padding_cmse( bx, llscratch, Size::from_bytes(copy_bytes), diff --git a/tests/assembly-llvm/cmse-clear-padding.rs b/tests/assembly-llvm/cmse-clear-padding.rs index 91188c75fe01f..93b10845ea511 100644 --- a/tests/assembly-llvm/cmse-clear-padding.rs +++ b/tests/assembly-llvm/cmse-clear-padding.rs @@ -237,10 +237,16 @@ enum VariantsDifferentSize { } impl Copy for VariantsDifferentSize {} +// A uxtbeq conditionally clears the padding only for variant A. +// // CHECK-LABEL: variants_different_size: // CHECK: mov r7, sp -// CHECK-NEXT: ldr r0, [r0] -// CHECK-NEXT: bic r0, r0, #65280 +// CHECK-NEXT: ldrh r1, [r0, #2] +// CHECK-NEXT: ldrb r0, [r0] +// CHECK-NEXT: lsls r2, r0, #31 +// CHECK-NEXT: it eq +// CHECK-NEXT: uxtbeq r1, r1 +// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 #[no_mangle] extern "cmse-nonsecure-entry" fn variants_different_size( v: &VariantsDifferentSize, @@ -258,6 +264,8 @@ enum UninhabitedVariant { } impl Copy for UninhabitedVariant {} +// Only `B` is inhabited, so reading the tag is not needed. +// // CHECK-LABEL: uninhabited_variant: // CHECK: mov r7, sp // CHECK-NEXT: ldrh r1, [r0, #2] @@ -268,6 +276,7 @@ extern "cmse-nonsecure-entry" fn uninhabited_variant(v: &UninhabitedVariant) -> *v } +// The single guaranteed-padding byte is cleared with a `bic` mask over the whole loaded word. // CHECK-LABEL: variants_same_size_array: // CHECK: mov r7, sp // CHECK-NEXT: ldr r0, [r0] @@ -282,8 +291,12 @@ extern "cmse-nonsecure-entry" fn variants_same_size_array( // CHECK-LABEL: variants_different_size_array: // CHECK: mov r7, sp -// CHECK-NEXT: ldr r0, [r0] -// CHECK-NEXT: bic r0, r0, #65280 +// CHECK-NEXT: ldrh r1, [r0, #2] +// CHECK-NEXT: ldrb r0, [r0] +// CHECK-NEXT: lsls r2, r0, #31 +// CHECK-NEXT: it eq +// CHECK-NEXT: uxtbeq r1, r1 +// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_different_size_array( @@ -307,8 +320,12 @@ extern "cmse-nonsecure-entry" fn variants_same_size_tuple( // CHECK-LABEL: variants_different_size_tuple: // CHECK: mov r7, sp -// CHECK-NEXT: ldr r0, [r0] -// CHECK-NEXT: bic r0, r0, #65280 +// CHECK-NEXT: ldrh r1, [r0, #2] +// CHECK-NEXT: ldrb r0, [r0] +// CHECK-NEXT: lsls r2, r0, #31 +// CHECK-NEXT: it eq +// CHECK-NEXT: uxtbeq r1, r1 +// CHECK-NEXT: orr.w r0, r0, r1, lsl #16 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "cmse-nonsecure-entry" fn variants_different_size_tuple( @@ -326,10 +343,21 @@ enum ThreeVariants { } // CHECK-LABEL: cmse_call_three_variants: -// CHECK: mov r7, sp -// CHECK-NEXT: mov r3, r0 +// CHECK: mov r3, r0 +// +// Clears padding in the extend the discriminant. // CHECK-NEXT: uxtb r0, r1 -// CHECK-NEXT: mov r1, r2 +// +// Uses uxtb for the A variant, uxtheq for the B variant, +// and nothing for the C variant. +// +// CHECK-NEXT: cbz r0, .LBB{{[0-9_]+}} +// CHECK-NEXT: cmp r0, #1 +// CHECK-NEXT: it eq +// CHECK-NEXT: uxtheq r2, r2 +// CHECK-NEXT: b .LBB{{[0-9_]+}} +// CHECK-NEXT: .LBB{{[0-9_]+}}: +// CHECK-NEXT: uxtb r2, r2 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "C" fn cmse_call_three_variants( @@ -339,6 +367,51 @@ extern "C" fn cmse_call_three_variants( unsafe { f(x) } } +/// Three variants of different sizes, with a nested enum. +#[repr(C)] +enum ThreeVariantsNested { + A(u8), + B(Option), + C(u32), +} + +// CHECK-LABEL: cmse_call_three_variants_nested: +// CHECK: mov r3, r0 +// +// Clears padding in the extend the discriminant. +// CHECK-NEXT: uxtb r0, r1 +// +// Match on the discriminant, jump to A block +// +// CHECK-NEXT: cbz r0, .LBB{{[0-9_]+}} +// +// Match on the discriminant, do nothing for C. +// +// CHECK-NEXT: cmp r0, #1 +// CHECK-NEXT: bne .LBB{{[0-9_]+}} +// +// The B variant conditionally clears the Option payload. +// +// CHECK-NEXT: lsls r1, r2, #31 +// CHECK-NEXT: movw r1, #65535 +// CHECK-NEXT: it eq +// CHECK-NEXT: moveq r1, #254 +// CHECK-NEXT: ands r2, r1 +// CHECK-NEXT: b .LBB{{[0-9_]+}} +// +// The A variant uses uxtb. +// +// CHECK-NEXT: .LBB{{[0-9_]+}}: +// CHECK-NEXT: uxtb r2, r2 +#[no_mangle] +#[expect(improper_ctypes_definitions)] +extern "C" fn cmse_call_three_variants_nested( + f: unsafe extern "cmse-nonsecure-call" fn(ThreeVariantsNested), + x: ThreeVariantsNested, +) { + unsafe { f(x) } +} + /// The tag is stored in the niche of the `bool`. #[repr(C)] struct BoolU32 { @@ -346,11 +419,17 @@ struct BoolU32 { val: u32, } +// Bit 0b0010 is used to encode the tag, so `r0 - 2 == 0` checks the tag value. +// Zero-extension clears padding in the tag 32-bit word, the `val` is either 0 +// (stored in r1) when None or the actual value r2 when Some. +// // CHECK-LABEL: cmse_call_niche: // CHECK: mov r7, sp // CHECK-NEXT: mov r3, r0 // CHECK-NEXT: uxtb r0, r1 -// CHECK-NEXT: mov r1, r2 +// CHECK-NEXT: subs r1, r0, #2 +// CHECK-NEXT: it ne +// CHECK-NEXT: movne r1, r2 #[no_mangle] #[expect(improper_ctypes_definitions)] extern "C" fn cmse_call_niche(