From a755d0f4cb3b235f3bb5586e38a95239bc59c048 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 18 Apr 2026 15:37:12 +0200 Subject: [PATCH 01/18] Add an edge-case test for `--remap-path-prefix` for `rustc` & `rustdoc` --- .../remap-path-prefix-edge-cases/rmake.rs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/run-make/remap-path-prefix-edge-cases/rmake.rs diff --git a/tests/run-make/remap-path-prefix-edge-cases/rmake.rs b/tests/run-make/remap-path-prefix-edge-cases/rmake.rs new file mode 100644 index 000000000000..364c5b30f476 --- /dev/null +++ b/tests/run-make/remap-path-prefix-edge-cases/rmake.rs @@ -0,0 +1,51 @@ +//! This test checks multiple edge-case of `--remap-path-prefix`. +//! +//! It tests: +//! - `=` sign in FROM path +//! - multiple path remappings +//! - multiple conflicting path remappings + +//@ ignore-windows (does not support directories with = sign) + +use std::path::Path; + +use run_make_support::{ + CompletedProcess, assert_contains, assert_not_contains, cwd, rfs, run_in_tmpdir, rustc, rustdoc, +}; + +fn main() { + run_in_tmpdir(|| { + let out_dir = cwd(); + + // Create a directory with an `=` sign + let eq_dir = out_dir.join("path=with=equal"); + rfs::create_dir_all(&eq_dir); + + let src_path = eq_dir.join("lib.rs"); + rfs::write(&src_path, "pub fn broken_func() { "); + + // Use multiple remap args and conflicting remappings + let remap_args = [ + format!("--remap-path-prefix={}={}", eq_dir.display(), "REMAPPED_DIR"), + format!("--remap-path-prefix={}={}", eq_dir.display(), "REMAPPED_DIR2"), + ]; + + fn run_test(cmd: impl FnOnce() -> CompletedProcess) { + let output = cmd(); + let stderr = output.stderr_utf8(); + + // Checks the diagnostic output + assert_contains(&stderr, "REMAPPED_DIR2/lib.rs"); + assert_not_contains(&stderr, "REMAPPED_DIR/"); + assert_not_contains(&stderr, "path=with=equal"); + }; + + // Test with rustc + run_test(|| rustc().input(&src_path).args(&remap_args).run_fail()); + + // Test with rustdoc + run_test(|| { + rustdoc().input(&src_path).arg("-Zunstable-options").args(&remap_args).run_fail() + }); + }); +} From 72c56ed0c04fc71d383ef32eece7de77b594b836 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 22 Apr 2026 11:35:02 +0000 Subject: [PATCH 02/18] remove `deriving-via-extension-*.rs` tests --- .../deriving/deriving-via-extension-c-enum.rs | 17 ----------------- .../ui/deriving/deriving-via-extension-enum.rs | 16 ---------------- .../deriving-via-extension-hash-enum.rs | 17 ----------------- .../deriving-via-extension-hash-struct.rs | 11 ----------- .../deriving-via-extension-struct-empty.rs | 8 -------- ...ng-via-extension-struct-like-enum-variant.rs | 13 ------------- .../deriving-via-extension-struct-tuple.rs | 17 ----------------- .../deriving/deriving-via-extension-struct.rs | 16 ---------------- .../deriving-via-extension-type-params.rs | 16 ---------------- 9 files changed, 131 deletions(-) delete mode 100644 tests/ui/deriving/deriving-via-extension-c-enum.rs delete mode 100644 tests/ui/deriving/deriving-via-extension-enum.rs delete mode 100644 tests/ui/deriving/deriving-via-extension-hash-enum.rs delete mode 100644 tests/ui/deriving/deriving-via-extension-hash-struct.rs delete mode 100644 tests/ui/deriving/deriving-via-extension-struct-empty.rs delete mode 100644 tests/ui/deriving/deriving-via-extension-struct-like-enum-variant.rs delete mode 100644 tests/ui/deriving/deriving-via-extension-struct-tuple.rs delete mode 100644 tests/ui/deriving/deriving-via-extension-struct.rs delete mode 100644 tests/ui/deriving/deriving-via-extension-type-params.rs diff --git a/tests/ui/deriving/deriving-via-extension-c-enum.rs b/tests/ui/deriving/deriving-via-extension-c-enum.rs deleted file mode 100644 index 8d15257116f1..000000000000 --- a/tests/ui/deriving/deriving-via-extension-c-enum.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#[derive(PartialEq, Debug)] -enum Foo { - Bar, - Baz, - Boo -} - -pub fn main() { - let a = Foo::Bar; - let b = Foo::Bar; - assert_eq!(a, b); - assert!(!(a != b)); - assert!(a.eq(&b)); - assert!(!a.ne(&b)); -} diff --git a/tests/ui/deriving/deriving-via-extension-enum.rs b/tests/ui/deriving/deriving-via-extension-enum.rs deleted file mode 100644 index f844c8243d43..000000000000 --- a/tests/ui/deriving/deriving-via-extension-enum.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#[derive(PartialEq, Debug)] -enum Foo { - Bar(isize, isize), - Baz(f64, f64) -} - -pub fn main() { - let a = Foo::Bar(1, 2); - let b = Foo::Bar(1, 2); - assert_eq!(a, b); - assert!(!(a != b)); - assert!(a.eq(&b)); - assert!(!a.ne(&b)); -} diff --git a/tests/ui/deriving/deriving-via-extension-hash-enum.rs b/tests/ui/deriving/deriving-via-extension-hash-enum.rs deleted file mode 100644 index acd34f781871..000000000000 --- a/tests/ui/deriving/deriving-via-extension-hash-enum.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#[derive(Hash)] -enum Foo { - Bar(isize, char), - Baz(char, isize) -} - -#[derive(Hash)] -enum A { - B, - C, - D, - E -} - -pub fn main(){} diff --git a/tests/ui/deriving/deriving-via-extension-hash-struct.rs b/tests/ui/deriving/deriving-via-extension-hash-struct.rs deleted file mode 100644 index 2b1bc9e108b1..000000000000 --- a/tests/ui/deriving/deriving-via-extension-hash-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -#[derive(Hash)] -struct Foo { - x: isize, - y: isize, - z: isize -} - -pub fn main() {} diff --git a/tests/ui/deriving/deriving-via-extension-struct-empty.rs b/tests/ui/deriving/deriving-via-extension-struct-empty.rs deleted file mode 100644 index 43a60013e79e..000000000000 --- a/tests/ui/deriving/deriving-via-extension-struct-empty.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -#[derive(PartialEq, Debug)] -struct Foo; - -pub fn main() { - assert_eq!(Foo, Foo); - assert!(!(Foo != Foo)); -} diff --git a/tests/ui/deriving/deriving-via-extension-struct-like-enum-variant.rs b/tests/ui/deriving/deriving-via-extension-struct-like-enum-variant.rs deleted file mode 100644 index fe382c4e4b90..000000000000 --- a/tests/ui/deriving/deriving-via-extension-struct-like-enum-variant.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#[derive(PartialEq, Debug)] -enum S { - X { x: isize, y: isize }, - Y -} - -pub fn main() { - let x = S::X { x: 1, y: 2 }; - assert_eq!(x, x); - assert!(!(x != x)); -} diff --git a/tests/ui/deriving/deriving-via-extension-struct-tuple.rs b/tests/ui/deriving/deriving-via-extension-struct-tuple.rs deleted file mode 100644 index 3192b85a37be..000000000000 --- a/tests/ui/deriving/deriving-via-extension-struct-tuple.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass -#[derive(PartialEq, Debug)] -struct Foo(isize, isize, String); - -pub fn main() { - let a1 = Foo(5, 6, "abc".to_string()); - let a2 = Foo(5, 6, "abc".to_string()); - let b = Foo(5, 7, "def".to_string()); - - assert_eq!(a1, a1); - assert_eq!(a2, a1); - assert!(!(a1 == b)); - - assert!(a1 != b); - assert!(!(a1 != a1)); - assert!(!(a2 != a1)); -} diff --git a/tests/ui/deriving/deriving-via-extension-struct.rs b/tests/ui/deriving/deriving-via-extension-struct.rs deleted file mode 100644 index 4a5c3453876a..000000000000 --- a/tests/ui/deriving/deriving-via-extension-struct.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ run-pass -#[derive(PartialEq, Debug)] -struct Foo { - x: isize, - y: isize, - z: isize, -} - -pub fn main() { - let a = Foo { x: 1, y: 2, z: 3 }; - let b = Foo { x: 1, y: 2, z: 3 }; - assert_eq!(a, b); - assert!(!(a != b)); - assert!(a.eq(&b)); - assert!(!a.ne(&b)); -} diff --git a/tests/ui/deriving/deriving-via-extension-type-params.rs b/tests/ui/deriving/deriving-via-extension-type-params.rs deleted file mode 100644 index 79ac0c316754..000000000000 --- a/tests/ui/deriving/deriving-via-extension-type-params.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ run-pass -#[derive(PartialEq, Hash, Debug)] -struct Foo { - x: isize, - y: T, - z: isize -} - -pub fn main() { - let a = Foo { x: 1, y: 2.0f64, z: 3 }; - let b = Foo { x: 1, y: 2.0f64, z: 3 }; - assert_eq!(a, b); - assert!(!(a != b)); - assert!(a.eq(&b)); - assert!(!a.ne(&b)); -} From f2657b899113672fac83c448aa9d4d1095c64a9f Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 22 Apr 2026 12:59:20 +0000 Subject: [PATCH 03/18] create `derives/coercepointee` --- .../coercepointee}/auxiliary/another-proc-macro.rs | 0 .../coercepointee}/auxiliary/malicious-macro.rs | 0 .../coercepointee}/built-in-proc-macro-scope.rs | 0 .../coercepointee}/built-in-proc-macro-scope.stdout | 0 .../coercepointee}/coerce-pointee-bounds-issue-127647.rs | 0 .../coercepointee}/deriving-coerce-pointee-expanded.rs | 0 .../coercepointee}/deriving-coerce-pointee-expanded.stdout | 0 .../coercepointee}/deriving-coerce-pointee-neg.rs | 0 .../coercepointee}/deriving-coerce-pointee-neg.stderr | 0 .../coercepointee}/deriving-coerce-pointee.rs | 0 .../coercepointee}/proc-macro-attribute-mixing.rs | 0 .../coercepointee}/proc-macro-attribute-mixing.stdout | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{deriving => derives/coercepointee}/auxiliary/another-proc-macro.rs (100%) rename tests/ui/{deriving => derives/coercepointee}/auxiliary/malicious-macro.rs (100%) rename tests/ui/{deriving => derives/coercepointee}/built-in-proc-macro-scope.rs (100%) rename tests/ui/{deriving => derives/coercepointee}/built-in-proc-macro-scope.stdout (100%) rename tests/ui/{deriving => derives/coercepointee}/coerce-pointee-bounds-issue-127647.rs (100%) rename tests/ui/{deriving => derives/coercepointee}/deriving-coerce-pointee-expanded.rs (100%) rename tests/ui/{deriving => derives/coercepointee}/deriving-coerce-pointee-expanded.stdout (100%) rename tests/ui/{deriving => derives/coercepointee}/deriving-coerce-pointee-neg.rs (100%) rename tests/ui/{deriving => derives/coercepointee}/deriving-coerce-pointee-neg.stderr (100%) rename tests/ui/{deriving => derives/coercepointee}/deriving-coerce-pointee.rs (100%) rename tests/ui/{deriving => derives/coercepointee}/proc-macro-attribute-mixing.rs (100%) rename tests/ui/{deriving => derives/coercepointee}/proc-macro-attribute-mixing.stdout (100%) diff --git a/tests/ui/deriving/auxiliary/another-proc-macro.rs b/tests/ui/derives/coercepointee/auxiliary/another-proc-macro.rs similarity index 100% rename from tests/ui/deriving/auxiliary/another-proc-macro.rs rename to tests/ui/derives/coercepointee/auxiliary/another-proc-macro.rs diff --git a/tests/ui/deriving/auxiliary/malicious-macro.rs b/tests/ui/derives/coercepointee/auxiliary/malicious-macro.rs similarity index 100% rename from tests/ui/deriving/auxiliary/malicious-macro.rs rename to tests/ui/derives/coercepointee/auxiliary/malicious-macro.rs diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/derives/coercepointee/built-in-proc-macro-scope.rs similarity index 100% rename from tests/ui/deriving/built-in-proc-macro-scope.rs rename to tests/ui/derives/coercepointee/built-in-proc-macro-scope.rs diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/derives/coercepointee/built-in-proc-macro-scope.stdout similarity index 100% rename from tests/ui/deriving/built-in-proc-macro-scope.stdout rename to tests/ui/derives/coercepointee/built-in-proc-macro-scope.stdout diff --git a/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs b/tests/ui/derives/coercepointee/coerce-pointee-bounds-issue-127647.rs similarity index 100% rename from tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs rename to tests/ui/derives/coercepointee/coerce-pointee-bounds-issue-127647.rs diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.rs b/tests/ui/derives/coercepointee/deriving-coerce-pointee-expanded.rs similarity index 100% rename from tests/ui/deriving/deriving-coerce-pointee-expanded.rs rename to tests/ui/derives/coercepointee/deriving-coerce-pointee-expanded.rs diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout b/tests/ui/derives/coercepointee/deriving-coerce-pointee-expanded.stdout similarity index 100% rename from tests/ui/deriving/deriving-coerce-pointee-expanded.stdout rename to tests/ui/derives/coercepointee/deriving-coerce-pointee-expanded.stdout diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.rs b/tests/ui/derives/coercepointee/deriving-coerce-pointee-neg.rs similarity index 100% rename from tests/ui/deriving/deriving-coerce-pointee-neg.rs rename to tests/ui/derives/coercepointee/deriving-coerce-pointee-neg.rs diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/derives/coercepointee/deriving-coerce-pointee-neg.stderr similarity index 100% rename from tests/ui/deriving/deriving-coerce-pointee-neg.stderr rename to tests/ui/derives/coercepointee/deriving-coerce-pointee-neg.stderr diff --git a/tests/ui/deriving/deriving-coerce-pointee.rs b/tests/ui/derives/coercepointee/deriving-coerce-pointee.rs similarity index 100% rename from tests/ui/deriving/deriving-coerce-pointee.rs rename to tests/ui/derives/coercepointee/deriving-coerce-pointee.rs diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/derives/coercepointee/proc-macro-attribute-mixing.rs similarity index 100% rename from tests/ui/deriving/proc-macro-attribute-mixing.rs rename to tests/ui/derives/coercepointee/proc-macro-attribute-mixing.rs diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/derives/coercepointee/proc-macro-attribute-mixing.stdout similarity index 100% rename from tests/ui/deriving/proc-macro-attribute-mixing.stdout rename to tests/ui/derives/coercepointee/proc-macro-attribute-mixing.stdout From 674eb8a04db4b8cf07a43655306ad1e4b4b18a7b Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 22 Apr 2026 13:10:25 +0000 Subject: [PATCH 04/18] create `derives/debug` --- tests/ui/derives/{ => debug}/derive-Debug-enum-variants.rs | 0 tests/ui/derives/{ => debug}/derive-Debug-use-ufcs-struct.rs | 0 tests/ui/derives/{ => debug}/derive-Debug-use-ufcs-tuple.rs | 0 .../deriving-show-2.rs => derives/debug/derive-debug-2.rs} | 0 .../ui/derives/{ => debug}/derive-debug-generic-with-lifetime.rs | 0 .../ui/derives/{ => debug}/derive-debug-newtype-unsized-slice.rs | 0 tests/ui/derives/{ => debug}/derive-debug-uninhabited-enum.rs | 0 tests/ui/derives/{ => debug}/derive-debug-uninhabited-enum.stderr | 0 .../{deriving/deriving-show.rs => derives/debug/derive-debug.rs} | 0 tests/ui/derives/{ => debug}/derives-span-Debug.rs | 0 tests/ui/derives/{ => debug}/derives-span-Debug.stderr | 0 tests/ui/derives/{ => debug}/nonsense-input-to-debug.rs | 0 tests/ui/derives/{ => debug}/nonsense-input-to-debug.stderr | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/derives/{ => debug}/derive-Debug-enum-variants.rs (100%) rename tests/ui/derives/{ => debug}/derive-Debug-use-ufcs-struct.rs (100%) rename tests/ui/derives/{ => debug}/derive-Debug-use-ufcs-tuple.rs (100%) rename tests/ui/{deriving/deriving-show-2.rs => derives/debug/derive-debug-2.rs} (100%) rename tests/ui/derives/{ => debug}/derive-debug-generic-with-lifetime.rs (100%) rename tests/ui/derives/{ => debug}/derive-debug-newtype-unsized-slice.rs (100%) rename tests/ui/derives/{ => debug}/derive-debug-uninhabited-enum.rs (100%) rename tests/ui/derives/{ => debug}/derive-debug-uninhabited-enum.stderr (100%) rename tests/ui/{deriving/deriving-show.rs => derives/debug/derive-debug.rs} (100%) rename tests/ui/derives/{ => debug}/derives-span-Debug.rs (100%) rename tests/ui/derives/{ => debug}/derives-span-Debug.stderr (100%) rename tests/ui/derives/{ => debug}/nonsense-input-to-debug.rs (100%) rename tests/ui/derives/{ => debug}/nonsense-input-to-debug.stderr (100%) diff --git a/tests/ui/derives/derive-Debug-enum-variants.rs b/tests/ui/derives/debug/derive-Debug-enum-variants.rs similarity index 100% rename from tests/ui/derives/derive-Debug-enum-variants.rs rename to tests/ui/derives/debug/derive-Debug-enum-variants.rs diff --git a/tests/ui/derives/derive-Debug-use-ufcs-struct.rs b/tests/ui/derives/debug/derive-Debug-use-ufcs-struct.rs similarity index 100% rename from tests/ui/derives/derive-Debug-use-ufcs-struct.rs rename to tests/ui/derives/debug/derive-Debug-use-ufcs-struct.rs diff --git a/tests/ui/derives/derive-Debug-use-ufcs-tuple.rs b/tests/ui/derives/debug/derive-Debug-use-ufcs-tuple.rs similarity index 100% rename from tests/ui/derives/derive-Debug-use-ufcs-tuple.rs rename to tests/ui/derives/debug/derive-Debug-use-ufcs-tuple.rs diff --git a/tests/ui/deriving/deriving-show-2.rs b/tests/ui/derives/debug/derive-debug-2.rs similarity index 100% rename from tests/ui/deriving/deriving-show-2.rs rename to tests/ui/derives/debug/derive-debug-2.rs diff --git a/tests/ui/derives/derive-debug-generic-with-lifetime.rs b/tests/ui/derives/debug/derive-debug-generic-with-lifetime.rs similarity index 100% rename from tests/ui/derives/derive-debug-generic-with-lifetime.rs rename to tests/ui/derives/debug/derive-debug-generic-with-lifetime.rs diff --git a/tests/ui/derives/derive-debug-newtype-unsized-slice.rs b/tests/ui/derives/debug/derive-debug-newtype-unsized-slice.rs similarity index 100% rename from tests/ui/derives/derive-debug-newtype-unsized-slice.rs rename to tests/ui/derives/debug/derive-debug-newtype-unsized-slice.rs diff --git a/tests/ui/derives/derive-debug-uninhabited-enum.rs b/tests/ui/derives/debug/derive-debug-uninhabited-enum.rs similarity index 100% rename from tests/ui/derives/derive-debug-uninhabited-enum.rs rename to tests/ui/derives/debug/derive-debug-uninhabited-enum.rs diff --git a/tests/ui/derives/derive-debug-uninhabited-enum.stderr b/tests/ui/derives/debug/derive-debug-uninhabited-enum.stderr similarity index 100% rename from tests/ui/derives/derive-debug-uninhabited-enum.stderr rename to tests/ui/derives/debug/derive-debug-uninhabited-enum.stderr diff --git a/tests/ui/deriving/deriving-show.rs b/tests/ui/derives/debug/derive-debug.rs similarity index 100% rename from tests/ui/deriving/deriving-show.rs rename to tests/ui/derives/debug/derive-debug.rs diff --git a/tests/ui/derives/derives-span-Debug.rs b/tests/ui/derives/debug/derives-span-Debug.rs similarity index 100% rename from tests/ui/derives/derives-span-Debug.rs rename to tests/ui/derives/debug/derives-span-Debug.rs diff --git a/tests/ui/derives/derives-span-Debug.stderr b/tests/ui/derives/debug/derives-span-Debug.stderr similarity index 100% rename from tests/ui/derives/derives-span-Debug.stderr rename to tests/ui/derives/debug/derives-span-Debug.stderr diff --git a/tests/ui/derives/nonsense-input-to-debug.rs b/tests/ui/derives/debug/nonsense-input-to-debug.rs similarity index 100% rename from tests/ui/derives/nonsense-input-to-debug.rs rename to tests/ui/derives/debug/nonsense-input-to-debug.rs diff --git a/tests/ui/derives/nonsense-input-to-debug.stderr b/tests/ui/derives/debug/nonsense-input-to-debug.stderr similarity index 100% rename from tests/ui/derives/nonsense-input-to-debug.stderr rename to tests/ui/derives/debug/nonsense-input-to-debug.stderr From 87a26ec40bd4f0fe6d8a9c8014824089f3d6a805 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 22 Apr 2026 13:15:18 +0000 Subject: [PATCH 05/18] create `derives/default` --- tests/ui/derives/{ => default}/derives-span-Default.rs | 0 tests/ui/derives/{ => default}/derives-span-Default.stderr | 0 tests/ui/{deriving => derives/default}/deriving-default-box.rs | 0 tests/ui/{deriving => derives/default}/deriving-default-enum.rs | 0 tests/ui/{deriving => derives/default}/multiple-defaults.rs | 0 tests/ui/{deriving => derives/default}/multiple-defaults.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/derives/{ => default}/derives-span-Default.rs (100%) rename tests/ui/derives/{ => default}/derives-span-Default.stderr (100%) rename tests/ui/{deriving => derives/default}/deriving-default-box.rs (100%) rename tests/ui/{deriving => derives/default}/deriving-default-enum.rs (100%) rename tests/ui/{deriving => derives/default}/multiple-defaults.rs (100%) rename tests/ui/{deriving => derives/default}/multiple-defaults.stderr (100%) diff --git a/tests/ui/derives/derives-span-Default.rs b/tests/ui/derives/default/derives-span-Default.rs similarity index 100% rename from tests/ui/derives/derives-span-Default.rs rename to tests/ui/derives/default/derives-span-Default.rs diff --git a/tests/ui/derives/derives-span-Default.stderr b/tests/ui/derives/default/derives-span-Default.stderr similarity index 100% rename from tests/ui/derives/derives-span-Default.stderr rename to tests/ui/derives/default/derives-span-Default.stderr diff --git a/tests/ui/deriving/deriving-default-box.rs b/tests/ui/derives/default/deriving-default-box.rs similarity index 100% rename from tests/ui/deriving/deriving-default-box.rs rename to tests/ui/derives/default/deriving-default-box.rs diff --git a/tests/ui/deriving/deriving-default-enum.rs b/tests/ui/derives/default/deriving-default-enum.rs similarity index 100% rename from tests/ui/deriving/deriving-default-enum.rs rename to tests/ui/derives/default/deriving-default-enum.rs diff --git a/tests/ui/deriving/multiple-defaults.rs b/tests/ui/derives/default/multiple-defaults.rs similarity index 100% rename from tests/ui/deriving/multiple-defaults.rs rename to tests/ui/derives/default/multiple-defaults.rs diff --git a/tests/ui/deriving/multiple-defaults.stderr b/tests/ui/derives/default/multiple-defaults.stderr similarity index 100% rename from tests/ui/deriving/multiple-defaults.stderr rename to tests/ui/derives/default/multiple-defaults.stderr From 818e51128eaf8f7245e57451c0ac4f68230e6566 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 22 Apr 2026 13:28:56 +0000 Subject: [PATCH 06/18] create `derives/eq-ord` --- tests/ui/derives/{ => eq-ord}/derive-eq-check-all-variants.rs | 0 tests/ui/derives/{ => eq-ord}/derive-eq-check-all-variants.stderr | 0 .../derives/{ => eq-ord}/derive-partial-ord-discriminant-64bit.rs | 0 tests/ui/derives/{ => eq-ord}/derive-partial-ord-discriminant.rs | 0 tests/ui/derives/{ => eq-ord}/derive-partial-ord.rs | 0 .../{deriving => derives/eq-ord}/derive-partialord-correctness.rs | 0 tests/ui/derives/{ => eq-ord}/derives-span-Eq.rs | 0 tests/ui/derives/{ => eq-ord}/derives-span-Eq.stderr | 0 tests/ui/derives/{ => eq-ord}/derives-span-Ord.rs | 0 tests/ui/derives/{ => eq-ord}/derives-span-Ord.stderr | 0 tests/ui/derives/{ => eq-ord}/derives-span-PartialEq.rs | 0 tests/ui/derives/{ => eq-ord}/derives-span-PartialEq.stderr | 0 tests/ui/derives/{ => eq-ord}/derives-span-PartialOrd.rs | 0 tests/ui/derives/{ => eq-ord}/derives-span-PartialOrd.stderr | 0 .../ui/{deriving => derives/eq-ord}/deriving-cmp-generic-enum.rs | 0 .../eq-ord}/deriving-cmp-generic-struct-enum.rs | 0 .../{deriving => derives/eq-ord}/deriving-cmp-generic-struct.rs | 0 .../eq-ord}/deriving-cmp-generic-tuple-struct.rs | 0 .../ui/{deriving => derives/eq-ord}/deriving-cmp-shortcircuit.rs | 0 .../{deriving => derives/eq-ord}/deriving-eq-ord-boxed-slice.rs | 0 .../eq-ord}/deriving-self-lifetime-totalord-totaleq.rs | 0 .../eq-ord}/do-not-suggest-calling-fn-in-derive-macro.rs | 0 .../eq-ord}/do-not-suggest-calling-fn-in-derive-macro.stderr | 0 .../eq-ord}/internal_eq_trait_method_impls.rs | 0 .../eq-ord}/internal_eq_trait_method_impls.stderr | 0 tests/ui/derives/{ => eq-ord}/invalid-derive-comparison-34229.rs | 0 .../derives/{ => eq-ord}/invalid-derive-comparison-34229.stderr | 0 27 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/derives/{ => eq-ord}/derive-eq-check-all-variants.rs (100%) rename tests/ui/derives/{ => eq-ord}/derive-eq-check-all-variants.stderr (100%) rename tests/ui/derives/{ => eq-ord}/derive-partial-ord-discriminant-64bit.rs (100%) rename tests/ui/derives/{ => eq-ord}/derive-partial-ord-discriminant.rs (100%) rename tests/ui/derives/{ => eq-ord}/derive-partial-ord.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/derive-partialord-correctness.rs (100%) rename tests/ui/derives/{ => eq-ord}/derives-span-Eq.rs (100%) rename tests/ui/derives/{ => eq-ord}/derives-span-Eq.stderr (100%) rename tests/ui/derives/{ => eq-ord}/derives-span-Ord.rs (100%) rename tests/ui/derives/{ => eq-ord}/derives-span-Ord.stderr (100%) rename tests/ui/derives/{ => eq-ord}/derives-span-PartialEq.rs (100%) rename tests/ui/derives/{ => eq-ord}/derives-span-PartialEq.stderr (100%) rename tests/ui/derives/{ => eq-ord}/derives-span-PartialOrd.rs (100%) rename tests/ui/derives/{ => eq-ord}/derives-span-PartialOrd.stderr (100%) rename tests/ui/{deriving => derives/eq-ord}/deriving-cmp-generic-enum.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/deriving-cmp-generic-struct-enum.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/deriving-cmp-generic-struct.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/deriving-cmp-generic-tuple-struct.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/deriving-cmp-shortcircuit.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/deriving-eq-ord-boxed-slice.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/deriving-self-lifetime-totalord-totaleq.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/do-not-suggest-calling-fn-in-derive-macro.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/do-not-suggest-calling-fn-in-derive-macro.stderr (100%) rename tests/ui/{deriving => derives/eq-ord}/internal_eq_trait_method_impls.rs (100%) rename tests/ui/{deriving => derives/eq-ord}/internal_eq_trait_method_impls.stderr (100%) rename tests/ui/derives/{ => eq-ord}/invalid-derive-comparison-34229.rs (100%) rename tests/ui/derives/{ => eq-ord}/invalid-derive-comparison-34229.stderr (100%) diff --git a/tests/ui/derives/derive-eq-check-all-variants.rs b/tests/ui/derives/eq-ord/derive-eq-check-all-variants.rs similarity index 100% rename from tests/ui/derives/derive-eq-check-all-variants.rs rename to tests/ui/derives/eq-ord/derive-eq-check-all-variants.rs diff --git a/tests/ui/derives/derive-eq-check-all-variants.stderr b/tests/ui/derives/eq-ord/derive-eq-check-all-variants.stderr similarity index 100% rename from tests/ui/derives/derive-eq-check-all-variants.stderr rename to tests/ui/derives/eq-ord/derive-eq-check-all-variants.stderr diff --git a/tests/ui/derives/derive-partial-ord-discriminant-64bit.rs b/tests/ui/derives/eq-ord/derive-partial-ord-discriminant-64bit.rs similarity index 100% rename from tests/ui/derives/derive-partial-ord-discriminant-64bit.rs rename to tests/ui/derives/eq-ord/derive-partial-ord-discriminant-64bit.rs diff --git a/tests/ui/derives/derive-partial-ord-discriminant.rs b/tests/ui/derives/eq-ord/derive-partial-ord-discriminant.rs similarity index 100% rename from tests/ui/derives/derive-partial-ord-discriminant.rs rename to tests/ui/derives/eq-ord/derive-partial-ord-discriminant.rs diff --git a/tests/ui/derives/derive-partial-ord.rs b/tests/ui/derives/eq-ord/derive-partial-ord.rs similarity index 100% rename from tests/ui/derives/derive-partial-ord.rs rename to tests/ui/derives/eq-ord/derive-partial-ord.rs diff --git a/tests/ui/deriving/derive-partialord-correctness.rs b/tests/ui/derives/eq-ord/derive-partialord-correctness.rs similarity index 100% rename from tests/ui/deriving/derive-partialord-correctness.rs rename to tests/ui/derives/eq-ord/derive-partialord-correctness.rs diff --git a/tests/ui/derives/derives-span-Eq.rs b/tests/ui/derives/eq-ord/derives-span-Eq.rs similarity index 100% rename from tests/ui/derives/derives-span-Eq.rs rename to tests/ui/derives/eq-ord/derives-span-Eq.rs diff --git a/tests/ui/derives/derives-span-Eq.stderr b/tests/ui/derives/eq-ord/derives-span-Eq.stderr similarity index 100% rename from tests/ui/derives/derives-span-Eq.stderr rename to tests/ui/derives/eq-ord/derives-span-Eq.stderr diff --git a/tests/ui/derives/derives-span-Ord.rs b/tests/ui/derives/eq-ord/derives-span-Ord.rs similarity index 100% rename from tests/ui/derives/derives-span-Ord.rs rename to tests/ui/derives/eq-ord/derives-span-Ord.rs diff --git a/tests/ui/derives/derives-span-Ord.stderr b/tests/ui/derives/eq-ord/derives-span-Ord.stderr similarity index 100% rename from tests/ui/derives/derives-span-Ord.stderr rename to tests/ui/derives/eq-ord/derives-span-Ord.stderr diff --git a/tests/ui/derives/derives-span-PartialEq.rs b/tests/ui/derives/eq-ord/derives-span-PartialEq.rs similarity index 100% rename from tests/ui/derives/derives-span-PartialEq.rs rename to tests/ui/derives/eq-ord/derives-span-PartialEq.rs diff --git a/tests/ui/derives/derives-span-PartialEq.stderr b/tests/ui/derives/eq-ord/derives-span-PartialEq.stderr similarity index 100% rename from tests/ui/derives/derives-span-PartialEq.stderr rename to tests/ui/derives/eq-ord/derives-span-PartialEq.stderr diff --git a/tests/ui/derives/derives-span-PartialOrd.rs b/tests/ui/derives/eq-ord/derives-span-PartialOrd.rs similarity index 100% rename from tests/ui/derives/derives-span-PartialOrd.rs rename to tests/ui/derives/eq-ord/derives-span-PartialOrd.rs diff --git a/tests/ui/derives/derives-span-PartialOrd.stderr b/tests/ui/derives/eq-ord/derives-span-PartialOrd.stderr similarity index 100% rename from tests/ui/derives/derives-span-PartialOrd.stderr rename to tests/ui/derives/eq-ord/derives-span-PartialOrd.stderr diff --git a/tests/ui/deriving/deriving-cmp-generic-enum.rs b/tests/ui/derives/eq-ord/deriving-cmp-generic-enum.rs similarity index 100% rename from tests/ui/deriving/deriving-cmp-generic-enum.rs rename to tests/ui/derives/eq-ord/deriving-cmp-generic-enum.rs diff --git a/tests/ui/deriving/deriving-cmp-generic-struct-enum.rs b/tests/ui/derives/eq-ord/deriving-cmp-generic-struct-enum.rs similarity index 100% rename from tests/ui/deriving/deriving-cmp-generic-struct-enum.rs rename to tests/ui/derives/eq-ord/deriving-cmp-generic-struct-enum.rs diff --git a/tests/ui/deriving/deriving-cmp-generic-struct.rs b/tests/ui/derives/eq-ord/deriving-cmp-generic-struct.rs similarity index 100% rename from tests/ui/deriving/deriving-cmp-generic-struct.rs rename to tests/ui/derives/eq-ord/deriving-cmp-generic-struct.rs diff --git a/tests/ui/deriving/deriving-cmp-generic-tuple-struct.rs b/tests/ui/derives/eq-ord/deriving-cmp-generic-tuple-struct.rs similarity index 100% rename from tests/ui/deriving/deriving-cmp-generic-tuple-struct.rs rename to tests/ui/derives/eq-ord/deriving-cmp-generic-tuple-struct.rs diff --git a/tests/ui/deriving/deriving-cmp-shortcircuit.rs b/tests/ui/derives/eq-ord/deriving-cmp-shortcircuit.rs similarity index 100% rename from tests/ui/deriving/deriving-cmp-shortcircuit.rs rename to tests/ui/derives/eq-ord/deriving-cmp-shortcircuit.rs diff --git a/tests/ui/deriving/deriving-eq-ord-boxed-slice.rs b/tests/ui/derives/eq-ord/deriving-eq-ord-boxed-slice.rs similarity index 100% rename from tests/ui/deriving/deriving-eq-ord-boxed-slice.rs rename to tests/ui/derives/eq-ord/deriving-eq-ord-boxed-slice.rs diff --git a/tests/ui/deriving/deriving-self-lifetime-totalord-totaleq.rs b/tests/ui/derives/eq-ord/deriving-self-lifetime-totalord-totaleq.rs similarity index 100% rename from tests/ui/deriving/deriving-self-lifetime-totalord-totaleq.rs rename to tests/ui/derives/eq-ord/deriving-self-lifetime-totalord-totaleq.rs diff --git a/tests/ui/deriving/do-not-suggest-calling-fn-in-derive-macro.rs b/tests/ui/derives/eq-ord/do-not-suggest-calling-fn-in-derive-macro.rs similarity index 100% rename from tests/ui/deriving/do-not-suggest-calling-fn-in-derive-macro.rs rename to tests/ui/derives/eq-ord/do-not-suggest-calling-fn-in-derive-macro.rs diff --git a/tests/ui/deriving/do-not-suggest-calling-fn-in-derive-macro.stderr b/tests/ui/derives/eq-ord/do-not-suggest-calling-fn-in-derive-macro.stderr similarity index 100% rename from tests/ui/deriving/do-not-suggest-calling-fn-in-derive-macro.stderr rename to tests/ui/derives/eq-ord/do-not-suggest-calling-fn-in-derive-macro.stderr diff --git a/tests/ui/deriving/internal_eq_trait_method_impls.rs b/tests/ui/derives/eq-ord/internal_eq_trait_method_impls.rs similarity index 100% rename from tests/ui/deriving/internal_eq_trait_method_impls.rs rename to tests/ui/derives/eq-ord/internal_eq_trait_method_impls.rs diff --git a/tests/ui/deriving/internal_eq_trait_method_impls.stderr b/tests/ui/derives/eq-ord/internal_eq_trait_method_impls.stderr similarity index 100% rename from tests/ui/deriving/internal_eq_trait_method_impls.stderr rename to tests/ui/derives/eq-ord/internal_eq_trait_method_impls.stderr diff --git a/tests/ui/derives/invalid-derive-comparison-34229.rs b/tests/ui/derives/eq-ord/invalid-derive-comparison-34229.rs similarity index 100% rename from tests/ui/derives/invalid-derive-comparison-34229.rs rename to tests/ui/derives/eq-ord/invalid-derive-comparison-34229.rs diff --git a/tests/ui/derives/invalid-derive-comparison-34229.stderr b/tests/ui/derives/eq-ord/invalid-derive-comparison-34229.stderr similarity index 100% rename from tests/ui/derives/invalid-derive-comparison-34229.stderr rename to tests/ui/derives/eq-ord/invalid-derive-comparison-34229.stderr From b0b5b1256a93c847ef1cc5071efe47eb57ca4d62 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 22 Apr 2026 13:21:25 +0000 Subject: [PATCH 07/18] create `derives/clone-copy` --- tests/ui/derives/{ => clone-copy}/clone-vector-element-size.rs | 0 tests/ui/derives/{ => clone-copy}/copy-drop-mutually-exclusive.rs | 0 .../derives/{ => clone-copy}/copy-drop-mutually-exclusive.stderr | 0 tests/ui/derives/{ => clone-copy}/derive-clone-basic.rs | 0 tests/ui/derives/{ => clone-copy}/derives-span-Clone.rs | 0 tests/ui/derives/{ => clone-copy}/derives-span-Clone.stderr | 0 tests/ui/derives/{ => clone-copy}/deriving-copyclone.rs | 0 tests/ui/derives/{ => clone-copy}/deriving-copyclone.stderr | 0 .../{ => clone-copy}/duplicate-derive-copy-clone-diagnostics.rs | 0 .../duplicate-derive-copy-clone-diagnostics.stderr | 0 .../clone-copy/misbehaving-clone-impl.rs} | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/derives/{ => clone-copy}/clone-vector-element-size.rs (100%) rename tests/ui/derives/{ => clone-copy}/copy-drop-mutually-exclusive.rs (100%) rename tests/ui/derives/{ => clone-copy}/copy-drop-mutually-exclusive.stderr (100%) rename tests/ui/derives/{ => clone-copy}/derive-clone-basic.rs (100%) rename tests/ui/derives/{ => clone-copy}/derives-span-Clone.rs (100%) rename tests/ui/derives/{ => clone-copy}/derives-span-Clone.stderr (100%) rename tests/ui/derives/{ => clone-copy}/deriving-copyclone.rs (100%) rename tests/ui/derives/{ => clone-copy}/deriving-copyclone.stderr (100%) rename tests/ui/derives/{ => clone-copy}/duplicate-derive-copy-clone-diagnostics.rs (100%) rename tests/ui/derives/{ => clone-copy}/duplicate-derive-copy-clone-diagnostics.stderr (100%) rename tests/ui/{deriving/deriving-copyclone.rs => derives/clone-copy/misbehaving-clone-impl.rs} (100%) diff --git a/tests/ui/derives/clone-vector-element-size.rs b/tests/ui/derives/clone-copy/clone-vector-element-size.rs similarity index 100% rename from tests/ui/derives/clone-vector-element-size.rs rename to tests/ui/derives/clone-copy/clone-vector-element-size.rs diff --git a/tests/ui/derives/copy-drop-mutually-exclusive.rs b/tests/ui/derives/clone-copy/copy-drop-mutually-exclusive.rs similarity index 100% rename from tests/ui/derives/copy-drop-mutually-exclusive.rs rename to tests/ui/derives/clone-copy/copy-drop-mutually-exclusive.rs diff --git a/tests/ui/derives/copy-drop-mutually-exclusive.stderr b/tests/ui/derives/clone-copy/copy-drop-mutually-exclusive.stderr similarity index 100% rename from tests/ui/derives/copy-drop-mutually-exclusive.stderr rename to tests/ui/derives/clone-copy/copy-drop-mutually-exclusive.stderr diff --git a/tests/ui/derives/derive-clone-basic.rs b/tests/ui/derives/clone-copy/derive-clone-basic.rs similarity index 100% rename from tests/ui/derives/derive-clone-basic.rs rename to tests/ui/derives/clone-copy/derive-clone-basic.rs diff --git a/tests/ui/derives/derives-span-Clone.rs b/tests/ui/derives/clone-copy/derives-span-Clone.rs similarity index 100% rename from tests/ui/derives/derives-span-Clone.rs rename to tests/ui/derives/clone-copy/derives-span-Clone.rs diff --git a/tests/ui/derives/derives-span-Clone.stderr b/tests/ui/derives/clone-copy/derives-span-Clone.stderr similarity index 100% rename from tests/ui/derives/derives-span-Clone.stderr rename to tests/ui/derives/clone-copy/derives-span-Clone.stderr diff --git a/tests/ui/derives/deriving-copyclone.rs b/tests/ui/derives/clone-copy/deriving-copyclone.rs similarity index 100% rename from tests/ui/derives/deriving-copyclone.rs rename to tests/ui/derives/clone-copy/deriving-copyclone.rs diff --git a/tests/ui/derives/deriving-copyclone.stderr b/tests/ui/derives/clone-copy/deriving-copyclone.stderr similarity index 100% rename from tests/ui/derives/deriving-copyclone.stderr rename to tests/ui/derives/clone-copy/deriving-copyclone.stderr diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs b/tests/ui/derives/clone-copy/duplicate-derive-copy-clone-diagnostics.rs similarity index 100% rename from tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs rename to tests/ui/derives/clone-copy/duplicate-derive-copy-clone-diagnostics.rs diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr b/tests/ui/derives/clone-copy/duplicate-derive-copy-clone-diagnostics.stderr similarity index 100% rename from tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr rename to tests/ui/derives/clone-copy/duplicate-derive-copy-clone-diagnostics.stderr diff --git a/tests/ui/deriving/deriving-copyclone.rs b/tests/ui/derives/clone-copy/misbehaving-clone-impl.rs similarity index 100% rename from tests/ui/deriving/deriving-copyclone.rs rename to tests/ui/derives/clone-copy/misbehaving-clone-impl.rs From e908aa8671e80825963f2700e57664ef0e71c772 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 22 Apr 2026 20:15:37 +0000 Subject: [PATCH 08/18] delete some no-longer-meaningful tests --- tests/ui/derives/auxiliary/rustc-serialize.rs | 16 ------------ .../deriving/deriving-enum-single-variant.rs | 11 -------- tests/ui/deriving/deriving-in-macro.rs | 16 ------------ tests/ui/deriving/deriving-meta-multiple.rs | 25 ------------------- tests/ui/deriving/deriving-meta.rs | 22 ---------------- 5 files changed, 90 deletions(-) delete mode 100644 tests/ui/derives/auxiliary/rustc-serialize.rs delete mode 100644 tests/ui/deriving/deriving-enum-single-variant.rs delete mode 100644 tests/ui/deriving/deriving-in-macro.rs delete mode 100644 tests/ui/deriving/deriving-meta-multiple.rs delete mode 100644 tests/ui/deriving/deriving-meta.rs diff --git a/tests/ui/derives/auxiliary/rustc-serialize.rs b/tests/ui/derives/auxiliary/rustc-serialize.rs deleted file mode 100644 index 24177af931c4..000000000000 --- a/tests/ui/derives/auxiliary/rustc-serialize.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![crate_type = "lib"] - -pub trait Decoder { - type Error; - - fn read_enum(&mut self, name: &str, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; - fn read_enum_variant(&mut self, names: &[&str], f: F) - -> Result - where F: FnMut(&mut Self, usize) -> Result; - -} - -pub trait Decodable: Sized { - fn decode(d: &mut D) -> Result; -} diff --git a/tests/ui/deriving/deriving-enum-single-variant.rs b/tests/ui/deriving/deriving-enum-single-variant.rs deleted file mode 100644 index 43d229c442c4..000000000000 --- a/tests/ui/deriving/deriving-enum-single-variant.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] - -pub type task_id = isize; - -#[derive(PartialEq)] -pub enum Task { - TaskHandle(task_id) -} - -pub fn main() { } diff --git a/tests/ui/deriving/deriving-in-macro.rs b/tests/ui/deriving/deriving-in-macro.rs deleted file mode 100644 index 739d9b306822..000000000000 --- a/tests/ui/deriving/deriving-in-macro.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ check-pass -#![allow(non_camel_case_types)] -#![allow(dead_code)] - -macro_rules! define_vec { - () => ( - mod foo { - #[derive(PartialEq)] - pub struct bar; - } - ) -} - -define_vec![]; - -pub fn main() {} diff --git a/tests/ui/deriving/deriving-meta-multiple.rs b/tests/ui/deriving/deriving-meta-multiple.rs deleted file mode 100644 index 7c2d3566fbf2..000000000000 --- a/tests/ui/deriving/deriving-meta-multiple.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ run-pass -#![allow(unused_must_use)] -#![allow(unused_imports)] -#![allow(deprecated)] - -use std::hash::{Hash, SipHasher}; - -// testing multiple separate deriving attributes -#[derive(PartialEq)] -#[derive(Clone)] -#[derive(Hash)] -struct Foo { - bar: usize, - baz: isize -} - -fn hash(_t: &T) {} - -pub fn main() { - let a = Foo {bar: 4, baz: -3}; - - a == a; // check for PartialEq impl w/o testing its correctness - a.clone(); // check for Clone impl w/o testing its correctness - hash(&a); // check for Hash impl w/o testing its correctness -} diff --git a/tests/ui/deriving/deriving-meta.rs b/tests/ui/deriving/deriving-meta.rs deleted file mode 100644 index 70b5821edae1..000000000000 --- a/tests/ui/deriving/deriving-meta.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ run-pass -#![allow(unused_must_use)] -#![allow(unused_imports)] -#![allow(deprecated)] - -use std::hash::{Hash, SipHasher}; - -#[derive(PartialEq, Clone, Hash)] -struct Foo { - bar: usize, - baz: isize -} - -fn hash(_t: &T) {} - -pub fn main() { - let a = Foo {bar: 4, baz: -3}; - - a == a; // check for PartialEq impl w/o testing its correctness - a.clone(); // check for Clone impl w/o testing its correctness - hash(&a); // check for Hash impl w/o testing its correctness -} From 11ba127dfcef2d8e7978e5be6e7c9938cc6d74ab Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 22 Apr 2026 20:26:08 +0000 Subject: [PATCH 09/18] move remaining files from `deriving` to `derives` --- tests/ui/README.md | 4 ---- tests/ui/{deriving => derives}/auxiliary/derive-no-std.rs | 0 tests/ui/{deriving => derives}/derive-no-std.rs | 0 tests/ui/{deriving => derives}/deriving-all-codegen.rs | 0 tests/ui/{deriving => derives}/deriving-all-codegen.stdout | 0 tests/ui/{deriving => derives}/deriving-associated-types.rs | 0 tests/ui/{deriving => derives}/deriving-from-wrong-target.rs | 0 .../{deriving => derives}/deriving-from-wrong-target.stderr | 0 tests/ui/{deriving => derives}/deriving-from.rs | 0 tests/ui/{deriving => derives}/deriving-hash.rs | 0 tests/ui/{deriving => derives}/deriving-in-fn.rs | 0 tests/ui/{deriving => derives}/deriving-with-helper.rs | 0 .../deriving-with-repr-packed-3.rs} | 0 triagebot.toml | 2 +- 14 files changed, 1 insertion(+), 5 deletions(-) rename tests/ui/{deriving => derives}/auxiliary/derive-no-std.rs (100%) rename tests/ui/{deriving => derives}/derive-no-std.rs (100%) rename tests/ui/{deriving => derives}/deriving-all-codegen.rs (100%) rename tests/ui/{deriving => derives}/deriving-all-codegen.stdout (100%) rename tests/ui/{deriving => derives}/deriving-associated-types.rs (100%) rename tests/ui/{deriving => derives}/deriving-from-wrong-target.rs (100%) rename tests/ui/{deriving => derives}/deriving-from-wrong-target.stderr (100%) rename tests/ui/{deriving => derives}/deriving-from.rs (100%) rename tests/ui/{deriving => derives}/deriving-hash.rs (100%) rename tests/ui/{deriving => derives}/deriving-in-fn.rs (100%) rename tests/ui/{deriving => derives}/deriving-with-helper.rs (100%) rename tests/ui/{deriving/deriving-with-repr-packed.rs => derives/deriving-with-repr-packed-3.rs} (100%) diff --git a/tests/ui/README.md b/tests/ui/README.md index 0af02ab39c23..139837864357 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -420,10 +420,6 @@ Tests for quality of diagnostics involving suppression of cascading errors in so Tests for built-in derive macros (`Debug`, `Clone`, etc.) when used in conjunction with built-in `#[derive(..)]` attributes. -## `tests/ui/deriving/`: Derive Macro - -**FIXME**: Coalesce with `tests/ui/derives`. - ## `tests/ui/dest-prop/` Destination Propagation **FIXME**: Contains a single test for the `DestProp` mir-opt, should probably be rehomed. diff --git a/tests/ui/deriving/auxiliary/derive-no-std.rs b/tests/ui/derives/auxiliary/derive-no-std.rs similarity index 100% rename from tests/ui/deriving/auxiliary/derive-no-std.rs rename to tests/ui/derives/auxiliary/derive-no-std.rs diff --git a/tests/ui/deriving/derive-no-std.rs b/tests/ui/derives/derive-no-std.rs similarity index 100% rename from tests/ui/deriving/derive-no-std.rs rename to tests/ui/derives/derive-no-std.rs diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/derives/deriving-all-codegen.rs similarity index 100% rename from tests/ui/deriving/deriving-all-codegen.rs rename to tests/ui/derives/deriving-all-codegen.rs diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/derives/deriving-all-codegen.stdout similarity index 100% rename from tests/ui/deriving/deriving-all-codegen.stdout rename to tests/ui/derives/deriving-all-codegen.stdout diff --git a/tests/ui/deriving/deriving-associated-types.rs b/tests/ui/derives/deriving-associated-types.rs similarity index 100% rename from tests/ui/deriving/deriving-associated-types.rs rename to tests/ui/derives/deriving-associated-types.rs diff --git a/tests/ui/deriving/deriving-from-wrong-target.rs b/tests/ui/derives/deriving-from-wrong-target.rs similarity index 100% rename from tests/ui/deriving/deriving-from-wrong-target.rs rename to tests/ui/derives/deriving-from-wrong-target.rs diff --git a/tests/ui/deriving/deriving-from-wrong-target.stderr b/tests/ui/derives/deriving-from-wrong-target.stderr similarity index 100% rename from tests/ui/deriving/deriving-from-wrong-target.stderr rename to tests/ui/derives/deriving-from-wrong-target.stderr diff --git a/tests/ui/deriving/deriving-from.rs b/tests/ui/derives/deriving-from.rs similarity index 100% rename from tests/ui/deriving/deriving-from.rs rename to tests/ui/derives/deriving-from.rs diff --git a/tests/ui/deriving/deriving-hash.rs b/tests/ui/derives/deriving-hash.rs similarity index 100% rename from tests/ui/deriving/deriving-hash.rs rename to tests/ui/derives/deriving-hash.rs diff --git a/tests/ui/deriving/deriving-in-fn.rs b/tests/ui/derives/deriving-in-fn.rs similarity index 100% rename from tests/ui/deriving/deriving-in-fn.rs rename to tests/ui/derives/deriving-in-fn.rs diff --git a/tests/ui/deriving/deriving-with-helper.rs b/tests/ui/derives/deriving-with-helper.rs similarity index 100% rename from tests/ui/deriving/deriving-with-helper.rs rename to tests/ui/derives/deriving-with-helper.rs diff --git a/tests/ui/deriving/deriving-with-repr-packed.rs b/tests/ui/derives/deriving-with-repr-packed-3.rs similarity index 100% rename from tests/ui/deriving/deriving-with-repr-packed.rs rename to tests/ui/derives/deriving-with-repr-packed-3.rs diff --git a/triagebot.toml b/triagebot.toml index a4155914fb02..575d5d38a2ef 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1283,7 +1283,7 @@ Please ensure that if you've changed the output: """ cc = ["@aDotInTheVoid", "@obi1kenobi"] -[mentions."tests/ui/deriving/deriving-all-codegen.stdout"] +[mentions."tests/ui/derives/deriving-all-codegen.stdout"] message = "Changes to the code generated for builtin derived traits." cc = ["@nnethercote"] From 13ec3de67337e0781eaee2d952f746272760a51e Mon Sep 17 00:00:00 2001 From: Flakebi Date: Fri, 24 Apr 2026 10:03:45 +0200 Subject: [PATCH 10/18] Add intrinsic for launch-sized workgroup memory on GPUs Workgroup memory is a memory region that is shared between all threads in a workgroup on GPUs. Workgroup memory can be allocated statically or after compilation, when launching a gpu-kernel. The intrinsic added here returns the pointer to the memory that is allocated at launch-time. # Interface With this change, workgroup memory can be accessed in Rust by calling the new `gpu_launch_sized_workgroup_mem() -> *mut T` intrinsic. It returns the pointer to workgroup memory guaranteeing that it is aligned to at least the alignment of `T`. The pointer is dereferencable for the size specified when launching the current gpu-kernel (which may be the size of `T` but can also be larger or smaller or zero). All calls to this intrinsic return a pointer to the same address. See the intrinsic documentation for more details. ## Alternative Interfaces It was also considered to expose dynamic workgroup memory as extern static variables in Rust, like they are represented in LLVM IR. However, due to the pointer not being guaranteed to be dereferencable (that depends on the allocated size at runtime), such a global must be zero-sized, which makes global variables a bad fit. # Implementation Details Workgroup memory in amdgpu and nvptx lives in address space 3. Workgroup memory from a launch is implemented by creating an external global variable in address space 3. The global is declared with size 0, as the actual size is only known at runtime. It is defined behavior in LLVM to access an external global outside the defined size. There is no similar way to get the allocated size of launch-sized workgroup memory on amdgpu an nvptx, so users have to pass this out-of-band or rely on target specific ways for now. --- compiler/rustc_abi/src/lib.rs | 3 ++ compiler/rustc_codegen_llvm/src/declare.rs | 23 +++++++++ compiler/rustc_codegen_llvm/src/intrinsic.rs | 49 +++++++++++++++++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 7 +++ .../rustc_codegen_ssa/src/mir/intrinsic.rs | 1 + .../rustc_hir_analysis/src/check/intrinsic.rs | 2 + .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 26 ++++++++-- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/gpu.rs | 45 +++++++++++++++++ src/tools/tidy/src/style.rs | 4 ++ .../gpu-launch-sized-workgroup-memory.rs | 41 ++++++++++++++++ 11 files changed, 193 insertions(+), 9 deletions(-) create mode 100644 tests/codegen-llvm/gpu-launch-sized-workgroup-memory.rs diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 450a93ee8481..96e4b822b041 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1753,6 +1753,9 @@ pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator impl AddressSpace { /// LLVM's `0` address space. pub const ZERO: Self = AddressSpace(0); + /// The address space for workgroup memory on nvptx and amdgpu. + /// See e.g. the `gpu_launch_sized_workgroup_mem` intrinsic for details. + pub const GPU_WORKGROUP: Self = AddressSpace(3); } /// How many scalable vectors are in a `BackendRepr::ScalableVector`? diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index d7b8a304e959..419d38f95e59 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -14,6 +14,7 @@ use std::borrow::Borrow; use itertools::Itertools; +use rustc_abi::AddressSpace; use rustc_codegen_ssa::traits::{MiscCodegenMethods, TypeMembershipCodegenMethods}; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::ty::{Instance, Ty}; @@ -104,6 +105,28 @@ pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { ) } } + + /// Declare a global value in a specific address space. + /// + /// If there’s a value with the same name already declared, the function will + /// return its Value instead. + pub(crate) fn declare_global_in_addrspace( + &self, + name: &str, + ty: &'ll Type, + addr_space: AddressSpace, + ) -> &'ll Value { + debug!("declare_global(name={name:?}, addrspace={addr_space:?})"); + unsafe { + llvm::LLVMRustGetOrInsertGlobalInAddrspace( + (**self).borrow().llmod, + name.as_c_char_ptr(), + name.len(), + ty, + addr_space.0, + ) + } + } } impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index b8ba6db9aa80..a298cf963dcc 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -3,8 +3,8 @@ use std::{assert_matches, iter, ptr}; use rustc_abi::{ - Align, BackendRepr, Float, HasDataLayout, Integer, NumScalableVectors, Primitive, Size, - WrappingRange, + AddressSpace, Align, BackendRepr, Float, HasDataLayout, Integer, NumScalableVectors, Primitive, + Size, WrappingRange, }; use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; @@ -176,6 +176,7 @@ fn codegen_intrinsic_call( span: Span, ) -> Result<(), ty::Instance<'tcx>> { let tcx = self.tcx; + let llvm_version = crate::llvm_util::get_version(); let name = tcx.item_name(instance.def_id()); let fn_args = instance.args; @@ -192,7 +193,7 @@ fn codegen_intrinsic_call( | sym::maximum_number_nsz_f64 | sym::maximum_number_nsz_f128 // Need at least LLVM 22 for `min/maximumnum` to not crash LLVM. - if crate::llvm_util::get_version() >= (22, 0, 0) => + if llvm_version >= (22, 0, 0) => { let intrinsic_name = if name.as_str().starts_with("min") { "llvm.minimumnum" @@ -418,7 +419,7 @@ fn codegen_intrinsic_call( } // FIXME move into the branch below when LLVM 22 is the lowest version we support. - sym::carryless_mul if crate::llvm_util::get_version() >= (22, 0, 0) => { + sym::carryless_mul if llvm_version >= (22, 0, 0) => { let ty = args[0].layout.ty; if !ty.is_integral() { tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType { @@ -618,6 +619,46 @@ fn codegen_intrinsic_call( return Ok(()); } + sym::gpu_launch_sized_workgroup_mem => { + // Generate an anonymous global per call, with these properties: + // 1. The global is in the address space for workgroup memory + // 2. It is an `external` global + // 3. It is correctly aligned for the pointee `T` + // All instances of extern addrspace(gpu_workgroup) globals are merged in the LLVM backend. + // The name is irrelevant. + // See https://docs.nvidia.com/cuda/cuda-c-programming-guide/#shared + let name = if llvm_version < (23, 0, 0) && tcx.sess.target.arch == Arch::Nvptx64 { + // The auto-assigned name for extern shared globals in the nvptx backend does + // not compile in ptxas. Workaround this issue by assigning a name. + // Fixed in LLVM 23. + "gpu_launch_sized_workgroup_mem" + } else { + "" + }; + let global = self.declare_global_in_addrspace( + name, + self.type_array(self.type_i8(), 0), + AddressSpace::GPU_WORKGROUP, + ); + let ty::RawPtr(inner_ty, _) = result.layout.ty.kind() else { unreachable!() }; + // The alignment of the global is used to specify the *minimum* alignment that + // must be obeyed by the GPU runtime. + // When multiple of these global variables are used by a kernel, the maximum alignment is taken. + // See https://github.com/llvm/llvm-project/blob/a271d07488a85ce677674bbe8101b10efff58c95/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp#L821 + let alignment = self.align_of(*inner_ty).bytes() as u32; + unsafe { + // FIXME Workaround the above issue by taking maximum alignment if the global existed + if tcx.sess.target.arch == Arch::Nvptx64 { + if alignment > llvm::LLVMGetAlignment(global) { + llvm::LLVMSetAlignment(global, alignment); + } + } else { + llvm::LLVMSetAlignment(global, alignment); + } + } + self.cx().const_pointercast(global, self.type_ptr()) + } + sym::amdgpu_dispatch_ptr => { let val = self.call_intrinsic("llvm.amdgcn.dispatch.ptr", &[], &[]); // Relying on `LLVMBuildPointerCast` to produce an addrspacecast diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 525d1dbe9d0d..3e373c42eca3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2003,6 +2003,13 @@ pub(crate) fn LLVMRustGetOrInsertGlobal<'a>( NameLen: size_t, T: &'a Type, ) -> &'a Value; + pub(crate) fn LLVMRustGetOrInsertGlobalInAddrspace<'a>( + M: &'a Module, + Name: *const c_char, + NameLen: size_t, + T: &'a Type, + AddressSpace: c_uint, + ) -> &'a Value; pub(crate) fn LLVMRustGetNamedValue( M: &Module, Name: *const c_char, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index fd0c7c656ac2..f4a5e8baa2a5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -111,6 +111,7 @@ pub fn codegen_intrinsic_call( sym::abort | sym::unreachable | sym::cold_path + | sym::gpu_launch_sized_workgroup_mem | sym::breakpoint | sym::amdgpu_dispatch_ptr | sym::assert_zero_valid diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index d952faa5edb7..9cc66f3c2adf 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -130,6 +130,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::forget | sym::frem_algebraic | sym::fsub_algebraic + | sym::gpu_launch_sized_workgroup_mem | sym::is_val_statically_known | sym::log2f16 | sym::log2f32 @@ -297,6 +298,7 @@ pub(crate) fn check_intrinsic_type( sym::field_offset => (1, 0, vec![], tcx.types.usize), sym::rustc_peek => (1, 0, vec![param(0)], param(0)), sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()), + sym::gpu_launch_sized_workgroup_mem => (1, 0, vec![], Ty::new_mut_ptr(tcx, param(0))), sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => { (1, 0, vec![], tcx.types.unit) } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index c310e580af55..91bb1c973363 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -299,10 +299,12 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, .getCallee()); } -extern "C" LLVMValueRef LLVMRustGetOrInsertGlobal(LLVMModuleRef M, - const char *Name, - size_t NameLen, - LLVMTypeRef Ty) { +// Get the global variable with the given name if it exists or create a new +// external global. +extern "C" LLVMValueRef +LLVMRustGetOrInsertGlobalInAddrspace(LLVMModuleRef M, const char *Name, + size_t NameLen, LLVMTypeRef Ty, + unsigned int AddressSpace) { Module *Mod = unwrap(M); auto NameRef = StringRef(Name, NameLen); @@ -313,10 +315,24 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertGlobal(LLVMModuleRef M, GlobalVariable *GV = Mod->getGlobalVariable(NameRef, true); if (!GV) GV = new GlobalVariable(*Mod, unwrap(Ty), false, - GlobalValue::ExternalLinkage, nullptr, NameRef); + GlobalValue::ExternalLinkage, nullptr, NameRef, + nullptr, GlobalValue::NotThreadLocal, AddressSpace); return wrap(GV); } +// Get the global variable with the given name if it exists or create a new +// external global. +extern "C" LLVMValueRef LLVMRustGetOrInsertGlobal(LLVMModuleRef M, + const char *Name, + size_t NameLen, + LLVMTypeRef Ty) { + Module *Mod = unwrap(M); + unsigned int AddressSpace = + Mod->getDataLayout().getDefaultGlobalsAddressSpace(); + return LLVMRustGetOrInsertGlobalInAddrspace(M, Name, NameLen, Ty, + AddressSpace); +} + // Must match the layout of `rustc_codegen_llvm::llvm::ffi::AttributeKind`. enum class LLVMRustAttributeKind { AlwaysInline = 0, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 981bfed363dc..5e7834e800ff 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1032,6 +1032,7 @@ global_asm, global_registration, globs, + gpu_launch_sized_workgroup_mem, gt, guard, guard_patterns, diff --git a/library/core/src/intrinsics/gpu.rs b/library/core/src/intrinsics/gpu.rs index 9e7624841d0c..43cb7251c3c8 100644 --- a/library/core/src/intrinsics/gpu.rs +++ b/library/core/src/intrinsics/gpu.rs @@ -5,6 +5,51 @@ #![unstable(feature = "gpu_intrinsics", issue = "none")] +/// Returns the pointer to workgroup memory allocated at launch-time on GPUs. +/// +/// Workgroup memory is a memory region that is shared between all threads in +/// the same workgroup. It is faster to access than other memory but pointers do not +/// work outside the workgroup where they were obtained. +/// Workgroup memory can be allocated statically or after compilation, when +/// launching a gpu-kernel. `gpu_launch_sized_workgroup_mem` returns the pointer to +/// the memory that is allocated at launch-time. +/// The size of this memory can differ between launches of a gpu-kernel, depending on +/// what is specified at launch-time. +/// However, the alignment is fixed by the kernel itself, at compile-time. +/// +/// The returned pointer is the start of the workgroup memory region that is +/// allocated at launch-time. +/// All calls to `gpu_launch_sized_workgroup_mem` in a workgroup, independent of the +/// generic type, return the same address, so alias the same memory. +/// The returned pointer is aligned by at least the alignment of `T`. +/// +/// If `gpu_launch_sized_workgroup_mem` is invoked multiple times with different +/// types that have different alignment, then you may only rely on the resulting +/// pointer having the alignment of `T` after a call to `gpu_launch_sized_workgroup_mem::` +/// has occurred in the current program execution. +/// +/// # Safety +/// +/// The pointer is safe to dereference from the start (the returned pointer) up to the +/// size of workgroup memory that was specified when launching the current gpu-kernel. +/// This allocated size is not related in any way to `T`. +/// +/// The user must take care of synchronizing access to workgroup memory between +/// threads in a workgroup. The usual data race requirements apply. +/// +/// # Other APIs +/// +/// CUDA and HIP call this dynamic shared memory, shared between threads in a block. +/// OpenCL and SYCL call this local memory, shared between threads in a work-group. +/// GLSL calls this shared memory, shared between invocations in a work group. +/// DirectX calls this groupshared memory, shared between threads in a thread-group. +#[must_use = "returns a pointer that does nothing unless used"] +#[rustc_intrinsic] +#[rustc_nounwind] +#[unstable(feature = "gpu_launch_sized_workgroup_mem", issue = "135513")] +#[cfg(any(target_arch = "amdgpu", target_arch = "nvptx64"))] +pub fn gpu_launch_sized_workgroup_mem() -> *mut T; + /// Returns a pointer to the HSA kernel dispatch packet. /// /// A `gpu-kernel` on amdgpu is always launched through a kernel dispatch packet. diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index d144ffa22209..4e2f71b94ce2 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -222,6 +222,10 @@ fn should_ignore(line: &str) -> bool { || static_regex!( "\\s*//@ \\!?(count|files|has|has-dir|hasraw|matches|matchesraw|snapshot)\\s.*" ).is_match(line) + // Matching for FileCheck checks + || static_regex!( + "\\s*// [a-zA-Z0-9-_]*:\\s.*" + ).is_match(line) } /// Returns `true` if `line` is allowed to be longer than the normal limit. diff --git a/tests/codegen-llvm/gpu-launch-sized-workgroup-memory.rs b/tests/codegen-llvm/gpu-launch-sized-workgroup-memory.rs new file mode 100644 index 000000000000..4764160fd0b5 --- /dev/null +++ b/tests/codegen-llvm/gpu-launch-sized-workgroup-memory.rs @@ -0,0 +1,41 @@ +// Checks that the GPU intrinsic to get launch-sized workgroup memory works +// and correctly aligns the `external addrspace(...) global`s over multiple calls. + +//@ revisions: amdgpu nvptx-pre-llvm-23 nvptx-post-llvm-23 +//@ compile-flags: --crate-type=rlib -Copt-level=1 +// +//@ [amdgpu] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 +//@ [amdgpu] needs-llvm-components: amdgpu + +//@ [nvptx-pre-llvm-23] compile-flags: --target nvptx64-nvidia-cuda +//@ [nvptx-pre-llvm-23] needs-llvm-components: nvptx +//@ [nvptx-pre-llvm-23] max-llvm-major-version: 22 +//@ [nvptx-post-llvm-23] compile-flags: --target nvptx64-nvidia-cuda +//@ [nvptx-post-llvm-23] needs-llvm-components: nvptx +//@ [nvptx-post-llvm-23] min-llvm-version: 23 +//@ add-minicore +#![feature(intrinsics, no_core, rustc_attrs)] +#![no_core] + +extern crate minicore; + +#[rustc_intrinsic] +#[rustc_nounwind] +fn gpu_launch_sized_workgroup_mem() -> *mut T; + +// amdgpu-DAG: @[[SMALL:[^ ]+]] = external addrspace(3) global [0 x i8], align 4 +// amdgpu-DAG: @[[BIG:[^ ]+]] = external addrspace(3) global [0 x i8], align 8 +// amdgpu: ret { ptr, ptr } { ptr addrspacecast (ptr addrspace(3) @[[SMALL]] to ptr), ptr addrspacecast (ptr addrspace(3) @[[BIG]] to ptr) } + +// nvptx-pre-llvm-23: @[[BIG:[^ ]+]] = external addrspace(3) global [0 x i8], align 8 +// nvptx-pre-llvm-23: ret { ptr, ptr } { ptr addrspacecast (ptr addrspace(3) @[[BIG]] to ptr), ptr addrspacecast (ptr addrspace(3) @[[BIG]] to ptr) } + +// nvptx-post-llvm-23-DAG: @[[SMALL:[^ ]+]] = external addrspace(3) global [0 x i8], align 4 +// nvptx-post-llvm-23-DAG: @[[BIG:[^ ]+]] = external addrspace(3) global [0 x i8], align 8 +// nvptx-post-llvm-23: ret { ptr, ptr } { ptr addrspacecast (ptr addrspace(3) @[[SMALL]] to ptr), ptr addrspacecast (ptr addrspace(3) @[[BIG]] to ptr) } +#[unsafe(no_mangle)] +pub fn fun() -> (*mut i32, *mut f64) { + let small = gpu_launch_sized_workgroup_mem::(); + let big = gpu_launch_sized_workgroup_mem::(); // Increase alignment to 8 + (small, big) +} From 9aa431c046b10865d38f17246bc2ea431117b364 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Mon, 13 Apr 2026 19:29:59 +0000 Subject: [PATCH 11/18] Add a simpler, harder to misuse, attribute parsing API --- .../src/attributes/allow_unstable.rs | 2 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 12 ++--- .../src/attributes/codegen_attrs.rs | 23 +++------ .../src/attributes/confusables.rs | 6 +-- .../src/attributes/crate_level.rs | 8 +--- .../src/attributes/debugger.rs | 2 +- .../src/attributes/diagnostic/mod.rs | 4 +- .../rustc_attr_parsing/src/attributes/doc.rs | 4 +- .../src/attributes/inline.rs | 10 +--- .../src/attributes/instruction_set.rs | 2 +- .../src/attributes/link_attrs.rs | 2 +- .../src/attributes/macro_attrs.rs | 4 +- .../src/attributes/proc_macro_attrs.rs | 7 +-- .../src/attributes/prototype.rs | 6 +-- .../rustc_attr_parsing/src/attributes/repr.rs | 9 ++-- .../src/attributes/rustc_dump.rs | 4 +- .../src/attributes/rustc_internal.rs | 47 +++++-------------- .../src/attributes/stability.rs | 18 ++----- .../src/attributes/test_attrs.rs | 24 ++++------ .../src/attributes/traits.rs | 6 +-- .../rustc_attr_parsing/src/attributes/util.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 29 ++++++++++-- compiler/rustc_attr_parsing/src/parser.rs | 4 +- 23 files changed, 85 insertions(+), 150 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index c2511ac75d5d..278b3200a454 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -81,7 +81,7 @@ fn parse_unstable( ) -> impl IntoIterator { let mut res = Vec::new(); - let Some(list) = args.list() else { + let Some(list) = args.as_list() else { cx.emit_err(session_diagnostics::ExpectsFeatureList { span: cx.attr_span, name: symbol.to_ident_string(), diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 84c83be8b4a5..c2dda74e9f51 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -44,13 +44,9 @@ pub fn parse_cfg( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> Option { - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; - let Some(single) = list.single() else { + let Some(single) = list.as_single() else { let target = cx.target; let mut adcx = cx.adcx(); if list.is_empty() { @@ -93,7 +89,7 @@ pub fn parse_cfg_entry( MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() { ArgParser::List(list) => match meta.path().word_sym() { Some(sym::not) => { - let Some(single) = list.single() else { + let Some(single) = list.as_single() else { return Err(cx.adcx().expected_single_argument(list.span, list.len())); }; CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span) @@ -136,7 +132,7 @@ fn parse_cfg_entry_version( meta_span: Span, ) -> Result { try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option()); - let Some(version) = list.single() else { + let Some(version) = list.as_single() else { return Err( cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span }) ); diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 357be2f48f85..ceb4da3df6a2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -24,7 +24,7 @@ impl SingleAttributeParser for OptimizeParser { const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_single_element_list(args, cx.attr_span)?; let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) { Some(sym::size) => OptimizeAttr::Size, @@ -75,7 +75,7 @@ impl SingleAttributeParser for CoverageParser { const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let arg = cx.single_element_list(args, cx.attr_span)?; + let arg = cx.expect_single_element_list(args, cx.attr_span)?; let mut fail_incorrect_argument = |span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]); @@ -371,8 +371,7 @@ impl AttributeParser for UsedParser { let used_by = match args { ArgParser::NoArgs => UsedBy::Default, ArgParser::List(list) => { - let Some(l) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); + let Some(l) = cx.expect_single(list) else { return; }; @@ -463,9 +462,7 @@ fn parse_tf_attribute( args: &ArgParser, ) -> impl IntoIterator { let mut features = Vec::new(); - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return features; }; if list.is_empty() { @@ -588,11 +585,7 @@ impl SingleAttributeParser for SanitizeParser { ]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; let mut on_set = SanitizerSet::empty(); let mut off_set = SanitizerSet::empty(); @@ -719,11 +712,7 @@ impl SingleAttributeParser for PatchableFunctionEntryParser { const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(meta_item_list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let meta_item_list = cx.expect_list(args, cx.attr_span)?; let mut prefix = None; let mut entry = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 4041ce85fa98..4aa6468be889 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -12,11 +12,7 @@ impl AttributeParser for ConfusablesParser { &[sym::rustc_confusables], template!(List: &[r#""name1", "name2", ..."#]), |this, cx, args| { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return; - }; + let Some(list) = cx.expect_list(args, cx.attr_span) else { return }; if list.is_empty() { cx.emit_err(EmptyConfusables { span: cx.attr_span }); diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 3739461c2004..451e126dd5c6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -314,9 +314,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return Vec::new(); }; @@ -362,9 +360,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return Vec::new(); }; diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index 65e9b968e946..f31cf7008544 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -20,7 +20,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_single_element_list(args, cx.attr_span)?; let Some(mi) = single.meta_item() else { cx.adcx().expected_name_value(single.span(), None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 32d73ff32361..1580cc2b3175 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -304,7 +304,7 @@ fn parse_directive_items<'p, S: Stage>( } (Mode::RustcOnUnimplemented, sym::on) => { if is_root { - let items = or_malformed!(item.args().list()?); + let items = or_malformed!(item.args().as_list()?); let mut iter = items.mixed(); let condition: &MetaItemOrLitParser = match iter.next() { Some(c) => c, @@ -478,7 +478,7 @@ fn parse_predicate(input: &MetaItemOrLitParser) -> Result Ok(Predicate::Any(parse_predicate_sequence(mis)?)), sym::all => Ok(Predicate::All(parse_predicate_sequence(mis)?)), sym::not => { - if let Some(single) = mis.single() { + if let Some(single) = mis.as_single() { Ok(Predicate::Not(Box::new(parse_predicate(single)?))) } else { Err(InvalidOnClause::ExpectedOnePredInNot { span: mis.span }) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 2b6d56c41193..a2e6062108ac 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -199,7 +199,7 @@ fn parse_single_test_doc_attr_item( self.attribute.no_crate_inject = Some(path.span()) } Some(sym::attr) => { - let Some(list) = args.list() else { + let Some(list) = args.as_list() else { // FIXME: remove this method once merged and uncomment the line below instead. // cx.expected_list(cx.attr_span, args); let span = cx.attr_span; @@ -587,7 +587,7 @@ macro_rules! string_arg_and_crate_level { }), Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args), Some(sym::test) => { - let Some(list) = args.list() else { + let Some(list) = args.as_list() else { cx.emit_dyn_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| DocTestTakesList.into_diag(dcx, level), diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 32f995753bad..0fc226add012 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -37,10 +37,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), ArgParser::List(list) => { - let Some(l) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); - return None; - }; + let l = cx.expect_single(list)?; match l.meta_item().and_then(|i| i.path().word_sym()) { Some(sym::always) => { @@ -78,10 +75,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option None, ArgParser::List(list) => { - let Some(l) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); - return None; - }; + let l = cx.expect_single(list)?; let Some(reason) = l.lit().and_then(|i| i.kind.str()) else { cx.adcx().expected_string_literal(l.span(), l.lit()); diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs index 36e45a763e17..8a182959f95d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs +++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs @@ -19,7 +19,7 @@ impl SingleAttributeParser for InstructionSetParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { const POSSIBLE_SYMBOLS: &[Symbol] = &[sym::arm_a32, sym::arm_t32]; const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32]; - let maybe_meta_item = cx.single_element_list(args, cx.attr_span)?; + let maybe_meta_item = cx.expect_single_element_list(args, cx.attr_span)?; let Some(meta_item) = maybe_meta_item.meta_item() else { cx.adcx().expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS); diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 9f48f7f8ab55..ca14e993e5e8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -390,7 +390,7 @@ fn parse_link_cfg( cx.adcx().duplicate_key(item.span(), sym::cfg); return true; } - let Some(link_cfg) = cx.single_element_list(item.args(), item.span()) else { + let Some(link_cfg) = cx.expect_single_element_list(item.args(), item.span()) else { return true; }; if !features.link_cfg() { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 7dcf1b3eb064..f23694a84c4d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -142,7 +142,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option false, ArgParser::List(list) => { - let Some(l) = list.single() else { + let Some(l) = list.as_single() else { cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); return None; }; @@ -174,7 +174,7 @@ impl SingleAttributeParser for CollapseDebugInfoParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_single_element_list(args, cx.attr_span)?; let Some(mi) = single.meta_item() else { cx.adcx().expected_not_literal(single.span()); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index 76dc171c6831..e57a34e7888a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -57,7 +57,7 @@ fn parse_derive_like( args: &ArgParser, trait_name_mandatory: bool, ) -> Option<(Option, ThinVec)> { - let Some(list) = args.list() else { + let Some(list) = args.as_list() else { // For #[rustc_builtin_macro], it is permitted to leave out the trait name if args.no_args().is_ok() && !trait_name_mandatory { return Some((None, ThinVec::new())); @@ -101,10 +101,7 @@ fn parse_derive_like( cx.adcx().expected_specific_argument(attrs.span(), &[sym::attributes]); return None; } - let Some(attr_list) = attr_list.args().list() else { - cx.adcx().expected_list(attrs.span(), attr_list.args()); - return None; - }; + let attr_list = cx.expect_list(attr_list.args(), attrs.span())?; // Parse item in `attributes(...)` argument for attr in attr_list.mixed() { diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index b6110f627a8c..1778c68832a3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -22,11 +22,7 @@ impl SingleAttributeParser for CustomMirParser { const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; let mut dialect = None; let mut phase = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 71a41384d213..a90fa7d749f8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -32,9 +32,7 @@ fn extend( ) -> impl IntoIterator { let mut reprs = Vec::new(); - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return reprs; }; @@ -197,7 +195,7 @@ fn parse_repr_align( ) -> Option { use AlignKind::*; - let Some(align) = list.single() else { + let Some(align) = list.as_single() else { match align_kind { Packed => { cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { @@ -296,8 +294,7 @@ fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParse cx.adcx().expected_list(attr_span, args); } ArgParser::List(list) => { - let Some(align) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); + let Some(align) = cx.expect_single(list) else { return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index e6f97683c612..3a9eb71f3136 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -96,9 +96,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let ArgParser::List(items) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(items) = cx.expect_list(args, cx.attr_span) else { return vec![]; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 3f4049366f40..1d35923339eb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -30,11 +30,7 @@ impl SingleAttributeParser for RustcMustImplementOneOfParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(list) = args.list() else { - let span = cx.attr_span; - cx.adcx().expected_list(span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; let mut fn_names = ThinVec::new(); @@ -130,11 +126,7 @@ impl SingleAttributeParser for RustcLegacyConstGenericsParser { const TEMPLATE: AttributeTemplate = template!(List: &["N"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let ArgParser::List(meta_items) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let meta_items = cx.expect_list(args, cx.attr_span)?; let mut parsed_indexes = ThinVec::new(); let mut errored = false; @@ -185,7 +177,7 @@ impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]); const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let arg = cx.single_element_list(args, cx.attr_span)?; + let arg = cx.expect_single_element_list(args, cx.attr_span)?; let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg else { @@ -210,11 +202,7 @@ fn parse_cgu_fields( args: &ArgParser, accepts_kind: bool, ) -> Option<(Symbol, Symbol, Option)> { - let Some(args) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let args = cx.expect_list(args, cx.attr_span)?; let mut cfg = None::<(Symbol, Span)>; let mut module = None::<(Symbol, Span)>; @@ -359,7 +347,7 @@ impl SingleAttributeParser for RustcDeprecatedSafe2024Parser { const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_single_element_list(args, cx.attr_span)?; let Some(arg) = single.meta_item() else { cx.adcx().expected_name_value(single.span(), None); @@ -418,11 +406,7 @@ impl SingleAttributeParser for RustcNeverTypeOptionsParser { ]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; let mut fallback = None::; let mut diverging_block_default = None::; @@ -703,9 +687,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return ThinVec::new(); }; @@ -825,11 +807,8 @@ fn extend( if !cx.cx.sess.opts.unstable_opts.query_dep_graph { cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" }); } - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; + let mut except = None; let mut loaded_from_disk = None; let mut cfg = None; @@ -926,11 +905,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)), ArgParser::List(list) => { - let Some(item) = list.single() else { - let attr_span = cx.attr_span; - cx.adcx().expected_single_argument(attr_span, list.len()); - return None; - }; + let item = cx.expect_single(list)?; let Some(ident) = item.meta_item().and_then(|item| item.ident()) else { cx.adcx().expected_identifier(item.span()); return None; @@ -988,7 +963,7 @@ fn extend( if !cx.cx.sess.opts.unstable_opts.query_dep_graph { cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" }); } - let item = cx.single_element_list(args, cx.attr_span)?; + let item = cx.expect_single_element_list(args, cx.attr_span)?; let Some(ident) = item.meta_item().and_then(|item| item.ident()) else { cx.adcx().expected_identifier(item.span()); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 0559469bc369..f6f964fb4d69 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -311,11 +311,7 @@ pub(crate) fn parse_stability( let mut feature = None; let mut since = None; - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; for param in list.mixed() { let param_span = param.span(); @@ -383,11 +379,7 @@ pub(crate) fn parse_unstability( let mut implied_by = None; let mut old_name = None; - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; for param in list.mixed() { let Some(param) = param.meta_item() else { @@ -503,11 +495,7 @@ fn extend( return None; } - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; for param in list.mixed() { let Some(param) = param.meta_item() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 06087c8a4baa..456b29d0c3aa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -28,10 +28,11 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let help = list.single().and_then(|item| item.meta_item()).and_then(|item| { - item.args().no_args().ok()?; - Some(item.path().to_string()) - }); + let help = + list.as_single().and_then(|item| item.meta_item()).and_then(|item| { + item.args().no_args().ok()?; + Some(item.path().to_string()) + }); cx.adcx().warn_ill_formed_attribute_input_with_help( ILL_FORMED_ATTRIBUTE_INPUT, help, @@ -71,10 +72,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(single) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); - return None; - }; + let single = cx.expect_single(list)?; let Some(single) = single.meta_item() else { cx.adcx().expected_name_value(single.span(), Some(sym::expected)); return None; @@ -140,17 +138,13 @@ impl SingleAttributeParser for RustcAbiParser { ]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(args) = args.list() else { + let Some(args) = args.as_list() else { let attr_span = cx.attr_span; cx.adcx().expected_specific_argument_and_list(attr_span, &[sym::assert_eq, sym::debug]); return None; }; - let Some(arg) = args.single() else { - let attr_span = cx.attr_span; - cx.adcx().expected_single_argument(attr_span, args.len()); - return None; - }; + let arg = cx.expect_single(args)?; let mut fail_incorrect_argument = |span| cx.adcx().expected_specific_argument(span, &[sym::assert_eq, sym::debug]); @@ -203,7 +197,7 @@ impl SingleAttributeParser for TestRunnerParser { const TEMPLATE: AttributeTemplate = template!(List: &["path"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_single_element_list(args, cx.attr_span)?; let Some(meta) = single.meta_item() else { cx.adcx().expected_not_literal(single.span()); diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index b2a9addfeab3..d3eb62a4c60d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -17,11 +17,7 @@ impl SingleAttributeParser for RustcSkipDuringMethodDispatchParser fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let mut array = false; let mut boxed_slice = false; - let Some(args) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let args = cx.expect_list(args, cx.attr_span)?; if args.is_empty() { cx.adcx().expected_at_least_one_argument(args.span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 98f8cc23b500..1f91b1a58309 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -41,7 +41,7 @@ pub(crate) fn parse_single_integer( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_single_element_list(args, cx.attr_span)?; let Some(lit) = single.lit() else { cx.adcx().expected_integer_literal(single.span()); return None; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 5ced5d5f975a..af4e0155e0ab 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -61,7 +61,7 @@ use crate::attributes::traits::*; use crate::attributes::transparency::*; use crate::attributes::{AttributeParser as _, AttributeSafety, Combine, Single, WithoutArgs}; -use crate::parser::{ArgParser, MetaItemOrLitParser, RefPathParser}; +use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, RefPathParser}; use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions, ParsedDescription, @@ -554,7 +554,7 @@ pub(crate) fn adcx(&mut self) -> AttributeDiagnosticContext<'_, 'f, 'sess, S> { /// /// The provided span is used as a fallback for diagnostic generation in case `arg` does not /// contain any. It should be the span of the node that contains `arg`. - pub(crate) fn single_element_list<'arg>( + pub(crate) fn expect_single_element_list<'arg>( &mut self, arg: &'arg ArgParser, span: Span, @@ -564,13 +564,36 @@ pub(crate) fn single_element_list<'arg>( return None; }; - let Some(single) = l.single() else { + let Some(single) = l.as_single() else { self.adcx().expected_single_argument(l.span, l.len()); return None; }; Some(single) } + + pub(crate) fn expect_list<'arg>( + &mut self, + args: &'arg ArgParser, + span: Span, + ) -> Option<&'arg MetaItemListParser> { + let list = args.as_list(); + if list.is_none() { + self.adcx().expected_list(span, args); + } + list + } + + pub(crate) fn expect_single<'arg>( + &mut self, + list: &'arg MetaItemListParser, + ) -> Option<&'arg MetaItemOrLitParser> { + let single = list.as_single(); + if single.is_none() { + self.adcx().expected_single_argument(list.span, list.len()); + } + single + } } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a7daec6d6096..3883b1107566 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -176,7 +176,7 @@ pub fn from_attr_args<'sess>( /// /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list - pub fn list(&self) -> Option<&MetaItemListParser> { + pub fn as_list(&self) -> Option<&MetaItemListParser> { match self { Self::List(l) => Some(l), Self::NameValue(_) | Self::NoArgs => None, @@ -694,7 +694,7 @@ pub fn is_empty(&self) -> bool { /// Returns Some if the list contains only a single element. /// /// Inside the Some is the parser to parse this single element. - pub fn single(&self) -> Option<&MetaItemOrLitParser> { + pub fn as_single(&self) -> Option<&MetaItemOrLitParser> { let mut iter = self.mixed(); iter.next().filter(|_| iter.next().is_none()) } From 067ef3df9cd99506714228a78a3bd29ca4c044e1 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Mon, 20 Apr 2026 09:08:37 +0000 Subject: [PATCH 12/18] Add documentation for higher-level attribute parsing API --- compiler/rustc_attr_parsing/src/context.rs | 23 ++++++++++++++++++++++ compiler/rustc_attr_parsing/src/parser.rs | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index af4e0155e0ab..cebbabfcbf1b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -572,6 +572,20 @@ pub(crate) fn expect_single_element_list<'arg>( Some(single) } + /// Asserts that an [`ArgParser`] is a list and returns it, or emits an error and returns + /// `None`. + /// + /// Some examples: + /// + /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list + /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list + /// + /// This is a higher-level (and harder to misuse) wrapper over [`ArgParser::as_list`]. That + /// allows using `?` when the attribute parsing function allows it. You may still want to use + /// [`ArgParser::as_list`] for the following reasons: + /// + /// - You want to emit your own diagnostics (for instance, with [`SharedContext::emit_err`]). + /// - The attribute can be parsed in multiple ways and it does not make sense to emit an error. pub(crate) fn expect_list<'arg>( &mut self, args: &'arg ArgParser, @@ -584,6 +598,15 @@ pub(crate) fn expect_list<'arg>( list } + /// Asserts that a [`MetaItemListParser`] contains a single element and returns it, or emits an + /// error and returns `None`. + /// + /// This is a higher-level (and harder to misuse) wrapper over [`MetaItemListParser::as_single`]. + /// That allows using `?` to early return. You may still want to use + /// [`MetaItemListParser::as_single`] for the following reasons: + /// + /// - You want to emit your own diagnostics (for instance, with [`SharedContext::emit_err`]). + /// - The attribute can be parsed in multiple ways and it does not make sense to emit an error. pub(crate) fn expect_single<'arg>( &mut self, list: &'arg MetaItemListParser, diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 3883b1107566..ce2367006128 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -255,6 +255,7 @@ pub fn meta_item(&self) -> Option<&MetaItemParser> { } } +// FIXME(scrabsha): once #155696 is merged, update this and mention the higher-level APIs. /// Utility that deconstructs a MetaItem into usable parts. /// /// MetaItems are syntactically extremely flexible, but specific attributes want to parse @@ -263,7 +264,7 @@ pub fn meta_item(&self) -> Option<&MetaItemParser> { /// MetaItems consist of some path, and some args. The args could be empty. In other words: /// /// - `name` -> args are empty -/// - `name(...)` -> args are a [`list`](ArgParser::list), which is the bit between the parentheses +/// - `name(...)` -> args are a [`list`](ArgParser::as_list), which is the bit between the parentheses /// - `name = value`-> arg is [`name_value`](ArgParser::name_value), where the argument is the /// `= value` part /// From 45b4e3c52bd48434b7d140ea109228c9610c5072 Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 5 Apr 2026 06:11:36 +0800 Subject: [PATCH 13/18] Fix ICE of trying to get span from all attrs --- compiler/rustc_hir/src/hir.rs | 9 ++++ compiler/rustc_hir_typeck/src/expr.rs | 20 +-------- compiler/rustc_lint/src/context.rs | 7 +--- .../cfg-attr-parsed-span-issue-154801.rs | 11 +++++ .../cfg-attr-parsed-span-issue-154801.stderr | 42 +++++++++++++++++++ 5 files changed, 64 insertions(+), 25 deletions(-) create mode 100644 tests/ui/conditional-compilation/cfg-attr-parsed-span-issue-154801.rs create mode 100644 tests/ui/conditional-compilation/cfg-attr-parsed-span-issue-154801.stderr diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 5608bd82fdac..dad08e0bc92f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1304,6 +1304,15 @@ pub fn is_parsed_attr(&self) -> bool { Attribute::Unparsed(_) => false, } } + + pub fn is_prefix_attr_for_suggestions(&self) -> bool { + match self { + Attribute::Unparsed(attr) => attr.span.desugaring_kind().is_none(), + // Other parsed attributes that can appear on expressions originate from source and + // should make suggestions treat the expression like a prefixed form. + Attribute::Parsed(_) => true, + } + } } impl AttributeExt for Attribute { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index ac77354f2a79..71c02dc32f6b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -57,25 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence { let has_attr = |id: HirId| -> bool { - for attr in self.tcx.hir_attrs(id) { - // For the purpose of rendering suggestions, disregard attributes - // that originate from desugaring of any kind. For example, `x?` - // desugars to `#[allow(unreachable_code)] match ...`. Failing to - // ignore the prefix attribute in the desugaring would cause this - // suggestion: - // - // let y: u32 = x?.try_into().unwrap(); - // ++++++++++++++++++++ - // - // to be rendered as: - // - // let y: u32 = (x?).try_into().unwrap(); - // + +++++++++++++++++++++ - if attr.span().desugaring_kind().is_none() { - return true; - } - } - false + self.tcx.hir_attrs(id).iter().any(hir::Attribute::is_prefix_attr_for_suggestions) }; // Special case: range expressions are desugared to struct literals in HIR, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 46aeec65fe2d..352652413751 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -845,12 +845,7 @@ pub fn get_associated_type( /// be used for pretty-printing HIR by rustc_hir_pretty. pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence { let has_attr = |id: hir::HirId| -> bool { - for attr in self.tcx.hir_attrs(id) { - if attr.span().desugaring_kind().is_none() { - return true; - } - } - false + self.tcx.hir_attrs(id).iter().any(hir::Attribute::is_prefix_attr_for_suggestions) }; expr.precedence(&has_attr) } diff --git a/tests/ui/conditional-compilation/cfg-attr-parsed-span-issue-154801.rs b/tests/ui/conditional-compilation/cfg-attr-parsed-span-issue-154801.rs new file mode 100644 index 000000000000..2264d2ba44a8 --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-attr-parsed-span-issue-154801.rs @@ -0,0 +1,11 @@ +fn main() { + let _x = 30; + #[cfg_attr(, (cc))] //~ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `,` + _x //~ ERROR mismatched types +} + +fn inline_case() { + let _x = 30; + #[inline] //~ ERROR `#[inline]` attribute cannot be used on expressions + _x //~ ERROR mismatched types +} diff --git a/tests/ui/conditional-compilation/cfg-attr-parsed-span-issue-154801.stderr b/tests/ui/conditional-compilation/cfg-attr-parsed-span-issue-154801.stderr new file mode 100644 index 000000000000..ee62d232b12a --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-attr-parsed-span-issue-154801.stderr @@ -0,0 +1,42 @@ +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `,` + --> $DIR/cfg-attr-parsed-span-issue-154801.rs:3:16 + | +LL | #[cfg_attr(, (cc))] + | ^ + | + = note: for more information, visit +help: must be of the form + | +LL - #[cfg_attr(, (cc))] +LL + #[cfg_attr(predicate, attr1, attr2, ...)] + | + +error: `#[inline]` attribute cannot be used on expressions + --> $DIR/cfg-attr-parsed-span-issue-154801.rs:9:5 + | +LL | #[inline] + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + +error[E0308]: mismatched types + --> $DIR/cfg-attr-parsed-span-issue-154801.rs:4:5 + | +LL | fn main() { + | - expected `()` because of default return type +... +LL | _x + | ^^ expected `()`, found integer + +error[E0308]: mismatched types + --> $DIR/cfg-attr-parsed-span-issue-154801.rs:10:5 + | +LL | fn inline_case() { + | - help: try adding a return type: `-> i32` +... +LL | _x + | ^^ expected `()`, found integer + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From ff73b8ac2b6d67bb8ec24690d748d179d53745cd Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 25 Apr 2026 10:10:45 +0200 Subject: [PATCH 14/18] triagebot.toml: Ping Enselic when tests/debuginfo/basic-stepping.rs changes The test `tests/debuginfo/basic-stepping.rs` has a history of regressing for subtle reasons, and has non-obvious expectations. So I'd like to keep an extra eye on it. --- triagebot.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index b0bf55a9248f..dee80752930b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1345,6 +1345,9 @@ cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] [mentions."tests/codegen-llvm/stack-protector.rs"] cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] +[mentions."tests/debuginfo/basic-stepping.rs"] +cc = ["@Enselic"] + [mentions."tests/ui/sanitizer"] cc = ["@rcvalle"] From b17822575ce06e8d7caa907a7687a2ded0999c05 Mon Sep 17 00:00:00 2001 From: Qai Juang <237468078+qaijuang@users.noreply.github.com> Date: Sat, 25 Apr 2026 11:47:34 -0400 Subject: [PATCH 15/18] Do not suggest internal cfg trace attributes --- compiler/rustc_resolve/src/diagnostics.rs | 5 +++++ tests/ui/suggestions/attribute-typos.rs | 7 +++++++ tests/ui/suggestions/attribute-typos.stderr | 14 +++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index a92ed9cd3ae8..cbec647bdc95 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1281,6 +1281,11 @@ pub(crate) fn add_scope_set_candidates( suggestions.extend( BUILTIN_ATTRIBUTES .iter() + // These trace attributes are compiler-generated and have + // deliberately invalid names. + .filter(|attr| { + !matches!(attr.name, sym::cfg_trace | sym::cfg_attr_trace) + }) .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)), ); } diff --git a/tests/ui/suggestions/attribute-typos.rs b/tests/ui/suggestions/attribute-typos.rs index 4c2336e105e2..6dbfb1df5876 100644 --- a/tests/ui/suggestions/attribute-typos.rs +++ b/tests/ui/suggestions/attribute-typos.rs @@ -8,4 +8,11 @@ fn bar() {} //~^ ERROR cannot find attribute `rustc_dumm` in this scope //~| ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler +// Regression test for https://github.com/rust-lang/rust/issues/150566. +#[cfg_trace] //~ ERROR cannot find attribute `cfg_trace` in this scope +fn cfg_trace_attr() {} + +#[cfg_attr_trace] //~ ERROR cannot find attribute `cfg_attr_trace` in this scope +fn cfg_attr_trace_attr() {} + fn main() {} diff --git a/tests/ui/suggestions/attribute-typos.stderr b/tests/ui/suggestions/attribute-typos.stderr index 960e0b0f620f..7ca425fa9bd6 100644 --- a/tests/ui/suggestions/attribute-typos.stderr +++ b/tests/ui/suggestions/attribute-typos.stderr @@ -4,6 +4,12 @@ error: attributes starting with `rustc` are reserved for use by the `rustc` comp LL | #[rustc_dumm] | ^^^^^^^^^^ +error: cannot find attribute `cfg_attr_trace` in this scope + --> $DIR/attribute-typos.rs:15:3 + | +LL | #[cfg_attr_trace] + | ^^^^^^^^^^^^^^ + error: cannot find attribute `rustc_dumm` in this scope --> $DIR/attribute-typos.rs:7:3 | @@ -15,6 +21,12 @@ help: a built-in attribute with a similar name exists LL | #[rustc_dummy] | + +error: cannot find attribute `cfg_trace` in this scope + --> $DIR/attribute-typos.rs:12:3 + | +LL | #[cfg_trace] + | ^^^^^^^^^ + error: cannot find attribute `tests` in this scope --> $DIR/attribute-typos.rs:4:3 | @@ -41,5 +53,5 @@ help: a built-in attribute with a similar name exists LL | #[deprecated] | + -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors From a4f5c6e9715f4f4198ce358204948f02ba8ee807 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 9 Apr 2026 21:42:34 +0200 Subject: [PATCH 16/18] error on invalid macho section specifier --- .../src/attributes/link_attrs.rs | 40 ++++++++++++- .../src/session_diagnostics.rs | 19 ++++++ .../rustc_hir/src/attrs/data_structures.rs | 2 +- tests/codegen-llvm/link_section.rs | 18 +++--- .../codegen-llvm/naked-fn/naked-functions.rs | 9 ++- tests/rustdoc-html/attributes-2021-edition.rs | 4 +- tests/rustdoc-html/attributes.rs | 1 + tests/rustdoc-html/inline_cross/attributes.rs | 2 +- .../inline_cross/auxiliary/attributes.rs | 2 +- tests/rustdoc-json/attrs/link_section_2021.rs | 4 +- tests/rustdoc-json/attrs/link_section_2024.rs | 4 +- tests/ui/asm/naked-functions.rs | 7 ++- tests/ui/attributes/attr-on-mac-call.rs | 2 +- tests/ui/attributes/attr-on-mac-call.stderr | 4 +- .../codegen_attr_on_required_trait_method.rs | 2 +- ...degen_attr_on_required_trait_method.stderr | 4 +- .../issue-43106-gating-of-builtin-attrs.rs | 26 ++++----- ...issue-43106-gating-of-builtin-attrs.stderr | 32 +++++----- tests/ui/linkage-attr/link-section-macho.rs | 58 +++++++++++++++++++ .../ui/linkage-attr/link-section-macho.stderr | 37 ++++++++++++ .../ui/linkage-attr/link-section-placement.rs | 53 ++++++++--------- tests/ui/lint/lint-unsafe-code.rs | 4 +- tests/ui/lint/lint-unsafe-code.stderr | 8 +-- tests/ui/lint/unused/unused-attr-duplicate.rs | 11 ++-- .../lint/unused/unused-attr-duplicate.stderr | 48 +++++++-------- .../unsafe-attributes-fix.fixed | 10 ++-- .../unsafe-attributes-fix.rs | 10 ++-- .../unsafe-attributes-fix.stderr | 4 +- 28 files changed, 292 insertions(+), 133 deletions(-) create mode 100644 tests/ui/linkage-attr/link-section-macho.rs create mode 100644 tests/ui/linkage-attr/link-section-macho.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 9f48f7f8ab55..b563ca535428 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -16,8 +16,9 @@ use crate::session_diagnostics::{ AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic, ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier, - LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers, - NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic, + InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, LinkOrdinalOutOfRange, + LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, + WholeArchiveNeedsStatic, }; pub(crate) struct LinkNameParser; @@ -462,6 +463,29 @@ fn parse_link_import_name_type( pub(crate) struct LinkSectionParser; +fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReason> { + let mut parts = name.as_str().split(',').map(|s| s.trim()); + + // The segment can be empty. + let _segment = parts.next(); + + // But the section is required. + let section = match parts.next() { + None | Some("") => return Err(InvalidMachoSectionReason::MissingSection), + Some(section) => section, + }; + + if section.len() > 16 { + return Err(InvalidMachoSectionReason::SectionTooLong { section: section.to_string() }); + } + + // LLVM also checks the other components of the section specifier, but that logic is hard to + // keep in sync. We skip it here for now, assuming that if you got that far you'll be able + // to interpret the LLVM errors. + + Ok(()) +} + impl SingleAttributeParser for LinkSectionParser { const PATH: &[Symbol] = &[sym::link_section]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; @@ -495,6 +519,18 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option match check_link_section_macho(name) { + Ok(()) => {} + Err(reason) => { + cx.emit_err(InvalidMachoSection { name_span: nv.value_span, reason }); + return None; + } + }, + BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Wasm | BinaryFormat::Xcoff => {} + } + Some(LinkSection { name, span: cx.attr_span }) } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 203c7f8ebff1..0a9c96033257 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -1137,3 +1137,22 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature { #[label("the stability attribute annotates this item")] pub item_span: Span, } + +#[derive(Diagnostic)] +#[diag("invalid Mach-O section specifier")] +pub(crate) struct InvalidMachoSection { + #[primary_span] + #[label("not a valid Mach-O section specifier")] + pub name_span: Span, + #[subdiagnostic] + pub reason: InvalidMachoSectionReason, +} + +#[derive(Subdiagnostic)] +pub(crate) enum InvalidMachoSectionReason { + #[note("a Mach-O section specifier requires a segment and a section, separated by a comma")] + #[help("an example of a valid Mach-O section specifier is `__TEXT,__cstring`")] + MissingSection, + #[note("section name `{$section}` is longer than 16 bytes")] + SectionTooLong { section: String }, +} diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 78ce2f019a39..6304b830f6ed 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1098,8 +1098,8 @@ pub enum AttributeKind { /// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute) LinkSection { - name: Symbol, span: Span, + name: Symbol, }, /// Represents `#[linkage]`. diff --git a/tests/codegen-llvm/link_section.rs b/tests/codegen-llvm/link_section.rs index f62f69480793..f196ea86c447 100644 --- a/tests/codegen-llvm/link_section.rs +++ b/tests/codegen-llvm/link_section.rs @@ -3,14 +3,14 @@ #![crate_type = "lib"] -// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section ".test_one" +// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section "__TEST,one" #[no_mangle] -#[link_section = ".test_one"] +#[link_section = "__TEST,one"] #[cfg(target_endian = "little")] pub static VAR1: u32 = 1; #[no_mangle] -#[link_section = ".test_one"] +#[link_section = "__TEST,one"] #[cfg(target_endian = "big")] pub static VAR1: u32 = 0x01000000; @@ -19,17 +19,17 @@ pub enum E { B(f32), } -// CHECK: @VAR2 = {{(dso_local )?}}constant {{.*}}, section ".test_two" +// CHECK: @VAR2 = {{(dso_local )?}}constant {{.*}}, section "__TEST,two" #[no_mangle] -#[link_section = ".test_two"] +#[link_section = "__TEST,two"] pub static VAR2: E = E::A(666); -// CHECK: @VAR3 = {{(dso_local )?}}constant {{.*}}, section ".test_three" +// CHECK: @VAR3 = {{(dso_local )?}}constant {{.*}}, section "__TEST,three" #[no_mangle] -#[link_section = ".test_three"] +#[link_section = "__TEST,three"] pub static VAR3: E = E::B(1.); -// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section ".test_four" { +// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section "__TEST,four" { #[no_mangle] -#[link_section = ".test_four"] +#[link_section = "__TEST,four"] pub fn fn1() {} diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs index a782ab5310e3..dba77cd0e536 100644 --- a/tests/codegen-llvm/naked-fn/naked-functions.rs +++ b/tests/codegen-llvm/naked-fn/naked-functions.rs @@ -22,7 +22,7 @@ //@[thumb] needs-llvm-components: arm #![crate_type = "lib"] -#![feature(no_core, lang_items, rustc_attrs)] +#![feature(no_core, lang_items, rustc_attrs, cfg_target_object_format)] #![no_core] extern crate minicore; @@ -170,14 +170,17 @@ pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { } // linux,linux_no_function_sections: .pushsection .text.some_different_name,\22ax\22, @progbits -// macos: .pushsection .text.some_different_name,regular,pure_instructions +// macos: .pushsection __TEXT,different,regular,pure_instructions // win_x86_msvc,win_x86_gnu,win_i686_gnu: .section .text.some_different_name,\22xr\22 // win_x86_gnu_function_sections: .section .text.some_different_name,\22xr\22 // thumb: .pushsection .text.some_different_name,\22ax\22, %progbits // CHECK-LABEL: test_link_section: #[no_mangle] #[unsafe(naked)] -#[link_section = ".text.some_different_name"] +#[link_section = cfg_select!( + target_object_format = "mach-o" => "__TEXT,different", + _ => ".text.some_different_name" +)] pub extern "C" fn test_link_section() { cfg_select! { all(target_arch = "arm", target_feature = "thumb-mode") => { diff --git a/tests/rustdoc-html/attributes-2021-edition.rs b/tests/rustdoc-html/attributes-2021-edition.rs index b5028d8c8525..40d6dda508a5 100644 --- a/tests/rustdoc-html/attributes-2021-edition.rs +++ b/tests/rustdoc-html/attributes-2021-edition.rs @@ -9,6 +9,6 @@ pub extern "C" fn f() {} #[export_name = "bar"] pub extern "C" fn g() {} -//@ has foo/fn.example.html '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".text")]' -#[link_section = ".text"] +//@ has foo/fn.example.html '//pre[@class="rust item-decl"]' '#[unsafe(link_section = "__TEXT,__text")]' +#[link_section = "__TEXT,__text"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-html/attributes.rs b/tests/rustdoc-html/attributes.rs index 6032c3d38801..8a6dd5ab33d5 100644 --- a/tests/rustdoc-html/attributes.rs +++ b/tests/rustdoc-html/attributes.rs @@ -1,4 +1,5 @@ //@ edition: 2024 +//@ only-linux #![crate_name = "foo"] //@ has foo/fn.f.html '//*[@class="code-attribute"]' '#[unsafe(no_mangle)]' diff --git a/tests/rustdoc-html/inline_cross/attributes.rs b/tests/rustdoc-html/inline_cross/attributes.rs index 1657b7bdc8f7..324686a33612 100644 --- a/tests/rustdoc-html/inline_cross/attributes.rs +++ b/tests/rustdoc-html/inline_cross/attributes.rs @@ -9,7 +9,7 @@ pub use attributes::no_mangle; //@ has 'user/fn.link_section.html' '//pre[@class="rust item-decl"]' \ -// '#[unsafe(link_section = ".here")]' +// '#[unsafe(link_section = "__TEXT,__here")]' pub use attributes::link_section; //@ has 'user/fn.export_name.html' '//pre[@class="rust item-decl"]' \ diff --git a/tests/rustdoc-html/inline_cross/auxiliary/attributes.rs b/tests/rustdoc-html/inline_cross/auxiliary/attributes.rs index 6068d3855858..efceda87165c 100644 --- a/tests/rustdoc-html/inline_cross/auxiliary/attributes.rs +++ b/tests/rustdoc-html/inline_cross/auxiliary/attributes.rs @@ -1,7 +1,7 @@ #[unsafe(no_mangle)] pub fn no_mangle() {} -#[unsafe(link_section = ".here")] +#[unsafe(link_section = "__TEXT,__here")] pub fn link_section() {} #[unsafe(export_name = "exonym")] diff --git a/tests/rustdoc-json/attrs/link_section_2021.rs b/tests/rustdoc-json/attrs/link_section_2021.rs index acd8ecd0e30c..82df8071592c 100644 --- a/tests/rustdoc-json/attrs/link_section_2021.rs +++ b/tests/rustdoc-json/attrs/link_section_2021.rs @@ -2,6 +2,6 @@ #![no_std] //@ count "$.index[?(@.name=='example')].attrs[*]" 1 -//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"' -#[link_section = ".text"] +//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '"__TEXT,__text"' +#[link_section = "__TEXT,__text"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/link_section_2024.rs b/tests/rustdoc-json/attrs/link_section_2024.rs index 8107493229b5..acf9406ce528 100644 --- a/tests/rustdoc-json/attrs/link_section_2024.rs +++ b/tests/rustdoc-json/attrs/link_section_2024.rs @@ -5,6 +5,6 @@ // However, the unsafe qualification is not shown by rustdoc. //@ count "$.index[?(@.name=='example')].attrs[*]" 1 -//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"' -#[unsafe(link_section = ".text")] +//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '"__TEXT,__text"' +#[unsafe(link_section = "__TEXT,__text")] pub extern "C" fn example() {} diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index dadacb8d4683..55f2f552ad31 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -3,7 +3,7 @@ //@ ignore-spirv //@ reference: attributes.codegen.naked.body -#![feature(asm_unwind, linkage, rustc_attrs)] +#![feature(asm_unwind, linkage, rustc_attrs, cfg_target_object_format)] #![crate_type = "lib"] use std::arch::{asm, naked_asm}; @@ -200,7 +200,10 @@ pub extern "C" fn compatible_must_use_attributes() -> u64 { } #[export_name = "exported_function_name"] -#[link_section = ".custom_section"] +#[link_section = cfg_select!( + target_object_format = "mach-o" => "__TEXT,__custom", + _ => ".custom", +)] #[unsafe(naked)] pub extern "C" fn compatible_ffi_attributes_1() { naked_asm!("", options(raw)); diff --git a/tests/ui/attributes/attr-on-mac-call.rs b/tests/ui/attributes/attr-on-mac-call.rs index a23ced123efb..577272a99a0d 100644 --- a/tests/ui/attributes/attr-on-mac-call.rs +++ b/tests/ui/attributes/attr-on-mac-call.rs @@ -27,7 +27,7 @@ fn main() { #[link_name = "x"] //~^ WARN attribute cannot be used on macro calls //~| WARN previously accepted - #[link_section = "x"] + #[link_section = "__TEXT,__text"] //~^ WARN attribute cannot be used on macro calls //~| WARN previously accepted #[link_ordinal(42)] diff --git a/tests/ui/attributes/attr-on-mac-call.stderr b/tests/ui/attributes/attr-on-mac-call.stderr index 3bb50f2d6f65..9fc4e319117f 100644 --- a/tests/ui/attributes/attr-on-mac-call.stderr +++ b/tests/ui/attributes/attr-on-mac-call.stderr @@ -78,8 +78,8 @@ LL | #[link_name = "x"] warning: `#[link_section]` attribute cannot be used on macro calls --> $DIR/attr-on-mac-call.rs:30:5 | -LL | #[link_section = "x"] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = "__TEXT,__text"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions and statics diff --git a/tests/ui/attributes/codegen_attr_on_required_trait_method.rs b/tests/ui/attributes/codegen_attr_on_required_trait_method.rs index 6301a5a8ebf7..cd9987f1e6a3 100644 --- a/tests/ui/attributes/codegen_attr_on_required_trait_method.rs +++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.rs @@ -7,7 +7,7 @@ trait Test { //~^ ERROR cannot be used on required trait methods [unused_attributes] //~| WARN previously accepted fn method1(&self); - #[link_section = ".text"] + #[link_section = "__TEXT,__text"] //~^ ERROR cannot be used on required trait methods [unused_attributes] //~| WARN previously accepted fn method2(&self); diff --git a/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr index 0770ccae4146..7b529440b008 100644 --- a/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr +++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr @@ -15,8 +15,8 @@ LL | #![deny(unused_attributes)] error: `#[link_section]` attribute cannot be used on required trait methods --> $DIR/codegen_attr_on_required_trait_method.rs:10:5 | -LL | #[link_section = ".text"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = "__TEXT,__text"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 36568449b82e..8f3e98cfc2a7 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -74,7 +74,7 @@ //~| WARN previously accepted //~| HELP can be applied to //~| HELP remove the attribute -#![link_section = "1800"] +#![link_section = ",1800"] //~^ WARN attribute cannot be used on //~| WARN previously accepted //~| HELP can be applied to @@ -616,66 +616,66 @@ mod inner { #![link_name="1900"] } //~| HELP remove the attribute } -#[link_section = "1800"] +#[link_section = ",1800"] //~^ WARN attribute cannot be used on //~| WARN previously accepted //~| HELP can be applied to //~| HELP remove the attribute mod link_section { - mod inner { #![link_section="1800"] } + mod inner { #![link_section=",1800"] } //~^ WARN attribute cannot be used on //~| WARN previously accepted //~| HELP can be applied to //~| HELP remove the attribute - #[link_section = "1800"] fn f() { } + #[link_section = ",1800"] fn f() { } - #[link_section = "1800"] struct S; + #[link_section = ",1800"] struct S; //~^ WARN attribute cannot be used on //~| WARN previously accepted //~| HELP can be applied to //~| HELP remove the attribute - #[link_section = "1800"] type T = S; + #[link_section = ",1800"] type T = S; //~^ WARN attribute cannot be used on //~| WARN previously accepted //~| HELP can be applied to //~| HELP remove the attribute - #[link_section = "1800"] impl S { } + #[link_section = ",1800"] impl S { } //~^ WARN attribute cannot be used on //~| WARN previously accepted //~| HELP can be applied to //~| HELP remove the attribute - #[link_section = "1800"] + #[link_section = ",1800"] //~^ WARN attribute cannot be used on //~| WARN previously accepted //~| HELP can be applied to //~| HELP remove the attribute trait Tr { - #[link_section = "1800"] + #[link_section = ",1800"] //~^ WARN attribute cannot be used on //~| WARN previously accepted //~| HELP can be applied to //~| HELP remove the attribute fn inside_tr_no_default(&self); - #[link_section = "1800"] + #[link_section = ",1800"] fn inside_tr_default(&self) { } } impl S { - #[link_section = "1800"] + #[link_section = ",1800"] fn inside_abc_123(&self) { } } impl Tr for S { - #[link_section = "1800"] + #[link_section = ",1800"] fn inside_tr_no_default(&self) { } } - #[link_section = "1800"] + #[link_section = ",1800"] fn should_always_link() { } } 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 724d623e79ee..f6ed182b17ef 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 @@ -866,8 +866,8 @@ LL | #[link_name = "1900"] impl S { } warning: `#[link_section]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:1 | -LL | #[link_section = "1800"] - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = ",1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions and statics @@ -875,8 +875,8 @@ LL | #[link_section = "1800"] warning: `#[link_section]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:625:17 | -LL | mod inner { #![link_section="1800"] } - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | mod inner { #![link_section=",1800"] } + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions and statics @@ -884,8 +884,8 @@ LL | mod inner { #![link_section="1800"] } warning: `#[link_section]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:5 | -LL | #[link_section = "1800"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = ",1800"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions and statics @@ -893,8 +893,8 @@ LL | #[link_section = "1800"] struct S; warning: `#[link_section]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 | -LL | #[link_section = "1800"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = ",1800"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions and statics @@ -902,8 +902,8 @@ LL | #[link_section = "1800"] type T = S; warning: `#[link_section]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:5 | -LL | #[link_section = "1800"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = ",1800"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions and statics @@ -911,8 +911,8 @@ LL | #[link_section = "1800"] impl S { } warning: `#[link_section]` attribute cannot be used on traits --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5 | -LL | #[link_section = "1800"] - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = ",1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions and statics @@ -920,8 +920,8 @@ LL | #[link_section = "1800"] warning: `#[link_section]` attribute cannot be used on required trait methods --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:9 | -LL | #[link_section = "1800"] - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = ",1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks @@ -1570,8 +1570,8 @@ LL | #![link_name = "1900"] warning: `#[link_section]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs.rs:77:1 | -LL | #![link_section = "1800"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![link_section = ",1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions and statics diff --git a/tests/ui/linkage-attr/link-section-macho.rs b/tests/ui/linkage-attr/link-section-macho.rs new file mode 100644 index 000000000000..b414a8cc1860 --- /dev/null +++ b/tests/ui/linkage-attr/link-section-macho.rs @@ -0,0 +1,58 @@ +//@ add-minicore +//@ compile-flags: --target aarch64-apple-darwin +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[unsafe(link_section = "foo")] +//~^ ERROR invalid Mach-O section specifier +#[unsafe(no_mangle)] +fn missing_section() {} + +#[unsafe(link_section = "foo,")] +//~^ ERROR invalid Mach-O section specifier +#[unsafe(no_mangle)] +fn empty_section() {} + +#[unsafe(link_section = "foo, ")] +//~^ ERROR invalid Mach-O section specifier +#[unsafe(no_mangle)] +fn whitespace_section() {} + +#[unsafe(link_section = "foo,somelongwindedthing")] +//~^ ERROR invalid Mach-O section specifier +#[unsafe(no_mangle)] +fn section_too_long() {} + +#[unsafe(link_section = "foo,bar")] +#[unsafe(no_mangle)] +fn segment_and_section() {} + +#[unsafe(link_section = "foo,bar,")] +#[unsafe(no_mangle)] +fn segment_and_section_and_comma() {} + +#[unsafe(link_section = ",foo")] +#[unsafe(no_mangle)] +fn missing_segment_is_fine() {} + +#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,16")] +#[unsafe(no_mangle)] +fn stub_size_decimal() {} + +#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,0x10")] +#[unsafe(no_mangle)] +fn stub_size_hex() {} + +#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,020")] +#[unsafe(no_mangle)] +fn stub_size_oct() {} + +#[unsafe(link_section = "__TEXT,__stubs,symbol_stubs,none,020,rest,is,ignored")] +#[unsafe(no_mangle)] +fn rest_is_ignored() {} diff --git a/tests/ui/linkage-attr/link-section-macho.stderr b/tests/ui/linkage-attr/link-section-macho.stderr new file mode 100644 index 000000000000..42eac39c7806 --- /dev/null +++ b/tests/ui/linkage-attr/link-section-macho.stderr @@ -0,0 +1,37 @@ +error: invalid Mach-O section specifier + --> $DIR/link-section-macho.rs:12:25 + | +LL | #[unsafe(link_section = "foo")] + | ^^^^^ not a valid Mach-O section specifier + | + = note: a Mach-O section specifier requires a segment and a section, separated by a comma + = help: an example of a valid Mach-O section specifier is `__TEXT,__cstring` + +error: invalid Mach-O section specifier + --> $DIR/link-section-macho.rs:17:25 + | +LL | #[unsafe(link_section = "foo,")] + | ^^^^^^ not a valid Mach-O section specifier + | + = note: a Mach-O section specifier requires a segment and a section, separated by a comma + = help: an example of a valid Mach-O section specifier is `__TEXT,__cstring` + +error: invalid Mach-O section specifier + --> $DIR/link-section-macho.rs:22:25 + | +LL | #[unsafe(link_section = "foo, ")] + | ^^^^^^^ not a valid Mach-O section specifier + | + = note: a Mach-O section specifier requires a segment and a section, separated by a comma + = help: an example of a valid Mach-O section specifier is `__TEXT,__cstring` + +error: invalid Mach-O section specifier + --> $DIR/link-section-macho.rs:27:25 + | +LL | #[unsafe(link_section = "foo,somelongwindedthing")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a valid Mach-O section specifier + | + = note: section name `somelongwindedthing` is longer than 16 bytes + +error: aborting due to 4 previous errors + diff --git a/tests/ui/linkage-attr/link-section-placement.rs b/tests/ui/linkage-attr/link-section-placement.rs index 6a143bfedb45..299ad31d82d0 100644 --- a/tests/ui/linkage-attr/link-section-placement.rs +++ b/tests/ui/linkage-attr/link-section-placement.rs @@ -2,37 +2,38 @@ //@ run-pass +#![feature(cfg_target_object_format)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] #![allow(non_upper_case_globals)] -#[cfg(not(target_vendor = "apple"))] -#[link_section = ".moretext"] -fn i_live_in_more_text() -> &'static str { - "knock knock" + +cfg_select! { + target_object_format = "mach-o" => { + #[link_section = "__TEXT,__moretext"] + fn i_live_in_more_text() -> &'static str { + "knock knock" + } + + #[link_section = "__RODATA,__imm"] + static magic: usize = 42; + + #[link_section = "__DATA,__mut"] + static mut frobulator: usize = 0xdeadbeef; + } + _ => { + #[link_section = ".moretext"] + fn i_live_in_more_text() -> &'static str { + "knock knock" + } + + #[link_section = ".imm"] + static magic: usize = 42; + + #[link_section = ".mut"] + static mut frobulator: usize = 0xdeadbeef; + } } -#[cfg(not(target_vendor = "apple"))] -#[link_section = ".imm"] -static magic: usize = 42; - -#[cfg(not(target_vendor = "apple"))] -#[link_section = ".mut"] -static mut frobulator: usize = 0xdeadbeef; - -#[cfg(target_vendor = "apple")] -#[link_section = "__TEXT,__moretext"] -fn i_live_in_more_text() -> &'static str { - "knock knock" -} - -#[cfg(target_vendor = "apple")] -#[link_section = "__RODATA,__imm"] -static magic: usize = 42; - -#[cfg(target_vendor = "apple")] -#[link_section = "__DATA,__mut"] -static mut frobulator: usize = 0xdeadbeef; - pub fn main() { unsafe { frobulator = 0x12345678; diff --git a/tests/ui/lint/lint-unsafe-code.rs b/tests/ui/lint/lint-unsafe-code.rs index b72e4c3a9e7f..9b32336b05d4 100644 --- a/tests/ui/lint/lint-unsafe-code.rs +++ b/tests/ui/lint/lint-unsafe-code.rs @@ -48,8 +48,8 @@ impl AssocFnTrait for AssocFnFoo { #[export_name = "bar"] fn bar() {} //~ ERROR: declaration of a function with `export_name` #[export_name = "BAR"] static BAR: u32 = 5; //~ ERROR: declaration of a static with `export_name` -#[link_section = ".example_section"] fn uwu() {} //~ ERROR: declaration of a function with `link_section` -#[link_section = ".example_section"] static UWU: u32 = 5; //~ ERROR: declaration of a static with `link_section` +#[link_section = "__TEXT,__text"] fn uwu() {} //~ ERROR: declaration of a function with `link_section` +#[link_section = "__TEXT,__text"] static UWU: u32 = 5; //~ ERROR: declaration of a static with `link_section` struct AssocFnBar; diff --git a/tests/ui/lint/lint-unsafe-code.stderr b/tests/ui/lint/lint-unsafe-code.stderr index 037f0a8323a7..aade33aef44e 100644 --- a/tests/ui/lint/lint-unsafe-code.stderr +++ b/tests/ui/lint/lint-unsafe-code.stderr @@ -54,16 +54,16 @@ LL | #[export_name = "BAR"] static BAR: u32 = 5; error: declaration of a function with `link_section` --> $DIR/lint-unsafe-code.rs:51:1 | -LL | #[link_section = ".example_section"] fn uwu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = "__TEXT,__text"] fn uwu() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them error: declaration of a static with `link_section` --> $DIR/lint-unsafe-code.rs:52:1 | -LL | #[link_section = ".example_section"] static UWU: u32 = 5; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = "__TEXT,__text"] static UWU: u32 = 5; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them diff --git a/tests/ui/lint/unused/unused-attr-duplicate.rs b/tests/ui/lint/unused/unused-attr-duplicate.rs index 2b29fde128e4..54c040f4bcac 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.rs +++ b/tests/ui/lint/unused/unused-attr-duplicate.rs @@ -61,8 +61,9 @@ macro_rules! foo { fn t1() {} #[must_use] -#[must_use = "some message"] //~ ERROR unused attribute -//~^ WARN this was previously accepted +#[must_use = "some message"] +//~^ ERROR unused attribute +//~| WARN this was previously accepted // No warnings for #[repr], would require more logic. #[repr(C)] #[repr(C)] @@ -96,7 +97,7 @@ pub fn xyz() {} } #[export_name = "exported_symbol_name"] -#[export_name = "exported_symbol_name2"] //~ ERROR unused attribute +#[export_name = "exported_symbol_name2"] //~ ERROR unused attribute //~^ WARN this was previously accepted pub fn export_test() {} @@ -108,8 +109,8 @@ pub fn no_mangle_test() {} #[used] //~ ERROR unused attribute static FOO: u32 = 0; -#[link_section = ".text"] -#[link_section = ".bss"] +#[link_section = "__TEXT,__text"] +#[link_section = "__DATA,__mod_init_func"] //~^ ERROR unused attribute //~| WARN this was previously accepted pub extern "C" fn example() {} diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 1942249d1f8e..f25263e9cef9 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -104,127 +104,127 @@ LL | #[must_use] = 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:70:1 + --> $DIR/unused-attr-duplicate.rs:71:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:69:1 + --> $DIR/unused-attr-duplicate.rs:70:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:76:1 + --> $DIR/unused-attr-duplicate.rs:77:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:75:1 + --> $DIR/unused-attr-duplicate.rs:76:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:80:1 + --> $DIR/unused-attr-duplicate.rs:81:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:79:1 + --> $DIR/unused-attr-duplicate.rs:80:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ = 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:83:1 + --> $DIR/unused-attr-duplicate.rs:84:1 | LL | #[cold] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:82:1 + --> $DIR/unused-attr-duplicate.rs:83:1 | LL | #[cold] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:85:1 + --> $DIR/unused-attr-duplicate.rs:86:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:84:1 + --> $DIR/unused-attr-duplicate.rs:85:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:93:5 + --> $DIR/unused-attr-duplicate.rs:94:5 | LL | #[link_name = "rust_dbg_extern_identity_u32"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:92:5 + --> $DIR/unused-attr-duplicate.rs:93:5 | LL | #[link_name = "this_does_not_exist"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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:99:1 + --> $DIR/unused-attr-duplicate.rs:100:1 | LL | #[export_name = "exported_symbol_name2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:98:1 + --> $DIR/unused-attr-duplicate.rs:99:1 | LL | #[export_name = "exported_symbol_name"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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:104:1 + --> $DIR/unused-attr-duplicate.rs:105:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:103:1 + --> $DIR/unused-attr-duplicate.rs:104:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:108:1 + --> $DIR/unused-attr-duplicate.rs:109:1 | LL | #[used] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:107:1 + --> $DIR/unused-attr-duplicate.rs:108:1 | LL | #[used] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:112:1 + --> $DIR/unused-attr-duplicate.rs:113:1 | -LL | #[link_section = ".bss"] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute +LL | #[link_section = "__DATA,__mod_init_func"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:111:1 + --> $DIR/unused-attr-duplicate.rs:112:1 | -LL | #[link_section = ".text"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = "__TEXT,__text"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed index c1adc90161a4..1865405de8e5 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed @@ -15,7 +15,7 @@ macro_rules! ident { //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition extern "C" fn bar() {} - } + }; } macro_rules! ident2 { @@ -24,26 +24,26 @@ macro_rules! ident2 { //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition extern "C" fn bars() {} - } + }; } macro_rules! meta { ($m:meta) => { #[$m] extern "C" fn baz() {} - } + }; } macro_rules! meta2 { ($m:meta) => { #[$m] extern "C" fn baw() {} - } + }; } macro_rules! with_cfg_attr { () => { - #[cfg_attr(true, unsafe(link_section = ".custom_section"))] + #[cfg_attr(true, unsafe(link_section = "__TEXT,__custom"))] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition pub extern "C" fn abc() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs index 9fdf37904634..ec290957e537 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs @@ -15,7 +15,7 @@ macro_rules! ident { //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition extern "C" fn bar() {} - } + }; } macro_rules! ident2 { @@ -24,26 +24,26 @@ macro_rules! ident2 { //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition extern "C" fn bars() {} - } + }; } macro_rules! meta { ($m:meta) => { #[$m] extern "C" fn baz() {} - } + }; } macro_rules! meta2 { ($m:meta) => { #[$m] extern "C" fn baw() {} - } + }; } macro_rules! with_cfg_attr { () => { - #[cfg_attr(true, link_section = ".custom_section")] + #[cfg_attr(true, link_section = "__TEXT,__custom")] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition pub extern "C" fn abc() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr index 279e61a9cb67..f03842139f0b 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr @@ -79,7 +79,7 @@ LL | #[unsafe($e = $l)] error: unsafe attribute used without unsafe --> $DIR/unsafe-attributes-fix.rs:46:26 | -LL | #[cfg_attr(true, link_section = ".custom_section")] +LL | #[cfg_attr(true, link_section = "__TEXT,__custom")] | ^^^^^^^^^^^^ usage of unsafe attribute ... LL | with_cfg_attr!(); @@ -90,7 +90,7 @@ LL | with_cfg_attr!(); = note: this error originates in the macro `with_cfg_attr` (in Nightly builds, run with -Z macro-backtrace for more info) help: wrap the attribute in `unsafe(...)` | -LL | #[cfg_attr(true, unsafe(link_section = ".custom_section"))] +LL | #[cfg_attr(true, unsafe(link_section = "__TEXT,__custom"))] | +++++++ + error: unsafe attribute used without unsafe From 642ee63c228ad8d8c988cb3c68089776ddc97980 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 22 Apr 2026 16:59:44 +0200 Subject: [PATCH 17/18] Add regression test --- .../consts/drop-impl-nonconst-drop-field.rs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/ui/consts/drop-impl-nonconst-drop-field.rs diff --git a/tests/ui/consts/drop-impl-nonconst-drop-field.rs b/tests/ui/consts/drop-impl-nonconst-drop-field.rs new file mode 100644 index 000000000000..a431c91bf2d9 --- /dev/null +++ b/tests/ui/consts/drop-impl-nonconst-drop-field.rs @@ -0,0 +1,31 @@ +#![feature(const_trait_impl)] +#![feature(const_destruct)] +//@ check-pass + +use std::marker::Destruct; + +struct NotConstDrop; + +impl Drop for NotConstDrop { + fn drop(&mut self) {} +} + +struct ConstDrop(NotConstDrop); + +impl const Drop for ConstDrop { + fn drop(&mut self) {} +} + +struct ConstDrop2(T); + +impl const Drop for ConstDrop2 { + fn drop(&mut self) {} +} + +struct ConstDrop3(T); + +impl const Drop for ConstDrop3 { + fn drop(&mut self) {} +} + +fn main() {} From 7dcedafff23aaddf40d061d9dd5be3b62aa2cfe8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 22 Apr 2026 17:09:33 +0200 Subject: [PATCH 18/18] Reject implementing `const Drop` for types that are not const `Destruct` already --- .../src/check/always_applicable.rs | 62 ++++++++++++++++++- .../consts/drop-impl-nonconst-drop-field.rs | 3 +- .../drop-impl-nonconst-drop-field.stderr | 27 ++++++++ .../const-drop-fail.new_precise.stderr | 25 ++++++-- .../const-drop-fail.new_stock.stderr | 25 ++++++-- .../const-drop-fail.old_precise.stderr | 25 ++++++-- .../const-drop-fail.old_stock.stderr | 25 ++++++-- .../ui/traits/const-traits/const-drop-fail.rs | 1 + .../traits/const-traits/minicore-drop-fail.rs | 2 +- 9 files changed, 168 insertions(+), 27 deletions(-) create mode 100644 tests/ui/consts/drop-impl-nonconst-drop-field.stderr diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index bdef0b57d691..dbf5465ee18b 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -11,7 +11,7 @@ use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::span_bug; use rustc_middle::ty::util::CheckRegions; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -65,6 +65,8 @@ pub(crate) fn check_drop_impl( adt_to_impl_args, )?; + ensure_all_fields_are_const_destruct(tcx, drop_impl_did, adt_def.did())?; + ensure_impl_predicates_are_implied_by_item_defn( tcx, drop_impl_did, @@ -173,6 +175,64 @@ fn ensure_impl_params_and_item_params_correspond<'tcx>( Err(err.emit()) } +fn ensure_all_fields_are_const_destruct<'tcx>( + tcx: TyCtxt<'tcx>, + impl_def_id: LocalDefId, + adt_def_id: DefId, +) -> Result<(), ErrorGuaranteed> { + if !tcx.is_conditionally_const(impl_def_id) { + return Ok(()); + } + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); + + let impl_span = tcx.def_span(impl_def_id.to_def_id()); + let env = + ty::EarlyBinder::bind(tcx.param_env(impl_def_id)).instantiate_identity().skip_norm_wip(); + let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id); + let destruct_trait = tcx.lang_items().destruct_trait().unwrap(); + for field in tcx.adt_def(adt_def_id).all_fields() { + let field_ty = field.ty(tcx, args); + let cause = traits::ObligationCause::new( + tcx.def_span(field.did), + impl_def_id, + ObligationCauseCode::Misc, + ); + ocx.register_obligation(traits::Obligation::new( + tcx, + cause, + env, + ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref: ty::TraitRef::new(tcx, destruct_trait, [field_ty]), + constness: ty::BoundConstness::Maybe, + }), + )); + } + ocx.evaluate_obligations_error_on_ambiguity() + .into_iter() + .map(|error| { + let ty::ClauseKind::HostEffect(eff) = + error.root_obligation.predicate.expect_clause().kind().no_bound_vars().unwrap() + else { + unreachable!() + }; + let field_ty = eff.trait_ref.self_ty(); + let diag = struct_span_code_err!( + tcx.dcx(), + error.root_obligation.cause.span, + E0367, + "`{field_ty}` does not implement `[const] Destruct`", + ) + .with_span_note(impl_span, "required for this `Drop` impl"); + if field_ty.has_param() { + // FIXME: suggest adding `[const] Destruct` by teaching + // `suggest_restricting_param_bound` about const traits. + } + Err(diag.emit()) + }) + .collect() +} + /// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be /// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are /// implied by the ADT being well formed. diff --git a/tests/ui/consts/drop-impl-nonconst-drop-field.rs b/tests/ui/consts/drop-impl-nonconst-drop-field.rs index a431c91bf2d9..9715724007cc 100644 --- a/tests/ui/consts/drop-impl-nonconst-drop-field.rs +++ b/tests/ui/consts/drop-impl-nonconst-drop-field.rs @@ -1,6 +1,5 @@ #![feature(const_trait_impl)] #![feature(const_destruct)] -//@ check-pass use std::marker::Destruct; @@ -11,12 +10,14 @@ fn drop(&mut self) {} } struct ConstDrop(NotConstDrop); +//~^ ERROR: `NotConstDrop` does not implement `[const] Destruct` impl const Drop for ConstDrop { fn drop(&mut self) {} } struct ConstDrop2(T); +//~^ ERROR: `T` does not implement `[const] Destruct` impl const Drop for ConstDrop2 { fn drop(&mut self) {} diff --git a/tests/ui/consts/drop-impl-nonconst-drop-field.stderr b/tests/ui/consts/drop-impl-nonconst-drop-field.stderr new file mode 100644 index 000000000000..0e626176579c --- /dev/null +++ b/tests/ui/consts/drop-impl-nonconst-drop-field.stderr @@ -0,0 +1,27 @@ +error[E0367]: `NotConstDrop` does not implement `[const] Destruct` + --> $DIR/drop-impl-nonconst-drop-field.rs:12:18 + | +LL | struct ConstDrop(NotConstDrop); + | ^^^^^^^^^^^^ + | +note: required for this `Drop` impl + --> $DIR/drop-impl-nonconst-drop-field.rs:15:1 + | +LL | impl const Drop for ConstDrop { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0367]: `T` does not implement `[const] Destruct` + --> $DIR/drop-impl-nonconst-drop-field.rs:19:22 + | +LL | struct ConstDrop2(T); + | ^ + | +note: required for this `Drop` impl + --> $DIR/drop-impl-nonconst-drop-field.rs:22:1 + | +LL | impl const Drop for ConstDrop2 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0367`. diff --git a/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr index ff803ff889b8..db4df30800b6 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr @@ -1,5 +1,17 @@ +error[E0367]: `NonTrivialDrop` does not implement `[const] Destruct` + --> $DIR/const-drop-fail.rs:19:30 + | +LL | struct ConstImplWithDropGlue(NonTrivialDrop); + | ^^^^^^^^^^^^^^ + | +note: required for this `Drop` impl + --> $DIR/const-drop-fail.rs:22:1 + | +LL | impl const Drop for ConstImplWithDropGlue { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:34:5 + --> $DIR/const-drop-fail.rs:35:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +20,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:25:19 + --> $DIR/const-drop-fail.rs:26:19 | LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:36:5 + --> $DIR/const-drop-fail.rs:37:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,11 +35,12 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:25:19 + --> $DIR/const-drop-fail.rs:26:19 | LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0367. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr index ff803ff889b8..db4df30800b6 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr @@ -1,5 +1,17 @@ +error[E0367]: `NonTrivialDrop` does not implement `[const] Destruct` + --> $DIR/const-drop-fail.rs:19:30 + | +LL | struct ConstImplWithDropGlue(NonTrivialDrop); + | ^^^^^^^^^^^^^^ + | +note: required for this `Drop` impl + --> $DIR/const-drop-fail.rs:22:1 + | +LL | impl const Drop for ConstImplWithDropGlue { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:34:5 + --> $DIR/const-drop-fail.rs:35:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +20,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:25:19 + --> $DIR/const-drop-fail.rs:26:19 | LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:36:5 + --> $DIR/const-drop-fail.rs:37:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,11 +35,12 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:25:19 + --> $DIR/const-drop-fail.rs:26:19 | LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0367. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr index ff803ff889b8..db4df30800b6 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr @@ -1,5 +1,17 @@ +error[E0367]: `NonTrivialDrop` does not implement `[const] Destruct` + --> $DIR/const-drop-fail.rs:19:30 + | +LL | struct ConstImplWithDropGlue(NonTrivialDrop); + | ^^^^^^^^^^^^^^ + | +note: required for this `Drop` impl + --> $DIR/const-drop-fail.rs:22:1 + | +LL | impl const Drop for ConstImplWithDropGlue { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:34:5 + --> $DIR/const-drop-fail.rs:35:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +20,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:25:19 + --> $DIR/const-drop-fail.rs:26:19 | LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:36:5 + --> $DIR/const-drop-fail.rs:37:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,11 +35,12 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:25:19 + --> $DIR/const-drop-fail.rs:26:19 | LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0367. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr index ff803ff889b8..db4df30800b6 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr @@ -1,5 +1,17 @@ +error[E0367]: `NonTrivialDrop` does not implement `[const] Destruct` + --> $DIR/const-drop-fail.rs:19:30 + | +LL | struct ConstImplWithDropGlue(NonTrivialDrop); + | ^^^^^^^^^^^^^^ + | +note: required for this `Drop` impl + --> $DIR/const-drop-fail.rs:22:1 + | +LL | impl const Drop for ConstImplWithDropGlue { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:34:5 + --> $DIR/const-drop-fail.rs:35:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +20,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:25:19 + --> $DIR/const-drop-fail.rs:26:19 | LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:36:5 + --> $DIR/const-drop-fail.rs:37:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,11 +35,12 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:25:19 + --> $DIR/const-drop-fail.rs:26:19 | LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0367. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-drop-fail.rs b/tests/ui/traits/const-traits/const-drop-fail.rs index b74716f00617..7e12043ce74a 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.rs +++ b/tests/ui/traits/const-traits/const-drop-fail.rs @@ -17,6 +17,7 @@ fn drop(&mut self) { } struct ConstImplWithDropGlue(NonTrivialDrop); +//~^ ERROR: `NonTrivialDrop` does not implement `[const] Destruct` impl const Drop for ConstImplWithDropGlue { fn drop(&mut self) {} diff --git a/tests/ui/traits/const-traits/minicore-drop-fail.rs b/tests/ui/traits/const-traits/minicore-drop-fail.rs index d01d259040c6..f17a88dd9021 100644 --- a/tests/ui/traits/const-traits/minicore-drop-fail.rs +++ b/tests/ui/traits/const-traits/minicore-drop-fail.rs @@ -19,7 +19,7 @@ const trait Foo {} impl Foo for () {} struct Conditional(T); -impl const Drop for Conditional where T: [const] Foo { +impl const Drop for Conditional where T: [const] Foo + [const] Destruct { fn drop(&mut self) {} }