From 06fb36c92ea0d92d93361badde0cae5aab763d43 Mon Sep 17 00:00:00 2001 From: "Kurt Heiritz (pseudo)" Date: Fri, 27 Jun 2025 16:26:53 +0530 Subject: [PATCH 01/68] Update poison.rs to fix the typo (sys->sync) --- library/std/src/sync/poison.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index cc1d0b30152a..571f0d14248e 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -13,7 +13,7 @@ //! depend on the primitive. See [#Overview] bellow. //! //! For the alternative implementations that do not employ poisoning, -//! see `std::sys::nonpoisoning`. +//! see `std::sync::nonpoisoning`. //! //! # Overview //! From 6ca9b43ea9f50d5e77dc0f8d4d62283017b3f1b0 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sun, 29 Jun 2025 21:04:41 +0500 Subject: [PATCH 02/68] moved test files --- .../nested-cfg-attr-conditional-compilation.rs} | 0 .../nested-cfg-attr-conditional-compilation.stderr} | 0 tests/ui/{myriad-closures.rs => closures/many-closures.rs} | 0 .../mutable-function-parameters.rs} | 0 .../generic-params-nested-fn-scope-error.rs} | 0 .../generic-params-nested-fn-scope-error.stderr} | 0 .../{nested-block-comment.rs => parser/nested-block-comments.rs} | 0 tests/ui/{nested-class.rs => resolve/resolve-same-name-struct.rs} | 0 .../mutually-recursive-types.rs} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{nested-cfg-attrs.rs => cfg/nested-cfg-attr-conditional-compilation.rs} (100%) rename tests/ui/{nested-cfg-attrs.stderr => cfg/nested-cfg-attr-conditional-compilation.stderr} (100%) rename tests/ui/{myriad-closures.rs => closures/many-closures.rs} (100%) rename tests/ui/{mut-function-arguments.rs => fn/mutable-function-parameters.rs} (100%) rename tests/ui/{nested-ty-params.rs => generics/generic-params-nested-fn-scope-error.rs} (100%) rename tests/ui/{nested-ty-params.stderr => generics/generic-params-nested-fn-scope-error.stderr} (100%) rename tests/ui/{nested-block-comment.rs => parser/nested-block-comments.rs} (100%) rename tests/ui/{nested-class.rs => resolve/resolve-same-name-struct.rs} (100%) rename tests/ui/{mutual-recursion-group.rs => type/mutually-recursive-types.rs} (100%) diff --git a/tests/ui/nested-cfg-attrs.rs b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs similarity index 100% rename from tests/ui/nested-cfg-attrs.rs rename to tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs diff --git a/tests/ui/nested-cfg-attrs.stderr b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr similarity index 100% rename from tests/ui/nested-cfg-attrs.stderr rename to tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr diff --git a/tests/ui/myriad-closures.rs b/tests/ui/closures/many-closures.rs similarity index 100% rename from tests/ui/myriad-closures.rs rename to tests/ui/closures/many-closures.rs diff --git a/tests/ui/mut-function-arguments.rs b/tests/ui/fn/mutable-function-parameters.rs similarity index 100% rename from tests/ui/mut-function-arguments.rs rename to tests/ui/fn/mutable-function-parameters.rs diff --git a/tests/ui/nested-ty-params.rs b/tests/ui/generics/generic-params-nested-fn-scope-error.rs similarity index 100% rename from tests/ui/nested-ty-params.rs rename to tests/ui/generics/generic-params-nested-fn-scope-error.rs diff --git a/tests/ui/nested-ty-params.stderr b/tests/ui/generics/generic-params-nested-fn-scope-error.stderr similarity index 100% rename from tests/ui/nested-ty-params.stderr rename to tests/ui/generics/generic-params-nested-fn-scope-error.stderr diff --git a/tests/ui/nested-block-comment.rs b/tests/ui/parser/nested-block-comments.rs similarity index 100% rename from tests/ui/nested-block-comment.rs rename to tests/ui/parser/nested-block-comments.rs diff --git a/tests/ui/nested-class.rs b/tests/ui/resolve/resolve-same-name-struct.rs similarity index 100% rename from tests/ui/nested-class.rs rename to tests/ui/resolve/resolve-same-name-struct.rs diff --git a/tests/ui/mutual-recursion-group.rs b/tests/ui/type/mutually-recursive-types.rs similarity index 100% rename from tests/ui/mutual-recursion-group.rs rename to tests/ui/type/mutually-recursive-types.rs From f12120d2bd237ffbf03c8de027513a8d0bc63616 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sun, 29 Jun 2025 21:05:19 +0500 Subject: [PATCH 03/68] cleaned up some tests --- ...nested-cfg-attr-conditional-compilation.rs | 16 ++++++- ...ed-cfg-attr-conditional-compilation.stderr | 6 +-- tests/ui/closures/many-closures.rs | 38 +++++++++------ tests/ui/fn/mutable-function-parameters.rs | 9 +++- .../generic-params-nested-fn-scope-error.rs | 15 ++++-- ...eneric-params-nested-fn-scope-error.stderr | 16 +++---- tests/ui/parser/nested-block-comments.rs | 27 ++++++++++- tests/ui/resolve/resolve-same-name-struct.rs | 44 ++++++++++-------- tests/ui/type/mutually-recursive-types.rs | 46 ++++++++++++++++--- 9 files changed, 154 insertions(+), 63 deletions(-) diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs index 941807a84310..7618e83a6429 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs @@ -1,4 +1,18 @@ +//! Test that nested `cfg_attr` attributes work correctly for conditional compilation. +//! This checks that `cfg_attr` can be arbitrarily deeply nested and that the +//! expansion works from outside to inside, eventually applying the innermost +//! conditional compilation directive. +//! +//! In this test, `cfg_attr(all(), cfg_attr(all(), cfg(false)))` should expand to: +//! 1. `cfg_attr(all(), cfg(false))` (outer cfg_attr applied) +//! 2. `cfg(false)` (inner cfg_attr applied) +//! 3. Function `f` is excluded from compilation +//! +//! Added in . + #[cfg_attr(all(), cfg_attr(all(), cfg(false)))] fn f() {} -fn main() { f() } //~ ERROR cannot find function `f` in this scope +fn main() { + f() //~ ERROR cannot find function `f` in this scope +} diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr index 16c293071435..ddb8ea1e13ae 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr @@ -1,8 +1,8 @@ error[E0425]: cannot find function `f` in this scope - --> $DIR/nested-cfg-attrs.rs:4:13 + --> $DIR/nested-cfg-attr-conditional-compilation.rs:17:5 | -LL | fn main() { f() } - | ^ not found in this scope +LL | f() + | ^ not found in this scope error: aborting due to 1 previous error diff --git a/tests/ui/closures/many-closures.rs b/tests/ui/closures/many-closures.rs index 541d27d5de40..c96ef5544c22 100644 --- a/tests/ui/closures/many-closures.rs +++ b/tests/ui/closures/many-closures.rs @@ -1,13 +1,17 @@ +//! Test that the compiler can handle code bases with a high number of closures. +//! This is particularly important for the MinGW toolchain which has a limit of +//! 2^15 weak symbols per binary. This test creates 2^12 closures (256 functions +//! with 16 closures each) to check the compiler handles this correctly. +//! +//! Regression test for . +//! See also . + //@ run-pass -// This test case tests whether we can handle code bases that contain a high -// number of closures, something that needs special handling in the MingGW -// toolchain. -// See https://github.com/rust-lang/rust/issues/34793 for more information. // Make sure we don't optimize anything away: //@ compile-flags: -C no-prepopulate-passes -Cpasses=name-anon-globals -// Expand something exponentially +/// Macro for exponential expansion - creates 2^n copies of the given macro call macro_rules! go_bacterial { ($mac:ident) => ($mac!()); ($mac:ident 1 $($t:tt)*) => ( @@ -16,24 +20,28 @@ macro_rules! go_bacterial { ) } -macro_rules! mk_closure { - () => ((move || {})()) +/// Creates and immediately calls a closure +macro_rules! create_closure { + () => { + (move || {})() + }; } -macro_rules! mk_fn { +/// Creates a function containing 16 closures (2^4) +macro_rules! create_function_with_closures { () => { { - fn function() { - // Make 16 closures - go_bacterial!(mk_closure 1 1 1 1); + fn function_with_closures() { + // Create 16 closures using exponential expansion: 2^4 = 16 + go_bacterial!(create_closure 1 1 1 1); } - let _ = function(); + let _ = function_with_closures(); } } } fn main() { - // Make 2^8 functions, each containing 16 closures, - // resulting in 2^12 closures overall. - go_bacterial!(mk_fn 1 1 1 1 1 1 1 1); + // Create 2^8 = 256 functions, each containing 16 closures, + // resulting in 2^12 = 4096 closures total. + go_bacterial!(create_function_with_closures 1 1 1 1 1 1 1 1); } diff --git a/tests/ui/fn/mutable-function-parameters.rs b/tests/ui/fn/mutable-function-parameters.rs index 01c264fce038..5045a783f049 100644 --- a/tests/ui/fn/mutable-function-parameters.rs +++ b/tests/ui/fn/mutable-function-parameters.rs @@ -1,3 +1,6 @@ +//! Test that function and closure parameters marked as `mut` can be mutated +//! within the function body. + //@ run-pass fn f(mut y: Box) { @@ -6,10 +9,12 @@ fn f(mut y: Box) { } fn g() { - let frob = |mut q: Box| { *q = 2; assert_eq!(*q, 2); }; + let frob = |mut q: Box| { + *q = 2; + assert_eq!(*q, 2); + }; let w = Box::new(37); frob(w); - } pub fn main() { diff --git a/tests/ui/generics/generic-params-nested-fn-scope-error.rs b/tests/ui/generics/generic-params-nested-fn-scope-error.rs index c00c3bc33723..eaf514da3376 100644 --- a/tests/ui/generics/generic-params-nested-fn-scope-error.rs +++ b/tests/ui/generics/generic-params-nested-fn-scope-error.rs @@ -1,9 +1,14 @@ -fn hd(v: Vec ) -> U { - fn hd1(w: [U]) -> U { return w[0]; } - //~^ ERROR can't use generic parameters from outer item - //~| ERROR can't use generic parameters from outer item +//! Test that generic parameters from an outer function are not accessible +//! in nested functions. - return hd1(v); +fn foo(v: Vec) -> U { + fn bar(w: [U]) -> U { + //~^ ERROR can't use generic parameters from outer item + //~| ERROR can't use generic parameters from outer item + return w[0]; + } + + return bar(v); } fn main() {} diff --git a/tests/ui/generics/generic-params-nested-fn-scope-error.stderr b/tests/ui/generics/generic-params-nested-fn-scope-error.stderr index 7ca65b421b25..7fd1069c651f 100644 --- a/tests/ui/generics/generic-params-nested-fn-scope-error.stderr +++ b/tests/ui/generics/generic-params-nested-fn-scope-error.stderr @@ -1,19 +1,19 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/nested-ty-params.rs:2:16 + --> $DIR/generic-params-nested-fn-scope-error.rs:5:16 | -LL | fn hd(v: Vec ) -> U { - | - type parameter from outer item -LL | fn hd1(w: [U]) -> U { return w[0]; } +LL | fn foo(v: Vec) -> U { + | - type parameter from outer item +LL | fn bar(w: [U]) -> U { | - ^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` error[E0401]: can't use generic parameters from outer item - --> $DIR/nested-ty-params.rs:2:23 + --> $DIR/generic-params-nested-fn-scope-error.rs:5:23 | -LL | fn hd(v: Vec ) -> U { - | - type parameter from outer item -LL | fn hd1(w: [U]) -> U { return w[0]; } +LL | fn foo(v: Vec) -> U { + | - type parameter from outer item +LL | fn bar(w: [U]) -> U { | - ^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` diff --git a/tests/ui/parser/nested-block-comments.rs b/tests/ui/parser/nested-block-comments.rs index 008df27e0e2a..8fe778963619 100644 --- a/tests/ui/parser/nested-block-comments.rs +++ b/tests/ui/parser/nested-block-comments.rs @@ -1,11 +1,34 @@ +//! Test that nested block comments are properly supported by the parser. +//! +//! See . + //@ run-pass /* This test checks that nested comments are supported - /* - This should not panic + /* This is a nested comment + /* And this is even more deeply nested */ + Back to the first level of nesting */ + + /* Another nested comment at the same level */ +*/ + +/* Additional test cases for nested comments */ + +#[rustfmt::skip] +/* + /* Level 1 + /* Level 2 + /* Level 3 */ + */ + */ */ pub fn main() { + // Check that code after nested comments works correctly + let _x = 42; + + /* Even inline /* nested */ comments work */ + let _y = /* nested /* comment */ test */ 100; } diff --git a/tests/ui/resolve/resolve-same-name-struct.rs b/tests/ui/resolve/resolve-same-name-struct.rs index f84ab40dd1d4..1bea0938e3da 100644 --- a/tests/ui/resolve/resolve-same-name-struct.rs +++ b/tests/ui/resolve/resolve-same-name-struct.rs @@ -1,25 +1,29 @@ +//! Test that name resolution works correctly when a struct and its constructor +//! function have the same name within a nested scope. This checks that the +//! compiler can distinguish between type names and value names in the same +//! namespace. + //@ run-pass -#![allow(non_camel_case_types)] +struct Point { + i: isize, +} + +impl Point { + fn get_value(&self) -> isize { + return 37; + } +} + +// Constructor function with the same name as the struct +#[allow(non_snake_case)] +fn Point(i: isize) -> Point { + Point { i } +} pub fn main() { - struct b { - i: isize, - } - - impl b { - fn do_stuff(&self) -> isize { return 37; } - } - - fn b(i:isize) -> b { - b { - i: i - } - } - - // fn b(x:isize) -> isize { panic!(); } - - let z = b(42); - assert_eq!(z.i, 42); - assert_eq!(z.do_stuff(), 37); + // Test that we can use the constructor function + let point = Point(42); + assert_eq!(point.i, 42); + assert_eq!(point.get_value(), 37); } diff --git a/tests/ui/type/mutually-recursive-types.rs b/tests/ui/type/mutually-recursive-types.rs index f83150af7dc8..5472e1582218 100644 --- a/tests/ui/type/mutually-recursive-types.rs +++ b/tests/ui/type/mutually-recursive-types.rs @@ -1,15 +1,47 @@ +//! Test that mutually recursive type definitions are properly handled by the compiler. +//! This checks that types can reference each other in their definitions through +//! `Box` indirection, creating cycles in the type dependency graph. + //@ run-pass -#![allow(non_camel_case_types)] -#![allow(dead_code)] +#[derive(Debug, PartialEq)] +enum Colour { + Red, + Green, + Blue, +} +#[derive(Debug, PartialEq)] +enum Tree { + Children(Box), + Leaf(Colour), +} -enum colour { red, green, blue, } +#[derive(Debug, PartialEq)] +enum List { + Cons(Box, Box), + Nil, +} -enum tree { children(Box), leaf(colour), } +#[derive(Debug, PartialEq)] +enum SmallList { + Kons(isize, Box), + Neel, +} -enum list { cons(Box, Box), nil, } +pub fn main() { + // Construct and test all variants of Colour + let _ = Tree::Leaf(Colour::Red); -enum small_list { kons(isize, Box), neel, } + let _ = Tree::Leaf(Colour::Green); -pub fn main() { } + let _ = Tree::Leaf(Colour::Blue); + + let _ = List::Nil; + + let _ = Tree::Children(Box::new(List::Nil)); + + let _ = List::Cons(Box::new(Tree::Leaf(Colour::Blue)), Box::new(List::Nil)); + + let _ = SmallList::Kons(42, Box::new(SmallList::Neel)); +} From 3b57db4d87ea589ec05e2c7543fb6ad2df41795f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 1 Jul 2025 06:59:49 +0000 Subject: [PATCH 04/68] Give some UI tests more apropriate names Prepare for rework done by the rest of RUST-142440. Co-authored-by: Kivooeo --- src/tools/tidy/src/issues.txt | 4 ---- .../impl-future-escaping-bound-vars-ice.rs} | 0 .../impl-future-escaping-bound-vars-ice.stderr} | 0 .../closure-capture-after-clone.rs} | 0 .../closure-last-use-move.rs} | 0 .../closure-upvar-last-use-analysis.rs} | 0 .../auxiliary/cross-crate-refcell-match.rs} | 0 tests/ui/{ => cross-crate}/auxiliary/kinds_in_metadata.rs | 0 .../cross-crate-refcell-match.rs} | 0 .../metadata-trait-serialization.rs} | 0 .../higher-ranked-encoding.rs} | 0 .../{item-name-overload.rs => modules/mod-same-item-names.rs} | 0 .../inherent-impl-primitive-types-error.rs} | 0 .../inherent-impl-primitive-types-error.stderr} | 0 14 files changed, 4 deletions(-) rename tests/ui/{issues-71798.rs => async-await/impl-future-escaping-bound-vars-ice.rs} (100%) rename tests/ui/{issues-71798.stderr => async-await/impl-future-escaping-bound-vars-ice.stderr} (100%) rename tests/ui/{last-use-is-capture.rs => closures/closure-capture-after-clone.rs} (100%) rename tests/ui/{last-use-in-block.rs => closures/closure-last-use-move.rs} (100%) rename tests/ui/{last-use-in-cap-clause.rs => closures/closure-upvar-last-use-analysis.rs} (100%) rename tests/ui/{auxiliary/issue-16822.rs => cross-crate/auxiliary/cross-crate-refcell-match.rs} (100%) rename tests/ui/{ => cross-crate}/auxiliary/kinds_in_metadata.rs (100%) rename tests/ui/{issue-16822.rs => cross-crate/cross-crate-refcell-match.rs} (100%) rename tests/ui/{kinds-in-metadata.rs => cross-crate/metadata-trait-serialization.rs} (100%) rename tests/ui/{issue-15924.rs => higher-ranked/higher-ranked-encoding.rs} (100%) rename tests/ui/{item-name-overload.rs => modules/mod-same-item-names.rs} (100%) rename tests/ui/{kinds-of-primitive-impl.rs => type/inherent-impl-primitive-types-error.rs} (100%) rename tests/ui/{kinds-of-primitive-impl.stderr => type/inherent-impl-primitive-types-error.stderr} (100%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 18da874dbef2..0966c3d79356 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -276,7 +276,6 @@ ui/auto-traits/issue-23080-2.rs ui/auto-traits/issue-23080.rs ui/auto-traits/issue-83857-ub.rs ui/auto-traits/issue-84075.rs -ui/auxiliary/issue-16822.rs ui/bench/issue-32062.rs ui/binding/issue-40402-1.rs ui/binding/issue-40402-2.rs @@ -1368,9 +1367,6 @@ ui/infinite/issue-41731-infinite-macro-println.rs ui/intrinsics/issue-28575.rs ui/intrinsics/issue-84297-reifying-copy.rs ui/invalid/issue-114435-layout-type-err.rs -ui/issue-15924.rs -ui/issue-16822.rs -ui/issues-71798.rs ui/issues/auxiliary/issue-11224.rs ui/issues/auxiliary/issue-11508.rs ui/issues/auxiliary/issue-11529.rs diff --git a/tests/ui/issues-71798.rs b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.rs similarity index 100% rename from tests/ui/issues-71798.rs rename to tests/ui/async-await/impl-future-escaping-bound-vars-ice.rs diff --git a/tests/ui/issues-71798.stderr b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.stderr similarity index 100% rename from tests/ui/issues-71798.stderr rename to tests/ui/async-await/impl-future-escaping-bound-vars-ice.stderr diff --git a/tests/ui/last-use-is-capture.rs b/tests/ui/closures/closure-capture-after-clone.rs similarity index 100% rename from tests/ui/last-use-is-capture.rs rename to tests/ui/closures/closure-capture-after-clone.rs diff --git a/tests/ui/last-use-in-block.rs b/tests/ui/closures/closure-last-use-move.rs similarity index 100% rename from tests/ui/last-use-in-block.rs rename to tests/ui/closures/closure-last-use-move.rs diff --git a/tests/ui/last-use-in-cap-clause.rs b/tests/ui/closures/closure-upvar-last-use-analysis.rs similarity index 100% rename from tests/ui/last-use-in-cap-clause.rs rename to tests/ui/closures/closure-upvar-last-use-analysis.rs diff --git a/tests/ui/auxiliary/issue-16822.rs b/tests/ui/cross-crate/auxiliary/cross-crate-refcell-match.rs similarity index 100% rename from tests/ui/auxiliary/issue-16822.rs rename to tests/ui/cross-crate/auxiliary/cross-crate-refcell-match.rs diff --git a/tests/ui/auxiliary/kinds_in_metadata.rs b/tests/ui/cross-crate/auxiliary/kinds_in_metadata.rs similarity index 100% rename from tests/ui/auxiliary/kinds_in_metadata.rs rename to tests/ui/cross-crate/auxiliary/kinds_in_metadata.rs diff --git a/tests/ui/issue-16822.rs b/tests/ui/cross-crate/cross-crate-refcell-match.rs similarity index 100% rename from tests/ui/issue-16822.rs rename to tests/ui/cross-crate/cross-crate-refcell-match.rs diff --git a/tests/ui/kinds-in-metadata.rs b/tests/ui/cross-crate/metadata-trait-serialization.rs similarity index 100% rename from tests/ui/kinds-in-metadata.rs rename to tests/ui/cross-crate/metadata-trait-serialization.rs diff --git a/tests/ui/issue-15924.rs b/tests/ui/higher-ranked/higher-ranked-encoding.rs similarity index 100% rename from tests/ui/issue-15924.rs rename to tests/ui/higher-ranked/higher-ranked-encoding.rs diff --git a/tests/ui/item-name-overload.rs b/tests/ui/modules/mod-same-item-names.rs similarity index 100% rename from tests/ui/item-name-overload.rs rename to tests/ui/modules/mod-same-item-names.rs diff --git a/tests/ui/kinds-of-primitive-impl.rs b/tests/ui/type/inherent-impl-primitive-types-error.rs similarity index 100% rename from tests/ui/kinds-of-primitive-impl.rs rename to tests/ui/type/inherent-impl-primitive-types-error.rs diff --git a/tests/ui/kinds-of-primitive-impl.stderr b/tests/ui/type/inherent-impl-primitive-types-error.stderr similarity index 100% rename from tests/ui/kinds-of-primitive-impl.stderr rename to tests/ui/type/inherent-impl-primitive-types-error.stderr From 1daba456361d0bbac3d0bd9e0f11b7784d20ebe5 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Fri, 13 Jun 2025 02:30:47 +0500 Subject: [PATCH 05/68] cleaned up some tests --- .../impl-future-escaping-bound-vars-ice.rs | 4 ++ ...impl-future-escaping-bound-vars-ice.stderr | 4 +- .../closures/closure-capture-after-clone.rs | 40 ++++++++++++++---- tests/ui/closures/closure-last-use-move.rs | 42 ++++++++++++------- .../closure-upvar-last-use-analysis.rs | 27 +++++++++--- .../cross-crate/cross-crate-refcell-match.rs | 24 ++++++++--- .../metadata-trait-serialization.rs | 5 +-- .../higher-ranked/higher-ranked-encoding.rs | 15 ++++--- tests/ui/modules/mod-same-item-names.rs | 11 +++-- .../inherent-impl-primitive-types-error.rs | 10 +++-- ...inherent-impl-primitive-types-error.stderr | 10 ++--- 11 files changed, 131 insertions(+), 61 deletions(-) diff --git a/tests/ui/async-await/impl-future-escaping-bound-vars-ice.rs b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.rs index 14b6c0f35812..ea30e8c839f7 100644 --- a/tests/ui/async-await/impl-future-escaping-bound-vars-ice.rs +++ b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.rs @@ -1,3 +1,7 @@ +//! Regression test for issue https://github.com/rust-lang/rust/issues/71798 +// ICE with escaping bound variables when impl Future + '_ +// returns non-Future type combined with syntax errors + fn test_ref(x: &u32) -> impl std::future::Future + '_ { //~^ ERROR `u32` is not a future *x diff --git a/tests/ui/async-await/impl-future-escaping-bound-vars-ice.stderr b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.stderr index 52dd14ccb0a1..5beca58e13c7 100644 --- a/tests/ui/async-await/impl-future-escaping-bound-vars-ice.stderr +++ b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find value `u` in this scope - --> $DIR/issues-71798.rs:7:24 + --> $DIR/impl-future-escaping-bound-vars-ice.rs:11:24 | LL | let _ = test_ref & u; | ^ not found in this scope error[E0277]: `u32` is not a future - --> $DIR/issues-71798.rs:1:25 + --> $DIR/impl-future-escaping-bound-vars-ice.rs:5:25 | LL | fn test_ref(x: &u32) -> impl std::future::Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future diff --git a/tests/ui/closures/closure-capture-after-clone.rs b/tests/ui/closures/closure-capture-after-clone.rs index 6e07895f1d30..29fba147909b 100644 --- a/tests/ui/closures/closure-capture-after-clone.rs +++ b/tests/ui/closures/closure-capture-after-clone.rs @@ -1,13 +1,39 @@ +//! Regression test for issue #1399 +//! +//! This tests that when a variable is used (via clone) and then later +//! captured by a closure, the last-use analysis doesn't incorrectly optimize +//! the earlier use as a "last use" and perform an invalid move. +//! +//! The sequence being tested: +//! 1. Create variable `k` +//! 2. Use `k.clone()` for some purpose +//! 3. Later capture `k` in a closure +//! +//! The analysis must not treat step 2 as the "last use" since step 3 needs `k`. +//! +//! See: https://github.com/rust-lang/rust/issues/1399 + //@ run-pass -#![allow(dead_code)] -// Make sure #1399 stays fixed - -struct A { a: Box } +struct A { + _a: Box, +} pub fn main() { - fn invoke(f: F) where F: FnOnce() { f(); } + fn invoke(f: F) + where + F: FnOnce(), + { + f(); + } + let k: Box<_> = 22.into(); - let _u = A {a: k.clone()}; - invoke(|| println!("{}", k.clone()) ) + + // This clone should NOT be treated as "last use" of k + // even though k is not used again until the closure + let _u = A { _a: k.clone() }; + + // Here k is actually captured by the closure + // The last-use analyzer must have accounted for this when processing the clone above + invoke(|| println!("{}", k.clone())); } diff --git a/tests/ui/closures/closure-last-use-move.rs b/tests/ui/closures/closure-last-use-move.rs index 4a166b97bda4..f5b99d87f091 100644 --- a/tests/ui/closures/closure-last-use-move.rs +++ b/tests/ui/closures/closure-last-use-move.rs @@ -1,21 +1,33 @@ +//! Regression test for issue #1818 +//! last-use analysis in closures should allow moves instead of requiring copies. +//! +//! The original issue was that the compiler incorrectly flagged certain return values +//! in anonymous functions/closures as requiring copies of non-copyable values, when +//! they should have been treated as moves (since they were the last use of the value). +//! +//! See: https://github.com/rust-lang/rust/issues/1818 + //@ run-pass -#![allow(dead_code)] -#![allow(unused_parens)] -// Issue #1818 - - -fn lp(s: String, mut f: F) -> T where F: FnMut(String) -> T { - while false { - let r = f(s); - return (r); +fn apply(s: String, mut f: F) -> T +where + F: FnMut(String) -> T +{ + fn g(s: String, mut f: F) -> T + where + F: FnMut(String) -> T + { + f(s) } - panic!(); + + g(s, |v| { + let r = f(v); + r // This should be a move, not requiring copy + }) } -fn apply(s: String, mut f: F) -> T where F: FnMut(String) -> T { - fn g(s: String, mut f: F) -> T where F: FnMut(String) -> T {f(s)} - g(s, |v| { let r = f(v); r }) +pub fn main() { + // Actually test the functionality + let result = apply(String::from("test"), |s| s.len()); + assert_eq!(result, 4); } - -pub fn main() {} diff --git a/tests/ui/closures/closure-upvar-last-use-analysis.rs b/tests/ui/closures/closure-upvar-last-use-analysis.rs index 23c263c98058..2c3e349437dc 100644 --- a/tests/ui/closures/closure-upvar-last-use-analysis.rs +++ b/tests/ui/closures/closure-upvar-last-use-analysis.rs @@ -1,14 +1,29 @@ +//! Regression test for issue #1399 +//! +//! This tests that the compiler's last-use analysis correctly handles variables +//! that are captured by closures (upvars). The original issue was that the analysis +//! would incorrectly optimize variable usage as "last use" and perform moves, even when +//! the variable was later needed by a closure that captured it. +//! +//! See: https://github.com/rust-lang/rust/issues/1399 + //@ run-pass -#![allow(dead_code)] -// Make sure #1399 stays fixed - -struct A { a: Box } +struct A { + _a: Box, +} fn foo() -> Box isize + 'static> { let k: Box<_> = Box::new(22); - let _u = A {a: k.clone()}; - let result = || 22; + + // This use of k.clone() should not be treated as a "last use" + // even though the closure below doesn't actually capture k + let _u = A { _a: k.clone() }; + + // The closure doesn't actually use k, but the analyzer needs to handle + // the potential capture scenario correctly + let result = || 22; + Box::new(result) } diff --git a/tests/ui/cross-crate/cross-crate-refcell-match.rs b/tests/ui/cross-crate/cross-crate-refcell-match.rs index 94d89f88f470..7e46425612f3 100644 --- a/tests/ui/cross-crate/cross-crate-refcell-match.rs +++ b/tests/ui/cross-crate/cross-crate-refcell-match.rs @@ -1,12 +1,24 @@ -//@ run-pass -//@ aux-build:issue-16822.rs +//! Regression test for https://github.com/rust-lang/rust/issues/16822 +// +//! ICE when using RefCell::borrow_mut() +//! inside match statement with cross-crate generics. +//! +//! The bug occurred when: +//! - A library defines a generic struct with RefCell and uses borrow_mut() in match +//! - Main crate implements the library trait for its own type +//! - Cross-crate generic constraint causes type inference issues +//! +//! The problematic match statement is in the auxiliary file, this file triggers it. -extern crate issue_16822 as lib; +//@ run-pass +//@ aux-build:cross-crate-refcell-match.rs + +extern crate cross_crate_refcell_match as lib; use std::cell::RefCell; struct App { - i: isize + i: isize, } impl lib::Update for App { @@ -15,8 +27,10 @@ impl lib::Update for App { } } -fn main(){ +fn main() { let app = App { i: 5 }; let window = lib::Window { data: RefCell::new(app) }; + // This specific pattern (RefCell::borrow_mut in match with cross-crate generics) + // caused the ICE in the original issue window.update(1); } diff --git a/tests/ui/cross-crate/metadata-trait-serialization.rs b/tests/ui/cross-crate/metadata-trait-serialization.rs index 58dffba861d5..a6645018da4a 100644 --- a/tests/ui/cross-crate/metadata-trait-serialization.rs +++ b/tests/ui/cross-crate/metadata-trait-serialization.rs @@ -1,12 +1,11 @@ +//! Test that trait information (like Copy) is correctly serialized in crate metadata + //@ run-pass //@ aux-build:kinds_in_metadata.rs - /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -// Tests that metadata serialization works for the `Copy` kind. - extern crate kinds_in_metadata; use kinds_in_metadata::f; diff --git a/tests/ui/higher-ranked/higher-ranked-encoding.rs b/tests/ui/higher-ranked/higher-ranked-encoding.rs index eb2aef9cee12..463e0f50e537 100644 --- a/tests/ui/higher-ranked/higher-ranked-encoding.rs +++ b/tests/ui/higher-ranked/higher-ranked-encoding.rs @@ -1,9 +1,7 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15924 + //@ run-pass -#![allow(unused_imports)] -#![allow(unused_must_use)] - -use std::fmt; use std::marker::PhantomData; trait Encoder { @@ -26,9 +24,8 @@ impl Encoder for JsonEncoder<'_> { type Error = (); } -fn encode_json Encodable>>( - object: &T, -) -> Result { +// This function uses higher-ranked trait bounds, which previously caused ICE +fn encode_json Encodable>>(object: &T) -> Result { let s = String::new(); { let mut encoder = JsonEncoder(PhantomData); @@ -37,13 +34,15 @@ fn encode_json Encodable>>( Ok(s) } +// Structure with HRTB constraint that was problematic struct Foo Encodable>> { v: T, } +// Drop implementation that exercises the HRTB bounds impl Encodable>> Drop for Foo { fn drop(&mut self) { - encode_json(&self.v); + let _ = encode_json(&self.v); } } diff --git a/tests/ui/modules/mod-same-item-names.rs b/tests/ui/modules/mod-same-item-names.rs index dd2925aa53fe..1e9a9caa5fc5 100644 --- a/tests/ui/modules/mod-same-item-names.rs +++ b/tests/ui/modules/mod-same-item-names.rs @@ -1,16 +1,15 @@ +//! Test that items with identical names can coexist in different modules + //@ run-pass #![allow(dead_code)] - - - mod foo { - pub fn baz() { } + pub fn baz() {} } mod bar { - pub fn baz() { } + pub fn baz() {} } -pub fn main() { } +pub fn main() {} diff --git a/tests/ui/type/inherent-impl-primitive-types-error.rs b/tests/ui/type/inherent-impl-primitive-types-error.rs index f1c2ee8e5506..88b8b9da56b8 100644 --- a/tests/ui/type/inherent-impl-primitive-types-error.rs +++ b/tests/ui/type/inherent-impl-primitive-types-error.rs @@ -1,16 +1,18 @@ +//! Test that inherent impl blocks cannot be defined for primitive types + impl u8 { -//~^ error: cannot define inherent `impl` for primitive types + //~^ ERROR: cannot define inherent `impl` for primitive types pub const B: u8 = 0; } impl str { -//~^ error: cannot define inherent `impl` for primitive types + //~^ ERROR: cannot define inherent `impl` for primitive types fn foo() {} fn bar(self) {} //~ ERROR: size for values of type `str` cannot be known } impl char { -//~^ error: cannot define inherent `impl` for primitive types + //~^ ERROR: cannot define inherent `impl` for primitive types pub const B: u8 = 0; pub const C: u8 = 0; fn foo() {} @@ -19,7 +21,7 @@ impl char { struct MyType; impl &MyType { -//~^ error: cannot define inherent `impl` for primitive types + //~^ ERROR: cannot define inherent `impl` for primitive types pub fn for_ref(self) {} } diff --git a/tests/ui/type/inherent-impl-primitive-types-error.stderr b/tests/ui/type/inherent-impl-primitive-types-error.stderr index 1c8c417e88c1..5b79521a35e7 100644 --- a/tests/ui/type/inherent-impl-primitive-types-error.stderr +++ b/tests/ui/type/inherent-impl-primitive-types-error.stderr @@ -1,5 +1,5 @@ error[E0390]: cannot define inherent `impl` for primitive types - --> $DIR/kinds-of-primitive-impl.rs:1:1 + --> $DIR/inherent-impl-primitive-types-error.rs:3:1 | LL | impl u8 { | ^^^^^^^ @@ -7,7 +7,7 @@ LL | impl u8 { = help: consider using an extension trait instead error[E0390]: cannot define inherent `impl` for primitive types - --> $DIR/kinds-of-primitive-impl.rs:6:1 + --> $DIR/inherent-impl-primitive-types-error.rs:8:1 | LL | impl str { | ^^^^^^^^ @@ -15,7 +15,7 @@ LL | impl str { = help: consider using an extension trait instead error[E0390]: cannot define inherent `impl` for primitive types - --> $DIR/kinds-of-primitive-impl.rs:12:1 + --> $DIR/inherent-impl-primitive-types-error.rs:14:1 | LL | impl char { | ^^^^^^^^^ @@ -23,7 +23,7 @@ LL | impl char { = help: consider using an extension trait instead error[E0390]: cannot define inherent `impl` for primitive types - --> $DIR/kinds-of-primitive-impl.rs:21:1 + --> $DIR/inherent-impl-primitive-types-error.rs:23:1 | LL | impl &MyType { | ^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | impl &MyType { = note: you could also try moving the reference to uses of `MyType` (such as `self`) within the implementation error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/kinds-of-primitive-impl.rs:9:12 + --> $DIR/inherent-impl-primitive-types-error.rs:11:12 | LL | fn bar(self) {} | ^^^^ doesn't have a size known at compile-time From 986f1c9b692665d4e7388062b8d8536acb0c99fd Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 18:21:05 +0500 Subject: [PATCH 06/68] moved tests --- .../allocator-reallocate-overflow.rs} | 0 .../auto-trait-phantom-data-bounds.rs} | 0 .../auto-trait-phantom-data-bounds.stderr} | 0 .../binop-evaluation-order-primitive.rs} | 0 .../basic-ptr-coercions.rs} | 0 .../ptr-mutability-errors.rs} | 0 .../ptr-mutability-errors.stderr} | 0 .../stdout-stderr-separation.rs} | 0 .../closure-parameter-type-inference-mismatch.rs} | 0 ...losure-parameter-type-inference-mismatch.stderr} | 0 .../type-error-diagnostic-in-complex-return.rs} | 0 .../type-error-diagnostic-in-complex-return.stderr} | 0 .../doc-comment-in-generic.rs} | 0 .../raw/raw-string-literals.rs} | Bin .../pattern-ref-bindings-reassignment.rs} | 0 .../pattern-ref-bindings-reassignment.stderr} | 0 .../print-calling-conventions.rs | 0 .../print-calling-conventions.stdout | 0 .../fs-nul-byte-paths.rs} | 0 .../nested-generic-traits-performance.rs} | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{realloc-16687.rs => allocator/allocator-reallocate-overflow.rs} (100%) rename tests/ui/{phantom-auto-trait.rs => auto-traits/auto-trait-phantom-data-bounds.rs} (100%) rename tests/ui/{phantom-auto-trait.stderr => auto-traits/auto-trait-phantom-data-bounds.stderr} (100%) rename tests/ui/{primitive-binop-lhs-mut.rs => binop/binop-evaluation-order-primitive.rs} (100%) rename tests/ui/{ptr-coercion-rpass.rs => coercion/basic-ptr-coercions.rs} (100%) rename tests/ui/{ptr-coercion.rs => coercion/ptr-mutability-errors.rs} (100%) rename tests/ui/{ptr-coercion.stderr => coercion/ptr-mutability-errors.stderr} (100%) rename tests/ui/{print-stdout-eprint-stderr.rs => io-checks/stdout-stderr-separation.rs} (100%) rename tests/ui/{pptypedef.rs => mismatched_types/closure-parameter-type-inference-mismatch.rs} (100%) rename tests/ui/{pptypedef.stderr => mismatched_types/closure-parameter-type-inference-mismatch.stderr} (100%) rename tests/ui/{point-to-type-err-cause-on-impl-trait-return-2.rs => mismatched_types/type-error-diagnostic-in-complex-return.rs} (100%) rename tests/ui/{point-to-type-err-cause-on-impl-trait-return-2.stderr => mismatched_types/type-error-diagnostic-in-complex-return.stderr} (100%) rename tests/ui/{query-visibility.rs => parser/doc-comment-in-generic.rs} (100%) rename tests/ui/{raw-str.rs => parser/raw/raw-string-literals.rs} (100%) rename tests/ui/{reassign-ref-mut.rs => pattern/move-ref-patterns/pattern-ref-bindings-reassignment.rs} (100%) rename tests/ui/{reassign-ref-mut.stderr => pattern/move-ref-patterns/pattern-ref-bindings-reassignment.stderr} (100%) rename tests/ui/{ => print-request}/print-calling-conventions.rs (100%) rename tests/ui/{ => print-request}/print-calling-conventions.stdout (100%) rename tests/ui/{paths-containing-nul.rs => std/fs-nul-byte-paths.rs} (100%) rename tests/ui/{project-cache-issue-31849.rs => typeck/nested-generic-traits-performance.rs} (100%) diff --git a/tests/ui/realloc-16687.rs b/tests/ui/allocator/allocator-reallocate-overflow.rs similarity index 100% rename from tests/ui/realloc-16687.rs rename to tests/ui/allocator/allocator-reallocate-overflow.rs diff --git a/tests/ui/phantom-auto-trait.rs b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.rs similarity index 100% rename from tests/ui/phantom-auto-trait.rs rename to tests/ui/auto-traits/auto-trait-phantom-data-bounds.rs diff --git a/tests/ui/phantom-auto-trait.stderr b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.stderr similarity index 100% rename from tests/ui/phantom-auto-trait.stderr rename to tests/ui/auto-traits/auto-trait-phantom-data-bounds.stderr diff --git a/tests/ui/primitive-binop-lhs-mut.rs b/tests/ui/binop/binop-evaluation-order-primitive.rs similarity index 100% rename from tests/ui/primitive-binop-lhs-mut.rs rename to tests/ui/binop/binop-evaluation-order-primitive.rs diff --git a/tests/ui/ptr-coercion-rpass.rs b/tests/ui/coercion/basic-ptr-coercions.rs similarity index 100% rename from tests/ui/ptr-coercion-rpass.rs rename to tests/ui/coercion/basic-ptr-coercions.rs diff --git a/tests/ui/ptr-coercion.rs b/tests/ui/coercion/ptr-mutability-errors.rs similarity index 100% rename from tests/ui/ptr-coercion.rs rename to tests/ui/coercion/ptr-mutability-errors.rs diff --git a/tests/ui/ptr-coercion.stderr b/tests/ui/coercion/ptr-mutability-errors.stderr similarity index 100% rename from tests/ui/ptr-coercion.stderr rename to tests/ui/coercion/ptr-mutability-errors.stderr diff --git a/tests/ui/print-stdout-eprint-stderr.rs b/tests/ui/io-checks/stdout-stderr-separation.rs similarity index 100% rename from tests/ui/print-stdout-eprint-stderr.rs rename to tests/ui/io-checks/stdout-stderr-separation.rs diff --git a/tests/ui/pptypedef.rs b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.rs similarity index 100% rename from tests/ui/pptypedef.rs rename to tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.rs diff --git a/tests/ui/pptypedef.stderr b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.stderr similarity index 100% rename from tests/ui/pptypedef.stderr rename to tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.stderr diff --git a/tests/ui/point-to-type-err-cause-on-impl-trait-return-2.rs b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.rs similarity index 100% rename from tests/ui/point-to-type-err-cause-on-impl-trait-return-2.rs rename to tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.rs diff --git a/tests/ui/point-to-type-err-cause-on-impl-trait-return-2.stderr b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.stderr similarity index 100% rename from tests/ui/point-to-type-err-cause-on-impl-trait-return-2.stderr rename to tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.stderr diff --git a/tests/ui/query-visibility.rs b/tests/ui/parser/doc-comment-in-generic.rs similarity index 100% rename from tests/ui/query-visibility.rs rename to tests/ui/parser/doc-comment-in-generic.rs diff --git a/tests/ui/raw-str.rs b/tests/ui/parser/raw/raw-string-literals.rs similarity index 100% rename from tests/ui/raw-str.rs rename to tests/ui/parser/raw/raw-string-literals.rs diff --git a/tests/ui/reassign-ref-mut.rs b/tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.rs similarity index 100% rename from tests/ui/reassign-ref-mut.rs rename to tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.rs diff --git a/tests/ui/reassign-ref-mut.stderr b/tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.stderr similarity index 100% rename from tests/ui/reassign-ref-mut.stderr rename to tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.stderr diff --git a/tests/ui/print-calling-conventions.rs b/tests/ui/print-request/print-calling-conventions.rs similarity index 100% rename from tests/ui/print-calling-conventions.rs rename to tests/ui/print-request/print-calling-conventions.rs diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-request/print-calling-conventions.stdout similarity index 100% rename from tests/ui/print-calling-conventions.stdout rename to tests/ui/print-request/print-calling-conventions.stdout diff --git a/tests/ui/paths-containing-nul.rs b/tests/ui/std/fs-nul-byte-paths.rs similarity index 100% rename from tests/ui/paths-containing-nul.rs rename to tests/ui/std/fs-nul-byte-paths.rs diff --git a/tests/ui/project-cache-issue-31849.rs b/tests/ui/typeck/nested-generic-traits-performance.rs similarity index 100% rename from tests/ui/project-cache-issue-31849.rs rename to tests/ui/typeck/nested-generic-traits-performance.rs From 1549585f26881927ea8305e0724d2d1f1dc45ade Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 19:28:14 +0500 Subject: [PATCH 07/68] moved tests --- .../reexport-test-harness-entry-point.rs} | 0 .../{stable-addr-of.rs => const-ptr/pointer-address-stability.rs} | 0 .../error-format-short.rs} | 0 .../error-format-short.stderr} | 0 .../{resource-assign-is-not-copy.rs => drop/drop-once-on-move.rs} | 0 tests/ui/{resource-destruct.rs => drop/drop-scope-exit.rs} | 0 .../ui/{seq-args.rs => generics/trait-incorrect-generic-args.rs} | 0 .../trait-incorrect-generic-args.stderr} | 0 .../io-stdout-blocking-writes.rs} | 0 tests/ui/{shadow-bool.rs => shadowed/primitive-type-shadowing.rs} | 0 .../use-shadows-reexport.rs} | 0 .../recursive-type-infinite-size.rs} | 0 .../recursive-type-infinite-size.stderr} | 0 .../sized-box-unsized-content.rs} | 0 .../sized-reference-to-unsized.rs} | 0 .../atomic-types-not-copyable.rs} | 0 .../atomic-types-not-copyable.stderr} | 0 tests/ui/{sse2.rs => target-feature/target-feature-detection.rs} | 0 .../error-trait-object-from-string.rs} | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{reexport-test-harness-main.rs => attributes/reexport-test-harness-entry-point.rs} (100%) rename tests/ui/{stable-addr-of.rs => const-ptr/pointer-address-stability.rs} (100%) rename tests/ui/{short-error-format.rs => diagnostic-flags/error-format-short.rs} (100%) rename tests/ui/{short-error-format.stderr => diagnostic-flags/error-format-short.stderr} (100%) rename tests/ui/{resource-assign-is-not-copy.rs => drop/drop-once-on-move.rs} (100%) rename tests/ui/{resource-destruct.rs => drop/drop-scope-exit.rs} (100%) rename tests/ui/{seq-args.rs => generics/trait-incorrect-generic-args.rs} (100%) rename tests/ui/{seq-args.stderr => generics/trait-incorrect-generic-args.stderr} (100%) rename tests/ui/{stdio-is-blocking.rs => io-checks/io-stdout-blocking-writes.rs} (100%) rename tests/ui/{shadow-bool.rs => shadowed/primitive-type-shadowing.rs} (100%) rename tests/ui/{shadowed-use-visibility.rs => shadowed/use-shadows-reexport.rs} (100%) rename tests/ui/{sized-cycle-note.rs => sized/recursive-type-infinite-size.rs} (100%) rename tests/ui/{sized-cycle-note.stderr => sized/recursive-type-infinite-size.stderr} (100%) rename tests/ui/{sized-owned-pointer.rs => sized/sized-box-unsized-content.rs} (100%) rename tests/ui/{sized-borrowed-pointer.rs => sized/sized-reference-to-unsized.rs} (100%) rename tests/ui/{std-uncopyable-atomics.rs => sync/atomic-types-not-copyable.rs} (100%) rename tests/ui/{std-uncopyable-atomics.stderr => sync/atomic-types-not-copyable.stderr} (100%) rename tests/ui/{sse2.rs => target-feature/target-feature-detection.rs} (100%) rename tests/ui/{string-box-error.rs => traits/error-trait-object-from-string.rs} (100%) diff --git a/tests/ui/reexport-test-harness-main.rs b/tests/ui/attributes/reexport-test-harness-entry-point.rs similarity index 100% rename from tests/ui/reexport-test-harness-main.rs rename to tests/ui/attributes/reexport-test-harness-entry-point.rs diff --git a/tests/ui/stable-addr-of.rs b/tests/ui/const-ptr/pointer-address-stability.rs similarity index 100% rename from tests/ui/stable-addr-of.rs rename to tests/ui/const-ptr/pointer-address-stability.rs diff --git a/tests/ui/short-error-format.rs b/tests/ui/diagnostic-flags/error-format-short.rs similarity index 100% rename from tests/ui/short-error-format.rs rename to tests/ui/diagnostic-flags/error-format-short.rs diff --git a/tests/ui/short-error-format.stderr b/tests/ui/diagnostic-flags/error-format-short.stderr similarity index 100% rename from tests/ui/short-error-format.stderr rename to tests/ui/diagnostic-flags/error-format-short.stderr diff --git a/tests/ui/resource-assign-is-not-copy.rs b/tests/ui/drop/drop-once-on-move.rs similarity index 100% rename from tests/ui/resource-assign-is-not-copy.rs rename to tests/ui/drop/drop-once-on-move.rs diff --git a/tests/ui/resource-destruct.rs b/tests/ui/drop/drop-scope-exit.rs similarity index 100% rename from tests/ui/resource-destruct.rs rename to tests/ui/drop/drop-scope-exit.rs diff --git a/tests/ui/seq-args.rs b/tests/ui/generics/trait-incorrect-generic-args.rs similarity index 100% rename from tests/ui/seq-args.rs rename to tests/ui/generics/trait-incorrect-generic-args.rs diff --git a/tests/ui/seq-args.stderr b/tests/ui/generics/trait-incorrect-generic-args.stderr similarity index 100% rename from tests/ui/seq-args.stderr rename to tests/ui/generics/trait-incorrect-generic-args.stderr diff --git a/tests/ui/stdio-is-blocking.rs b/tests/ui/io-checks/io-stdout-blocking-writes.rs similarity index 100% rename from tests/ui/stdio-is-blocking.rs rename to tests/ui/io-checks/io-stdout-blocking-writes.rs diff --git a/tests/ui/shadow-bool.rs b/tests/ui/shadowed/primitive-type-shadowing.rs similarity index 100% rename from tests/ui/shadow-bool.rs rename to tests/ui/shadowed/primitive-type-shadowing.rs diff --git a/tests/ui/shadowed-use-visibility.rs b/tests/ui/shadowed/use-shadows-reexport.rs similarity index 100% rename from tests/ui/shadowed-use-visibility.rs rename to tests/ui/shadowed/use-shadows-reexport.rs diff --git a/tests/ui/sized-cycle-note.rs b/tests/ui/sized/recursive-type-infinite-size.rs similarity index 100% rename from tests/ui/sized-cycle-note.rs rename to tests/ui/sized/recursive-type-infinite-size.rs diff --git a/tests/ui/sized-cycle-note.stderr b/tests/ui/sized/recursive-type-infinite-size.stderr similarity index 100% rename from tests/ui/sized-cycle-note.stderr rename to tests/ui/sized/recursive-type-infinite-size.stderr diff --git a/tests/ui/sized-owned-pointer.rs b/tests/ui/sized/sized-box-unsized-content.rs similarity index 100% rename from tests/ui/sized-owned-pointer.rs rename to tests/ui/sized/sized-box-unsized-content.rs diff --git a/tests/ui/sized-borrowed-pointer.rs b/tests/ui/sized/sized-reference-to-unsized.rs similarity index 100% rename from tests/ui/sized-borrowed-pointer.rs rename to tests/ui/sized/sized-reference-to-unsized.rs diff --git a/tests/ui/std-uncopyable-atomics.rs b/tests/ui/sync/atomic-types-not-copyable.rs similarity index 100% rename from tests/ui/std-uncopyable-atomics.rs rename to tests/ui/sync/atomic-types-not-copyable.rs diff --git a/tests/ui/std-uncopyable-atomics.stderr b/tests/ui/sync/atomic-types-not-copyable.stderr similarity index 100% rename from tests/ui/std-uncopyable-atomics.stderr rename to tests/ui/sync/atomic-types-not-copyable.stderr diff --git a/tests/ui/sse2.rs b/tests/ui/target-feature/target-feature-detection.rs similarity index 100% rename from tests/ui/sse2.rs rename to tests/ui/target-feature/target-feature-detection.rs diff --git a/tests/ui/string-box-error.rs b/tests/ui/traits/error-trait-object-from-string.rs similarity index 100% rename from tests/ui/string-box-error.rs rename to tests/ui/traits/error-trait-object-from-string.rs From 5292554337171308eff06605cd825d0fcc68874c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 3 Jul 2025 22:23:15 -0700 Subject: [PATCH 08/68] Block SIMD in transmute_immediate; delete `OperandValueKind` See conversation in . --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 11 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 218 ++++++------------ tests/codegen/intrinsics/transmute-x64.rs | 11 +- .../simd-intrinsic-transmute-array.rs | 6 +- tests/codegen/transmute-scalar.rs | 14 +- tests/codegen/vec-in-place.rs | 31 +-- 6 files changed, 101 insertions(+), 190 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index da615cc9a003..2c4fca71e2a0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -346,6 +346,13 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let val = if field.is_zst() { OperandValue::ZeroSized + } else if let BackendRepr::SimdVector { .. } = self.layout.backend_repr { + // codegen_transmute_operand doesn't support SIMD, but since the previous + // check handled ZSTs, the only possible field access into something SIMD + // is to the `non_1zst_field` that's the same SIMD. (Other things, even + // just padding, would change the wrapper's representation type.) + assert_eq!(field.size, self.layout.size); + self.val } else if field.size == self.layout.size { assert_eq!(offset.bytes(), 0); fx.codegen_transmute_operand(bx, *self, field).unwrap_or_else(|| { @@ -606,10 +613,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result> { }; let mut update = |tgt: &mut Result, src, from_scalar| { - let from_bty = bx.cx().type_from_scalar(from_scalar); let to_scalar = tgt.unwrap_err(); - let to_bty = bx.cx().type_from_scalar(to_scalar); - let imm = transmute_immediate(bx, src, from_scalar, from_bty, to_scalar, to_bty); + let imm = transmute_immediate(bx, src, from_scalar, to_scalar); *tgt = Ok(imm); }; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 60cf4e28b5a0..10954c5a98b8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1,10 +1,8 @@ -use std::assert_matches::assert_matches; - use rustc_abi::{self as abi, FIRST_VARIANT}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_middle::{bug, mir, span_bug}; +use rustc_middle::{bug, mir}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; @@ -12,7 +10,7 @@ use tracing::{debug, instrument}; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; use super::{FunctionCx, LocalRef}; -use crate::common::IntPredicate; +use crate::common::{IntPredicate, TypeKind}; use crate::traits::*; use crate::{MemFlags, base}; @@ -200,31 +198,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert!(src.layout.is_sized()); assert!(dst.layout.is_sized()); - if let Some(val) = self.codegen_transmute_operand(bx, src, dst.layout) { - val.store(bx, dst); - return; - } - - match src.val { - OperandValue::Ref(..) | OperandValue::ZeroSized => { - span_bug!( - self.mir.span, - "Operand path should have handled transmute \ - from {src:?} to place {dst:?}" - ); - } - OperandValue::Immediate(..) | OperandValue::Pair(..) => { - // When we have immediate(s), the alignment of the source is irrelevant, - // so we can store them using the destination's alignment. - src.val.store(bx, dst.val.with_type(src.layout)); - } + if src.layout.size == dst.layout.size { + // Since in this path we have a place anyway, we can store or copy to it, + // making sure we use the destination place's alignment even if the + // source would normally have a higher one. + src.val.store(bx, dst.val.with_type(src.layout)); + } else if src.layout.is_uninhabited() { + bx.unreachable() + } else { + // Since this is known statically and the input could have existed + // without already having hit UB, might as well trap for it, even + // though it's UB so we *could* also unreachable it. + bx.abort(); } } /// Attempts to transmute an `OperandValue` to another `OperandValue`. /// /// Returns `None` for cases that can't work in that framework, such as for - /// `Immediate`->`Ref` that needs an `alloc` to get the location. + /// `Immediate`->`Ref` that needs an `alloca` to get the location. pub(crate) fn codegen_transmute_operand( &mut self, bx: &mut Bx, @@ -247,69 +239,34 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return Some(OperandValue::poison(bx, cast)); } - let operand_kind = self.value_kind(operand.layout); - let cast_kind = self.value_kind(cast); - - match operand.val { - OperandValue::Ref(source_place_val) => { + Some(match (operand.val, operand.layout.backend_repr, cast.backend_repr) { + _ if cast.is_zst() => OperandValue::ZeroSized, + (OperandValue::ZeroSized, _, _) => bug!(), + ( + OperandValue::Ref(source_place_val), + abi::BackendRepr::Memory { .. }, + abi::BackendRepr::Scalar(_) | abi::BackendRepr::ScalarPair(_, _), + ) => { assert_eq!(source_place_val.llextra, None); - assert_matches!(operand_kind, OperandValueKind::Ref); // The existing alignment is part of `source_place_val`, // so that alignment will be used, not `cast`'s. - Some(bx.load_operand(source_place_val.with_type(cast)).val) + bx.load_operand(source_place_val.with_type(cast)).val } - OperandValue::ZeroSized => { - let OperandValueKind::ZeroSized = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); - }; - if let OperandValueKind::ZeroSized = cast_kind { - Some(OperandValue::ZeroSized) - } else { - None - } - } - OperandValue::Immediate(imm) => { - let OperandValueKind::Immediate(from_scalar) = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); - }; - if let OperandValueKind::Immediate(to_scalar) = cast_kind - && from_scalar.size(self.cx) == to_scalar.size(self.cx) - { - let from_backend_ty = bx.backend_type(operand.layout); - let to_backend_ty = bx.backend_type(cast); - Some(OperandValue::Immediate(transmute_immediate( - bx, - imm, - from_scalar, - from_backend_ty, - to_scalar, - to_backend_ty, - ))) - } else { - None - } - } - OperandValue::Pair(imm_a, imm_b) => { - let OperandValueKind::Pair(in_a, in_b) = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); - }; - if let OperandValueKind::Pair(out_a, out_b) = cast_kind - && in_a.size(self.cx) == out_a.size(self.cx) - && in_b.size(self.cx) == out_b.size(self.cx) - { - let in_a_ibty = bx.scalar_pair_element_backend_type(operand.layout, 0, false); - let in_b_ibty = bx.scalar_pair_element_backend_type(operand.layout, 1, false); - let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false); - let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false); - Some(OperandValue::Pair( - transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty), - transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty), - )) - } else { - None - } - } - } + ( + OperandValue::Immediate(imm), + abi::BackendRepr::Scalar(from_scalar), + abi::BackendRepr::Scalar(to_scalar), + ) => OperandValue::Immediate(transmute_immediate(bx, imm, from_scalar, to_scalar)), + ( + OperandValue::Pair(imm_a, imm_b), + abi::BackendRepr::ScalarPair(in_a, in_b), + abi::BackendRepr::ScalarPair(out_a, out_b), + ) => OperandValue::Pair( + transmute_immediate(bx, imm_a, in_a, out_a), + transmute_immediate(bx, imm_b, in_b, out_b), + ), + _ => return None, + }) } /// Cast one of the immediates from an [`OperandValue::Immediate`] @@ -479,9 +436,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // path as the other integer-to-X casts. | mir::CastKind::PointerWithExposedProvenance => { let imm = operand.immediate(); - let operand_kind = self.value_kind(operand.layout); - let OperandValueKind::Immediate(from_scalar) = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); + let abi::BackendRepr::Scalar(from_scalar) = operand.layout.backend_repr else { + bug!("Found non-scalar for operand {operand:?}"); }; let from_backend_ty = bx.cx().immediate_backend_type(operand.layout); @@ -491,9 +447,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty)); return OperandRef { val, layout: cast }; } - let cast_kind = self.value_kind(cast); - let OperandValueKind::Immediate(to_scalar) = cast_kind else { - bug!("Found {cast_kind:?} for operand {cast:?}"); + let abi::BackendRepr::Scalar(to_scalar) = cast.layout.backend_repr else { + bug!("Found non-scalar for cast {cast:?}"); }; self.cast_immediate(bx, imm, from_scalar, from_backend_ty, to_scalar, to_backend_ty) @@ -993,31 +948,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let operand_ty = operand.ty(self.mir, self.cx.tcx()); let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty)); let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty)); - - match (self.value_kind(operand_layout), self.value_kind(cast_layout)) { - // Can always load from a pointer as needed - (OperandValueKind::Ref, _) => true, - - // ZST-to-ZST is the easiest thing ever - (OperandValueKind::ZeroSized, OperandValueKind::ZeroSized) => true, - - // But if only one of them is a ZST the sizes can't match - (OperandValueKind::ZeroSized, _) | (_, OperandValueKind::ZeroSized) => false, - - // Need to generate an `alloc` to get a pointer from an immediate - (OperandValueKind::Immediate(..) | OperandValueKind::Pair(..), OperandValueKind::Ref) => false, + match (operand_layout.backend_repr, cast_layout.backend_repr) { + // If the input is in a place we can load immediates from there. + (abi::BackendRepr::Memory { .. }, abi::BackendRepr::Scalar(_) | abi::BackendRepr::ScalarPair(_, _)) => true, // When we have scalar immediates, we can only convert things // where the sizes match, to avoid endianness questions. - (OperandValueKind::Immediate(a), OperandValueKind::Immediate(b)) => + (abi::BackendRepr::Scalar(a), abi::BackendRepr::Scalar(b)) => a.size(self.cx) == b.size(self.cx), - (OperandValueKind::Pair(a0, a1), OperandValueKind::Pair(b0, b1)) => + (abi::BackendRepr::ScalarPair(a0, a1), abi::BackendRepr::ScalarPair(b0, b1)) => a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx), - // Send mixings between scalars and pairs through the memory route - // FIXME: Maybe this could use insertvalue/extractvalue instead? - (OperandValueKind::Immediate(..), OperandValueKind::Pair(..)) | - (OperandValueKind::Pair(..), OperandValueKind::Immediate(..)) => false, + // SIMD vectors don't work like normal immediates, + // so always send them through memory. + (abi::BackendRepr::SimdVector { .. }, _) | (_, abi::BackendRepr::SimdVector { .. }) => false, + + // When the output will be in memory anyway, just use its place + // (instead of the operand path) unless it's the trivial ZST case. + (_, abi::BackendRepr::Memory { .. }) => cast_layout.is_zst(), + + // Mixing Scalars and ScalarPairs can get quite complicated when + // padding and undef get involved, so leave that to the memory path. + (abi::BackendRepr::Scalar(_), abi::BackendRepr::ScalarPair(_, _)) | + (abi::BackendRepr::ScalarPair(_, _), abi::BackendRepr::Scalar(_)) => false, } } mir::Rvalue::Ref(..) | @@ -1062,41 +1015,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // (*) this is only true if the type is suitable } - - /// Gets which variant of [`OperandValue`] is expected for a particular type. - fn value_kind(&self, layout: TyAndLayout<'tcx>) -> OperandValueKind { - if layout.is_zst() { - OperandValueKind::ZeroSized - } else if self.cx.is_backend_immediate(layout) { - assert!(!self.cx.is_backend_scalar_pair(layout)); - OperandValueKind::Immediate(match layout.backend_repr { - abi::BackendRepr::Scalar(s) => s, - abi::BackendRepr::SimdVector { element, .. } => element, - x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), - }) - } else if self.cx.is_backend_scalar_pair(layout) { - let abi::BackendRepr::ScalarPair(s1, s2) = layout.backend_repr else { - span_bug!( - self.mir.span, - "Couldn't translate {:?} as backend scalar pair", - layout.backend_repr, - ); - }; - OperandValueKind::Pair(s1, s2) - } else { - OperandValueKind::Ref - } - } -} - -/// The variants of this match [`OperandValue`], giving details about the -/// backend values that will be held in that other type. -#[derive(Debug, Copy, Clone)] -enum OperandValueKind { - Ref, - Immediate(abi::Scalar), - Pair(abi::Scalar, abi::Scalar), - ZeroSized, } /// Transmutes one of the immediates from an [`OperandValue::Immediate`] @@ -1108,22 +1026,30 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, mut imm: Bx::Value, from_scalar: abi::Scalar, - from_backend_ty: Bx::Type, to_scalar: abi::Scalar, - to_backend_ty: Bx::Type, ) -> Bx::Value { assert_eq!(from_scalar.size(bx.cx()), to_scalar.size(bx.cx())); + let imm_ty = bx.cx().val_ty(imm); + assert_ne!( + bx.cx().type_kind(imm_ty), + TypeKind::Vector, + "Vector type {imm_ty:?} not allowed in transmute_immediate {from_scalar:?} -> {to_scalar:?}" + ); // While optimizations will remove no-op transmutes, they might still be // there in debug or things that aren't no-op in MIR because they change // the Rust type but not the underlying layout/niche. - if from_scalar == to_scalar && from_backend_ty == to_backend_ty { + if from_scalar == to_scalar { return imm; } use abi::Primitive::*; imm = bx.from_immediate(imm); + let from_backend_ty = bx.cx().type_from_scalar(from_scalar); + debug_assert_eq!(bx.cx().val_ty(imm), from_backend_ty); + let to_backend_ty = bx.cx().type_from_scalar(to_scalar); + // If we have a scalar, we must already know its range. Either // // 1) It's a parameter with `range` parameter metadata, @@ -1154,6 +1080,8 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } }; + debug_assert_eq!(bx.cx().val_ty(imm), to_backend_ty); + // This `assume` remains important for cases like (a conceptual) // transmute::(x) == 0 // since it's never passed to something with parameter metadata (especially diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs index be45e4db90fd..8c9480ab0915 100644 --- a/tests/codegen/intrinsics/transmute-x64.rs +++ b/tests/codegen/intrinsics/transmute-x64.rs @@ -9,17 +9,20 @@ use std::mem::transmute; // CHECK-LABEL: @check_sse_pair_to_avx( #[no_mangle] pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i { + // CHECK: start: // CHECK-NOT: alloca - // CHECK: %0 = load <4 x i64>, ptr %x, align 16 - // CHECK: store <4 x i64> %0, ptr %_0, align 32 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 32 %_0, ptr align 16 %x, i64 32, i1 false) + // CHECK-NEXT: ret void transmute(x) } // CHECK-LABEL: @check_sse_pair_from_avx( #[no_mangle] pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) { + // CHECK: start: // CHECK-NOT: alloca - // CHECK: %0 = load <4 x i64>, ptr %x, align 32 - // CHECK: store <4 x i64> %0, ptr %_0, align 16 + // CHECK-NEXT: %[[TEMP:.+]] = load <4 x i64>, ptr %x, align 32 + // CHECK-NEXT: store <4 x i64> %[[TEMP]], ptr %_0, align 16 + // CHECK-NEXT: ret void transmute(x) } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index 977bf3379b7d..301f06c2d74a 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -40,8 +40,7 @@ pub fn build_array_s(x: [f32; 4]) -> S<4> { // CHECK-LABEL: @build_array_transmute_s #[no_mangle] pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { - // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) unsafe { std::mem::transmute(x) } } @@ -55,7 +54,6 @@ pub fn build_array_t(x: [f32; 4]) -> T { // CHECK-LABEL: @build_array_transmute_t #[no_mangle] pub fn build_array_transmute_t(x: [f32; 4]) -> T { - // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) unsafe { std::mem::transmute(x) } } diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index 3ac6ba3beb1e..ce1b0558b2ee 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -111,8 +111,11 @@ pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool { struct S([i64; 1]); // CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b) -// CHECK: bitcast <1 x i64> %b to i64 -// CHECK: ret i64 +// CHECK-NEXT: start: +// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] +// CHECK-NEXT: store <1 x i64> %b, ptr %[[RET]] +// CHECK-NEXT: %[[TEMP:.+]] = load i64, ptr %[[RET]] +// CHECK-NEXT: ret i64 %[[TEMP]] #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] @@ -124,8 +127,11 @@ pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 { } // CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b) -// CHECK: bitcast i64 %b to <1 x i64> -// CHECK: ret <1 x i64> +// CHECK-NEXT: start: +// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] +// CHECK-NEXT: store i64 %b, ptr %[[RET]] +// CHECK-NEXT: %[[TEMP:.+]] = load <1 x i64>, ptr %[[RET]] +// CHECK-NEXT: ret <1 x i64> %[[TEMP]] #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs index 1f6836f6dfab..a5ef8653b997 100644 --- a/tests/codegen/vec-in-place.rs +++ b/tests/codegen/vec-in-place.rs @@ -41,9 +41,6 @@ pub fn vec_iterator_cast_primitive(vec: Vec) -> Vec { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call vec.into_iter().map(|e| e as u8).collect() } @@ -55,9 +52,6 @@ pub fn vec_iterator_cast_wrapper(vec: Vec) -> Vec> { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call vec.into_iter().map(|e| Wrapper(e)).collect() } @@ -86,9 +80,6 @@ pub fn vec_iterator_cast_unwrap(vec: Vec>) -> Vec { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call vec.into_iter().map(|e| e.0).collect() } @@ -100,9 +91,6 @@ pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() } @@ -114,9 +102,6 @@ pub fn vec_iterator_cast_deaggregate_tra(vec: Vec) -> Vec<[u64; 4]> { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. // This currently is not guaranteed for repr(Rust) types, but it happens to work here and @@ -133,9 +118,6 @@ pub fn vec_iterator_cast_deaggregate_fold(vec: Vec) -> Vec<[u64; 4]> { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. // This currently is not guaranteed for repr(Rust) types, but it happens to work here and @@ -156,12 +138,7 @@ pub fn vec_iterator_cast_unwrap_drop(vec: Vec>) -> Vec { // CHECK-NOT: call // CHECK-NOT: %{{.*}} = mul // CHECK-NOT: %{{.*}} = udiv - // CHECK: call - // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} - // CHECK-NOT: call - // CHECK-NOT: %{{.*}} = mul - // CHECK-NOT: %{{.*}} = udiv + // CHECK: ret void vec.into_iter().map(|Wrapper(e)| e).collect() } @@ -178,12 +155,6 @@ pub fn vec_iterator_cast_wrap_drop(vec: Vec) -> Vec> { // CHECK-NOT: call // CHECK-NOT: %{{.*}} = mul // CHECK-NOT: %{{.*}} = udiv - // CHECK: call - // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} - // CHECK-NOT: call - // CHECK-NOT: %{{.*}} = mul - // CHECK-NOT: %{{.*}} = udiv // CHECK: ret void vec.into_iter().map(Wrapper).collect() From 32115c3a1710d1ac98b2ffea23014e0d2ee19c0d Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 28 Jun 2025 10:32:08 +0800 Subject: [PATCH 09/68] Add a regression test for ld64 --- tests/ui/darwin-ld64.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/ui/darwin-ld64.rs diff --git a/tests/ui/darwin-ld64.rs b/tests/ui/darwin-ld64.rs new file mode 100644 index 000000000000..75acc07a002c --- /dev/null +++ b/tests/ui/darwin-ld64.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Copt-level=3 -Ccodegen-units=256 -Clink-arg=-ld_classic +//@ run-pass +//@ only-x86_64-apple-darwin + +// This is a regression test for https://github.com/rust-lang/rust/issues/140686. +// Although this is a ld64(ld-classic) bug, we still need to support it +// due to cross-compilation and support for older Xcode. + +fn main() { + let dst: Vec = Vec::new(); + let len = broken_func(std::hint::black_box(2), dst); + assert_eq!(len, 8); +} + +#[inline(never)] +pub fn broken_func(version: usize, mut dst: Vec) -> usize { + match version { + 1 => dst.extend_from_slice(b"aaaaaaaa"), + 2 => dst.extend_from_slice(b"bbbbbbbb"), + 3 => dst.extend_from_slice(b"bbbbbbbb"), + _ => panic!(), + } + dst.len() +} From 1339b905505917725c3f1cd1bb52d7ff4f5eea9a Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 4 Jul 2025 23:05:40 +0800 Subject: [PATCH 10/68] Update LLVM submodule --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index ed6566573eb2..9b1bf4cf041c 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit ed6566573eb21b00a3f87815e14ff766fd56ef42 +Subproject commit 9b1bf4cf041c1c1fe62cf03891ac90431615e780 From a3277a1bbb82423416a716b13c483a13e00aef59 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 3 Jul 2025 20:39:32 +0200 Subject: [PATCH 11/68] test rust calling a C C-variadic function --- .../c-link-to-rust-va-list-fn/checkrust.rs | 62 +++++++++++++++---- .../run-make/c-link-to-rust-va-list-fn/test.c | 53 ++++++++++++++++ 2 files changed, 104 insertions(+), 11 deletions(-) diff --git a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs index 36c9db106ec4..63d8d713d622 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs @@ -1,7 +1,8 @@ #![crate_type = "staticlib"] #![feature(c_variadic)] +#![feature(cfg_select)] -use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong}; +use std::ffi::{CStr, CString, VaList, VaListImpl, c_char, c_double, c_int, c_long, c_longlong}; macro_rules! continue_if { ($cond:expr) => { @@ -19,7 +20,7 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize { continue_if!(ap.arg::() == 1); continue_if!(ap.arg::() == 2); @@ -27,7 +28,7 @@ pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize { continue_if!(ap.arg::() == -1); continue_if!(ap.arg::() == 'A' as c_int); @@ -39,7 +40,7 @@ pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize { continue_if!(ap.arg::().floor() == 3.14f64.floor()); continue_if!(ap.arg::() == 12); @@ -51,7 +52,7 @@ pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { continue_if!(ap.arg::().floor() == 6.28f64.floor()); continue_if!(ap.arg::() == 16); @@ -64,14 +65,14 @@ pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { ) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 42); continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello, World!")); 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::().floor() == 3.14f64.floor()); continue_if!(ap.arg::() == 12); @@ -80,12 +81,12 @@ pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 1); continue_if!(ap.arg::() == 2); @@ -100,7 +101,7 @@ pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize { continue_if!(ap.arg::() == 1.0); continue_if!(ap.arg::() == 2.0); @@ -118,7 +119,7 @@ pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 1.0); continue_if!(ap.arg::() == 1); @@ -148,3 +149,42 @@ pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 13.0); 0 } + +unsafe extern "C" { + fn test_variadic(_: c_int, ...) -> usize; + fn test_va_list_by_value(_: VaList) -> usize; + fn test_va_list_by_pointer(_: *mut VaListImpl) -> usize; + fn test_va_list_by_pointer_pointer(_: *mut *mut VaListImpl) -> usize; +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_variadic() -> usize { + return unsafe { test_variadic(0, 1 as c_longlong, 2 as c_int, 3 as c_longlong) }; +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_va_list_by_value() -> usize { + unsafe extern "C" fn helper(mut ap: ...) -> usize { + unsafe { test_va_list_by_value(ap.as_va_list()) } + } + + unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_va_list_by_pointer() -> usize { + unsafe extern "C" fn helper(mut ap: ...) -> usize { + unsafe { test_va_list_by_pointer(&mut ap) } + } + + unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_va_list_by_pointer_pointer() -> usize { + unsafe extern "C" fn helper(mut ap: ...) -> usize { + unsafe { test_va_list_by_pointer_pointer(&mut (&mut ap as *mut _)) } + } + + unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } +} diff --git a/tests/run-make/c-link-to-rust-va-list-fn/test.c b/tests/run-make/c-link-to-rust-va-list-fn/test.c index b47a9357880f..2bb93c0b5d0e 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/test.c +++ b/tests/run-make/c-link-to-rust-va-list-fn/test.c @@ -15,6 +15,11 @@ extern size_t check_varargs_3(int fixed, ...); extern size_t check_varargs_4(double fixed, ...); extern size_t check_varargs_5(int fixed, ...); +extern size_t run_test_variadic(); +extern size_t run_test_va_list_by_value(); +extern size_t run_test_va_list_by_pointer(); +extern size_t run_test_va_list_by_pointer_pointer(); + int test_rust(size_t (*fn)(va_list), ...) { size_t ret = 0; va_list ap; @@ -47,5 +52,53 @@ int main(int argc, char* argv[]) { assert(check_varargs_5(0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4, 5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0, 9, 9.0, 10, 10.0, 11, 11.0, 12, 12.0, 13, 13.0) == 0); + assert(run_test_variadic() == 0); + assert(run_test_va_list_by_value() == 0); + assert(run_test_va_list_by_pointer() == 0); + assert(run_test_va_list_by_pointer_pointer() == 0); + + return 0; +} + +#define continue_if_else_end(cond) \ + do { if (!(cond)) { va_end(ap); return 0xff; } } while (0) + +size_t test_variadic(int unused, ...) { + va_list ap; + va_start(ap, unused); + + continue_if_else_end(va_arg(ap, long long) == 1); + continue_if_else_end(va_arg(ap, int) == 2); + continue_if_else_end(va_arg(ap, long long) == 3); + + va_end(ap); + + return 0; +} + +#define continue_if(cond) \ + do { if (!(cond)) { return 0xff; } } while (0) + +size_t test_va_list_by_value(va_list ap) { + continue_if(va_arg(ap, long long) == 1); + continue_if(va_arg(ap, int) == 2); + continue_if(va_arg(ap, long long) == 3); + + return 0; +} + +size_t test_va_list_by_pointer(va_list *ap) { + continue_if(va_arg(*ap, long long) == 1); + continue_if(va_arg(*ap, int) == 2); + continue_if(va_arg(*ap, long long) == 3); + + return 0; +} + +size_t test_va_list_by_pointer_pointer(va_list **ap) { + continue_if(va_arg(**ap, long long) == 1); + continue_if(va_arg(**ap, int) == 2); + continue_if(va_arg(**ap, long long) == 3); + return 0; } From e0c54c3a9bc92b480570d26251c98ce497109988 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 4 Jul 2025 10:35:51 -0700 Subject: [PATCH 12/68] =?UTF-8?q?Rename=20`transmute=5Fimmediate`=20?= =?UTF-8?q?=E2=86=92=20`transmute=5Fscalar`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 20 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 2c4fca71e2a0..4b1c689a0106 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -13,7 +13,7 @@ use rustc_session::config::OptLevel; use tracing::{debug, instrument}; use super::place::{PlaceRef, PlaceValue}; -use super::rvalue::transmute_immediate; +use super::rvalue::transmute_scalar; use super::{FunctionCx, LocalRef}; use crate::common::IntPredicate; use crate::traits::*; @@ -614,7 +614,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result> { let mut update = |tgt: &mut Result, src, from_scalar| { let to_scalar = tgt.unwrap_err(); - let imm = transmute_immediate(bx, src, from_scalar, to_scalar); + let imm = transmute_scalar(bx, src, from_scalar, to_scalar); *tgt = Ok(imm); }; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 10954c5a98b8..589405e885fb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -256,14 +256,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Immediate(imm), abi::BackendRepr::Scalar(from_scalar), abi::BackendRepr::Scalar(to_scalar), - ) => OperandValue::Immediate(transmute_immediate(bx, imm, from_scalar, to_scalar)), + ) => OperandValue::Immediate(transmute_scalar(bx, imm, from_scalar, to_scalar)), ( OperandValue::Pair(imm_a, imm_b), abi::BackendRepr::ScalarPair(in_a, in_b), abi::BackendRepr::ScalarPair(out_a, out_b), ) => OperandValue::Pair( - transmute_immediate(bx, imm_a, in_a, out_a), - transmute_immediate(bx, imm_b, in_b, out_b), + transmute_scalar(bx, imm_a, in_a, out_a), + transmute_scalar(bx, imm_b, in_b, out_b), ), _ => return None, }) @@ -1017,12 +1017,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } -/// Transmutes one of the immediates from an [`OperandValue::Immediate`] -/// or an [`OperandValue::Pair`] to an immediate of the target type. +/// Transmutes a single scalar value `imm` from `from_scalar` to `to_scalar`. /// -/// `to_backend_ty` must be the *non*-immediate backend type (so it will be -/// `i8`, not `i1`, for `bool`-like types.) -pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +/// This is expected to be in *immediate* form, as seen in [`OperandValue::Immediate`] +/// or [`OperandValue::Pair`] (so `i1` for bools, not `i8`, for example). +/// +/// ICEs if the passed-in `imm` is not a value of the expected type for +/// `from_scalar`, such as if it's a vector or a pair. +pub(super) fn transmute_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, mut imm: Bx::Value, from_scalar: abi::Scalar, @@ -1033,7 +1035,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( assert_ne!( bx.cx().type_kind(imm_ty), TypeKind::Vector, - "Vector type {imm_ty:?} not allowed in transmute_immediate {from_scalar:?} -> {to_scalar:?}" + "Vector type {imm_ty:?} not allowed in transmute_scalar {from_scalar:?} -> {to_scalar:?}" ); // While optimizations will remove no-op transmutes, they might still be From 42c9bfd2b96f2e6cd0e4e6fab21c2d5499883089 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 11 Apr 2025 04:17:19 +0000 Subject: [PATCH 13/68] Remove Symbol for Named LateParam/Bound variants --- .../src/diagnostics/conflict_errors.rs | 4 +- .../src/diagnostics/region_errors.rs | 3 +- .../src/diagnostics/region_name.rs | 10 +- compiler/rustc_borrowck/src/nll.rs | 4 +- compiler/rustc_borrowck/src/polonius/dump.rs | 17 +-- .../src/region_infer/graphviz.rs | 34 ++++-- compiler/rustc_borrowck/src/type_check/mod.rs | 5 +- .../src/type_check/relate_tys.rs | 8 +- .../rustc_borrowck/src/universal_regions.rs | 6 +- .../src/check/compare_impl_item.rs | 6 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 6 +- .../src/collect/resolve_bound_vars.rs | 4 +- .../src/hir_ty_lowering/bounds.rs | 15 +-- .../src/hir_ty_lowering/mod.rs | 20 ++-- .../rustc_lint/src/impl_trait_overcaptures.rs | 27 ++--- compiler/rustc_middle/src/ty/context.rs | 5 +- compiler/rustc_middle/src/ty/print/pretty.rs | 83 ++++--------- compiler/rustc_middle/src/ty/region.rs | 112 +++++++++--------- .../rustc_middle/src/ty/structural_impls.rs | 22 ++-- compiler/rustc_middle/src/ty/sty.rs | 2 +- .../stable_mir/unstable/convert/internal.rs | 7 +- .../stable_mir/unstable/convert/stable/ty.rs | 12 +- .../nice_region_error/named_anon_conflict.rs | 20 ++-- .../nice_region_error/placeholder_error.rs | 4 +- .../nice_region_error/placeholder_relation.rs | 21 ++-- .../nice_region_error/static_impl_trait.rs | 5 +- .../trait_impl_difference.rs | 11 +- .../infer/nice_region_error/util.rs | 4 +- .../src/error_reporting/infer/region.rs | 34 +++--- .../src/errors/note_and_explain.rs | 5 +- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 83 ++++++------- src/librustdoc/clean/utils.rs | 6 +- .../occurs-check/associated-type.next.stderr | 4 +- .../occurs-check/associated-type.old.stderr | 4 +- .../structually-relate-aliases.stderr | 2 +- .../ty-outlives/impl-trait-captures.stderr | 8 +- .../issue-118950-root-region.stderr | 2 +- .../higher-ranked-fn-type.verbose.stderr | 4 +- 40 files changed, 304 insertions(+), 329 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index d1dac1c7145d..3ec33e5e5c88 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4194,7 +4194,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // anything. let return_ty = sig.output(); match return_ty.skip_binder().kind() { - ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { + ty::Ref(return_region, _, _) + if return_region.has_name(self.infcx.tcx) && !is_closure => + { // This is case 1 from above, return type is a named reference so we need to // search for relevant arguments. let mut arguments = Vec::new(); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index a611557dc924..d14f2417ea7c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -852,7 +852,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { return; }; - let lifetime = if f.has_name() { fr_name.name } else { kw::UnderscoreLifetime }; + let lifetime = + if f.has_name(self.infcx.tcx) { fr_name.name } else { kw::UnderscoreLifetime }; let arg = match param.param.pat.simple_ident() { Some(simple_ident) => format!("argument `{simple_ident}`"), diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 1ad629ad167d..439e4c7328a8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -300,16 +300,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } ty::ReLateParam(late_param) => match late_param.kind { - ty::LateParamRegionKind::Named(region_def_id, name) => { + ty::LateParamRegionKind::Named(region_def_id) => { // Get the span to point to, even if we don't use the name. let span = tcx.hir_span_if_local(region_def_id).unwrap_or(DUMMY_SP); - debug!( - "bound region named: {:?}, is_named: {:?}", - name, - late_param.kind.is_named() - ); - if late_param.kind.is_named() { + if let Some(name) = late_param.kind.get_name(tcx) { // A named region that is actually named. Some(RegionName { name, @@ -369,6 +364,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } ty::LateParamRegionKind::Anon(_) => None, + ty::LateParamRegionKind::NamedAnon(_, _) => bug!("only used for pretty printing"), }, ty::ReBound(..) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 1b011d733854..af4505072960 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -232,13 +232,13 @@ pub(super) fn dump_nll_mir<'tcx>( // Also dump the region constraint graph as a graphviz file. let _: io::Result<()> = try { let mut file = create_dump_file(tcx, "regioncx.all.dot", false, "nll", &0, body)?; - regioncx.dump_graphviz_raw_constraints(&mut file)?; + regioncx.dump_graphviz_raw_constraints(tcx, &mut file)?; }; // Also dump the region constraint SCC graph as a graphviz file. let _: io::Result<()> = try { let mut file = create_dump_file(tcx, "regioncx.scc.dot", false, "nll", &0, body)?; - regioncx.dump_graphviz_scc_constraints(&mut file)?; + regioncx.dump_graphviz_scc_constraints(tcx, &mut file)?; }; } diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index 6a943e192082..6b13b5ad0814 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -116,7 +116,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "
")?; writeln!(out, "NLL regions")?; writeln!(out, "
")?;
-    emit_mermaid_nll_regions(regioncx, out)?;
+    emit_mermaid_nll_regions(tcx, regioncx, out)?;
     writeln!(out, "
")?; writeln!(out, "
")?; @@ -124,7 +124,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "
")?; writeln!(out, "NLL SCCs")?; writeln!(out, "
")?;
-    emit_mermaid_nll_sccs(regioncx, out)?;
+    emit_mermaid_nll_sccs(tcx, regioncx, out)?;
     writeln!(out, "
")?; writeln!(out, "
")?; @@ -306,9 +306,10 @@ fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()> } /// Emits a region's label: index, universe, external name. -fn render_region( +fn render_region<'tcx>( + tcx: TyCtxt<'tcx>, region: RegionVid, - regioncx: &RegionInferenceContext<'_>, + regioncx: &RegionInferenceContext<'tcx>, out: &mut dyn io::Write, ) -> io::Result<()> { let def = regioncx.region_definition(region); @@ -318,7 +319,7 @@ fn render_region( if !universe.is_root() { write!(out, "/{universe:?}")?; } - if let Some(name) = def.external_name.and_then(|e| e.get_name()) { + if let Some(name) = def.external_name.and_then(|e| e.get_name(tcx)) { write!(out, " ({name})")?; } Ok(()) @@ -327,6 +328,7 @@ fn render_region( /// Emits a mermaid flowchart of the NLL regions and the outlives constraints between them, similar /// to the graphviz version. fn emit_mermaid_nll_regions<'tcx>( + tcx: TyCtxt<'tcx>, regioncx: &RegionInferenceContext<'tcx>, out: &mut dyn io::Write, ) -> io::Result<()> { @@ -336,7 +338,7 @@ fn emit_mermaid_nll_regions<'tcx>( // Emit the region nodes. for region in regioncx.definitions.indices() { write!(out, "{}[\"", region.as_usize())?; - render_region(region, regioncx, out)?; + render_region(tcx, region, regioncx, out)?; writeln!(out, "\"]")?; } @@ -378,6 +380,7 @@ fn emit_mermaid_nll_regions<'tcx>( /// Emits a mermaid flowchart of the NLL SCCs and the outlives constraints between them, similar /// to the graphviz version. fn emit_mermaid_nll_sccs<'tcx>( + tcx: TyCtxt<'tcx>, regioncx: &RegionInferenceContext<'tcx>, out: &mut dyn io::Write, ) -> io::Result<()> { @@ -395,7 +398,7 @@ fn emit_mermaid_nll_sccs<'tcx>( // The node label: the regions contained in the SCC. write!(out, "{scc}[\"SCC({scc}) = {{", scc = scc.as_usize())?; for (idx, ®ion) in regions.iter().enumerate() { - render_region(region, regioncx, out)?; + render_region(tcx, region, regioncx, out)?; if idx < regions.len() - 1 { write!(out, ",")?; } diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index 1936752b63c6..a3e29982e90f 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -26,11 +26,15 @@ fn render_universe(u: UniverseIndex) -> String { format!("/{:?}", u) } -fn render_region_vid(rvid: RegionVid, regioncx: &RegionInferenceContext<'_>) -> String { +fn render_region_vid<'tcx>( + tcx: TyCtxt<'tcx>, + rvid: RegionVid, + regioncx: &RegionInferenceContext<'tcx>, +) -> String { let universe_str = render_universe(regioncx.region_definition(rvid).universe); let external_name_str = if let Some(external_name) = - regioncx.region_definition(rvid).external_name.and_then(|e| e.get_name()) + regioncx.region_definition(rvid).external_name.and_then(|e| e.get_name(tcx)) { format!(" ({external_name})") } else { @@ -42,12 +46,20 @@ fn render_region_vid(rvid: RegionVid, regioncx: &RegionInferenceContext<'_>) -> impl<'tcx> RegionInferenceContext<'tcx> { /// Write out the region constraint graph. - pub(crate) fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { - dot::render(&RawConstraints { regioncx: self }, &mut w) + pub(crate) fn dump_graphviz_raw_constraints( + &self, + tcx: TyCtxt<'tcx>, + mut w: &mut dyn Write, + ) -> io::Result<()> { + dot::render(&RawConstraints { tcx, regioncx: self }, &mut w) } /// Write out the region constraint SCC graph. - pub(crate) fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { + pub(crate) fn dump_graphviz_scc_constraints( + &self, + tcx: TyCtxt<'tcx>, + mut w: &mut dyn Write, + ) -> io::Result<()> { let mut nodes_per_scc: IndexVec = self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect(); @@ -56,11 +68,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { nodes_per_scc[scc].push(region); } - dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w) + dot::render(&SccConstraints { tcx, regioncx: self, nodes_per_scc }, &mut w) } } struct RawConstraints<'a, 'tcx> { + tcx: TyCtxt<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>, } @@ -78,7 +91,7 @@ impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) } fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> { - dot::LabelText::LabelStr(render_region_vid(*n, self.regioncx).into()) + dot::LabelText::LabelStr(render_region_vid(self.tcx, *n, self.regioncx).into()) } fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> { dot::LabelText::LabelStr(render_outlives_constraint(e).into()) @@ -110,6 +123,7 @@ impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { } struct SccConstraints<'a, 'tcx> { + tcx: TyCtxt<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>, nodes_per_scc: IndexVec>, } @@ -128,8 +142,10 @@ impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> { Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) } fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> { - let nodes_str = - self.nodes_per_scc[*n].iter().map(|n| render_region_vid(*n, self.regioncx)).join(", "); + let nodes_str = self.nodes_per_scc[*n] + .iter() + .map(|n| render_region_vid(self.tcx, *n, self.regioncx)) + .join(", "); dot::LabelText::LabelStr(format!("SCC({n}) = {{{nodes_str}}}", n = n.as_usize()).into()) } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 05bcd9f862ef..f877e5eaadb9 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -786,8 +786,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let region_ctxt_fn = || { let reg_info = match br.kind { ty::BoundRegionKind::Anon => sym::anon, - ty::BoundRegionKind::Named(_, name) => name, + ty::BoundRegionKind::Named(def_id) => tcx.item_name(def_id), ty::BoundRegionKind::ClosureEnv => sym::env, + ty::BoundRegionKind::NamedAnon(_) => { + bug!("only used for pretty printing") + } }; RegionCtxt::LateBound(reg_info) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 02a41469c97f..e023300f1c28 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -7,11 +7,11 @@ use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_infer::traits::Obligation; use rustc_infer::traits::solve::Goal; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys}; use rustc_middle::ty::{self, FnMutDelegate, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -215,7 +215,8 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { if let Some(ex_reg_var) = reg_map.get(&br) { *ex_reg_var } else { - let ex_reg_var = self.next_existential_region_var(true, br.kind.get_name()); + let ex_reg_var = + self.next_existential_region_var(true, br.kind.get_name(infcx.infcx.tcx)); debug!(?ex_reg_var); reg_map.insert(br, ex_reg_var); @@ -263,8 +264,9 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { let reg_info = match placeholder.bound.kind { ty::BoundRegionKind::Anon => sym::anon, - ty::BoundRegionKind::Named(_, name) => name, + ty::BoundRegionKind::Named(def_id) => self.type_checker.tcx().item_name(def_id), ty::BoundRegionKind::ClosureEnv => sym::env, + ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"), }; if cfg!(debug_assertions) { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 846299711be3..f138f2653203 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -497,7 +497,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { |r| { debug!(?r); let region_vid = { - let name = r.get_name_or_anon(); + let name = r.get_name_or_anon(self.infcx.tcx); self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) }; @@ -523,7 +523,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind); let r = ty::Region::new_late_param(self.infcx.tcx, self.mir_def.to_def_id(), kind); let region_vid = { - let name = r.get_name_or_anon(); + let name = r.get_name_or_anon(self.infcx.tcx); self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) }; @@ -861,7 +861,7 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { T: TypeFoldable>, { fold_regions(self.infcx.tcx, value, |region, _depth| { - let name = region.get_name_or_anon(); + let name = region.get_name_or_anon(self.infcx.tcx); debug!(?region, ?name); self.next_nll_region_var(origin, || RegionCtxt::Free(name)) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index abbe497858bb..674f8e0eeafa 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1239,7 +1239,7 @@ fn check_region_late_boundedness<'tcx>( .unwrap_region_constraints() .opportunistic_resolve_var(tcx, vid) && let ty::ReLateParam(ty::LateParamRegion { - kind: ty::LateParamRegionKind::Named(trait_param_def_id, _), + kind: ty::LateParamRegionKind::Named(trait_param_def_id), .. }) = r.kind() && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind() @@ -1264,7 +1264,7 @@ fn check_region_late_boundedness<'tcx>( .unwrap_region_constraints() .opportunistic_resolve_var(tcx, vid) && let ty::ReLateParam(ty::LateParamRegion { - kind: ty::LateParamRegionKind::Named(impl_param_def_id, _), + kind: ty::LateParamRegionKind::Named(impl_param_def_id), .. }) = r.kind() && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind() @@ -2479,7 +2479,7 @@ fn param_env_with_gat_bounds<'tcx>( .into() } GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::Named(param.def_id, param.name); + let kind = ty::BoundRegionKind::Named(param.def_id); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); ty::Region::new_bound( diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4934136bc7af..089ba14bcf71 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2338,7 +2338,7 @@ fn lint_redundant_lifetimes<'tcx>( lifetimes.push(ty::Region::new_late_param(tcx, owner_id.to_def_id(), kind)); } } - lifetimes.retain(|candidate| candidate.has_name()); + lifetimes.retain(|candidate| candidate.has_name(tcx)); // Keep track of lifetimes which have already been replaced with other lifetimes. // This makes sure that if `'a = 'b = 'c`, we don't say `'c` should be replaced by diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index aad9b08b2a3a..f99cfc7cd506 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -579,11 +579,7 @@ fn get_new_lifetime_name<'tcx>( .collect_referenced_late_bound_regions(poly_trait_ref) .into_iter() .filter_map(|lt| { - if let ty::BoundRegionKind::Named(_, name) = lt { - Some(name.as_str().to_string()) - } else { - None - } + if let Some(name) = lt.get_name(tcx) { Some(name.as_str().to_string()) } else { None } }) .chain(generics.params.iter().filter_map(|param| { if let hir::GenericParamKind::Lifetime { .. } = ¶m.kind { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 0e775d374ab4..b1be8545b36d 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -287,7 +287,7 @@ fn late_arg_as_bound_arg<'tcx>( let name = tcx.item_name(def_id); match param.kind { GenericParamKind::Lifetime { .. } => { - ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id, name)) + ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) } GenericParamKind::Type { .. } => { ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) @@ -302,7 +302,7 @@ fn late_arg_as_bound_arg<'tcx>( fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVariableKind { match param.kind { ty::GenericParamDefKind::Lifetime => { - ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(param.def_id, param.name)) + ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(param.def_id)) } ty::GenericParamDefKind::Type { .. } => { ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index d17986d45d2f..1221ca15b7be 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, }; -use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; +use rustc_span::{ErrorGuaranteed, Ident, Span, kw}; use rustc_trait_selection::traits; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -888,7 +888,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundRegionKind::Named(param.def_id, param.name), + kind: ty::BoundRegionKind::Named(param.def_id), }, ) .into(), @@ -1006,12 +1006,12 @@ fn check_assoc_const_binding_type<'tcx>( ty_note, })); } - for (var_def_id, var_name) in collector.vars { + for var_def_id in collector.vars { guar.get_or_insert(cx.dcx().emit_err( crate::errors::EscapingBoundVarInTyOfAssocConstBinding { span: assoc_const.span, assoc_const, - var_name, + var_name: cx.tcx().item_name(var_def_id), var_def_kind: tcx.def_descr(var_def_id), var_defined_here_label: tcx.def_ident_span(var_def_id).unwrap(), ty_note, @@ -1026,7 +1026,7 @@ fn check_assoc_const_binding_type<'tcx>( struct GenericParamAndBoundVarCollector<'a, 'tcx> { cx: &'a dyn HirTyLowerer<'tcx>, params: FxIndexSet, - vars: FxIndexSet<(DefId, Symbol)>, + vars: FxIndexSet, depth: ty::DebruijnIndex, } @@ -1050,7 +1050,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 't } ty::Bound(db, bt) if *db >= self.depth => { self.vars.insert(match bt.kind { - ty::BoundTyKind::Param(def_id, name) => (def_id, name), + ty::BoundTyKind::Param(def_id, _) => def_id, ty::BoundTyKind::Anon => { let reported = self .cx @@ -1073,7 +1073,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 't } ty::ReBound(db, br) if db >= self.depth => { self.vars.insert(match br.kind { - ty::BoundRegionKind::Named(def_id, name) => (def_id, name), + ty::BoundRegionKind::Named(def_id) => def_id, ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => { let guar = self .cx @@ -1081,6 +1081,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 't .delayed_bug(format!("unexpected bound region kind: {:?}", br.kind)); return ControlFlow::Break(guar); } + ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"), }); } _ => {} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index e13daabeb505..1de5a15ad003 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -392,16 +392,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { #[instrument(level = "debug", skip(self), ret)] pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { let tcx = self.tcx(); - let lifetime_name = |def_id| tcx.hir_name(tcx.local_def_id_to_hir_id(def_id)); match resolved { rbv::ResolvedArg::StaticLifetime => tcx.lifetimes.re_static, rbv::ResolvedArg::LateBound(debruijn, index, def_id) => { - let name = lifetime_name(def_id); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), - kind: ty::BoundRegionKind::Named(def_id.to_def_id(), name), + kind: ty::BoundRegionKind::Named(def_id.to_def_id()), }; ty::Region::new_bound(tcx, debruijn, br) } @@ -415,11 +413,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } rbv::ResolvedArg::Free(scope, id) => { - let name = lifetime_name(id); ty::Region::new_late_param( tcx, scope.to_def_id(), - ty::LateParamRegionKind::Named(id.to_def_id(), name), + ty::LateParamRegionKind::Named(id.to_def_id()), ) // (*) -- not late-bound, won't change @@ -2749,18 +2746,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { generate_err: impl Fn(&str) -> Diag<'cx>, ) { for br in referenced_regions.difference(&constrained_regions) { - let br_name = match *br { - ty::BoundRegionKind::Named(_, kw::UnderscoreLifetime) - | ty::BoundRegionKind::Anon - | ty::BoundRegionKind::ClosureEnv => "an anonymous lifetime".to_string(), - ty::BoundRegionKind::Named(_, name) => format!("lifetime `{name}`"), + let br_name = if let Some(name) = br.get_name(self.tcx()) { + format!("lifetime `{name}`") + } else { + "an anonymous lifetime".to_string() }; let mut err = generate_err(&br_name); - if let ty::BoundRegionKind::Named(_, kw::UnderscoreLifetime) - | ty::BoundRegionKind::Anon = *br - { + if !br.is_named(self.tcx()) { // The only way for an anonymous lifetime to wind up // in the return type but **also** be unconstrained is // if it only appears in "associated types" in the diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index aa6f36a67f09..c83380447930 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -136,7 +136,7 @@ enum ParamKind { // Early-bound var. Early(Symbol, u32), // Late-bound var on function, not within a binder. We can capture these. - Free(DefId, Symbol), + Free(DefId), // Late-bound var in a binder. We can't capture these yet. Late, } @@ -156,12 +156,11 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { } for bound_var in sig.bound_vars() { - let ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id, name)) = bound_var - else { + let ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) = bound_var else { span_bug!(tcx.def_span(parent_def_id), "unexpected non-lifetime binder on fn sig"); }; - in_scope_parameters.insert(def_id, ParamKind::Free(def_id, name)); + in_scope_parameters.insert(def_id, ParamKind::Free(def_id)); } let sig = tcx.liberate_late_bound_regions(parent_def_id.to_def_id(), sig); @@ -215,7 +214,7 @@ where for arg in t.bound_vars() { let arg: ty::BoundVariableKind = arg; match arg { - ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id, ..)) + ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) | ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, _)) => { added.push(def_id); let unique = self.in_scope_parameters.insert(def_id, ParamKind::Late); @@ -316,10 +315,10 @@ where self.tcx, ty::EarlyParamRegion { name, index }, ), - ParamKind::Free(def_id, name) => ty::Region::new_late_param( + ParamKind::Free(def_id) => ty::Region::new_late_param( self.tcx, self.parent_def_id.to_def_id(), - ty::LateParamRegionKind::Named(def_id, name), + ty::LateParamRegionKind::Named(def_id), ), // Totally ignore late bound args from binders. ParamKind::Late => return true, @@ -463,13 +462,10 @@ fn extract_def_id_from_arg<'tcx>( match arg.kind() { ty::GenericArgKind::Lifetime(re) => match re.kind() { ty::ReEarlyParam(ebr) => generics.region_param(ebr, tcx).def_id, - ty::ReBound( - _, - ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id, ..), .. }, - ) + ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. }) | ty::ReLateParam(ty::LateParamRegion { scope: _, - kind: ty::LateParamRegionKind::Named(def_id, ..), + kind: ty::LateParamRegionKind::Named(def_id), }) => def_id, _ => unreachable!(), }, @@ -532,13 +528,10 @@ impl<'tcx> TypeRelation> for FunctionalVariances<'tcx> { ) -> RelateResult<'tcx, ty::Region<'tcx>> { let def_id = match a.kind() { ty::ReEarlyParam(ebr) => self.generics.region_param(ebr, self.tcx).def_id, - ty::ReBound( - _, - ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id, ..), .. }, - ) + ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. }) | ty::ReLateParam(ty::LateParamRegion { scope: _, - kind: ty::LateParamRegionKind::Named(def_id, ..), + kind: ty::LateParamRegionKind::Named(def_id), }) => def_id, _ => { return Ok(a); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8aa50d14faa6..021d0148fd16 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3279,10 +3279,7 @@ impl<'tcx> TyCtxt<'tcx> { return ty::Region::new_late_param( self, new_parent.to_def_id(), - ty::LateParamRegionKind::Named( - lbv.to_def_id(), - self.item_name(lbv.to_def_id()), - ), + ty::LateParamRegionKind::Named(lbv.to_def_id()), ); } resolve_bound_vars::ResolvedArg::Error(guar) => { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b4c4f48a0a6c..ad4639844597 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -11,7 +11,7 @@ use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::LangItem; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; -use rustc_hir::def_id::{CRATE_DEF_ID, DefIdMap, DefIdSet, LOCAL_CRATE, ModDefId}; +use rustc_hir::def_id::{DefIdMap, DefIdSet, LOCAL_CRATE, ModDefId}; use rustc_hir::definitions::{DefKey, DefPathDataName}; use rustc_macros::{Lift, extension}; use rustc_session::Limit; @@ -2553,12 +2553,12 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { match region.kind() { ty::ReEarlyParam(ref data) => data.has_name(), - ty::ReLateParam(ty::LateParamRegion { kind, .. }) => kind.is_named(), + ty::ReLateParam(ty::LateParamRegion { kind, .. }) => kind.is_named(self.tcx), ty::ReBound(_, ty::BoundRegion { kind: br, .. }) | ty::RePlaceholder(ty::Placeholder { bound: ty::BoundRegion { kind: br, .. }, .. }) => { - if br.is_named() { + if br.is_named(self.tcx) { return true; } @@ -2626,7 +2626,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { return Ok(()); } ty::ReLateParam(ty::LateParamRegion { kind, .. }) => { - if let Some(name) = kind.get_name() { + if let Some(name) = kind.get_name(self.tcx) { p!(write("{}", name)); return Ok(()); } @@ -2635,9 +2635,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { | ty::RePlaceholder(ty::Placeholder { bound: ty::BoundRegion { kind: br, .. }, .. }) => { - if let ty::BoundRegionKind::Named(_, name) = br - && br.is_named() - { + if let Some(name) = br.get_name(self.tcx) { p!(write("{}", name)); return Ok(()); } @@ -2844,56 +2842,23 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { let mut name = |lifetime_idx: Option, binder_level_idx: ty::DebruijnIndex, br: ty::BoundRegion| { - let (name, kind) = match br.kind { - ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => { - let name = next_name(self); - - if let Some(lt_idx) = lifetime_idx { - if lt_idx > binder_level_idx { - let kind = - ty::BoundRegionKind::Named(CRATE_DEF_ID.to_def_id(), name); - return ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: br.var, kind }, - ); - } - } - - (name, ty::BoundRegionKind::Named(CRATE_DEF_ID.to_def_id(), name)) - } - ty::BoundRegionKind::Named(def_id, kw::UnderscoreLifetime) => { - let name = next_name(self); - - if let Some(lt_idx) = lifetime_idx { - if lt_idx > binder_level_idx { - let kind = ty::BoundRegionKind::Named(def_id, name); - return ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: br.var, kind }, - ); - } - } - - (name, ty::BoundRegionKind::Named(def_id, name)) - } - ty::BoundRegionKind::Named(_, name) => { - if let Some(lt_idx) = lifetime_idx { - if lt_idx > binder_level_idx { - let kind = br.kind; - return ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: br.var, kind }, - ); - } - } - - (name, br.kind) - } + let (name, kind) = if let Some(name) = br.kind.get_name(tcx) { + (name, br.kind) + } else { + let name = next_name(self); + (name, ty::BoundRegionKind::NamedAnon(name)) }; + if let Some(lt_idx) = lifetime_idx { + if lt_idx > binder_level_idx { + return ty::Region::new_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: br.var, kind }, + ); + } + } + // Unconditionally render `unsafe<>`. if !trim_path || mode == WrapBinderMode::Unsafe { start_or_continue(self, mode.start_str(), ", "); @@ -2960,13 +2925,15 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { T: TypeFoldable>, { struct RegionNameCollector<'tcx> { + tcx: TyCtxt<'tcx>, used_region_names: FxHashSet, type_collector: SsoHashSet>, } impl<'tcx> RegionNameCollector<'tcx> { - fn new() -> Self { + fn new(tcx: TyCtxt<'tcx>) -> Self { RegionNameCollector { + tcx, used_region_names: Default::default(), type_collector: SsoHashSet::new(), } @@ -2980,7 +2947,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { // Collect all named lifetimes. These allow us to prevent duplication // of already existing lifetime names when introducing names for // anonymous late-bound regions. - if let Some(name) = r.get_name() { + if let Some(name) = r.get_name(self.tcx) { self.used_region_names.insert(name); } } @@ -2995,7 +2962,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { } } - let mut collector = RegionNameCollector::new(); + let mut collector = RegionNameCollector::new(self.tcx()); value.visit_with(&mut collector); self.used_region_names = collector.used_region_names; self.region_index = 0; diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index cc25cd16567b..c598cd21fc83 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -163,37 +163,33 @@ impl<'tcx> Region<'tcx> { *self.0.0 } - pub fn get_name(self) -> Option { - if self.has_name() { - match self.kind() { - ty::ReEarlyParam(ebr) => Some(ebr.name), - ty::ReBound(_, br) => br.kind.get_name(), - ty::ReLateParam(fr) => fr.kind.get_name(), - ty::ReStatic => Some(kw::StaticLifetime), - ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(), - _ => None, - } - } else { - None + pub fn get_name(self, tcx: TyCtxt<'tcx>) -> Option { + match self.kind() { + ty::ReEarlyParam(ebr) => Some(ebr.name), + ty::ReBound(_, br) => br.kind.get_name(tcx), + ty::ReLateParam(fr) => fr.kind.get_name(tcx), + ty::ReStatic => Some(kw::StaticLifetime), + ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(tcx), + _ => None, } } - pub fn get_name_or_anon(self) -> Symbol { - match self.get_name() { + pub fn get_name_or_anon(self, tcx: TyCtxt<'tcx>) -> Symbol { + match self.get_name(tcx) { Some(name) => name, None => sym::anon, } } /// Is this region named by the user? - pub fn has_name(self) -> bool { + pub fn has_name(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { ty::ReEarlyParam(ebr) => ebr.has_name(), - ty::ReBound(_, br) => br.kind.is_named(), - ty::ReLateParam(fr) => fr.kind.is_named(), + ty::ReBound(_, br) => br.kind.is_named(tcx), + ty::ReLateParam(fr) => fr.kind.is_named(tcx), ty::ReStatic => true, ty::ReVar(..) => false, - ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(), + ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(tcx), ty::ReErased => false, ty::ReError(_) => false, } @@ -313,7 +309,7 @@ impl<'tcx> Region<'tcx> { Some(tcx.generics_of(binding_item).region_param(ebr, tcx).def_id) } ty::ReLateParam(ty::LateParamRegion { - kind: ty::LateParamRegionKind::Named(def_id, _), + kind: ty::LateParamRegionKind::Named(def_id), .. }) => Some(def_id), _ => None, @@ -371,11 +367,13 @@ pub enum LateParamRegionKind { /// sake of diagnostics in `FnCtxt::sig_of_closure_with_expectation`. Anon(u32), - /// Named region parameters for functions (a in &'a T) + /// An anonymous region parameter with a `Symbol` name. /// - /// The `DefId` is needed to distinguish free regions in - /// the event of shadowing. - Named(DefId, Symbol), + /// Used to give late-bound regions names for things like pretty printing. + NamedAnon(u32, Symbol), + + /// Late-bound regions that appear in the AST. + Named(DefId), /// Anonymous region for the implicit env pointer parameter /// to a closure @@ -386,32 +384,30 @@ impl LateParamRegionKind { pub fn from_bound(var: BoundVar, br: BoundRegionKind) -> LateParamRegionKind { match br { BoundRegionKind::Anon => LateParamRegionKind::Anon(var.as_u32()), - BoundRegionKind::Named(def_id, name) => LateParamRegionKind::Named(def_id, name), + BoundRegionKind::Named(def_id) => LateParamRegionKind::Named(def_id), BoundRegionKind::ClosureEnv => LateParamRegionKind::ClosureEnv, + BoundRegionKind::NamedAnon(name) => LateParamRegionKind::NamedAnon(var.as_u32(), name), } } - pub fn is_named(&self) -> bool { + pub fn is_named(&self, tcx: TyCtxt<'_>) -> bool { + self.get_name(tcx).is_some() + } + + pub fn get_name(&self, tcx: TyCtxt<'_>) -> Option { match *self { - LateParamRegionKind::Named(_, name) => name != kw::UnderscoreLifetime, - _ => false, - } - } - - pub fn get_name(&self) -> Option { - if self.is_named() { - match *self { - LateParamRegionKind::Named(_, name) => return Some(name), - _ => unreachable!(), + LateParamRegionKind::Named(def_id) => { + let name = tcx.item_name(def_id); + if name != kw::UnderscoreLifetime { Some(name) } else { None } } + LateParamRegionKind::NamedAnon(_, name) => Some(name), + _ => None, } - - None } pub fn get_id(&self) -> Option { match *self { - LateParamRegionKind::Named(id, _) => Some(id), + LateParamRegionKind::Named(id) => Some(id), _ => None, } } @@ -423,11 +419,13 @@ pub enum BoundRegionKind { /// An anonymous region parameter for a given fn (&T) Anon, - /// Named region parameters for functions (a in &'a T) + /// An anonymous region parameter with a `Symbol` name. /// - /// The `DefId` is needed to distinguish free regions in - /// the event of shadowing. - Named(DefId, Symbol), + /// Used to give late-bound regions names for things like pretty printing. + NamedAnon(Symbol), + + /// Late-bound regions that appear in the AST. + Named(DefId), /// Anonymous region for the implicit env pointer parameter /// to a closure @@ -456,35 +454,35 @@ impl core::fmt::Debug for BoundRegion { match self.kind { BoundRegionKind::Anon => write!(f, "{:?}", self.var), BoundRegionKind::ClosureEnv => write!(f, "{:?}.Env", self.var), - BoundRegionKind::Named(def, symbol) => { - write!(f, "{:?}.Named({:?}, {:?})", self.var, def, symbol) + BoundRegionKind::Named(def) => { + write!(f, "{:?}.Named({:?})", self.var, def) + } + BoundRegionKind::NamedAnon(symbol) => { + write!(f, "{:?}.NamedAnon({:?})", self.var, symbol) } } } } impl BoundRegionKind { - pub fn is_named(&self) -> bool { - match *self { - BoundRegionKind::Named(_, name) => name != kw::UnderscoreLifetime, - _ => false, - } + pub fn is_named(&self, tcx: TyCtxt<'_>) -> bool { + self.get_name(tcx).is_some() } - pub fn get_name(&self) -> Option { - if self.is_named() { - match *self { - BoundRegionKind::Named(_, name) => return Some(name), - _ => unreachable!(), + pub fn get_name(&self, tcx: TyCtxt<'_>) -> Option { + match *self { + BoundRegionKind::Named(def_id) => { + let name = tcx.item_name(def_id); + if name != kw::UnderscoreLifetime { Some(name) } else { None } } + BoundRegionKind::NamedAnon(name) => Some(name), + _ => None, } - - None } pub fn get_id(&self) -> Option { match *self { - BoundRegionKind::Named(id, _) => Some(id), + BoundRegionKind::Named(id) => Some(id), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1214731a3b2e..3a0bd1fb0294 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -69,12 +69,11 @@ impl fmt::Debug for ty::BoundRegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ty::BoundRegionKind::Anon => write!(f, "BrAnon"), - ty::BoundRegionKind::Named(did, name) => { - if did.is_crate_root() { - write!(f, "BrNamed({name})") - } else { - write!(f, "BrNamed({did:?}, {name})") - } + ty::BoundRegionKind::NamedAnon(name) => { + write!(f, "BrNamedAnon({name})") + } + ty::BoundRegionKind::Named(did) => { + write!(f, "BrNamed({did:?})") } ty::BoundRegionKind::ClosureEnv => write!(f, "BrEnv"), } @@ -91,12 +90,11 @@ impl fmt::Debug for ty::LateParamRegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ty::LateParamRegionKind::Anon(idx) => write!(f, "LateAnon({idx})"), - ty::LateParamRegionKind::Named(did, name) => { - if did.is_crate_root() { - write!(f, "LateNamed({name})") - } else { - write!(f, "LateNamed({did:?}, {name})") - } + ty::LateParamRegionKind::NamedAnon(idx, name) => { + write!(f, "LateNamedAnon({idx:?}, {name})") + } + ty::LateParamRegionKind::Named(did) => { + write!(f, "LateNamed({did:?})") } ty::LateParamRegionKind::ClosureEnv => write!(f, "LateEnv"), } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 7a1890226c9a..ae3b2a90e6aa 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2032,7 +2032,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(ty::RegionKind<'_>, 24); + static_assert_size!(ty::RegionKind<'_>, 20); static_assert_size!(ty::TyKind<'_>, 24); // tidy-alphabetical-end } diff --git a/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs index 4cbe02bfa0db..67c0020bd178 100644 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs +++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs @@ -453,10 +453,9 @@ impl RustcInternal for BoundVariableKind { }), BoundVariableKind::Region(kind) => rustc_ty::BoundVariableKind::Region(match kind { BoundRegionKind::BrAnon => rustc_ty::BoundRegionKind::Anon, - BoundRegionKind::BrNamed(def, symbol) => rustc_ty::BoundRegionKind::Named( - def.0.internal(tables, tcx), - Symbol::intern(symbol), - ), + BoundRegionKind::BrNamed(def, _symbol) => { + rustc_ty::BoundRegionKind::Named(def.0.internal(tables, tcx)) + } BoundRegionKind::BrEnv => rustc_ty::BoundRegionKind::ClosureEnv, }), BoundVariableKind::Const => rustc_ty::BoundVariableKind::Const, diff --git a/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs index c0a430079d8b..c9cbc9329db3 100644 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs @@ -1,7 +1,7 @@ //! Conversion of internal Rust compiler `ty` items to stable ones. use rustc_middle::ty::Ty; -use rustc_middle::{mir, ty}; +use rustc_middle::{bug, mir, ty}; use rustc_smir::Tables; use rustc_smir::context::SmirCtxt; use stable_mir::alloc; @@ -310,16 +310,18 @@ impl<'tcx> Stable<'tcx> for ty::BoundRegionKind { fn stable<'cx>( &self, tables: &mut Tables<'cx, BridgeTys>, - _: &SmirCtxt<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, ) -> Self::T { use stable_mir::ty::BoundRegionKind; match self { ty::BoundRegionKind::Anon => BoundRegionKind::BrAnon, - ty::BoundRegionKind::Named(def_id, symbol) => { - BoundRegionKind::BrNamed(tables.br_named_def(*def_id), symbol.to_string()) - } + ty::BoundRegionKind::Named(def_id) => BoundRegionKind::BrNamed( + tables.br_named_def(*def_id), + cx.tcx.item_name(*def_id).to_string(), + ), ty::BoundRegionKind::ClosureEnv => BoundRegionKind::BrEnv, + ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"), } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs index aa7935a29f0b..679adcae768a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs @@ -2,8 +2,6 @@ //! where one region is named and the other is anonymous. use rustc_errors::Diag; -use rustc_middle::ty; -use rustc_span::kw; use tracing::debug; use crate::error_reporting::infer::nice_region_error::NiceRegionError; @@ -27,12 +25,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // only introduced anonymous regions in parameters) as well as a // version new_ty of its type where the anonymous region is replaced // with the named one. - let (named, anon, anon_param_info, region_info) = if sub.has_name() + let (named, anon, anon_param_info, region_info) = if sub.has_name(self.tcx()) && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sup) && let Some(anon_param_info) = self.find_param_with_region(sup, sub) { (sub, sup, anon_param_info, region_info) - } else if sup.has_name() + } else if sup.has_name(self.tcx()) && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sub) && let Some(anon_param_info) = self.find_param_with_region(sub, sup) { @@ -58,14 +56,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let scope_def_id = region_info.scope; let is_impl_item = region_info.is_impl_item; - match anon_param_info.kind { - ty::LateParamRegionKind::Named(_, kw::UnderscoreLifetime) - | ty::LateParamRegionKind::Anon(_) => {} - _ => { - /* not an anonymous region */ - debug!("try_report_named_anon_conflict: not an anonymous region"); - return None; - } + if !anon_param_info.kind.is_named(self.tcx()) { + // Anon region + } else { + /* not an anonymous region */ + debug!("try_report_named_anon_conflict: not an anonymous region"); + return None; } if is_impl_item { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 5056161e117e..d4e6a33b5cec 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -164,7 +164,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sub_region @ Region(Interned(RePlaceholder(_), _)), sup_region, )) => self.try_report_trait_placeholder_mismatch( - (!sup_region.has_name()).then_some(*sup_region), + (!sup_region.has_name(self.tcx())).then_some(*sup_region), cause, Some(*sub_region), None, @@ -176,7 +176,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sub_region, sup_region @ Region(Interned(RePlaceholder(_), _)), )) => self.try_report_trait_placeholder_mismatch( - (!sub_region.has_name()).then_some(*sub_region), + (!sub_region.has_name(self.tcx())).then_some(*sub_region), cause, None, Some(*sup_region), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs index 7fcd3c847e39..3bab09bc587f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs @@ -1,5 +1,6 @@ use rustc_data_structures::intern::Interned; use rustc_errors::Diag; +use rustc_middle::bug; use rustc_middle::ty::{self, RePlaceholder, Region}; use crate::error_reporting::infer::nice_region_error::NiceRegionError; @@ -28,20 +29,22 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { )), )) => { let span = *span; - let (sub_span, sub_symbol) = match sub_name { - ty::BoundRegionKind::Named(def_id, symbol) => { - (Some(self.tcx().def_span(def_id)), Some(symbol)) + let (sub_span, sub_symbol) = match *sub_name { + ty::BoundRegionKind::Named(def_id) => { + (Some(self.tcx().def_span(def_id)), Some(self.tcx().item_name(def_id))) } ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => (None, None), + ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"), }; - let (sup_span, sup_symbol) = match sup_name { - ty::BoundRegionKind::Named(def_id, symbol) => { - (Some(self.tcx().def_span(def_id)), Some(symbol)) + let (sup_span, sup_symbol) = match *sup_name { + ty::BoundRegionKind::Named(def_id) => { + (Some(self.tcx().def_span(def_id)), Some(self.tcx().item_name(def_id))) } ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => (None, None), + ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"), }; let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) { - (Some(sub_span), Some(sup_span), Some(&sub_symbol), Some(&sup_symbol)) => { + (Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => { PlaceholderRelationLfNotSatisfied::HasBoth { span, sub_span, @@ -51,7 +54,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { note: (), } } - (Some(sub_span), Some(sup_span), _, Some(&sup_symbol)) => { + (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => { PlaceholderRelationLfNotSatisfied::HasSup { span, sub_span, @@ -60,7 +63,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { note: (), } } - (Some(sub_span), Some(sup_span), Some(&sub_symbol), _) => { + (Some(sub_span), Some(sup_span), Some(sub_symbol), _) => { PlaceholderRelationLfNotSatisfied::HasSub { span, sub_span, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index eaa06d8e8b0a..16b2e63ea776 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -45,7 +45,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let return_sp = sub_origin.span(); let param = self.find_param_with_region(*sup_r, *sub_r)?; let simple_ident = param.param.pat.simple_ident(); - let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; + let lifetime_name = + if sup_r.has_name(self.tcx()) { sup_r.to_string() } else { "'_".to_owned() }; let (mention_influencer, influencer_point) = if sup_origin.span().overlaps(param.param_ty_span) { @@ -99,7 +100,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // We don't need a note, it's already at the end, it can be shown as a `span_label`. require_span_as_label: (!require_as_note).then_some(require_span), - has_lifetime: sup_r.has_name(), + has_lifetime: sup_r.has_name(self.tcx()), lifetime: lifetime_name.clone(), has_param_name: simple_ident.is_some(), param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index f1237130c15a..422b9cfdd045 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -60,14 +60,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Mark all unnamed regions in the type with a number. // This diagnostic is called in response to lifetime errors, so be informative. struct HighlightBuilder<'tcx> { + tcx: TyCtxt<'tcx>, highlight: RegionHighlightMode<'tcx>, counter: usize, } impl<'tcx> HighlightBuilder<'tcx> { - fn build(sig: ty::PolyFnSig<'tcx>) -> RegionHighlightMode<'tcx> { + fn build(tcx: TyCtxt<'tcx>, sig: ty::PolyFnSig<'tcx>) -> RegionHighlightMode<'tcx> { let mut builder = - HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 }; + HighlightBuilder { tcx, highlight: RegionHighlightMode::default(), counter: 1 }; sig.visit_with(&mut builder); builder.highlight } @@ -75,15 +76,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { impl<'tcx> ty::TypeVisitor> for HighlightBuilder<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) { - if !r.has_name() && self.counter <= 3 { + if !r.has_name(self.tcx) && self.counter <= 3 { self.highlight.highlighting_region(r, self.counter); self.counter += 1; } } } - let expected_highlight = HighlightBuilder::build(expected); let tcx = self.cx.tcx; + let expected_highlight = HighlightBuilder::build(tcx, expected); let expected = Highlighted { highlight: expected_highlight, ns: Namespace::TypeNS, @@ -91,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { value: expected, } .to_string(); - let found_highlight = HighlightBuilder::build(found); + let found_highlight = HighlightBuilder::build(tcx, found); let found = Highlighted { highlight: found_highlight, ns: Namespace::TypeNS, tcx, value: found } .to_string(); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index 4a71ab4e06a3..5f2aab38c31c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -46,7 +46,7 @@ pub fn find_param_with_region<'tcx>( ty::ReLateParam(late_param) => (late_param.scope, late_param.kind), ty::ReEarlyParam(ebr) => { let region_def = tcx.generics_of(generic_param_scope).region_param(ebr, tcx).def_id; - (tcx.parent(region_def), ty::LateParamRegionKind::Named(region_def, ebr.name)) + (tcx.parent(region_def), ty::LateParamRegionKind::Named(region_def)) } _ => return None, // not a free region }; @@ -144,7 +144,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // We are only checking is any region meets the condition so order doesn't matter #[allow(rustc::potential_query_instability)] late_bound_regions.iter().any(|r| match *r { - ty::BoundRegionKind::Named(def_id, _) => def_id == region_def_id, + ty::BoundRegionKind::Named(def_id) => def_id == region_def_id, _ => false, }) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 4fab67b01cb9..f9de3e96d790 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -729,7 +729,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .dcx() .struct_span_err(span, format!("{labeled_user_string} may not live long enough")); err.code(match sub.kind() { - ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309, + ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name(self.tcx) => E0309, ty::ReStatic => E0310, _ => E0311, }); @@ -755,7 +755,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { || (bound_kind, sub).has_placeholders() || !bound_kind.is_suggestable(self.tcx, false) { - let lt_name = sub.get_name_or_anon().to_string(); + let lt_name = sub.get_name_or_anon(self.tcx).to_string(); err.help(format!("{msg} `{bound_kind}: {lt_name}`...")); break 'suggestion; } @@ -875,13 +875,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - let (lifetime_def_id, lifetime_scope) = match self - .tcx - .is_suitable_region(generic_param_scope, lifetime) - { - Some(info) if !lifetime.has_name() => (info.region_def_id.expect_local(), info.scope), - _ => return lifetime.get_name_or_anon().to_string(), - }; + let (lifetime_def_id, lifetime_scope) = + match self.tcx.is_suitable_region(generic_param_scope, lifetime) { + Some(info) if !lifetime.has_name(self.tcx) => { + (info.region_def_id.expect_local(), info.scope) + } + _ => return lifetime.get_name_or_anon(self.tcx).to_string(), + }; let new_lt = { let generics = self.tcx.generics_of(lifetime_scope); @@ -895,7 +895,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // consider late-bound lifetimes ... used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map( |p| match p { - ty::BoundVariableKind::Region(lt) => lt.get_name(), + ty::BoundVariableKind::Region(lt) => lt.get_name(self.tcx), _ => None, }, )); @@ -1006,7 +1006,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> { let br_string = |br: ty::BoundRegionKind| { let mut s = match br { - ty::BoundRegionKind::Named(_, name) => name.to_string(), + ty::BoundRegionKind::Named(def_id) => self.tcx.item_name(def_id).to_string(), _ => String::new(), }; if !s.is_empty() { @@ -1117,13 +1117,14 @@ fn msg_span_from_named_region<'tcx>( (text, Some(span)) } ty::ReLateParam(ref fr) => { - if !fr.kind.is_named() + if !fr.kind.is_named(tcx) && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region) { ("the anonymous lifetime defined here".to_string(), Some(ty.span)) } else { match fr.kind { - ty::LateParamRegionKind::Named(param_def_id, name) => { + ty::LateParamRegionKind::Named(param_def_id) => { + let name = tcx.item_name(param_def_id); let span = tcx.def_span(param_def_id); let text = if name == kw::UnderscoreLifetime { "the anonymous lifetime as defined here".to_string() @@ -1145,9 +1146,12 @@ fn msg_span_from_named_region<'tcx>( } ty::ReStatic => ("the static lifetime".to_owned(), alt_span), ty::RePlaceholder(ty::PlaceholderRegion { - bound: ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id, name), .. }, + bound: ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. }, .. - }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))), + }) => ( + format!("the lifetime `{}` as defined here", tcx.item_name(def_id)), + Some(tcx.def_span(def_id)), + ), ty::RePlaceholder(ty::PlaceholderRegion { bound: ty::BoundRegion { kind: ty::BoundRegionKind::Anon, .. }, .. diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index ec3c1ba4a455..0a1cdb16f5a0 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -39,14 +39,15 @@ impl<'a> DescriptionCtx<'a> { } } ty::ReLateParam(ref fr) => { - if !fr.kind.is_named() + if !fr.kind.is_named(tcx) && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region) { (Some(ty.span), "defined_here", String::new()) } else { let scope = fr.scope.expect_local(); match fr.kind { - ty::LateParamRegionKind::Named(_, name) => { + ty::LateParamRegionKind::Named(def_id) => { + let name = tcx.item_name(def_id); let span = if let Some(param) = tcx .hir_get_generics(scope) .and_then(|generics| generics.get_named(name)) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index dcd499d5f0de..96199cb972a8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -293,7 +293,7 @@ pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box( GenericBound::TraitBound( PolyTrait { trait_: clean_trait_ref_with_constraints(cx, poly_trait_ref, constraints), - generic_params: clean_bound_vars(poly_trait_ref.bound_vars()), + generic_params: clean_bound_vars(poly_trait_ref.bound_vars(), cx), }, hir::TraitBoundModifiers::NONE, ) @@ -325,24 +325,11 @@ pub(crate) fn clean_middle_const<'tcx>( ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() } } -pub(crate) fn clean_middle_region(region: ty::Region<'_>) -> Option { - match region.kind() { - ty::ReStatic => Some(Lifetime::statik()), - _ if !region.has_name() => None, - ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. }) => { - Some(Lifetime(name)) - } - ty::ReEarlyParam(ref data) => Some(Lifetime(data.name)), - ty::ReBound(..) - | ty::ReLateParam(..) - | ty::ReVar(..) - | ty::ReError(_) - | ty::RePlaceholder(..) - | ty::ReErased => { - debug!("cannot clean region {region:?}"); - None - } - } +pub(crate) fn clean_middle_region<'tcx>( + region: ty::Region<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option { + region.get_name(cx.tcx).map(Lifetime) } fn clean_where_predicate<'tcx>( @@ -384,7 +371,7 @@ pub(crate) fn clean_predicate<'tcx>( let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { ty::ClauseKind::Trait(pred) => clean_poly_trait_predicate(bound_predicate.rebind(pred), cx), - ty::ClauseKind::RegionOutlives(pred) => Some(clean_region_outlives_predicate(pred)), + ty::ClauseKind::RegionOutlives(pred) => Some(clean_region_outlives_predicate(pred, cx)), ty::ClauseKind::TypeOutlives(pred) => { Some(clean_type_outlives_predicate(bound_predicate.rebind(pred), cx)) } @@ -418,13 +405,16 @@ fn clean_poly_trait_predicate<'tcx>( }) } -fn clean_region_outlives_predicate(pred: ty::RegionOutlivesPredicate<'_>) -> WherePredicate { +fn clean_region_outlives_predicate<'tcx>( + pred: ty::RegionOutlivesPredicate<'tcx>, + cx: &mut DocContext<'tcx>, +) -> WherePredicate { let ty::OutlivesPredicate(a, b) = pred; WherePredicate::RegionPredicate { - lifetime: clean_middle_region(a).expect("failed to clean lifetime"), + lifetime: clean_middle_region(a, cx).expect("failed to clean lifetime"), bounds: vec![GenericBound::Outlives( - clean_middle_region(b).expect("failed to clean bounds"), + clean_middle_region(b, cx).expect("failed to clean bounds"), )], } } @@ -438,7 +428,7 @@ fn clean_type_outlives_predicate<'tcx>( WherePredicate::BoundPredicate { ty: clean_middle_ty(pred.rebind(ty), cx, None, None), bounds: vec![GenericBound::Outlives( - clean_middle_region(lt).expect("failed to clean lifetimes"), + clean_middle_region(lt, cx).expect("failed to clean lifetimes"), )], bound_params: Vec::new(), } @@ -1905,8 +1895,8 @@ fn clean_trait_object_lifetime_bound<'tcx>( match region.kind() { ty::ReStatic => Some(Lifetime::statik()), ty::ReEarlyParam(region) => Some(Lifetime(region.name)), - ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. }) => { - Some(Lifetime(name)) + ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. }) => { + Some(Lifetime(tcx.item_name(def_id))) } ty::ReBound(..) | ty::ReLateParam(_) @@ -1935,7 +1925,9 @@ fn can_elide_trait_object_lifetime_bound<'tcx>( match default { ObjectLifetimeDefault::Static => return region.kind() == ty::ReStatic, // FIXME(fmease): Don't compare lexically but respect de Bruijn indices etc. to handle shadowing correctly. - ObjectLifetimeDefault::Arg(default) => return region.get_name() == default.get_name(), + ObjectLifetimeDefault::Arg(default) => { + return region.get_name(tcx) == default.get_name(tcx); + } // > If there is more than one bound from the containing type then an explicit bound must be specified // Due to ambiguity there is no default trait-object lifetime and thus elision is impossible. // Don't elide the lifetime. @@ -1957,7 +1949,7 @@ fn can_elide_trait_object_lifetime_bound<'tcx>( // > If the trait is defined with a single lifetime bound then that bound is used. // > If 'static is used for any lifetime bound then 'static is used. // FIXME(fmease): Don't compare lexically but respect de Bruijn indices etc. to handle shadowing correctly. - [object_region] => object_region.get_name() == region.get_name(), + [object_region] => object_region.get_name(tcx) == region.get_name(tcx), // There are several distinct trait regions and none are `'static`. // Due to ambiguity there is no default trait-object lifetime and thus elision is impossible. // Don't elide the lifetime. @@ -2051,7 +2043,7 @@ pub(crate) fn clean_middle_ty<'tcx>( RawPointer(mutbl, Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))) } ty::Ref(r, ty, mutbl) => BorrowedRef { - lifetime: clean_middle_region(r), + lifetime: clean_middle_region(r, cx), mutability: mutbl, type_: Box::new(clean_middle_ty( bound_ty.rebind(ty), @@ -2064,7 +2056,7 @@ pub(crate) fn clean_middle_ty<'tcx>( // FIXME: should we merge the outer and inner binders somehow? let sig = bound_ty.skip_binder().fn_sig(cx.tcx); let decl = clean_poly_fn_sig(cx, None, sig); - let generic_params = clean_bound_vars(sig.bound_vars()); + let generic_params = clean_bound_vars(sig.bound_vars(), cx); BareFunction(Box::new(BareFunctionDecl { safety: sig.safety(), @@ -2074,7 +2066,7 @@ pub(crate) fn clean_middle_ty<'tcx>( })) } ty::UnsafeBinder(inner) => { - let generic_params = clean_bound_vars(inner.bound_vars()); + let generic_params = clean_bound_vars(inner.bound_vars(), cx); let ty = clean_middle_ty(inner.into(), cx, None, None); UnsafeBinder(Box::new(UnsafeBinderTy { generic_params, ty })) } @@ -2148,10 +2140,13 @@ pub(crate) fn clean_middle_ty<'tcx>( .iter() .flat_map(|pred| pred.bound_vars()) .filter_map(|var| match var { - ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id, name)) - if name != kw::UnderscoreLifetime => - { - Some(GenericParamDef::lifetime(def_id, name)) + ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) => { + let name = cx.tcx.item_name(def_id); + if name != kw::UnderscoreLifetime { + Some(GenericParamDef::lifetime(def_id, name)) + } else { + None + } } _ => None, }) @@ -2282,7 +2277,7 @@ fn clean_middle_opaque_bounds<'tcx>( let trait_ref = match bound_predicate.skip_binder() { ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref), ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => { - return clean_middle_region(reg).map(GenericBound::Outlives); + return clean_middle_region(reg, cx).map(GenericBound::Outlives); } _ => return None, }; @@ -3182,14 +3177,20 @@ fn clean_assoc_item_constraint<'tcx>( } } -fn clean_bound_vars(bound_vars: &ty::List) -> Vec { +fn clean_bound_vars<'tcx>( + bound_vars: &ty::List, + cx: &mut DocContext<'tcx>, +) -> Vec { bound_vars .into_iter() .filter_map(|var| match var { - ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id, name)) - if name != kw::UnderscoreLifetime => - { - Some(GenericParamDef::lifetime(def_id, name)) + ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) => { + let name = cx.tcx.item_name(def_id); + if name != kw::UnderscoreLifetime { + Some(GenericParamDef::lifetime(def_id, name)) + } else { + None + } } ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) => { Some(GenericParamDef { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 2c9878636abf..bf3f7607274d 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -125,9 +125,9 @@ pub(crate) fn clean_middle_generic_args<'tcx>( } match arg.skip_binder().kind() { - GenericArgKind::Lifetime(lt) => { - Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided()))) - } + GenericArgKind::Lifetime(lt) => Some(GenericArg::Lifetime( + clean_middle_region(lt, cx).unwrap_or(Lifetime::elided()), + )), GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty( arg.rebind(ty), cx, diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 25f9523f4e45..52794b19945b 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:32:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index e091ddcacb20..9fa443eefb3d 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:32:1 | diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr index 025fcc5e1702..b27a2dcceb13 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.stderr +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -1,4 +1,4 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a))], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied --> $DIR/structually-relate-aliases.rs:13:36 | diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr index 6fd41a761e99..6bf1e333327f 100644 --- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -4,14 +4,14 @@ error[E0700]: hidden type for `Opaque(DefId(0:11 ~ impl_trait_captures[aeb9]::fo LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { | -- ------------ opaque type defined here | | - | hidden type `&ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), LateNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_), '_)) T` captures the anonymous lifetime defined here + | hidden type `&ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), LateNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_))) T` captures the anonymous lifetime defined here LL | x | ^ | -help: add a `use<...>` bound to explicitly capture `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), LateNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_), '_))` +help: add a `use<...>` bound to explicitly capture `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), LateNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_)))` | -LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + use<'a, ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), LateNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_), '_)), T> { - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + use<'a, ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), LateNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_))), T> { + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index 391272b8d3bc..ce4f742a3fa9 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -25,7 +25,7 @@ help: this trait has no implementations, consider adding one LL | trait ToUnit<'a> { | ^^^^^^^^^^^^^^^^ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a)), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } error[E0277]: the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied --> $DIR/issue-118950-root-region.rs:19:9 | diff --git a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr index 0d8ec5f89289..89a91a1f1ad7 100644 --- a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr +++ b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `for fn(&'^1_0.Named(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), "'b") ()): Foo` is not satisfied +error[E0277]: the trait bound `for fn(&'^1_0.Named(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b)) ()): Foo` is not satisfied --> $DIR/higher-ranked-fn-type.rs:20:5 | LL | called() | ^^^^^^^^ unsatisfied trait bound | - = help: the trait `for Foo` is not implemented for `fn(&'^1_0.Named(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), "'b") ())` + = help: the trait `for Foo` is not implemented for `fn(&'^1_0.Named(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b)) ())` help: this trait has no implementations, consider adding one --> $DIR/higher-ranked-fn-type.rs:6:1 | From 74570e526e6816b04c479a34dc1f2116e121e798 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 11 Apr 2025 04:25:25 +0000 Subject: [PATCH 14/68] Same for types --- .../src/check/compare_impl_item.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 24 +++++++------------ .../src/hir_ty_lowering/bounds.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 3 +-- .../rustc_lint/src/impl_trait_overcaptures.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 8 +++---- .../rustc_middle/src/ty/structural_impls.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- .../stable_mir/unstable/convert/internal.rs | 8 +++---- .../stable_mir/unstable/convert/stable/ty.rs | 6 ++--- src/librustdoc/clean/mod.rs | 5 ++-- 11 files changed, 28 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 674f8e0eeafa..87db80f2423d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2468,7 +2468,7 @@ fn param_env_with_gat_bounds<'tcx>( let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id) .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind { GenericParamDefKind::Type { .. } => { - let kind = ty::BoundTyKind::Param(param.def_id, param.name); + let kind = ty::BoundTyKind::Param(param.def_id); let bound_var = ty::BoundVariableKind::Ty(kind); bound_vars.push(bound_var); Ty::new_bound( diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index b1be8545b36d..a0d1273eb858 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -279,19 +279,13 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou rbv } -fn late_arg_as_bound_arg<'tcx>( - tcx: TyCtxt<'tcx>, - param: &GenericParam<'tcx>, -) -> ty::BoundVariableKind { +fn late_arg_as_bound_arg<'tcx>(param: &GenericParam<'tcx>) -> ty::BoundVariableKind { let def_id = param.def_id.to_def_id(); - let name = tcx.item_name(def_id); match param.kind { GenericParamKind::Lifetime { .. } => { ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) } - GenericParamKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) - } + GenericParamKind::Type { .. } => ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id)), GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, } } @@ -305,7 +299,7 @@ fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVaria ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(param.def_id)) } ty::GenericParamDefKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id)) } ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, } @@ -386,7 +380,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| { let arg = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param); bound_vars.insert(param.def_id, arg); - late_arg_as_bound_arg(self.tcx, param) + late_arg_as_bound_arg(param) }); binders.extend(binders_iter); @@ -485,7 +479,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .map(|(late_bound_idx, param)| { ( (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), - late_arg_as_bound_arg(self.tcx, param), + late_arg_as_bound_arg(param), ) }) .unzip(); @@ -718,7 +712,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .map(|(late_bound_idx, param)| { ( (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), - late_arg_as_bound_arg(self.tcx, param), + late_arg_as_bound_arg(param), ) }) .unzip(); @@ -748,7 +742,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .map(|(late_bound_idx, param)| { ( (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), - late_arg_as_bound_arg(self.tcx, param), + late_arg_as_bound_arg(param), ) }) .unzip(); @@ -957,7 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .map(|(late_bound_idx, param)| { ( (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), - late_arg_as_bound_arg(self.tcx, param), + late_arg_as_bound_arg(param), ) }) .unzip(); @@ -1171,7 +1165,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { matches!(param.kind, GenericParamKind::Lifetime { .. }) && self.tcx.is_late_bound(param.hir_id) }) - .map(|param| late_arg_as_bound_arg(self.tcx, param)) + .map(|param| late_arg_as_bound_arg(param)) .collect(); self.record_late_bound_vars(hir_id, binders); let scope = Scope::Binder { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 1221ca15b7be..f90418eb8649 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -1050,7 +1050,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 't } ty::Bound(db, bt) if *db >= self.depth => { self.vars.insert(match bt.kind { - ty::BoundTyKind::Param(def_id, _) => def_id, + ty::BoundTyKind::Param(def_id) => def_id, ty::BoundTyKind::Anon => { let reported = self .cx diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 1de5a15ad003..434375060dff 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2067,10 +2067,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { - let name = tcx.item_name(def_id.to_def_id()); let br = ty::BoundTy { var: ty::BoundVar::from_u32(index), - kind: ty::BoundTyKind::Param(def_id.to_def_id(), name), + kind: ty::BoundTyKind::Param(def_id.to_def_id()), }; Ty::new_bound(tcx, debruijn, br) } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index c83380447930..c17281deff4e 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -215,7 +215,7 @@ where let arg: ty::BoundVariableKind = arg; match arg { ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) - | ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, _)) => { + | ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id)) => { added.push(def_id); let unique = self.in_scope_parameters.insert(def_id, ParamKind::Late); assert_eq!(unique, None); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ad4639844597..9cb049cd6221 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -795,9 +795,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::BoundTyKind::Anon => { rustc_type_ir::debug_bound_var(self, debruijn, bound_ty.var)? } - ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() { + ty::BoundTyKind::Param(def_id) => match self.should_print_verbose() { true => p!(write("{:?}", ty.kind())), - false => p!(write("{s}")), + false => p!(write("{}", self.tcx().item_name(def_id))), }, }, ty::Adt(def, args) => { @@ -824,9 +824,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } ty::Placeholder(placeholder) => match placeholder.bound.kind { ty::BoundTyKind::Anon => p!(write("{placeholder:?}")), - ty::BoundTyKind::Param(_, name) => match self.should_print_verbose() { + ty::BoundTyKind::Param(def_id) => match self.should_print_verbose() { true => p!(write("{:?}", ty.kind())), - false => p!(write("{name}")), + false => p!(write("{}", self.tcx().item_name(def_id))), }, }, ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 3a0bd1fb0294..049f85ed6517 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -183,7 +183,7 @@ impl fmt::Debug for ty::BoundTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.kind { ty::BoundTyKind::Anon => write!(f, "{:?}", self.var), - ty::BoundTyKind::Param(_, sym) => write!(f, "{sym:?}"), + ty::BoundTyKind::Param(def_id) => write!(f, "{def_id:?}"), } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ae3b2a90e6aa..8bb3b3f1263f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -400,7 +400,7 @@ impl<'tcx> rustc_type_ir::inherent::BoundVarLike> for BoundTy { #[derive(HashStable)] pub enum BoundTyKind { Anon, - Param(DefId, Symbol), + Param(DefId), } impl From for BoundTy { diff --git a/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs index 67c0020bd178..37c93af392ec 100644 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs +++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs @@ -7,7 +7,6 @@ use rustc_middle::ty::{self as rustc_ty, Const as InternalConst, Ty as InternalTy}; use rustc_smir::Tables; -use rustc_span::Symbol; use stable_mir::abi::Layout; use stable_mir::compiler_interface::BridgeTys; use stable_mir::mir::alloc::AllocId; @@ -446,10 +445,9 @@ impl RustcInternal for BoundVariableKind { match self { BoundVariableKind::Ty(kind) => rustc_ty::BoundVariableKind::Ty(match kind { BoundTyKind::Anon => rustc_ty::BoundTyKind::Anon, - BoundTyKind::Param(def, symbol) => rustc_ty::BoundTyKind::Param( - def.0.internal(tables, tcx), - Symbol::intern(symbol), - ), + BoundTyKind::Param(def, _symbol) => { + rustc_ty::BoundTyKind::Param(def.0.internal(tables, tcx)) + } }), BoundVariableKind::Region(kind) => rustc_ty::BoundVariableKind::Region(match kind { BoundRegionKind::BrAnon => rustc_ty::BoundRegionKind::Anon, diff --git a/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs index c9cbc9329db3..596c8b96bfcd 100644 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs @@ -291,14 +291,14 @@ impl<'tcx> Stable<'tcx> for ty::BoundTyKind { fn stable<'cx>( &self, tables: &mut Tables<'cx, BridgeTys>, - _: &SmirCtxt<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, ) -> Self::T { use stable_mir::ty::BoundTyKind; match self { ty::BoundTyKind::Anon => BoundTyKind::Anon, - ty::BoundTyKind::Param(def_id, symbol) => { - BoundTyKind::Param(tables.param_def(*def_id), symbol.to_string()) + ty::BoundTyKind::Param(def_id) => { + BoundTyKind::Param(tables.param_def(*def_id), cx.tcx.item_name(*def_id).to_string()) } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 68dea4616f9d..5cd5c434521c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2221,7 +2221,7 @@ pub(crate) fn clean_middle_ty<'tcx>( } ty::Bound(_, ref ty) => match ty.kind { - ty::BoundTyKind::Param(_, name) => Generic(name), + ty::BoundTyKind::Param(def_id) => Generic(cx.tcx.item_name(def_id)), ty::BoundTyKind::Anon => panic!("unexpected anonymous bound type variable"), }, @@ -3192,7 +3192,8 @@ fn clean_bound_vars<'tcx>( None } } - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id)) => { + let name = cx.tcx.item_name(def_id); Some(GenericParamDef { name, def_id, From d79b669b09909e1280af940f7b2739d018e14327 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 25 Jun 2025 17:07:18 +0000 Subject: [PATCH 15/68] Fix pretty printing of placeholder types --- .../src/infer/region_constraints/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 18 +++++++------ .../rustc_middle/src/ty/structural_impls.rs | 2 +- .../src/error_reporting/infer/region.rs | 12 ++++----- ...laceholders-dont-outlive-static.bad.stderr | 8 +++--- ...aceholders-dont-outlive-static.good.stderr | 8 +++--- .../placeholders-dont-outlive-static.rs | 2 +- .../type-match-with-late-bound.stderr | 25 ++++++++++--------- 8 files changed, 41 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index f4cb73685d52..a1744b4df80f 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -655,7 +655,7 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { GenericKind::Param(ref p) => write!(f, "{p}"), - GenericKind::Placeholder(ref p) => write!(f, "{p:?}"), + GenericKind::Placeholder(ref p) => write!(f, "{p}"), GenericKind::Alias(ref p) => write!(f, "{p}"), } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 9cb049cd6221..d991b3126e73 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -822,13 +822,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::Alias(ty::Projection | ty::Inherent | ty::Free, ref data) => { p!(print(data)) } - ty::Placeholder(placeholder) => match placeholder.bound.kind { - ty::BoundTyKind::Anon => p!(write("{placeholder:?}")), - ty::BoundTyKind::Param(def_id) => match self.should_print_verbose() { - true => p!(write("{:?}", ty.kind())), - false => p!(write("{}", self.tcx().item_name(def_id))), - }, - }, + ty::Placeholder(placeholder) => p!(print(placeholder)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // We use verbose printing in 'NO_QUERIES' mode, to // avoid needing to call `predicates_of`. This should @@ -3373,6 +3367,16 @@ define_print_and_forward_display! { p!(write("{}", self.name)) } + ty::PlaceholderType { + match self.bound.kind { + ty::BoundTyKind::Anon => p!(write("{self:?}")), + ty::BoundTyKind::Param(def_id) => match cx.should_print_verbose() { + true => p!(write("{self:?}")), + false => p!(write("{}", cx.tcx().item_name(def_id))), + }, + } + } + ty::ParamConst { p!(write("{}", self.name)) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 049f85ed6517..af9c98bd87d0 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -272,7 +272,6 @@ TrivialTypeTraversalImpls! { crate::ty::BoundVar, crate::ty::InferConst, crate::ty::Placeholder, - crate::ty::Placeholder, crate::ty::Placeholder, crate::ty::UserTypeAnnotationIndex, crate::ty::ValTree<'tcx>, @@ -303,6 +302,7 @@ TrivialTypeTraversalAndLiftImpls! { // tidy-alphabetical-start crate::ty::ParamConst, crate::ty::ParamTy, + crate::ty::Placeholder, crate::ty::instance::ReifyReason, rustc_hir::def_id::DefId, // tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index f9de3e96d790..72f08777f9d8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -713,14 +713,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let labeled_user_string = match bound_kind { - GenericKind::Param(ref p) => format!("the parameter type `{p}`"), - GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"), - GenericKind::Alias(ref p) => match p.kind(self.tcx) { + GenericKind::Param(_) => format!("the parameter type `{bound_kind}`"), + GenericKind::Placeholder(_) => format!("the placeholder type `{bound_kind}`"), + GenericKind::Alias(p) => match p.kind(self.tcx) { ty::Projection | ty::Inherent => { - format!("the associated type `{p}`") + format!("the associated type `{bound_kind}`") } - ty::Free => format!("the type alias `{p}`"), - ty::Opaque => format!("the opaque type `{p}`"), + ty::Free => format!("the type alias `{bound_kind}`"), + ty::Opaque => format!("the opaque type `{bound_kind}`"), }, }; diff --git a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.bad.stderr b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.bad.stderr index 7dd383b1e7a5..d51927aaa342 100644 --- a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.bad.stderr +++ b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.bad.stderr @@ -7,19 +7,19 @@ LL | #![feature(non_lifetime_binders)] = note: see issue #108185 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0310]: the placeholder type `!1_"T"` may not live long enough +error[E0310]: the placeholder type `T` may not live long enough --> $DIR/placeholders-dont-outlive-static.rs:13:5 | LL | foo(); | ^^^^^ | | - | the placeholder type `!1_"T"` must be valid for the static lifetime... + | the placeholder type `T` must be valid for the static lifetime... | ...so that the type `T` will meet its required lifetime bounds | help: consider adding an explicit lifetime bound | -LL | fn bad() where !1_"T": 'static { - | +++++++++++++++++++++ +LL | fn bad() where T: 'static { + | ++++++++++++++++ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.good.stderr b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.good.stderr index b4f00978ada8..bc1a19923997 100644 --- a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.good.stderr +++ b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.good.stderr @@ -7,19 +7,19 @@ LL | #![feature(non_lifetime_binders)] = note: see issue #108185 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0310]: the placeholder type `!1_"T"` may not live long enough +error[E0310]: the placeholder type `T` may not live long enough --> $DIR/placeholders-dont-outlive-static.rs:19:5 | LL | foo(); | ^^^^^ | | - | the placeholder type `!1_"T"` must be valid for the static lifetime... + | the placeholder type `T` must be valid for the static lifetime... | ...so that the type `T` will meet its required lifetime bounds | help: consider adding an explicit lifetime bound | -LL | fn good() where for T: 'static, !1_"T": 'static { - | +++++++++++++++++ +LL | fn good() where for T: 'static, T: 'static { + | ++++++++++++ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.rs b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.rs index e87863ab2512..3133d6aeedce 100644 --- a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.rs +++ b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.rs @@ -11,7 +11,7 @@ fn foo() where for T: 'static {} #[cfg(bad)] fn bad() { foo(); - //[bad]~^ ERROR the placeholder type `!1_"T"` may not live long enough + //[bad]~^ ERROR the placeholder type `T` may not live long enough } #[cfg(good)] diff --git a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr index 9d54675c260b..15902bf16de5 100644 --- a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr +++ b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr @@ -7,11 +7,11 @@ LL | #![feature(non_lifetime_binders)] = note: see issue #108185 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0309]: the placeholder type `!1_"F"` may not live long enough +error[E0309]: the placeholder type `F` may not live long enough --> $DIR/type-match-with-late-bound.rs:8:1 | LL | async fn walk2<'a, T: 'a>(_: T) - | ^ -- the placeholder type `!1_"F"` must be valid for the lifetime `'a` as defined here... + | ^ -- the placeholder type `F` must be valid for the lifetime `'a` as defined here... | _| | | LL | | where @@ -25,36 +25,37 @@ LL | for F: 'a, | ^^ help: consider adding an explicit lifetime bound | -LL | for F: 'a, !1_"F": 'a - | ++++++++++ +LL | for F: 'a, F: 'a + | +++++ -error[E0309]: the placeholder type `!1_"F"` may not live long enough +error[E0309]: the placeholder type `F` may not live long enough --> $DIR/type-match-with-late-bound.rs:11:1 | LL | async fn walk2<'a, T: 'a>(_: T) - | -- the placeholder type `!1_"F"` must be valid for the lifetime `'a` as defined here... + | -- the placeholder type `F` must be valid for the lifetime `'a` as defined here... ... LL | {} | ^^ ...so that the type `F` will meet its required lifetime bounds | help: consider adding an explicit lifetime bound | -LL | for F: 'a, !1_"F": 'a - | ++++++++++ +LL | for F: 'a, F: 'a + | +++++ -error[E0309]: the placeholder type `!2_"F"` may not live long enough +error[E0309]: the placeholder type `F` may not live long enough --> $DIR/type-match-with-late-bound.rs:11:1 | LL | async fn walk2<'a, T: 'a>(_: T) - | -- the placeholder type `!2_"F"` must be valid for the lifetime `'a` as defined here... + | -- the placeholder type `F` must be valid for the lifetime `'a` as defined here... ... LL | {} | ^^ ...so that the type `F` will meet its required lifetime bounds | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit lifetime bound | -LL | for F: 'a, !2_"F": 'a - | ++++++++++ +LL | for F: 'a, F: 'a + | +++++ error: aborting due to 3 previous errors; 1 warning emitted From 0ad96c1e1f12a21f4cb734acd76d94a27066700e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 25 Jun 2025 22:32:23 +0000 Subject: [PATCH 16/68] Fix elided lifetimes in rustdoc --- compiler/rustc_borrowck/src/diagnostics/region_name.rs | 6 +++--- compiler/rustc_hir_analysis/src/coherence/builtin.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_middle/src/ty/region.rs | 4 ++-- .../src/error_reporting/infer/region.rs | 2 +- .../rustc_trait_selection/src/errors/note_and_explain.rs | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 439e4c7328a8..edd14d155f66 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -289,7 +289,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { debug!("give_region_a_name: error_region = {:?}", error_region); match error_region.kind() { - ty::ReEarlyParam(ebr) => ebr.has_name().then(|| { + ty::ReEarlyParam(ebr) => ebr.is_named().then(|| { let def_id = tcx.generics_of(self.mir_def_id()).region_param(ebr, tcx).def_id; let span = tcx.hir_span_if_local(def_id).unwrap_or(DUMMY_SP); RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyParamRegion(span) } @@ -895,7 +895,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let ty::ReEarlyParam(region) = self.to_error_region(fr)?.kind() else { return None; }; - if region.has_name() { + if region.is_named() { return None; }; @@ -930,7 +930,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let ty::ReEarlyParam(region) = self.to_error_region(fr)?.kind() else { return None; }; - if region.has_name() { + if region.is_named() { return None; }; diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 65bc441a473e..8356a0af63c3 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -654,7 +654,7 @@ fn infringing_fields_error<'tcx>( .or_default() .push(origin.span()); if let ty::RegionKind::ReEarlyParam(ebr) = b.kind() - && ebr.has_name() + && ebr.is_named() { bounds.push((b.to_string(), a.to_string(), None)); } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a92d6fe3916d..f1b16ea54e63 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -474,7 +474,7 @@ impl<'tcx> rustc_type_ir::Flags for Ty<'tcx> { impl EarlyParamRegion { /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). - pub fn has_name(&self) -> bool { + pub fn is_named(&self) -> bool { self.name != kw::UnderscoreLifetime } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index d991b3126e73..1dba4a7b040a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2545,7 +2545,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions; match region.kind() { - ty::ReEarlyParam(ref data) => data.has_name(), + ty::ReEarlyParam(ref data) => data.is_named(), ty::ReLateParam(ty::LateParamRegion { kind, .. }) => kind.is_named(self.tcx), ty::ReBound(_, ty::BoundRegion { kind: br, .. }) diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index c598cd21fc83..ab6316c94840 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -165,7 +165,7 @@ impl<'tcx> Region<'tcx> { pub fn get_name(self, tcx: TyCtxt<'tcx>) -> Option { match self.kind() { - ty::ReEarlyParam(ebr) => Some(ebr.name), + ty::ReEarlyParam(ebr) => ebr.is_named().then_some(ebr.name), ty::ReBound(_, br) => br.kind.get_name(tcx), ty::ReLateParam(fr) => fr.kind.get_name(tcx), ty::ReStatic => Some(kw::StaticLifetime), @@ -184,7 +184,7 @@ impl<'tcx> Region<'tcx> { /// Is this region named by the user? pub fn has_name(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { - ty::ReEarlyParam(ebr) => ebr.has_name(), + ty::ReEarlyParam(ebr) => ebr.is_named(), ty::ReBound(_, br) => br.kind.is_named(tcx), ty::ReLateParam(fr) => fr.kind.is_named(tcx), ty::ReStatic => true, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 72f08777f9d8..7b11d61cf99a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -1109,7 +1109,7 @@ fn msg_span_from_named_region<'tcx>( ty::ReEarlyParam(br) => { let param_def_id = tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id; let span = tcx.def_span(param_def_id); - let text = if br.has_name() { + let text = if br.is_named() { format!("the lifetime `{}` as defined here", br.name) } else { "the anonymous lifetime as defined here".to_string() diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index 0a1cdb16f5a0..3471036256db 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -32,7 +32,7 @@ impl<'a> DescriptionCtx<'a> { } else { tcx.def_span(scope) }; - if br.has_name() { + if br.is_named() { (Some(span), "as_defined", br.name.to_string()) } else { (Some(span), "as_defined_anon", String::new()) From dc8cac8e8d1e7e8f9535bd53c4aa7d70cce617fb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 4 Jul 2025 18:09:11 +0000 Subject: [PATCH 17/68] Nits --- .../rustc_borrowck/src/diagnostics/conflict_errors.rs | 2 +- compiler/rustc_borrowck/src/diagnostics/region_errors.rs | 2 +- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 4 +--- compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs | 2 +- compiler/rustc_middle/src/ty/region.rs | 2 +- .../infer/nice_region_error/named_anon_conflict.rs | 8 +++----- .../infer/nice_region_error/placeholder_error.rs | 4 ++-- .../infer/nice_region_error/static_impl_trait.rs | 4 ++-- .../infer/nice_region_error/trait_impl_difference.rs | 2 +- .../src/error_reporting/infer/region.rs | 4 ++-- 11 files changed, 16 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 3ec33e5e5c88..040a0607db56 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4195,7 +4195,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let return_ty = sig.output(); match return_ty.skip_binder().kind() { ty::Ref(return_region, _, _) - if return_region.has_name(self.infcx.tcx) && !is_closure => + if return_region.is_named(self.infcx.tcx) && !is_closure => { // This is case 1 from above, return type is a named reference so we need to // search for relevant arguments. diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index d14f2417ea7c..b130cf8ed276 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -853,7 +853,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }; let lifetime = - if f.has_name(self.infcx.tcx) { fr_name.name } else { kw::UnderscoreLifetime }; + if f.is_named(self.infcx.tcx) { fr_name.name } else { kw::UnderscoreLifetime }; let arg = match param.param.pat.simple_ident() { Some(simple_ident) => format!("argument `{simple_ident}`"), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 089ba14bcf71..0a3e018b79a4 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2338,7 +2338,7 @@ fn lint_redundant_lifetimes<'tcx>( lifetimes.push(ty::Region::new_late_param(tcx, owner_id.to_def_id(), kind)); } } - lifetimes.retain(|candidate| candidate.has_name(tcx)); + lifetimes.retain(|candidate| candidate.is_named(tcx)); // Keep track of lifetimes which have already been replaced with other lifetimes. // This makes sure that if `'a = 'b = 'c`, we don't say `'c` should be replaced by diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f99cfc7cd506..478c4c13fac2 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -578,9 +578,7 @@ fn get_new_lifetime_name<'tcx>( let existing_lifetimes = tcx .collect_referenced_late_bound_regions(poly_trait_ref) .into_iter() - .filter_map(|lt| { - if let Some(name) = lt.get_name(tcx) { Some(name.as_str().to_string()) } else { None } - }) + .filter_map(|lt| lt.get_name(tcx).map(|name| name.as_str().to_string())) .chain(generics.params.iter().filter_map(|param| { if let hir::GenericParamKind::Lifetime { .. } = ¶m.kind { Some(param.name.ident().as_str().to_string()) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index f90418eb8649..4784cfb5235b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, }; -use rustc_span::{ErrorGuaranteed, Ident, Span, kw}; +use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use rustc_trait_selection::traits; use smallvec::SmallVec; use tracing::{debug, instrument}; diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index ab6316c94840..51be93d9a72a 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -182,7 +182,7 @@ impl<'tcx> Region<'tcx> { } /// Is this region named by the user? - pub fn has_name(self, tcx: TyCtxt<'tcx>) -> bool { + pub fn is_named(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { ty::ReEarlyParam(ebr) => ebr.is_named(), ty::ReBound(_, br) => br.kind.is_named(tcx), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs index 679adcae768a..73a04d78519c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs @@ -25,12 +25,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // only introduced anonymous regions in parameters) as well as a // version new_ty of its type where the anonymous region is replaced // with the named one. - let (named, anon, anon_param_info, region_info) = if sub.has_name(self.tcx()) + let (named, anon, anon_param_info, region_info) = if sub.is_named(self.tcx()) && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sup) && let Some(anon_param_info) = self.find_param_with_region(sup, sub) { (sub, sup, anon_param_info, region_info) - } else if sup.has_name(self.tcx()) + } else if sup.is_named(self.tcx()) && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sub) && let Some(anon_param_info) = self.find_param_with_region(sub, sup) { @@ -56,9 +56,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let scope_def_id = region_info.scope; let is_impl_item = region_info.is_impl_item; - if !anon_param_info.kind.is_named(self.tcx()) { - // Anon region - } else { + if anon_param_info.kind.is_named(self.tcx()) { /* not an anonymous region */ debug!("try_report_named_anon_conflict: not an anonymous region"); return None; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index d4e6a33b5cec..64fc365c44a6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -164,7 +164,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sub_region @ Region(Interned(RePlaceholder(_), _)), sup_region, )) => self.try_report_trait_placeholder_mismatch( - (!sup_region.has_name(self.tcx())).then_some(*sup_region), + (!sup_region.is_named(self.tcx())).then_some(*sup_region), cause, Some(*sub_region), None, @@ -176,7 +176,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sub_region, sup_region @ Region(Interned(RePlaceholder(_), _)), )) => self.try_report_trait_placeholder_mismatch( - (!sub_region.has_name(self.tcx())).then_some(*sub_region), + (!sub_region.is_named(self.tcx())).then_some(*sub_region), cause, None, Some(*sup_region), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 16b2e63ea776..3edc365c886e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let param = self.find_param_with_region(*sup_r, *sub_r)?; let simple_ident = param.param.pat.simple_ident(); let lifetime_name = - if sup_r.has_name(self.tcx()) { sup_r.to_string() } else { "'_".to_owned() }; + if sup_r.is_named(self.tcx()) { sup_r.to_string() } else { "'_".to_owned() }; let (mention_influencer, influencer_point) = if sup_origin.span().overlaps(param.param_ty_span) { @@ -100,7 +100,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // We don't need a note, it's already at the end, it can be shown as a `span_label`. require_span_as_label: (!require_as_note).then_some(require_span), - has_lifetime: sup_r.has_name(self.tcx()), + has_lifetime: sup_r.is_named(self.tcx()), lifetime: lifetime_name.clone(), has_param_name: simple_ident.is_some(), param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index 422b9cfdd045..772a7f013323 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -76,7 +76,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { impl<'tcx> ty::TypeVisitor> for HighlightBuilder<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) { - if !r.has_name(self.tcx) && self.counter <= 3 { + if !r.is_named(self.tcx) && self.counter <= 3 { self.highlight.highlighting_region(r, self.counter); self.counter += 1; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 7b11d61cf99a..f3441a8d72aa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -729,7 +729,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .dcx() .struct_span_err(span, format!("{labeled_user_string} may not live long enough")); err.code(match sub.kind() { - ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name(self.tcx) => E0309, + ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.is_named(self.tcx) => E0309, ty::ReStatic => E0310, _ => E0311, }); @@ -877,7 +877,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let (lifetime_def_id, lifetime_scope) = match self.tcx.is_suitable_region(generic_param_scope, lifetime) { - Some(info) if !lifetime.has_name(self.tcx) => { + Some(info) if !lifetime.is_named(self.tcx) => { (info.region_def_id.expect_local(), info.scope) } _ => return lifetime.get_name_or_anon(self.tcx).to_string(), From 4e615272bf5fc1331b5389c35893c1744dfc46f0 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 4 Jul 2025 12:12:07 -0700 Subject: [PATCH 18/68] Address PR feedback --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 7 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 86 +++++++++++-------- tests/codegen/intrinsics/transmute.rs | 14 +-- 3 files changed, 59 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 4b1c689a0106..568c54c65706 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -355,12 +355,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { self.val } else if field.size == self.layout.size { assert_eq!(offset.bytes(), 0); - fx.codegen_transmute_operand(bx, *self, field).unwrap_or_else(|| { - bug!( - "Expected `codegen_transmute_operand` to handle equal-size \ - field {i:?} projection from {self:?} to {field:?}" - ) - }) + fx.codegen_transmute_operand(bx, *self, field) } else { let (in_scalar, imm) = match (self.val, self.layout.backend_repr) { // Extract a scalar component from a pair. diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 589405e885fb..f7e8d5dcab26 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -188,6 +188,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + /// Transmutes the `src` value to the destination type by writing it to `dst`. + /// + /// See also [`Self::codegen_transmute_operand`] for cases that can be done + /// without needing a pre-allocated place for the destination. fn codegen_transmute( &mut self, bx: &mut Bx, @@ -198,31 +202,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert!(src.layout.is_sized()); assert!(dst.layout.is_sized()); - if src.layout.size == dst.layout.size { + if src.layout.size != dst.layout.size + || src.layout.is_uninhabited() + || dst.layout.is_uninhabited() + { + // These cases are all UB to actually hit, so don't emit code for them. + // (The size mismatches are reachable via `transmute_unchecked`.) + // We can't use unreachable because that's a terminator, and we + // need something that can be in the middle of a basic block. + bx.assume(bx.cx().const_bool(false)) + } else { // Since in this path we have a place anyway, we can store or copy to it, // making sure we use the destination place's alignment even if the // source would normally have a higher one. src.val.store(bx, dst.val.with_type(src.layout)); - } else if src.layout.is_uninhabited() { - bx.unreachable() - } else { - // Since this is known statically and the input could have existed - // without already having hit UB, might as well trap for it, even - // though it's UB so we *could* also unreachable it. - bx.abort(); } } - /// Attempts to transmute an `OperandValue` to another `OperandValue`. + /// Transmutes an `OperandValue` to another `OperandValue`. /// - /// Returns `None` for cases that can't work in that framework, such as for - /// `Immediate`->`Ref` that needs an `alloca` to get the location. + /// This is supported only for cases where [`Self::rvalue_creates_operand`] + /// returns `true`, and will ICE otherwise. (In particular, anything that + /// would need to `alloca` in order to return a `PlaceValue` will ICE, + /// expecting those to go via [`Self::codegen_transmute`] instead where + /// the destination place is already allocated.) pub(crate) fn codegen_transmute_operand( &mut self, bx: &mut Bx, operand: OperandRef<'tcx, Bx::Value>, cast: TyAndLayout<'tcx>, - ) -> Option> { + ) -> OperandValue { // Check for transmutes that are always UB. if operand.layout.size != cast.size || operand.layout.is_uninhabited() @@ -236,17 +245,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Because this transmute is UB, return something easy to generate, // since it's fine that later uses of the value are probably UB. - return Some(OperandValue::poison(bx, cast)); + return OperandValue::poison(bx, cast); } - Some(match (operand.val, operand.layout.backend_repr, cast.backend_repr) { + match (operand.val, operand.layout.backend_repr, cast.backend_repr) { _ if cast.is_zst() => OperandValue::ZeroSized, - (OperandValue::ZeroSized, _, _) => bug!(), - ( - OperandValue::Ref(source_place_val), - abi::BackendRepr::Memory { .. }, - abi::BackendRepr::Scalar(_) | abi::BackendRepr::ScalarPair(_, _), - ) => { + (_, _, abi::BackendRepr::Memory { .. }) => { + bug!("Cannot `codegen_transmute_operand` to non-ZST memory-ABI output {cast:?}"); + } + (OperandValue::Ref(source_place_val), abi::BackendRepr::Memory { .. }, _) => { assert_eq!(source_place_val.llextra, None); // The existing alignment is part of `source_place_val`, // so that alignment will be used, not `cast`'s. @@ -265,8 +272,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { transmute_scalar(bx, imm_a, in_a, out_a), transmute_scalar(bx, imm_b, in_b, out_b), ), - _ => return None, - }) + _ => bug!("Cannot `codegen_transmute_operand` {operand:?} to {cast:?}"), + } } /// Cast one of the immediates from an [`OperandValue::Immediate`] @@ -458,9 +465,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) } mir::CastKind::Transmute => { - self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| { - bug!("Unsupported transmute-as-operand of {operand:?} to {cast:?}"); - }) + self.codegen_transmute_operand(bx, operand, cast) } }; OperandRef { val, layout: cast } @@ -942,6 +947,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Pair(val, of) } + /// Returns `true` if the `rvalue` can be computed into an [`OperandRef`], + /// rather than needing a full `PlaceRef` for the assignment destination. + /// + /// This is used by the [`super::analyze`] code to decide which MIR locals + /// can stay as SSA values (as opposed to generating `alloca` slots for them). + /// As such, some paths here return `true` even where the specific rvalue + /// will not actually take the operand path because the result type is such + /// that it always gets an `alloca`, but where it's not worth re-checking the + /// layout in this code when the right thing will happen anyway. pub(crate) fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { match *rvalue { mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => { @@ -949,8 +963,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty)); let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty)); match (operand_layout.backend_repr, cast_layout.backend_repr) { - // If the input is in a place we can load immediates from there. - (abi::BackendRepr::Memory { .. }, abi::BackendRepr::Scalar(_) | abi::BackendRepr::ScalarPair(_, _)) => true, + // When the output will be in memory anyway, just use its place + // (instead of the operand path) unless it's the trivial ZST case. + (_, abi::BackendRepr::Memory { .. }) => cast_layout.is_zst(), + + // Otherwise (for a non-memory output) if the input is memory + // then we can just read the value from the place. + (abi::BackendRepr::Memory { .. }, _) => true, // When we have scalar immediates, we can only convert things // where the sizes match, to avoid endianness questions. @@ -959,18 +978,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (abi::BackendRepr::ScalarPair(a0, a1), abi::BackendRepr::ScalarPair(b0, b1)) => a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx), - // SIMD vectors don't work like normal immediates, - // so always send them through memory. - (abi::BackendRepr::SimdVector { .. }, _) | (_, abi::BackendRepr::SimdVector { .. }) => false, - - // When the output will be in memory anyway, just use its place - // (instead of the operand path) unless it's the trivial ZST case. - (_, abi::BackendRepr::Memory { .. }) => cast_layout.is_zst(), - // Mixing Scalars and ScalarPairs can get quite complicated when // padding and undef get involved, so leave that to the memory path. (abi::BackendRepr::Scalar(_), abi::BackendRepr::ScalarPair(_, _)) | (abi::BackendRepr::ScalarPair(_, _), abi::BackendRepr::Scalar(_)) => false, + + // SIMD vectors aren't worth the trouble of dealing with complex + // cases like from vectors of f32 to vectors of pointers or + // from fat pointers to vectors of u16. (See #143194 #110021 ...) + (abi::BackendRepr::SimdVector { .. }, _) | (_, abi::BackendRepr::SimdVector { .. }) => false, } } mir::Rvalue::Ref(..) | diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index 560ebcccdd02..e375724bc1bb 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -29,28 +29,28 @@ pub struct Aggregate8(u8); // CHECK-LABEL: @check_bigger_size( #[no_mangle] pub unsafe fn check_bigger_size(x: u16) -> u32 { - // CHECK: call void @llvm.trap + // CHECK: call void @llvm.assume(i1 false) transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_size( #[no_mangle] pub unsafe fn check_smaller_size(x: u32) -> u16 { - // CHECK: call void @llvm.trap + // CHECK: call void @llvm.assume(i1 false) transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_array( #[no_mangle] pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] { - // CHECK: call void @llvm.trap + // CHECK: call void @llvm.assume(i1 false) transmute_unchecked(x) } // CHECK-LABEL: @check_bigger_array( #[no_mangle] pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { - // CHECK: call void @llvm.trap + // CHECK: call void @llvm.assume(i1 false) transmute_unchecked(x) } @@ -73,9 +73,9 @@ pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call mir! { { RET = CastTransmute(x); From 9ad98f78d4485f6f7f9615c1961bb75b281bfceb Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 00:41:51 +0500 Subject: [PATCH 19/68] moved tests --- .../{not-copy-closure.rs => closures/closure-no-copy-mut-env.rs} | 0 .../closure-no-copy-mut-env.stderr} | 0 tests/ui/{ => fn}/auxiliary/delegate_macro.rs | 0 .../fn-arg-count-mismatch-diagnostics.rs} | 0 .../fn-arg-count-mismatch-diagnostics.stderr} | 0 .../null-pointer-optimization.rs} | 0 .../null-pointer-size-optimization.rs} | 0 tests/ui/{nul-characters.rs => str/nul-char-equivalence.rs} | 0 .../trait-object-method-receiver-rules.rs} | 0 .../trait-object-method-receiver-rules.stderr} | 0 .../trait-object-mut-to-shared-coercion.rs} | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{not-copy-closure.rs => closures/closure-no-copy-mut-env.rs} (100%) rename tests/ui/{not-copy-closure.stderr => closures/closure-no-copy-mut-env.stderr} (100%) rename tests/ui/{ => fn}/auxiliary/delegate_macro.rs (100%) rename tests/ui/{not-enough-arguments.rs => fn/fn-arg-count-mismatch-diagnostics.rs} (100%) rename tests/ui/{not-enough-arguments.stderr => fn/fn-arg-count-mismatch-diagnostics.stderr} (100%) rename tests/ui/{nullable-pointer-iotareduction.rs => layout/null-pointer-optimization.rs} (100%) rename tests/ui/{nullable-pointer-size.rs => layout/null-pointer-size-optimization.rs} (100%) rename tests/ui/{nul-characters.rs => str/nul-char-equivalence.rs} (100%) rename tests/ui/{object-pointer-types.rs => traits/trait-object-method-receiver-rules.rs} (100%) rename tests/ui/{object-pointer-types.stderr => traits/trait-object-method-receiver-rules.stderr} (100%) rename tests/ui/{objects-coerce-freeze-borrored.rs => traits/trait-object-mut-to-shared-coercion.rs} (100%) diff --git a/tests/ui/not-copy-closure.rs b/tests/ui/closures/closure-no-copy-mut-env.rs similarity index 100% rename from tests/ui/not-copy-closure.rs rename to tests/ui/closures/closure-no-copy-mut-env.rs diff --git a/tests/ui/not-copy-closure.stderr b/tests/ui/closures/closure-no-copy-mut-env.stderr similarity index 100% rename from tests/ui/not-copy-closure.stderr rename to tests/ui/closures/closure-no-copy-mut-env.stderr diff --git a/tests/ui/auxiliary/delegate_macro.rs b/tests/ui/fn/auxiliary/delegate_macro.rs similarity index 100% rename from tests/ui/auxiliary/delegate_macro.rs rename to tests/ui/fn/auxiliary/delegate_macro.rs diff --git a/tests/ui/not-enough-arguments.rs b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs similarity index 100% rename from tests/ui/not-enough-arguments.rs rename to tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs diff --git a/tests/ui/not-enough-arguments.stderr b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr similarity index 100% rename from tests/ui/not-enough-arguments.stderr rename to tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr diff --git a/tests/ui/nullable-pointer-iotareduction.rs b/tests/ui/layout/null-pointer-optimization.rs similarity index 100% rename from tests/ui/nullable-pointer-iotareduction.rs rename to tests/ui/layout/null-pointer-optimization.rs diff --git a/tests/ui/nullable-pointer-size.rs b/tests/ui/layout/null-pointer-size-optimization.rs similarity index 100% rename from tests/ui/nullable-pointer-size.rs rename to tests/ui/layout/null-pointer-size-optimization.rs diff --git a/tests/ui/nul-characters.rs b/tests/ui/str/nul-char-equivalence.rs similarity index 100% rename from tests/ui/nul-characters.rs rename to tests/ui/str/nul-char-equivalence.rs diff --git a/tests/ui/object-pointer-types.rs b/tests/ui/traits/trait-object-method-receiver-rules.rs similarity index 100% rename from tests/ui/object-pointer-types.rs rename to tests/ui/traits/trait-object-method-receiver-rules.rs diff --git a/tests/ui/object-pointer-types.stderr b/tests/ui/traits/trait-object-method-receiver-rules.stderr similarity index 100% rename from tests/ui/object-pointer-types.stderr rename to tests/ui/traits/trait-object-method-receiver-rules.stderr diff --git a/tests/ui/objects-coerce-freeze-borrored.rs b/tests/ui/traits/trait-object-mut-to-shared-coercion.rs similarity index 100% rename from tests/ui/objects-coerce-freeze-borrored.rs rename to tests/ui/traits/trait-object-mut-to-shared-coercion.rs From b28806da237176468ab2afae42b51fe43ad416e6 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 18:24:12 +0500 Subject: [PATCH 20/68] cleaned up some tests --- ...e-overflow.rs => alloc-shrink-oob-read.rs} | 10 +-- .../auto-trait-phantom-data-bounds.rs | 6 +- .../auto-trait-phantom-data-bounds.stderr | 18 ++--- .../binop/binop-evaluation-order-primitive.rs | 11 ++- tests/ui/coercion/basic-ptr-coercions.rs | 25 +++---- tests/ui/coercion/ptr-mutability-errors.rs | 3 +- .../ui/coercion/ptr-mutability-errors.stderr | 6 +- .../ui/io-checks/stdout-stderr-separation.rs | 3 + ...osure-parameter-type-inference-mismatch.rs | 26 +++++-- ...e-parameter-type-inference-mismatch.stderr | 28 +++---- ...type-error-diagnostic-in-complex-return.rs | 6 +- ...-error-diagnostic-in-complex-return.stderr | 2 +- tests/ui/parser/doc-comment-in-generic.rs | 10 ++- tests/ui/parser/raw/raw-string-literals.rs | Bin 848 -> 998 bytes .../pattern-ref-bindings-reassignment.rs | 26 ++++--- .../pattern-ref-bindings-reassignment.stderr | 5 +- .../print-calling-conventions.rs | 2 + tests/ui/std/fs-nul-byte-paths.rs | 20 +++-- .../nested-generic-traits-performance.rs | 69 +++++++++++------- 19 files changed, 168 insertions(+), 108 deletions(-) rename tests/ui/allocator/{allocator-reallocate-overflow.rs => alloc-shrink-oob-read.rs} (96%) diff --git a/tests/ui/allocator/allocator-reallocate-overflow.rs b/tests/ui/allocator/alloc-shrink-oob-read.rs similarity index 96% rename from tests/ui/allocator/allocator-reallocate-overflow.rs rename to tests/ui/allocator/alloc-shrink-oob-read.rs index 43810a469dfe..b9edfca3b7b5 100644 --- a/tests/ui/allocator/allocator-reallocate-overflow.rs +++ b/tests/ui/allocator/alloc-shrink-oob-read.rs @@ -1,13 +1,13 @@ +//! Sanity check for out-of-bounds read caused by copying the entire original buffer on shrink. +//! +//! Regression test for: + //@ run-pass -// alloc::heap::reallocate test. -// -// Ideally this would be revised to use no_std, but for now it serves -// well enough to reproduce (and illustrate) the bug from #16687. #![feature(allocator_api)] #![feature(slice_ptr_get)] -use std::alloc::{handle_alloc_error, Allocator, Global, Layout}; +use std::alloc::{Allocator, Global, Layout, handle_alloc_error}; use std::ptr::{self, NonNull}; fn main() { diff --git a/tests/ui/auto-traits/auto-trait-phantom-data-bounds.rs b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.rs index 0172ca335c32..6d1c4c87fad4 100644 --- a/tests/ui/auto-traits/auto-trait-phantom-data-bounds.rs +++ b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.rs @@ -1,9 +1,9 @@ -// Ensure that auto trait checks `T` when it encounters a `PhantomData` field, instead of -// checking the `PhantomData` type itself (which almost always implements an auto trait). +//! Ensure that auto trait checks `T` when it encounters a `PhantomData` field, instead of +//! checking the `PhantomData` type itself (which almost always implements an auto trait). #![feature(auto_traits)] -use std::marker::{PhantomData}; +use std::marker::PhantomData; unsafe auto trait Zen {} diff --git a/tests/ui/auto-traits/auto-trait-phantom-data-bounds.stderr b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.stderr index ffd4c3a0e1ad..56c2e8ff257b 100644 --- a/tests/ui/auto-traits/auto-trait-phantom-data-bounds.stderr +++ b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.stderr @@ -1,5 +1,5 @@ error[E0277]: `T` cannot be shared between threads safely - --> $DIR/phantom-auto-trait.rs:21:12 + --> $DIR/auto-trait-phantom-data-bounds.rs:21:12 | LL | is_zen(x) | ------ ^ `T` cannot be shared between threads safely @@ -7,19 +7,19 @@ LL | is_zen(x) | required by a bound introduced by this call | note: required for `&T` to implement `Zen` - --> $DIR/phantom-auto-trait.rs:10:24 + --> $DIR/auto-trait-phantom-data-bounds.rs:10:24 | LL | unsafe impl<'a, T: 'a> Zen for &'a T where T: Sync {} | ^^^ ^^^^^ ---- unsatisfied trait bound introduced here note: required because it appears within the type `PhantomData<&T>` --> $SRC_DIR/core/src/marker.rs:LL:COL note: required because it appears within the type `Guard<'_, T>` - --> $DIR/phantom-auto-trait.rs:12:8 + --> $DIR/auto-trait-phantom-data-bounds.rs:12:8 | LL | struct Guard<'a, T: 'a> { | ^^^^^ note: required by a bound in `is_zen` - --> $DIR/phantom-auto-trait.rs:18:14 + --> $DIR/auto-trait-phantom-data-bounds.rs:18:14 | LL | fn is_zen(_: T) {} | ^^^ required by this bound in `is_zen` @@ -29,7 +29,7 @@ LL | fn not_sync(x: Guard) { | +++++++++++++++++++ error[E0277]: `T` cannot be shared between threads safely - --> $DIR/phantom-auto-trait.rs:26:12 + --> $DIR/auto-trait-phantom-data-bounds.rs:26:12 | LL | is_zen(x) | ------ ^ `T` cannot be shared between threads safely @@ -37,24 +37,24 @@ LL | is_zen(x) | required by a bound introduced by this call | note: required for `&T` to implement `Zen` - --> $DIR/phantom-auto-trait.rs:10:24 + --> $DIR/auto-trait-phantom-data-bounds.rs:10:24 | LL | unsafe impl<'a, T: 'a> Zen for &'a T where T: Sync {} | ^^^ ^^^^^ ---- unsatisfied trait bound introduced here note: required because it appears within the type `PhantomData<&T>` --> $SRC_DIR/core/src/marker.rs:LL:COL note: required because it appears within the type `Guard<'_, T>` - --> $DIR/phantom-auto-trait.rs:12:8 + --> $DIR/auto-trait-phantom-data-bounds.rs:12:8 | LL | struct Guard<'a, T: 'a> { | ^^^^^ note: required because it appears within the type `Nested>` - --> $DIR/phantom-auto-trait.rs:16:8 + --> $DIR/auto-trait-phantom-data-bounds.rs:16:8 | LL | struct Nested(T); | ^^^^^^ note: required by a bound in `is_zen` - --> $DIR/phantom-auto-trait.rs:18:14 + --> $DIR/auto-trait-phantom-data-bounds.rs:18:14 | LL | fn is_zen(_: T) {} | ^^^ required by this bound in `is_zen` diff --git a/tests/ui/binop/binop-evaluation-order-primitive.rs b/tests/ui/binop/binop-evaluation-order-primitive.rs index d988e2ed14fc..33266d1c0478 100644 --- a/tests/ui/binop/binop-evaluation-order-primitive.rs +++ b/tests/ui/binop/binop-evaluation-order-primitive.rs @@ -1,6 +1,15 @@ +//! Test evaluation order in binary operations with primitive types. + //@ run-pass fn main() { let x = Box::new(0); - assert_eq!(0, *x + { drop(x); let _ = Box::new(main); 0 }); + assert_eq!( + 0, + *x + { + drop(x); + let _ = Box::new(main); + 0 + } + ); } diff --git a/tests/ui/coercion/basic-ptr-coercions.rs b/tests/ui/coercion/basic-ptr-coercions.rs index 8cc4120328e4..4229d1fb2745 100644 --- a/tests/ui/coercion/basic-ptr-coercions.rs +++ b/tests/ui/coercion/basic-ptr-coercions.rs @@ -1,29 +1,24 @@ +//! Tests basic pointer coercions + //@ run-pass -#![allow(unused_variables)] -// Test coercions between pointers which don't do anything fancy like unsizing. - - pub fn main() { // &mut -> & let x: &mut isize = &mut 42; - let x: &isize = x; - - let x: &isize = &mut 42; + let _x: &isize = x; + let _x: &isize = &mut 42; // & -> *const let x: &isize = &42; - let x: *const isize = x; - - let x: *const isize = &42; + let _x: *const isize = x; + let _x: *const isize = &42; // &mut -> *const let x: &mut isize = &mut 42; - let x: *const isize = x; - - let x: *const isize = &mut 42; + let _x: *const isize = x; + let _x: *const isize = &mut 42; // *mut -> *const - let x: *mut isize = &mut 42; - let x: *const isize = x; + let _x: *mut isize = &mut 42; + let _x: *const isize = x; } diff --git a/tests/ui/coercion/ptr-mutability-errors.rs b/tests/ui/coercion/ptr-mutability-errors.rs index 2549bd6f134d..391eaf0b9134 100644 --- a/tests/ui/coercion/ptr-mutability-errors.rs +++ b/tests/ui/coercion/ptr-mutability-errors.rs @@ -1,5 +1,4 @@ -// Test coercions between pointers which don't do anything fancy like unsizing. -// These are testing that we don't lose mutability when converting to raw pointers. +//! Tests that pointer coercions preserving mutability are enforced: //@ dont-require-annotations: NOTE diff --git a/tests/ui/coercion/ptr-mutability-errors.stderr b/tests/ui/coercion/ptr-mutability-errors.stderr index 8de41d2c3827..b4ded821c79c 100644 --- a/tests/ui/coercion/ptr-mutability-errors.stderr +++ b/tests/ui/coercion/ptr-mutability-errors.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/ptr-coercion.rs:9:25 + --> $DIR/ptr-mutability-errors.rs:8:25 | LL | let x: *mut isize = x; | ---------- ^ types differ in mutability @@ -10,7 +10,7 @@ LL | let x: *mut isize = x; found raw pointer `*const isize` error[E0308]: mismatched types - --> $DIR/ptr-coercion.rs:15:25 + --> $DIR/ptr-mutability-errors.rs:14:25 | LL | let x: *mut isize = &42; | ---------- ^^^ types differ in mutability @@ -21,7 +21,7 @@ LL | let x: *mut isize = &42; found reference `&isize` error[E0308]: mismatched types - --> $DIR/ptr-coercion.rs:21:25 + --> $DIR/ptr-mutability-errors.rs:20:25 | LL | let x: *mut isize = x; | ---------- ^ types differ in mutability diff --git a/tests/ui/io-checks/stdout-stderr-separation.rs b/tests/ui/io-checks/stdout-stderr-separation.rs index 4b356e2fe617..1bb3f16d3a1f 100644 --- a/tests/ui/io-checks/stdout-stderr-separation.rs +++ b/tests/ui/io-checks/stdout-stderr-separation.rs @@ -1,3 +1,6 @@ +//! Test that print!/println! output to stdout and eprint!/eprintln! +//! output to stderr correctly. + //@ run-pass //@ needs-subprocess diff --git a/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.rs b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.rs index d5f43df9d85c..1cd41114bbdd 100644 --- a/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.rs +++ b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.rs @@ -1,13 +1,25 @@ +//! Test closure parameter type inference and type mismatch errors. +//! +//! Related to . + //@ dont-require-annotations: NOTE -fn let_in(x: T, f: F) where F: FnOnce(T) {} +fn let_in(x: T, f: F) +where + F: FnOnce(T), +{ +} fn main() { - let_in(3u32, |i| { assert!(i == 3i32); }); - //~^ ERROR mismatched types - //~| NOTE expected `u32`, found `i32` + let_in(3u32, |i| { + assert!(i == 3i32); + //~^ ERROR mismatched types + //~| NOTE expected `u32`, found `i32` + }); - let_in(3i32, |i| { assert!(i == 3u32); }); - //~^ ERROR mismatched types - //~| NOTE expected `i32`, found `u32` + let_in(3i32, |i| { + assert!(i == 3u32); + //~^ ERROR mismatched types + //~| NOTE expected `i32`, found `u32` + }); } diff --git a/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.stderr b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.stderr index a6d673e61c69..c75e90ce4ef1 100644 --- a/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.stderr @@ -1,29 +1,29 @@ error[E0308]: mismatched types - --> $DIR/pptypedef.rs:6:37 + --> $DIR/closure-parameter-type-inference-mismatch.rs:15:22 | -LL | let_in(3u32, |i| { assert!(i == 3i32); }); - | - ^^^^ expected `u32`, found `i32` - | | - | expected because this is `u32` +LL | assert!(i == 3i32); + | - ^^^^ expected `u32`, found `i32` + | | + | expected because this is `u32` | help: change the type of the numeric literal from `i32` to `u32` | -LL - let_in(3u32, |i| { assert!(i == 3i32); }); -LL + let_in(3u32, |i| { assert!(i == 3u32); }); +LL - assert!(i == 3i32); +LL + assert!(i == 3u32); | error[E0308]: mismatched types - --> $DIR/pptypedef.rs:10:37 + --> $DIR/closure-parameter-type-inference-mismatch.rs:21:22 | -LL | let_in(3i32, |i| { assert!(i == 3u32); }); - | - ^^^^ expected `i32`, found `u32` - | | - | expected because this is `i32` +LL | assert!(i == 3u32); + | - ^^^^ expected `i32`, found `u32` + | | + | expected because this is `i32` | help: change the type of the numeric literal from `u32` to `i32` | -LL - let_in(3i32, |i| { assert!(i == 3u32); }); -LL + let_in(3i32, |i| { assert!(i == 3i32); }); +LL - assert!(i == 3u32); +LL + assert!(i == 3i32); | error: aborting due to 2 previous errors diff --git a/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.rs b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.rs index 50f1fe873cb5..6711d303eb3d 100644 --- a/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.rs +++ b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.rs @@ -1,4 +1,8 @@ -fn unrelated() -> Result<(), std::string::ParseError> { // #57664 +//! Regression test for . +//! Checks that compiler doesn't get confused by `?` operator and complex +//! return types when reporting type mismatches. + +fn unrelated() -> Result<(), std::string::ParseError> { let x = 0; match x { diff --git a/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.stderr b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.stderr index 34aaea5b70bb..38392fe99d66 100644 --- a/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.stderr +++ b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return-2.rs:9:41 + --> $DIR/type-error-diagnostic-in-complex-return.rs:13:41 | LL | let value: &bool = unsafe { &42 }; | ^^^ expected `&bool`, found `&{integer}` diff --git a/tests/ui/parser/doc-comment-in-generic.rs b/tests/ui/parser/doc-comment-in-generic.rs index 84abe875910c..2596496763ba 100644 --- a/tests/ui/parser/doc-comment-in-generic.rs +++ b/tests/ui/parser/doc-comment-in-generic.rs @@ -1,9 +1,13 @@ +//! Tests correct parsing of doc comments on generic parameters in traits. +//! Checks that compiler doesn't panic when processing this. + //@ check-pass -// Check that it doesn't panic when `Input` gets its visibility checked. #![crate_type = "lib"] pub trait Layer< - /// Hello. + /// Documentation for generic parameter. Input, -> {} +> +{ +} diff --git a/tests/ui/parser/raw/raw-string-literals.rs b/tests/ui/parser/raw/raw-string-literals.rs index 230184032952effa5fe5fc30f3aef8bd5570a652..2272f268b3675960d76334943606ee19261a548e 100644 GIT binary patch delta 234 zcmcb>_Kdw=UtdunB(=DtSfMPjC^NsbSRpOHD7RQ4KTV-1v0S0Jq$o2lT_Gp4B(*3p zrzt@Aq-mw#lb@HaP>@(sl3J7pvobBeNTDn $DIR/reassign-ref-mut.rs:12:5 + --> $DIR/pattern-ref-bindings-reassignment.rs:18:5 | LL | let &mut (ref a, ref mut b) = &mut one_two; | ----- first assignment to `a` +... LL | a = &three_four.0; | ^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/reassign-ref-mut.rs:14:5 + --> $DIR/pattern-ref-bindings-reassignment.rs:22:5 | LL | let &mut (ref a, ref mut b) = &mut one_two; | --------- first assignment to `b` diff --git a/tests/ui/print-request/print-calling-conventions.rs b/tests/ui/print-request/print-calling-conventions.rs index 302ed088142d..cefaa0d9b6fc 100644 --- a/tests/ui/print-request/print-calling-conventions.rs +++ b/tests/ui/print-request/print-calling-conventions.rs @@ -1,2 +1,4 @@ +//! Test that `--print calling-conventions` outputs all supported calling conventions. + //@ compile-flags: --print calling-conventions //@ build-pass diff --git a/tests/ui/std/fs-nul-byte-paths.rs b/tests/ui/std/fs-nul-byte-paths.rs index 5c37980127db..790123623474 100644 --- a/tests/ui/std/fs-nul-byte-paths.rs +++ b/tests/ui/std/fs-nul-byte-paths.rs @@ -1,18 +1,22 @@ -//@ run-pass +//! Test that `std::fs` functions properly reject paths containing NUL bytes. +//@ run-pass #![allow(deprecated)] //@ ignore-wasm32 no cwd //@ ignore-sgx no files -use std::fs; -use std::io; +use std::{fs, io}; fn assert_invalid_input(on: &str, result: io::Result) { fn inner(on: &str, result: io::Result<()>) { match result { Ok(()) => panic!("{} didn't return an error on a path with NUL", on), - Err(e) => assert!(e.kind() == io::ErrorKind::InvalidInput, - "{} returned a strange {:?} on a path with NUL", on, e.kind()), + Err(e) => assert!( + e.kind() == io::ErrorKind::InvalidInput, + "{} returned a strange {:?} on a path with NUL", + on, + e.kind() + ), } } inner(on, result.map(drop)) @@ -43,6 +47,8 @@ fn main() { assert_invalid_input("remove_dir", fs::remove_dir("\0")); assert_invalid_input("remove_dir_all", fs::remove_dir_all("\0")); assert_invalid_input("read_dir", fs::read_dir("\0")); - assert_invalid_input("set_permissions", - fs::set_permissions("\0", fs::metadata(".").unwrap().permissions())); + assert_invalid_input( + "set_permissions", + fs::set_permissions("\0", fs::metadata(".").unwrap().permissions()), + ); } diff --git a/tests/ui/typeck/nested-generic-traits-performance.rs b/tests/ui/typeck/nested-generic-traits-performance.rs index 29c278171a61..e029228c1b2e 100644 --- a/tests/ui/typeck/nested-generic-traits-performance.rs +++ b/tests/ui/typeck/nested-generic-traits-performance.rs @@ -1,65 +1,82 @@ +//! Test that deeply nested generic traits with complex bounds +//! don't cause excessive memory usage during type checking. +//! +//! Regression test for . + //@ run-pass -// Regression test for #31849: the problem here was actually a performance -// cliff, but I'm adding the test for reference. pub trait Upcast { fn upcast(self) -> T; } -impl Upcast<(T1, T2)> for (S1,S2) - where S1: Upcast, - S2: Upcast, +impl Upcast<(T1, T2)> for (S1, S2) +where + S1: Upcast, + S2: Upcast, { - fn upcast(self) -> (T1, T2) { (self.0.upcast(), self.1.upcast()) } + fn upcast(self) -> (T1, T2) { + (self.0.upcast(), self.1.upcast()) + } } -impl Upcast<()> for () -{ - fn upcast(self) -> () { () } +impl Upcast<()> for () { + fn upcast(self) -> () { + () + } } pub trait ToStatic { type Static: 'static; - fn to_static(self) -> Self::Static where Self: Sized; + fn to_static(self) -> Self::Static + where + Self: Sized; } impl ToStatic for (T, U) - where T: ToStatic, - U: ToStatic +where + T: ToStatic, + U: ToStatic, { type Static = (T::Static, U::Static); - fn to_static(self) -> Self::Static { (self.0.to_static(), self.1.to_static()) } + fn to_static(self) -> Self::Static { + (self.0.to_static(), self.1.to_static()) + } } -impl ToStatic for () -{ +impl ToStatic for () { type Static = (); - fn to_static(self) -> () { () } + fn to_static(self) -> () { + () + } } - trait Factory { type Output; fn build(&self) -> Self::Output; } -impl Factory for (S, T) - where S: Factory, - T: Factory, - S::Output: ToStatic, - ::Static: Upcast, +impl Factory for (S, T) +where + S: Factory, + T: Factory, + S::Output: ToStatic, + ::Static: Upcast, { type Output = (S::Output, T::Output); - fn build(&self) -> Self::Output { (self.0.build().to_static().upcast(), self.1.build()) } + fn build(&self) -> Self::Output { + (self.0.build().to_static().upcast(), self.1.build()) + } } impl Factory for () { type Output = (); - fn build(&self) -> Self::Output { () } + fn build(&self) -> Self::Output { + () + } } fn main() { - // More parens, more time. - let it = ((((((((((),()),()),()),()),()),()),()),()),()); + // Deeply nested tuple to trigger the original performance issue + let it = ((((((((((), ()), ()), ()), ()), ()), ()), ()), ()), ()); it.build(); } From 7f2e37fc5cdca01d4e140921f59fad398862606d Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 02:07:53 +0500 Subject: [PATCH 21/68] moved & deleted tests opeq.rs was removed as duplicating test logic in other tests --- .../compound-assign-by-ref.rs} | 0 .../fnonce-call-twice-error.rs} | 0 .../fnonce-call-twice-error.stderr} | 0 tests/ui/opeq.rs | 17 ----------------- .../oom-panic-unwind.rs} | 0 .../copy-requires-all-fields-copy.rs} | 0 .../copy-requires-all-fields-copy.stderr} | 0 .../direct-self-reference-occurs-check.rs} | 0 .../direct-self-reference-occurs-check.stderr} | 0 .../enum-self-reference-occurs-check.rs} | 0 .../enum-self-reference-occurs-check.stderr} | 0 .../infinite-type-occurs-check.rs} | 0 .../infinite-type-occurs-check.stderr} | 0 13 files changed, 17 deletions(-) rename tests/ui/{op-assign-builtins-by-ref.rs => binop/compound-assign-by-ref.rs} (100%) rename tests/ui/{once-cant-call-twice-on-heap.rs => closures/fnonce-call-twice-error.rs} (100%) rename tests/ui/{once-cant-call-twice-on-heap.stderr => closures/fnonce-call-twice-error.stderr} (100%) delete mode 100644 tests/ui/opeq.rs rename tests/ui/{oom_unwind.rs => panics/oom-panic-unwind.rs} (100%) rename tests/ui/{opt-in-copy.rs => traits/copy-requires-all-fields-copy.rs} (100%) rename tests/ui/{opt-in-copy.stderr => traits/copy-requires-all-fields-copy.stderr} (100%) rename tests/ui/{occurs-check.rs => type-inference/direct-self-reference-occurs-check.rs} (100%) rename tests/ui/{occurs-check.stderr => type-inference/direct-self-reference-occurs-check.stderr} (100%) rename tests/ui/{occurs-check-3.rs => type-inference/enum-self-reference-occurs-check.rs} (100%) rename tests/ui/{occurs-check-3.stderr => type-inference/enum-self-reference-occurs-check.stderr} (100%) rename tests/ui/{occurs-check-2.rs => type-inference/infinite-type-occurs-check.rs} (100%) rename tests/ui/{occurs-check-2.stderr => type-inference/infinite-type-occurs-check.stderr} (100%) diff --git a/tests/ui/op-assign-builtins-by-ref.rs b/tests/ui/binop/compound-assign-by-ref.rs similarity index 100% rename from tests/ui/op-assign-builtins-by-ref.rs rename to tests/ui/binop/compound-assign-by-ref.rs diff --git a/tests/ui/once-cant-call-twice-on-heap.rs b/tests/ui/closures/fnonce-call-twice-error.rs similarity index 100% rename from tests/ui/once-cant-call-twice-on-heap.rs rename to tests/ui/closures/fnonce-call-twice-error.rs diff --git a/tests/ui/once-cant-call-twice-on-heap.stderr b/tests/ui/closures/fnonce-call-twice-error.stderr similarity index 100% rename from tests/ui/once-cant-call-twice-on-heap.stderr rename to tests/ui/closures/fnonce-call-twice-error.stderr diff --git a/tests/ui/opeq.rs b/tests/ui/opeq.rs deleted file mode 100644 index 956ea0684fa7..000000000000 --- a/tests/ui/opeq.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass - -pub fn main() { - let mut x: isize = 1; - x *= 2; - println!("{}", x); - assert_eq!(x, 2); - x += 3; - println!("{}", x); - assert_eq!(x, 5); - x *= x; - println!("{}", x); - assert_eq!(x, 25); - x /= 5; - println!("{}", x); - assert_eq!(x, 5); -} diff --git a/tests/ui/oom_unwind.rs b/tests/ui/panics/oom-panic-unwind.rs similarity index 100% rename from tests/ui/oom_unwind.rs rename to tests/ui/panics/oom-panic-unwind.rs diff --git a/tests/ui/opt-in-copy.rs b/tests/ui/traits/copy-requires-all-fields-copy.rs similarity index 100% rename from tests/ui/opt-in-copy.rs rename to tests/ui/traits/copy-requires-all-fields-copy.rs diff --git a/tests/ui/opt-in-copy.stderr b/tests/ui/traits/copy-requires-all-fields-copy.stderr similarity index 100% rename from tests/ui/opt-in-copy.stderr rename to tests/ui/traits/copy-requires-all-fields-copy.stderr diff --git a/tests/ui/occurs-check.rs b/tests/ui/type-inference/direct-self-reference-occurs-check.rs similarity index 100% rename from tests/ui/occurs-check.rs rename to tests/ui/type-inference/direct-self-reference-occurs-check.rs diff --git a/tests/ui/occurs-check.stderr b/tests/ui/type-inference/direct-self-reference-occurs-check.stderr similarity index 100% rename from tests/ui/occurs-check.stderr rename to tests/ui/type-inference/direct-self-reference-occurs-check.stderr diff --git a/tests/ui/occurs-check-3.rs b/tests/ui/type-inference/enum-self-reference-occurs-check.rs similarity index 100% rename from tests/ui/occurs-check-3.rs rename to tests/ui/type-inference/enum-self-reference-occurs-check.rs diff --git a/tests/ui/occurs-check-3.stderr b/tests/ui/type-inference/enum-self-reference-occurs-check.stderr similarity index 100% rename from tests/ui/occurs-check-3.stderr rename to tests/ui/type-inference/enum-self-reference-occurs-check.stderr diff --git a/tests/ui/occurs-check-2.rs b/tests/ui/type-inference/infinite-type-occurs-check.rs similarity index 100% rename from tests/ui/occurs-check-2.rs rename to tests/ui/type-inference/infinite-type-occurs-check.rs diff --git a/tests/ui/occurs-check-2.stderr b/tests/ui/type-inference/infinite-type-occurs-check.stderr similarity index 100% rename from tests/ui/occurs-check-2.stderr rename to tests/ui/type-inference/infinite-type-occurs-check.stderr From 0f7a86bb2ac5b2ca57e5524127f9cbeb88f89a74 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 02:09:12 +0500 Subject: [PATCH 22/68] cleaned up some tests --- tests/ui/binop/compound-assign-by-ref.rs | 5 ++--- tests/ui/closures/fnonce-call-twice-error.rs | 7 +++---- tests/ui/closures/fnonce-call-twice-error.stderr | 12 ++++++------ tests/ui/panics/oom-panic-unwind.rs | 2 ++ tests/ui/traits/copy-requires-all-fields-copy.rs | 2 ++ tests/ui/traits/copy-requires-all-fields-copy.stderr | 4 ++-- .../direct-self-reference-occurs-check.rs | 4 ++++ .../direct-self-reference-occurs-check.stderr | 2 +- .../enum-self-reference-occurs-check.rs | 11 ++++++++--- .../enum-self-reference-occurs-check.stderr | 2 +- .../ui/type-inference/infinite-type-occurs-check.rs | 5 ++++- .../type-inference/infinite-type-occurs-check.stderr | 2 +- 12 files changed, 36 insertions(+), 22 deletions(-) diff --git a/tests/ui/binop/compound-assign-by-ref.rs b/tests/ui/binop/compound-assign-by-ref.rs index 73788da92321..e1f519a137fc 100644 --- a/tests/ui/binop/compound-assign-by-ref.rs +++ b/tests/ui/binop/compound-assign-by-ref.rs @@ -1,9 +1,8 @@ +//! Test compound assignment operators with reference right-hand side. + //@ run-pass fn main() { - // test compound assignment operators with ref as right-hand side, - // for each operator, with various types as operands. - // test AddAssign { let mut x = 3i8; diff --git a/tests/ui/closures/fnonce-call-twice-error.rs b/tests/ui/closures/fnonce-call-twice-error.rs index 3fd8c5cadca9..1662b7bddaae 100644 --- a/tests/ui/closures/fnonce-call-twice-error.rs +++ b/tests/ui/closures/fnonce-call-twice-error.rs @@ -1,16 +1,15 @@ -// Testing guarantees provided by once functions. -// This program would segfault if it were legal. +//! Test that `FnOnce` closures cannot be called twice. use std::sync::Arc; -fn foo(blk: F) { +fn foo(blk: F) { blk(); blk(); //~ ERROR use of moved value } fn main() { let x = Arc::new(true); - foo(move|| { + foo(move || { assert!(*x); drop(x); }); diff --git a/tests/ui/closures/fnonce-call-twice-error.stderr b/tests/ui/closures/fnonce-call-twice-error.stderr index 42697374115c..51d8a33dcd79 100644 --- a/tests/ui/closures/fnonce-call-twice-error.stderr +++ b/tests/ui/closures/fnonce-call-twice-error.stderr @@ -1,18 +1,18 @@ error[E0382]: use of moved value: `blk` - --> $DIR/once-cant-call-twice-on-heap.rs:8:5 + --> $DIR/fnonce-call-twice-error.rs:7:5 | -LL | fn foo(blk: F) { - | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait +LL | fn foo(blk: F) { + | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait LL | blk(); | ----- `blk` moved due to this call LL | blk(); | ^^^ value used here after move | note: `FnOnce` closures can only be called once - --> $DIR/once-cant-call-twice-on-heap.rs:6:10 + --> $DIR/fnonce-call-twice-error.rs:5:11 | -LL | fn foo(blk: F) { - | ^^^^^^^^ `F` is made to be an `FnOnce` closure here +LL | fn foo(blk: F) { + | ^^^^^^^^ `F` is made to be an `FnOnce` closure here LL | blk(); | ----- this value implements `FnOnce`, which causes it to be moved when called diff --git a/tests/ui/panics/oom-panic-unwind.rs b/tests/ui/panics/oom-panic-unwind.rs index be5e63d430b7..5974ad91406f 100644 --- a/tests/ui/panics/oom-panic-unwind.rs +++ b/tests/ui/panics/oom-panic-unwind.rs @@ -1,3 +1,5 @@ +//! Test that out-of-memory conditions trigger catchable panics with `-Z oom=panic`. + //@ compile-flags: -Z oom=panic //@ run-pass //@ no-prefer-dynamic diff --git a/tests/ui/traits/copy-requires-all-fields-copy.rs b/tests/ui/traits/copy-requires-all-fields-copy.rs index d0257b5745d8..8c829a7382b3 100644 --- a/tests/ui/traits/copy-requires-all-fields-copy.rs +++ b/tests/ui/traits/copy-requires-all-fields-copy.rs @@ -1,3 +1,5 @@ +//! Test that `Copy` cannot be implemented if any field doesn't implement `Copy`. + struct CantCopyThis; struct IWantToCopyThis { diff --git a/tests/ui/traits/copy-requires-all-fields-copy.stderr b/tests/ui/traits/copy-requires-all-fields-copy.stderr index 258ff16e6e48..1a9e1ada3663 100644 --- a/tests/ui/traits/copy-requires-all-fields-copy.stderr +++ b/tests/ui/traits/copy-requires-all-fields-copy.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/opt-in-copy.rs:7:15 + --> $DIR/copy-requires-all-fields-copy.rs:9:15 | LL | but_i_cant: CantCopyThis, | ------------------------ this field does not implement `Copy` @@ -8,7 +8,7 @@ LL | impl Copy for IWantToCopyThis {} | ^^^^^^^^^^^^^^^ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/opt-in-copy.rs:19:15 + --> $DIR/copy-requires-all-fields-copy.rs:21:15 | LL | ButICant(CantCopyThisEither), | ------------------ this field does not implement `Copy` diff --git a/tests/ui/type-inference/direct-self-reference-occurs-check.rs b/tests/ui/type-inference/direct-self-reference-occurs-check.rs index 638b9b6d7e4c..6e3d8251fc4f 100644 --- a/tests/ui/type-inference/direct-self-reference-occurs-check.rs +++ b/tests/ui/type-inference/direct-self-reference-occurs-check.rs @@ -1,3 +1,7 @@ +//! Test that occurs check prevents direct self-reference in variable assignment. +//! +//! Regression test for . + fn main() { let f; f = Box::new(f); diff --git a/tests/ui/type-inference/direct-self-reference-occurs-check.stderr b/tests/ui/type-inference/direct-self-reference-occurs-check.stderr index ea7c541abc13..6c522ffac1f7 100644 --- a/tests/ui/type-inference/direct-self-reference-occurs-check.stderr +++ b/tests/ui/type-inference/direct-self-reference-occurs-check.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow assigning `Box<_>` to `_` - --> $DIR/occurs-check.rs:3:18 + --> $DIR/direct-self-reference-occurs-check.rs:7:18 | LL | f = Box::new(f); | ^ diff --git a/tests/ui/type-inference/enum-self-reference-occurs-check.rs b/tests/ui/type-inference/enum-self-reference-occurs-check.rs index 377a043daf3f..2905868b8bfa 100644 --- a/tests/ui/type-inference/enum-self-reference-occurs-check.rs +++ b/tests/ui/type-inference/enum-self-reference-occurs-check.rs @@ -1,11 +1,16 @@ -// From Issue #778 +//! Test that occurs check prevents infinite types with enum self-references. +//! +//! Regression test for . + +enum Clam { + A(T), +} -enum Clam { A(T) } fn main() { let c; c = Clam::A(c); //~^ ERROR overflow assigning `Clam<_>` to `_` match c { - Clam::A::(_) => { } + Clam::A::(_) => {} } } diff --git a/tests/ui/type-inference/enum-self-reference-occurs-check.stderr b/tests/ui/type-inference/enum-self-reference-occurs-check.stderr index eb05c94957c9..3239be51a176 100644 --- a/tests/ui/type-inference/enum-self-reference-occurs-check.stderr +++ b/tests/ui/type-inference/enum-self-reference-occurs-check.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow assigning `Clam<_>` to `_` - --> $DIR/occurs-check-3.rs:6:17 + --> $DIR/enum-self-reference-occurs-check.rs:11:17 | LL | c = Clam::A(c); | ^ diff --git a/tests/ui/type-inference/infinite-type-occurs-check.rs b/tests/ui/type-inference/infinite-type-occurs-check.rs index 9289a8e870a1..b353824e931d 100644 --- a/tests/ui/type-inference/infinite-type-occurs-check.rs +++ b/tests/ui/type-inference/infinite-type-occurs-check.rs @@ -1,5 +1,8 @@ -fn main() { +//! Test that occurs check prevents infinite types during type inference. +//! +//! Regression test for . +fn main() { let f; let g; diff --git a/tests/ui/type-inference/infinite-type-occurs-check.stderr b/tests/ui/type-inference/infinite-type-occurs-check.stderr index 5f296967f30d..9cb8bb917962 100644 --- a/tests/ui/type-inference/infinite-type-occurs-check.stderr +++ b/tests/ui/type-inference/infinite-type-occurs-check.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow assigning `Box<_>` to `_` - --> $DIR/occurs-check-2.rs:6:9 + --> $DIR/infinite-type-occurs-check.rs:9:9 | LL | g = f; | ^ From 46ce66ff5c1627230d43a5b5d41592186f79ebc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 4 Jul 2025 21:24:42 +0200 Subject: [PATCH 23/68] Unify completion list between `x test tidy` and `x run generate-completions` --- src/bootstrap/src/core/build_steps/run.rs | 45 +++++++++++----------- src/bootstrap/src/core/build_steps/test.rs | 13 +++---- src/bootstrap/src/core/config/flags.rs | 10 ++++- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index b3104ae05e88..b2293fdd9b52 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -5,6 +5,8 @@ use std::path::PathBuf; +use clap_complete::{Generator, shells}; + use crate::core::build_steps::dist::distdir; use crate::core::build_steps::test; use crate::core::build_steps::tool::{self, SourceType, Tool}; @@ -285,36 +287,35 @@ impl Step for GenerateWindowsSys { } } +/// Return tuples of (shell, file containing completions). +pub fn get_completion_paths(builder: &Builder<'_>) -> Vec<(&'static dyn Generator, PathBuf)> { + vec![ + (&shells::Bash as &'static dyn Generator, builder.src.join("src/etc/completions/x.py.sh")), + (&shells::Zsh, builder.src.join("src/etc/completions/x.py.zsh")), + (&shells::Fish, builder.src.join("src/etc/completions/x.py.fish")), + (&shells::PowerShell, builder.src.join("src/etc/completions/x.py.ps1")), + (&shells::Bash, builder.src.join("src/etc/completions/x.sh")), + (&shells::Zsh, builder.src.join("src/etc/completions/x.zsh")), + (&shells::Fish, builder.src.join("src/etc/completions/x.fish")), + (&shells::PowerShell, builder.src.join("src/etc/completions/x.ps1")), + ] +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GenerateCompletions; -macro_rules! generate_completions { - ( $( ( $shell:ident, $filename:expr ) ),* ) => { - $( - if let Some(comp) = get_completion($shell, &$filename) { - std::fs::write(&$filename, comp).expect(&format!("writing {} completion", stringify!($shell))); - } - )* - }; -} - impl Step for GenerateCompletions { type Output = (); /// Uses `clap_complete` to generate shell completions. fn run(self, builder: &Builder<'_>) { - use clap_complete::shells::{Bash, Fish, PowerShell, Zsh}; - - generate_completions!( - (Bash, builder.src.join("src/etc/completions/x.py.sh")), - (Zsh, builder.src.join("src/etc/completions/x.py.zsh")), - (Fish, builder.src.join("src/etc/completions/x.py.fish")), - (PowerShell, builder.src.join("src/etc/completions/x.py.ps1")), - (Bash, builder.src.join("src/etc/completions/x.sh")), - (Zsh, builder.src.join("src/etc/completions/x.zsh")), - (Fish, builder.src.join("src/etc/completions/x.fish")), - (PowerShell, builder.src.join("src/etc/completions/x.ps1")) - ); + for (shell, path) in get_completion_paths(builder) { + if let Some(comp) = get_completion(shell, &path) { + std::fs::write(&path, comp).unwrap_or_else(|e| { + panic!("writing completion into {} failed: {e:?}", path.display()) + }); + } + } } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 2d4d9e535981..a5b7b22aba85 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -8,12 +8,11 @@ use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::{env, fs, iter}; -use clap_complete::shells; - use crate::core::build_steps::compile::{Std, run_cargo}; use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; +use crate::core::build_steps::run::get_completion_paths; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool}; use crate::core::build_steps::toolstate::ToolState; @@ -1153,14 +1152,12 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to cmd.delay_failure().run(builder); builder.info("x.py completions check"); - let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] - .map(|filename| builder.src.join("src/etc/completions").join(filename)); + let completion_paths = get_completion_paths(builder); if builder.config.cmd.bless() { builder.ensure(crate::core::build_steps::run::GenerateCompletions); - } else if get_completion(shells::Bash, &bash).is_some() - || get_completion(shells::Fish, &fish).is_some() - || get_completion(shells::PowerShell, &powershell).is_some() - || crate::flags::get_completion(shells::Zsh, &zsh).is_some() + } else if completion_paths + .into_iter() + .any(|(shell, path)| get_completion(shell, &path).is_some()) { eprintln!( "x.py completions were changed; run `x.py run generate-completions` to update them" diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 79275db64863..bfc06f90d4f2 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use clap::{CommandFactory, Parser, ValueEnum}; +use clap_complete::Generator; #[cfg(feature = "tracing")] use tracing::instrument; @@ -644,7 +645,7 @@ impl Subcommand { /// Returns the shell completion for a given shell, if the result differs from the current /// content of `path`. If `path` does not exist, always returns `Some`. -pub fn get_completion(shell: G, path: &Path) -> Option { +pub fn get_completion(shell: &dyn Generator, path: &Path) -> Option { let mut cmd = Flags::command(); let current = if !path.exists() { String::new() @@ -662,7 +663,12 @@ pub fn get_completion(shell: G, path: &Path) -> Opt .expect("file name should be UTF-8") .rsplit_once('.') .expect("file name should have an extension"); - clap_complete::generate(shell, &mut cmd, bin_name, &mut buf); + + // We sort of replicate `clap_complete::generate` here, because we want to call it with + // `&dyn Generator`, but that function requires `G: Generator` instead. + cmd.set_bin_name(bin_name); + cmd.build(); + shell.generate(&cmd, &mut buf); if buf == current.as_bytes() { return None; } From 1a1f56174b10c877aa408700fd4dacb5d40df46d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 4 Jul 2025 21:26:21 +0200 Subject: [PATCH 24/68] Update completions --- src/etc/completions/x.fish | 2 +- src/etc/completions/x.ps1 | 2 +- src/etc/completions/x.zsh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 46d18ac7dbcb..69bd525a3122 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -293,7 +293,7 @@ complete -c x -n "__fish_x_using_subcommand doc" -l skip-std-check-if-no-downloa complete -c x -n "__fish_x_using_subcommand doc" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x -n "__fish_x_using_subcommand test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r -complete -c x -n "__fish_x_using_subcommand test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)' -r +complete -c x -n "__fish_x_using_subcommand test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix)' -r complete -c x -n "__fish_x_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r complete -c x -n "__fish_x_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r complete -c x -n "__fish_x_using_subcommand test" -l run -d 'whether to execute run-* tests' -r diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index 1ca00bb67dfe..7b142ba97ce5 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -339,7 +339,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;test' { [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)') [CompletionResult]::new('--compiletest-rustc-args', '--compiletest-rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running compiletest tests') - [CompletionResult]::new('--extra-checks', '--extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)') + [CompletionResult]::new('--extra-checks', '--extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix)') [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to') [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode') [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 00fb7d8e2ecb..c495e8318ba4 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -338,7 +338,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS:_default' \ '*--compiletest-rustc-args=[extra options to pass the compiler when running compiletest tests]:ARGS:_default' \ -'--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS:_default' \ +'--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell, shell\:lint, cpp, cpp\:fmt, spellcheck, spellcheck\:fix)]:EXTRA_CHECKS:_default' \ '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \ '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \ '--run=[whether to execute run-* tests]:auto | always | never:_default' \ From 62ada473281d86e9a7e19d2fe375171874f83cab Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 00:43:31 +0500 Subject: [PATCH 25/68] cleaned up some tests --- tests/ui/closures/closure-no-copy-mut-env.rs | 2 +- .../closures/closure-no-copy-mut-env.stderr | 4 +- .../fn/fn-arg-count-mismatch-diagnostics.rs | 9 ++-- .../fn-arg-count-mismatch-diagnostics.stderr | 20 ++++----- ....rs => null-pointer-optimization-sizes.rs} | 18 ++++++-- tests/ui/layout/null-pointer-optimization.rs | 44 ++++++++++--------- tests/ui/str/nul-char-equivalence.rs | 13 +++--- .../trait-object-method-receiver-rules.rs | 5 ++- .../trait-object-method-receiver-rules.stderr | 6 +-- .../trait-object-mut-to-shared-coercion.rs | 4 +- 10 files changed, 70 insertions(+), 55 deletions(-) rename tests/ui/layout/{null-pointer-size-optimization.rs => null-pointer-optimization-sizes.rs} (65%) diff --git a/tests/ui/closures/closure-no-copy-mut-env.rs b/tests/ui/closures/closure-no-copy-mut-env.rs index f6530f9a410a..890e99c1ac79 100644 --- a/tests/ui/closures/closure-no-copy-mut-env.rs +++ b/tests/ui/closures/closure-no-copy-mut-env.rs @@ -1,4 +1,4 @@ -// Check that closures do not implement `Copy` if their environment is not `Copy`. +//! Checks that closures do not implement `Copy` when they capture mutable references. fn main() { let mut a = 5; diff --git a/tests/ui/closures/closure-no-copy-mut-env.stderr b/tests/ui/closures/closure-no-copy-mut-env.stderr index 60cb13523130..1443366a4770 100644 --- a/tests/ui/closures/closure-no-copy-mut-env.stderr +++ b/tests/ui/closures/closure-no-copy-mut-env.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `hello` - --> $DIR/not-copy-closure.rs:10:13 + --> $DIR/closure-no-copy-mut-env.rs:10:13 | LL | let b = hello; | ----- value moved here @@ -7,7 +7,7 @@ LL | let c = hello; | ^^^^^ value used here after move | note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment - --> $DIR/not-copy-closure.rs:6:9 + --> $DIR/closure-no-copy-mut-env.rs:6:9 | LL | a += 1; | ^ diff --git a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs index ec660a1de81b..b2f80ba1bf62 100644 --- a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs +++ b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs @@ -1,15 +1,15 @@ +//! Checks clean diagnostics for argument count mismatches without unrelated errors. +//! +//! `delegate!` part related: + //@ aux-build: delegate_macro.rs extern crate delegate_macro; use delegate_macro::delegate; -// Check that the only error msg we report is the -// mismatch between the # of params, and not other -// unrelated errors. fn foo(a: isize, b: isize, c: isize, d: isize) { panic!(); } -// Check that all arguments are shown in the error message, even if they're across multiple lines. fn bar(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) { println!("{}", a); println!("{}", b); @@ -37,6 +37,7 @@ struct Bar; impl Bar { fn foo(a: u8, b: u8) {} + fn bar() { delegate_local!(foo); delegate!(foo); diff --git a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr index 908d0273bbec..6af7671af03b 100644 --- a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr +++ b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr @@ -1,5 +1,5 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied - --> $DIR/not-enough-arguments.rs:24:9 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:24:9 | LL | ::$method(8) | ^^^^^^^^^^^^^^^--- argument #2 of type `u8` is missing @@ -8,7 +8,7 @@ LL | delegate_local!(foo); | -------------------- in this macro invocation | note: associated function defined here - --> $DIR/not-enough-arguments.rs:39:8 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:39:8 | LL | fn foo(a: u8, b: u8) {} | ^^^ ----- @@ -19,20 +19,20 @@ LL | ::$method(8, /* u8 */) | ++++++++++ error[E0061]: this function takes 2 arguments but 1 argument was supplied - --> $DIR/not-enough-arguments.rs:42:9 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:43:9 | LL | delegate!(foo); | ^^^^^^^^^^^^^^ argument #2 of type `u8` is missing | note: associated function defined here - --> $DIR/not-enough-arguments.rs:39:8 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:39:8 | LL | fn foo(a: u8, b: u8) {} | ^^^ ----- = note: this error originates in the macro `delegate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0061]: this function takes 2 arguments but 1 argument was supplied - --> $DIR/not-enough-arguments.rs:31:9 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:31:9 | LL | <$from>::$method(8) | ^^^^^^^^^^^^^^^^--- argument #2 of type `u8` is missing @@ -41,7 +41,7 @@ LL | delegate_from!(Bar, foo); | ------------------------ in this macro invocation | note: associated function defined here - --> $DIR/not-enough-arguments.rs:39:8 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:39:8 | LL | fn foo(a: u8, b: u8) {} | ^^^ ----- @@ -52,13 +52,13 @@ LL | <$from>::$method(8, /* u8 */) | ++++++++++ error[E0061]: this function takes 4 arguments but 3 arguments were supplied - --> $DIR/not-enough-arguments.rs:49:5 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:50:5 | LL | foo(1, 2, 3); | ^^^--------- argument #4 of type `isize` is missing | note: function defined here - --> $DIR/not-enough-arguments.rs:8:4 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:9:4 | LL | fn foo(a: isize, b: isize, c: isize, d: isize) { | ^^^ -------- @@ -68,13 +68,13 @@ LL | foo(1, 2, 3, /* isize */); | +++++++++++++ error[E0061]: this function takes 6 arguments but 3 arguments were supplied - --> $DIR/not-enough-arguments.rs:51:5 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:52:5 | LL | bar(1, 2, 3); | ^^^--------- three arguments of type `i32`, `i32`, and `i32` are missing | note: function defined here - --> $DIR/not-enough-arguments.rs:13:4 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:13:4 | LL | fn bar(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) { | ^^^ ------ ------ ------ diff --git a/tests/ui/layout/null-pointer-size-optimization.rs b/tests/ui/layout/null-pointer-optimization-sizes.rs similarity index 65% rename from tests/ui/layout/null-pointer-size-optimization.rs rename to tests/ui/layout/null-pointer-optimization-sizes.rs index aabdfa140dff..95310b32e25f 100644 --- a/tests/ui/layout/null-pointer-size-optimization.rs +++ b/tests/ui/layout/null-pointer-optimization-sizes.rs @@ -1,10 +1,20 @@ +//! null pointer optimization preserves type sizes. +//! +//! Verifies that Option has the same size as T for non-null pointer types, +//! and for custom enums that have a niche. + //@ run-pass +// Needs for Nothing variat in Enum #![allow(dead_code)] use std::mem; -enum E { Thing(isize, T), Nothing((), ((), ()), [i8; 0]) } +enum E { + Thing(isize, T), + Nothing((), ((), ()), [i8; 0]), +} + struct S(isize, T); // These are macros so we get useful assert messages. @@ -12,20 +22,20 @@ struct S(isize, T); macro_rules! check_option { ($T:ty) => { assert_eq!(mem::size_of::>(), mem::size_of::<$T>()); - } + }; } macro_rules! check_fancy { ($T:ty) => { assert_eq!(mem::size_of::>(), mem::size_of::>()); - } + }; } macro_rules! check_type { ($T:ty) => {{ check_option!($T); check_fancy!($T); - }} + }}; } pub fn main() { diff --git a/tests/ui/layout/null-pointer-optimization.rs b/tests/ui/layout/null-pointer-optimization.rs index 1b73164c9fc7..5e77c8d22ab2 100644 --- a/tests/ui/layout/null-pointer-optimization.rs +++ b/tests/ui/layout/null-pointer-optimization.rs @@ -1,27 +1,34 @@ -//@ run-pass +//! null pointer optimization with iota-reduction for enums. +//! +//! Iota-reduction is a rule from the Calculus of (Co-)Inductive Constructions: +//! "a destructor applied to an object built from a constructor behaves as expected". +//! See . +//! +//! This test verifies that null pointer optimization works correctly for both +//! Option and custom enums, accounting for pointers and regions. -// Iota-reduction is a rule in the Calculus of (Co-)Inductive Constructions, -// which "says that a destructor applied to an object built from a constructor -// behaves as expected". -- https://coq.inria.fr/doc/language/core/conversion.html#iota-reduction -// -// It's a little more complicated here, because of pointers and regions and -// trying to get assert failure messages that at least identify which case -// failed. +//@ run-pass #![allow(unpredictable_function_pointer_comparisons)] -enum E { Thing(isize, T), #[allow(dead_code)] Nothing((), ((), ()), [i8; 0]) } +enum E { + Thing(isize, T), + #[allow(dead_code)] + Nothing((), ((), ()), [i8; 0]), +} + impl E { fn is_none(&self) -> bool { match *self { E::Thing(..) => false, - E::Nothing(..) => true + E::Nothing(..) => true, } } + fn get_ref(&self) -> (isize, &T) { match *self { - E::Nothing(..) => panic!("E::get_ref(Nothing::<{}>)", stringify!(T)), - E::Thing(x, ref y) => (x, y) + E::Nothing(..) => panic!("E::get_ref(Nothing::<{}>)", stringify!(T)), + E::Thing(x, ref y) => (x, y), } } } @@ -36,7 +43,7 @@ macro_rules! check_option { let s_ = Some::<$T>(e); let $v = s_.as_ref().unwrap(); $chk - }} + }}; } macro_rules! check_fancy { @@ -48,11 +55,10 @@ macro_rules! check_fancy { let e = $e; let t_ = E::Thing::<$T>(23, e); match t_.get_ref() { - (23, $v) => { $chk } - _ => panic!("Thing::<{}>(23, {}).get_ref() != (23, _)", - stringify!($T), stringify!($e)) + (23, $v) => $chk, + _ => panic!("Thing::<{}>(23, {}).get_ref() != (23, _)", stringify!($T), stringify!($e)), } - }} + }}; } macro_rules! check_type { @@ -67,7 +73,5 @@ pub fn main() { check_type!(Box::new(18), Box); check_type!("foo".to_string(), String); check_type!(vec![20, 22], Vec); - check_type!(main, fn(), |pthing| { - assert_eq!(main as fn(), *pthing as fn()) - }); + check_type!(main, fn(), |pthing| assert_eq!(main as fn(), *pthing as fn())); } diff --git a/tests/ui/str/nul-char-equivalence.rs b/tests/ui/str/nul-char-equivalence.rs index eb83f440d3e0..2d4110de6812 100644 --- a/tests/ui/str/nul-char-equivalence.rs +++ b/tests/ui/str/nul-char-equivalence.rs @@ -1,7 +1,8 @@ +//! Checks that different NUL character representations are equivalent in strings and chars. + //@ run-pass -pub fn main() -{ +pub fn main() { let all_nuls1 = "\0\x00\u{0}\u{0}"; let all_nuls2 = "\u{0}\u{0}\x00\0"; let all_nuls3 = "\u{0}\u{0}\x00\0"; @@ -17,11 +18,9 @@ pub fn main() assert_eq!(all_nuls3, all_nuls4); // all extracted characters in all_nuls are equivalent to each other - for c1 in all_nuls1.chars() - { - for c2 in all_nuls1.chars() - { - assert_eq!(c1,c2); + for c1 in all_nuls1.chars() { + for c2 in all_nuls1.chars() { + assert_eq!(c1, c2); } } diff --git a/tests/ui/traits/trait-object-method-receiver-rules.rs b/tests/ui/traits/trait-object-method-receiver-rules.rs index 760a50e5b797..383e59c131a1 100644 --- a/tests/ui/traits/trait-object-method-receiver-rules.rs +++ b/tests/ui/traits/trait-object-method-receiver-rules.rs @@ -1,7 +1,8 @@ +//! Checks that method availability rules for trait objects depend on receiver type. + trait Foo { fn borrowed(&self); fn borrowed_mut(&mut self); - fn owned(self: Box); } @@ -20,7 +21,7 @@ fn borrowed_mut_receiver(x: &mut dyn Foo) { fn owned_receiver(x: Box) { x.borrowed(); x.borrowed_mut(); // See [1] - x.managed(); //~ ERROR no method named `managed` found + x.managed(); //~ ERROR no method named `managed` found x.owned(); } diff --git a/tests/ui/traits/trait-object-method-receiver-rules.stderr b/tests/ui/traits/trait-object-method-receiver-rules.stderr index 72b290f2ad9f..83b61a2e6b52 100644 --- a/tests/ui/traits/trait-object-method-receiver-rules.stderr +++ b/tests/ui/traits/trait-object-method-receiver-rules.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `owned` found for reference `&dyn Foo` in the current scope - --> $DIR/object-pointer-types.rs:11:7 + --> $DIR/trait-object-method-receiver-rules.rs:12:7 | LL | fn owned(self: Box); | --------- the method might not be found because of this arbitrary self type @@ -13,7 +13,7 @@ LL | x.to_owned(); | +++ error[E0599]: no method named `owned` found for mutable reference `&mut dyn Foo` in the current scope - --> $DIR/object-pointer-types.rs:17:7 + --> $DIR/trait-object-method-receiver-rules.rs:18:7 | LL | fn owned(self: Box); | --------- the method might not be found because of this arbitrary self type @@ -22,7 +22,7 @@ LL | x.owned(); | ^^^^^ method not found in `&mut dyn Foo` error[E0599]: no method named `managed` found for struct `Box<(dyn Foo + 'static)>` in the current scope - --> $DIR/object-pointer-types.rs:23:7 + --> $DIR/trait-object-method-receiver-rules.rs:24:7 | LL | x.managed(); | ^^^^^^^ method not found in `Box<(dyn Foo + 'static)>` diff --git a/tests/ui/traits/trait-object-mut-to-shared-coercion.rs b/tests/ui/traits/trait-object-mut-to-shared-coercion.rs index e122bb993806..26b5cc6d2dfc 100644 --- a/tests/ui/traits/trait-object-mut-to-shared-coercion.rs +++ b/tests/ui/traits/trait-object-mut-to-shared-coercion.rs @@ -1,6 +1,6 @@ -//@ run-pass -// Test that we can coerce an `@Object` to an `&Object` +//! Tests that coercion from `&mut dyn Trait` to `&dyn Trait` works correctly. +//@ run-pass trait Foo { fn foo(&self) -> usize; From 066a281f60fd5071a50cf15a28ed40f15bef7563 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 19:28:38 +0500 Subject: [PATCH 26/68] cleaned up some tests --- .../reexport-test-harness-entry-point.rs | 3 +++ .../ui/const-ptr/pointer-address-stability.rs | 7 ++++-- .../ui/diagnostic-flags/error-format-short.rs | 3 +++ .../error-format-short.stderr | 4 ++-- tests/ui/drop/drop-once-on-move.rs | 8 ++++--- tests/ui/drop/drop-scope-exit.rs | 20 ++++++++++------ .../generics/trait-incorrect-generic-args.rs | 4 +++- .../trait-incorrect-generic-args.stderr | 12 +++++----- .../ui/io-checks/io-stdout-blocking-writes.rs | 24 +++++++++++-------- tests/ui/shadowed/primitive-type-shadowing.rs | 3 +++ tests/ui/shadowed/use-shadows-reexport.rs | 2 ++ .../ui/sized/recursive-type-infinite-size.rs | 17 +++++++++---- .../sized/recursive-type-infinite-size.stderr | 22 ++++++++++------- tests/ui/sized/sized-box-unsized-content.rs | 13 +++++----- tests/ui/sized/sized-reference-to-unsized.rs | 12 ++++++---- tests/ui/sync/atomic-types-not-copyable.rs | 8 ++++--- .../ui/sync/atomic-types-not-copyable.stderr | 8 +++---- .../target-feature-detection.rs | 19 +++++++++++---- .../traits/error-trait-object-from-string.rs | 5 ++-- 19 files changed, 126 insertions(+), 68 deletions(-) diff --git a/tests/ui/attributes/reexport-test-harness-entry-point.rs b/tests/ui/attributes/reexport-test-harness-entry-point.rs index f79828fc7d66..95765a719ed5 100644 --- a/tests/ui/attributes/reexport-test-harness-entry-point.rs +++ b/tests/ui/attributes/reexport-test-harness-entry-point.rs @@ -1,3 +1,6 @@ +//! Check that `#[reexport_test_harness_main]` correctly reexports the test harness entry point +//! and allows it to be called from within the code. + //@ run-pass //@ compile-flags:--test diff --git a/tests/ui/const-ptr/pointer-address-stability.rs b/tests/ui/const-ptr/pointer-address-stability.rs index e330a4853ce0..84a36e1ddf51 100644 --- a/tests/ui/const-ptr/pointer-address-stability.rs +++ b/tests/ui/const-ptr/pointer-address-stability.rs @@ -1,6 +1,9 @@ -//@ run-pass -// Issue #2040 +//! Check that taking the address of a stack variable with `&` +//! yields a stable and comparable pointer. +//! +//! Regression test for . +//@ run-pass pub fn main() { let foo: isize = 1; diff --git a/tests/ui/diagnostic-flags/error-format-short.rs b/tests/ui/diagnostic-flags/error-format-short.rs index 719870a04fb9..4c793cd1b189 100644 --- a/tests/ui/diagnostic-flags/error-format-short.rs +++ b/tests/ui/diagnostic-flags/error-format-short.rs @@ -1,3 +1,6 @@ +//! Check that compile errors are formatted in the "short" style +//! when `--error-format=short` is used. + //@ compile-flags: --error-format=short fn foo(_: u32) {} diff --git a/tests/ui/diagnostic-flags/error-format-short.stderr b/tests/ui/diagnostic-flags/error-format-short.stderr index 1a4a6d4df88e..0a097e2f623c 100644 --- a/tests/ui/diagnostic-flags/error-format-short.stderr +++ b/tests/ui/diagnostic-flags/error-format-short.stderr @@ -1,3 +1,3 @@ -$DIR/short-error-format.rs:6:9: error[E0308]: mismatched types: expected `u32`, found `String` -$DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for type `u32` in the current scope: method not found in `u32` +$DIR/error-format-short.rs:9:9: error[E0308]: mismatched types: expected `u32`, found `String` +$DIR/error-format-short.rs:11:7: error[E0599]: no method named `salut` found for type `u32` in the current scope: method not found in `u32` error: aborting due to 2 previous errors diff --git a/tests/ui/drop/drop-once-on-move.rs b/tests/ui/drop/drop-once-on-move.rs index ab4260169013..da0180580769 100644 --- a/tests/ui/drop/drop-once-on-move.rs +++ b/tests/ui/drop/drop-once-on-move.rs @@ -1,3 +1,7 @@ +//! Check that types not implementing `Copy` are moved, not copied, during assignment +//! operations, and their `Drop` implementation is called exactly once when the +//! value goes out of scope. + //@ run-pass #![allow(non_camel_case_types)] @@ -15,9 +19,7 @@ impl<'a> Drop for r<'a> { } fn r(i: &Cell) -> r<'_> { - r { - i: i - } + r { i } } pub fn main() { diff --git a/tests/ui/drop/drop-scope-exit.rs b/tests/ui/drop/drop-scope-exit.rs index 480cbe091a7a..4d003fec7125 100644 --- a/tests/ui/drop/drop-scope-exit.rs +++ b/tests/ui/drop/drop-scope-exit.rs @@ -1,31 +1,37 @@ +//! Check that the `Drop` implementation is called when a value goes out of scope. + //@ run-pass #![allow(non_camel_case_types)] use std::cell::Cell; struct shrinky_pointer<'a> { - i: &'a Cell, + i: &'a Cell, } impl<'a> Drop for shrinky_pointer<'a> { fn drop(&mut self) { - println!("Hello!"); self.i.set(self.i.get() - 1); + println!("Hello!"); + self.i.set(self.i.get() - 1); } } impl<'a> shrinky_pointer<'a> { - pub fn look_at(&self) -> isize { return self.i.get(); } + pub fn look_at(&self) -> isize { + return self.i.get(); + } } fn shrinky_pointer(i: &Cell) -> shrinky_pointer<'_> { - shrinky_pointer { - i: i - } + shrinky_pointer { i } } pub fn main() { let my_total = &Cell::new(10); - { let pt = shrinky_pointer(my_total); assert_eq!(pt.look_at(), 10); } + { + let pt = shrinky_pointer(my_total); + assert_eq!(pt.look_at(), 10); + } println!("my_total = {}", my_total.get()); assert_eq!(my_total.get(), 9); } diff --git a/tests/ui/generics/trait-incorrect-generic-args.rs b/tests/ui/generics/trait-incorrect-generic-args.rs index 627dfcc31986..9715100b19cc 100644 --- a/tests/ui/generics/trait-incorrect-generic-args.rs +++ b/tests/ui/generics/trait-incorrect-generic-args.rs @@ -1,5 +1,7 @@ +//! Check for compilation errors when a trait is used with an incorrect number of generic arguments. + fn main() { - trait Seq { } + trait Seq {} impl Seq for Vec { //~^ ERROR trait takes 0 generic arguments but 1 generic argument diff --git a/tests/ui/generics/trait-incorrect-generic-args.stderr b/tests/ui/generics/trait-incorrect-generic-args.stderr index 6e0d484d013d..afc4ff03d949 100644 --- a/tests/ui/generics/trait-incorrect-generic-args.stderr +++ b/tests/ui/generics/trait-incorrect-generic-args.stderr @@ -1,5 +1,5 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/seq-args.rs:4:13 + --> $DIR/trait-incorrect-generic-args.rs:6:13 | LL | impl Seq for Vec { | ^^^--- help: remove the unnecessary generics @@ -7,13 +7,13 @@ LL | impl Seq for Vec { | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/seq-args.rs:2:11 + --> $DIR/trait-incorrect-generic-args.rs:4:11 | -LL | trait Seq { } +LL | trait Seq {} | ^^^ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/seq-args.rs:9:10 + --> $DIR/trait-incorrect-generic-args.rs:11:10 | LL | impl Seq for u32 { | ^^^------ help: remove the unnecessary generics @@ -21,9 +21,9 @@ LL | impl Seq for u32 { | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/seq-args.rs:2:11 + --> $DIR/trait-incorrect-generic-args.rs:4:11 | -LL | trait Seq { } +LL | trait Seq {} | ^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/io-checks/io-stdout-blocking-writes.rs b/tests/ui/io-checks/io-stdout-blocking-writes.rs index 615530dcd47e..1197b7f43be8 100644 --- a/tests/ui/io-checks/io-stdout-blocking-writes.rs +++ b/tests/ui/io-checks/io-stdout-blocking-writes.rs @@ -1,10 +1,12 @@ +//! Check that writes to standard output are blocking, avoiding interleaving +//! even with concurrent writes from multiple threads. + //@ run-pass //@ needs-subprocess -use std::env; use std::io::prelude::*; use std::process::Command; -use std::thread; +use std::{env, thread}; const THREADS: usize = 20; const WRITES: usize = 100; @@ -33,14 +35,16 @@ fn parent() { } fn child() { - let threads = (0..THREADS).map(|_| { - thread::spawn(|| { - let buf = [b'a'; WRITE_SIZE]; - for _ in 0..WRITES { - write_all(&buf); - } + let threads = (0..THREADS) + .map(|_| { + thread::spawn(|| { + let buf = [b'a'; WRITE_SIZE]; + for _ in 0..WRITES { + write_all(&buf); + } + }) }) - }).collect::>(); + .collect::>(); for thread in threads { thread.join().unwrap(); @@ -63,8 +67,8 @@ fn write_all(buf: &[u8]) { fn write_all(buf: &[u8]) { use std::fs::File; use std::mem; - use std::os::windows::raw::*; use std::os::windows::prelude::*; + use std::os::windows::raw::*; const STD_OUTPUT_HANDLE: u32 = (-11i32) as u32; diff --git a/tests/ui/shadowed/primitive-type-shadowing.rs b/tests/ui/shadowed/primitive-type-shadowing.rs index 8cba2c1710b4..fdcb4246a82f 100644 --- a/tests/ui/shadowed/primitive-type-shadowing.rs +++ b/tests/ui/shadowed/primitive-type-shadowing.rs @@ -1,3 +1,6 @@ +//! Check that a primitive type can be shadowed by a user-defined type, and the primitive type +//! can still be referenced using its fully qualified path (e.g., `core::primitive::bool`). + //@ check-pass mod bar { diff --git a/tests/ui/shadowed/use-shadows-reexport.rs b/tests/ui/shadowed/use-shadows-reexport.rs index 5ce4103b5597..d220e4b406be 100644 --- a/tests/ui/shadowed/use-shadows-reexport.rs +++ b/tests/ui/shadowed/use-shadows-reexport.rs @@ -1,3 +1,5 @@ +//! Check that a local `use` declaration can shadow a re-exported item within the same module. + //@ run-pass #![allow(unused_imports)] diff --git a/tests/ui/sized/recursive-type-infinite-size.rs b/tests/ui/sized/recursive-type-infinite-size.rs index 766a5fa0de3d..5cd8e8955739 100644 --- a/tests/ui/sized/recursive-type-infinite-size.rs +++ b/tests/ui/sized/recursive-type-infinite-size.rs @@ -1,7 +1,16 @@ -struct Baz { q: Option } -//~^ ERROR recursive types `Baz` and `Foo` have infinite size -struct Foo { q: Option } +//! Check for compilation errors when recursive types are defined in a way +//! that leads to an infinite size. -impl Foo { fn bar(&self) {} } +struct Baz { + //~^ ERROR recursive types `Baz` and `Foo` have infinite size + q: Option, +} +struct Foo { + q: Option, +} + +impl Foo { + fn bar(&self) {} +} fn main() {} diff --git a/tests/ui/sized/recursive-type-infinite-size.stderr b/tests/ui/sized/recursive-type-infinite-size.stderr index 21e54c12feda..98ac36c4bb6b 100644 --- a/tests/ui/sized/recursive-type-infinite-size.stderr +++ b/tests/ui/sized/recursive-type-infinite-size.stderr @@ -1,17 +1,23 @@ error[E0072]: recursive types `Baz` and `Foo` have infinite size - --> $DIR/sized-cycle-note.rs:1:1 + --> $DIR/recursive-type-infinite-size.rs:4:1 | -LL | struct Baz { q: Option } - | ^^^^^^^^^^ --- recursive without indirection +LL | struct Baz { + | ^^^^^^^^^^ LL | -LL | struct Foo { q: Option } - | ^^^^^^^^^^ --- recursive without indirection +LL | q: Option, + | --- recursive without indirection +LL | } +LL | struct Foo { + | ^^^^^^^^^^ +LL | q: Option, + | --- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | -LL ~ struct Baz { q: Option> } -LL | -LL ~ struct Foo { q: Option> } +LL ~ q: Option>, +LL | } +LL | struct Foo { +LL ~ q: Option>, | error: aborting due to 1 previous error diff --git a/tests/ui/sized/sized-box-unsized-content.rs b/tests/ui/sized/sized-box-unsized-content.rs index b35c0f91abd2..9cc202a1582f 100644 --- a/tests/ui/sized/sized-box-unsized-content.rs +++ b/tests/ui/sized/sized-box-unsized-content.rs @@ -1,10 +1,11 @@ +//! Check that `Box` is `Sized`, even when `T` is a dynamically sized type. + //@ run-pass #![allow(dead_code)] -// Possibly-dynamic size of typaram should be cleared at pointer boundary. - - -fn bar() { } -fn foo() { bar::>() } -pub fn main() { } +fn bar() {} +fn foo() { + bar::>() +} +pub fn main() {} diff --git a/tests/ui/sized/sized-reference-to-unsized.rs b/tests/ui/sized/sized-reference-to-unsized.rs index bd213c067db5..ac2934d8fe64 100644 --- a/tests/ui/sized/sized-reference-to-unsized.rs +++ b/tests/ui/sized/sized-reference-to-unsized.rs @@ -1,9 +1,11 @@ +//! Check that a reference to a potentially unsized type (`&T`) is itself considered `Sized`. + //@ run-pass #![allow(dead_code)] -// Possibly-dynamic size of typaram should be cleared at pointer boundary. - -fn bar() { } -fn foo() { bar::<&T>() } -pub fn main() { } +fn bar() {} +fn foo() { + bar::<&T>() +} +pub fn main() {} diff --git a/tests/ui/sync/atomic-types-not-copyable.rs b/tests/ui/sync/atomic-types-not-copyable.rs index d85864ecac28..d96414676ee6 100644 --- a/tests/ui/sync/atomic-types-not-copyable.rs +++ b/tests/ui/sync/atomic-types-not-copyable.rs @@ -1,8 +1,10 @@ -// Issue #8380 +//! Check that atomic types from `std::sync::atomic` are not `Copy` +//! and cannot be moved out of a shared reference. +//! +//! Regression test for . - -use std::sync::atomic::*; use std::ptr; +use std::sync::atomic::*; fn main() { let x = AtomicBool::new(false); diff --git a/tests/ui/sync/atomic-types-not-copyable.stderr b/tests/ui/sync/atomic-types-not-copyable.stderr index 8c5d0b960962..05103f5d8f26 100644 --- a/tests/ui/sync/atomic-types-not-copyable.stderr +++ b/tests/ui/sync/atomic-types-not-copyable.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/std-uncopyable-atomics.rs:9:13 + --> $DIR/atomic-types-not-copyable.rs:11:13 | LL | let x = *&x; | ^^^ move occurs because value has type `std::sync::atomic::AtomicBool`, which does not implement the `Copy` trait @@ -11,7 +11,7 @@ LL + let x = &x; | error[E0507]: cannot move out of a shared reference - --> $DIR/std-uncopyable-atomics.rs:11:13 + --> $DIR/atomic-types-not-copyable.rs:13:13 | LL | let x = *&x; | ^^^ move occurs because value has type `std::sync::atomic::AtomicIsize`, which does not implement the `Copy` trait @@ -23,7 +23,7 @@ LL + let x = &x; | error[E0507]: cannot move out of a shared reference - --> $DIR/std-uncopyable-atomics.rs:13:13 + --> $DIR/atomic-types-not-copyable.rs:15:13 | LL | let x = *&x; | ^^^ move occurs because value has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait @@ -35,7 +35,7 @@ LL + let x = &x; | error[E0507]: cannot move out of a shared reference - --> $DIR/std-uncopyable-atomics.rs:15:13 + --> $DIR/atomic-types-not-copyable.rs:17:13 | LL | let x = *&x; | ^^^ move occurs because value has type `std::sync::atomic::AtomicPtr`, which does not implement the `Copy` trait diff --git a/tests/ui/target-feature/target-feature-detection.rs b/tests/ui/target-feature/target-feature-detection.rs index a1894cc03dbc..3404bfbe782a 100644 --- a/tests/ui/target-feature/target-feature-detection.rs +++ b/tests/ui/target-feature/target-feature-detection.rs @@ -1,3 +1,6 @@ +//! Check that `cfg!(target_feature = "...")` correctly detects available CPU features, +//! specifically `sse2` on x86/x86_64 platforms, and correctly reports absent features. + //@ run-pass #![allow(stable_features)] @@ -10,17 +13,23 @@ fn main() { Ok(s) => { // Skip this tests on i586-unknown-linux-gnu where sse2 is disabled if s.contains("i586") { - return + return; } } Err(_) => return, } if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { - assert!(cfg!(target_feature = "sse2"), - "SSE2 was not detected as available on an x86 platform"); + assert!( + cfg!(target_feature = "sse2"), + "SSE2 was not detected as available on an x86 platform" + ); } // check a negative case too -- certainly not enabled by default #[expect(unexpected_cfgs)] - { assert!(cfg!(not(target_feature = "ferris_wheel")), - "🎡 shouldn't be detected as available by default on any platform") }; + { + assert!( + cfg!(not(target_feature = "ferris_wheel")), + "🎡 shouldn't be detected as available by default on any platform" + ) + }; } diff --git a/tests/ui/traits/error-trait-object-from-string.rs b/tests/ui/traits/error-trait-object-from-string.rs index 9a7cd81ee045..896f164a04d4 100644 --- a/tests/ui/traits/error-trait-object-from-string.rs +++ b/tests/ui/traits/error-trait-object-from-string.rs @@ -1,6 +1,7 @@ +//! Check that `String` and `&str` can be converted into `Box` and +//! `Box` trait objects + //@ run-pass -// Ensure that both `Box` and `Box` can be -// obtained from `String`. use std::error::Error; From 2d1aa582254e87b06c0805e6c3dcc4559bc7924c Mon Sep 17 00:00:00 2001 From: "Kurt Heiritz (pseudo)" Date: Thu, 26 Jun 2025 10:41:27 +0530 Subject: [PATCH 27/68] Make Rem const for floats --- library/core/src/ops/arith.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 7ffde233da34..e53c128efe06 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -627,7 +627,7 @@ macro_rules! rem_impl_float { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ops", issue = "90080")] - impl Rem for $t { + impl const Rem for $t { type Output = $t; #[inline] From 1f01d9b3db949340c614cb0a9cf8319808088054 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sat, 5 Jul 2025 10:19:38 +0530 Subject: [PATCH 28/68] std: sys: net: uefi: tcp4: Implement read A blocking implementation of tcp4 read. Signed-off-by: Ayush Singh --- .../std/src/sys/net/connection/uefi/mod.rs | 13 ++++--- .../std/src/sys/net/connection/uefi/tcp.rs | 6 +++ .../std/src/sys/net/connection/uefi/tcp4.rs | 39 +++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 2d465bd0efaa..6835ba44ee24 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -38,16 +38,17 @@ impl TcpStream { unsupported() } - pub fn read(&self, _: &mut [u8]) -> io::Result { - unsupported() + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) } - pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { - unsupported() + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) } - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { - unsupported() + pub fn read_vectored(&self, buf: &mut [IoSliceMut<'_>]) -> io::Result { + // FIXME: UEFI does support vectored read, so implement that. + crate::io::default_read_vectored(|b| self.read(b), buf) } pub fn is_read_vectored(&self) -> bool { diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 9c3462e3468c..55b6dbf2490b 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -24,4 +24,10 @@ impl Tcp { Self::V4(client) => client.write(buf), } } + + pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result { + match self { + Self::V4(client) => client.read(buf), + } + } } diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs index d0f0d27d975f..af1ba2be47ad 100644 --- a/library/std/src/sys/net/connection/uefi/tcp4.rs +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -128,6 +128,45 @@ impl Tcp4 { } } + pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result { + let evt = unsafe { self.create_evt() }?; + let completion_token = + tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; + let data_len = u32::try_from(buf.len()).unwrap_or(u32::MAX); + + let fragment = tcp4::FragmentData { + fragment_length: data_len, + fragment_buffer: buf.as_mut_ptr().cast::(), + }; + let mut tx_data = tcp4::ReceiveData { + urgent_flag: r_efi::efi::Boolean::FALSE, + data_length: data_len, + fragment_count: 1, + fragment_table: [fragment], + }; + + let protocol = self.protocol.as_ptr(); + let mut token = tcp4::IoToken { + completion_token, + packet: tcp4::IoTokenPacket { + rx_data: (&raw mut tx_data).cast::>(), + }, + }; + + let r = unsafe { ((*protocol).receive)(protocol, &mut token) }; + if r.is_error() { + return Err(io::Error::from_raw_os_error(r.as_usize())); + } + + self.wait_for_flag(); + + if completion_token.status.is_error() { + Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) + } else { + Ok(data_len as usize) + } + } + unsafe fn create_evt(&self) -> io::Result { self.flag.store(false, Ordering::Relaxed); helpers::OwnedEvent::new( From 3f3f12c341c7e84294f4b0a548c58fa9ba9d307a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 3 Jul 2025 13:59:46 +0530 Subject: [PATCH 29/68] add streaming command struct for (spawn + piping scenario) --- src/bootstrap/src/utils/exec.rs | 74 ++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index d092765ef762..23296c534bb0 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -13,7 +13,9 @@ use std::fmt::{Debug, Formatter}; use std::hash::Hash; use std::panic::Location; use std::path::Path; -use std::process::{Child, Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio}; +use std::process::{ + Child, ChildStderr, ChildStdout, Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio, +}; use std::sync::{Arc, Mutex}; use build_helper::ci::CiEnv; @@ -209,15 +211,22 @@ impl<'a> BootstrapCommand { exec_ctx.as_ref().start(self, OutputMode::Capture, OutputMode::Print) } - /// Provides access to the stdlib Command inside. - /// FIXME: This function should be eventually removed from bootstrap. - pub fn as_command_mut(&mut self) -> &mut Command { - // We proactively mark this command as executed since we can't be certain how the returned - // command will be handled. Caching must also be avoided here, as the inner command could be - // modified externally without us being aware. - self.mark_as_executed(); - self.do_not_cache(); - &mut self.command + /// Spawn the command in background, while capturing and returns a handle to stream the output. + #[track_caller] + pub fn stream_capture( + &'a mut self, + exec_ctx: impl AsRef, + ) -> Option { + exec_ctx.as_ref().stream(self, OutputMode::Capture, OutputMode::Capture) + } + + /// Spawn the command in background, while capturing and returning stdout, and printing stderr. + #[track_caller] + pub fn stream_capture_stdout( + &'a mut self, + exec_ctx: impl AsRef, + ) -> Option { + exec_ctx.as_ref().stream(self, OutputMode::Capture, OutputMode::Print) } /// Mark the command as being executed, disarming the drop bomb. @@ -449,6 +458,12 @@ enum CommandState<'a> { }, } +pub struct StreamingCommand { + child: Child, + pub stdout: Option, + pub stderr: Option, +} + #[must_use] pub struct DeferredCommand<'a> { state: CommandState<'a>, @@ -617,6 +632,39 @@ impl ExecutionContext { } exit!(1); } + +<<<<<<< HEAD + pub fn stream<'a>( +======= + /// Spawns the command with configured stdout and stderr handling. + /// + /// Returns `None` if in dry-run mode and the command is not allowed to run. + /// + /// Panics if the command fails to spawn. + pub fn stream( +>>>>>>> c2e83361cec (add comment to exec) + &self, + command: &'a mut BootstrapCommand, + stdout: OutputMode, + stderr: OutputMode, + ) -> Option { + command.mark_as_executed(); + if !command.run_in_dry_run && self.dry_run() { + return None; + } + let cmd = &mut command.command; + cmd.stdout(stdout.stdio()); + cmd.stderr(stderr.stdio()); + let child = cmd.spawn(); + let mut child = match child { + Ok(child) => child, + Err(e) => panic!("failed to execute command: {cmd:?}\nERROR: {e}"), + }; + + let stdout = child.stdout.take(); + let stderr = child.stderr.take(); + return Some(StreamingCommand { child, stdout, stderr }); + } } impl AsRef for ExecutionContext { @@ -625,6 +673,12 @@ impl AsRef for ExecutionContext { } } +impl StreamingCommand { + pub fn wait(mut self) -> Result { + self.child.wait() + } +} + impl<'a> DeferredCommand<'a> { pub fn wait_for_output(self, exec_ctx: impl AsRef) -> CommandOutput { match self.state { From b891d9add1200f29496c66334775a1636cd32151 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 3 Jul 2025 14:00:20 +0530 Subject: [PATCH 30/68] migrate cargo streaming to new bootstrap command streaming API's --- src/bootstrap/src/core/build_steps/compile.rs | 24 ++++++++----------- src/bootstrap/src/utils/exec.rs | 1 + 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index c3a3eddd1612..431c242608b7 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -12,7 +12,6 @@ use std::ffi::OsStr; use std::io::BufReader; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use std::process::Stdio; use std::{env, fs, str}; use serde_derive::Deserialize; @@ -2507,7 +2506,6 @@ pub fn stream_cargo( #[cfg(feature = "tracing")] let _run_span = crate::trace_cmd!(cmd); - let cargo = cmd.as_command_mut(); // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. let mut message_format = if builder.config.json_output { @@ -2519,27 +2517,24 @@ pub fn stream_cargo( message_format.push_str(",json-diagnostic-"); message_format.push_str(s); } - cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped()); + cmd.arg("--message-format").arg(message_format); for arg in tail_args { - cargo.arg(arg); + cmd.arg(arg); } - builder.verbose(|| println!("running: {cargo:?}")); + builder.verbose(|| println!("running: {cmd:?}")); - if builder.config.dry_run() { + let streaming_command = cmd.stream_capture_stdout(&builder.config.exec_ctx); + + let Some(mut streaming_command) = streaming_command else { return true; - } - - let mut child = match cargo.spawn() { - Ok(child) => child, - Err(e) => panic!("failed to execute command: {cargo:?}\nERROR: {e}"), }; // Spawn Cargo slurping up its JSON output. We'll start building up the // `deps` array of all files it generated along with a `toplevel` array of // files we need to probe for later. - let stdout = BufReader::new(child.stdout.take().unwrap()); + let stdout = BufReader::new(streaming_command.stdout.take().unwrap()); for line in stdout.lines() { let line = t!(line); match serde_json::from_str::>(&line) { @@ -2556,13 +2551,14 @@ pub fn stream_cargo( } // Make sure Cargo actually succeeded after we read all of its stdout. - let status = t!(child.wait()); + let status = t!(streaming_command.wait()); if builder.is_verbose() && !status.success() { eprintln!( - "command did not execute successfully: {cargo:?}\n\ + "command did not execute successfully: {cmd:?}\n\ expected success, got: {status}" ); } + status.success() } diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 23296c534bb0..d1822752f920 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -221,6 +221,7 @@ impl<'a> BootstrapCommand { } /// Spawn the command in background, while capturing and returning stdout, and printing stderr. + /// Returns None in dry-mode #[track_caller] pub fn stream_capture_stdout( &'a mut self, From 0a57612e63e5110d8a93cc000755b0395fca018d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 3 Jul 2025 14:00:46 +0530 Subject: [PATCH 31/68] migrate render test to new bootstrap command streaming API's --- src/bootstrap/src/utils/render_tests.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 051d7dd9fd4d..283563f3aca9 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -7,7 +7,7 @@ //! to reimplement all the rendering logic in this module because of that. use std::io::{BufRead, BufReader, Read, Write}; -use std::process::{ChildStdout, Stdio}; +use std::process::ChildStdout; use std::time::Duration; use termcolor::{Color, ColorSpec, WriteColor}; @@ -52,32 +52,28 @@ pub(crate) fn try_run_tests( } fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { - let cmd = cmd.as_command_mut(); - cmd.stdout(Stdio::piped()); - builder.verbose(|| println!("running: {cmd:?}")); - let mut process = cmd.spawn().unwrap(); + let mut streaming_command = cmd.stream_capture_stdout(&builder.config.exec_ctx).unwrap(); // This runs until the stdout of the child is closed, which means the child exited. We don't // run this on another thread since the builder is not Sync. - let renderer = Renderer::new(process.stdout.take().unwrap(), builder); + let renderer = Renderer::new(streaming_command.stdout.take().unwrap(), builder); if stream { renderer.stream_all(); } else { renderer.render_all(); } - let result = process.wait_with_output().unwrap(); - if !result.status.success() && builder.is_verbose() { + let status = streaming_command.wait().unwrap(); + if !status.success() && builder.is_verbose() { println!( "\n\ncommand did not execute successfully: {cmd:?}\n\ - expected success, got: {}", - result.status + expected success, got: {status}", ); } - result.status.success() + status.success() } struct Renderer<'a> { From 8199c950e83b1ae7913f5c1a9b5608065b299039 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 4 Jul 2025 20:51:17 +0530 Subject: [PATCH 32/68] make mark_as_executed private --- src/bootstrap/src/utils/exec.rs | 13 ++----------- src/bootstrap/src/utils/render_tests.rs | 9 +++------ 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index d1822752f920..c5b3c322be4d 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -211,15 +211,6 @@ impl<'a> BootstrapCommand { exec_ctx.as_ref().start(self, OutputMode::Capture, OutputMode::Print) } - /// Spawn the command in background, while capturing and returns a handle to stream the output. - #[track_caller] - pub fn stream_capture( - &'a mut self, - exec_ctx: impl AsRef, - ) -> Option { - exec_ctx.as_ref().stream(self, OutputMode::Capture, OutputMode::Capture) - } - /// Spawn the command in background, while capturing and returning stdout, and printing stderr. /// Returns None in dry-mode #[track_caller] @@ -232,7 +223,7 @@ impl<'a> BootstrapCommand { /// Mark the command as being executed, disarming the drop bomb. /// If this method is not called before the command is dropped, its drop will panic. - pub fn mark_as_executed(&mut self) { + fn mark_as_executed(&mut self) { self.drop_bomb.defuse(); } @@ -664,7 +655,7 @@ impl ExecutionContext { let stdout = child.stdout.take(); let stderr = child.stderr.take(); - return Some(StreamingCommand { child, stdout, stderr }); + Some(StreamingCommand { child, stdout, stderr }) } } diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 283563f3aca9..73a22ec28260 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -34,11 +34,6 @@ pub(crate) fn try_run_tests( cmd: &mut BootstrapCommand, stream: bool, ) -> bool { - if builder.config.dry_run() { - cmd.mark_as_executed(); - return true; - } - if !run_tests(builder, cmd, stream) { if builder.fail_fast { crate::exit!(1); @@ -54,7 +49,9 @@ pub(crate) fn try_run_tests( fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { builder.verbose(|| println!("running: {cmd:?}")); - let mut streaming_command = cmd.stream_capture_stdout(&builder.config.exec_ctx).unwrap(); + let Some(mut streaming_command) = cmd.stream_capture_stdout(&builder.config.exec_ctx) else { + return true; + }; // This runs until the stdout of the child is closed, which means the child exited. We don't // run this on another thread since the builder is not Sync. From 006e97a234baf050e599576a7bce239173ce5556 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 5 Jul 2025 14:54:12 +0800 Subject: [PATCH 33/68] Pretend in bootstrap snapshot tests that we always build in-tree LLVM --- src/bootstrap/src/utils/tests/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index b8984d1f3aaf..59c169b0f2b7 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -7,6 +7,7 @@ use tempfile::TempDir; use crate::core::builder::Builder; use crate::core::config::DryRun; +use crate::utils::helpers::get_host_target; use crate::{Build, Config, Flags, t}; pub mod git; @@ -91,6 +92,13 @@ impl ConfigBuilder { self.args.push("--set".to_string()); self.args.push("build.submodules=false".to_string()); + // Override any external LLVM set and inhibit CI LLVM; pretend that we're always building + // in-tree LLVM from sources. + self.args.push("--set".to_string()); + self.args.push("llvm.download-ci-llvm=false".to_string()); + self.args.push("--set".to_string()); + self.args.push(format!("target.'{}'.llvm-config=false", get_host_target())); + // Do not mess with the local rustc checkout build directory self.args.push("--build-dir".to_string()); self.args.push(self.directory.join("build").display().to_string()); From 4ae22fba5b4af7ffa223c46e7d81a15f53a6a387 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 4 Jul 2025 20:10:53 +0200 Subject: [PATCH 34/68] move the `va_copy`, `va_arg` and `va_end` to `core::intrinsics` --- library/core/src/ffi/va_list.rs | 18 +----------------- library/core/src/intrinsics/mod.rs | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 8f7c090bc1ba..88ad11977774 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -5,6 +5,7 @@ use crate::ffi::c_void; #[allow(unused_imports)] use crate::fmt; +use crate::intrinsics::{va_arg, va_copy, va_end}; use crate::marker::{PhantomData, PhantomInvariantLifetime}; use crate::ops::{Deref, DerefMut}; @@ -280,20 +281,3 @@ impl<'f> Drop for VaListImpl<'f> { // This works for now, since `va_end` is a no-op on all current LLVM targets. } } - -/// Destroy the arglist `ap` after initialization with `va_start` or -/// `va_copy`. -#[rustc_intrinsic] -#[rustc_nounwind] -unsafe fn va_end(ap: &mut VaListImpl<'_>); - -/// Copies the current location of arglist `src` to the arglist `dst`. -#[rustc_intrinsic] -#[rustc_nounwind] -unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); - -/// Loads an argument of type `T` from the `va_list` `ap` and increment the -/// argument `ap` points to. -#[rustc_intrinsic] -#[rustc_nounwind] -unsafe fn va_arg(ap: &mut VaListImpl<'_>) -> T; diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index ab99492638ec..791d10eda6d0 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -54,6 +54,7 @@ )] #![allow(missing_docs)] +use crate::ffi::va_list::{VaArgSafe, VaListImpl}; use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple}; use crate::ptr; @@ -3142,3 +3143,25 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize } ) } + +/// Copies the current location of arglist `src` to the arglist `dst`. +/// +/// FIXME: document safety requirements +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); + +/// Loads an argument of type `T` from the `va_list` `ap` and increment the +/// argument `ap` points to. +/// +/// FIXME: document safety requirements +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn va_arg(ap: &mut VaListImpl<'_>) -> T; + +/// Destroy the arglist `ap` after initialization with `va_start` or `va_copy`. +/// +/// FIXME: document safety requirements +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn va_end(ap: &mut VaListImpl<'_>); From 7405e2a9154268955de216840ef4dd7e975b0cd5 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 4 Jul 2025 19:20:09 +0800 Subject: [PATCH 35/68] Improve compiletest config documentation Including a bunch of FIXMEs. --- src/tools/compiletest/src/common.rs | 395 ++++++++++++++---- src/tools/compiletest/src/debuggers.rs | 2 + src/tools/compiletest/src/executor.rs | 12 +- src/tools/compiletest/src/lib.rs | 11 + src/tools/compiletest/src/runtest.rs | 22 +- .../compiletest/src/runtest/debuginfo.rs | 4 + 6 files changed, 353 insertions(+), 93 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index cdce5d941d01..7122746fa87e 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -172,207 +172,422 @@ pub enum Sanitizer { Hwaddress, } -/// Configuration for compiletest +/// Configuration for `compiletest` *per invocation*. +/// +/// In terms of `bootstrap`, this means that `./x test tests/ui tests/run-make` actually correspond +/// to *two* separate invocations of `compiletest`. +/// +/// FIXME: this `Config` struct should be broken up into smaller logically contained sub-config +/// structs, it's too much of a "soup" of everything at the moment. +/// +/// # Configuration sources +/// +/// Configuration values for `compiletest` comes from several sources: +/// +/// - CLI args passed from `bootstrap` while running the `compiletest` binary. +/// - Env vars. +/// - Discovery (e.g. trying to identify a suitable debugger based on filesystem discovery). +/// - Cached output of running the `rustc` under test (e.g. output of `rustc` print requests). +/// +/// FIXME: make sure we *clearly* account for sources of *all* config options. +/// +/// FIXME: audit these options to make sure we are not hashing less than necessary for build stamp +/// (for changed test detection). #[derive(Debug, Default, Clone)] pub struct Config { - /// `true` to overwrite stderr/stdout files instead of complaining about changes in output. + /// Some test [`Mode`]s support [snapshot testing], where a *reference snapshot* of outputs (of + /// `stdout`, `stderr`, or other form of artifacts) can be compared to the *actual output*. + /// + /// This option can be set to `true` to update the *reference snapshots* in-place, otherwise + /// `compiletest` will only try to compare. + /// + /// [snapshot testing]: https://jestjs.io/docs/snapshot-testing pub bless: bool, - /// Stop as soon as possible after any test fails. - /// May run a few more tests before stopping, due to threading. + /// Attempt to stop as soon as possible after any test fails. We may still run a few more tests + /// before stopping when multiple test threads are used. pub fail_fast: bool, - /// The library paths required for running the compiler. + /// Path to libraries needed to run the *staged* `rustc`-under-test on the **host** platform. + /// + /// FIXME: maybe rename this to reflect (1) which target platform (host, not target), and (2) + /// which `rustc` (the `rustc`-under-test, not the stage 0 `rustc` unless forced). pub compile_lib_path: Utf8PathBuf, - /// The library paths required for running compiled programs. + /// Path to libraries needed to run the compiled executable for the **target** platform. This + /// corresponds to the **target** sysroot libraries, including the **target** standard library. + /// + /// FIXME: maybe rename this to reflect (1) which target platform (target, not host), and (2) + /// what "run libraries" are against. + /// + /// FIXME: this is very under-documented in conjunction with the `remote-test-client` scheme and + /// `RUNNER` scheme to actually run the target executable under the target platform environment, + /// cf. [`Self::remote_test_client`] and [`Self::runner`]. pub run_lib_path: Utf8PathBuf, - /// The rustc executable. + /// Path to the *staged* `rustc`-under-test. Unless forced, this `rustc` is *staged*, and must + /// not be confused with [`Self::stage0_rustc_path`]. + /// + /// FIXME: maybe rename this to reflect that this is the `rustc`-under-test. pub rustc_path: Utf8PathBuf, - /// The cargo executable. + /// Path to a *staged* **host** platform cargo executable (unless stage 0 is forced). This + /// staged `cargo` is only used within `run-make` test recipes during recipe run time (and is + /// *not* used to compile the test recipes), and so must be staged as there may be differences + /// between e.g. beta `cargo` vs in-tree `cargo`. + /// + /// FIXME: maybe rename this to reflect that this is a *staged* host cargo. + /// + /// FIXME(#134109): split `run-make` into two test suites, a test suite *with* staged cargo, and + /// another test suite *without*. pub cargo_path: Option, - /// Rustc executable used to compile run-make recipes. + /// Path to the stage 0 `rustc` used to build `run-make` recipes. This must not be confused with + /// [`Self::rustc_path`]. pub stage0_rustc_path: Option, - /// The rustdoc executable. + /// Path to the `rustdoc`-under-test. Like [`Self::rustc_path`], this `rustdoc` is *staged*. pub rustdoc_path: Option, - /// The coverage-dump executable. + /// Path to the `src/tools/coverage-dump/` bootstrap tool executable. pub coverage_dump_path: Option, - /// The Python executable to use for LLDB and htmldocck. + /// Path to the Python 3 executable to use for LLDB and htmldocck. + /// + /// FIXME: the `lldb` setup currently requires I believe Python 3.10 **exactly**, it can't even + /// be Python 3.11 or 3.9... pub python: String, - /// The jsondocck executable. + /// Path to the `src/tools/jsondocck/` bootstrap tool executable. pub jsondocck_path: Option, - /// The jsondoclint executable. + /// Path to the `src/tools/jsondoclint/` bootstrap tool executable. pub jsondoclint_path: Option, - /// The LLVM `FileCheck` binary path. + /// Path to a host LLVM `FileCheck` executable. pub llvm_filecheck: Option, - /// Path to LLVM's bin directory. + /// Path to a host LLVM bintools directory. pub llvm_bin_dir: Option, - /// The path to the Clang executable to run Clang-based tests with. If - /// `None` then these tests will be ignored. + /// The path to the **target** `clang` executable to run `clang`-based tests with. If `None`, + /// then these tests will be ignored. pub run_clang_based_tests_with: Option, - /// The directory containing the sources. + /// Path to the directory containing the sources. This corresponds to the root folder of a + /// `rust-lang/rust` checkout. + /// + /// FIXME: this name is confusing, because this is actually `$checkout_root`, **not** the + /// `$checkout_root/src/` folder. pub src_root: Utf8PathBuf, - /// The directory containing the test suite sources. Must be a subdirectory of `src_root`. + + /// Path to the directory containing the test suites sources. This corresponds to the + /// `$src_root/tests/` folder. + /// + /// Must be an immediate subdirectory of [`Self::src_root`]. + /// + /// FIXME: this name is also confusing, maybe just call it `tests_root`. pub src_test_suite_root: Utf8PathBuf, - /// Root build directory (e.g. `build/`). + /// Path to the build directory (e.g. `build/`). pub build_root: Utf8PathBuf, - /// Test suite specific build directory (e.g. `build/host/test/ui/`). + + /// Path to the test suite specific build directory (e.g. `build/host/test/ui/`). + /// + /// Must be a subdirectory of [`Self::build_root`]. pub build_test_suite_root: Utf8PathBuf, - /// The directory containing the compiler sysroot + /// Path to the directory containing the sysroot of the `rustc`-under-test. + /// + /// When stage 0 is forced, this will correspond to the sysroot *of* that specified stage 0 + /// `rustc`. + /// + /// FIXME: this name is confusing, because it doesn't specify *which* compiler this sysroot + /// corresponds to. It's actually the `rustc`-under-test, and not the bootstrap `rustc`, unless + /// stage 0 is forced and no custom stage 0 `rustc` was otherwise specified (so that it + /// *happens* to run against the bootstrap `rustc`, but this non-custom bootstrap `rustc` case + /// is not really supported). pub sysroot_base: Utf8PathBuf, /// The number of the stage under test. pub stage: u32, + /// The id of the stage under test (stage1-xxx, etc). + /// + /// FIXME: reconsider this string; this is hashed for test build stamp. pub stage_id: String, - /// The test mode, e.g. ui or debuginfo. + /// The test [`Mode`]. E.g. [`Mode::Ui`]. Each test mode can correspond to one or more test + /// suites. + /// + /// FIXME: stop using stringly-typed test suites! pub mode: Mode, - /// The test suite (essentially which directory is running, but without the - /// directory prefix such as tests) + /// The test suite. + /// + /// Example: `tests/ui/` is the "UI" test *suite*, which happens to also be of the [`Mode::Ui`] + /// test *mode*. + /// + /// Note that the same test directory (e.g. `tests/coverage/`) may correspond to multiple test + /// modes, e.g. `tests/coverage/` can be run under both [`Mode::CoverageRun`] and + /// [`Mode::CoverageMap`]. + /// + /// FIXME: stop using stringly-typed test suites! pub suite: String, - /// The debugger to use in debuginfo mode. Unset otherwise. + /// When specified, **only** the specified [`Debugger`] will be used to run against the + /// `tests/debuginfo` test suite. When unspecified, `compiletest` will attempt to find all three + /// of {`lldb`, `cdb`, `gdb`} implicitly, and then try to run the `debuginfo` test suite against + /// all three debuggers. + /// + /// FIXME: this implicit behavior is really nasty, in that it makes it hard for the user to + /// control *which* debugger(s) are available and used to run the debuginfo test suite. We + /// should have `bootstrap` allow the user to *explicitly* configure the debuggers, and *not* + /// try to implicitly discover some random debugger from the user environment. This makes the + /// debuginfo test suite particularly hard to work with. pub debugger: Option, - /// Run ignored tests + /// Run ignored tests *unconditionally*, overriding their ignore reason. + /// + /// FIXME: this is wired up through the test execution logic, but **not** accessible from + /// `bootstrap` directly; `compiletest` exposes this as `--ignored`. I.e. you'd have to use `./x + /// test $test_suite -- --ignored=true`. pub run_ignored: bool, - /// Whether rustc was built with debug assertions. + /// Whether *staged* `rustc`-under-test was built with debug assertions. + /// + /// FIXME: make it clearer that this refers to the staged `rustc`-under-test, not stage 0 + /// `rustc`. pub with_rustc_debug_assertions: bool, - /// Whether std was built with debug assertions. + /// Whether *staged* `std` was built with debug assertions. + /// + /// FIXME: make it clearer that this refers to the staged `std`, not stage 0 `std`. pub with_std_debug_assertions: bool, - /// Only run tests that match these filters + /// Only run tests that match these filters (using `libtest` "test name contains" filter logic). + /// + /// FIXME(#139660): the current hand-rolled test executor intentionally mimics the `libtest` + /// "test name contains" filter matching logic to preserve previous `libtest` executor behavior, + /// but this is often not intuitive. We should consider changing that behavior with an MCP to do + /// test path *prefix* matching which better corresponds to how `compiletest` `tests/` are + /// organized, and how users would intuitively expect the filtering logic to work like. pub filters: Vec, - /// Skip tests matching these substrings. Corresponds to - /// `test::TestOpts::skip`. `filter_exact` does not apply to these flags. + /// Skip tests matching these substrings. The matching logic exactly corresponds to + /// [`Self::filters`] but inverted. + /// + /// FIXME(#139660): ditto on test matching behavior. pub skip: Vec, - /// Exactly match the filter, rather than a substring + /// Exactly match the filter, rather than a substring. + /// + /// FIXME(#139660): ditto on test matching behavior. pub filter_exact: bool, - /// Force the pass mode of a check/build/run-pass test to this mode. + /// Force the pass mode of a check/build/run test to instead use this mode instead. + /// + /// FIXME: make it even more obvious (especially in PR CI where `--pass=check` is used) when a + /// pass mode is forced when the test fails, because it can be very non-obvious when e.g. an + /// error is emitted only when `//@ build-pass` but not `//@ check-pass`. pub force_pass_mode: Option, - /// Explicitly enable or disable running. + /// Explicitly enable or disable running of the target test binary. + /// + /// FIXME: this scheme is a bit confusing, and at times questionable. Re-evaluate this run + /// scheme. + /// + /// FIXME: Currently `--run` is a tri-state, it can be `--run={auto,always,never}`, and when + /// `--run=auto` is specified, it's run if the platform doesn't end with `-fuchsia`. See + /// [`Config::run_enabled`]. pub run: Option, - /// A command line to prefix program execution with, - /// for running under valgrind for example. + /// A command line to prefix target program execution with, for running under valgrind for + /// example, i.e. `$runner target.exe [args..]`. Similar to `CARGO_*_RUNNER` configuration. /// - /// Similar to `CARGO_*_RUNNER` configuration. + /// Note: this is not to be confused with [`Self::remote_test_client`], which is a different + /// scheme. + /// + /// FIXME: the runner scheme is very under-documented. pub runner: Option, - /// Flags to pass to the compiler when building for the host + /// Compiler flags to pass to the *staged* `rustc`-under-test when building for the **host** + /// platform. pub host_rustcflags: Vec, - /// Flags to pass to the compiler when building for the target + /// Compiler flags to pass to the *staged* `rustc`-under-test when building for the **target** + /// platform. pub target_rustcflags: Vec, - /// Whether the compiler and stdlib has been built with randomized struct layouts + /// Whether the *staged* `rustc`-under-test and the associated *staged* `std` has been built + /// with randomized struct layouts. pub rust_randomized_layout: bool, - /// Whether tests should be optimized by default. Individual test-suites and test files may - /// override this setting. + /// Whether tests should be optimized by default (`-O`). Individual test suites and test files + /// may override this setting. + /// + /// FIXME: this flag / config option is somewhat misleading. For instance, in ui tests, it's + /// *only* applied to the [`PassMode::Run`] test crate and not its auxiliaries. pub optimize_tests: bool, - /// Target system to be tested + /// Target platform tuple. pub target: String, - /// Host triple for the compiler being invoked + /// Host platform tuple. pub host: String, - /// Path to / name of the Microsoft Console Debugger (CDB) executable + /// Path to / name of the Microsoft Console Debugger (CDB) executable. + /// + /// FIXME: this is an *opt-in* "override" option. When this isn't provided, we try to conjure a + /// cdb by looking at the user's program files on Windows... See `debuggers::find_cdb`. pub cdb: Option, - /// Version of CDB + /// Version of CDB. + /// + /// FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! + /// + /// FIXME: audit cdb version gating. pub cdb_version: Option<[u16; 4]>, - /// Path to / name of the GDB executable + /// Path to / name of the GDB executable. + /// + /// FIXME: the fallback path when `gdb` isn't provided tries to find *a* `gdb` or `gdb.exe` from + /// `PATH`, which is... arguably questionable. + /// + /// FIXME: we are propagating a python from `PYTHONPATH`, not from an explicit config for gdb + /// debugger script. pub gdb: Option, /// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch + /// + /// FIXME: this gdb version gating scheme is possibly questionable -- gdb does not use semver, + /// only its major version is likely materially meaningful, cf. + /// . Even the major version I'm not sure + /// is super meaningful. Maybe min gdb `major.minor` version gating is sufficient for the + /// purposes of debuginfo tests? + /// + /// FIXME: `gdb_version` is *derived* from gdb, but it's *not* technically a config! pub gdb_version: Option, - /// Version of LLDB + /// Version of LLDB. + /// + /// FIXME: `lldb_version` is *derived* from lldb, but it's *not* technically a config! pub lldb_version: Option, - /// Version of LLVM + /// Version of LLVM. + /// + /// FIXME: Audit the fallback derivation of + /// [`crate::directives::extract_llvm_version_from_binary`], that seems very questionable? pub llvm_version: Option, - /// Is LLVM a system LLVM + /// Is LLVM a system LLVM. pub system_llvm: bool, - /// Path to the android tools + /// Path to the android tools. + /// + /// Note: this is only used for android gdb debugger script in the debuginfo test suite. + /// + /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for + /// `arm-linux-androideabi` target. pub android_cross_path: Utf8PathBuf, - /// Extra parameter to run adb on arm-linux-androideabi + /// Extra parameter to run adb on `arm-linux-androideabi`. + /// + /// FIXME: is this *only* `arm-linux-androideabi`, or is it also for other Tier 2/3 android + /// targets? + /// + /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for + /// `arm-linux-androideabi` target. pub adb_path: String, - /// Extra parameter to run test suite on arm-linux-androideabi + /// Extra parameter to run test suite on `arm-linux-androideabi`. + /// + /// FIXME: is this *only* `arm-linux-androideabi`, or is it also for other Tier 2/3 android + /// targets? + /// + /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for + /// `arm-linux-androideabi` target. pub adb_test_dir: String, - /// status whether android device available or not + /// Status whether android device available or not. When unavailable, this will cause tests to + /// panic when the test binary is attempted to be run. + /// + /// FIXME: take a look at this; this also influences adb in gdb code paths in a strange way. pub adb_device_status: bool, - /// the path containing LLDB's Python module + /// Path containing LLDB's Python module. + /// + /// FIXME: `PYTHONPATH` takes precedence over this flag...? See `runtest::run_lldb`. pub lldb_python_dir: Option, - /// Explain what's going on + /// Verbose dump a lot of info. + /// + /// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump. pub verbose: bool, - /// Print one character per test instead of one line + /// (Useless) Adjust libtest output format. + /// + /// FIXME: the hand-rolled executor does not support non-JSON output, because `compiletest` need + /// to package test outcome as `libtest`-esque JSON that `bootstrap` can intercept *anyway*. + /// However, now that we don't use the `libtest` executor, this is useless. pub format: OutputFormat, - /// Whether to use colors in test. + /// Whether to use colors in test output. + /// + /// Note: the exact control mechanism is delegated to [`colored`]. pub color: ColorConfig, - /// where to find the remote test client process, if we're using it + /// Where to find the remote test client process, if we're using it. + /// + /// Note: this is *only* used for target platform executables created by `run-make` test + /// recipes. + /// + /// Note: this is not to be confused with [`Self::runner`], which is a different scheme. + /// + /// FIXME: the `remote_test_client` scheme is very under-documented. pub remote_test_client: Option, - /// mode describing what file the actual ui output will be compared to + /// [`CompareMode`] describing what file the actual ui output will be compared to. + /// + /// FIXME: currently, [`CompareMode`] is a mishmash of lot of things (different borrow-checker + /// model, different trait solver, different debugger, etc.). pub compare_mode: Option, /// If true, this will generate a coverage file with UI test files that run `MachineApplicable` /// diagnostics but are missing `run-rustfix` annotations. The generated coverage file is - /// created in `/rustfix_missing_coverage.txt` + /// created in `$test_suite_build_root/rustfix_missing_coverage.txt` pub rustfix_coverage: bool, - /// whether to run `tidy` (html-tidy) when a rustdoc test fails + /// Whether to run `tidy` (html-tidy) when a rustdoc test fails. pub has_html_tidy: bool, - /// whether to run `enzyme` autodiff tests + /// Whether to run `enzyme` autodiff tests. pub has_enzyme: bool, - /// The current Rust channel + /// The current Rust channel info. + /// + /// FIXME: treat this more carefully; "stable", "beta" and "nightly" are definitely valid, but + /// channel might also be "dev" or such, which should be treated as "nightly". pub channel: String, - /// Whether adding git commit information such as the commit hash has been enabled for building + /// Whether adding git commit information such as the commit hash has been enabled for building. + /// + /// FIXME: `compiletest` cannot trust `bootstrap` for this information, because `bootstrap` can + /// have bugs and had bugs on that logic. We need to figure out how to obtain this e.g. directly + /// from CI or via git locally. pub git_hash: bool, - /// The default Rust edition + /// The default Rust edition. + /// + /// FIXME: perform stronger validation for this. There are editions that *definitely* exists, + /// but there might also be "future" edition. pub edition: Option, - // Configuration for various run-make tests frobbing things like C compilers - // or querying about various LLVM component information. + // Configuration for various run-make tests frobbing things like C compilers or querying about + // various LLVM component information. + // + // FIXME: this really should be better packaged together. + // FIXME: these need better docs, e.g. for *host*, or for *target*? pub cc: String, pub cxx: String, pub cflags: String, @@ -382,41 +597,63 @@ pub struct Config { pub host_linker: Option, pub llvm_components: String, - /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests + /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests. pub nodejs: Option, - /// Path to a npm executable. Used for rustdoc GUI tests + /// Path to a npm executable. Used for rustdoc GUI tests. pub npm: Option, /// Whether to rerun tests even if the inputs are unchanged. pub force_rerun: bool, - /// Only rerun the tests that result has been modified according to Git status + /// Only rerun the tests that result has been modified according to `git status`. + /// + /// FIXME: this is undocumented. + /// + /// FIXME: how does this interact with [`Self::force_rerun`]? pub only_modified: bool, + // FIXME: these are really not "config"s, but rather are information derived from + // `rustc`-under-test. This poses an interesting conundrum: if we're testing the + // `rustc`-under-test, can we trust its print request outputs and target cfgs? In theory, this + // itself can break or be unreliable -- ideally, we'd be sharing these kind of information not + // through `rustc`-under-test's execution output. In practice, however, print requests are very + // unlikely to completely break (we also have snapshot ui tests for them). Furthermore, even if + // we share them via some kind of static config, that static config can still be wrong! Who + // tests the tester? Therefore, we make a pragmatic compromise here, and use information derived + // from print requests produced by the `rustc`-under-test. + // + // FIXME: move them out from `Config`, because they are *not* configs. pub target_cfgs: OnceLock, pub builtin_cfg_names: OnceLock>, pub supported_crate_types: OnceLock>, + /// FIXME: this is why we still need to depend on *staged* `std`, it's because we currently rely + /// on `#![feature(internal_output_capture)]` for [`std::io::set_output_capture`] to implement + /// `libtest`-esque `--no-capture`. + /// + /// FIXME: rename this to the more canonical `no_capture`, or better, invert this to `capture` + /// to avoid `!nocapture` double-negatives. pub nocapture: bool, - // Needed both to construct build_helper::git::GitConfig + /// Needed both to construct [`build_helper::git::GitConfig`]. pub nightly_branch: String, pub git_merge_commit_email: String, - /// True if the profiler runtime is enabled for this target. - /// Used by the "needs-profiler-runtime" directive in test files. + /// True if the profiler runtime is enabled for this target. Used by the + /// `needs-profiler-runtime` directive in test files. pub profiler_runtime: bool, /// Command for visual diff display, e.g. `diff-tool --color=always`. pub diff_command: Option, - /// Path to minicore aux library, used for `no_core` tests that need `core` stubs in - /// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g. - /// ABI tests. + /// Path to minicore aux library (`tests/auxiliary/minicore.rs`), used for `no_core` tests that + /// need `core` stubs in cross-compilation scenarios that do not otherwise want/need to + /// `-Zbuild-std`. Used in e.g. ABI tests. pub minicore_path: Utf8PathBuf, } impl Config { + /// FIXME: this run scheme is... confusing. pub fn run_enabled(&self) -> bool { self.run.unwrap_or_else(|| { // Auto-detect whether to run based on the platform. diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index c133d7fd4fbd..0edc3d82d4f5 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -51,6 +51,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> { pub(crate) fn configure_lldb(config: &Config) -> Option> { config.lldb_python_dir.as_ref()?; + // FIXME: this is super old if let Some(350) = config.lldb_version { println!( "WARNING: The used version of LLDB (350) has a \ @@ -78,6 +79,7 @@ fn is_pc_windows_msvc_target(target: &str) -> bool { target.ends_with("-pc-windows-msvc") } +/// FIXME: this is very questionable... fn find_cdb(target: &str) -> Option { if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { return None; diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 0c4ef36828a0..df64f12784f5 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -207,9 +207,9 @@ impl TestOutcome { /// /// Adapted from `filter_tests` in libtest. /// -/// FIXME(#139660): After the libtest dependency is removed, redesign the whole -/// filtering system to do a better job of understanding and filtering _paths_, -/// instead of being tied to libtest's substring/exact matching behaviour. +/// FIXME(#139660): After the libtest dependency is removed, redesign the whole filtering system to +/// do a better job of understanding and filtering _paths_, instead of being tied to libtest's +/// substring/exact matching behaviour. fn filter_tests(opts: &Config, tests: Vec) -> Vec { let mut filtered = tests; @@ -235,9 +235,9 @@ fn filter_tests(opts: &Config, tests: Vec) -> Vec /// /// Copied from `get_concurrency` in libtest. /// -/// FIXME(#139660): After the libtest dependency is removed, consider making -/// bootstrap specify the number of threads on the command-line, instead of -/// propagating the `RUST_TEST_THREADS` environment variable. +/// FIXME(#139660): After the libtest dependency is removed, consider making bootstrap specify the +/// number of threads on the command-line, instead of propagating the `RUST_TEST_THREADS` +/// environment variable. fn get_concurrency() -> usize { if let Ok(value) = env::var("RUST_TEST_THREADS") { match value.parse::>().ok() { diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index dfce4b8b408b..9819079e284f 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -242,9 +242,12 @@ pub fn parse_config(args: Vec) -> Config { let target = opt_str2(matches.opt_str("target")); let android_cross_path = opt_path(matches, "android-cross-path"); + // FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! let (cdb, cdb_version) = debuggers::analyze_cdb(matches.opt_str("cdb"), &target); + // FIXME: `gdb_version` is *derived* from gdb, but it's *not* technically a config! let (gdb, gdb_version) = debuggers::analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); + // FIXME: `lldb_version` is *derived* from lldb, but it's *not* technically a config! let lldb_version = matches.opt_str("lldb-version").as_deref().and_then(debuggers::extract_lldb_version); let color = match matches.opt_str("color").as_deref() { @@ -253,6 +256,9 @@ pub fn parse_config(args: Vec) -> Config { Some("never") => ColorConfig::NeverColor, Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; + // FIXME: this is very questionable, we really should be obtaining LLVM version info from + // `bootstrap`, and not trying to be figuring out that in `compiletest` by running the + // `FileCheck` binary. let llvm_version = matches.opt_str("llvm-version").as_deref().map(directives::extract_llvm_version).or_else( || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), @@ -370,6 +376,7 @@ pub fn parse_config(args: Vec) -> Config { mode.parse::() .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode)) }), + // FIXME: this run scheme is... confusing. run: matches.opt_str("run").and_then(|mode| match mode.as_str() { "auto" => None, "always" => Some(true), @@ -545,6 +552,10 @@ pub fn run_tests(config: Arc) { Some(Debugger::Cdb) => configs.extend(debuggers::configure_cdb(&config)), Some(Debugger::Gdb) => configs.extend(debuggers::configure_gdb(&config)), Some(Debugger::Lldb) => configs.extend(debuggers::configure_lldb(&config)), + // FIXME: the *implicit* debugger discovery makes it really difficult to control + // which {`cdb`, `gdb`, `lldb`} are used. These should **not** be implicitly + // discovered by `compiletest`; these should be explicit `bootstrap` configuration + // options that are passed to `compiletest`! None => { configs.extend(debuggers::configure_cdb(&config)); configs.extend(debuggers::configure_gdb(&config)); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f8bf4ee3022e..0b07bb4da9b4 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -121,6 +121,8 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) { } _ => { + // FIXME: this logic seems strange as well. + // android has its own gdb handling if config.debugger == Some(Debugger::Gdb) && config.gdb.is_none() { panic!("gdb not available but debuginfo gdb debuginfo test requested"); @@ -1055,18 +1057,20 @@ impl<'test> TestCx<'test> { let proc_res = match &*self.config.target { // This is pretty similar to below, we're transforming: // - // program arg1 arg2 + // ```text + // program arg1 arg2 + // ``` // // into // - // remote-test-client run program 2 support-lib.so support-lib2.so arg1 arg2 + // ```text + // remote-test-client run program 2 support-lib.so support-lib2.so arg1 arg2 + // ``` // - // The test-client program will upload `program` to the emulator - // along with all other support libraries listed (in this case - // `support-lib.so` and `support-lib2.so`. It will then execute - // the program on the emulator with the arguments specified - // (in the environment we give the process) and then report back - // the same result. + // The test-client program will upload `program` to the emulator along with all other + // support libraries listed (in this case `support-lib.so` and `support-lib2.so`. It + // will then execute the program on the emulator with the arguments specified (in the + // environment we give the process) and then report back the same result. _ if self.config.remote_test_client.is_some() => { let aux_dir = self.aux_output_dir_name(); let ProcArgs { prog, args } = self.make_run_args(); @@ -1532,6 +1536,8 @@ impl<'test> TestCx<'test> { )); // Optionally prevent default --sysroot if specified in test compile-flags. + // + // FIXME: I feel like this logic is fairly sus. if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) && !self.config.host_rustcflags.iter().any(|flag| flag == "--sysroot") { diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index d9e1e4dfc8dd..471e4a4c8193 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -322,6 +322,8 @@ impl TestCx<'_> { &["-quiet".as_ref(), "-batch".as_ref(), "-nx".as_ref(), &debugger_script]; let mut gdb = Command::new(self.config.gdb.as_ref().unwrap()); + + // FIXME: we are propagating `PYTHONPATH` from the environment, not a compiletest flag! let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { format!("{pp}:{rust_pp_module_abs_path}") } else { @@ -443,6 +445,8 @@ impl TestCx<'_> { fn run_lldb(&self, test_executable: &Utf8Path, debugger_script: &Utf8Path) -> ProcRes { // Prepare the lldb_batchmode which executes the debugger script let lldb_script_path = self.config.src_root.join("src/etc/lldb_batchmode.py"); + + // FIXME: `PYTHONPATH` takes precedence over the flag...? let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { format!("{pp}:{}", self.config.lldb_python_dir.as_ref().unwrap()) } else { From 226b0fbe11812c71c8002b10a40063571cf52b3f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 5 Jul 2025 08:26:32 +0200 Subject: [PATCH 36/68] use `is_multiple_of` instead of manual modulo --- compiler/rustc_borrowck/src/polonius/legacy/location.rs | 2 +- compiler/rustc_codegen_llvm/src/abi.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 4 ++-- compiler/rustc_query_system/src/query/plumbing.rs | 2 +- compiler/rustc_target/src/callconv/sparc64.rs | 6 +++--- compiler/rustc_ty_utils/src/layout/invariant.rs | 2 +- library/core/src/slice/mod.rs | 8 ++++---- library/core/src/slice/sort/shared/smallsort.rs | 2 +- library/core/src/str/count.rs | 2 +- library/core/src/str/validations.rs | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/legacy/location.rs b/compiler/rustc_borrowck/src/polonius/legacy/location.rs index 5f816bb9bbdc..618119a6a3d6 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/location.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/location.rs @@ -109,6 +109,6 @@ impl PoloniusLocationTable { impl LocationIndex { fn is_start(self) -> bool { // even indices are start points; odd indices are mid points - (self.index() % 2) == 0 + self.index().is_multiple_of(2) } } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 4b07c8aef915..009e7e2487b6 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -146,7 +146,7 @@ impl LlvmType for CastTarget { "total size {:?} cannot be divided into units of zero size", self.rest.total ); - if self.rest.total.bytes() % self.rest.unit.size.bytes() != 0 { + if !self.rest.total.bytes().is_multiple_of(self.rest.unit.size.bytes()) { assert_eq!(self.rest.unit.kind, RegKind::Integer, "only int regs can be split"); } self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes()) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ff822b52a8df..c97d53a45de7 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -537,7 +537,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[inline] fn is_offset_misaligned(offset: u64, align: Align) -> Option { - if offset % align.bytes() == 0 { + if offset.is_multiple_of(align.bytes()) { None } else { // The biggest power of two through which `offset` is divisible. @@ -1554,7 +1554,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If the allocation is N-aligned, and the offset is not divisible by N, // then `base + offset` has a non-zero remainder after division by `N`, // which means `base + offset` cannot be null. - if offset.bytes() % info.align.bytes() != 0 { + if !offset.bytes().is_multiple_of(info.align.bytes()) { return interp_ok(false); } // We don't know enough, this might be null. diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3c1fc7317848..06e59eb4cccd 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -597,7 +597,7 @@ where // from disk. Re-hashing results is fairly expensive, so we can't // currently afford to verify every hash. This subset should still // give us some coverage of potential bugs though. - let try_verify = prev_fingerprint.split().1.as_u64() % 32 == 0; + let try_verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32); if std::intrinsics::unlikely( try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich, ) { diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 186826c08fcb..ecc9067ced35 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -90,7 +90,7 @@ where _ => {} } - if (offset.bytes() % 4) != 0 + if !offset.bytes().is_multiple_of(4) && matches!(scalar2.primitive(), Primitive::Float(Float::F32 | Float::F64)) { offset += Size::from_bytes(4 - (offset.bytes() % 4)); @@ -181,7 +181,7 @@ where // Structure { float, int, int } doesn't like to be handled like // { float, long int }. Other way around it doesn't mind. if data.last_offset < arg.layout.size - && (data.last_offset.bytes() % 8) != 0 + && !data.last_offset.bytes().is_multiple_of(8) && data.prefix_index < data.prefix.len() { data.prefix[data.prefix_index] = Some(Reg::i32()); @@ -190,7 +190,7 @@ where } let mut rest_size = arg.layout.size - data.last_offset; - if (rest_size.bytes() % 8) != 0 && data.prefix_index < data.prefix.len() { + if !rest_size.bytes().is_multiple_of(8) && data.prefix_index < data.prefix.len() { data.prefix[data.prefix_index] = Some(Reg::i32()); rest_size = rest_size - Reg::i32().size; } diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 4b65c05d0e9f..1311ee31182c 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout}; pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { let tcx = cx.tcx(); - if layout.size.bytes() % layout.align.abi.bytes() != 0 { + if !layout.size.bytes().is_multiple_of(layout.align.abi.bytes()) { bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); } if layout.size.bytes() >= tcx.data_layout.obj_size_bound() { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 3a3f44c6b854..dc09ba8d788f 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1316,7 +1316,7 @@ impl [T] { assert_unsafe_precondition!( check_language_ub, "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", - (n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0, + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n), ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { exact_div(self.len(), N) }; @@ -1512,7 +1512,7 @@ impl [T] { assert_unsafe_precondition!( check_language_ub, "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", - (n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0 + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n) ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { exact_div(self.len(), N) }; @@ -4866,7 +4866,7 @@ impl [T] { let byte_offset = elem_start.wrapping_sub(self_start); - if byte_offset % size_of::() != 0 { + if !byte_offset.is_multiple_of(size_of::()) { return None; } @@ -4920,7 +4920,7 @@ impl [T] { let byte_start = subslice_start.wrapping_sub(self_start); - if byte_start % size_of::() != 0 { + if !byte_start.is_multiple_of(size_of::()) { return None; } diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index 4280f7570db4..400daba16c1b 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -823,7 +823,7 @@ unsafe fn bidirectional_merge bool>( let right_end = right_rev.wrapping_add(1); // Odd length, so one element is left unconsumed in the input. - if len % 2 != 0 { + if !len.is_multiple_of(2) { let left_nonempty = left < left_end; let last_src = if left_nonempty { left } else { right }; ptr::copy_nonoverlapping(last_src, dst, 1); diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs index 452403b23dee..f59ad3e66b43 100644 --- a/library/core/src/str/count.rs +++ b/library/core/src/str/count.rs @@ -52,7 +52,7 @@ fn do_count_chars(s: &str) -> usize { // Check the properties of `CHUNK_SIZE` and `UNROLL_INNER` that are required // for correctness. const _: () = assert!(CHUNK_SIZE < 256); - const _: () = assert!(CHUNK_SIZE % UNROLL_INNER == 0); + const _: () = assert!(CHUNK_SIZE.is_multiple_of(UNROLL_INNER)); // SAFETY: transmuting `[u8]` to `[usize]` is safe except for size // differences which are handled by `align_to`. diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index 8174e4ff97df..b54d6478e584 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -219,7 +219,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // Ascii case, try to skip forward quickly. // When the pointer is aligned, read 2 words of data per iteration // until we find a word containing a non-ascii byte. - if align != usize::MAX && align.wrapping_sub(index) % USIZE_BYTES == 0 { + if align != usize::MAX && align.wrapping_sub(index).is_multiple_of(USIZE_BYTES) { let ptr = v.as_ptr(); while index < blocks_end { // SAFETY: since `align - index` and `ascii_block_size` are From ed3711ea29398b09483e4e2a3930567e9ba81d93 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 5 Jul 2025 08:36:27 +0200 Subject: [PATCH 37/68] use `div_ceil` instead of manual logic --- compiler/rustc_abi/src/lib.rs | 3 +-- compiler/rustc_codegen_llvm/src/va_arg.rs | 4 ++-- compiler/rustc_index/src/bit_set.rs | 4 ++-- compiler/rustc_passes/src/liveness/rwu_table.rs | 2 +- compiler/rustc_serialize/src/leb128.rs | 2 +- compiler/rustc_span/src/edit_distance.rs | 2 +- compiler/rustc_target/src/callconv/x86.rs | 2 +- compiler/rustc_target/src/callconv/x86_64.rs | 2 +- compiler/rustc_target/src/callconv/xtensa.rs | 2 +- library/core/src/slice/sort/stable/drift.rs | 4 ++-- library/core/src/str/iter.rs | 6 +++--- library/portable-simd/crates/core_simd/src/lane_count.rs | 2 +- 12 files changed, 17 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 0df8921c9b72..a438545c76f1 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -527,8 +527,7 @@ impl Size { /// not a multiple of 8. pub fn from_bits(bits: impl TryInto) -> Size { let bits = bits.try_into().ok().unwrap(); - // Avoid potential overflow from `bits + 7`. - Size { raw: bits / 8 + ((bits % 8) + 7) / 8 } + Size { raw: bits.div_ceil(8) } } #[inline] diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 4fe4c9bcbf26..486dc894a4e3 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -172,10 +172,10 @@ fn emit_aapcs_va_arg<'ll, 'tcx>( let gr_type = target_ty.is_any_ptr() || target_ty.is_integral(); let (reg_off, reg_top, slot_size) = if gr_type { - let nreg = (layout.size.bytes() + 7) / 8; + let nreg = layout.size.bytes().div_ceil(8); (gr_offs, gr_top, nreg * 8) } else { - let nreg = (layout.size.bytes() + 15) / 16; + let nreg = layout.size.bytes().div_ceil(16); (vr_offs, vr_top, nreg * 16) }; diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index a4885aabe1ff..645d95b1dba9 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1744,13 +1744,13 @@ impl SparseBitMatrix { #[inline] fn num_words(domain_size: T) -> usize { - (domain_size.index() + WORD_BITS - 1) / WORD_BITS + domain_size.index().div_ceil(WORD_BITS) } #[inline] fn num_chunks(domain_size: T) -> usize { assert!(domain_size.index() > 0); - (domain_size.index() + CHUNK_BITS - 1) / CHUNK_BITS + domain_size.index().div_ceil(CHUNK_BITS) } #[inline] diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs index 4c1f6ea141e6..a1177946f868 100644 --- a/compiler/rustc_passes/src/liveness/rwu_table.rs +++ b/compiler/rustc_passes/src/liveness/rwu_table.rs @@ -44,7 +44,7 @@ impl RWUTable { const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS; pub(super) fn new(live_nodes: usize, vars: usize) -> RWUTable { - let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT; + let live_node_words = vars.div_ceil(Self::WORD_RWU_COUNT); Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] } } diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index 954c1f728f2f..da328dcea033 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -7,7 +7,7 @@ use crate::serialize::Decoder; /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type pub const fn max_leb128_len() -> usize { // The longest LEB128 encoding for an integer uses 7 bits per byte. - (size_of::() * 8 + 6) / 7 + (size_of::() * 8).div_ceil(7) } /// Returns the length of the longest LEB128 encoding of all supported integer types. diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 4f3202b694c1..416e9daa8fb0 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -130,7 +130,7 @@ pub fn edit_distance_with_substrings(a: &str, b: &str, limit: usize) -> Option( continue; } - let size_in_regs = (arg.layout.size.bits() + 31) / 32; + let size_in_regs = arg.layout.size.bits().div_ceil(32); if size_in_regs == 0 { continue; diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 700ee73c8fdc..d8db7ed6e4c0 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -95,7 +95,7 @@ where Ok(()) } - let n = ((arg.layout.size.bytes() + 7) / 8) as usize; + let n = arg.layout.size.bytes().div_ceil(8) as usize; if n > MAX_EIGHTBYTES { return Err(Memory); } diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index b687f0e20c66..a73a70a1a0c0 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -54,7 +54,7 @@ where // Determine the number of GPRs needed to pass the current argument // according to the ABI. 2*XLen-aligned varargs are passed in "aligned" // register pairs, so may consume 3 registers. - let mut needed_arg_gprs = (size + 32 - 1) / 32; + let mut needed_arg_gprs = size.div_ceil(32); if needed_align == 64 { needed_arg_gprs += *arg_gprs_left % 2; } diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs index cf1df1e91a50..1edffe095a89 100644 --- a/library/core/src/slice/sort/stable/drift.rs +++ b/library/core/src/slice/sort/stable/drift.rs @@ -158,7 +158,7 @@ fn merge_tree_scale_factor(n: usize) -> u64 { panic!("Platform not supported"); } - ((1 << 62) + n as u64 - 1) / n as u64 + (1u64 << 62).div_ceil(n as u64) } // Note: merge_tree_depth output is < 64 when left < right as f*x and f*y must @@ -182,7 +182,7 @@ fn sqrt_approx(n: usize) -> usize { // Finally we note that the exponentiation / division can be done directly // with shifts. We OR with 1 to avoid zero-checks in the integer log. let ilog = (n | 1).ilog2(); - let shift = (1 + ilog) / 2; + let shift = ilog.div_ceil(2); ((1 << shift) + (n >> shift)) / 2 } diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 425c4eaee28e..bcf886484add 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -102,7 +102,7 @@ impl<'a> Iterator for Chars<'a> { // `(len + 3)` can't overflow, because we know that the `slice::Iter` // belongs to a slice in memory which has a maximum length of // `isize::MAX` (that's well below `usize::MAX`). - ((len + 3) / 4, Some(len)) + (len.div_ceil(4), Some(len)) } #[inline] @@ -1532,11 +1532,11 @@ impl<'a> Iterator for EncodeUtf16<'a> { // belongs to a slice in memory which has a maximum length of // `isize::MAX` (that's well below `usize::MAX`) if self.extra == 0 { - ((len + 2) / 3, Some(len)) + (len.div_ceil(3), Some(len)) } else { // We're in the middle of a surrogate pair, so add the remaining // surrogate to the bounds. - ((len + 2) / 3 + 1, Some(len + 1)) + (len.div_ceil(3) + 1, Some(len + 1)) } } } diff --git a/library/portable-simd/crates/core_simd/src/lane_count.rs b/library/portable-simd/crates/core_simd/src/lane_count.rs index 280b27bc9bc6..bbdfd5f5f3ed 100644 --- a/library/portable-simd/crates/core_simd/src/lane_count.rs +++ b/library/portable-simd/crates/core_simd/src/lane_count.rs @@ -8,7 +8,7 @@ pub struct LaneCount; impl LaneCount { /// The number of bytes in a bitmask with this many lanes. - pub const BITMASK_LEN: usize = (N + 7) / 8; + pub const BITMASK_LEN: usize = N.div_ceil(8); } /// Statically guarantees that a lane count is marked as supported. From 6b71399d3850216f9fab05bc99d63854df731e6a Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 3 Jul 2025 21:36:43 -0700 Subject: [PATCH 38/68] mbe: Introduce an enum for which part of a rule we're parsing Rather than a `bool` that's `true` for the LHS and `false` for the RHS, use a self-documenting enum. --- compiler/rustc_expand/src/mbe/macro_rules.rs | 5 +- compiler/rustc_expand/src/mbe/quoted.rs | 48 ++++++++++++++------ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 2ffd4e3cf285..16b9fef6a21c 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -36,6 +36,7 @@ use crate::base::{ }; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser}; +use crate::mbe::quoted::RulePart; use crate::mbe::transcribe::transcribe; use crate::mbe::{self, KleeneOp, macro_check}; @@ -396,7 +397,7 @@ pub fn compile_declarative_macro( let lhs_tt = p.parse_token_tree(); let lhs_tt = mbe::quoted::parse( &TokenStream::new(vec![lhs_tt]), - true, // LHS + RulePart::Pattern, sess, node_id, features, @@ -423,7 +424,7 @@ pub fn compile_declarative_macro( let rhs_tt = p.parse_token_tree(); let rhs_tt = mbe::quoted::parse( &TokenStream::new(vec![rhs_tt]), - false, // RHS + RulePart::Body, sess, node_id, features, diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 2daa4e715584..065ae23a262d 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -16,6 +16,27 @@ pub(crate) const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, \ `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility"; +/// Which part of a macro rule we're parsing +#[derive(Copy, Clone)] +pub(crate) enum RulePart { + /// The left-hand side, with patterns and metavar definitions with types + Pattern, + /// The right-hand side body, with metavar references and metavar expressions + Body, +} + +impl RulePart { + #[inline(always)] + fn is_pattern(&self) -> bool { + matches!(self, Self::Pattern) + } + + #[inline(always)] + fn is_body(&self) -> bool { + matches!(self, Self::Body) + } +} + /// Takes a `tokenstream::TokenStream` and returns a `Vec`. Specifically, this /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a /// collection of `TokenTree` for use in parsing a macro. @@ -23,8 +44,8 @@ pub(crate) const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are /// # Parameters /// /// - `input`: a token stream to read from, the contents of which we are parsing. -/// - `parsing_patterns`: `parse` can be used to parse either the "patterns" or the "body" of a -/// macro. Both take roughly the same form _except_ that: +/// - `part`: whether we're parsing the patterns or the body of a macro. Both take roughly the same +/// form _except_ that: /// - In a pattern, metavars are declared with their "matcher" type. For example `$var:expr` or /// `$id:ident`. In this example, `expr` and `ident` are "matchers". They are not present in the /// body of a macro rule -- just in the pattern. @@ -38,7 +59,7 @@ pub(crate) const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`. pub(super) fn parse( input: &tokenstream::TokenStream, - parsing_patterns: bool, + part: RulePart, sess: &Session, node_id: NodeId, features: &Features, @@ -53,9 +74,9 @@ pub(super) fn parse( while let Some(tree) = iter.next() { // Given the parsed tree, if there is a metavar and we are expecting matchers, actually // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`). - let tree = parse_tree(tree, &mut iter, parsing_patterns, sess, node_id, features, edition); + let tree = parse_tree(tree, &mut iter, part, sess, node_id, features, edition); - if !parsing_patterns { + if part.is_body() { // No matchers allowed, nothing to process here result.push(tree); continue; @@ -157,13 +178,13 @@ fn maybe_emit_macro_metavar_expr_concat_feature(features: &Features, sess: &Sess /// - `tree`: the tree we wish to convert. /// - `outer_iter`: an iterator over trees. We may need to read more tokens from it in order to finish /// converting `tree` -/// - `parsing_patterns`: same as [parse]. +/// - `part`: same as [parse]. /// - `sess`: the parsing session. Any errors will be emitted to this session. /// - `features`: language features so we can do feature gating. fn parse_tree<'a>( tree: &'a tokenstream::TokenTree, outer_iter: &mut TokenStreamIter<'a>, - parsing_patterns: bool, + part: RulePart, sess: &Session, node_id: NodeId, features: &Features, @@ -189,7 +210,7 @@ fn parse_tree<'a>( match next { // `tree` is followed by a delimited set of token trees. Some(&tokenstream::TokenTree::Delimited(delim_span, _, delim, ref tts)) => { - if parsing_patterns { + if part.is_pattern() { if delim != Delimiter::Parenthesis { span_dollar_dollar_or_metavar_in_the_lhs_err( sess, @@ -244,13 +265,13 @@ fn parse_tree<'a>( // If we didn't find a metavar expression above, then we must have a // repetition sequence in the macro (e.g. `$(pat)*`). Parse the // contents of the sequence itself - let sequence = parse(tts, parsing_patterns, sess, node_id, features, edition); + let sequence = parse(tts, part, sess, node_id, features, edition); // Get the Kleene operator and optional separator let (separator, kleene) = parse_sep_and_kleene_op(&mut iter, delim_span.entire(), sess); // Count the number of captured "names" (i.e., named metavars) let num_captures = - if parsing_patterns { count_metavar_decls(&sequence) } else { 0 }; + if part.is_pattern() { count_metavar_decls(&sequence) } else { 0 }; TokenTree::Sequence( delim_span, SequenceRepetition { tts: sequence, separator, kleene, num_captures }, @@ -274,7 +295,7 @@ fn parse_tree<'a>( Token { kind: token::Dollar, span: dollar_span2 }, _, )) => { - if parsing_patterns { + if part.is_pattern() { span_dollar_dollar_or_metavar_in_the_lhs_err( sess, &Token { kind: token::Dollar, span: dollar_span2 }, @@ -306,10 +327,7 @@ fn parse_tree<'a>( &tokenstream::TokenTree::Delimited(span, spacing, delim, ref tts) => TokenTree::Delimited( span, spacing, - Delimited { - delim, - tts: parse(tts, parsing_patterns, sess, node_id, features, edition), - }, + Delimited { delim, tts: parse(tts, part, sess, node_id, features, edition) }, ), } } From 44d7238d86d7c58203e522334511d83a5f7626ff Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Sat, 5 Jul 2025 13:24:24 +0200 Subject: [PATCH 39/68] remove armv5te-unknown-linux-gnueabi target maintainer --- .../rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md index 1baf1049994b..0aebbc34d400 100644 --- a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md +++ b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md @@ -7,7 +7,7 @@ floating-point units. ## Target maintainers -[@koalatux](https://github.com/koalatux) +There are currently no formally documented target maintainers. ## Requirements From 90762c26b67f36a7d93a07fd90b2c354dd2be2a0 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 5 Jul 2025 12:37:17 +0000 Subject: [PATCH 40/68] Complete mut_visit. --- compiler/rustc_ast/src/visit.rs | 90 +++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 5dd6882b0256..f8ecff69a763 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1202,9 +1202,10 @@ macro_rules! common_visitor_and_walkers { let TyPat { id, kind, span, tokens: _ } = tp; try_visit!(visit_id(vis, id)); match kind { - TyPatKind::Range(start, end, _include_end) => { + TyPatKind::Range(start, end, Spanned { span, node: _include_end }) => { visit_opt!(vis, visit_anon_const, start); visit_opt!(vis, visit_anon_const, end); + try_visit!(visit_span(vis, span)); } TyPatKind::Or(variants) => walk_list!(vis, visit_ty_pat, variants), TyPatKind::Err(_) => {} @@ -1523,16 +1524,26 @@ macro_rules! common_visitor_and_walkers { } pub fn walk_inline_asm<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, asm: &$($lt)? $($mut)? InlineAsm) -> V::Result { - // FIXME: Visit spans inside all this currently ignored stuff. let InlineAsm { asm_macro: _, - template: _, - template_strs: _, + template, + template_strs, operands, - clobber_abis: _, + clobber_abis, options: _, - line_spans: _, + line_spans, } = asm; + for piece in template { + match piece { + InlineAsmTemplatePiece::String(_str) => {} + InlineAsmTemplatePiece::Placeholder { operand_idx: _, modifier: _, span } => { + try_visit!(visit_span(vis, span)); + } + } + } + for (_s1, _s2, span) in template_strs { + try_visit!(visit_span(vis, span)); + } for (op, span) in operands { match op { InlineAsmOperand::In { expr, reg: _ } @@ -1553,6 +1564,12 @@ macro_rules! common_visitor_and_walkers { } try_visit!(visit_span(vis, span)); } + for (_s1, span) in clobber_abis { + try_visit!(visit_span(vis, span)) + } + for span in line_spans { + try_visit!(visit_span(vis, span)) + } V::Result::output() } @@ -1565,9 +1582,9 @@ macro_rules! common_visitor_and_walkers { vis.visit_path(path) } - // FIXME: visit the template exhaustively. pub fn walk_format_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, fmt: &$($lt)? $($mut)? FormatArgs) -> V::Result { - let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _, is_source_literal: _ } = fmt; + let FormatArgs { span, template, arguments, uncooked_fmt_str: _, is_source_literal: _ } = fmt; + let args = $(${ignore($mut)} arguments.all_args_mut())? $(${ignore($lt)} arguments.all_args())? ; for FormatArgument { kind, expr } in args { match kind { @@ -1578,9 +1595,58 @@ macro_rules! common_visitor_and_walkers { } try_visit!(vis.visit_expr(expr)); } + for piece in template { + match piece { + FormatArgsPiece::Literal(_symbol) => {} + FormatArgsPiece::Placeholder(placeholder) => try_visit!(walk_format_placeholder(vis, placeholder)), + } + } visit_span(vis, span) } + fn walk_format_placeholder<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + placeholder: &$($lt)? $($mut)? FormatPlaceholder, + ) -> V::Result { + let FormatPlaceholder { argument, span, format_options, format_trait: _ } = placeholder; + if let Some(span) = span { + try_visit!(visit_span(vis, span)); + } + let FormatArgPosition { span, index: _, kind: _ } = argument; + if let Some(span) = span { + try_visit!(visit_span(vis, span)); + } + let FormatOptions { + width, + precision, + alignment: _, + fill: _, + sign: _, + alternate: _, + zero_pad: _, + debug_hex: _, + } = format_options; + match width { + None => {} + Some(FormatCount::Literal(_)) => {} + Some(FormatCount::Argument(FormatArgPosition { span, index: _, kind: _ })) => { + if let Some(span) = span { + try_visit!(visit_span(vis, span)); + } + } + } + match precision { + None => {} + Some(FormatCount::Literal(_)) => {} + Some(FormatCount::Argument(FormatArgPosition { span, index: _, kind: _ })) => { + if let Some(span) = span { + try_visit!(visit_span(vis, span)); + } + } + } + V::Result::output() + } + pub fn walk_expr<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, expression: &$($lt)? $($mut)? Expr) -> V::Result { let Expr { id, kind, span, attrs, tokens: _ } = expression; try_visit!(visit_id(vis, id)); @@ -1601,7 +1667,7 @@ macro_rules! common_visitor_and_walkers { try_visit!(visit_expr_fields(vis, fields)); match rest { StructRest::Base(expr) => try_visit!(vis.visit_expr(expr)), - StructRest::Rest(_span) => {} + StructRest::Rest(span) => try_visit!(visit_span(vis, span)), StructRest::None => {} } } @@ -1688,7 +1754,8 @@ macro_rules! common_visitor_and_walkers { visit_opt!(vis, visit_label, opt_label); try_visit!(vis.visit_block(block)); } - ExprKind::Gen(_capt, body, _kind, decl_span) => { + ExprKind::Gen(capture_clause, body, _kind, decl_span) => { + try_visit!(vis.visit_capture_by(capture_clause)); try_visit!(vis.visit_block(body)); try_visit!(visit_span(vis, decl_span)); } @@ -1705,9 +1772,10 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_expr(rhs)); try_visit!(visit_span(vis, span)); } - ExprKind::AssignOp(_op, left_expression, right_expression) => { + ExprKind::AssignOp(Spanned { span, node: _ }, left_expression, right_expression) => { try_visit!(vis.visit_expr(left_expression)); try_visit!(vis.visit_expr(right_expression)); + try_visit!(visit_span(vis, span)); } ExprKind::Field(subexpression, ident) => { try_visit!(vis.visit_expr(subexpression)); From 3cd13f72a26b45dd43a24fa8d47f680a9275e046 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Jul 2025 19:21:41 +0200 Subject: [PATCH 41/68] codegen_ssa: replace a Result by an Either --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index bf074fec66dd..2896dfd5463c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -1,5 +1,6 @@ use std::fmt; +use itertools::Either; use rustc_abi as abi; use rustc_abi::{ Align, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, TagEncoding, VariantIdx, Variants, @@ -567,12 +568,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { /// Creates an incomplete operand containing the [`abi::Scalar`]s expected based /// on the `layout` passed. This is for use with [`OperandRef::insert_field`] - /// later to set the necessary immediate(s). + /// later to set the necessary immediate(s), one-by-one converting all the `Right` to `Left`. /// /// Returns `None` for `layout`s which cannot be built this way. pub(crate) fn builder( layout: TyAndLayout<'tcx>, - ) -> Option>> { + ) -> Option>> { // Uninhabited types are weird, because for example `Result` // shows up as `FieldsShape::Primitive` and we need to be able to write // a field into `(u32, !)`. We'll do that in an `alloca` instead. @@ -582,15 +583,15 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let val = match layout.backend_repr { BackendRepr::Memory { .. } if layout.is_zst() => OperandValue::ZeroSized, - BackendRepr::Scalar(s) => OperandValue::Immediate(Err(s)), - BackendRepr::ScalarPair(a, b) => OperandValue::Pair(Err(a), Err(b)), + BackendRepr::Scalar(s) => OperandValue::Immediate(Either::Right(s)), + BackendRepr::ScalarPair(a, b) => OperandValue::Pair(Either::Right(a), Either::Right(b)), BackendRepr::Memory { .. } | BackendRepr::SimdVector { .. } => return None, }; Some(OperandRef { val, layout }) } } -impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result> { +impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Either> { pub(crate) fn insert_field>( &mut self, bx: &mut Bx, @@ -614,29 +615,29 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result> { (field_layout.is_zst(), field_offset == Size::ZERO) }; - let mut update = |tgt: &mut Result, src, from_scalar| { - let to_scalar = tgt.unwrap_err(); + let mut update = |tgt: &mut Either, src, from_scalar| { + let to_scalar = tgt.unwrap_right(); let imm = transmute_scalar(bx, src, from_scalar, to_scalar); - *tgt = Ok(imm); + *tgt = Either::Left(imm); }; match (operand.val, operand.layout.backend_repr) { (OperandValue::ZeroSized, _) if expect_zst => {} (OperandValue::Immediate(v), BackendRepr::Scalar(from_scalar)) => match &mut self.val { - OperandValue::Immediate(val @ Err(_)) if is_zero_offset => { + OperandValue::Immediate(val @ Either::Right(_)) if is_zero_offset => { update(val, v, from_scalar); } - OperandValue::Pair(fst @ Err(_), _) if is_zero_offset => { + OperandValue::Pair(fst @ Either::Right(_), _) if is_zero_offset => { update(fst, v, from_scalar); } - OperandValue::Pair(_, snd @ Err(_)) if !is_zero_offset => { + OperandValue::Pair(_, snd @ Either::Right(_)) if !is_zero_offset => { update(snd, v, from_scalar); } _ => bug!("Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}"), }, (OperandValue::Pair(a, b), BackendRepr::ScalarPair(from_sa, from_sb)) => { match &mut self.val { - OperandValue::Pair(fst @ Err(_), snd @ Err(_)) => { + OperandValue::Pair(fst @ Either::Right(_), snd @ Either::Right(_)) => { update(fst, a, from_sa); update(snd, b, from_sb); } @@ -656,21 +657,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result> { let field_offset = self.layout.fields.offset(f.as_usize()); let is_zero_offset = field_offset == Size::ZERO; match &mut self.val { - OperandValue::Immediate(val @ Err(_)) if is_zero_offset => { - *val = Ok(imm); + OperandValue::Immediate(val @ Either::Right(_)) if is_zero_offset => { + *val = Either::Left(imm); } - OperandValue::Pair(fst @ Err(_), _) if is_zero_offset => { - *fst = Ok(imm); + OperandValue::Pair(fst @ Either::Right(_), _) if is_zero_offset => { + *fst = Either::Left(imm); } - OperandValue::Pair(_, snd @ Err(_)) if !is_zero_offset => { - *snd = Ok(imm); + OperandValue::Pair(_, snd @ Either::Right(_)) if !is_zero_offset => { + *snd = Either::Left(imm); } _ => bug!("Tried to insert {imm:?} into field {f:?} of {self:?}"), } } /// After having set all necessary fields, this converts the - /// `OperandValue>` (as obtained from [`OperandRef::builder`]) + /// `OperandValue>` (as obtained from [`OperandRef::builder`]) /// to the normal `OperandValue`. /// /// ICEs if any required fields were not set. @@ -681,13 +682,13 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result> { // payload scalar will not actually have been set, so this converts // unset scalars to corresponding `undef` values so long as the scalar // from the layout allows uninit. - let unwrap = |r: Result| match r { - Ok(v) => v, - Err(s) if s.is_uninit_valid() => { + let unwrap = |r: Either| match r { + Either::Left(v) => v, + Either::Right(s) if s.is_uninit_valid() => { let bty = cx.type_from_scalar(s); cx.const_undef(bty) } - Err(_) => bug!("OperandRef::build called while fields are missing {self:?}"), + Either::Right(_) => bug!("OperandRef::build called while fields are missing {self:?}"), }; let val = match val { From a839b071f7988e77040474dc870ba16b77666a8f Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Sat, 5 Jul 2025 15:58:04 +0100 Subject: [PATCH 42/68] Use `object` crate from crates.io to fix windows build error --- compiler/rustc_codegen_gcc/Cargo.lock | 10 ++++++++++ compiler/rustc_codegen_gcc/Cargo.toml | 1 + compiler/rustc_codegen_gcc/src/lib.rs | 1 - 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index b20c181a8cbf..7f35c1a80bda 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -143,6 +143,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.20.2" @@ -179,6 +188,7 @@ dependencies = [ "boml", "gccjit", "lang_tester", + "object", "tempfile", ] diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index c284e3f060b8..05b0431b6ba9 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -22,6 +22,7 @@ master = ["gccjit/master"] default = ["master"] [dependencies] +object = { version = "0.37.0", default-features = false, features = ["std", "read"] } gccjit = "2.7" #gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a912678ef2a1..56afdd55bf99 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -27,7 +27,6 @@ #![allow(clippy::needless_lifetimes, clippy::uninlined_format_args)] // Some "regular" crates we want to share with rustc -extern crate object; extern crate smallvec; // FIXME(antoyo): clippy bug: remove the #[allow] when it's fixed. #[allow(unused_extern_crates)] From 971feb618518d5b53dcdc43dcc873b5f7be3f88c Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 5 Jul 2025 10:17:31 -0500 Subject: [PATCH 43/68] tidy: use --bless for tidy spellcheck instead of spellcheck:fix previous behavior was inconsistent with existing extra checks. --- src/tools/tidy/src/ext_tool_checks.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 2904908fd436..f76403711b14 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -72,8 +72,7 @@ fn check_impl( let shell_lint = lint_args.contains(&"shell:lint") || shell_all; let cpp_all = lint_args.contains(&"cpp"); let cpp_fmt = lint_args.contains(&"cpp:fmt") || cpp_all; - let spellcheck_all = lint_args.contains(&"spellcheck"); - let spellcheck_fix = lint_args.contains(&"spellcheck:fix"); + let spellcheck = lint_args.contains(&"spellcheck"); let mut py_path = None; @@ -226,7 +225,7 @@ fn check_impl( shellcheck_runner(&merge_args(&cfg_args, &file_args_shc))?; } - if spellcheck_all || spellcheck_fix { + if spellcheck { let config_path = root_path.join("typos.toml"); // sync target files with .github/workflows/spellcheck.yml let mut args = vec![ @@ -238,11 +237,11 @@ fn check_impl( "./src/librustdoc", ]; - if spellcheck_all { - eprintln!("spellcheck files"); - } else if spellcheck_fix { + if bless { eprintln!("spellcheck files and fix"); args.push("--write-changes"); + } else { + eprintln!("spellcheck files"); } spellcheck_runner(&args)?; } From 39ee1b2d774d4be6959e3b045052abef54a29e0b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 5 Jul 2025 15:11:09 +0000 Subject: [PATCH 44/68] Remove yields_in_scope from the scope tree. --- .../rustc_hir_analysis/src/check/region.rs | 205 ++++-------------- compiler/rustc_middle/src/middle/region.rs | 92 -------- .../src/builder/expr/as_rvalue.rs | 3 - 3 files changed, 37 insertions(+), 263 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index c458878da15b..288105dfba71 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -15,7 +15,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Arm, Block, Expr, LetStmt, Pat, PatKind, Stmt}; use rustc_index::Idx; -use rustc_middle::bug; use rustc_middle::middle::region::*; use rustc_middle::ty::TyCtxt; use rustc_session::lint; @@ -34,14 +33,6 @@ struct Context { struct ScopeResolutionVisitor<'tcx> { tcx: TyCtxt<'tcx>, - // The number of expressions and patterns visited in the current body. - expr_and_pat_count: usize, - // When this is `true`, we record the `Scopes` we encounter - // when processing a Yield expression. This allows us to fix - // up their indices. - pessimistic_yield: bool, - // Stores scopes when `pessimistic_yield` is `true`. - fixup_scopes: Vec, // The generated scope tree. scope_tree: ScopeTree, @@ -199,19 +190,14 @@ fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir: visitor.cx = prev_cx; } +#[tracing::instrument(level = "debug", skip(visitor))] fn resolve_pat<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) { // If this is a binding then record the lifetime of that binding. if let PatKind::Binding(..) = pat.kind { record_var_lifetime(visitor, pat.hir_id.local_id); } - debug!("resolve_pat - pre-increment {} pat = {:?}", visitor.expr_and_pat_count, pat); - intravisit::walk_pat(visitor, pat); - - visitor.expr_and_pat_count += 1; - - debug!("resolve_pat - post-increment {} pat = {:?}", visitor.expr_and_pat_count, pat); } fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hir::Stmt<'tcx>) { @@ -243,68 +229,15 @@ fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hi } } +#[tracing::instrument(level = "debug", skip(visitor))] fn resolve_expr<'tcx>( visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>, terminating: bool, ) { - debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr); - let prev_cx = visitor.cx; visitor.enter_node_scope_with_dtor(expr.hir_id.local_id, terminating); - let prev_pessimistic = visitor.pessimistic_yield; - - // Ordinarily, we can rely on the visit order of HIR intravisit - // to correspond to the actual execution order of statements. - // However, there's a weird corner case with compound assignment - // operators (e.g. `a += b`). The evaluation order depends on whether - // or not the operator is overloaded (e.g. whether or not a trait - // like AddAssign is implemented). - - // For primitive types (which, despite having a trait impl, don't actually - // end up calling it), the evaluation order is right-to-left. For example, - // the following code snippet: - // - // let y = &mut 0; - // *{println!("LHS!"); y} += {println!("RHS!"); 1}; - // - // will print: - // - // RHS! - // LHS! - // - // However, if the operator is used on a non-primitive type, - // the evaluation order will be left-to-right, since the operator - // actually get desugared to a method call. For example, this - // nearly identical code snippet: - // - // let y = &mut String::new(); - // *{println!("LHS String"); y} += {println!("RHS String"); "hi"}; - // - // will print: - // LHS String - // RHS String - // - // To determine the actual execution order, we need to perform - // trait resolution. Unfortunately, we need to be able to compute - // yield_in_scope before type checking is even done, as it gets - // used by AST borrowcheck. - // - // Fortunately, we don't need to know the actual execution order. - // It suffices to know the 'worst case' order with respect to yields. - // Specifically, we need to know the highest 'expr_and_pat_count' - // that we could assign to the yield expression. To do this, - // we pick the greater of the two values from the left-hand - // and right-hand expressions. This makes us overly conservative - // about what types could possibly live across yield points, - // but we will never fail to detect that a type does actually - // live across a yield point. The latter part is critical - - // we're already overly conservative about what types will live - // across yield points, as the generated MIR will determine - // when things are actually live. However, for typecheck to work - // properly, we can't miss any types. - match expr.kind { // Conditional or repeating scopes are always terminating // scopes, meaning that temporaries cannot outlive them. @@ -360,55 +293,42 @@ fn resolve_expr<'tcx>( let body = visitor.tcx.hir_body(body); visitor.visit_body(body); } + // Ordinarily, we can rely on the visit order of HIR intravisit + // to correspond to the actual execution order of statements. + // However, there's a weird corner case with compound assignment + // operators (e.g. `a += b`). The evaluation order depends on whether + // or not the operator is overloaded (e.g. whether or not a trait + // like AddAssign is implemented). + // + // For primitive types (which, despite having a trait impl, don't actually + // end up calling it), the evaluation order is right-to-left. For example, + // the following code snippet: + // + // let y = &mut 0; + // *{println!("LHS!"); y} += {println!("RHS!"); 1}; + // + // will print: + // + // RHS! + // LHS! + // + // However, if the operator is used on a non-primitive type, + // the evaluation order will be left-to-right, since the operator + // actually get desugared to a method call. For example, this + // nearly identical code snippet: + // + // let y = &mut String::new(); + // *{println!("LHS String"); y} += {println!("RHS String"); "hi"}; + // + // will print: + // LHS String + // RHS String + // + // To determine the actual execution order, we need to perform + // trait resolution. Fortunately, we don't need to know the actual execution order. hir::ExprKind::AssignOp(_, left_expr, right_expr) => { - debug!( - "resolve_expr - enabling pessimistic_yield, was previously {}", - prev_pessimistic - ); - - let start_point = visitor.fixup_scopes.len(); - visitor.pessimistic_yield = true; - - // If the actual execution order turns out to be right-to-left, - // then we're fine. However, if the actual execution order is left-to-right, - // then we'll assign too low a count to any `yield` expressions - // we encounter in 'right_expression' - they should really occur after all of the - // expressions in 'left_expression'. visitor.visit_expr(right_expr); - visitor.pessimistic_yield = prev_pessimistic; - - debug!("resolve_expr - restoring pessimistic_yield to {}", prev_pessimistic); visitor.visit_expr(left_expr); - debug!("resolve_expr - fixing up counts to {}", visitor.expr_and_pat_count); - - // Remove and process any scopes pushed by the visitor - let target_scopes = visitor.fixup_scopes.drain(start_point..); - - for scope in target_scopes { - let yield_data = - visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap().last_mut().unwrap(); - let count = yield_data.expr_and_pat_count; - let span = yield_data.span; - - // expr_and_pat_count never decreases. Since we recorded counts in yield_in_scope - // before walking the left-hand side, it should be impossible for the recorded - // count to be greater than the left-hand side count. - if count > visitor.expr_and_pat_count { - bug!( - "Encountered greater count {} at span {:?} - expected no greater than {}", - count, - span, - visitor.expr_and_pat_count - ); - } - let new_count = visitor.expr_and_pat_count; - debug!( - "resolve_expr - increasing count for scope {:?} from {} to {} at span {:?}", - scope, count, new_count, span - ); - - yield_data.expr_and_pat_count = new_count; - } } hir::ExprKind::If(cond, then, Some(otherwise)) => { @@ -453,43 +373,6 @@ fn resolve_expr<'tcx>( _ => intravisit::walk_expr(visitor, expr), } - visitor.expr_and_pat_count += 1; - - debug!("resolve_expr post-increment {}, expr = {:?}", visitor.expr_and_pat_count, expr); - - if let hir::ExprKind::Yield(_, source) = &expr.kind { - // Mark this expr's scope and all parent scopes as containing `yield`. - let mut scope = Scope { local_id: expr.hir_id.local_id, data: ScopeData::Node }; - loop { - let data = YieldData { - span: expr.span, - expr_and_pat_count: visitor.expr_and_pat_count, - source: *source, - }; - match visitor.scope_tree.yield_in_scope.get_mut(&scope) { - Some(yields) => yields.push(data), - None => { - visitor.scope_tree.yield_in_scope.insert(scope, vec![data]); - } - } - - if visitor.pessimistic_yield { - debug!("resolve_expr in pessimistic_yield - marking scope {:?} for fixup", scope); - visitor.fixup_scopes.push(scope); - } - - // Keep traversing up while we can. - match visitor.scope_tree.parent_map.get(&scope) { - // Don't cross from closure bodies to their parent. - Some(&superscope) => match superscope.data { - ScopeData::CallSite => break, - _ => scope = superscope, - }, - None => break, - } - } - } - visitor.cx = prev_cx; } @@ -612,8 +495,8 @@ fn resolve_local<'tcx>( } } - // Make sure we visit the initializer first, so expr_and_pat_count remains correct. - // The correct order, as shared between coroutine_interior, drop_ranges and intravisitor, + // Make sure we visit the initializer first. + // The correct order, as shared between drop_ranges and intravisitor, // is to walk initializer, followed by pattern bindings, finally followed by the `else` block. if let Some(expr) = init { visitor.visit_expr(expr); @@ -798,16 +681,7 @@ impl<'tcx> ScopeResolutionVisitor<'tcx> { } fn enter_body(&mut self, hir_id: hir::HirId, f: impl FnOnce(&mut Self)) { - // Save all state that is specific to the outer function - // body. These will be restored once down below, once we've - // visited the body. - let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0); let outer_cx = self.cx; - // The 'pessimistic yield' flag is set to true when we are - // processing a `+=` statement and have to make pessimistic - // control flow assumptions. This doesn't apply to nested - // bodies within the `+=` statements. See #69307. - let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false); self.enter_scope(Scope { local_id: hir_id.local_id, data: ScopeData::CallSite }); self.enter_scope(Scope { local_id: hir_id.local_id, data: ScopeData::Arguments }); @@ -815,9 +689,7 @@ impl<'tcx> ScopeResolutionVisitor<'tcx> { f(self); // Restore context we had at the start. - self.expr_and_pat_count = outer_ec; self.cx = outer_cx; - self.pessimistic_yield = outer_pessimistic_yield; } } @@ -919,10 +791,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { let mut visitor = ScopeResolutionVisitor { tcx, scope_tree: ScopeTree::default(), - expr_and_pat_count: 0, cx: Context { parent: None, var_parent: None }, - pessimistic_yield: false, - fixup_scopes: vec![], extended_super_lets: Default::default(), }; diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 92eab59dd027..0f5b63f5c1d2 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -7,7 +7,6 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html use std::fmt; -use std::ops::Deref; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordMap; @@ -228,82 +227,6 @@ pub struct ScopeTree { /// This information is used later for linting to identify locals and /// temporary values that will receive backwards-incompatible drop orders. pub backwards_incompatible_scope: UnordMap, - - /// If there are any `yield` nested within a scope, this map - /// stores the `Span` of the last one and its index in the - /// postorder of the Visitor traversal on the HIR. - /// - /// HIR Visitor postorder indexes might seem like a peculiar - /// thing to care about. but it turns out that HIR bindings - /// and the temporary results of HIR expressions are never - /// storage-live at the end of HIR nodes with postorder indexes - /// lower than theirs, and therefore don't need to be suspended - /// at yield-points at these indexes. - /// - /// For an example, suppose we have some code such as: - /// ```rust,ignore (example) - /// foo(f(), yield y, bar(g())) - /// ``` - /// - /// With the HIR tree (calls numbered for expository purposes) - /// - /// ```text - /// Call#0(foo, [Call#1(f), Yield(y), Call#2(bar, Call#3(g))]) - /// ``` - /// - /// Obviously, the result of `f()` was created before the yield - /// (and therefore needs to be kept valid over the yield) while - /// the result of `g()` occurs after the yield (and therefore - /// doesn't). If we want to infer that, we can look at the - /// postorder traversal: - /// ```plain,ignore - /// `foo` `f` Call#1 `y` Yield `bar` `g` Call#3 Call#2 Call#0 - /// ``` - /// - /// In which we can easily see that `Call#1` occurs before the yield, - /// and `Call#3` after it. - /// - /// To see that this method works, consider: - /// - /// Let `D` be our binding/temporary and `U` be our other HIR node, with - /// `HIR-postorder(U) < HIR-postorder(D)`. Suppose, as in our example, - /// U is the yield and D is one of the calls. - /// Let's show that `D` is storage-dead at `U`. - /// - /// Remember that storage-live/storage-dead refers to the state of - /// the *storage*, and does not consider moves/drop flags. - /// - /// Then: - /// - /// 1. From the ordering guarantee of HIR visitors (see - /// `rustc_hir::intravisit`), `D` does not dominate `U`. - /// - /// 2. Therefore, `D` is *potentially* storage-dead at `U` (because - /// we might visit `U` without ever getting to `D`). - /// - /// 3. However, we guarantee that at each HIR point, each - /// binding/temporary is always either always storage-live - /// or always storage-dead. This is what is being guaranteed - /// by `terminating_scopes` including all blocks where the - /// count of executions is not guaranteed. - /// - /// 4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`, - /// QED. - /// - /// This property ought to not on (3) in an essential way -- it - /// is probably still correct even if we have "unrestricted" terminating - /// scopes. However, why use the complicated proof when a simple one - /// works? - /// - /// A subtle thing: `box` expressions, such as `box (&x, yield 2, &y)`. It - /// might seem that a `box` expression creates a `Box` temporary - /// when it *starts* executing, at `HIR-preorder(BOX-EXPR)`. That might - /// be true in the MIR desugaring, but it is not important in the semantics. - /// - /// The reason is that semantically, until the `box` expression returns, - /// the values are still owned by their containing expressions. So - /// we'll see that `&x`. - pub yield_in_scope: UnordMap>, } /// See the `rvalue_candidates` field for more information on rvalue @@ -316,15 +239,6 @@ pub struct RvalueCandidate { pub lifetime: Option, } -#[derive(Debug, Copy, Clone, HashStable)] -pub struct YieldData { - /// The `Span` of the yield. - pub span: Span, - /// The number of expressions and patterns appearing before the `yield` in the body, plus one. - pub expr_and_pat_count: usize, - pub source: hir::YieldSource, -} - impl ScopeTree { pub fn record_scope_parent(&mut self, child: Scope, parent: Option) { debug!("{:?}.parent = {:?}", child, parent); @@ -380,10 +294,4 @@ impl ScopeTree { true } - - /// Checks whether the given scope contains a `yield`. If so, - /// returns `Some(YieldData)`. If not, returns `None`. - pub fn yield_in_scope(&self, scope: Scope) -> Option<&[YieldData]> { - self.yield_in_scope.get(&scope).map(Deref::deref) - } } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 975226bb642a..daf8fa5f19ee 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -171,9 +171,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.diverge_from(block); block = success; - // The `Box` temporary created here is not a part of the HIR, - // and therefore is not considered during coroutine auto-trait - // determination. See the comment about `box` at `yield_in_scope`. let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span)); this.cfg .push(block, Statement::new(source_info, StatementKind::StorageLive(result))); From c1ed2ac8a27bce8ccc655bd87102752d9d8015d6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 5 Jul 2025 10:24:17 -0500 Subject: [PATCH 45/68] tidy: add specific error message for trying to use `spellcheck:fix`. --- src/tools/tidy/src/ext_tool_checks.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index f76403711b14..d2da63a97031 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -65,6 +65,13 @@ fn check_impl( None => vec![], }; + if lint_args.contains(&"spellcheck:fix") { + return Err(Error::Generic( + "`spellcheck:fix` is no longer valid, use `--extra=check=spellcheck --bless`" + .to_string(), + )); + } + let python_all = lint_args.contains(&"py"); let python_lint = lint_args.contains(&"py:lint") || python_all; let python_fmt = lint_args.contains(&"py:fmt") || python_all; From ea7b7568759e071f50060a2d76a4619de6c42c2f Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Sat, 5 Jul 2025 17:23:39 +0100 Subject: [PATCH 46/68] Make tempfile a normal dependency --- compiler/rustc_codegen_gcc/Cargo.toml | 2 +- compiler/rustc_codegen_gcc/src/lib.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 05b0431b6ba9..193348d1ef60 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -23,6 +23,7 @@ default = ["master"] [dependencies] object = { version = "0.37.0", default-features = false, features = ["std", "read"] } +tempfile = "3.20" gccjit = "2.7" #gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } @@ -32,7 +33,6 @@ gccjit = "2.7" [dev-dependencies] boml = "0.3.1" lang_tester = "0.8.0" -tempfile = "3.20" [profile.dev] # By compiling dependencies with optimizations, performing tests gets much faster. diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 56afdd55bf99..1a6eec0ed0bf 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -26,11 +26,9 @@ #![deny(clippy::pattern_type_mismatch)] #![allow(clippy::needless_lifetimes, clippy::uninlined_format_args)] -// Some "regular" crates we want to share with rustc +// These crates are pulled from the sysroot because they are part of +// rustc's public API, so we need to ensure version compatibility. extern crate smallvec; -// FIXME(antoyo): clippy bug: remove the #[allow] when it's fixed. -#[allow(unused_extern_crates)] -extern crate tempfile; #[macro_use] extern crate tracing; From 8eb9f709793405b03a28e827bfe83146230473b6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 5 Jul 2025 18:37:08 +0000 Subject: [PATCH 47/68] Stop using Key trait randomly --- .../rustc_const_eval/src/const_eval/mod.rs | 5 ++-- compiler/rustc_lint/src/map_unit_fn.rs | 5 ++-- tests/ui/lint/lint_map_unit_fn.stderr | 25 +++++++++---------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index d95d552d7d54..0082f90f3b8c 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,9 +1,9 @@ // Not in interpret to make sure we do not use private implementation details use rustc_abi::{FieldIdx, VariantIdx}; -use rustc_middle::query::Key; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; +use rustc_span::DUMMY_SP; use tracing::instrument; use crate::interpret::InterpCx; @@ -71,8 +71,7 @@ pub fn tag_for_variant_provider<'tcx>( let (ty, variant_index) = key.value; assert!(ty.is_enum()); - let ecx = - InterpCx::new(tcx, ty.default_span(tcx), key.typing_env, crate::const_eval::DummyMachine); + let ecx = InterpCx::new(tcx, DUMMY_SP, key.typing_env, crate::const_eval::DummyMachine); let layout = ecx.layout_of(ty).unwrap(); ecx.tag_for_variant(layout, variant_index).unwrap().map(|(tag, _tag_field)| tag) diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs index 3b27e4561369..af509cb786db 100644 --- a/compiler/rustc_lint/src/map_unit_fn.rs +++ b/compiler/rustc_lint/src/map_unit_fn.rs @@ -1,5 +1,4 @@ use rustc_hir::{Expr, ExprKind, HirId, Stmt, StmtKind}; -use rustc_middle::query::Key; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint, declare_lint_pass}; @@ -69,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn { .span_of_impl(*id) .unwrap_or(default_span), argument_label: args[0].span, - map_label: arg_ty.default_span(cx.tcx), + map_label: span, suggestion: path.ident.span, replace: "for_each".to_string(), }, @@ -88,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn { .span_of_impl(*id) .unwrap_or(default_span), argument_label: args[0].span, - map_label: arg_ty.default_span(cx.tcx), + map_label: span, suggestion: path.ident.span, replace: "for_each".to_string(), }, diff --git a/tests/ui/lint/lint_map_unit_fn.stderr b/tests/ui/lint/lint_map_unit_fn.stderr index 91542af0f6df..930ecd30d1d1 100644 --- a/tests/ui/lint/lint_map_unit_fn.stderr +++ b/tests/ui/lint/lint_map_unit_fn.stderr @@ -25,19 +25,18 @@ LL + x.iter_mut().for_each(foo); error: `Iterator::map` call that discard the iterator's values --> $DIR/lint_map_unit_fn.rs:11:18 | -LL | x.iter_mut().map(|items| { - | ^ ------- - | | | - | ____________________|___this function returns `()`, which is likely not what you wanted - | | __________________| - | | | -LL | | | -LL | | | items.sort(); -LL | | | }); - | | | -^ after this call to map, the resulting iterator is `impl Iterator`, which means the only information carried by the iterator is the number of items - | | |_____|| - | |_______| - | called `Iterator::map` with callable that returns `()` +LL | x.iter_mut().map(|items| { + | ^ ------- + | | | + | ___________________|___this function returns `()`, which is likely not what you wanted + | | __________________| + | || +LL | || +LL | || items.sort(); +LL | || }); + | ||_____-^ after this call to map, the resulting iterator is `impl Iterator`, which means the only information carried by the iterator is the number of items + | |______| + | called `Iterator::map` with callable that returns `()` | = note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated help: you might have meant to use `Iterator::for_each` From 7f5d286de3a13eb716c12fbbcfa642eefa1ec3b4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Jun 2025 17:47:47 +0000 Subject: [PATCH 48/68] Canonicalize input ty/ct infer/placeholder in the root universe --- .../src/canonicalizer.rs | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 47ed9e872448..96233413ae1b 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -407,11 +407,18 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { "ty vid should have been resolved fully before canonicalization" ); - CanonicalVarKind::Ty(CanonicalTyVarKind::General( - self.delegate - .universe_of_ty(vid) - .unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")), - )) + match self.canonicalize_mode { + CanonicalizeMode::Input { .. } => CanonicalVarKind::Ty( + CanonicalTyVarKind::General(ty::UniverseIndex::ROOT), + ), + CanonicalizeMode::Response { .. } => { + CanonicalVarKind::Ty(CanonicalTyVarKind::General( + self.delegate.universe_of_ty(vid).unwrap_or_else(|| { + panic!("ty var should have been resolved: {t:?}") + }), + )) + } + } } ty::IntVar(vid) => { debug_assert_eq!( @@ -435,7 +442,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }, ty::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy( - PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()), + PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()), ), CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder), }, @@ -588,13 +595,21 @@ impl, I: Interner> TypeFolder for Canonicaliz c, "const vid should have been resolved fully before canonicalization" ); - CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap()) + + match self.canonicalize_mode { + CanonicalizeMode::Input { .. } => { + CanonicalVarKind::Const(ty::UniverseIndex::ROOT) + } + CanonicalizeMode::Response { .. } => { + CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap()) + } + } } ty::InferConst::Fresh(_) => todo!(), }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst( - PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()), + PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()), ), CanonicalizeMode::Response { .. } => { CanonicalVarKind::PlaceholderConst(placeholder) From 312de35d3aa33c2c58386ca1544046c54c6d4da2 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 4 Jul 2025 20:54:09 +0530 Subject: [PATCH 49/68] restructure try_run_tests --- src/bootstrap/src/utils/exec.rs | 12 +++--------- src/bootstrap/src/utils/render_tests.rs | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index c5b3c322be4d..487077835ac6 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -223,7 +223,7 @@ impl<'a> BootstrapCommand { /// Mark the command as being executed, disarming the drop bomb. /// If this method is not called before the command is dropped, its drop will panic. - fn mark_as_executed(&mut self) { + pub fn mark_as_executed(&mut self) { self.drop_bomb.defuse(); } @@ -625,18 +625,12 @@ impl ExecutionContext { exit!(1); } -<<<<<<< HEAD - pub fn stream<'a>( -======= /// Spawns the command with configured stdout and stderr handling. /// - /// Returns `None` if in dry-run mode and the command is not allowed to run. - /// - /// Panics if the command fails to spawn. + /// Returns None if in dry-run mode or Panics if the command fails to spawn. pub fn stream( ->>>>>>> c2e83361cec (add comment to exec) &self, - command: &'a mut BootstrapCommand, + command: &mut BootstrapCommand, stdout: OutputMode, stderr: OutputMode, ) -> Option { diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 73a22ec28260..934699d736b4 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -34,16 +34,17 @@ pub(crate) fn try_run_tests( cmd: &mut BootstrapCommand, stream: bool, ) -> bool { - if !run_tests(builder, cmd, stream) { - if builder.fail_fast { - crate::exit!(1); - } else { - builder.config.exec_ctx().add_to_delay_failure(format!("{cmd:?}")); - false - } - } else { - true + if run_tests(builder, cmd, stream) { + return true; } + + if builder.fail_fast { + crate::exit!(1); + } + + builder.config.exec_ctx().add_to_delay_failure(format!("{cmd:?}")); + + false } fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { From 418587459254a48c947312f69b70e2d68507aac7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 23 Jun 2025 20:43:04 +0000 Subject: [PATCH 50/68] Don't compress input universes --- .../src/canonicalizer.rs | 121 ++---------------- 1 file changed, 10 insertions(+), 111 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 96233413ae1b..a418aa82100c 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -1,5 +1,3 @@ -use std::cmp::Ordering; - use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack}; use rustc_type_ir::inherent::*; use rustc_type_ir::solve::{Goal, QueryInput}; @@ -266,11 +264,15 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // See the rustc-dev-guide section about how we deal with universes // during canonicalization in the new solver. match self.canonicalize_mode { - // We try to deduplicate as many query calls as possible and hide - // all information which should not matter for the solver. - // - // For this we compress universes as much as possible. - CanonicalizeMode::Input { .. } => {} + // All placeholders and vars are canonicalized in the root universe. + CanonicalizeMode::Input { .. } => { + debug_assert!( + var_kinds.iter().all(|var| var.universe() == ty::UniverseIndex::ROOT), + "expected all vars to be canonicalized in root universe: {var_kinds:#?}" + ); + let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); + (ty::UniverseIndex::ROOT, var_kinds) + } // When canonicalizing a response we map a universes already entered // by the caller to the root universe and only return useful universe // information for placeholders and inference variables created inside @@ -288,113 +290,10 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { .map(|kind| kind.universe()) .max() .unwrap_or(ty::UniverseIndex::ROOT); - let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); - return (max_universe, var_kinds); + (max_universe, var_kinds) } } - - // Given a `var_kinds` with existentials `En` and universals `Un` in - // universes `n`, this algorithm compresses them in place so that: - // - // - the new universe indices are as small as possible - // - we create a new universe if we would otherwise - // 1. put existentials from a different universe into the same one - // 2. put a placeholder in the same universe as an existential which cannot name it - // - // Let's walk through an example: - // - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0 - // - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1 - // - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2 - // - var_kinds: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5 - // - var_kinds: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6 - // - var_kinds: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: - - // - // This algorithm runs in `O(mn)` where `n` is the number of different universes and - // `m` the number of variables. This should be fine as both are expected to be small. - let mut curr_compressed_uv = ty::UniverseIndex::ROOT; - let mut existential_in_new_uv = None; - let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); - while let Some(orig_uv) = next_orig_uv.take() { - let mut update_uv = |var: &mut CanonicalVarKind, orig_uv, is_existential| { - let uv = var.universe(); - match uv.cmp(&orig_uv) { - Ordering::Less => (), // Already updated - Ordering::Equal => { - if is_existential { - if existential_in_new_uv.is_some_and(|uv| uv < orig_uv) { - // Condition 1. - // - // We already put an existential from a outer universe - // into the current compressed universe, so we need to - // create a new one. - curr_compressed_uv = curr_compressed_uv.next_universe(); - } - - // `curr_compressed_uv` will now contain an existential from - // `orig_uv`. Trying to canonicalizing an existential from - // a higher universe has to therefore use a new compressed - // universe. - existential_in_new_uv = Some(orig_uv); - } else if existential_in_new_uv.is_some() { - // Condition 2. - // - // `var` is a placeholder from a universe which is not nameable - // by an existential which we already put into the compressed - // universe `curr_compressed_uv`. We therefore have to create a - // new universe for `var`. - curr_compressed_uv = curr_compressed_uv.next_universe(); - existential_in_new_uv = None; - } - - *var = var.with_updated_universe(curr_compressed_uv); - } - Ordering::Greater => { - // We can ignore this variable in this iteration. We only look at - // universes which actually occur in the input for performance. - // - // For this we set `next_orig_uv` to the next smallest, not yet compressed, - // universe of the input. - if next_orig_uv.is_none_or(|curr_next_uv| uv.cannot_name(curr_next_uv)) { - next_orig_uv = Some(uv); - } - } - } - }; - - // For each universe which occurs in the input, we first iterate over all - // placeholders and then over all inference variables. - // - // Whenever we compress the universe of a placeholder, no existential with - // an already compressed universe can name that placeholder. - for is_existential in [false, true] { - for var in var_kinds.iter_mut() { - // We simply put all regions from the input into the highest - // compressed universe, so we only deal with them at the end. - if !var.is_region() { - if is_existential == var.is_existential() { - update_uv(var, orig_uv, is_existential) - } - } - } - } - } - - // We put all regions into a separate universe. - let mut first_region = true; - for var in var_kinds.iter_mut() { - if var.is_region() { - if first_region { - first_region = false; - curr_compressed_uv = curr_compressed_uv.next_universe(); - } - debug_assert!(var.is_existential()); - *var = var.with_updated_universe(curr_compressed_uv); - } - } - - let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); - (curr_compressed_uv, var_kinds) } fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty { From 2d8ffff10ae22cbe0effb7fb6f5561c8a859279e Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 30 Jun 2025 16:09:01 +0200 Subject: [PATCH 51/68] Port `#[ignore]` to the new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- .../src/attributes.rs | 7 +++ .../src/encode_cross_crate.rs | 1 + .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/test_attrs.rs | 46 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 + compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_parse/src/validate_attr.rs | 4 +- compiler/rustc_passes/src/check_attr.rs | 5 +- tests/ui/attributes/malformed-attrs.rs | 7 +++ tests/ui/attributes/malformed-attrs.stderr | 29 ++++++++---- ...issue-43106-gating-of-builtin-attrs.stderr | 12 ++--- .../lint/unused/unused-attr-duplicate.stderr | 24 +++++----- .../ui/malformed/malformed-regressions.stderr | 18 ++++---- 13 files changed, 117 insertions(+), 40 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/test_attrs.rs diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index b5934f4e36e8..6af15da7d08c 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -250,6 +250,13 @@ pub enum AttributeKind { span: Span, }, + /// Represents `#[ignore]` + Ignore { + span: Span, + /// ignore can optionally have a reason: `#[ignore = "reason this is ignored"]` + reason: Option, + }, + /// Represents `#[inline]` and `#[rustc_force_inline]`. Inline(InlineAttr, Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 02e95ddcb6fd..8ebd38a6ba7e 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -26,6 +26,7 @@ impl AttributeKind { Deprecation { .. } => Yes, DocComment { .. } => Yes, ExportName { .. } => Yes, + Ignore { .. } => No, Inline(..) => No, LinkName { .. } => Yes, LinkSection { .. } => No, diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index f5ac3890a46a..55fbb8254663 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -41,6 +41,7 @@ pub(crate) mod repr; pub(crate) mod rustc_internal; pub(crate) mod semantics; pub(crate) mod stability; +pub(crate) mod test_attrs; pub(crate) mod traits; pub(crate) mod transparency; pub(crate) mod util; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs new file mode 100644 index 000000000000..cea3ee52ff43 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -0,0 +1,46 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::lints::AttributeLintKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct IgnoreParser; + +impl SingleAttributeParser for IgnoreParser { + const PATH: &[Symbol] = &[sym::ignore]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + Some(AttributeKind::Ignore { + span: cx.attr_span, + reason: match args { + ArgParser::NoArgs => None, + ArgParser::NameValue(name_value) => { + let Some(str_value) = name_value.value_as_str() else { + let suggestions = >::TEMPLATE + .suggestions(false, "ignore"); + let span = cx.attr_span; + cx.emit_lint( + AttributeLintKind::IllFormedAttributeInput { suggestions }, + span, + ); + return None; + }; + Some(str_value) + } + ArgParser::List(_) => { + let suggestions = + >::TEMPLATE.suggestions(false, "ignore"); + let span = cx.attr_span; + cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + return None; + } + }, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 265e1bb6a8cb..2a01ee58493f 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -37,6 +37,7 @@ use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; +use crate::attributes::test_attrs::IgnoreParser; use crate::attributes::traits::SkipDuringMethodDispatchParser; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; @@ -126,6 +127,7 @@ attribute_parsers!( // tidy-alphabetical-start Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ca6405ea2094..559a771931e9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1303,6 +1303,7 @@ impl AttributeExt for Attribute { Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, + Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 27355a422d1f..8fdc06ee463a 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -304,6 +304,7 @@ fn emit_malformed_attribute( | sym::naked | sym::no_mangle | sym::non_exhaustive + | sym::ignore | sym::must_use | sym::track_caller | sym::link_name @@ -319,8 +320,7 @@ fn emit_malformed_attribute( // Some of previously accepted forms were used in practice, // report them as warnings for now. - let should_warn = - |name| matches!(name, sym::doc | sym::ignore | sym::link | sym::test | sym::bench); + let should_warn = |name| matches!(name, sym::doc | sym::link | sym::test | sym::bench); let error_msg = format!("malformed `{name}` attribute input"); let mut suggestions = vec![]; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c5ced4064140..18b3ab12e2d3 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -215,6 +215,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { self.check_may_dangle(hir_id, *attr_span) } + Attribute::Parsed(AttributeKind::Ignore { span, .. }) => { + self.check_generic_attr(hir_id, sym::ignore, *span, target, Target::Fn) + } Attribute::Parsed(AttributeKind::MustUse { span, .. }) => { self.check_must_use(hir_id, *span, target) } @@ -303,7 +306,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } [sym::path, ..] => self.check_generic_attr_unparsed(hir_id, attr, target, Target::Mod), [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), - [sym::ignore, ..] | [sym::should_panic, ..] => { + [sym::should_panic, ..] => { self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn) } [sym::automatically_derived, ..] => { diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index dbe9c35b0a4c..a09fe86557d2 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -219,4 +219,11 @@ macro_rules! slump { () => {} } +#[ignore = 1] +//~^ ERROR valid forms for the attribute are +//~| WARN this was previously accepted by the compiler +fn thing() { + +} + fn main() {} diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 32b0ddf87ba4..9fe4f45b3ef7 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -309,15 +309,6 @@ LL | #[link] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: valid forms for the attribute are `#[ignore]` and `#[ignore = "reason"]` - --> $DIR/malformed-attrs.rs:93:1 - | -LL | #[ignore()] - | ^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - error: invalid argument --> $DIR/malformed-attrs.rs:187:1 | @@ -600,6 +591,24 @@ LL | #[inline = 5] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 +error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` + --> $DIR/malformed-attrs.rs:93:1 + | +LL | #[ignore()] + | ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` + --> $DIR/malformed-attrs.rs:222:1 + | +LL | #[ignore = 1] + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + error[E0308]: mismatched types --> $DIR/malformed-attrs.rs:110:23 | @@ -611,7 +620,7 @@ LL | #[coroutine = 63] || {} = note: expected unit type `()` found coroutine `{coroutine@$DIR/malformed-attrs.rs:110:23: 110:25}` -error: aborting due to 73 previous errors; 3 warnings emitted +error: aborting due to 74 previous errors; 3 warnings emitted Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 9280dfdf92e5..5d7d1caeeab0 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -367,12 +367,6 @@ warning: `#[should_panic]` only has an effect on functions LL | #![should_panic] | ^^^^^^^^^^^^^^^^ -warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 - | -LL | #![ignore] - | ^^^^^^^^^^ - warning: `#[proc_macro_derive]` only has an effect on functions --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 | @@ -387,6 +381,12 @@ LL | #![link()] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: `#[ignore]` only has an effect on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 + | +LL | #![ignore] + | ^^^^^^^^^^ + warning: attribute should be applied to a foreign function or static --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1 | diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index eff478d04aee..275eb0563052 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -40,18 +40,6 @@ LL | #[path = "auxiliary/lint_unused_extern_crate.rs"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:53:1 - | -LL | #[ignore = "some text"] - | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:52:1 - | -LL | #[ignore] - | ^^^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:55:1 | @@ -165,6 +153,18 @@ note: attribute also specified here LL | #[macro_export] | ^^^^^^^^^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:53:1 + | +LL | #[ignore = "some text"] + | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:52:1 + | +LL | #[ignore] + | ^^^^^^^^^ + error: unused attribute --> $DIR/unused-attr-duplicate.rs:60:1 | diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index 535db55a13d6..8c22919a1c2f 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -8,15 +8,6 @@ LL | #[doc] = note: for more information, see issue #57571 = note: `#[deny(ill_formed_attribute_input)]` on by default -error: valid forms for the attribute are `#[ignore]` and `#[ignore = "reason"]` - --> $DIR/malformed-regressions.rs:3:1 - | -LL | #[ignore()] - | ^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]` --> $DIR/malformed-regressions.rs:7:1 | @@ -35,6 +26,15 @@ LL | #[link = ""] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 +error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` + --> $DIR/malformed-regressions.rs:3:1 + | +LL | #[ignore()] + | ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` --> $DIR/malformed-regressions.rs:5:1 | From 9c9c5b041b807ddef7d34d128b15ed10c55e751b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jul 2025 22:21:23 +0200 Subject: [PATCH 52/68] compiletest: print slightly more information on fs::write failure --- src/tools/compiletest/src/runtest.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f8bf4ee3022e..a03dd23b56bf 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1918,7 +1918,8 @@ impl<'test> TestCx<'test> { fn dump_output_file(&self, out: &str, extension: &str) { let outfile = self.make_out_name(extension); - fs::write(outfile.as_std_path(), out).unwrap(); + fs::write(outfile.as_std_path(), out) + .unwrap_or_else(|err| panic!("failed to write {outfile}: {err:?}")); } /// Creates a filename for output with the given extension. From 9f78173bb5270e6687a9b594e3ddb922f7b11bb1 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 5 Jul 2025 14:46:34 -0500 Subject: [PATCH 53/68] bootstrap: add change_tracker entry for removal of spellcheck:fix --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 68312a503eec..f5a958618f99 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -446,4 +446,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Added new option `build.tidy-extra-checks` to specify a default value for the --extra-checks cli flag.", }, + ChangeInfo { + change_id: 143493, + severity: ChangeSeverity::Warning, + summary: "The `spellcheck:fix` tidy extra check argument has been removed, use `--bless` instead", + }, ]; From a7382eae3fccb2db5353640454c5d09840d3089e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 3 Jul 2025 21:55:12 -0700 Subject: [PATCH 54/68] mbe: Add a helper to parse a single `TokenTree` The parser repeatedly invokes the `parse` function, constructing a one-entry vector, and assuming that the return value will be a one-entry vector. Add a helper for that case. This will simplify adding additional callers, and put all the logic in one place to allow potential future simplification of the one-TT case. --- compiler/rustc_expand/src/mbe/macro_rules.rs | 24 +++----------------- compiler/rustc_expand/src/mbe/quoted.rs | 18 ++++++++++++++- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 16b9fef6a21c..44201d48147b 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -36,7 +36,7 @@ use crate::base::{ }; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser}; -use crate::mbe::quoted::RulePart; +use crate::mbe::quoted::{RulePart, parse_one_tt}; use crate::mbe::transcribe::transcribe; use crate::mbe::{self, KleeneOp, macro_check}; @@ -395,16 +395,7 @@ pub fn compile_declarative_macro( while p.token != token::Eof { let lhs_tt = p.parse_token_tree(); - let lhs_tt = mbe::quoted::parse( - &TokenStream::new(vec![lhs_tt]), - RulePart::Pattern, - sess, - node_id, - features, - edition, - ) - .pop() - .unwrap(); + let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition); // We don't handle errors here, the driver will abort after parsing/expansion. We can // report every error in every macro this way. check_emission(check_lhs_nt_follows(sess, node_id, &lhs_tt)); @@ -422,16 +413,7 @@ pub fn compile_declarative_macro( return dummy_syn_ext(guar); } let rhs_tt = p.parse_token_tree(); - let rhs_tt = mbe::quoted::parse( - &TokenStream::new(vec![rhs_tt]), - RulePart::Body, - sess, - node_id, - features, - edition, - ) - .pop() - .unwrap(); + let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition); check_emission(check_rhs(sess, &rhs_tt)); check_emission(macro_check::check_meta_variables(&sess.psess, node_id, &lhs_tt, &rhs_tt)); lhses.push(lhs_tt); diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 065ae23a262d..eb874a27cece 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -57,7 +57,7 @@ impl RulePart { /// # Returns /// /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`. -pub(super) fn parse( +fn parse( input: &tokenstream::TokenStream, part: RulePart, sess: &Session, @@ -152,6 +152,22 @@ pub(super) fn parse( result } +/// Takes a `tokenstream::TokenTree` and returns a `self::TokenTree`. Like `parse`, but for a +/// single token tree. Emits errors to `sess` if needed. +#[inline] +pub(super) fn parse_one_tt( + input: tokenstream::TokenTree, + part: RulePart, + sess: &Session, + node_id: NodeId, + features: &Features, + edition: Edition, +) -> TokenTree { + parse(&tokenstream::TokenStream::new(vec![input]), part, sess, node_id, features, edition) + .pop() + .unwrap() +} + /// Asks for the `macro_metavar_expr` feature if it is not enabled fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) { if !features.macro_metavar_expr() { From 0d5ab3e46ce3be1e5e3c45ac0ff7d355303c4353 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 3 Jul 2025 22:57:06 -0700 Subject: [PATCH 55/68] mbe: Simplify a match to a let-else --- compiler/rustc_expand/src/mbe/macro_rules.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 44201d48147b..731a4a08ab00 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -213,9 +213,8 @@ fn expand_macro<'cx>( match try_success_result { Ok((i, named_matches)) => { - let (rhs, rhs_span): (&mbe::Delimited, DelimSpan) = match &rhses[i] { - mbe::TokenTree::Delimited(span, _, delimited) => (&delimited, *span), - _ => cx.dcx().span_bug(sp, "malformed macro rhs"), + let mbe::TokenTree::Delimited(rhs_span, _, ref rhs) = rhses[i] else { + cx.dcx().span_bug(sp, "malformed macro rhs"); }; let arm_span = rhses[i].span(); From 63cfb3af37d74d312829d4e260e03128eb7e3f27 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 4 Jul 2025 01:22:37 -0700 Subject: [PATCH 56/68] mbe: Defer checks for `compile_error!` until reporting an unused macro rule The MBE parser checks rules at initial parse time to see if their RHS has `compile_error!` in it, and returns a list of rule indexes and LHS spans that don't map to `compile_error!`, for use in unused macro rule checking. Instead, have the unused macro rule reporting ask the macro for the rule to report, and let the macro check at that time. That avoids checking rules unless they're unused. In the process, refactor the data structure used to store macro rules, to group the LHS and RHS (and LHS span) of each rule together, and refactor the unused rule tracking to only track rule indexes. This ends up being a net simplification, and reduction in code size. --- compiler/rustc_expand/src/base.rs | 4 + compiler/rustc_expand/src/mbe/diagnostics.rs | 10 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 114 +++++++----------- .../rustc_resolve/src/build_reduced_graph.rs | 8 +- compiler/rustc_resolve/src/lib.rs | 6 +- compiler/rustc_resolve/src/macros.rs | 30 +++-- 6 files changed, 80 insertions(+), 92 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 80f6e9d9fc48..d6d898088395 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -348,6 +348,10 @@ pub trait TTMacroExpander { span: Span, input: TokenStream, ) -> MacroExpanderResult<'cx>; + + fn get_unused_rule(&self, _rule_i: usize) -> Option<(&Ident, Span)> { + None + } } pub type MacroExpanderResult<'cx> = ExpandResult, ()>; diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index c607a3a3652c..7a280d671f41 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -10,7 +10,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::{ErrorGuaranteed, Ident, Span}; use tracing::debug; -use super::macro_rules::{NoopTracker, parser_from_cx}; +use super::macro_rules::{MacroRule, NoopTracker, parser_from_cx}; use crate::expand::{AstFragmentKind, parse_ast_fragment}; use crate::mbe::macro_parser::ParseResult::*; use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser}; @@ -22,14 +22,14 @@ pub(super) fn failed_to_match_macro( def_span: Span, name: Ident, arg: TokenStream, - lhses: &[Vec], + rules: &[MacroRule], ) -> (Span, ErrorGuaranteed) { debug!("failed to match macro"); // An error occurred, try the expansion again, tracking the expansion closely for better // diagnostics. let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp); - let try_success_result = try_match_macro(psess, name, &arg, lhses, &mut tracker); + let try_success_result = try_match_macro(psess, name, &arg, rules, &mut tracker); if try_success_result.is_ok() { // Nonterminal parser recovery might turn failed matches into successful ones, @@ -80,12 +80,12 @@ pub(super) fn failed_to_match_macro( // Check whether there's a missing comma in this macro call, like `println!("{}" a);` if let Some((arg, comma_span)) = arg.add_comma() { - for lhs in lhses { + for rule in rules { let parser = parser_from_cx(psess, arg.clone(), Recovery::Allowed); let mut tt_parser = TtParser::new(name); if let Success(_) = - tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker) + tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, &mut NoopTracker) { if comma_span.is_dummy() { err.note("you might be missing a comma"); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 731a4a08ab00..52cdcc5c747e 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -98,13 +98,18 @@ impl<'a> ParserAnyMacro<'a> { } } +pub(super) struct MacroRule { + pub(super) lhs: Vec, + lhs_span: Span, + rhs: mbe::TokenTree, +} + struct MacroRulesMacroExpander { node_id: NodeId, name: Ident, span: Span, transparency: Transparency, - lhses: Vec>, - rhses: Vec, + rules: Vec, } impl TTMacroExpander for MacroRulesMacroExpander { @@ -122,10 +127,15 @@ impl TTMacroExpander for MacroRulesMacroExpander { self.name, self.transparency, input, - &self.lhses, - &self.rhses, + &self.rules, )) } + + fn get_unused_rule(&self, rule_i: usize) -> Option<(&Ident, Span)> { + // If the rhs contains an invocation like `compile_error!`, don't report it as unused. + let rule = &self.rules[rule_i]; + if has_compile_error_macro(&rule.rhs) { None } else { Some((&self.name, rule.lhs_span)) } + } } struct DummyExpander(ErrorGuaranteed); @@ -184,9 +194,8 @@ impl<'matcher> Tracker<'matcher> for NoopTracker { } } -/// Expands the rules based macro defined by `lhses` and `rhses` for a given -/// input `arg`. -#[instrument(skip(cx, transparency, arg, lhses, rhses))] +/// Expands the rules based macro defined by `rules` for a given input `arg`. +#[instrument(skip(cx, transparency, arg, rules))] fn expand_macro<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -195,8 +204,7 @@ fn expand_macro<'cx>( name: Ident, transparency: Transparency, arg: TokenStream, - lhses: &[Vec], - rhses: &[mbe::TokenTree], + rules: &[MacroRule], ) -> Box { let psess = &cx.sess.psess; // Macros defined in the current crate have a real node id, @@ -209,14 +217,14 @@ fn expand_macro<'cx>( } // Track nothing for the best performance. - let try_success_result = try_match_macro(psess, name, &arg, lhses, &mut NoopTracker); + let try_success_result = try_match_macro(psess, name, &arg, rules, &mut NoopTracker); match try_success_result { - Ok((i, named_matches)) => { - let mbe::TokenTree::Delimited(rhs_span, _, ref rhs) = rhses[i] else { + Ok((i, rule, named_matches)) => { + let mbe::TokenTree::Delimited(rhs_span, _, ref rhs) = rule.rhs else { cx.dcx().span_bug(sp, "malformed macro rhs"); }; - let arm_span = rhses[i].span(); + let arm_span = rule.rhs.span(); // rhs has holes ( `$id` and `$(...)` that need filled) let id = cx.current_expansion.id; @@ -262,7 +270,7 @@ fn expand_macro<'cx>( Err(CanRetry::Yes) => { // Retry and emit a better error. let (span, guar) = - diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, lhses); + diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, rules); cx.trace_macros_diag(); DummyResult::any(span, guar) } @@ -278,14 +286,14 @@ pub(super) enum CanRetry { /// Try expanding the macro. Returns the index of the successful arm and its named_matches if it was successful, /// and nothing if it failed. On failure, it's the callers job to use `track` accordingly to record all errors /// correctly. -#[instrument(level = "debug", skip(psess, arg, lhses, track), fields(tracking = %T::description()))] +#[instrument(level = "debug", skip(psess, arg, rules, track), fields(tracking = %T::description()))] pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( psess: &ParseSess, name: Ident, arg: &TokenStream, - lhses: &'matcher [Vec], + rules: &'matcher [MacroRule], track: &mut T, -) -> Result<(usize, NamedMatches), CanRetry> { +) -> Result<(usize, &'matcher MacroRule, NamedMatches), CanRetry> { // We create a base parser that can be used for the "black box" parts. // Every iteration needs a fresh copy of that parser. However, the parser // is not mutated on many of the iterations, particularly when dealing with @@ -308,7 +316,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( let parser = parser_from_cx(psess, arg.clone(), T::recovery()); // Try each arm's matchers. let mut tt_parser = TtParser::new(name); - for (i, lhs) in lhses.iter().enumerate() { + for (i, rule) in rules.iter().enumerate() { let _tracing_span = trace_span!("Matching arm", %i); // Take a snapshot of the state of pre-expansion gating at this point. @@ -317,7 +325,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. let mut gated_spans_snapshot = mem::take(&mut *psess.gated_spans.spans.borrow_mut()); - let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, track); + let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, track); track.after_arm(&result); @@ -328,7 +336,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( // Merge the gated spans from parsing the matcher with the preexisting ones. psess.gated_spans.merge(gated_spans_snapshot); - return Ok((i, named_matches)); + return Ok((i, rule, named_matches)); } Failure(_) => { trace!("Failed to match arm, trying the next one"); @@ -364,7 +372,7 @@ pub fn compile_declarative_macro( span: Span, node_id: NodeId, edition: Edition, -) -> (SyntaxExtension, Vec<(usize, Span)>) { +) -> (SyntaxExtension, usize) { let mk_syn_ext = |expander| { SyntaxExtension::new( sess, @@ -377,7 +385,7 @@ pub fn compile_declarative_macro( node_id != DUMMY_NODE_ID, ) }; - let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), Vec::new()); + let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), 0); let macro_rules = macro_def.macro_rules; let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) }; @@ -389,8 +397,7 @@ pub fn compile_declarative_macro( let mut guar = None; let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err()); - let mut lhses = Vec::new(); - let mut rhses = Vec::new(); + let mut rules = Vec::new(); while p.token != token::Eof { let lhs_tt = p.parse_token_tree(); @@ -415,8 +422,15 @@ pub fn compile_declarative_macro( let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition); check_emission(check_rhs(sess, &rhs_tt)); check_emission(macro_check::check_meta_variables(&sess.psess, node_id, &lhs_tt, &rhs_tt)); - lhses.push(lhs_tt); - rhses.push(rhs_tt); + let lhs_span = lhs_tt.span(); + // Convert the lhs into `MatcherLoc` form, which is better for doing the + // actual matching. + let lhs = if let mbe::TokenTree::Delimited(.., delimited) = lhs_tt { + mbe::macro_parser::compute_locs(&delimited.tts) + } else { + return dummy_syn_ext(guar.unwrap()); + }; + rules.push(MacroRule { lhs, lhs_span, rhs: rhs_tt }); if p.token == token::Eof { break; } @@ -425,7 +439,7 @@ pub fn compile_declarative_macro( } } - if lhses.is_empty() { + if rules.is_empty() { let guar = sess.dcx().span_err(span, "macros must contain at least one rule"); return dummy_syn_ext(guar); } @@ -439,48 +453,12 @@ pub fn compile_declarative_macro( return dummy_syn_ext(guar); } - // Compute the spans of the macro rules for unused rule linting. - // Also, we are only interested in non-foreign macros. - let rule_spans = if node_id != DUMMY_NODE_ID { - lhses - .iter() - .zip(rhses.iter()) - .enumerate() - // If the rhs contains an invocation like compile_error!, - // don't consider the rule for the unused rule lint. - .filter(|(_idx, (_lhs, rhs))| !has_compile_error_macro(rhs)) - // We only take the span of the lhs here, - // so that the spans of created warnings are smaller. - .map(|(idx, (lhs, _rhs))| (idx, lhs.span())) - .collect::>() - } else { - Vec::new() - }; + // Return the number of rules for unused rule linting, if this is a local macro. + let nrules = if node_id != DUMMY_NODE_ID { rules.len() } else { 0 }; - // Convert the lhses into `MatcherLoc` form, which is better for doing the - // actual matching. - let lhses = lhses - .iter() - .map(|lhs| { - // Ignore the delimiters around the matcher. - match lhs { - mbe::TokenTree::Delimited(.., delimited) => { - mbe::macro_parser::compute_locs(&delimited.tts) - } - _ => sess.dcx().span_bug(span, "malformed macro lhs"), - } - }) - .collect(); - - let expander = Arc::new(MacroRulesMacroExpander { - name: ident, - span, - node_id, - transparency, - lhses, - rhses, - }); - (mk_syn_ext(expander), rule_spans) + let expander = + Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules }); + (mk_syn_ext(expander), nrules) } fn check_lhs_nt_follows( diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 650a827ba564..eeb8cb893d75 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1202,12 +1202,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) { if !ident.as_str().starts_with('_') { self.r.unused_macros.insert(def_id, (node_id, ident)); - for (rule_i, rule_span) in &self.r.macro_map[&def_id.to_def_id()].rule_spans { - self.r - .unused_macro_rules - .entry(node_id) - .or_default() - .insert(*rule_i, (ident, *rule_span)); + for rule_i in 0..self.r.macro_map[&def_id.to_def_id()].nrules { + self.r.unused_macro_rules.entry(node_id).or_default().insert(rule_i); } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7162f3a77d35..3f865d7c2dac 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1014,13 +1014,13 @@ struct DeriveData { struct MacroData { ext: Arc, - rule_spans: Vec<(usize, Span)>, + nrules: usize, macro_rules: bool, } impl MacroData { fn new(ext: Arc) -> MacroData { - MacroData { ext, rule_spans: Vec::new(), macro_rules: false } + MacroData { ext, nrules: 0, macro_rules: false } } } @@ -1135,7 +1135,7 @@ pub struct Resolver<'ra, 'tcx> { ast_transform_scopes: FxHashMap>, unused_macros: FxIndexMap, /// A map from the macro to all its potentially unused arms. - unused_macro_rules: FxIndexMap>, + unused_macro_rules: FxIndexMap>, proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 3d33a02a9c6d..9bc96403559e 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -351,13 +351,23 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } for (&node_id, unused_arms) in self.unused_macro_rules.iter() { - for (&arm_i, &(ident, rule_span)) in unused_arms.to_sorted_stable_ord() { - self.lint_buffer.buffer_lint( - UNUSED_MACRO_RULES, - node_id, - rule_span, - BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name), - ); + if unused_arms.is_empty() { + continue; + } + let def_id = self.local_def_id(node_id).to_def_id(); + let m = &self.macro_map[&def_id]; + let SyntaxExtensionKind::LegacyBang(ref ext) = m.ext.kind else { + continue; + }; + for &arm_i in unused_arms.to_sorted_stable_ord() { + if let Some((ident, rule_span)) = ext.get_unused_rule(arm_i) { + self.lint_buffer.buffer_lint( + UNUSED_MACRO_RULES, + node_id, + rule_span, + BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name), + ); + } } } } @@ -1146,7 +1156,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { node_id: NodeId, edition: Edition, ) -> MacroData { - let (mut ext, mut rule_spans) = compile_declarative_macro( + let (mut ext, mut nrules) = compile_declarative_macro( self.tcx.sess, self.tcx.features(), macro_def, @@ -1163,13 +1173,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. ext.kind = builtin_ext_kind.clone(); - rule_spans = Vec::new(); + nrules = 0; } else { self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident }); } } - MacroData { ext: Arc::new(ext), rule_spans, macro_rules: macro_def.macro_rules } + MacroData { ext: Arc::new(ext), nrules, macro_rules: macro_def.macro_rules } } fn path_accessible( From 6d64306df1d834966a23a27c085c043214668181 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 5 Jul 2025 16:52:59 -0700 Subject: [PATCH 57/68] Move macro tests in `parser` into `macro` directory The `macro` directory contains most of the macro tests, but not all of them; move the remainder into `macro`. --- tests/ui/parser/{ => macro}/break-in-unlabeled-block-in-macro.rs | 0 .../parser/{ => macro}/break-in-unlabeled-block-in-macro.stderr | 0 ...-semicolon-between-macro-without-exclamation-mark-and-array.rs | 0 ...icolon-between-macro-without-exclamation-mark-and-array.stderr | 0 tests/ui/parser/{ => macro}/extern-abi-from-mac-literal-frag.rs | 0 tests/ui/parser/{ => macro}/lit-err-in-macro.rs | 0 tests/ui/parser/{ => macro}/lit-err-in-macro.stderr | 0 tests/ui/parser/{ => macro}/macro-bad-delimiter-ident.rs | 0 tests/ui/parser/{ => macro}/macro-bad-delimiter-ident.stderr | 0 tests/ui/parser/{ => macro}/macro-braces-dot-question.rs | 0 tests/ui/parser/{ => macro}/macro-keyword.rs | 0 tests/ui/parser/{ => macro}/macro-keyword.stderr | 0 tests/ui/parser/{ => macro}/macro-mismatched-delim-brace-paren.rs | 0 .../parser/{ => macro}/macro-mismatched-delim-brace-paren.stderr | 0 tests/ui/parser/{ => macro}/macro-mismatched-delim-paren-brace.rs | 0 .../parser/{ => macro}/macro-mismatched-delim-paren-brace.stderr | 0 tests/ui/parser/{ => macro}/macros-no-semicolon-items.rs | 0 tests/ui/parser/{ => macro}/macros-no-semicolon-items.stderr | 0 tests/ui/parser/{ => macro}/macros-no-semicolon.rs | 0 tests/ui/parser/{ => macro}/macros-no-semicolon.stderr | 0 tests/ui/parser/{ => macro}/mbe_missing_right_paren.rs | 0 tests/ui/parser/{ => macro}/mbe_missing_right_paren.stderr | 0 tests/ui/parser/{ => macro}/misspelled-macro-rules.fixed | 0 tests/ui/parser/{ => macro}/misspelled-macro-rules.rs | 0 tests/ui/parser/{ => macro}/misspelled-macro-rules.stderr | 0 tests/ui/parser/{ => macro}/pub-method-macro.rs | 0 tests/ui/parser/{ => macro}/pub-method-macro.stderr | 0 tests/ui/parser/{ => macro}/semi-after-closure-in-macro.rs | 0 tests/ui/parser/{ => macro}/trailing-question-in-macro-type.rs | 0 .../ui/parser/{ => macro}/trailing-question-in-macro-type.stderr | 0 30 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/parser/{ => macro}/break-in-unlabeled-block-in-macro.rs (100%) rename tests/ui/parser/{ => macro}/break-in-unlabeled-block-in-macro.stderr (100%) rename tests/ui/parser/{ => macro}/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs (100%) rename tests/ui/parser/{ => macro}/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr (100%) rename tests/ui/parser/{ => macro}/extern-abi-from-mac-literal-frag.rs (100%) rename tests/ui/parser/{ => macro}/lit-err-in-macro.rs (100%) rename tests/ui/parser/{ => macro}/lit-err-in-macro.stderr (100%) rename tests/ui/parser/{ => macro}/macro-bad-delimiter-ident.rs (100%) rename tests/ui/parser/{ => macro}/macro-bad-delimiter-ident.stderr (100%) rename tests/ui/parser/{ => macro}/macro-braces-dot-question.rs (100%) rename tests/ui/parser/{ => macro}/macro-keyword.rs (100%) rename tests/ui/parser/{ => macro}/macro-keyword.stderr (100%) rename tests/ui/parser/{ => macro}/macro-mismatched-delim-brace-paren.rs (100%) rename tests/ui/parser/{ => macro}/macro-mismatched-delim-brace-paren.stderr (100%) rename tests/ui/parser/{ => macro}/macro-mismatched-delim-paren-brace.rs (100%) rename tests/ui/parser/{ => macro}/macro-mismatched-delim-paren-brace.stderr (100%) rename tests/ui/parser/{ => macro}/macros-no-semicolon-items.rs (100%) rename tests/ui/parser/{ => macro}/macros-no-semicolon-items.stderr (100%) rename tests/ui/parser/{ => macro}/macros-no-semicolon.rs (100%) rename tests/ui/parser/{ => macro}/macros-no-semicolon.stderr (100%) rename tests/ui/parser/{ => macro}/mbe_missing_right_paren.rs (100%) rename tests/ui/parser/{ => macro}/mbe_missing_right_paren.stderr (100%) rename tests/ui/parser/{ => macro}/misspelled-macro-rules.fixed (100%) rename tests/ui/parser/{ => macro}/misspelled-macro-rules.rs (100%) rename tests/ui/parser/{ => macro}/misspelled-macro-rules.stderr (100%) rename tests/ui/parser/{ => macro}/pub-method-macro.rs (100%) rename tests/ui/parser/{ => macro}/pub-method-macro.stderr (100%) rename tests/ui/parser/{ => macro}/semi-after-closure-in-macro.rs (100%) rename tests/ui/parser/{ => macro}/trailing-question-in-macro-type.rs (100%) rename tests/ui/parser/{ => macro}/trailing-question-in-macro-type.stderr (100%) diff --git a/tests/ui/parser/break-in-unlabeled-block-in-macro.rs b/tests/ui/parser/macro/break-in-unlabeled-block-in-macro.rs similarity index 100% rename from tests/ui/parser/break-in-unlabeled-block-in-macro.rs rename to tests/ui/parser/macro/break-in-unlabeled-block-in-macro.rs diff --git a/tests/ui/parser/break-in-unlabeled-block-in-macro.stderr b/tests/ui/parser/macro/break-in-unlabeled-block-in-macro.stderr similarity index 100% rename from tests/ui/parser/break-in-unlabeled-block-in-macro.stderr rename to tests/ui/parser/macro/break-in-unlabeled-block-in-macro.stderr diff --git a/tests/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs b/tests/ui/parser/macro/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs similarity index 100% rename from tests/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs rename to tests/ui/parser/macro/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs diff --git a/tests/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr b/tests/ui/parser/macro/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr similarity index 100% rename from tests/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr rename to tests/ui/parser/macro/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr diff --git a/tests/ui/parser/extern-abi-from-mac-literal-frag.rs b/tests/ui/parser/macro/extern-abi-from-mac-literal-frag.rs similarity index 100% rename from tests/ui/parser/extern-abi-from-mac-literal-frag.rs rename to tests/ui/parser/macro/extern-abi-from-mac-literal-frag.rs diff --git a/tests/ui/parser/lit-err-in-macro.rs b/tests/ui/parser/macro/lit-err-in-macro.rs similarity index 100% rename from tests/ui/parser/lit-err-in-macro.rs rename to tests/ui/parser/macro/lit-err-in-macro.rs diff --git a/tests/ui/parser/lit-err-in-macro.stderr b/tests/ui/parser/macro/lit-err-in-macro.stderr similarity index 100% rename from tests/ui/parser/lit-err-in-macro.stderr rename to tests/ui/parser/macro/lit-err-in-macro.stderr diff --git a/tests/ui/parser/macro-bad-delimiter-ident.rs b/tests/ui/parser/macro/macro-bad-delimiter-ident.rs similarity index 100% rename from tests/ui/parser/macro-bad-delimiter-ident.rs rename to tests/ui/parser/macro/macro-bad-delimiter-ident.rs diff --git a/tests/ui/parser/macro-bad-delimiter-ident.stderr b/tests/ui/parser/macro/macro-bad-delimiter-ident.stderr similarity index 100% rename from tests/ui/parser/macro-bad-delimiter-ident.stderr rename to tests/ui/parser/macro/macro-bad-delimiter-ident.stderr diff --git a/tests/ui/parser/macro-braces-dot-question.rs b/tests/ui/parser/macro/macro-braces-dot-question.rs similarity index 100% rename from tests/ui/parser/macro-braces-dot-question.rs rename to tests/ui/parser/macro/macro-braces-dot-question.rs diff --git a/tests/ui/parser/macro-keyword.rs b/tests/ui/parser/macro/macro-keyword.rs similarity index 100% rename from tests/ui/parser/macro-keyword.rs rename to tests/ui/parser/macro/macro-keyword.rs diff --git a/tests/ui/parser/macro-keyword.stderr b/tests/ui/parser/macro/macro-keyword.stderr similarity index 100% rename from tests/ui/parser/macro-keyword.stderr rename to tests/ui/parser/macro/macro-keyword.stderr diff --git a/tests/ui/parser/macro-mismatched-delim-brace-paren.rs b/tests/ui/parser/macro/macro-mismatched-delim-brace-paren.rs similarity index 100% rename from tests/ui/parser/macro-mismatched-delim-brace-paren.rs rename to tests/ui/parser/macro/macro-mismatched-delim-brace-paren.rs diff --git a/tests/ui/parser/macro-mismatched-delim-brace-paren.stderr b/tests/ui/parser/macro/macro-mismatched-delim-brace-paren.stderr similarity index 100% rename from tests/ui/parser/macro-mismatched-delim-brace-paren.stderr rename to tests/ui/parser/macro/macro-mismatched-delim-brace-paren.stderr diff --git a/tests/ui/parser/macro-mismatched-delim-paren-brace.rs b/tests/ui/parser/macro/macro-mismatched-delim-paren-brace.rs similarity index 100% rename from tests/ui/parser/macro-mismatched-delim-paren-brace.rs rename to tests/ui/parser/macro/macro-mismatched-delim-paren-brace.rs diff --git a/tests/ui/parser/macro-mismatched-delim-paren-brace.stderr b/tests/ui/parser/macro/macro-mismatched-delim-paren-brace.stderr similarity index 100% rename from tests/ui/parser/macro-mismatched-delim-paren-brace.stderr rename to tests/ui/parser/macro/macro-mismatched-delim-paren-brace.stderr diff --git a/tests/ui/parser/macros-no-semicolon-items.rs b/tests/ui/parser/macro/macros-no-semicolon-items.rs similarity index 100% rename from tests/ui/parser/macros-no-semicolon-items.rs rename to tests/ui/parser/macro/macros-no-semicolon-items.rs diff --git a/tests/ui/parser/macros-no-semicolon-items.stderr b/tests/ui/parser/macro/macros-no-semicolon-items.stderr similarity index 100% rename from tests/ui/parser/macros-no-semicolon-items.stderr rename to tests/ui/parser/macro/macros-no-semicolon-items.stderr diff --git a/tests/ui/parser/macros-no-semicolon.rs b/tests/ui/parser/macro/macros-no-semicolon.rs similarity index 100% rename from tests/ui/parser/macros-no-semicolon.rs rename to tests/ui/parser/macro/macros-no-semicolon.rs diff --git a/tests/ui/parser/macros-no-semicolon.stderr b/tests/ui/parser/macro/macros-no-semicolon.stderr similarity index 100% rename from tests/ui/parser/macros-no-semicolon.stderr rename to tests/ui/parser/macro/macros-no-semicolon.stderr diff --git a/tests/ui/parser/mbe_missing_right_paren.rs b/tests/ui/parser/macro/mbe_missing_right_paren.rs similarity index 100% rename from tests/ui/parser/mbe_missing_right_paren.rs rename to tests/ui/parser/macro/mbe_missing_right_paren.rs diff --git a/tests/ui/parser/mbe_missing_right_paren.stderr b/tests/ui/parser/macro/mbe_missing_right_paren.stderr similarity index 100% rename from tests/ui/parser/mbe_missing_right_paren.stderr rename to tests/ui/parser/macro/mbe_missing_right_paren.stderr diff --git a/tests/ui/parser/misspelled-macro-rules.fixed b/tests/ui/parser/macro/misspelled-macro-rules.fixed similarity index 100% rename from tests/ui/parser/misspelled-macro-rules.fixed rename to tests/ui/parser/macro/misspelled-macro-rules.fixed diff --git a/tests/ui/parser/misspelled-macro-rules.rs b/tests/ui/parser/macro/misspelled-macro-rules.rs similarity index 100% rename from tests/ui/parser/misspelled-macro-rules.rs rename to tests/ui/parser/macro/misspelled-macro-rules.rs diff --git a/tests/ui/parser/misspelled-macro-rules.stderr b/tests/ui/parser/macro/misspelled-macro-rules.stderr similarity index 100% rename from tests/ui/parser/misspelled-macro-rules.stderr rename to tests/ui/parser/macro/misspelled-macro-rules.stderr diff --git a/tests/ui/parser/pub-method-macro.rs b/tests/ui/parser/macro/pub-method-macro.rs similarity index 100% rename from tests/ui/parser/pub-method-macro.rs rename to tests/ui/parser/macro/pub-method-macro.rs diff --git a/tests/ui/parser/pub-method-macro.stderr b/tests/ui/parser/macro/pub-method-macro.stderr similarity index 100% rename from tests/ui/parser/pub-method-macro.stderr rename to tests/ui/parser/macro/pub-method-macro.stderr diff --git a/tests/ui/parser/semi-after-closure-in-macro.rs b/tests/ui/parser/macro/semi-after-closure-in-macro.rs similarity index 100% rename from tests/ui/parser/semi-after-closure-in-macro.rs rename to tests/ui/parser/macro/semi-after-closure-in-macro.rs diff --git a/tests/ui/parser/trailing-question-in-macro-type.rs b/tests/ui/parser/macro/trailing-question-in-macro-type.rs similarity index 100% rename from tests/ui/parser/trailing-question-in-macro-type.rs rename to tests/ui/parser/macro/trailing-question-in-macro-type.rs diff --git a/tests/ui/parser/trailing-question-in-macro-type.stderr b/tests/ui/parser/macro/trailing-question-in-macro-type.stderr similarity index 100% rename from tests/ui/parser/trailing-question-in-macro-type.stderr rename to tests/ui/parser/macro/trailing-question-in-macro-type.stderr From 31ea5f90c77abfe0b687fa74b2b20ee0738f3103 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 6 Jul 2025 00:26:38 +0000 Subject: [PATCH 58/68] cargo update compiler & tools dependencies: Locking 6 packages to latest compatible versions Adding io-uring v0.7.8 Updating jsonpath-rust v1.0.2 -> v1.0.3 Updating libffi v4.1.0 -> v4.1.1 Updating libffi-sys v3.3.1 -> v3.3.2 Updating tokio v1.45.1 -> v1.46.1 Updating wasm-component-ld v0.5.14 -> v0.5.15 note: pass `--verbose` to see 41 unchanged dependencies behind latest library dependencies: Locking 0 packages to latest compatible versions note: pass `--verbose` to see 4 unchanged dependencies behind latest rustbook dependencies: Locking 1 package to latest compatible version Updating cc v1.2.27 -> v1.2.29 --- Cargo.lock | 35 +++++++++++++++++++++++++---------- src/tools/rustbook/Cargo.lock | 4 ++-- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34fc0860a4b7..24e1cc7712f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1947,6 +1947,17 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "io-uring" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + [[package]] name = "ipc-channel" version = "0.19.0" @@ -2058,9 +2069,9 @@ dependencies = [ [[package]] name = "jsonpath-rust" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b37465feaf9d41f74df7da98c6c1c31ca8ea06d11b5bf7869c8f1ccc51a793f" +checksum = "7d057f8fd19e20c3f14d3663983397155739b6bc1148dc5cd4c4a1a5b3130eb0" dependencies = [ "pest", "pest_derive", @@ -2117,9 +2128,9 @@ dependencies = [ [[package]] name = "libffi" -version = "4.1.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebfd30a67b482a08116e753d0656cb626548cf4242543e5cc005be7639d99838" +checksum = "e7681c6fab541f799a829e44a445a0666cf8d8a6cfebf89419e6aed52c604e87" dependencies = [ "libc", "libffi-sys", @@ -2127,9 +2138,9 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "3.3.1" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f003aa318c9f0ee69eb0ada7c78f5c9d2fedd2ceb274173b5c7ff475eee584a3" +checksum = "7b0d828d367b4450ed08e7d510dc46636cd660055f50d67ac943bfe788767c29" dependencies = [ "cc", ] @@ -5462,13 +5473,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.1" +version = "1.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" dependencies = [ "backtrace", "bytes", + "io-uring", + "libc", + "mio", "pin-project-lite", + "slab", ] [[package]] @@ -5994,9 +6009,9 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b015ec93764aa5517bc8b839efa9941b90be8ce680b1134f8224644ba1e48e3f" +checksum = "6d95124e34fee1316222e03b9bbf41af186ecbae2c8b79f8debe6e21b3ff60c5" dependencies = [ "anyhow", "clap", diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index aeae5b61b955..050ddf47baef 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -156,9 +156,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.27" +version = "1.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" dependencies = [ "shlex", ] From e99f9c5ffcf5e412a13c974255031e33ab26015a Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 5 Jul 2025 20:21:51 -0700 Subject: [PATCH 59/68] rustc_builtin_macros: Make sure registered attributes stay sorted As with the list of builtin macros, use tidy to make sure the list of builtin attributes stays sorted. --- compiler/rustc_builtin_macros/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 0594f7e86c33..6bf590df5c9d 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -108,6 +108,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { } register_attr! { + // tidy-alphabetical-start alloc_error_handler: alloc_error_handler::expand, autodiff_forward: autodiff::expand_forward, autodiff_reverse: autodiff::expand_reverse, @@ -120,6 +121,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, + // tidy-alphabetical-end } register_derive! { From 131cffb6baca60f119c33f2599a0e6051b05c365 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 5 Jul 2025 16:57:24 -0700 Subject: [PATCH 60/68] Rename tests named with `mbe` to use `macro` instead Most macro tests use `macro` in the name, making it easy to find and run tests relevant to macros. However, a few use `mbe` instead. Rename those to say `macro`. --- ... => macro-async-trait-bound-theoretical-regression.rs} | 0 ...macro-async-trait-bound-theoretical-regression.stderr} | 8 ++++---- ...nd.rs => macro-bare-trait-object-maybe-trait-bound.rs} | 0 ...-a-type.rs => macro-dotdotdot-may-not-begin-a-type.rs} | 0 ...issing_right_paren.rs => macro-missing-right-paren.rs} | 0 ...ight_paren.stderr => macro-missing-right-paren.stderr} | 2 +- ....rs => macro-bare-trait-objects-const-trait-bounds.rs} | 0 ...=> macro-bare-trait-objects-const-trait-bounds.stderr} | 4 ++-- ... => macro-const-trait-bound-theoretical-regression.rs} | 0 ...macro-const-trait-bound-theoretical-regression.stderr} | 8 ++++---- .../{mbe-dyn-const-2015.rs => macro-dyn-const-2015.rs} | 0 11 files changed, 11 insertions(+), 11 deletions(-) rename tests/ui/async-await/async-fn/{mbe-async-trait-bound-theoretical-regression.rs => macro-async-trait-bound-theoretical-regression.rs} (100%) rename tests/ui/async-await/async-fn/{mbe-async-trait-bound-theoretical-regression.stderr => macro-async-trait-bound-theoretical-regression.stderr} (86%) rename tests/ui/parser/macro/{mbe-bare-trait-object-maybe-trait-bound.rs => macro-bare-trait-object-maybe-trait-bound.rs} (100%) rename tests/ui/parser/macro/{mbe-dotdotdot-may-not-begin-a-type.rs => macro-dotdotdot-may-not-begin-a-type.rs} (100%) rename tests/ui/parser/macro/{mbe_missing_right_paren.rs => macro-missing-right-paren.rs} (100%) rename tests/ui/parser/macro/{mbe_missing_right_paren.stderr => macro-missing-right-paren.stderr} (82%) rename tests/ui/traits/const-traits/{mbe-bare-trait-objects-const-trait-bounds.rs => macro-bare-trait-objects-const-trait-bounds.rs} (100%) rename tests/ui/traits/const-traits/{mbe-bare-trait-objects-const-trait-bounds.stderr => macro-bare-trait-objects-const-trait-bounds.stderr} (84%) rename tests/ui/traits/const-traits/{mbe-const-trait-bound-theoretical-regression.rs => macro-const-trait-bound-theoretical-regression.rs} (100%) rename tests/ui/traits/const-traits/{mbe-const-trait-bound-theoretical-regression.stderr => macro-const-trait-bound-theoretical-regression.stderr} (85%) rename tests/ui/traits/const-traits/{mbe-dyn-const-2015.rs => macro-dyn-const-2015.rs} (100%) diff --git a/tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.rs b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs similarity index 100% rename from tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.rs rename to tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs diff --git a/tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.stderr b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr similarity index 86% rename from tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.stderr rename to tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr index a463944d1133..6c3044e64d20 100644 --- a/tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.stderr +++ b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr @@ -1,5 +1,5 @@ error: ty - --> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19 + --> $DIR/macro-async-trait-bound-theoretical-regression.rs:8:19 | LL | ($ty:ty) => { compile_error!("ty"); }; | ^^^^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | demo! { impl async Trait } = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) error: ty - --> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19 + --> $DIR/macro-async-trait-bound-theoretical-regression.rs:8:19 | LL | ($ty:ty) => { compile_error!("ty"); }; | ^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | demo! { dyn async Trait } = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: `async` trait bounds are unstable - --> $DIR/mbe-async-trait-bound-theoretical-regression.rs:15:14 + --> $DIR/macro-async-trait-bound-theoretical-regression.rs:15:14 | LL | demo! { impl async Trait } | ^^^^^ @@ -32,7 +32,7 @@ LL | demo! { impl async Trait } = help: use the desugared name of the async trait, such as `AsyncFn` error[E0658]: `async` trait bounds are unstable - --> $DIR/mbe-async-trait-bound-theoretical-regression.rs:18:13 + --> $DIR/macro-async-trait-bound-theoretical-regression.rs:18:13 | LL | demo! { dyn async Trait } | ^^^^^ diff --git a/tests/ui/parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs b/tests/ui/parser/macro/macro-bare-trait-object-maybe-trait-bound.rs similarity index 100% rename from tests/ui/parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs rename to tests/ui/parser/macro/macro-bare-trait-object-maybe-trait-bound.rs diff --git a/tests/ui/parser/macro/mbe-dotdotdot-may-not-begin-a-type.rs b/tests/ui/parser/macro/macro-dotdotdot-may-not-begin-a-type.rs similarity index 100% rename from tests/ui/parser/macro/mbe-dotdotdot-may-not-begin-a-type.rs rename to tests/ui/parser/macro/macro-dotdotdot-may-not-begin-a-type.rs diff --git a/tests/ui/parser/macro/mbe_missing_right_paren.rs b/tests/ui/parser/macro/macro-missing-right-paren.rs similarity index 100% rename from tests/ui/parser/macro/mbe_missing_right_paren.rs rename to tests/ui/parser/macro/macro-missing-right-paren.rs diff --git a/tests/ui/parser/macro/mbe_missing_right_paren.stderr b/tests/ui/parser/macro/macro-missing-right-paren.stderr similarity index 82% rename from tests/ui/parser/macro/mbe_missing_right_paren.stderr rename to tests/ui/parser/macro/macro-missing-right-paren.stderr index d45a2e3ab529..285f14830ce6 100644 --- a/tests/ui/parser/macro/mbe_missing_right_paren.stderr +++ b/tests/ui/parser/macro/macro-missing-right-paren.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/mbe_missing_right_paren.rs:3:19 + --> $DIR/macro-missing-right-paren.rs:3:19 | LL | macro_rules! abc(ؼ | - ^ diff --git a/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs similarity index 100% rename from tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs rename to tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs diff --git a/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.stderr b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.stderr similarity index 84% rename from tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.stderr rename to tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.stderr index 56dad5301a4a..bc0e48112b9b 100644 --- a/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.stderr +++ b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.stderr @@ -1,5 +1,5 @@ error: expected identifier, found `]` - --> $DIR/mbe-bare-trait-objects-const-trait-bounds.rs:20:16 + --> $DIR/macro-bare-trait-objects-const-trait-bounds.rs:20:16 | LL | ($Type:ty) => { | -------- while parsing argument for this `ty` macro fragment @@ -8,7 +8,7 @@ LL | check! { [const] Trait } | ^ expected identifier error[E0658]: const trait impls are experimental - --> $DIR/mbe-bare-trait-objects-const-trait-bounds.rs:20:11 + --> $DIR/macro-bare-trait-objects-const-trait-bounds.rs:20:11 | LL | check! { [const] Trait } | ^^^^^ diff --git a/tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.rs b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs similarity index 100% rename from tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.rs rename to tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs diff --git a/tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.stderr b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr similarity index 85% rename from tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.stderr rename to tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr index f4b401b73869..5dd648554c9f 100644 --- a/tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.stderr +++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr @@ -1,5 +1,5 @@ error: ty - --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19 + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:8:19 | LL | ($ty:ty) => { compile_error!("ty"); }; | ^^^^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | demo! { impl const Trait } = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) error: ty - --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19 + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:8:19 | LL | ($ty:ty) => { compile_error!("ty"); }; | ^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | demo! { dyn const Trait } = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: const trait impls are experimental - --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:15:14 + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:15:14 | LL | demo! { impl const Trait } | ^^^^^ @@ -31,7 +31,7 @@ LL | demo! { impl const Trait } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: const trait impls are experimental - --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:18:13 + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:18:13 | LL | demo! { dyn const Trait } | ^^^^^ diff --git a/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs b/tests/ui/traits/const-traits/macro-dyn-const-2015.rs similarity index 100% rename from tests/ui/traits/const-traits/mbe-dyn-const-2015.rs rename to tests/ui/traits/const-traits/macro-dyn-const-2015.rs From 5bbab8967d08362a36ceb5622dd7daac0c5692f4 Mon Sep 17 00:00:00 2001 From: bohan Date: Sat, 5 Jul 2025 18:17:03 +0800 Subject: [PATCH 61/68] distinguish the duplicate item of rpitit --- compiler/rustc_ty_utils/src/assoc.rs | 31 ++++++++++- .../rpitit-duplicate-associated-fn.rs | 30 +++++++++++ .../rpitit-duplicate-associated-fn.stderr | 53 +++++++++++++++++++ 3 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.rs create mode 100644 tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.stderr diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index a65f9b347dc6..2fb3c5ff945a 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -195,12 +195,39 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { if let Some(output) = tcx.hir_get_fn_output(fn_def_id) { - let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); + let def_path_id = |def_id: LocalDefId| tcx.item_name(def_id.to_def_id()); + let def_path_data = def_path_id(fn_def_id); + + let (.., trait_item_refs) = tcx.hir_expect_item(parent_def_id).expect_trait(); + // The purpose of `disambiguator_idx` is to ensure there are + // no duplicate `def_id` in certain cases, such as: + // ``` + // trait Foo { + // fn bar() -> impl Trait; + // fn bar() -> impl Trait; + // // ~~~~~~~~~~ It will generate the same ID if we don’t disambiguate it. + // } + // ``` + let disambiguator_idx = trait_item_refs + .iter() + .take_while(|item| item.id.owner_id.def_id != fn_def_id) + .fold(0, |acc, item| { + if !matches!(item.kind, hir::AssocItemKind::Fn { .. }) { + acc + } else if def_path_id(item.id.owner_id.def_id) == def_path_data { + tcx.def_key(item.id.owner_id.def_id).disambiguated_data.disambiguator + + 1 + } else { + acc + } + }); + + let data = DefPathData::AnonAssocTy(def_path_data); let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, - disambiguator: DisambiguatorState::with(parent_def_id, data, 0), + disambiguator: DisambiguatorState::with(parent_def_id, data, disambiguator_idx), }; visitor.visit_fn_ret_ty(output); tcx.arena.alloc_from_iter( diff --git a/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.rs b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.rs new file mode 100644 index 000000000000..4fddd7c4ac8c --- /dev/null +++ b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.rs @@ -0,0 +1,30 @@ +// issue#140796 + +trait Bar { + fn method() -> impl Sized; + fn method() -> impl Sized; //~ ERROR: the name `method` is defined multiple times +} + +impl Bar for () { //~ ERROR: not all trait items implemented, missing: `method` + fn method() -> impl Sized { + 42 + } + fn method() -> impl Sized { //~ ERROR: duplicate definitions with name `method` + 42 + } +} + +trait T { + fn method() -> impl Sized; +} + +impl T for () { + fn method() -> impl Sized { + 42 + } + fn method() -> impl Sized { //~ ERROR: duplicate definitions with name `method` + 42 + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.stderr b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.stderr new file mode 100644 index 000000000000..b58e8136479c --- /dev/null +++ b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.stderr @@ -0,0 +1,53 @@ +error[E0428]: the name `method` is defined multiple times + --> $DIR/rpitit-duplicate-associated-fn.rs:5:5 + | +LL | fn method() -> impl Sized; + | -------------------------- previous definition of the value `method` here +LL | fn method() -> impl Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `method` redefined here + | + = note: `method` must be defined only once in the value namespace of this trait + +error[E0201]: duplicate definitions with name `method`: + --> $DIR/rpitit-duplicate-associated-fn.rs:12:5 + | +LL | fn method() -> impl Sized; + | -------------------------- item in trait +... +LL | / fn method() -> impl Sized { +LL | | 42 +LL | | } + | |_____- previous definition here +LL | / fn method() -> impl Sized { +LL | | 42 +LL | | } + | |_____^ duplicate definition + +error[E0201]: duplicate definitions with name `method`: + --> $DIR/rpitit-duplicate-associated-fn.rs:25:5 + | +LL | fn method() -> impl Sized; + | -------------------------- item in trait +... +LL | / fn method() -> impl Sized { +LL | | 42 +LL | | } + | |_____- previous definition here +LL | / fn method() -> impl Sized { +LL | | 42 +LL | | } + | |_____^ duplicate definition + +error[E0046]: not all trait items implemented, missing: `method` + --> $DIR/rpitit-duplicate-associated-fn.rs:8:1 + | +LL | fn method() -> impl Sized; + | -------------------------- `method` from trait +... +LL | impl Bar for () { + | ^^^^^^^^^^^^^^^ missing `method` in implementation + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0046, E0201, E0428. +For more information about an error, try `rustc --explain E0046`. From 3fa0ec91d8f3f14f9514d45d93e6fb7fdf1ad89e Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 4 Jul 2025 12:42:33 +0200 Subject: [PATCH 62/68] Rewrite empty attribute lint Signed-off-by: Jonathan Brouwer --- .../src/attributes.rs | 4 +- .../src/encode_cross_crate.rs | 2 +- .../rustc_attr_data_structures/src/lints.rs | 1 + compiler/rustc_attr_parsing/messages.ftl | 4 + .../src/attributes/codegen_attrs.rs | 4 + .../rustc_attr_parsing/src/attributes/repr.rs | 7 +- compiler/rustc_attr_parsing/src/context.rs | 10 ++ compiler/rustc_attr_parsing/src/lints.rs | 6 + .../src/session_diagnostics.rs | 7 + .../src/deriving/generic/mod.rs | 2 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 7 +- compiler/rustc_lint/src/nonstandard_style.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 7 +- compiler/rustc_passes/src/check_attr.rs | 98 ++++-------- src/librustdoc/clean/types.rs | 2 +- .../src/arbitrary_source_item_ordering.rs | 2 +- .../clippy_lints/src/attrs/repr_attributes.rs | 2 +- .../src/default_union_representation.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- tests/pretty/hir-lifetimes.pp | 2 +- tests/pretty/hir-pretty-attr.pp | 2 +- tests/ui/attributes/malformed-attrs.rs | 1 + tests/ui/attributes/malformed-attrs.stderr | 148 ++++++++++-------- tests/ui/empty/empty-attributes.stderr | 38 ++--- tests/ui/repr/repr-empty-packed.stderr | 25 ++- tests/ui/unpretty/exhaustive.hir.stdout | 3 +- 27 files changed, 198 insertions(+), 194 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 6af15da7d08c..ba62be676d46 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -67,8 +67,6 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(Align), - // this one is just so we can emit a lint for it - ReprEmpty, } pub use ReprAttr::*; @@ -304,7 +302,7 @@ pub enum AttributeKind { PubTransparent(Span), /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). - Repr(ThinVec<(ReprAttr, Span)>), + Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span }, /// Represents `#[rustc_layout_scalar_valid_range_end]`. RustcLayoutScalarValidRangeEnd(Box, Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 8ebd38a6ba7e..b109ebbf47bb 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -41,7 +41,7 @@ impl AttributeKind { Optimize(..) => No, PassByValue(..) => Yes, PubTransparent(..) => Yes, - Repr(..) => No, + Repr { .. } => No, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcObjectLifetimeDefault => No, diff --git a/compiler/rustc_attr_data_structures/src/lints.rs b/compiler/rustc_attr_data_structures/src/lints.rs index e34c54c6d323..60ca4d43ce9b 100644 --- a/compiler/rustc_attr_data_structures/src/lints.rs +++ b/compiler/rustc_attr_data_structures/src/lints.rs @@ -12,4 +12,5 @@ pub struct AttributeLint { pub enum AttributeLintKind { UnusedDuplicate { this: Span, other: Span, warning: bool }, IllFormedAttributeInput { suggestions: Vec }, + EmptyAttribute { first_span: Span }, } diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 9ad46a83f508..8a709ea5d20c 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -6,6 +6,10 @@ attr_parsing_deprecated_item_suggestion = .help = add `#![feature(deprecated_suggestion)]` to the crate root .note = see #94785 for more details +attr_parsing_empty_attribute = + unused attribute + .suggestion = remove this attribute + attr_parsing_empty_confusables = expected at least one confusable name attr_parsing_expected_one_cfg_pattern = diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 13f560dff38a..cb3956d46a01 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -298,6 +298,10 @@ impl CombineAttributeParser for TargetFeatureParser { cx.expected_list(cx.attr_span); return features; }; + if list.is_empty() { + cx.warn_empty_attribute(cx.attr_span); + return features; + } for item in list.mixed() { let Some(name_value) = item.meta_item() else { cx.expected_name_value(item.span(), Some(sym::enable)); diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 1c070dc26857..6a45832ed7fd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -23,7 +23,8 @@ pub(crate) struct ReprParser; impl CombineAttributeParser for ReprParser { type Item = (ReprAttr, Span); const PATH: &[Symbol] = &[sym::repr]; - const CONVERT: ConvertFn = |items, _| AttributeKind::Repr(items); + const CONVERT: ConvertFn = + |items, first_span| AttributeKind::Repr { reprs: items, first_span }; // FIXME(jdonszelmann): never used const TEMPLATE: AttributeTemplate = template!(List: "C | Rust | align(...) | packed(...) | | transparent"); @@ -40,8 +41,8 @@ impl CombineAttributeParser for ReprParser { }; if list.is_empty() { - // this is so validation can emit a lint - reprs.push((ReprAttr::ReprEmpty, cx.attr_span)); + cx.warn_empty_attribute(cx.attr_span); + return reprs; } for param in list.mixed() { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 2a01ee58493f..bcd7b024a9ea 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -165,6 +165,7 @@ mod private { #[allow(private_interfaces)] pub trait Stage: Sized + 'static + Sealed { type Id: Copy; + const SHOULD_EMIT_LINTS: bool; fn parsers() -> &'static group_type!(Self); @@ -175,6 +176,7 @@ pub trait Stage: Sized + 'static + Sealed { #[allow(private_interfaces)] impl Stage for Early { type Id = NodeId; + const SHOULD_EMIT_LINTS: bool = false; fn parsers() -> &'static group_type!(Self) { &early::ATTRIBUTE_PARSERS @@ -188,6 +190,7 @@ impl Stage for Early { #[allow(private_interfaces)] impl Stage for Late { type Id = HirId; + const SHOULD_EMIT_LINTS: bool = true; fn parsers() -> &'static group_type!(Self) { &late::ATTRIBUTE_PARSERS @@ -228,6 +231,9 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { /// must be delayed until after HIR is built. This method will take care of the details of /// that. pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { + if !S::SHOULD_EMIT_LINTS { + return; + } let id = self.target_id; (self.emit_lint)(AttributeLint { id, span, kind: lint }); } @@ -409,6 +415,10 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }, }) } + + pub(crate) fn warn_empty_attribute(&mut self, span: Span) { + self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span); + } } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index fee22293b473..e648ca4fdf80 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -28,5 +28,11 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi }, ); } + AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + *id, + *first_span, + session_diagnostics::EmptyAttributeList { attr_span: *first_span }, + ), } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 6145f1e1d3e3..28f6786f37fa 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -473,6 +473,13 @@ pub(crate) struct EmptyConfusables { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_empty_attribute)] +pub(crate) struct EmptyAttributeList { + #[suggestion(code = "", applicability = "machine-applicable")] + pub attr_span: Span, +} + #[derive(Diagnostic)] #[diag(attr_parsing_invalid_alignment_value, code = E0589)] pub(crate) struct InvalidAlignmentValue { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index d201ca196d69..8135f3744f89 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -485,7 +485,7 @@ impl<'a> TraitDef<'a> { Annotatable::Item(item) => { let is_packed = matches!( AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id), - Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..))) + Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..))) ); let newitem = match &item.kind { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 2713ec07f975..be63bb8ac59f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -109,7 +109,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let hir::Attribute::Parsed(p) = attr { match p { - AttributeKind::Repr(reprs) => { + AttributeKind::Repr { reprs, first_span: _ } => { codegen_fn_attrs.alignment = reprs .iter() .filter_map( diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f4fcb13b1a12..bd89d010a3c0 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1395,8 +1395,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { - if let Some(reprs) = - attrs::find_attr!(tcx.get_all_attrs(def.did()), attrs::AttributeKind::Repr(r) => r) + if let Some(reprs) = attrs::find_attr!(tcx.get_all_attrs(def.did()), attrs::AttributeKind::Repr { reprs, .. } => reprs) { for (r, _) in reprs { if let ReprPacked(pack) = r @@ -1619,10 +1618,10 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { if def.variants().is_empty() { attrs::find_attr!( tcx.get_all_attrs(def_id), - attrs::AttributeKind::Repr(rs) => { + attrs::AttributeKind::Repr { reprs, first_span } => { struct_span_code_err!( tcx.dcx(), - rs.first().unwrap().1, + reprs.first().map(|repr| repr.1).unwrap_or(*first_span), E0084, "unsupported representation for zero-variant enum" ) diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 97e627f2eb29..ad7686b3e5b7 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -168,7 +168,7 @@ impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id), - Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC) + Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC) ); if has_repr_c { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f1b16ea54e63..b780b1c5776b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1525,7 +1525,8 @@ impl<'tcx> TyCtxt<'tcx> { field_shuffle_seed ^= user_seed; } - if let Some(reprs) = attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr(r) => r) + if let Some(reprs) = + attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr { reprs, .. } => reprs) { for (r, _) in reprs { flags.insert(match *r { @@ -1566,10 +1567,6 @@ impl<'tcx> TyCtxt<'tcx> { max_align = max_align.max(Some(align)); ReprFlags::empty() } - attr::ReprEmpty => { - /* skip these, they're just for diagnostics */ - ReprFlags::empty() - } }); } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 18b3ab12e2d3..3fa5cdc36bce 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -160,7 +160,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Attribute::Parsed(AttributeKind::DocComment { .. }) => { /* `#[doc]` is actually a lot more than just doc comments, so is checked below*/ } - Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */ + Attribute::Parsed(AttributeKind::Repr { .. }) => { /* handled below this loop and elsewhere */ } Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => { self.check_object_lifetime_default(hir_id); @@ -1948,7 +1948,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // #[repr(foo)] // #[repr(bar, align(8))] // ``` - let reprs = find_attr!(attrs, AttributeKind::Repr(r) => r.as_slice()).unwrap_or(&[]); + let (reprs, first_attr_span) = find_attr!(attrs, AttributeKind::Repr { reprs, first_span } => (reprs.as_slice(), Some(*first_span))).unwrap_or((&[], None)); let mut int_reprs = 0; let mut is_explicit_rust = false; @@ -2045,33 +2045,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> { continue; } } - // FIXME(jdonszelmann): move the diagnostic for unused repr attrs here, I think - // it's a better place for it. - ReprAttr::ReprEmpty => { - // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`) - if item.is_some() { - match target { - Target::Struct | Target::Union | Target::Enum => continue, - Target::Fn | Target::Method(_) => { - self.dcx().emit_err(errors::ReprAlignShouldBeAlign { - span: *repr_span, - item: target.name(), - }); - } - _ => { - self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: *repr_span, - span, - }); - } - } - } - - return; - } }; } + // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`) + if let Some(first_attr_span) = first_attr_span + && reprs.is_empty() + && item.is_some() + { + match target { + Target::Struct | Target::Union | Target::Enum => {} + Target::Fn | Target::Method(_) => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlign { + span: first_attr_span, + item: target.name(), + }); + } + _ => { + self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { + hint_span: first_attr_span, + span, + }); + } + } + return; + } + // Just point at all repr hints if there are any incompatibilities. // This is not ideal, but tracking precisely which ones are at fault is a huge hassle. let hint_spans = reprs.iter().map(|(_, span)| *span); @@ -2324,43 +2323,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option) { - // FIXME(jdonszelmann): deduplicate these checks after more attrs are parsed. This is very - // ugly now but can 100% be removed later. - if let Attribute::Parsed(p) = attr { - match p { - AttributeKind::Repr(reprs) => { - for (r, span) in reprs { - if let ReprAttr::ReprEmpty = r { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - *span, - errors::Unused { - attr_span: *span, - note: errors::UnusedNote::EmptyList { name: sym::repr }, - }, - ); - } - } - return; - } - AttributeKind::TargetFeature(features, span) if features.len() == 0 => { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - *span, - errors::Unused { - attr_span: *span, - note: errors::UnusedNote::EmptyList { name: sym::target_feature }, - }, - ); - return; - } - _ => {} - }; - } - // Warn on useless empty attributes. + // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute` let note = if attr.has_any_name(&[ sym::macro_use, sym::allow, @@ -2576,7 +2540,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) { - if !find_attr!(attrs, AttributeKind::Repr(r) => r.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent)) + if !find_attr!(attrs, AttributeKind::Repr { reprs, .. } => reprs.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent)) .unwrap_or(false) { self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span }); @@ -2852,8 +2816,12 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { ATTRS_TO_CHECK.iter().find(|attr_to_check| attr.has_name(**attr_to_check)) { (attr.span(), *a) - } else if let Attribute::Parsed(AttributeKind::Repr(r)) = attr { - (r.first().unwrap().1, sym::repr) + } else if let Attribute::Parsed(AttributeKind::Repr { + reprs: _, + first_span: first_attr_span, + }) = attr + { + (*first_attr_span, sym::repr) } else { continue; }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index de920469fdca..a05aab22f1e1 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -784,7 +784,7 @@ impl Item { // don't want it it `Item::attrs`. hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None, // We have separate pretty-printing logic for `#[repr(..)]` attributes. - hir::Attribute::Parsed(AttributeKind::Repr(..)) => None, + hir::Attribute::Parsed(AttributeKind::Repr { .. }) => None, // target_feature is special-cased because cargo-semver-checks uses it hir::Attribute::Parsed(AttributeKind::TargetFeature(features, _)) => { let mut output = String::new(); diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index b9ae9afe8510..8b6bfaebbe58 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -266,7 +266,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { .tcx .hir_attrs(item.hir_id()) .iter() - .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr(..)))) + .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr{ .. }))) { // Do not lint items with a `#[repr]` attribute as their layout may be imposed by an external API. return; diff --git a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs index 05d8a8c26d1c..3e8808cec617 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs @@ -9,7 +9,7 @@ use clippy_utils::msrvs::{self, Msrv}; use super::REPR_PACKED_WITHOUT_ABI; pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute], msrv: Msrv) { - if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr(r) => r) { + if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr { reprs, .. } => reprs) { let packed_span = reprs .iter() .find(|(r, _)| matches!(r, ReprAttr::ReprPacked(..))) diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs index 615421f3a40d..9bf2144e445d 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -99,5 +99,5 @@ fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsR fn has_c_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { let attrs = cx.tcx.hir_attrs(hir_id); - find_attr!(attrs, AttributeKind::Repr(r) if r.iter().any(|(x, _)| *x == ReprAttr::ReprC)) + find_attr!(attrs, AttributeKind::Repr { reprs, .. } if reprs.iter().any(|(x, _)| *x == ReprAttr::ReprC)) } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index a8b33418c8c0..c01f0ffaac9a 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1761,7 +1761,7 @@ pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool { } pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { - find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr(..)) + find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr { .. }) } pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool { diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp index 4d1ab9d383bf..58de6d819158 100644 --- a/tests/pretty/hir-lifetimes.pp +++ b/tests/pretty/hir-lifetimes.pp @@ -69,7 +69,7 @@ type Q<'a> = dyn MyTrait<'a, 'a> + 'a; fn h<'b, F>(f: F, y: Foo<'b>) where F: for<'d> MyTrait<'d, 'b> { } // FIXME(?): attr printing is weird -#[attr = Repr([ReprC])] +#[attr = Repr {reprs: [ReprC]}] struct S<'a>(&'a u32); extern "C" { diff --git a/tests/pretty/hir-pretty-attr.pp b/tests/pretty/hir-pretty-attr.pp index d8cc8c424ca5..db7489c12641 100644 --- a/tests/pretty/hir-pretty-attr.pp +++ b/tests/pretty/hir-pretty-attr.pp @@ -6,6 +6,6 @@ extern crate std; //@ pretty-mode:hir //@ pp-exact:hir-pretty-attr.pp -#[attr = Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])] +#[attr = Repr {reprs: [ReprC, ReprPacked(Align(4 bytes)), ReprTransparent]}] struct Example { } diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index a09fe86557d2..aa52de63a609 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -47,6 +47,7 @@ //~^ ERROR malformed #[repr] //~^ ERROR malformed +//~| ERROR is not supported on function items #[rustc_as_ptr = 5] //~^ ERROR malformed #[inline = 5] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 9fe4f45b3ef7..2f7bf50ead5f 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -1,11 +1,11 @@ error: `cfg` is not followed by parentheses - --> $DIR/malformed-attrs.rs:101:1 + --> $DIR/malformed-attrs.rs:102:1 | LL | #[cfg] | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` error: malformed `cfg_attr` attribute input - --> $DIR/malformed-attrs.rs:103:1 + --> $DIR/malformed-attrs.rs:104:1 | LL | #[cfg_attr] | ^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)] | ++++++++++++++++++++++++++++++++++++++++++++ error[E0463]: can't find crate for `wloop` - --> $DIR/malformed-attrs.rs:210:1 + --> $DIR/malformed-attrs.rs:211:1 | LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate @@ -35,19 +35,19 @@ LL | #![windows_subsystem] | ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![windows_subsystem = "windows|console"]` error: malformed `crate_name` attribute input - --> $DIR/malformed-attrs.rs:73:1 + --> $DIR/malformed-attrs.rs:74:1 | LL | #[crate_name] | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` error: malformed `export_stable` attribute input - --> $DIR/malformed-attrs.rs:80:1 + --> $DIR/malformed-attrs.rs:81:1 | LL | #[export_stable = 1] | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_stable]` error: malformed `coverage` attribute input - --> $DIR/malformed-attrs.rs:89:1 + --> $DIR/malformed-attrs.rs:90:1 | LL | #[coverage] | ^^^^^^^^^^^ @@ -60,49 +60,49 @@ LL | #[coverage(on)] | ++++ error: malformed `no_sanitize` attribute input - --> $DIR/malformed-attrs.rs:91:1 + --> $DIR/malformed-attrs.rs:92:1 | LL | #[no_sanitize] | ^^^^^^^^^^^^^^ help: must be of the form: `#[no_sanitize(address, kcfi, memory, thread)]` error: malformed `proc_macro` attribute input - --> $DIR/malformed-attrs.rs:98:1 + --> $DIR/malformed-attrs.rs:99:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` error: malformed `instruction_set` attribute input - --> $DIR/malformed-attrs.rs:105:1 + --> $DIR/malformed-attrs.rs:106:1 | LL | #[instruction_set] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]` error: malformed `patchable_function_entry` attribute input - --> $DIR/malformed-attrs.rs:107:1 + --> $DIR/malformed-attrs.rs:108:1 | LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` error: malformed `coroutine` attribute input - --> $DIR/malformed-attrs.rs:110:5 + --> $DIR/malformed-attrs.rs:111:5 | LL | #[coroutine = 63] || {} | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[coroutine]` error: malformed `proc_macro_attribute` attribute input - --> $DIR/malformed-attrs.rs:115:1 + --> $DIR/malformed-attrs.rs:116:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` error: malformed `proc_macro_derive` attribute input - --> $DIR/malformed-attrs.rs:122:1 + --> $DIR/malformed-attrs.rs:123:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` error: malformed `must_not_suspend` attribute input - --> $DIR/malformed-attrs.rs:131:1 + --> $DIR/malformed-attrs.rs:132:1 | LL | #[must_not_suspend()] | ^^^^^^^^^^^^^^^^^^^^^ @@ -117,109 +117,109 @@ LL + #[must_not_suspend] | error: malformed `cfi_encoding` attribute input - --> $DIR/malformed-attrs.rs:133:1 + --> $DIR/malformed-attrs.rs:134:1 | LL | #[cfi_encoding] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]` error: malformed `type_const` attribute input - --> $DIR/malformed-attrs.rs:142:5 + --> $DIR/malformed-attrs.rs:143:5 | LL | #[type_const = 1] | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[type_const]` error: malformed `marker` attribute input - --> $DIR/malformed-attrs.rs:154:1 + --> $DIR/malformed-attrs.rs:155:1 | LL | #[marker = 3] | ^^^^^^^^^^^^^ help: must be of the form: `#[marker]` error: malformed `fundamental` attribute input - --> $DIR/malformed-attrs.rs:156:1 + --> $DIR/malformed-attrs.rs:157:1 | LL | #[fundamental()] | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[fundamental]` error: malformed `ffi_pure` attribute input - --> $DIR/malformed-attrs.rs:164:5 + --> $DIR/malformed-attrs.rs:165:5 | LL | #[unsafe(ffi_pure = 1)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[ffi_pure]` error: malformed `link_ordinal` attribute input - --> $DIR/malformed-attrs.rs:166:5 + --> $DIR/malformed-attrs.rs:167:5 | LL | #[link_ordinal] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_ordinal(ordinal)]` error: malformed `ffi_const` attribute input - --> $DIR/malformed-attrs.rs:170:5 + --> $DIR/malformed-attrs.rs:171:5 | LL | #[unsafe(ffi_const = 1)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[ffi_const]` error: malformed `linkage` attribute input - --> $DIR/malformed-attrs.rs:172:5 + --> $DIR/malformed-attrs.rs:173:5 | LL | #[linkage] | ^^^^^^^^^^ help: must be of the form: `#[linkage = "external|internal|..."]` error: malformed `allow` attribute input - --> $DIR/malformed-attrs.rs:177:1 + --> $DIR/malformed-attrs.rs:178:1 | LL | #[allow] | ^^^^^^^^ help: must be of the form: `#[allow(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `expect` attribute input - --> $DIR/malformed-attrs.rs:179:1 + --> $DIR/malformed-attrs.rs:180:1 | LL | #[expect] | ^^^^^^^^^ help: must be of the form: `#[expect(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `warn` attribute input - --> $DIR/malformed-attrs.rs:181:1 + --> $DIR/malformed-attrs.rs:182:1 | LL | #[warn] | ^^^^^^^ help: must be of the form: `#[warn(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `deny` attribute input - --> $DIR/malformed-attrs.rs:183:1 + --> $DIR/malformed-attrs.rs:184:1 | LL | #[deny] | ^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `forbid` attribute input - --> $DIR/malformed-attrs.rs:185:1 + --> $DIR/malformed-attrs.rs:186:1 | LL | #[forbid] | ^^^^^^^^^ help: must be of the form: `#[forbid(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `debugger_visualizer` attribute input - --> $DIR/malformed-attrs.rs:187:1 + --> $DIR/malformed-attrs.rs:188:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]` error: malformed `automatically_derived` attribute input - --> $DIR/malformed-attrs.rs:190:1 + --> $DIR/malformed-attrs.rs:191:1 | LL | #[automatically_derived = 18] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[automatically_derived]` error: malformed `thread_local` attribute input - --> $DIR/malformed-attrs.rs:202:1 + --> $DIR/malformed-attrs.rs:203:1 | LL | #[thread_local()] | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]` error: malformed `no_link` attribute input - --> $DIR/malformed-attrs.rs:206:1 + --> $DIR/malformed-attrs.rs:207:1 | LL | #[no_link()] | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]` error: malformed `macro_use` attribute input - --> $DIR/malformed-attrs.rs:208:1 + --> $DIR/malformed-attrs.rs:209:1 | LL | #[macro_use = 1] | ^^^^^^^^^^^^^^^^ @@ -234,7 +234,7 @@ LL + #[macro_use] | error: malformed `macro_export` attribute input - --> $DIR/malformed-attrs.rs:213:1 + --> $DIR/malformed-attrs.rs:214:1 | LL | #[macro_export = 18] | ^^^^^^^^^^^^^^^^^^^^ @@ -249,31 +249,31 @@ LL + #[macro_export] | error: malformed `allow_internal_unsafe` attribute input - --> $DIR/malformed-attrs.rs:215:1 + --> $DIR/malformed-attrs.rs:216:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[allow_internal_unsafe]` error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:98:1 + --> $DIR/malformed-attrs.rs:99:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:115:1 + --> $DIR/malformed-attrs.rs:116:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:122:1 + --> $DIR/malformed-attrs.rs:123:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint - --> $DIR/malformed-attrs.rs:215:1 + --> $DIR/malformed-attrs.rs:216:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ LL | #[doc] = note: `#[deny(ill_formed_attribute_input)]` on by default error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:75:1 + --> $DIR/malformed-attrs.rs:76:1 | LL | #[doc] | ^^^^^^ @@ -301,7 +301,7 @@ LL | #[doc] = note: for more information, see issue #57571 error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-attrs.rs:82:1 + --> $DIR/malformed-attrs.rs:83:1 | LL | #[link] | ^^^^^^^ @@ -310,7 +310,7 @@ LL | #[link] = note: for more information, see issue #57571 error: invalid argument - --> $DIR/malformed-attrs.rs:187:1 + --> $DIR/malformed-attrs.rs:188:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -382,7 +382,7 @@ LL | #[repr] | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | | transparent)]` error[E0565]: malformed `rustc_as_ptr` attribute input - --> $DIR/malformed-attrs.rs:50:1 + --> $DIR/malformed-attrs.rs:51:1 | LL | #[rustc_as_ptr = 5] | ^^^^^^^^^^^^^^^---^ @@ -391,7 +391,7 @@ LL | #[rustc_as_ptr = 5] | help: must be of the form: `#[rustc_as_ptr]` error[E0539]: malformed `align` attribute input - --> $DIR/malformed-attrs.rs:55:1 + --> $DIR/malformed-attrs.rs:56:1 | LL | #[align] | ^^^^^^^^ @@ -400,7 +400,7 @@ LL | #[align] | help: must be of the form: `#[align()]` error[E0539]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:57:1 + --> $DIR/malformed-attrs.rs:58:1 | LL | #[optimize] | ^^^^^^^^^^^ @@ -409,7 +409,7 @@ LL | #[optimize] | help: must be of the form: `#[optimize(size|speed|none)]` error[E0565]: malformed `cold` attribute input - --> $DIR/malformed-attrs.rs:59:1 + --> $DIR/malformed-attrs.rs:60:1 | LL | #[cold = 1] | ^^^^^^^---^ @@ -418,13 +418,13 @@ LL | #[cold = 1] | help: must be of the form: `#[cold]` error: valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` - --> $DIR/malformed-attrs.rs:61:1 + --> $DIR/malformed-attrs.rs:62:1 | LL | #[must_use()] | ^^^^^^^^^^^^^ error[E0565]: malformed `no_mangle` attribute input - --> $DIR/malformed-attrs.rs:63:1 + --> $DIR/malformed-attrs.rs:64:1 | LL | #[no_mangle = 1] | ^^^^^^^^^^^^---^ @@ -433,7 +433,7 @@ LL | #[no_mangle = 1] | help: must be of the form: `#[no_mangle]` error[E0565]: malformed `naked` attribute input - --> $DIR/malformed-attrs.rs:65:1 + --> $DIR/malformed-attrs.rs:66:1 | LL | #[unsafe(naked())] | ^^^^^^^^^^^^^^--^^ @@ -442,7 +442,7 @@ LL | #[unsafe(naked())] | help: must be of the form: `#[naked]` error[E0565]: malformed `track_caller` attribute input - --> $DIR/malformed-attrs.rs:67:1 + --> $DIR/malformed-attrs.rs:68:1 | LL | #[track_caller()] | ^^^^^^^^^^^^^^--^ @@ -451,13 +451,13 @@ LL | #[track_caller()] | help: must be of the form: `#[track_caller]` error[E0539]: malformed `export_name` attribute input - --> $DIR/malformed-attrs.rs:69:1 + --> $DIR/malformed-attrs.rs:70:1 | LL | #[export_name()] | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]` error[E0805]: malformed `used` attribute input - --> $DIR/malformed-attrs.rs:71:1 + --> $DIR/malformed-attrs.rs:72:1 | LL | #[used()] | ^^^^^^--^ @@ -473,7 +473,7 @@ LL + #[used] | error[E0539]: malformed `target_feature` attribute input - --> $DIR/malformed-attrs.rs:78:1 + --> $DIR/malformed-attrs.rs:79:1 | LL | #[target_feature] | ^^^^^^^^^^^^^^^^^ @@ -482,19 +482,19 @@ LL | #[target_feature] | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` error[E0539]: malformed `link_name` attribute input - --> $DIR/malformed-attrs.rs:85:1 + --> $DIR/malformed-attrs.rs:86:1 | LL | #[link_name] | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` error[E0539]: malformed `link_section` attribute input - --> $DIR/malformed-attrs.rs:87:1 + --> $DIR/malformed-attrs.rs:88:1 | LL | #[link_section] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` error[E0565]: malformed `no_implicit_prelude` attribute input - --> $DIR/malformed-attrs.rs:96:1 + --> $DIR/malformed-attrs.rs:97:1 | LL | #[no_implicit_prelude = 23] | ^^^^^^^^^^^^^^^^^^^^^^----^ @@ -503,7 +503,7 @@ LL | #[no_implicit_prelude = 23] | help: must be of the form: `#[no_implicit_prelude]` error[E0539]: malformed `must_use` attribute input - --> $DIR/malformed-attrs.rs:118:1 + --> $DIR/malformed-attrs.rs:119:1 | LL | #[must_use = 1] | ^^^^^^^^^^^^^-^ @@ -520,7 +520,7 @@ LL + #[must_use] | error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input - --> $DIR/malformed-attrs.rs:127:1 + --> $DIR/malformed-attrs.rs:128:1 | LL | #[rustc_layout_scalar_valid_range_start] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -529,7 +529,7 @@ LL | #[rustc_layout_scalar_valid_range_start] | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input - --> $DIR/malformed-attrs.rs:129:1 + --> $DIR/malformed-attrs.rs:130:1 | LL | #[rustc_layout_scalar_valid_range_end] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -538,7 +538,7 @@ LL | #[rustc_layout_scalar_valid_range_end] | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` error[E0565]: malformed `non_exhaustive` attribute input - --> $DIR/malformed-attrs.rs:196:1 + --> $DIR/malformed-attrs.rs:197:1 | LL | #[non_exhaustive = 1] | ^^^^^^^^^^^^^^^^^---^ @@ -558,8 +558,20 @@ LL | | #[coroutine = 63] || {} LL | | } | |_- not a `const fn` +error: `#[repr(align(...))]` is not supported on function items + --> $DIR/malformed-attrs.rs:48:1 + | +LL | #[repr] + | ^^^^^^^ + | +help: use `#[align(...)]` instead + --> $DIR/malformed-attrs.rs:48:1 + | +LL | #[repr] + | ^^^^^^^ + warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/malformed-attrs.rs:148:1 + --> $DIR/malformed-attrs.rs:149:1 | LL | #[diagnostic::do_not_recommend()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -567,7 +579,7 @@ LL | #[diagnostic::do_not_recommend()] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: missing options for `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:137:1 + --> $DIR/malformed-attrs.rs:138:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -575,7 +587,7 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: malformed `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:139:1 + --> $DIR/malformed-attrs.rs:140:1 | LL | #[diagnostic::on_unimplemented = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -583,7 +595,7 @@ LL | #[diagnostic::on_unimplemented = 1] = help: only `message`, `note` and `label` are allowed as options error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` - --> $DIR/malformed-attrs.rs:52:1 + --> $DIR/malformed-attrs.rs:53:1 | LL | #[inline = 5] | ^^^^^^^^^^^^^ @@ -592,7 +604,7 @@ LL | #[inline = 5] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:93:1 + --> $DIR/malformed-attrs.rs:94:1 | LL | #[ignore()] | ^^^^^^^^^^^ @@ -601,7 +613,7 @@ LL | #[ignore()] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:222:1 + --> $DIR/malformed-attrs.rs:223:1 | LL | #[ignore = 1] | ^^^^^^^^^^^^^ @@ -610,7 +622,7 @@ LL | #[ignore = 1] = note: for more information, see issue #57571 error[E0308]: mismatched types - --> $DIR/malformed-attrs.rs:110:23 + --> $DIR/malformed-attrs.rs:111:23 | LL | fn test() { | - help: a return type might be missing here: `-> _` @@ -618,9 +630,9 @@ LL | #[coroutine = 63] || {} | ^^^^^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{coroutine@$DIR/malformed-attrs.rs:110:23: 110:25}` + found coroutine `{coroutine@$DIR/malformed-attrs.rs:111:23: 111:25}` -error: aborting due to 74 previous errors; 3 warnings emitted +error: aborting due to 75 previous errors; 3 warnings emitted Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/empty/empty-attributes.stderr b/tests/ui/empty/empty-attributes.stderr index e86dea10c705..f0be56ddc6aa 100644 --- a/tests/ui/empty/empty-attributes.stderr +++ b/tests/ui/empty/empty-attributes.stderr @@ -1,24 +1,3 @@ -error: unused attribute - --> $DIR/empty-attributes.rs:9:1 - | -LL | #[repr()] - | ^^^^^^^^^ help: remove this attribute - | - = note: attribute `repr` with an empty list has no effect -note: the lint level is defined here - --> $DIR/empty-attributes.rs:1:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - -error: unused attribute - --> $DIR/empty-attributes.rs:12:1 - | -LL | #[target_feature()] - | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | - = note: attribute `target_feature` with an empty list has no effect - error: unused attribute --> $DIR/empty-attributes.rs:2:1 | @@ -26,6 +5,11 @@ LL | #![allow()] | ^^^^^^^^^^^ help: remove this attribute | = note: attribute `allow` with an empty list has no effect +note: the lint level is defined here + --> $DIR/empty-attributes.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ error: unused attribute --> $DIR/empty-attributes.rs:3:1 @@ -67,5 +51,17 @@ LL | #![feature()] | = note: attribute `feature` with an empty list has no effect +error: unused attribute + --> $DIR/empty-attributes.rs:9:1 + | +LL | #[repr()] + | ^^^^^^^^^ help: remove this attribute + +error: unused attribute + --> $DIR/empty-attributes.rs:12:1 + | +LL | #[target_feature()] + | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + error: aborting due to 8 previous errors diff --git a/tests/ui/repr/repr-empty-packed.stderr b/tests/ui/repr/repr-empty-packed.stderr index c824c2998b48..6565b2e8c1dc 100644 --- a/tests/ui/repr/repr-empty-packed.stderr +++ b/tests/ui/repr/repr-empty-packed.stderr @@ -1,16 +1,3 @@ -error: unused attribute - --> $DIR/repr-empty-packed.rs:4:1 - | -LL | #[repr()] - | ^^^^^^^^^ help: remove this attribute - | - = note: attribute `repr` with an empty list has no effect -note: the lint level is defined here - --> $DIR/repr-empty-packed.rs:2:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - error[E0517]: attribute should be applied to a struct or union --> $DIR/repr-empty-packed.rs:5:8 | @@ -22,6 +9,18 @@ LL | | Baz(i32), LL | | } | |_- not a struct or union +error: unused attribute + --> $DIR/repr-empty-packed.rs:4:1 + | +LL | #[repr()] + | ^^^^^^^^^ help: remove this attribute + | +note: the lint level is defined here + --> $DIR/repr-empty-packed.rs:2:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0517`. diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 2b8f3b21396b..0a983b41ef3e 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -64,7 +64,8 @@ mod attributes { #[doc = "outer doc attribute"] #[doc = "macro"] #[allow()] - #[attr = Repr([ReprC])] + #[attr = Repr {reprs: + [ReprC]}] struct Struct; } From 33f2cc7eda7a97e2870f9c60a229211a5f416b7a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 5 Jul 2025 22:21:28 +0200 Subject: [PATCH 63/68] Fix line break after ":" in unpretty attribute print Signed-off-by: Jonathan Brouwer --- compiler/rustc_macros/src/print_attribute.rs | 3 ++- tests/ui/unpretty/deprecated-attr.stdout | 12 +++++------- tests/ui/unpretty/exhaustive.hir.stdout | 3 +-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs index 42d94e72ee94..9023520c7504 100644 --- a/compiler/rustc_macros/src/print_attribute.rs +++ b/compiler/rustc_macros/src/print_attribute.rs @@ -21,7 +21,8 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok __p.word_space(","); } __p.word(#string_name); - __p.word_space(":"); + __p.word(":"); + __p.nbsp(); __printed_anything = true; } #name.print_attribute(__p); diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout index a2b645d00d06..042c2f61bd4c 100644 --- a/tests/ui/unpretty/deprecated-attr.stdout +++ b/tests/ui/unpretty/deprecated-attr.stdout @@ -9,12 +9,12 @@ extern crate std; #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] struct PlainDeprecated; -#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note: -"here's why this is deprecated"}}] +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, +note: "here's why this is deprecated"}}] struct DirectNote; -#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note: -"here's why this is deprecated"}}] +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, +note: "here's why this is deprecated"}}] struct ExplicitNote; #[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), @@ -28,8 +28,6 @@ struct FlippedOrder; fn f() { // Attribute is ignored here (with a warning), but still preserved in HIR - #[attr = Deprecation {deprecation: - Deprecation {since: - Unspecified}}] + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] 0 } diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 0a983b41ef3e..a559d51ed5d6 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -64,8 +64,7 @@ mod attributes { #[doc = "outer doc attribute"] #[doc = "macro"] #[allow()] - #[attr = Repr {reprs: - [ReprC]}] + #[attr = Repr {reprs: [ReprC]}] struct Struct; } From bab9c752e836bb94d87249422d48f8c85b4f41a4 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 5 Jul 2025 22:53:19 +0000 Subject: [PATCH 64/68] Do not unify borrowed locals in CopyProp. --- compiler/rustc_mir_transform/src/ssa.rs | 4 +- ...l.borrow_in_loop.CopyProp.panic-abort.diff | 101 +++++++++ ....borrow_in_loop.CopyProp.panic-unwind.diff | 101 +++++++++ ...d_local.borrowed.CopyProp.panic-abort.diff | 5 +- ..._local.borrowed.CopyProp.panic-unwind.diff | 5 +- tests/mir-opt/copy-prop/borrowed_local.rs | 37 +++- .../write_to_borrowed.main.CopyProp.diff | 5 +- tests/mir-opt/copy-prop/write_to_borrowed.rs | 4 +- ...variant_a-{closure#0}.PreCodegen.after.mir | 192 ++++++++++-------- 9 files changed, 360 insertions(+), 94 deletions(-) create mode 100644 tests/mir-opt/copy-prop/borrowed_local.borrow_in_loop.CopyProp.panic-abort.diff create mode 100644 tests/mir-opt/copy-prop/borrowed_local.borrow_in_loop.CopyProp.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 03b6f9b7ff3b..d3b4b99e9324 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -322,8 +322,8 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) { // visited before `local`, and we just have to copy the representing local. let head = copies[rhs]; - // Do not unify two borrowed locals. - if borrowed_classes.contains(local) && borrowed_classes.contains(head) { + // Do not unify borrowed locals. + if borrowed_classes.contains(local) || borrowed_classes.contains(head) { continue; } diff --git a/tests/mir-opt/copy-prop/borrowed_local.borrow_in_loop.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/borrowed_local.borrow_in_loop.CopyProp.panic-abort.diff new file mode 100644 index 000000000000..8c5e6a9e827a --- /dev/null +++ b/tests/mir-opt/copy-prop/borrowed_local.borrow_in_loop.CopyProp.panic-abort.diff @@ -0,0 +1,101 @@ +- // MIR for `borrow_in_loop` before CopyProp ++ // MIR for `borrow_in_loop` after CopyProp + + fn borrow_in_loop() -> () { + let mut _0: (); + let mut _1: bool; + let _3: bool; + let mut _4: !; + let mut _5: (); + let mut _7: bool; + let mut _9: bool; + let mut _10: bool; + let mut _11: &bool; + let _12: &bool; + let mut _13: bool; + let mut _14: bool; + let mut _15: bool; + let mut _16: !; + scope 1 { + debug c => _1; + let mut _2: &bool; + let mut _17: &bool; + scope 2 { + debug p => _2; + let _6: bool; + scope 3 { + debug a => _6; + let _8: bool; + scope 4 { + debug b => _8; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _17 = const borrow_in_loop::promoted[0]; + _2 = &(*_17); +- StorageLive(_4); + goto -> bb1; + } + + bb1: { +- StorageLive(_6); + StorageLive(_7); + _7 = copy (*_2); + _6 = Not(move _7); + StorageDead(_7); +- StorageLive(_8); + StorageLive(_9); + _9 = copy (*_2); + _8 = Not(move _9); + StorageDead(_9); +- StorageLive(_10); +- _10 = copy _6; +- _1 = move _10; +- StorageDead(_10); ++ _1 = copy _6; + StorageLive(_11); + StorageLive(_12); + _12 = &_1; + _11 = &(*_12); + _2 = move _11; + StorageDead(_11); + StorageDead(_12); + StorageLive(_13); +- StorageLive(_14); +- _14 = copy _6; +- StorageLive(_15); +- _15 = copy _8; +- _13 = Ne(move _14, move _15); ++ _13 = Ne(copy _6, copy _8); + switchInt(move _13) -> [0: bb3, otherwise: bb2]; + } + + bb2: { +- StorageDead(_15); +- StorageDead(_14); + _0 = const (); + StorageDead(_13); +- StorageDead(_8); +- StorageDead(_6); +- StorageDead(_4); + StorageDead(_2); + StorageDead(_1); + return; + } + + bb3: { +- StorageDead(_15); +- StorageDead(_14); +- _5 = const (); + StorageDead(_13); +- StorageDead(_8); +- StorageDead(_6); + goto -> bb1; + } + } + diff --git a/tests/mir-opt/copy-prop/borrowed_local.borrow_in_loop.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/borrowed_local.borrow_in_loop.CopyProp.panic-unwind.diff new file mode 100644 index 000000000000..8c5e6a9e827a --- /dev/null +++ b/tests/mir-opt/copy-prop/borrowed_local.borrow_in_loop.CopyProp.panic-unwind.diff @@ -0,0 +1,101 @@ +- // MIR for `borrow_in_loop` before CopyProp ++ // MIR for `borrow_in_loop` after CopyProp + + fn borrow_in_loop() -> () { + let mut _0: (); + let mut _1: bool; + let _3: bool; + let mut _4: !; + let mut _5: (); + let mut _7: bool; + let mut _9: bool; + let mut _10: bool; + let mut _11: &bool; + let _12: &bool; + let mut _13: bool; + let mut _14: bool; + let mut _15: bool; + let mut _16: !; + scope 1 { + debug c => _1; + let mut _2: &bool; + let mut _17: &bool; + scope 2 { + debug p => _2; + let _6: bool; + scope 3 { + debug a => _6; + let _8: bool; + scope 4 { + debug b => _8; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _17 = const borrow_in_loop::promoted[0]; + _2 = &(*_17); +- StorageLive(_4); + goto -> bb1; + } + + bb1: { +- StorageLive(_6); + StorageLive(_7); + _7 = copy (*_2); + _6 = Not(move _7); + StorageDead(_7); +- StorageLive(_8); + StorageLive(_9); + _9 = copy (*_2); + _8 = Not(move _9); + StorageDead(_9); +- StorageLive(_10); +- _10 = copy _6; +- _1 = move _10; +- StorageDead(_10); ++ _1 = copy _6; + StorageLive(_11); + StorageLive(_12); + _12 = &_1; + _11 = &(*_12); + _2 = move _11; + StorageDead(_11); + StorageDead(_12); + StorageLive(_13); +- StorageLive(_14); +- _14 = copy _6; +- StorageLive(_15); +- _15 = copy _8; +- _13 = Ne(move _14, move _15); ++ _13 = Ne(copy _6, copy _8); + switchInt(move _13) -> [0: bb3, otherwise: bb2]; + } + + bb2: { +- StorageDead(_15); +- StorageDead(_14); + _0 = const (); + StorageDead(_13); +- StorageDead(_8); +- StorageDead(_6); +- StorageDead(_4); + StorageDead(_2); + StorageDead(_1); + return; + } + + bb3: { +- StorageDead(_15); +- StorageDead(_14); +- _5 = const (); + StorageDead(_13); +- StorageDead(_8); +- StorageDead(_6); + goto -> bb1; + } + } + diff --git a/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-abort.diff index 40e8c06f357e..285cd0f65274 100644 --- a/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-abort.diff +++ b/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-abort.diff @@ -7,14 +7,13 @@ let mut _3: &T; bb0: { -- _2 = copy _1; + _2 = copy _1; _3 = &_1; _0 = opaque::<&T>(copy _3) -> [return: bb1, unwind unreachable]; } bb1: { -- _0 = opaque::(copy _2) -> [return: bb2, unwind unreachable]; -+ _0 = opaque::(copy _1) -> [return: bb2, unwind unreachable]; + _0 = opaque::(copy _2) -> [return: bb2, unwind unreachable]; } bb2: { diff --git a/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-unwind.diff index d09c96c0f2ba..f189615ea956 100644 --- a/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-unwind.diff +++ b/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-unwind.diff @@ -7,14 +7,13 @@ let mut _3: &T; bb0: { -- _2 = copy _1; + _2 = copy _1; _3 = &_1; _0 = opaque::<&T>(copy _3) -> [return: bb1, unwind continue]; } bb1: { -- _0 = opaque::(copy _2) -> [return: bb2, unwind continue]; -+ _0 = opaque::(copy _1) -> [return: bb2, unwind continue]; + _0 = opaque::(copy _2) -> [return: bb2, unwind continue]; } bb2: { diff --git a/tests/mir-opt/copy-prop/borrowed_local.rs b/tests/mir-opt/copy-prop/borrowed_local.rs index 8db19fbd3775..68cdc57483a2 100644 --- a/tests/mir-opt/copy-prop/borrowed_local.rs +++ b/tests/mir-opt/copy-prop/borrowed_local.rs @@ -50,10 +50,11 @@ fn compare_address() -> bool { fn borrowed(x: T) -> bool { // CHECK-LABEL: fn borrowed( // CHECK: bb0: { + // CHECK-NEXT: _2 = copy _1; // CHECK-NEXT: _3 = &_1; // CHECK-NEXT: _0 = opaque::<&T>(copy _3) // CHECK: bb1: { - // CHECK-NEXT: _0 = opaque::(copy _1) + // CHECK-NEXT: _0 = opaque::(copy _2) mir! { { let a = x; @@ -94,11 +95,45 @@ fn non_freeze(x: T) -> bool { } } +/// We must not unify a borrowed local with another that may be written-to before the borrow is +/// read again. As we have no aliasing model yet, this means forbidding unifying borrowed locals. +fn borrow_in_loop() { + // CHECK-LABEL: fn borrow_in_loop( + // CHECK: debug c => [[c:_.*]]; + // CHECK: debug p => [[p:_.*]]; + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK-NOT: &[[a]] + // CHECK-NOT: &[[b]] + // CHECK: [[a]] = Not({{.*}}); + // CHECK-NOT: &[[a]] + // CHECK-NOT: &[[b]] + // CHECK: [[b]] = Not({{.*}}); + // CHECK-NOT: &[[a]] + // CHECK-NOT: &[[b]] + // CHECK: &[[c]] + // CHECK-NOT: &[[a]] + // CHECK-NOT: &[[b]] + let mut c; + let mut p = &false; + loop { + let a = !*p; + let b = !*p; + c = a; + p = &c; + if a != b { + return; + } + } +} + fn main() { assert!(!compare_address()); non_freeze(5); + borrow_in_loop(); } // EMIT_MIR borrowed_local.compare_address.CopyProp.diff // EMIT_MIR borrowed_local.borrowed.CopyProp.diff // EMIT_MIR borrowed_local.non_freeze.CopyProp.diff +// EMIT_MIR borrowed_local.borrow_in_loop.CopyProp.diff diff --git a/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff b/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff index eab06b1ba1e7..baa71501047a 100644 --- a/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff +++ b/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff @@ -16,11 +16,10 @@ _3 = const 'b'; _5 = copy _3; _6 = &_3; -- _4 = copy _5; + _4 = copy _5; (*_1) = copy (*_6); _6 = &_5; -- _7 = dump_var::(copy _4) -> [return: bb1, unwind unreachable]; -+ _7 = dump_var::(copy _5) -> [return: bb1, unwind unreachable]; + _7 = dump_var::(copy _4) -> [return: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/copy-prop/write_to_borrowed.rs b/tests/mir-opt/copy-prop/write_to_borrowed.rs index 58809749103e..05aa2fba18d1 100644 --- a/tests/mir-opt/copy-prop/write_to_borrowed.rs +++ b/tests/mir-opt/copy-prop/write_to_borrowed.rs @@ -27,13 +27,13 @@ fn main() { _5 = _3; // CHECK-NEXT: _6 = &_3; _6 = &_3; - // CHECK-NOT: {{_.*}} = {{_.*}}; + // CHECK-NEXT: _4 = copy _5; _4 = _5; // CHECK-NEXT: (*_1) = copy (*_6); *_1 = *_6; // CHECK-NEXT: _6 = &_5; _6 = &_5; - // CHECK-NEXT: _7 = dump_var::(copy _5) + // CHECK-NEXT: _7 = dump_var::(copy _4) Call(_7 = dump_var(_4), ReturnTo(bb1), UnwindUnreachable()) } bb1 = { Return() } diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index cbdd194afd3a..97036745009b 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -10,18 +10,18 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 let mut _8: &&usize; let _9: &usize; let mut _10: &&usize; - let mut _13: bool; - let mut _14: &&usize; - let _15: &usize; + let mut _15: bool; let mut _16: &&usize; - let mut _19: bool; - let mut _20: &&usize; - let _21: &usize; - let mut _22: &&usize; + let _17: &usize; + let mut _18: &&usize; let mut _23: bool; let mut _24: &&usize; let _25: &usize; let mut _26: &&usize; + let mut _29: bool; + let mut _30: &&usize; + let _31: &usize; + let mut _32: &&usize; scope 1 { debug a => _4; debug b => _5; @@ -30,39 +30,47 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 scope 2 (inlined std::cmp::impls::::le) { debug self => _8; debug other => _10; + let mut _11: &usize; + let mut _12: &usize; scope 3 (inlined std::cmp::impls::::le) { - debug self => _4; - debug other => _6; - let mut _11: usize; - let mut _12: usize; + debug self => _11; + debug other => _12; + let mut _13: usize; + let mut _14: usize; } } scope 4 (inlined std::cmp::impls::::le) { - debug self => _14; - debug other => _16; + debug self => _16; + debug other => _18; + let mut _19: &usize; + let mut _20: &usize; scope 5 (inlined std::cmp::impls::::le) { - debug self => _7; - debug other => _5; - let mut _17: usize; - let mut _18: usize; + debug self => _19; + debug other => _20; + let mut _21: usize; + let mut _22: usize; } } scope 6 (inlined std::cmp::impls::::le) { - debug self => _20; - debug other => _22; + debug self => _24; + debug other => _26; + let mut _27: &usize; + let mut _28: &usize; scope 7 (inlined std::cmp::impls::::le) { - debug self => _6; - debug other => _4; + debug self => _27; + debug other => _28; } } scope 8 (inlined std::cmp::impls::::le) { - debug self => _24; - debug other => _26; + debug self => _30; + debug other => _32; + let mut _33: &usize; + let mut _34: &usize; scope 9 (inlined std::cmp::impls::::le) { - debug self => _5; - debug other => _7; - let mut _27: usize; - let mut _28: usize; + debug self => _33; + debug other => _34; + let mut _35: usize; + let mut _36: usize; } } } @@ -73,17 +81,23 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 _5 = &((*_3).1: usize); _6 = &((*_3).2: usize); _7 = &((*_3).3: usize); - StorageLive(_13); + StorageLive(_15); StorageLive(_8); _8 = &_4; StorageLive(_10); StorageLive(_9); _9 = copy _6; _10 = &_9; - _11 = copy ((*_3).0: usize); - _12 = copy ((*_3).2: usize); - _13 = Le(copy _11, copy _12); - switchInt(move _13) -> [0: bb1, otherwise: bb2]; + StorageLive(_11); + StorageLive(_12); + _11 = copy _4; + _12 = copy _6; + _13 = copy ((*_3).0: usize); + _14 = copy ((*_3).2: usize); + _15 = Le(copy _13, copy _14); + StorageDead(_12); + StorageDead(_11); + switchInt(move _15) -> [0: bb1, otherwise: bb2]; } bb1: { @@ -97,89 +111,107 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 StorageDead(_9); StorageDead(_10); StorageDead(_8); - StorageLive(_19); - StorageLive(_14); - _14 = &_7; + StorageLive(_23); StorageLive(_16); - StorageLive(_15); - _15 = copy _5; - _16 = &_15; - StorageLive(_17); - _17 = copy ((*_3).3: usize); + _16 = &_7; StorageLive(_18); - _18 = copy ((*_3).1: usize); - _19 = Le(move _17, move _18); - StorageDead(_18); - StorageDead(_17); - switchInt(move _19) -> [0: bb3, otherwise: bb8]; + StorageLive(_17); + _17 = copy _5; + _18 = &_17; + StorageLive(_19); + StorageLive(_20); + _19 = copy _7; + _20 = copy _5; + StorageLive(_21); + _21 = copy ((*_3).3: usize); + StorageLive(_22); + _22 = copy ((*_3).1: usize); + _23 = Le(move _21, move _22); + StorageDead(_22); + StorageDead(_21); + StorageDead(_20); + StorageDead(_19); + switchInt(move _23) -> [0: bb3, otherwise: bb8]; } bb3: { - StorageDead(_15); + StorageDead(_17); + StorageDead(_18); StorageDead(_16); - StorageDead(_14); goto -> bb4; } bb4: { - StorageLive(_23); - StorageLive(_20); - _20 = &_6; - StorageLive(_22); - StorageLive(_21); - _21 = copy _4; - _22 = &_21; - _23 = Le(copy _12, copy _11); - switchInt(move _23) -> [0: bb5, otherwise: bb6]; + StorageLive(_29); + StorageLive(_24); + _24 = &_6; + StorageLive(_26); + StorageLive(_25); + _25 = copy _4; + _26 = &_25; + StorageLive(_27); + StorageLive(_28); + _27 = copy _6; + _28 = copy _4; + _29 = Le(copy _14, copy _13); + StorageDead(_28); + StorageDead(_27); + switchInt(move _29) -> [0: bb5, otherwise: bb6]; } bb5: { - StorageDead(_21); - StorageDead(_22); - StorageDead(_20); + StorageDead(_25); + StorageDead(_26); + StorageDead(_24); _0 = const false; goto -> bb7; } bb6: { - StorageDead(_21); - StorageDead(_22); - StorageDead(_20); - StorageLive(_24); - _24 = &_5; - StorageLive(_26); - StorageLive(_25); - _25 = copy _7; - _26 = &_25; - StorageLive(_27); - _27 = copy ((*_3).1: usize); - StorageLive(_28); - _28 = copy ((*_3).3: usize); - _0 = Le(move _27, move _28); - StorageDead(_28); - StorageDead(_27); StorageDead(_25); StorageDead(_26); StorageDead(_24); + StorageLive(_30); + _30 = &_5; + StorageLive(_32); + StorageLive(_31); + _31 = copy _7; + _32 = &_31; + StorageLive(_33); + StorageLive(_34); + _33 = copy _5; + _34 = copy _7; + StorageLive(_35); + _35 = copy ((*_3).1: usize); + StorageLive(_36); + _36 = copy ((*_3).3: usize); + _0 = Le(move _35, move _36); + StorageDead(_36); + StorageDead(_35); + StorageDead(_34); + StorageDead(_33); + StorageDead(_31); + StorageDead(_32); + StorageDead(_30); goto -> bb7; } bb7: { - StorageDead(_23); + StorageDead(_29); goto -> bb9; } bb8: { - StorageDead(_15); + StorageDead(_17); + StorageDead(_18); StorageDead(_16); - StorageDead(_14); _0 = const true; goto -> bb9; } bb9: { - StorageDead(_19); - StorageDead(_13); + StorageDead(_23); + StorageDead(_15); return; } } From f24ee2c9b15dc3734e9ebd74ba0563a1e6c545db Mon Sep 17 00:00:00 2001 From: dvdsk Date: Sat, 31 May 2025 15:33:46 +0200 Subject: [PATCH 65/68] sleep_until: use clock_nanosleep where possible Using clock nanosleep leads to more accurate sleep times on platforms where it is supported. To enable using clock_nanosleep this makes `sleep_until` platform specific. That unfortunatly requires identical placeholder implementations for the other platforms (windows/mac/wasm etc). we will land platform specific implementations for those later. See the `sleep_until` tracking issue. This requires an accessors for the Instant type. As that accessor is only used on the platforms that have clock_nanosleep it is marked as allow_unused. 32bit time_t targets do not use clock_nanosleep atm, they instead rely on the same placeholder as the other platforms. We could make them use clock_nanosleep too in the future using `__clock_nanosleep_time64`. __clock_nanosleep_time64 is documented at: https://www.gnu.org/software/libc/manual/html_node/64_002dbit-time-symbol-handling.html --- library/std/src/sys/pal/hermit/thread.rs | 10 ++- library/std/src/sys/pal/itron/thread.rs | 10 ++- library/std/src/sys/pal/sgx/thread.rs | 10 ++- library/std/src/sys/pal/teeos/thread.rs | 10 ++- library/std/src/sys/pal/uefi/thread.rs | 10 ++- library/std/src/sys/pal/unix/thread.rs | 71 ++++++++++++++++++- library/std/src/sys/pal/unix/time.rs | 18 +++-- library/std/src/sys/pal/unsupported/thread.rs | 6 +- library/std/src/sys/pal/wasi/thread.rs | 10 ++- .../std/src/sys/pal/wasm/atomics/thread.rs | 10 ++- library/std/src/sys/pal/windows/thread.rs | 10 ++- library/std/src/sys/pal/xous/thread.rs | 10 ++- library/std/src/thread/mod.rs | 35 ++++++--- library/std/src/time.rs | 9 +++ library/std/tests/thread.rs | 14 +++- 15 files changed, 218 insertions(+), 25 deletions(-) diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index bb68a824fc31..9bc5a16b8002 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -4,7 +4,7 @@ use super::hermit_abi; use crate::ffi::CStr; use crate::mem::ManuallyDrop; use crate::num::NonZero; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{io, ptr}; pub type Tid = hermit_abi::Tid; @@ -86,6 +86,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { unsafe { let _ = hermit_abi::join(self.tid); diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs index a974f4f17ae6..813e1cbcd58f 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/pal/itron/thread.rs @@ -10,7 +10,7 @@ use crate::mem::ManuallyDrop; use crate::num::NonZero; use crate::ptr::NonNull; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{hint, io}; pub struct Thread { @@ -205,6 +205,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { // Safety: `ThreadInner` is alive at this point let inner = unsafe { self.p_inner.as_ref() }; diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs index 219ef1b7a989..85f6dcd96b4a 100644 --- a/library/std/src/sys/pal/sgx/thread.rs +++ b/library/std/src/sys/pal/sgx/thread.rs @@ -5,7 +5,7 @@ use super::unsupported; use crate::ffi::CStr; use crate::io; use crate::num::NonZero; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread(task_queue::JoinHandle); @@ -132,6 +132,14 @@ impl Thread { usercalls::wait_timeout(0, dur, || true); } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { self.0.wait(); } diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index e3b4908f8586..b9cdc7a2a58b 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -2,7 +2,7 @@ use crate::ffi::CStr; use crate::mem::{self, ManuallyDrop}; use crate::num::NonZero; use crate::sys::os; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{cmp, io, ptr}; pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024; @@ -109,6 +109,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + /// must join, because no pthread_detach supported pub fn join(self) { let id = self.into_id(); diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs index 7d4006ff4b2f..e4776ec42fbb 100644 --- a/library/std/src/sys/pal/uefi/thread.rs +++ b/library/std/src/sys/pal/uefi/thread.rs @@ -3,7 +3,7 @@ use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::ptr::NonNull; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread(!); @@ -39,6 +39,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { self.0 } diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index d8b189413f4a..3e4585c7187d 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -6,7 +6,7 @@ use crate::sys::weak::dlsym; #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))] use crate::sys::weak::weak; use crate::sys::{os, stack_overflow}; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{cmp, io, ptr}; #[cfg(not(any( target_os = "l4re", @@ -296,6 +296,75 @@ impl Thread { } } + // Any unix that has clock_nanosleep + #[cfg(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos", + target_os = "dragonfly", + target_os = "hurd", + target_os = "fuchsia", + target_os = "vxworks", + ))] + pub fn sleep_until(deadline: Instant) { + let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else { + // The deadline is further in the future then can be passed to + // clock_nanosleep. We have to use Self::sleep instead. This might + // happen on 32 bit platforms, especially closer to 2038. + let now = Instant::now(); + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + return; + }; + + unsafe { + // When we get interrupted (res = EINTR) call clock_nanosleep again + loop { + let res = libc::clock_nanosleep( + super::time::Instant::CLOCK_ID, + libc::TIMER_ABSTIME, + &ts, + core::ptr::null_mut(), // not required with TIMER_ABSTIME + ); + + if res == 0 { + break; + } else { + assert_eq!( + res, + libc::EINTR, + "timespec is in range, + clockid is valid and kernel should support it" + ); + } + } + } + } + + // Any unix that does not have clock_nanosleep + #[cfg(not(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos", + target_os = "dragonfly", + target_os = "hurd", + target_os = "fuchsia", + target_os = "vxworks", + )))] + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { let id = self.into_id(); let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 0074d7674741..bd7f74fea6a9 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -261,6 +261,10 @@ pub struct Instant { } impl Instant { + #[cfg(target_vendor = "apple")] + pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW; + #[cfg(not(target_vendor = "apple"))] + pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC; pub fn now() -> Instant { // https://www.manpagez.com/man/3/clock_gettime/ // @@ -273,11 +277,7 @@ impl Instant { // // Instant on macos was historically implemented using mach_absolute_time; // we preserve this value domain out of an abundance of caution. - #[cfg(target_vendor = "apple")] - const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW; - #[cfg(not(target_vendor = "apple"))] - const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC; - Instant { t: Timespec::now(clock_id) } + Instant { t: Timespec::now(Self::CLOCK_ID) } } pub fn checked_sub_instant(&self, other: &Instant) -> Option { @@ -291,6 +291,14 @@ impl Instant { pub fn checked_sub_duration(&self, other: &Duration) -> Option { Some(Instant { t: self.t.checked_sub_duration(other)? }) } + + #[cfg_attr( + not(target_os = "linux"), + allow(unused, reason = "needed by the `sleep_until` on some unix platforms") + )] + pub(crate) fn into_timespec(self) -> Timespec { + self.t + } } impl fmt::Debug for Instant { diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs index 89f8bad7026e..8a3119fa292d 100644 --- a/library/std/src/sys/pal/unsupported/thread.rs +++ b/library/std/src/sys/pal/unsupported/thread.rs @@ -2,7 +2,7 @@ use super::unsupported; use crate::ffi::CStr; use crate::io; use crate::num::NonZero; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread(!); @@ -26,6 +26,10 @@ impl Thread { panic!("can't sleep"); } + pub fn sleep_until(_deadline: Instant) { + panic!("can't sleep"); + } + pub fn join(self) { self.0 } diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index cc569bb3daf6..5f21a553673a 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -2,7 +2,7 @@ use crate::ffi::CStr; use crate::num::NonZero; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{io, mem}; cfg_if::cfg_if! { @@ -171,6 +171,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { cfg_if::cfg_if! { if #[cfg(target_feature = "atomics")] { diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs index dd5aff391fd8..44ce3eab109f 100644 --- a/library/std/src/sys/pal/wasm/atomics/thread.rs +++ b/library/std/src/sys/pal/wasm/atomics/thread.rs @@ -2,7 +2,7 @@ use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::sys::unsupported; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread(!); @@ -41,6 +41,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) {} } diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 45e52cf4d047..147851717553 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -8,7 +8,7 @@ use crate::os::windows::io::{AsRawHandle, HandleOrNull}; use crate::sys::handle::Handle; use crate::sys::{c, stack_overflow}; use crate::sys_common::FromInner; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{io, ptr}; pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; @@ -106,6 +106,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn handle(&self) -> &Handle { &self.handle } diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs index 0ebb46dc19fa..1b344e984dc3 100644 --- a/library/std/src/sys/pal/xous/thread.rs +++ b/library/std/src/sys/pal/xous/thread.rs @@ -8,7 +8,7 @@ use crate::os::xous::ffi::{ map_memory, update_memory_flags, }; use crate::os::xous::services::{TicktimerScalar, ticktimer_server}; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread { tid: ThreadId, @@ -128,6 +128,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { join_thread(self.tid).unwrap(); } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 26b2fb447243..6075173db47f 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -897,8 +897,31 @@ pub fn sleep(dur: Duration) { /// /// # Platform-specific behavior /// -/// This function uses [`sleep`] internally, see its platform-specific behavior. +/// In most cases this function will call an OS specific function. Where that +/// is not supported [`sleep`] is used. Those platforms are referred to as other +/// in the table below. /// +/// # Underlying System calls +/// +/// The following system calls are [currently] being used: +/// +/// | Platform | System call | +/// |-----------|----------------------------------------------------------------------| +/// | Linux | [clock_nanosleep] (Monotonic clock) | +/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock)] | +/// | Android | [clock_nanosleep] (Monotonic Clock)] | +/// | Solaris | [clock_nanosleep] (Monotonic Clock)] | +/// | Illumos | [clock_nanosleep] (Monotonic Clock)] | +/// | Dragonfly | [clock_nanosleep] (Monotonic Clock)] | +/// | Hurd | [clock_nanosleep] (Monotonic Clock)] | +/// | Fuchsia | [clock_nanosleep] (Monotonic Clock)] | +/// | Vxworks | [clock_nanosleep] (Monotonic Clock)] | +/// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself | +/// +/// [currently]: crate::io#platform-specific-behavior +/// [clock_nanosleep]: https://linux.die.net/man/3/clock_nanosleep +/// +/// **Disclaimer:** These system calls might change over time. /// /// # Examples /// @@ -923,9 +946,9 @@ pub fn sleep(dur: Duration) { /// } /// ``` /// -/// A slow api we must not call too fast and which takes a few +/// A slow API we must not call too fast and which takes a few /// tries before succeeding. By using `sleep_until` the time the -/// api call takes does not influence when we retry or when we give up +/// API call takes does not influence when we retry or when we give up /// /// ```no_run /// #![feature(thread_sleep_until)] @@ -960,11 +983,7 @@ pub fn sleep(dur: Duration) { /// ``` #[unstable(feature = "thread_sleep_until", issue = "113752")] pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - sleep(delay); - } + imp::Thread::sleep_until(deadline) } /// Used to ensure that `park` and `park_timeout` do not unwind, as that can diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 03af35e809c9..979f51ad3a39 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -407,6 +407,15 @@ impl Instant { pub fn checked_sub(&self, duration: Duration) -> Option { self.0.checked_sub_duration(&duration).map(Instant) } + + // Used by platform specific `sleep_until` implementations such as the one used on Linux. + #[cfg_attr( + not(target_os = "linux"), + allow(unused, reason = "not every platform has a specific `sleep_until`") + )] + pub(crate) fn into_inner(self) -> time::Instant { + self.0 + } } #[stable(feature = "time2", since = "1.8.0")] diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index 1bb17d149fa1..32561dd6ab6a 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -1,7 +1,8 @@ +#![feature(thread_sleep_until)] use std::cell::{Cell, RefCell}; use std::sync::{Arc, Mutex}; use std::thread; -use std::time::Duration; +use std::time::{Duration, Instant}; #[test] #[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads @@ -17,6 +18,17 @@ fn sleep_very_long() { assert_eq!(*finished.lock().unwrap(), false); } +#[test] +fn sleep_until() { + let now = Instant::now(); + let period = Duration::from_millis(100); + let deadline = now + period; + thread::sleep_until(deadline); + + let elapsed = now.elapsed(); + assert!(elapsed >= period); +} + #[test] fn thread_local_containing_const_statements() { // This exercises the `const $init:block` cases of the thread_local macro. From 61cf174dcea9e606d7c3e89c2df69e22ae888728 Mon Sep 17 00:00:00 2001 From: dvdsk Date: Thu, 3 Jul 2025 17:22:37 +0200 Subject: [PATCH 66/68] sleep_until: add clock_nanosleep support to Miri The clock_nanosleep support is there to allow code using `sleep_until` to run under Miri. Therefore the implementation is minimal. - Only the clocks REALTIME and MONOTONIC are supported. The first is supported simply because it was trivial to add not because it was needed for sleep_until. - The only supported flag combinations are no flags or TIMER_ABSTIME only. If an unsupported flag combination or clock is passed in this throws unsupported. --- library/std/src/sys/pal/unix/thread.rs | 1 + src/tools/miri/src/shims/time.rs | 57 +++++++++ .../miri/src/shims/unix/foreign_items.rs | 11 ++ .../miri/tests/pass-dep/libc/libc-time.rs | 114 ++++++++++++++++++ src/tools/miri/tests/pass/shims/time.rs | 10 ++ 5 files changed, 193 insertions(+) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 3e4585c7187d..53f0d1eeda5b 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -297,6 +297,7 @@ impl Thread { } // Any unix that has clock_nanosleep + // If this list changes update the MIRI chock_nanosleep shim #[cfg(any( target_os = "freebsd", target_os = "netbsd", diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 28f4ca5bb1b7..4d21fd248c89 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -362,6 +362,63 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(0)) } + fn clock_nanosleep( + &mut self, + clock_id: &OpTy<'tcx>, + flags: &OpTy<'tcx>, + timespec: &OpTy<'tcx>, + rem: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let clockid_t_size = this.libc_ty_layout("clockid_t").size; + + let clock_id = this.read_scalar(clock_id)?.to_int(clockid_t_size)?; + let timespec = this.deref_pointer_as(timespec, this.libc_ty_layout("timespec"))?; + let flags = this.read_scalar(flags)?.to_i32()?; + let _rem = this.read_pointer(rem)?; // Signal handlers are not supported, so rem will never be written to. + + // The standard lib through sleep_until only needs CLOCK_MONOTONIC + if clock_id != this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)? { + throw_unsup_format!("clock_nanosleep: only CLOCK_MONOTONIC is supported"); + } + + let duration = match this.read_timespec(×pec)? { + Some(duration) => duration, + None => { + return this.set_last_error_and_return_i32(LibcError("EINVAL")); + } + }; + + let timeout_anchor = if flags == 0 { + // No flags set, the timespec should be interperted as a duration + // to sleep for + TimeoutAnchor::Relative + } else if flags == this.eval_libc_i32("TIMER_ABSTIME") { + // Only flag TIMER_ABSTIME set, the timespec should be interperted as + // an absolute time. + TimeoutAnchor::Absolute + } else { + // The standard lib (through `sleep_until`) only needs TIMER_ABSTIME + throw_unsup_format!( + "`clock_nanosleep` unsupported flags {flags}, only no flags or \ + TIMER_ABSTIME is supported" + ); + }; + + this.block_thread( + BlockReason::Sleep, + Some((TimeoutClock::Monotonic, timeout_anchor, duration)), + callback!( + @capture<'tcx> {} + |_this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::TimedOut); + interp_ok(()) + } + ), + ); + interp_ok(Scalar::from_i32(0)) + } + #[allow(non_snake_case)] fn Sleep(&mut self, timeout: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index b3c58397a02b..5f3778d967e7 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -967,6 +967,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.nanosleep(req, rem)?; this.write_scalar(result, dest)?; } + "clock_nanosleep" => { + // Currently this function does not exist on all Unixes, e.g. on macOS. + this.check_target_os( + &["freebsd", "linux", "android", "solaris", "illumos"], + link_name, + )?; + let [clock_id, flags, req, rem] = + this.check_shim(abi, CanonAbi::C, link_name, args)?; + let result = this.clock_nanosleep(clock_id, flags, req, rem)?; + this.write_scalar(result, dest)?; + } "sched_getaffinity" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&["linux", "freebsd", "android"], link_name)?; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs index e53201e0bc5d..e8957846ad51 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -1,5 +1,6 @@ //@ignore-target: windows # no libc time APIs on Windows //@compile-flags: -Zmiri-disable-isolation +use std::time::{Duration, Instant}; use std::{env, mem, ptr}; fn main() { @@ -20,6 +21,19 @@ fn main() { test_localtime_r_future_32b(); #[cfg(target_pointer_width = "64")] test_localtime_r_future_64b(); + + test_nanosleep(); + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos" + ))] + { + test_clock_nanosleep::absolute(); + test_clock_nanosleep::relative(); + } } /// Tests whether clock support exists at all @@ -315,3 +329,103 @@ fn test_localtime_r_multiple_calls_deduplication() { NUM_CALLS - 1 ); } + +fn test_nanosleep() { + let start_test_sleep = Instant::now(); + let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + let remainder = ptr::null_mut::(); + let is_error = unsafe { libc::nanosleep(&duration_zero, remainder) }; + assert_eq!(is_error, 0); + assert!(start_test_sleep.elapsed() < Duration::from_millis(10)); + + let start_test_sleep = Instant::now(); + let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 }; + let remainder = ptr::null_mut::(); + let is_error = unsafe { libc::nanosleep(&duration_100_millis, remainder) }; + assert_eq!(is_error, 0); + assert!(start_test_sleep.elapsed() > Duration::from_millis(100)); +} + +#[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos" +))] +mod test_clock_nanosleep { + use super::*; + + /// Helper function used to create an instant in the future + fn add_100_millis(mut ts: libc::timespec) -> libc::timespec { + // While tv_nsec has type `c_long` tv_sec has type `time_t`. These might + // end up as different types (for example: like i32 and i64). + const SECOND: libc::c_long = 1_000_000_000; + ts.tv_nsec += SECOND / 10; + // If this pushes tv_nsec to SECOND or higher, we need to overflow to tv_sec. + ts.tv_sec += (ts.tv_nsec / SECOND) as libc::time_t; + ts.tv_nsec %= SECOND; + ts + } + + /// Helper function to get the current time for testing relative sleeps + fn timespec_now(clock: libc::clockid_t) -> libc::timespec { + let mut timespec = mem::MaybeUninit::::uninit(); + let is_error = unsafe { libc::clock_gettime(clock, timespec.as_mut_ptr()) }; + assert_eq!(is_error, 0); + unsafe { timespec.assume_init() } + } + + pub fn absolute() { + let start_test_sleep = Instant::now(); + let before_start = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + let remainder = ptr::null_mut::(); + let error = unsafe { + // this will not sleep since unix time zero is in the past + libc::clock_nanosleep( + libc::CLOCK_MONOTONIC, + libc::TIMER_ABSTIME, + &before_start, + remainder, + ) + }; + assert_eq!(error, 0); + assert!(start_test_sleep.elapsed() < Duration::from_millis(10)); + + let start_test_sleep = Instant::now(); + let hunderd_millis_after_start = add_100_millis(timespec_now(libc::CLOCK_MONOTONIC)); + let remainder = ptr::null_mut::(); + let error = unsafe { + libc::clock_nanosleep( + libc::CLOCK_MONOTONIC, + libc::TIMER_ABSTIME, + &hunderd_millis_after_start, + remainder, + ) + }; + assert_eq!(error, 0); + assert!(start_test_sleep.elapsed() > Duration::from_millis(100)); + } + + pub fn relative() { + const NO_FLAGS: i32 = 0; + + let start_test_sleep = Instant::now(); + let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + let remainder = ptr::null_mut::(); + let error = unsafe { + libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_zero, remainder) + }; + assert_eq!(error, 0); + assert!(start_test_sleep.elapsed() < Duration::from_millis(10)); + + let start_test_sleep = Instant::now(); + let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 }; + let remainder = ptr::null_mut::(); + let error = unsafe { + libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_100_millis, remainder) + }; + assert_eq!(error, 0); + assert!(start_test_sleep.elapsed() > Duration::from_millis(100)); + } +} diff --git a/src/tools/miri/tests/pass/shims/time.rs b/src/tools/miri/tests/pass/shims/time.rs index 226f04ade0f4..ef0b400f1a71 100644 --- a/src/tools/miri/tests/pass/shims/time.rs +++ b/src/tools/miri/tests/pass/shims/time.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation +#![feature(thread_sleep_until)] use std::time::{Duration, Instant, SystemTime}; @@ -15,6 +16,14 @@ fn test_sleep() { assert!((after - before).as_millis() >= 100); } +fn test_sleep_until() { + let before = Instant::now(); + let hunderd_millis_after_start = before + Duration::from_millis(100); + std::thread::sleep_until(hunderd_millis_after_start); + let after = Instant::now(); + assert!((after - before).as_millis() >= 100); +} + fn main() { // Check `SystemTime`. let now1 = SystemTime::now(); @@ -49,4 +58,5 @@ fn main() { duration_sanity(diff); test_sleep(); + test_sleep_until(); } From b1fdb4bdc8818aced53e46a34a3e92cfcfcc8ece Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 6 Jul 2025 16:11:43 +0000 Subject: [PATCH 67/68] Do not optimize stable-mir ui tests. --- tests/ui/stable-mir-print/async-closure.rs | 2 +- .../ui/stable-mir-print/async-closure.stdout | 75 ++- tests/ui/stable-mir-print/basic_function.rs | 2 +- .../ui/stable-mir-print/basic_function.stdout | 21 +- tests/ui/stable-mir-print/operands.rs | 2 +- tests/ui/stable-mir-print/operands.stdout | 559 +++++++++++++----- 6 files changed, 472 insertions(+), 189 deletions(-) diff --git a/tests/ui/stable-mir-print/async-closure.rs b/tests/ui/stable-mir-print/async-closure.rs index 7da532a359f9..80f96e09cfc7 100644 --- a/tests/ui/stable-mir-print/async-closure.rs +++ b/tests/ui/stable-mir-print/async-closure.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort +//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort -Zmir-opt-level=0 //@ check-pass //@ only-x86_64 //@ edition: 2024 diff --git a/tests/ui/stable-mir-print/async-closure.stdout b/tests/ui/stable-mir-print/async-closure.stdout index 12e7a5530ace..318112997220 100644 --- a/tests/ui/stable-mir-print/async-closure.stdout +++ b/tests/ui/stable-mir-print/async-closure.stdout @@ -8,19 +8,30 @@ fn foo() -> () { debug y => _1; debug x => _2; bb0: { + StorageLive(_1); _1 = 0_i32; + StorageLive(_2); + StorageLive(_3); _3 = &_1; _2 = {coroutine-closure@$DIR/async-closure.rs:9:13: 9:21}(move _3); + StorageDead(_3); + _0 = (); + StorageDead(_2); + StorageDead(_1); return; } } fn foo::{closure#0}(_1: &{async closure@$DIR/async-closure.rs:9:13: 9:21}) -> {async closure body@$DIR/async-closure.rs:9:22: 11:6} { let mut _0: {async closure body@$DIR/async-closure.rs:9:22: 11:6}; let mut _2: &i32; + let mut _3: &i32; debug y => (*((*_1).0: &i32)); bb0: { - _2 = CopyForDeref(((*_1).0: &i32)); - _0 = {coroutine@$DIR/async-closure.rs:9:22: 11:6}(_2); + StorageLive(_2); + _3 = CopyForDeref(((*_1).0: &i32)); + _2 = &(*_3); + _0 = {coroutine@$DIR/async-closure.rs:9:22: 11:6}(move _2); + StorageDead(_2); return; } } @@ -28,25 +39,31 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo let mut _0: Poll<()>; let _3: i32; let mut _4: &i32; - let mut _5: u32; - let mut _6: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; - let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + let mut _5: (); + let mut _6: &mut Context<'_>; + let mut _7: u32; let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; - debug _task_context => _2; + let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + debug _task_context => _6; debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32)); debug y => _3; bb0: { - _6 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - _5 = discriminant((*_6)); - switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb3]; + _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _7 = discriminant((*_8)); + switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3]; } bb1: { - _7 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - _4 = CopyForDeref(((*_7).0: &i32)); + _6 = move _2; + StorageLive(_3); + _9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _4 = CopyForDeref(((*_9).0: &i32)); _3 = (*_4); - _0 = std::task::Poll::Ready(()); - _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - discriminant((*_8) = 1; + _5 = (); + StorageDead(_3); + _0 = std::task::Poll::Ready(move _5); + _10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + discriminant((*_10) = 1; return; } bb2: { @@ -60,25 +77,31 @@ fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-c let mut _0: Poll<()>; let _3: i32; let mut _4: &i32; - let mut _5: u32; - let mut _6: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; - let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + let mut _5: (); + let mut _6: &mut Context<'_>; + let mut _7: u32; let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; - debug _task_context => _2; + let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + debug _task_context => _6; debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32)); debug y => _3; bb0: { - _6 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - _5 = discriminant((*_6)); - switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb3]; + _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _7 = discriminant((*_8)); + switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3]; } bb1: { - _7 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - _4 = CopyForDeref(((*_7).0: &i32)); + _6 = move _2; + StorageLive(_3); + _9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _4 = CopyForDeref(((*_9).0: &i32)); _3 = (*_4); - _0 = std::task::Poll::Ready(()); - _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - discriminant((*_8) = 1; + _5 = (); + StorageDead(_3); + _0 = std::task::Poll::Ready(move _5); + _10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + discriminant((*_10) = 1; return; } bb2: { diff --git a/tests/ui/stable-mir-print/basic_function.rs b/tests/ui/stable-mir-print/basic_function.rs index 5f582ece6fb4..21469c61f722 100644 --- a/tests/ui/stable-mir-print/basic_function.rs +++ b/tests/ui/stable-mir-print/basic_function.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z unpretty=stable-mir -Z mir-opt-level=3 +//@ compile-flags: -Z unpretty=stable-mir -Zmir-opt-level=0 //@ check-pass //@ only-x86_64 //@ needs-unwind unwind edges are different with panic=abort diff --git a/tests/ui/stable-mir-print/basic_function.stdout b/tests/ui/stable-mir-print/basic_function.stdout index 76288c2aa49f..319d9c1dc699 100644 --- a/tests/ui/stable-mir-print/basic_function.stdout +++ b/tests/ui/stable-mir-print/basic_function.stdout @@ -2,14 +2,18 @@ // If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir. fn foo(_1: i32) -> i32 { let mut _0: i32; - let mut _2: (i32, bool); + let mut _2: i32; + let mut _3: (i32, bool); debug i => _1; bb0: { - _2 = CheckedAdd(_1, 1_i32); - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, 1_i32) -> [success: bb1, unwind continue]; + StorageLive(_2); + _2 = _1; + _3 = CheckedAdd(_2, 1_i32); + assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, 1_i32) -> [success: bb1, unwind continue]; } bb1: { - _0 = move (_2.0: i32); + _0 = move (_3.0: i32); + StorageDead(_2); return; } } @@ -22,15 +26,23 @@ fn bar(_1: &mut Vec) -> Vec { debug vec => _1; debug new_vec => _2; bb0: { + StorageLive(_2); + StorageLive(_3); _3 = &(*_1); _2 = as Clone>::clone(move _3) -> [return: bb1, unwind continue]; } bb1: { + StorageDead(_3); + StorageLive(_4); + StorageLive(_5); _5 = &mut _2; _4 = Vec::::push(move _5, 1_i32) -> [return: bb2, unwind: bb3]; } bb2: { + StorageDead(_5); + StorageDead(_4); _0 = move _2; + StorageDead(_2); return; } bb3: { @@ -69,6 +81,7 @@ fn demux(_1: u8) -> u8 { fn main() -> () { let mut _0: (); bb0: { + _0 = (); return; } } diff --git a/tests/ui/stable-mir-print/operands.rs b/tests/ui/stable-mir-print/operands.rs index 34a74e2287e6..484ad07cf048 100644 --- a/tests/ui/stable-mir-print/operands.rs +++ b/tests/ui/stable-mir-print/operands.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort +//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort -Zmir-opt-level=0 //@ check-pass //@ only-x86_64 //@ needs-unwind unwind edges are different with panic=abort diff --git a/tests/ui/stable-mir-print/operands.stdout b/tests/ui/stable-mir-print/operands.stdout index c3b1151ae24a..37c5ec1a95e6 100644 --- a/tests/ui/stable-mir-print/operands.stdout +++ b/tests/ui/stable-mir-print/operands.stdout @@ -3,185 +3,398 @@ fn operands(_1: u8) -> () { let mut _0: (); let _2: [u8; 10]; - let _3: u8; - let _4: usize; - let mut _5: bool; - let _6: u8; - let _7: usize; - let mut _8: (usize, bool); - let mut _9: bool; - let mut _10: (&u8, &u8); - let mut _11: &u8; - let mut _12: &u8; - let _13: &u8; - let _14: &u8; - let mut _15: bool; - let mut _16: u8; - let mut _17: u8; - let _18: core::panicking::AssertKind; - let _19: !; - let mut _20: Option>; - let _21: &u8; - let _22: u8; - let mut _23: (&u8, &u8); + let mut _3: u8; + let _4: u8; + let _5: usize; + let mut _6: bool; + let _7: u8; + let _8: usize; + let mut _9: (usize, bool); + let mut _10: bool; + let _11: (); + let mut _12: (&u8, &u8); + let mut _13: &u8; + let mut _14: &u8; + let _15: &u8; + let _16: &u8; + let mut _17: bool; + let mut _18: u8; + let mut _19: u8; + let mut _20: !; + let _21: core::panicking::AssertKind; + let _22: !; + let mut _23: core::panicking::AssertKind; let mut _24: &u8; - let mut _25: &u8; - let _26: &u8; + let _25: &u8; + let mut _26: &u8; let _27: &u8; - let mut _28: bool; - let mut _29: u8; - let mut _30: u8; - let _31: core::panicking::AssertKind; - let _32: !; - let mut _33: Option>; - let _34: (u8, u8); - let _35: u8; - let _36: u8; - let mut _37: (&u8, &u8); - let mut _38: &u8; - let mut _39: &u8; - let _40: &u8; - let _41: &u8; - let mut _42: bool; - let mut _43: u8; - let mut _44: u8; - let _45: core::panicking::AssertKind; - let _46: !; - let mut _47: Option>; - let _48: usize; - let mut _49: &[u8]; - let mut _50: &[u8; 10]; - let _51: usize; - let _52: &usize; - let mut _53: (&usize, &usize); - let mut _54: &usize; - let mut _55: &usize; - let _56: &usize; - let _57: &usize; - let mut _58: bool; - let mut _59: usize; - let mut _60: usize; - let _61: core::panicking::AssertKind; - let _62: !; - let mut _63: Option>; + let mut _28: Option>; + let _29: &u8; + let _30: u8; + let _31: (); + let mut _32: (&u8, &u8); + let mut _33: &u8; + let mut _34: &u8; + let _35: &u8; + let _36: &u8; + let mut _37: bool; + let mut _38: u8; + let mut _39: u8; + let mut _40: !; + let _41: core::panicking::AssertKind; + let _42: !; + let mut _43: core::panicking::AssertKind; + let mut _44: &u8; + let _45: &u8; + let mut _46: &u8; + let _47: &u8; + let mut _48: Option>; + let _49: (u8, u8); + let mut _50: u8; + let mut _51: u8; + let _52: u8; + let _53: u8; + let _54: (); + let mut _55: (&u8, &u8); + let mut _56: &u8; + let mut _57: &u8; + let _58: &u8; + let _59: &u8; + let mut _60: bool; + let mut _61: u8; + let mut _62: u8; + let mut _63: !; + let _64: core::panicking::AssertKind; + let _65: !; + let mut _66: core::panicking::AssertKind; + let mut _67: &u8; + let _68: &u8; + let mut _69: &u8; + let _70: &u8; + let mut _71: Option>; + let _72: usize; + let mut _73: &[u8]; + let mut _74: &[u8; 10]; + let _75: usize; + let mut _76: &usize; + let _77: &usize; + let _78: (); + let mut _79: (&usize, &usize); + let mut _80: &usize; + let mut _81: &usize; + let _82: &usize; + let _83: &usize; + let mut _84: bool; + let mut _85: usize; + let mut _86: usize; + let mut _87: !; + let _88: core::panicking::AssertKind; + let _89: !; + let mut _90: core::panicking::AssertKind; + let mut _91: &usize; + let _92: &usize; + let mut _93: &usize; + let _94: &usize; + let mut _95: Option>; debug val => _1; debug array => _2; - debug first => _3; - debug last => _6; - debug left_val => _13; - debug right_val => _14; - debug kind => _18; - debug reference => _21; - debug dereferenced => _22; - debug left_val => _26; - debug right_val => _27; - debug kind => _31; - debug tuple => _34; - debug first_again => _35; - debug first_again_again => _36; - debug left_val => _40; - debug right_val => _41; - debug kind => _45; - debug length => _48; - debug size_of => _51; - debug left_val => _56; - debug right_val => _57; - debug kind => _61; + debug first => _4; + debug last => _7; + debug left_val => _15; + debug right_val => _16; + debug kind => _21; + debug reference => _29; + debug dereferenced => _30; + debug left_val => _35; + debug right_val => _36; + debug kind => _41; + debug tuple => _49; + debug first_again => _52; + debug first_again_again => _53; + debug left_val => _58; + debug right_val => _59; + debug kind => _64; + debug length => _72; + debug size_of => _75; + debug left_val => _82; + debug right_val => _83; + debug kind => _88; bb0: { - _2 = [_1; 10]; - _4 = 0_usize; - _5 = Lt(_4, 10_usize); - assert(move _5, "index out of bounds: the length is {} but the index is {}", 10_usize, _4) -> [success: bb1, unwind unreachable]; + StorageLive(_2); + StorageLive(_3); + _3 = _1; + _2 = [move _3; 10]; + StorageDead(_3); + StorageLive(_4); + StorageLive(_5); + _5 = 0_usize; + _6 = Lt(_5, 10_usize); + assert(move _6, "index out of bounds: the length is {} but the index is {}", 10_usize, _5) -> [success: bb1, unwind unreachable]; } bb1: { - _3 = _2[_4]; - _8 = CheckedSub(10_usize, 1_usize); - assert(!move (_8.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable]; + _4 = _2[_5]; + StorageDead(_5); + StorageLive(_7); + StorageLive(_8); + _9 = CheckedSub(10_usize, 1_usize); + assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable]; } bb2: { - _7 = move (_8.0: usize); - _9 = Lt(_7, 10_usize); - assert(move _9, "index out of bounds: the length is {} but the index is {}", 10_usize, _7) -> [success: bb3, unwind unreachable]; + _8 = move (_9.0: usize); + _10 = Lt(_8, 10_usize); + assert(move _10, "index out of bounds: the length is {} but the index is {}", 10_usize, _8) -> [success: bb3, unwind unreachable]; } bb3: { - _6 = _2[_7]; - _11 = &_3; - _12 = &_6; - _10 = (move _11, move _12); - _13 = (_10.0: &u8); - _14 = (_10.1: &u8); - _16 = (*_13); - _17 = (*_14); - _15 = Eq(move _16, move _17); - switchInt(move _15) -> [0: bb5, otherwise: bb4]; + _7 = _2[_8]; + StorageDead(_8); + StorageLive(_11); + StorageLive(_12); + StorageLive(_13); + _13 = &_4; + StorageLive(_14); + _14 = &_7; + _12 = (move _13, move _14); + StorageDead(_14); + StorageDead(_13); + StorageLive(_15); + _15 = (_12.0: &u8); + StorageLive(_16); + _16 = (_12.1: &u8); + StorageLive(_17); + StorageLive(_18); + _18 = (*_15); + StorageLive(_19); + _19 = (*_16); + _17 = Eq(move _18, move _19); + switchInt(move _17) -> [0: bb5, otherwise: bb4]; } bb4: { - _21 = &_3; - _22 = (*_21); - _24 = &_22; - _25 = &_3; - _23 = (move _24, move _25); - _26 = (_23.0: &u8); - _27 = (_23.1: &u8); - _29 = (*_26); - _30 = (*_27); - _28 = Eq(move _29, move _30); - switchInt(move _28) -> [0: bb7, otherwise: bb6]; + StorageDead(_19); + StorageDead(_18); + _11 = (); + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + StorageDead(_12); + StorageDead(_11); + StorageLive(_29); + _29 = &_4; + StorageLive(_30); + _30 = (*_29); + StorageLive(_31); + StorageLive(_32); + StorageLive(_33); + _33 = &_30; + StorageLive(_34); + _34 = &_4; + _32 = (move _33, move _34); + StorageDead(_34); + StorageDead(_33); + StorageLive(_35); + _35 = (_32.0: &u8); + StorageLive(_36); + _36 = (_32.1: &u8); + StorageLive(_37); + StorageLive(_38); + _38 = (*_35); + StorageLive(_39); + _39 = (*_36); + _37 = Eq(move _38, move _39); + switchInt(move _37) -> [0: bb7, otherwise: bb6]; } bb5: { - _18 = core::panicking::AssertKind::Eq; - _20 = std::option::Option::None; - _19 = core::panicking::assert_failed::(move _18, _13, _14, move _20) -> unwind unreachable; + StorageDead(_19); + StorageDead(_18); + StorageLive(_21); + _21 = core::panicking::AssertKind::Eq; + StorageLive(_22); + StorageLive(_23); + _23 = move _21; + StorageLive(_24); + StorageLive(_25); + _25 = &(*_15); + _24 = &(*_25); + StorageLive(_26); + StorageLive(_27); + _27 = &(*_16); + _26 = &(*_27); + StorageLive(_28); + _28 = std::option::Option::None; + _22 = core::panicking::assert_failed::(move _23, move _24, move _26, move _28) -> unwind unreachable; } bb6: { - _34 = (_3, _6); - _35 = (_34.0: u8); - _36 = (_34.0: u8); - _38 = &_35; - _39 = &_36; - _37 = (move _38, move _39); - _40 = (_37.0: &u8); - _41 = (_37.1: &u8); - _43 = (*_40); - _44 = (*_41); - _42 = Eq(move _43, move _44); - switchInt(move _42) -> [0: bb9, otherwise: bb8]; + StorageDead(_39); + StorageDead(_38); + _31 = (); + StorageDead(_37); + StorageDead(_36); + StorageDead(_35); + StorageDead(_32); + StorageDead(_31); + StorageLive(_49); + StorageLive(_50); + _50 = _4; + StorageLive(_51); + _51 = _7; + _49 = (move _50, move _51); + StorageDead(_51); + StorageDead(_50); + StorageLive(_52); + _52 = (_49.0: u8); + StorageLive(_53); + _53 = (_49.0: u8); + StorageLive(_54); + StorageLive(_55); + StorageLive(_56); + _56 = &_52; + StorageLive(_57); + _57 = &_53; + _55 = (move _56, move _57); + StorageDead(_57); + StorageDead(_56); + StorageLive(_58); + _58 = (_55.0: &u8); + StorageLive(_59); + _59 = (_55.1: &u8); + StorageLive(_60); + StorageLive(_61); + _61 = (*_58); + StorageLive(_62); + _62 = (*_59); + _60 = Eq(move _61, move _62); + switchInt(move _60) -> [0: bb9, otherwise: bb8]; } bb7: { - _31 = core::panicking::AssertKind::Eq; - _33 = std::option::Option::None; - _32 = core::panicking::assert_failed::(move _31, _26, _27, move _33) -> unwind unreachable; + StorageDead(_39); + StorageDead(_38); + StorageLive(_41); + _41 = core::panicking::AssertKind::Eq; + StorageLive(_42); + StorageLive(_43); + _43 = move _41; + StorageLive(_44); + StorageLive(_45); + _45 = &(*_35); + _44 = &(*_45); + StorageLive(_46); + StorageLive(_47); + _47 = &(*_36); + _46 = &(*_47); + StorageLive(_48); + _48 = std::option::Option::None; + _42 = core::panicking::assert_failed::(move _43, move _44, move _46, move _48) -> unwind unreachable; } bb8: { - _50 = &_2; - _49 = move _50 as &[u8]; - _48 = PtrMetadata(move _49); - _52 = &_48; - _51 = std::mem::size_of_val::(_52) -> [return: bb10, unwind unreachable]; + StorageDead(_62); + StorageDead(_61); + _54 = (); + StorageDead(_60); + StorageDead(_59); + StorageDead(_58); + StorageDead(_55); + StorageDead(_54); + StorageLive(_72); + StorageLive(_73); + StorageLive(_74); + _74 = &_2; + _73 = move _74 as &[u8]; + StorageDead(_74); + _72 = core::slice::::len(move _73) -> [return: bb10, unwind unreachable]; } bb9: { - _45 = core::panicking::AssertKind::Eq; - _47 = std::option::Option::None; - _46 = core::panicking::assert_failed::(move _45, _40, _41, move _47) -> unwind unreachable; + StorageDead(_62); + StorageDead(_61); + StorageLive(_64); + _64 = core::panicking::AssertKind::Eq; + StorageLive(_65); + StorageLive(_66); + _66 = move _64; + StorageLive(_67); + StorageLive(_68); + _68 = &(*_58); + _67 = &(*_68); + StorageLive(_69); + StorageLive(_70); + _70 = &(*_59); + _69 = &(*_70); + StorageLive(_71); + _71 = std::option::Option::None; + _65 = core::panicking::assert_failed::(move _66, move _67, move _69, move _71) -> unwind unreachable; } bb10: { - _54 = &_48; - _55 = &_51; - _53 = (move _54, move _55); - _56 = (_53.0: &usize); - _57 = (_53.1: &usize); - _59 = (*_56); - _60 = (*_57); - _58 = Eq(move _59, move _60); - switchInt(move _58) -> [0: bb12, otherwise: bb11]; + StorageDead(_73); + StorageLive(_75); + StorageLive(_76); + StorageLive(_77); + _77 = &_72; + _76 = &(*_77); + _75 = std::mem::size_of_val::(move _76) -> [return: bb11, unwind unreachable]; } bb11: { - return; + StorageDead(_76); + StorageDead(_77); + StorageLive(_78); + StorageLive(_79); + StorageLive(_80); + _80 = &_72; + StorageLive(_81); + _81 = &_75; + _79 = (move _80, move _81); + StorageDead(_81); + StorageDead(_80); + StorageLive(_82); + _82 = (_79.0: &usize); + StorageLive(_83); + _83 = (_79.1: &usize); + StorageLive(_84); + StorageLive(_85); + _85 = (*_82); + StorageLive(_86); + _86 = (*_83); + _84 = Eq(move _85, move _86); + switchInt(move _84) -> [0: bb13, otherwise: bb12]; } bb12: { - _61 = core::panicking::AssertKind::Eq; - _63 = std::option::Option::None; - _62 = core::panicking::assert_failed::(move _61, _56, _57, move _63) -> unwind unreachable; + StorageDead(_86); + StorageDead(_85); + _78 = (); + StorageDead(_84); + StorageDead(_83); + StorageDead(_82); + StorageDead(_79); + StorageDead(_78); + _0 = (); + StorageDead(_75); + StorageDead(_72); + StorageDead(_53); + StorageDead(_52); + StorageDead(_49); + StorageDead(_30); + StorageDead(_29); + StorageDead(_7); + StorageDead(_4); + StorageDead(_2); + return; + } + bb13: { + StorageDead(_86); + StorageDead(_85); + StorageLive(_88); + _88 = core::panicking::AssertKind::Eq; + StorageLive(_89); + StorageLive(_90); + _90 = move _88; + StorageLive(_91); + StorageLive(_92); + _92 = &(*_82); + _91 = &(*_92); + StorageLive(_93); + StorageLive(_94); + _94 = &(*_83); + _93 = &(*_94); + StorageLive(_95); + _95 = std::option::Option::None; + _89 = core::panicking::assert_failed::(move _90, move _91, move _93, move _95) -> unwind unreachable; } } fn operands::{constant#0}() -> usize { @@ -196,17 +409,41 @@ fn more_operands() -> [Ctors; 3] { let _1: Dummy; let _2: Ctors; let _3: Ctors; - let _4: Ctors; + let mut _4: Dummy; + let _5: Ctors; + let mut _6: Ctors; + let mut _7: Ctors; + let mut _8: Ctors; debug dummy => _1; debug unit => _2; debug struct_like => _3; - debug tup_like => _4; + debug tup_like => _5; bb0: { + StorageLive(_1); _1 = Dummy('a', core::num::::MIN); + StorageLive(_2); _2 = Ctors::Unit; - _3 = Ctors::StructLike(move _1); - _4 = Ctors::TupLike(false); - _0 = [move _2, move _3, move _4]; + StorageLive(_3); + StorageLive(_4); + _4 = move _1; + _3 = Ctors::StructLike(move _4); + StorageDead(_4); + StorageLive(_5); + _5 = Ctors::TupLike(false); + StorageLive(_6); + _6 = move _2; + StorageLive(_7); + _7 = move _3; + StorageLive(_8); + _8 = move _5; + _0 = [move _6, move _7, move _8]; + StorageDead(_8); + StorageDead(_7); + StorageDead(_6); + StorageDead(_5); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); return; } } @@ -230,23 +467,33 @@ fn closures::{closure#0}(_1: {closure@$DIR/operands.rs:47:5: 47:19}, _2: bool) - let mut _0: bool; let mut _3: bool; let mut _4: bool; + let mut _5: bool; debug y => _2; debug x => (_1.0: bool); debug z => (_1.1: bool); bb0: { + StorageLive(_3); + StorageLive(_4); _4 = (_1.0: bool); - _3 = BitXor(move _4, _2); + StorageLive(_5); + _5 = _2; + _3 = BitXor(move _4, move _5); switchInt(move _3) -> [0: bb2, otherwise: bb1]; } bb1: { + StorageDead(_5); + StorageDead(_4); _0 = true; goto -> bb3; } bb2: { + StorageDead(_5); + StorageDead(_4); _0 = (_1.1: bool); goto -> bb3; } bb3: { + StorageDead(_3); return; } } From 59af8f36e31165dc2fa5968941a2edad3e1c0025 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 7 Jul 2025 04:58:18 +0000 Subject: [PATCH 68/68] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0130cf13a45f..7ca7acb3fd70 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -733b47ea4b1b86216f14ef56e49440c33933f230 +ca98d4d4b3114116203699c2734805547df86f9a