From 3c6c901f6b0b8926ccb28e3e8aba26548a5842ac Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 1 Jun 2026 06:07:03 +0200 Subject: [PATCH 01/14] move batch --- .../issue-17959.rs => dropck/drop-impl-sized-bound-mismatch.rs} | 0 .../drop-impl-sized-bound-mismatch.stderr} | 0 .../impl-generic-struct-with-concrete-types.rs} | 0 .../issue-18183.rs => generics/type-param-self-reference.rs} | 0 .../type-param-self-reference.stderr} | 0 .../issue-18107.rs => impl-trait/bare-trait-object-return.rs} | 0 .../bare-trait-object-return.stderr} | 0 .../elided-lifetime-mismatch-in-self-type.rs} | 0 .../elided-lifetime-mismatch-in-self-type.stderr} | 0 .../issue-18232.rs => lifetimes/trait-method-lifetime-bounds.rs} | 0 .../issue-17999.rs => lint/unused/unused-variables-in-loop.rs} | 0 .../unused/unused-variables-in-loop.stderr} | 0 .../issue-18446.rs => methods/call-ambig-trait-object-method.rs} | 0 .../call-ambig-trait-object-method.stderr} | 0 .../inherent-method-on-dyn-with-default.rs} | 0 .../issue-18173.rs => traits/bound/implicit-assoc-type.rs} | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-17959.rs => dropck/drop-impl-sized-bound-mismatch.rs} (100%) rename tests/ui/{issues/issue-17959.stderr => dropck/drop-impl-sized-bound-mismatch.stderr} (100%) rename tests/ui/{issues/issue-17905.rs => generics/impl-generic-struct-with-concrete-types.rs} (100%) rename tests/ui/{issues/issue-18183.rs => generics/type-param-self-reference.rs} (100%) rename tests/ui/{issues/issue-18183.stderr => generics/type-param-self-reference.stderr} (100%) rename tests/ui/{issues/issue-18107.rs => impl-trait/bare-trait-object-return.rs} (100%) rename tests/ui/{issues/issue-18107.stderr => impl-trait/bare-trait-object-return.stderr} (100%) rename tests/ui/{issues/issue-17905-2.rs => lifetimes/elided-lifetime-mismatch-in-self-type.rs} (100%) rename tests/ui/{issues/issue-17905-2.stderr => lifetimes/elided-lifetime-mismatch-in-self-type.stderr} (100%) rename tests/ui/{issues/issue-18232.rs => lifetimes/trait-method-lifetime-bounds.rs} (100%) rename tests/ui/{issues/issue-17999.rs => lint/unused/unused-variables-in-loop.rs} (100%) rename tests/ui/{issues/issue-17999.stderr => lint/unused/unused-variables-in-loop.stderr} (100%) rename tests/ui/{issues/issue-18446.rs => methods/call-ambig-trait-object-method.rs} (100%) rename tests/ui/{issues/issue-18446.stderr => methods/call-ambig-trait-object-method.stderr} (100%) rename tests/ui/{issues/issue-18446-2.rs => methods/inherent-method-on-dyn-with-default.rs} (100%) rename tests/ui/{issues/issue-18173.rs => traits/bound/implicit-assoc-type.rs} (100%) diff --git a/tests/ui/issues/issue-17959.rs b/tests/ui/dropck/drop-impl-sized-bound-mismatch.rs similarity index 100% rename from tests/ui/issues/issue-17959.rs rename to tests/ui/dropck/drop-impl-sized-bound-mismatch.rs diff --git a/tests/ui/issues/issue-17959.stderr b/tests/ui/dropck/drop-impl-sized-bound-mismatch.stderr similarity index 100% rename from tests/ui/issues/issue-17959.stderr rename to tests/ui/dropck/drop-impl-sized-bound-mismatch.stderr diff --git a/tests/ui/issues/issue-17905.rs b/tests/ui/generics/impl-generic-struct-with-concrete-types.rs similarity index 100% rename from tests/ui/issues/issue-17905.rs rename to tests/ui/generics/impl-generic-struct-with-concrete-types.rs diff --git a/tests/ui/issues/issue-18183.rs b/tests/ui/generics/type-param-self-reference.rs similarity index 100% rename from tests/ui/issues/issue-18183.rs rename to tests/ui/generics/type-param-self-reference.rs diff --git a/tests/ui/issues/issue-18183.stderr b/tests/ui/generics/type-param-self-reference.stderr similarity index 100% rename from tests/ui/issues/issue-18183.stderr rename to tests/ui/generics/type-param-self-reference.stderr diff --git a/tests/ui/issues/issue-18107.rs b/tests/ui/impl-trait/bare-trait-object-return.rs similarity index 100% rename from tests/ui/issues/issue-18107.rs rename to tests/ui/impl-trait/bare-trait-object-return.rs diff --git a/tests/ui/issues/issue-18107.stderr b/tests/ui/impl-trait/bare-trait-object-return.stderr similarity index 100% rename from tests/ui/issues/issue-18107.stderr rename to tests/ui/impl-trait/bare-trait-object-return.stderr diff --git a/tests/ui/issues/issue-17905-2.rs b/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.rs similarity index 100% rename from tests/ui/issues/issue-17905-2.rs rename to tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.rs diff --git a/tests/ui/issues/issue-17905-2.stderr b/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.stderr similarity index 100% rename from tests/ui/issues/issue-17905-2.stderr rename to tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.stderr diff --git a/tests/ui/issues/issue-18232.rs b/tests/ui/lifetimes/trait-method-lifetime-bounds.rs similarity index 100% rename from tests/ui/issues/issue-18232.rs rename to tests/ui/lifetimes/trait-method-lifetime-bounds.rs diff --git a/tests/ui/issues/issue-17999.rs b/tests/ui/lint/unused/unused-variables-in-loop.rs similarity index 100% rename from tests/ui/issues/issue-17999.rs rename to tests/ui/lint/unused/unused-variables-in-loop.rs diff --git a/tests/ui/issues/issue-17999.stderr b/tests/ui/lint/unused/unused-variables-in-loop.stderr similarity index 100% rename from tests/ui/issues/issue-17999.stderr rename to tests/ui/lint/unused/unused-variables-in-loop.stderr diff --git a/tests/ui/issues/issue-18446.rs b/tests/ui/methods/call-ambig-trait-object-method.rs similarity index 100% rename from tests/ui/issues/issue-18446.rs rename to tests/ui/methods/call-ambig-trait-object-method.rs diff --git a/tests/ui/issues/issue-18446.stderr b/tests/ui/methods/call-ambig-trait-object-method.stderr similarity index 100% rename from tests/ui/issues/issue-18446.stderr rename to tests/ui/methods/call-ambig-trait-object-method.stderr diff --git a/tests/ui/issues/issue-18446-2.rs b/tests/ui/methods/inherent-method-on-dyn-with-default.rs similarity index 100% rename from tests/ui/issues/issue-18446-2.rs rename to tests/ui/methods/inherent-method-on-dyn-with-default.rs diff --git a/tests/ui/issues/issue-18173.rs b/tests/ui/traits/bound/implicit-assoc-type.rs similarity index 100% rename from tests/ui/issues/issue-18173.rs rename to tests/ui/traits/bound/implicit-assoc-type.rs From 01f5cc80731a968550ab858d28904948f4780fe6 Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 1 Jun 2026 06:35:38 +0200 Subject: [PATCH 02/14] bless batch --- tests/ui/dropck/drop-impl-sized-bound-mismatch.rs | 2 ++ .../ui/dropck/drop-impl-sized-bound-mismatch.stderr | 4 ++-- .../impl-generic-struct-with-concrete-types.rs | 2 ++ tests/ui/generics/type-param-self-reference.rs | 2 ++ tests/ui/generics/type-param-self-reference.stderr | 2 +- tests/ui/impl-trait/bare-trait-object-return.rs | 2 ++ tests/ui/impl-trait/bare-trait-object-return.stderr | 2 +- .../elided-lifetime-mismatch-in-self-type.rs | 2 ++ .../elided-lifetime-mismatch-in-self-type.stderr | 12 ++++++------ tests/ui/lifetimes/trait-method-lifetime-bounds.rs | 2 ++ tests/ui/lint/unused/unused-variables-in-loop.rs | 2 ++ tests/ui/lint/unused/unused-variables-in-loop.stderr | 6 +++--- tests/ui/methods/call-ambig-trait-object-method.rs | 5 +++-- .../ui/methods/call-ambig-trait-object-method.stderr | 6 +++--- .../methods/inherent-method-on-dyn-with-default.rs | 5 ++++- tests/ui/traits/bound/implicit-assoc-type.rs | 2 ++ 16 files changed, 39 insertions(+), 19 deletions(-) diff --git a/tests/ui/dropck/drop-impl-sized-bound-mismatch.rs b/tests/ui/dropck/drop-impl-sized-bound-mismatch.rs index 8bf9e623605ca..c5a0e256d7b7f 100644 --- a/tests/ui/dropck/drop-impl-sized-bound-mismatch.rs +++ b/tests/ui/dropck/drop-impl-sized-bound-mismatch.rs @@ -1,3 +1,5 @@ +//! Regression test for . + extern crate core; use core::ops::Drop; diff --git a/tests/ui/dropck/drop-impl-sized-bound-mismatch.stderr b/tests/ui/dropck/drop-impl-sized-bound-mismatch.stderr index 604413c4b6d19..b21cc26245ed8 100644 --- a/tests/ui/dropck/drop-impl-sized-bound-mismatch.stderr +++ b/tests/ui/dropck/drop-impl-sized-bound-mismatch.stderr @@ -1,11 +1,11 @@ error[E0367]: `Drop` impl requires `T: Sized` but the struct it is implemented for does not - --> $DIR/issue-17959.rs:11:6 + --> $DIR/drop-impl-sized-bound-mismatch.rs:13:6 | LL | impl Drop for G { | ^ | note: the implementor must specify the same requirement - --> $DIR/issue-17959.rs:7:1 + --> $DIR/drop-impl-sized-bound-mismatch.rs:9:1 | LL | struct G { | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/generics/impl-generic-struct-with-concrete-types.rs b/tests/ui/generics/impl-generic-struct-with-concrete-types.rs index 6238379b5a04b..68a7db69a2bb1 100644 --- a/tests/ui/generics/impl-generic-struct-with-concrete-types.rs +++ b/tests/ui/generics/impl-generic-struct-with-concrete-types.rs @@ -1,3 +1,5 @@ +//! Regression test for . + //@ run-pass #[derive(Debug)] diff --git a/tests/ui/generics/type-param-self-reference.rs b/tests/ui/generics/type-param-self-reference.rs index 64476d1c10999..dd8fead948916 100644 --- a/tests/ui/generics/type-param-self-reference.rs +++ b/tests/ui/generics/type-param-self-reference.rs @@ -1,3 +1,5 @@ +//! Regression test for . + pub struct Foo(Bar); //~ ERROR E0128 pub struct Baz(Foo); fn main() {} diff --git a/tests/ui/generics/type-param-self-reference.stderr b/tests/ui/generics/type-param-self-reference.stderr index 07fa4cdc7535c..b24f0ee8b67e0 100644 --- a/tests/ui/generics/type-param-self-reference.stderr +++ b/tests/ui/generics/type-param-self-reference.stderr @@ -1,5 +1,5 @@ error[E0128]: generic parameter defaults cannot reference parameters before they are declared - --> $DIR/issue-18183.rs:1:20 + --> $DIR/type-param-self-reference.rs:3:20 | LL | pub struct Foo(Bar); | ^^^ cannot reference `Bar` before it is declared diff --git a/tests/ui/impl-trait/bare-trait-object-return.rs b/tests/ui/impl-trait/bare-trait-object-return.rs index b1b6ff4f7ad26..18cafddd6a911 100644 --- a/tests/ui/impl-trait/bare-trait-object-return.rs +++ b/tests/ui/impl-trait/bare-trait-object-return.rs @@ -1,3 +1,5 @@ +//! Regression test for . + pub trait AbstractRenderer {} fn _create_render(_: &()) -> diff --git a/tests/ui/impl-trait/bare-trait-object-return.stderr b/tests/ui/impl-trait/bare-trait-object-return.stderr index 177ef2f1c33f7..0445926e4d4a3 100644 --- a/tests/ui/impl-trait/bare-trait-object-return.stderr +++ b/tests/ui/impl-trait/bare-trait-object-return.stderr @@ -1,5 +1,5 @@ error[E0746]: return type cannot be a trait object without pointer indirection - --> $DIR/issue-18107.rs:4:5 + --> $DIR/bare-trait-object-return.rs:6:5 | LL | dyn AbstractRenderer | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.rs b/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.rs index 44279cc867b46..fa634c8447a79 100644 --- a/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.rs +++ b/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.rs @@ -1,3 +1,5 @@ +//! Regression test for . + #[derive(Debug)] struct Pair (T, V); diff --git a/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.stderr b/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.stderr index c66cb2224897d..920fe850f0ec7 100644 --- a/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.stderr +++ b/tests/ui/lifetimes/elided-lifetime-mismatch-in-self-type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched `self` parameter type - --> $DIR/issue-17905-2.rs:8:18 + --> $DIR/elided-lifetime-mismatch-in-self-type.rs:10:18 | LL | fn say(self: &Pair<&str, isize>) { | ^^^^^^^^^^^^^^^^^^ lifetime mismatch @@ -7,18 +7,18 @@ LL | fn say(self: &Pair<&str, isize>) { = note: expected struct `Pair<&_, _>` found struct `Pair<&_, _>` note: the anonymous lifetime defined here... - --> $DIR/issue-17905-2.rs:8:24 + --> $DIR/elided-lifetime-mismatch-in-self-type.rs:10:24 | LL | fn say(self: &Pair<&str, isize>) { | ^^^^ note: ...does not necessarily outlive the anonymous lifetime as defined here - --> $DIR/issue-17905-2.rs:5:5 + --> $DIR/elided-lifetime-mismatch-in-self-type.rs:7:5 | LL | &str, | ^ error[E0308]: mismatched `self` parameter type - --> $DIR/issue-17905-2.rs:8:18 + --> $DIR/elided-lifetime-mismatch-in-self-type.rs:10:18 | LL | fn say(self: &Pair<&str, isize>) { | ^^^^^^^^^^^^^^^^^^ lifetime mismatch @@ -26,12 +26,12 @@ LL | fn say(self: &Pair<&str, isize>) { = note: expected struct `Pair<&_, _>` found struct `Pair<&_, _>` note: the anonymous lifetime as defined here... - --> $DIR/issue-17905-2.rs:5:5 + --> $DIR/elided-lifetime-mismatch-in-self-type.rs:7:5 | LL | &str, | ^ note: ...does not necessarily outlive the anonymous lifetime defined here - --> $DIR/issue-17905-2.rs:8:24 + --> $DIR/elided-lifetime-mismatch-in-self-type.rs:10:24 | LL | fn say(self: &Pair<&str, isize>) { | ^^^^ diff --git a/tests/ui/lifetimes/trait-method-lifetime-bounds.rs b/tests/ui/lifetimes/trait-method-lifetime-bounds.rs index d526a67950cf6..eebdce5b49286 100644 --- a/tests/ui/lifetimes/trait-method-lifetime-bounds.rs +++ b/tests/ui/lifetimes/trait-method-lifetime-bounds.rs @@ -1,3 +1,5 @@ +//! Regression test for . + //@ run-pass struct Cursor<'a>(::std::marker::PhantomData<&'a ()>); diff --git a/tests/ui/lint/unused/unused-variables-in-loop.rs b/tests/ui/lint/unused/unused-variables-in-loop.rs index 941f1e7755afe..c96d2ac5f3fe5 100644 --- a/tests/ui/lint/unused/unused-variables-in-loop.rs +++ b/tests/ui/lint/unused/unused-variables-in-loop.rs @@ -1,3 +1,5 @@ +//! Regression test for . + #![deny(unused_variables)] fn main() { diff --git a/tests/ui/lint/unused/unused-variables-in-loop.stderr b/tests/ui/lint/unused/unused-variables-in-loop.stderr index 4a1ef7350b8cb..6c311f03ce508 100644 --- a/tests/ui/lint/unused/unused-variables-in-loop.stderr +++ b/tests/ui/lint/unused/unused-variables-in-loop.stderr @@ -1,17 +1,17 @@ error: unused variable: `x` - --> $DIR/issue-17999.rs:5:13 + --> $DIR/unused-variables-in-loop.rs:7:13 | LL | let x = (); | ^ help: if this is intentional, prefix it with an underscore: `_x` | note: the lint level is defined here - --> $DIR/issue-17999.rs:1:9 + --> $DIR/unused-variables-in-loop.rs:3:9 | LL | #![deny(unused_variables)] | ^^^^^^^^^^^^^^^^ error: unused variable: `a` - --> $DIR/issue-17999.rs:7:13 + --> $DIR/unused-variables-in-loop.rs:9:13 | LL | a => {} | ^ help: if this is intentional, prefix it with an underscore: `_a` diff --git a/tests/ui/methods/call-ambig-trait-object-method.rs b/tests/ui/methods/call-ambig-trait-object-method.rs index a2e238da03a3e..9e2f5c5aebe8b 100644 --- a/tests/ui/methods/call-ambig-trait-object-method.rs +++ b/tests/ui/methods/call-ambig-trait-object-method.rs @@ -1,5 +1,6 @@ -// Test that name clashes between the method in an impl for the type -// and the method in the trait when both are in the same scope. +//! Regression test for . +//! Test that name clashes between the method in an impl for the type +//! and the method in the trait when both are in the same scope. trait T { fn foo(&self); diff --git a/tests/ui/methods/call-ambig-trait-object-method.stderr b/tests/ui/methods/call-ambig-trait-object-method.stderr index 25ae303e902b5..b76f107160011 100644 --- a/tests/ui/methods/call-ambig-trait-object-method.stderr +++ b/tests/ui/methods/call-ambig-trait-object-method.stderr @@ -1,16 +1,16 @@ error[E0034]: multiple applicable items in scope - --> $DIR/issue-18446.rs:18:7 + --> $DIR/call-ambig-trait-object-method.rs:19:7 | LL | x.foo(); | ^^^ multiple `foo` found | note: candidate #1 is defined in the trait `T` - --> $DIR/issue-18446.rs:5:5 + --> $DIR/call-ambig-trait-object-method.rs:6:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ note: candidate #2 is defined in an impl for the type `(dyn T + 'a)` - --> $DIR/issue-18446.rs:9:5 + --> $DIR/call-ambig-trait-object-method.rs:10:5 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ diff --git a/tests/ui/methods/inherent-method-on-dyn-with-default.rs b/tests/ui/methods/inherent-method-on-dyn-with-default.rs index d403487c001fb..cb84da56defad 100644 --- a/tests/ui/methods/inherent-method-on-dyn-with-default.rs +++ b/tests/ui/methods/inherent-method-on-dyn-with-default.rs @@ -1,6 +1,9 @@ +//! Regression test for . +//! Tests that an inherent method on a trait object with existing default method +//! doesn't emit a duplicate definition error. + //@ check-pass #![allow(dead_code)] -// Test that methods in trait impls should override default methods. trait T { fn foo(&self) -> i32 { 0 } diff --git a/tests/ui/traits/bound/implicit-assoc-type.rs b/tests/ui/traits/bound/implicit-assoc-type.rs index a9f20e827fbe3..491516ac6bfae 100644 --- a/tests/ui/traits/bound/implicit-assoc-type.rs +++ b/tests/ui/traits/bound/implicit-assoc-type.rs @@ -1,3 +1,5 @@ +//! Regression test for . + //@ check-pass trait Foo { type T; From 7092ebf8624c2a31684b4bb04e20a640c6c47497 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 24 May 2026 18:49:41 +0000 Subject: [PATCH 03/14] Integrate `field_names` inside `field_tys`. We already have a vector of `CoroutineSavedTy`, no need to have a separate one just for debuginfo. --- .../src/debuginfo/metadata/enums/mod.rs | 3 ++- compiler/rustc_middle/src/mir/pretty.rs | 17 +++++--------- compiler/rustc_middle/src/mir/query.rs | 5 ++-- compiler/rustc_middle/src/ty/mod.rs | 1 - compiler/rustc_mir_transform/src/coroutine.rs | 23 +++++++++---------- compiler/rustc_ty_utils/src/layout.rs | 2 +- 6 files changed, 22 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 86060f068eaf0..3a1b4fb91faa7 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -328,7 +328,8 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>( .map(|field_index| { let coroutine_saved_local = coroutine_layout.variant_fields[variant_index] [FieldIdx::from_usize(field_index)]; - let field_name_maybe = coroutine_layout.field_names[coroutine_saved_local]; + let field_name_maybe = + coroutine_layout.field_tys[coroutine_saved_local].debuginfo_name; let field_name = field_name_maybe .as_ref() .map(|s| Cow::from(s.as_str())) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f93c4b0d24f80..38782c4eb8d57 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -429,9 +429,9 @@ fn write_scope_tree( // Coroutine debuginfo. if let Some(layout) = body.coroutine_layout_raw() { - for (field, name) in layout.field_names.iter_enumerated() { - let source_info = layout.field_tys[field].source_info; - if let Some(name) = name + for (field, field_decl) in layout.field_tys.iter_enumerated() { + let source_info = field_decl.source_info; + if let Some(name) = field_decl.debuginfo_name && source_info.scope == parent { let indented_debug_info = @@ -559,17 +559,12 @@ fn write_coroutine_layout<'tcx>( w: &mut dyn io::Write, options: PrettyPrintMirOptions, ) -> io::Result<()> { - let CoroutineLayout { - field_tys, - field_names: _, // Dumped in scope tree with debug info. - variant_fields, - variant_source_info, - storage_conflicts, - } = layout; + let CoroutineLayout { field_tys, variant_fields, variant_source_info, storage_conflicts } = + layout; writeln!(w, "{INDENT}coroutine layout {{")?; - for (field, CoroutineSavedTy { ty, source_info, ignore_for_traits }) in + for (field, CoroutineSavedTy { ty, source_info, ignore_for_traits, debuginfo_name: _ }) in field_tys.iter_enumerated() { let ignore_for_traits = if *ignore_for_traits { " (ignored for traits)" } else { "" }; diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index f8607cafcfa6e..616b1719359f1 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -27,6 +27,8 @@ pub struct CoroutineSavedTy<'tcx> { pub source_info: SourceInfo, /// Whether the local should be ignored for trait bound computations. pub ignore_for_traits: bool, + /// The name for debuginfo. + pub debuginfo_name: Option, } /// The layout of coroutine state. @@ -36,9 +38,6 @@ pub struct CoroutineLayout<'tcx> { /// The type of every local stored inside the coroutine. pub field_tys: IndexVec>, - /// The name for debuginfo. - pub field_names: IndexVec>, - /// Which of the above fields are in each variant. Note that one field may /// be stored in multiple variants. pub variant_fields: IndexVec>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6df1ed82d260a..bfb9869383b56 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1929,7 +1929,6 @@ impl<'tcx> TyCtxt<'tcx> { iter::repeat(source_info).take(CoroutineArgs::RESERVED_VARIANTS).collect(); let proxy_layout = CoroutineLayout { field_tys: [].into(), - field_names: [].into(), variant_fields, variant_source_info, storage_conflicts: BitMatrix::new(0, 0), diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 9047055bc2570..27410a396b971 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1001,8 +1001,13 @@ fn compute_layout<'tcx>( ClearCrossCrate::Set(LocalInfo::FakeBorrow) => true, _ => false, }; - let decl = - CoroutineSavedTy { ty: decl.ty, source_info: decl.source_info, ignore_for_traits }; + let decl = CoroutineSavedTy { + ty: decl.ty, + source_info: decl.source_info, + ignore_for_traits, + // Will be set later when walking debuginfo. + debuginfo_name: None, + }; debug!(?decl); tys.push(decl); @@ -1046,7 +1051,6 @@ fn compute_layout<'tcx>( debug!(?variant_fields); debug!(?storage_conflicts); - let mut field_names = IndexVec::from_elem(None, &tys); for var in &body.var_debug_info { let VarDebugInfoContents::Place(place) = &var.value else { continue }; let Some(local) = place.as_local() else { continue }; @@ -1054,17 +1058,12 @@ fn compute_layout<'tcx>( continue; }; - let saved_local = variant_fields[variant][field]; - field_names.get_or_insert_with(saved_local, || var.name); + let saved_local: CoroutineSavedLocal = variant_fields[variant][field]; + tys[saved_local].debuginfo_name.get_or_insert(var.name); } - let layout = CoroutineLayout { - field_tys: tys, - field_names, - variant_fields, - variant_source_info, - storage_conflicts, - }; + let layout = + CoroutineLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; debug!(?remap); debug!(?layout); debug!(?storage_liveness); diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 9cc15a374ff70..85b6534f095a7 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -968,7 +968,7 @@ fn variant_info_for_coroutine<'tcx>( .iter() .enumerate() .map(|(field_idx, local)| { - let field_name = coroutine.field_names[*local]; + let field_name = coroutine.field_tys[*local].debuginfo_name; let field_layout = variant_layout.field(cx, field_idx); let offset = variant_layout.fields.offset(field_idx); // The struct is as large as the last field's end From c8ce74aa2619b3f9e74aebbc8aebe24c9352f804 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Tue, 2 Jun 2026 08:29:39 +0000 Subject: [PATCH 04/14] Simplify `compute_layout`. Avoid complicated loops just for an optimization. --- compiler/rustc_mir_transform/src/coroutine.rs | 70 ++++++++++--------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 27410a396b971..7a5375f1c14b5 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -978,40 +978,39 @@ fn compute_layout<'tcx>( storage_liveness, } = liveness; - // Gather live local types and their indices. - let mut locals = IndexVec::::with_capacity(saved_locals.domain_size()); - let mut tys = IndexVec::::with_capacity(saved_locals.domain_size()); - for (saved_local, local) in saved_locals.iter_enumerated() { - debug!("coroutine saved local {:?} => {:?}", saved_local, local); - - locals.push(local); - let decl = &body.local_decls[local]; - debug!(?decl); - - // Do not `unwrap_crate_local` here, as post-borrowck cleanup may have already cleared - // the information. This is alright, since `ignore_for_traits` is only relevant when - // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer - // default. - let ignore_for_traits = match decl.local_info { - // Do not include raw pointers created from accessing `static` items, as those could - // well be re-created by another access to the same static. - ClearCrossCrate::Set(LocalInfo::StaticRef { is_thread_local, .. }) => !is_thread_local, - // Fake borrows are only read by fake reads, so do not have any reality in - // post-analysis MIR. - ClearCrossCrate::Set(LocalInfo::FakeBorrow) => true, - _ => false, - }; - let decl = CoroutineSavedTy { - ty: decl.ty, - source_info: decl.source_info, - ignore_for_traits, - // Will be set later when walking debuginfo. - debuginfo_name: None, - }; - debug!(?decl); + // Gather live local types. + let mut tys: IndexVec> = saved_locals + .iter_enumerated() + .map(|(saved_local, local)| { + debug!("coroutine saved local {:?} => {:?}", saved_local, local); + + let decl = &body.local_decls[local]; + + // Do not `unwrap_crate_local` here, as post-borrowck cleanup may have already cleared + // the information. This is alright, since `ignore_for_traits` is only relevant when + // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer + // default. + let ignore_for_traits = match decl.local_info { + // Do not include raw pointers created from accessing `static` items, as those could + // well be re-created by another access to the same static. + ClearCrossCrate::Set(LocalInfo::StaticRef { is_thread_local, .. }) => { + !is_thread_local + } + // Fake borrows are only read by fake reads, so do not have any reality in + // post-analysis MIR. + ClearCrossCrate::Set(LocalInfo::FakeBorrow) => true, + _ => false, + }; - tys.push(decl); - } + CoroutineSavedTy { + ty: decl.ty, + source_info: decl.source_info, + ignore_for_traits, + // Will be set later when walking debuginfo. + debuginfo_name: None, + } + }) + .collect(); // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states. // In debuginfo, these will correspond to the beginning (UNRESUMED) or end @@ -1026,6 +1025,9 @@ fn compute_layout<'tcx>( SourceInfo::outermost(body_span.shrink_to_hi()), ]); + // Simple map from new to old indices to avoid repeatedly counting bits. + let reverse_local_map: IndexVec = saved_locals.iter().collect(); + // Build the coroutine variant field list. // Create a map from local indices to coroutine struct indices. let mut variant_fields: IndexVec = IndexVec::from_elem_n( @@ -1044,7 +1046,7 @@ fn compute_layout<'tcx>( // just use the first one here. That's fine; fields do not move // around inside coroutines, so it doesn't matter which variant // index we access them by. - remap[locals[saved_local]] = Some((tys[saved_local].ty, variant_index, idx)); + remap[reverse_local_map[saved_local]] = Some((tys[saved_local].ty, variant_index, idx)); } variant_source_info.push(source_info_at_suspension_point); } From 2a2e4c9b7e155c695bd76a63435c0e2f1c61dad9 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 31 May 2026 08:32:56 +0000 Subject: [PATCH 05/14] Split coroutine layout computation to its own file. `coroutine.rs` was getting too large, and mixing MIR analyses for trait solving and runtime transformations. --- compiler/rustc_mir_transform/src/coroutine.rs | 701 +---------------- .../src/coroutine/layout.rs | 722 ++++++++++++++++++ 2 files changed, 731 insertions(+), 692 deletions(-) create mode 100644 compiler/rustc_mir_transform/src/coroutine/layout.rs diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 7a5375f1c14b5..235654fd3454e 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -52,7 +52,7 @@ mod by_move_body; mod drop; -use std::ops; +mod layout; pub(super) use by_move_body::coroutine_by_move_body_def_id; use drop::{ @@ -60,36 +60,25 @@ use drop::{ create_coroutine_drop_shim_proxy_async, elaborate_coroutine_drops, has_async_drops, insert_clean_drop, }; -use itertools::izip; +pub(super) use layout::mir_coroutine_witnesses; +use layout::{CoroutineSavedLocals, compute_layout, locals_live_across_suspend_points}; use rustc_abi::{FieldIdx, VariantIdx}; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::pluralize; use rustc_hir::lang_items::LangItem; -use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind, find_attr}; +use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind}; use rustc_index::bit_set::{BitMatrix, DenseBitSet, GrowableBitSet}; use rustc_index::{Idx, IndexVec, indexvec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{ - self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode, + self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, }; use rustc_middle::{bug, span_bug}; -use rustc_mir_dataflow::impls::{ - MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, - always_storage_live_locals, -}; -use rustc_mir_dataflow::{ - Analysis, Results, ResultsCursor, ResultsVisitor, visit_reachable_results, -}; -use rustc_span::Span; -use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_trait_selection::error_reporting::InferCtxtErrorExt; -use rustc_trait_selection::infer::TyCtxtInferExt as _; -use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; -use tracing::{debug, instrument, trace}; +use rustc_mir_dataflow::impls::always_storage_live_locals; +use rustc_span::def_id::DefId; +use tracing::{debug, instrument}; use crate::deref_separator::deref_finder; -use crate::{abort_unwinding_calls, errors, pass_manager as pm, simplify}; +use crate::{abort_unwinding_calls, pass_manager as pm, simplify}; pub(super) struct StateTransform; @@ -673,406 +662,6 @@ fn transform_gen_context<'tcx>(body: &mut Body<'tcx>) { body.arg_count = 1; } -struct LivenessInfo { - /// Which locals are live across any suspension point. - saved_locals: CoroutineSavedLocals, - - /// The set of saved locals live at each suspension point. - live_locals_at_suspension_points: Vec>, - - /// Parallel vec to the above with SourceInfo for each yield terminator. - source_info_at_suspension_points: Vec, - - /// For every saved local, the set of other saved locals that are - /// storage-live at the same time as this local. We cannot overlap locals in - /// the layout which have conflicting storage. - storage_conflicts: BitMatrix, - - /// For every suspending block, the locals which are storage-live across - /// that suspension point. - storage_liveness: IndexVec>>, -} - -/// Computes which locals have to be stored in the state-machine for the -/// given coroutine. -/// -/// The basic idea is as follows: -/// - a local is live until we encounter a `StorageDead` statement. In -/// case none exist, the local is considered to be always live. -/// - a local has to be stored if it is either directly used after the -/// the suspend point, or if it is live and has been previously borrowed. -#[tracing::instrument(level = "trace", skip(tcx, body))] -fn locals_live_across_suspend_points<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - always_live_locals: &DenseBitSet, - movable: bool, -) -> LivenessInfo { - // Calculate when MIR locals have live storage. This gives us an upper bound of their - // lifetimes. - let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals)) - .iterate_to_fixpoint(tcx, body, None) - .into_results_cursor(body); - - // Calculate the MIR locals that have been previously borrowed (even if they are still active). - let borrowed_locals = MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); - let borrowed_locals_cursor1 = ResultsCursor::new_borrowing(body, &borrowed_locals); - let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing(body, &borrowed_locals); - - // Calculate the MIR locals that we need to keep storage around for. - let requires_storage = - MaybeRequiresStorage::new(borrowed_locals_cursor1).iterate_to_fixpoint(tcx, body, None); - let mut requires_storage_cursor = ResultsCursor::new_borrowing(body, &requires_storage); - - // Calculate the liveness of MIR locals ignoring borrows. - let mut liveness = - MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")).into_results_cursor(body); - - let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks); - let mut live_locals_at_suspension_points = Vec::new(); - let mut source_info_at_suspension_points = Vec::new(); - let mut live_locals_at_any_suspension_point = DenseBitSet::new_empty(body.local_decls.len()); - - for (block, data) in body.basic_blocks.iter_enumerated() { - let TerminatorKind::Yield { .. } = data.terminator().kind else { continue }; - - let loc = Location { block, statement_index: data.statements.len() }; - - liveness.seek_to_block_end(block); - let mut live_locals = liveness.get().clone(); - - if !movable { - // The `liveness` variable contains the liveness of MIR locals ignoring borrows. - // This is correct for movable coroutines since borrows cannot live across - // suspension points. However for immovable coroutines we need to account for - // borrows, so we conservatively assume that all borrowed locals are live until - // we find a StorageDead statement referencing the locals. - // To do this we just union our `liveness` result with `borrowed_locals`, which - // contains all the locals which has been borrowed before this suspension point. - // If a borrow is converted to a raw reference, we must also assume that it lives - // forever. Note that the final liveness is still bounded by the storage liveness - // of the local, which happens using the `intersect` operation below. - borrowed_locals_cursor2.seek_before_primary_effect(loc); - live_locals.union(borrowed_locals_cursor2.get()); - } - - // Store the storage liveness for later use so we can restore the state - // after a suspension point - storage_live.seek_before_primary_effect(loc); - storage_liveness_map[block] = Some(storage_live.get().clone()); - - // Locals live are live at this point only if they are used across - // suspension points (the `liveness` variable) - // and their storage is required (the `storage_required` variable) - requires_storage_cursor.seek_before_primary_effect(loc); - live_locals.intersect(requires_storage_cursor.get()); - - // The coroutine argument is ignored. - live_locals.remove(SELF_ARG); - - debug!(?loc, ?live_locals); - - // Add the locals live at this suspension point to the set of locals which live across - // any suspension points - live_locals_at_any_suspension_point.union(&live_locals); - - live_locals_at_suspension_points.push(live_locals); - source_info_at_suspension_points.push(data.terminator().source_info); - } - - debug!(?live_locals_at_any_suspension_point); - let saved_locals = CoroutineSavedLocals(live_locals_at_any_suspension_point); - - // Renumber our liveness_map bitsets to include only the locals we are - // saving. - let live_locals_at_suspension_points = live_locals_at_suspension_points - .iter() - .map(|live_here| saved_locals.renumber_bitset(live_here)) - .collect(); - - let storage_conflicts = compute_storage_conflicts( - body, - &saved_locals, - always_live_locals.clone(), - &requires_storage, - ); - - LivenessInfo { - saved_locals, - live_locals_at_suspension_points, - source_info_at_suspension_points, - storage_conflicts, - storage_liveness: storage_liveness_map, - } -} - -/// The set of `Local`s that must be saved across yield points. -/// -/// `CoroutineSavedLocal` is indexed in terms of the elements in this set; -/// i.e. `CoroutineSavedLocal::new(1)` corresponds to the second local -/// included in this set. -struct CoroutineSavedLocals(DenseBitSet); - -impl CoroutineSavedLocals { - /// Returns an iterator over each `CoroutineSavedLocal` along with the `Local` it corresponds - /// to. - fn iter_enumerated(&self) -> impl '_ + Iterator { - self.iter().enumerate().map(|(i, l)| (CoroutineSavedLocal::from(i), l)) - } - - /// Transforms a `DenseBitSet` that contains only locals saved across yield points to the - /// equivalent `DenseBitSet`. - fn renumber_bitset(&self, input: &DenseBitSet) -> DenseBitSet { - assert!(self.superset(input), "{:?} not a superset of {:?}", self.0, input); - let mut out = DenseBitSet::new_empty(self.count()); - for (saved_local, local) in self.iter_enumerated() { - if input.contains(local) { - out.insert(saved_local); - } - } - out - } - - fn get(&self, local: Local) -> Option { - if !self.contains(local) { - return None; - } - - let idx = self.iter().take_while(|&l| l < local).count(); - Some(CoroutineSavedLocal::new(idx)) - } -} - -impl ops::Deref for CoroutineSavedLocals { - type Target = DenseBitSet; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -/// For every saved local, looks for which locals are StorageLive at the same -/// time. Generates a bitset for every local of all the other locals that may be -/// StorageLive simultaneously with that local. This is used in the layout -/// computation; see `CoroutineLayout` for more. -fn compute_storage_conflicts<'mir, 'tcx>( - body: &'mir Body<'tcx>, - saved_locals: &'mir CoroutineSavedLocals, - always_live_locals: DenseBitSet, - results: &Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, -) -> BitMatrix { - assert_eq!(body.local_decls.len(), saved_locals.domain_size()); - - debug!("compute_storage_conflicts({:?})", body.span); - debug!("always_live = {:?}", always_live_locals); - - // Locals that are always live or ones that need to be stored across - // suspension points are not eligible for overlap. - let mut ineligible_locals = always_live_locals; - ineligible_locals.intersect(&**saved_locals); - - // Compute the storage conflicts for all eligible locals. - let mut visitor = StorageConflictVisitor { - body, - saved_locals, - local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), - eligible_storage_live: DenseBitSet::new_empty(body.local_decls.len()), - }; - - visit_reachable_results(body, results, &mut visitor); - - let local_conflicts = visitor.local_conflicts; - - // Compress the matrix using only stored locals (Local -> CoroutineSavedLocal). - // - // NOTE: Today we store a full conflict bitset for every local. Technically - // this is twice as many bits as we need, since the relation is symmetric. - // However, in practice these bitsets are not usually large. The layout code - // also needs to keep track of how many conflicts each local has, so it's - // simpler to keep it this way for now. - let mut storage_conflicts = BitMatrix::new(saved_locals.count(), saved_locals.count()); - for (saved_local_a, local_a) in saved_locals.iter_enumerated() { - if ineligible_locals.contains(local_a) { - // Conflicts with everything. - storage_conflicts.insert_all_into_row(saved_local_a); - } else { - // Keep overlap information only for stored locals. - for (saved_local_b, local_b) in saved_locals.iter_enumerated() { - if local_conflicts.contains(local_a, local_b) { - storage_conflicts.insert(saved_local_a, saved_local_b); - } - } - } - } - storage_conflicts -} - -struct StorageConflictVisitor<'a, 'tcx> { - body: &'a Body<'tcx>, - saved_locals: &'a CoroutineSavedLocals, - // FIXME(tmandry): Consider using sparse bitsets here once we have good - // benchmarks for coroutines. - local_conflicts: BitMatrix, - // We keep this bitset as a buffer to avoid reallocating memory. - eligible_storage_live: DenseBitSet, -} - -impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> - for StorageConflictVisitor<'a, 'tcx> -{ - fn visit_after_early_statement_effect( - &mut self, - _analysis: &MaybeRequiresStorage<'a, 'tcx>, - state: &DenseBitSet, - _statement: &Statement<'tcx>, - loc: Location, - ) { - self.apply_state(state, loc); - } - - fn visit_after_early_terminator_effect( - &mut self, - _analysis: &MaybeRequiresStorage<'a, 'tcx>, - state: &DenseBitSet, - _terminator: &Terminator<'tcx>, - loc: Location, - ) { - self.apply_state(state, loc); - } -} - -impl StorageConflictVisitor<'_, '_> { - fn apply_state(&mut self, state: &DenseBitSet, loc: Location) { - // Ignore unreachable blocks. - if let TerminatorKind::Unreachable = self.body.basic_blocks[loc.block].terminator().kind { - return; - } - - self.eligible_storage_live.clone_from(state); - self.eligible_storage_live.intersect(&**self.saved_locals); - - for local in self.eligible_storage_live.iter() { - self.local_conflicts.union_row_with(&self.eligible_storage_live, local); - } - - if self.eligible_storage_live.count() > 1 { - trace!("at {:?}, eligible_storage_live={:?}", loc, self.eligible_storage_live); - } - } -} - -#[tracing::instrument(level = "trace", skip(liveness, body))] -fn compute_layout<'tcx>( - liveness: LivenessInfo, - body: &Body<'tcx>, -) -> ( - IndexVec, VariantIdx, FieldIdx)>>, - CoroutineLayout<'tcx>, - IndexVec>>, -) { - let LivenessInfo { - saved_locals, - live_locals_at_suspension_points, - source_info_at_suspension_points, - storage_conflicts, - storage_liveness, - } = liveness; - - // Gather live local types. - let mut tys: IndexVec> = saved_locals - .iter_enumerated() - .map(|(saved_local, local)| { - debug!("coroutine saved local {:?} => {:?}", saved_local, local); - - let decl = &body.local_decls[local]; - - // Do not `unwrap_crate_local` here, as post-borrowck cleanup may have already cleared - // the information. This is alright, since `ignore_for_traits` is only relevant when - // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer - // default. - let ignore_for_traits = match decl.local_info { - // Do not include raw pointers created from accessing `static` items, as those could - // well be re-created by another access to the same static. - ClearCrossCrate::Set(LocalInfo::StaticRef { is_thread_local, .. }) => { - !is_thread_local - } - // Fake borrows are only read by fake reads, so do not have any reality in - // post-analysis MIR. - ClearCrossCrate::Set(LocalInfo::FakeBorrow) => true, - _ => false, - }; - - CoroutineSavedTy { - ty: decl.ty, - source_info: decl.source_info, - ignore_for_traits, - // Will be set later when walking debuginfo. - debuginfo_name: None, - } - }) - .collect(); - - // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states. - // In debuginfo, these will correspond to the beginning (UNRESUMED) or end - // (RETURNED, POISONED) of the function. - let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span; - let mut variant_source_info: IndexVec = IndexVec::with_capacity( - CoroutineArgs::RESERVED_VARIANTS + live_locals_at_suspension_points.len(), - ); - variant_source_info.extend([ - SourceInfo::outermost(body_span.shrink_to_lo()), - SourceInfo::outermost(body_span.shrink_to_hi()), - SourceInfo::outermost(body_span.shrink_to_hi()), - ]); - - // Simple map from new to old indices to avoid repeatedly counting bits. - let reverse_local_map: IndexVec = saved_locals.iter().collect(); - - // Build the coroutine variant field list. - // Create a map from local indices to coroutine struct indices. - let mut variant_fields: IndexVec = IndexVec::from_elem_n( - IndexVec::new(), - CoroutineArgs::RESERVED_VARIANTS + live_locals_at_suspension_points.len(), - ); - let mut remap = IndexVec::from_elem_n(None, saved_locals.domain_size()); - for (live_locals, &source_info_at_suspension_point, (variant_index, fields)) in izip!( - &live_locals_at_suspension_points, - &source_info_at_suspension_points, - variant_fields.iter_enumerated_mut().skip(CoroutineArgs::RESERVED_VARIANTS) - ) { - *fields = live_locals.iter().collect(); - for (idx, &saved_local) in fields.iter_enumerated() { - // Note that if a field is included in multiple variants, we will - // just use the first one here. That's fine; fields do not move - // around inside coroutines, so it doesn't matter which variant - // index we access them by. - remap[reverse_local_map[saved_local]] = Some((tys[saved_local].ty, variant_index, idx)); - } - variant_source_info.push(source_info_at_suspension_point); - } - debug!(?variant_fields); - debug!(?storage_conflicts); - - for var in &body.var_debug_info { - let VarDebugInfoContents::Place(place) = &var.value else { continue }; - let Some(local) = place.as_local() else { continue }; - let Some(&Some((_, variant, field))) = remap.get(local) else { - continue; - }; - - let saved_local: CoroutineSavedLocal = variant_fields[variant][field]; - tys[saved_local].debuginfo_name.get_or_insert(var.name); - } - - let layout = - CoroutineLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; - debug!(?remap); - debug!(?layout); - debug!(?storage_liveness); - - (remap, layout, storage_liveness) -} - /// Replaces the entry point of `body` with a block that switches on the coroutine discriminant and /// dispatches to blocks according to `cases`. /// @@ -1375,79 +964,6 @@ fn create_cases<'tcx>( .collect() } -#[instrument(level = "debug", skip(tcx), ret)] -pub(crate) fn mir_coroutine_witnesses<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, -) -> Option> { - let (body, _) = tcx.mir_promoted(def_id); - let body = body.borrow(); - let body = &*body; - - // The first argument is the coroutine type passed by value - let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; - - let movable = match *coroutine_ty.kind() { - ty::Coroutine(def_id, _) => tcx.coroutine_movability(def_id) == hir::Movability::Movable, - ty::Error(_) => return None, - _ => span_bug!(body.span, "unexpected coroutine type {}", coroutine_ty), - }; - - // The witness simply contains all locals live across suspend points. - - let always_live_locals = always_storage_live_locals(body); - let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); - - // Extract locals which are live across suspension point into `layout` - // `remap` gives a mapping from local indices onto coroutine struct indices - // `storage_liveness` tells us which locals have live storage at suspension points - let (_, coroutine_layout, _) = compute_layout(liveness_info, body); - - check_suspend_tys(tcx, &coroutine_layout, body); - check_field_tys_sized(tcx, &coroutine_layout, def_id); - - Some(coroutine_layout) -} - -fn check_field_tys_sized<'tcx>( - tcx: TyCtxt<'tcx>, - coroutine_layout: &CoroutineLayout<'tcx>, - def_id: LocalDefId, -) { - // No need to check if unsized_fn_params is disabled, - // since we will error during typeck. - if !tcx.features().unsized_fn_params() { - return; - } - - // FIXME(#132279): @lcnr believes that we may want to support coroutines - // whose `Sized`-ness relies on the hidden types of opaques defined by the - // parent function. In this case we'd have to be able to reveal only these - // opaques here. - let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); - let param_env = tcx.param_env(def_id); - - let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - for field_ty in &coroutine_layout.field_tys { - ocx.register_bound( - ObligationCause::new( - field_ty.source_info.span, - def_id, - ObligationCauseCode::SizedCoroutineInterior(def_id), - ), - param_env, - field_ty.ty, - tcx.require_lang_item(hir::LangItem::Sized, field_ty.source_info.span), - ); - } - - let errors = ocx.evaluate_obligations_error_on_ambiguity(); - debug!(?errors); - if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(errors); - } -} - impl<'tcx> crate::MirPass<'tcx> for StateTransform { #[instrument(level = "debug", skip(self, tcx, body), ret)] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -1773,202 +1289,3 @@ impl<'tcx> Visitor<'tcx> for EnsureCoroutineFieldAssignmentsNeverAlias<'_> { } } } - -fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &CoroutineLayout<'tcx>, body: &Body<'tcx>) { - let mut linted_tys = FxHashSet::default(); - - for (variant, yield_source_info) in - layout.variant_fields.iter().zip(&layout.variant_source_info) - { - debug!(?variant); - for &local in variant { - let decl = &layout.field_tys[local]; - debug!(?decl); - - if !decl.ignore_for_traits && linted_tys.insert(decl.ty) { - let Some(hir_id) = decl.source_info.scope.lint_root(&body.source_scopes) else { - continue; - }; - - check_must_not_suspend_ty( - tcx, - decl.ty, - hir_id, - SuspendCheckData { - source_span: decl.source_info.span, - yield_span: yield_source_info.span, - plural_len: 1, - ..Default::default() - }, - ); - } - } - } -} - -#[derive(Default)] -struct SuspendCheckData<'a> { - source_span: Span, - yield_span: Span, - descr_pre: &'a str, - descr_post: &'a str, - plural_len: usize, -} - -// Returns whether it emitted a diagnostic or not -// Note that this fn and the proceeding one are based on the code -// for creating must_use diagnostics -// -// Note that this technique was chosen over things like a `Suspend` marker trait -// as it is simpler and has precedent in the compiler -fn check_must_not_suspend_ty<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - hir_id: hir::HirId, - data: SuspendCheckData<'_>, -) -> bool { - if ty.is_unit() { - return false; - } - - let plural_suffix = pluralize!(data.plural_len); - - debug!("Checking must_not_suspend for {}", ty); - - match *ty.kind() { - ty::Adt(_, args) if ty.is_box() => { - let boxed_ty = args.type_at(0); - let allocator_ty = args.type_at(1); - check_must_not_suspend_ty( - tcx, - boxed_ty, - hir_id, - SuspendCheckData { descr_pre: &format!("{}boxed ", data.descr_pre), ..data }, - ) || check_must_not_suspend_ty( - tcx, - allocator_ty, - hir_id, - SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data }, - ) - } - // FIXME(sized_hierarchy): This should be replaced with a requirement that types in - // coroutines implement `const Sized`. Scalable vectors are temporarily `Sized` while - // `feature(sized_hierarchy)` is not fully implemented, but in practice are - // non-`const Sized` and so do not have a known size at compilation time. Layout computation - // for a coroutine containing scalable vectors would be incorrect. - ty::Adt(def, _) if def.repr().scalable() => { - tcx.dcx() - .span_err(data.source_span, "scalable vectors cannot be held over await points"); - true - } - ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data), - // FIXME: support adding the attribute to TAITs - ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: def }, .. }) => { - let mut has_emitted = false; - for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() { - // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::ClauseKind::Trait(ref poly_trait_predicate) = - predicate.kind().skip_binder() - { - let def_id = poly_trait_predicate.trait_ref.def_id; - let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix); - if check_must_not_suspend_def( - tcx, - def_id, - hir_id, - SuspendCheckData { descr_pre, ..data }, - ) { - has_emitted = true; - break; - } - } - } - has_emitted - } - ty::Dynamic(binder, _) => { - let mut has_emitted = false; - for predicate in binder.iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { - let def_id = trait_ref.def_id; - let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post); - if check_must_not_suspend_def( - tcx, - def_id, - hir_id, - SuspendCheckData { descr_post, ..data }, - ) { - has_emitted = true; - break; - } - } - } - has_emitted - } - ty::Tuple(fields) => { - let mut has_emitted = false; - for (i, ty) in fields.iter().enumerate() { - let descr_post = &format!(" in tuple element {i}"); - if check_must_not_suspend_ty( - tcx, - ty, - hir_id, - SuspendCheckData { descr_post, ..data }, - ) { - has_emitted = true; - } - } - has_emitted - } - ty::Array(ty, len) => { - let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); - check_must_not_suspend_ty( - tcx, - ty, - hir_id, - SuspendCheckData { - descr_pre, - // FIXME(must_not_suspend): This is wrong. We should handle printing unevaluated consts. - plural_len: len.try_to_target_usize(tcx).unwrap_or(0) as usize + 1, - ..data - }, - ) - } - // If drop tracking is enabled, we want to look through references, since the referent - // may not be considered live across the await point. - ty::Ref(_region, ty, _mutability) => { - let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix); - check_must_not_suspend_ty(tcx, ty, hir_id, SuspendCheckData { descr_pre, ..data }) - } - _ => false, - } -} - -fn check_must_not_suspend_def( - tcx: TyCtxt<'_>, - def_id: DefId, - hir_id: hir::HirId, - data: SuspendCheckData<'_>, -) -> bool { - if let Some(reason_str) = find_attr!(tcx, def_id, MustNotSupend {reason} => reason) { - let reason = - reason_str.map(|s| errors::MustNotSuspendReason { span: data.source_span, reason: s }); - tcx.emit_node_span_lint( - rustc_session::lint::builtin::MUST_NOT_SUSPEND, - hir_id, - data.source_span, - errors::MustNotSupend { - tcx, - yield_sp: data.yield_span, - reason, - src_sp: data.source_span, - pre: data.descr_pre, - def_id, - post: data.descr_post, - }, - ); - - true - } else { - false - } -} diff --git a/compiler/rustc_mir_transform/src/coroutine/layout.rs b/compiler/rustc_mir_transform/src/coroutine/layout.rs new file mode 100644 index 0000000000000..ed997cc08a888 --- /dev/null +++ b/compiler/rustc_mir_transform/src/coroutine/layout.rs @@ -0,0 +1,722 @@ +//! Coroutine `StateTransform` inverts control flow in a coroutine from a function with yield +//! points to a state machine. Each yield point corresponds to a state variant, and each variant +//! stores the locals that are needed to continue the coroutine. +//! +//! The state transform creates a `poll` method such that calling the coroutine `f()` is equivalent +//! to: +//! ```rust (ignore) +//! fn initial_mir(state: CoroutineState, mut resume_arg: ResumeTy) { +//! // Repeatedly poll the state machine. +//! loop { +//! match final_mir(&mut state, resume_arg) { +//! CoroutineState::Yielded(yield_value) => resume_arg = yield yield_value, +//! CoroutineState::Complete(return_value) => return return_value, +//! } +//! } +//! } +//! ``` +//! +//! This file compute for each yield point the set of locals that need to be saved in the coroutine +//! state. This is also used for borrowck to compute the set of types held inside that state, which +//! determine trait and region predicates that hold for this state. + +use std::ops; + +use itertools::izip; +use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::pluralize; +use rustc_hir::{self as hir, find_attr}; +use rustc_index::bit_set::{BitMatrix, DenseBitSet}; +use rustc_index::{Idx, IndexVec}; +use rustc_middle::mir::*; +use rustc_middle::span_bug; +use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, Ty, TyCtxt, TypingMode}; +use rustc_mir_dataflow::impls::{ + MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, + always_storage_live_locals, +}; +use rustc_mir_dataflow::{ + Analysis, Results, ResultsCursor, ResultsVisitor, visit_reachable_results, +}; +use rustc_span::Span; +use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::infer::TyCtxtInferExt as _; +use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; +use tracing::{debug, instrument, trace}; + +use crate::errors::{MustNotSupend, MustNotSuspendReason}; + +const SELF_ARG: Local = Local::arg(0); + +pub(super) struct LivenessInfo { + /// Which locals are live across any suspension point. + pub(super) saved_locals: CoroutineSavedLocals, + + /// The set of saved locals live at each suspension point. + live_locals_at_suspension_points: Vec>, + + /// Parallel vec to the above with SourceInfo for each yield terminator. + source_info_at_suspension_points: Vec, + + /// For every saved local, the set of other saved locals that are + /// storage-live at the same time as this local. We cannot overlap locals in + /// the layout which have conflicting storage. + pub(super) storage_conflicts: BitMatrix, + + /// For every suspending block, the locals which are storage-live across + /// that suspension point. + storage_liveness: IndexVec>>, +} + +/// Computes which locals have to be stored in the state-machine for the +/// given coroutine. +/// +/// The basic idea is as follows: +/// - a local is live until we encounter a `StorageDead` statement. In +/// case none exist, the local is considered to be always live. +/// - a local has to be stored if it is either directly used after the +/// the suspend point, or if it is live and has been previously borrowed. +#[tracing::instrument(level = "trace", skip(tcx, body))] +pub(super) fn locals_live_across_suspend_points<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + always_live_locals: &DenseBitSet, + movable: bool, +) -> LivenessInfo { + // Calculate when MIR locals have live storage. This gives us an upper bound of their + // lifetimes. + let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals)) + .iterate_to_fixpoint(tcx, body, None) + .into_results_cursor(body); + + // Calculate the MIR locals that have been previously borrowed (even if they are still active). + let borrowed_locals = MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); + let borrowed_locals_cursor1 = ResultsCursor::new_borrowing(body, &borrowed_locals); + let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing(body, &borrowed_locals); + + // Calculate the MIR locals that we need to keep storage around for. + let requires_storage = + MaybeRequiresStorage::new(borrowed_locals_cursor1).iterate_to_fixpoint(tcx, body, None); + let mut requires_storage_cursor = ResultsCursor::new_borrowing(body, &requires_storage); + + // Calculate the liveness of MIR locals ignoring borrows. + let mut liveness = + MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")).into_results_cursor(body); + + let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks); + let mut live_locals_at_suspension_points = Vec::new(); + let mut source_info_at_suspension_points = Vec::new(); + let mut live_locals_at_any_suspension_point = DenseBitSet::new_empty(body.local_decls.len()); + + for (block, data) in body.basic_blocks.iter_enumerated() { + let TerminatorKind::Yield { .. } = data.terminator().kind else { continue }; + + let loc = Location { block, statement_index: data.statements.len() }; + + liveness.seek_to_block_end(block); + let mut live_locals = liveness.get().clone(); + + if !movable { + // The `liveness` variable contains the liveness of MIR locals ignoring borrows. + // This is correct for movable coroutines since borrows cannot live across + // suspension points. However for immovable coroutines we need to account for + // borrows, so we conservatively assume that all borrowed locals are live until + // we find a StorageDead statement referencing the locals. + // To do this we just union our `liveness` result with `borrowed_locals`, which + // contains all the locals which has been borrowed before this suspension point. + // If a borrow is converted to a raw reference, we must also assume that it lives + // forever. Note that the final liveness is still bounded by the storage liveness + // of the local, which happens using the `intersect` operation below. + borrowed_locals_cursor2.seek_before_primary_effect(loc); + live_locals.union(borrowed_locals_cursor2.get()); + } + + // Store the storage liveness for later use so we can restore the state + // after a suspension point + storage_live.seek_before_primary_effect(loc); + storage_liveness_map[block] = Some(storage_live.get().clone()); + + // Locals live are live at this point only if they are used across + // suspension points (the `liveness` variable) + // and their storage is required (the `storage_required` variable) + requires_storage_cursor.seek_before_primary_effect(loc); + live_locals.intersect(requires_storage_cursor.get()); + + // The coroutine argument is ignored. + live_locals.remove(SELF_ARG); + + debug!(?loc, ?live_locals); + + // Add the locals live at this suspension point to the set of locals which live across + // any suspension points + live_locals_at_any_suspension_point.union(&live_locals); + + live_locals_at_suspension_points.push(live_locals); + source_info_at_suspension_points.push(data.terminator().source_info); + } + + debug!(?live_locals_at_any_suspension_point); + let saved_locals = CoroutineSavedLocals(live_locals_at_any_suspension_point); + + // Renumber our liveness_map bitsets to include only the locals we are + // saving. + let live_locals_at_suspension_points = live_locals_at_suspension_points + .iter() + .map(|live_here| saved_locals.renumber_bitset(live_here)) + .collect(); + + let storage_conflicts = compute_storage_conflicts( + body, + &saved_locals, + always_live_locals.clone(), + &requires_storage, + ); + + LivenessInfo { + saved_locals, + live_locals_at_suspension_points, + source_info_at_suspension_points, + storage_conflicts, + storage_liveness: storage_liveness_map, + } +} + +/// The set of `Local`s that must be saved across yield points. +/// +/// `CoroutineSavedLocal` is indexed in terms of the elements in this set; +/// i.e. `CoroutineSavedLocal::new(1)` corresponds to the second local +/// included in this set. +pub(super) struct CoroutineSavedLocals(DenseBitSet); + +impl CoroutineSavedLocals { + /// Returns an iterator over each `CoroutineSavedLocal` along with the `Local` it corresponds + /// to. + fn iter_enumerated(&self) -> impl '_ + Iterator { + self.iter().enumerate().map(|(i, l)| (CoroutineSavedLocal::from(i), l)) + } + + /// Transforms a `DenseBitSet` that contains only locals saved across yield points to the + /// equivalent `DenseBitSet`. + fn renumber_bitset(&self, input: &DenseBitSet) -> DenseBitSet { + assert!(self.superset(input), "{:?} not a superset of {:?}", self.0, input); + let mut out = DenseBitSet::new_empty(self.count()); + for (saved_local, local) in self.iter_enumerated() { + if input.contains(local) { + out.insert(saved_local); + } + } + out + } + + pub(super) fn get(&self, local: Local) -> Option { + if !self.contains(local) { + return None; + } + + let idx = self.iter().take_while(|&l| l < local).count(); + Some(CoroutineSavedLocal::new(idx)) + } +} + +impl ops::Deref for CoroutineSavedLocals { + type Target = DenseBitSet; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// For every saved local, looks for which locals are StorageLive at the same +/// time. Generates a bitset for every local of all the other locals that may be +/// StorageLive simultaneously with that local. This is used in the layout +/// computation; see `CoroutineLayout` for more. +fn compute_storage_conflicts<'mir, 'tcx>( + body: &'mir Body<'tcx>, + saved_locals: &'mir CoroutineSavedLocals, + always_live_locals: DenseBitSet, + results: &Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, +) -> BitMatrix { + assert_eq!(body.local_decls.len(), saved_locals.domain_size()); + + debug!("compute_storage_conflicts({:?})", body.span); + debug!("always_live = {:?}", always_live_locals); + + // Locals that are always live or ones that need to be stored across + // suspension points are not eligible for overlap. + let mut ineligible_locals = always_live_locals; + ineligible_locals.intersect(&**saved_locals); + + // Compute the storage conflicts for all eligible locals. + let mut visitor = StorageConflictVisitor { + body, + saved_locals, + local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), + eligible_storage_live: DenseBitSet::new_empty(body.local_decls.len()), + }; + + visit_reachable_results(body, results, &mut visitor); + + let local_conflicts = visitor.local_conflicts; + + // Compress the matrix using only stored locals (Local -> CoroutineSavedLocal). + // + // NOTE: Today we store a full conflict bitset for every local. Technically + // this is twice as many bits as we need, since the relation is symmetric. + // However, in practice these bitsets are not usually large. The layout code + // also needs to keep track of how many conflicts each local has, so it's + // simpler to keep it this way for now. + let mut storage_conflicts = BitMatrix::new(saved_locals.count(), saved_locals.count()); + for (saved_local_a, local_a) in saved_locals.iter_enumerated() { + if ineligible_locals.contains(local_a) { + // Conflicts with everything. + storage_conflicts.insert_all_into_row(saved_local_a); + } else { + // Keep overlap information only for stored locals. + for (saved_local_b, local_b) in saved_locals.iter_enumerated() { + if local_conflicts.contains(local_a, local_b) { + storage_conflicts.insert(saved_local_a, saved_local_b); + } + } + } + } + storage_conflicts +} + +struct StorageConflictVisitor<'a, 'tcx> { + body: &'a Body<'tcx>, + saved_locals: &'a CoroutineSavedLocals, + // FIXME(tmandry): Consider using sparse bitsets here once we have good + // benchmarks for coroutines. + local_conflicts: BitMatrix, + // We keep this bitset as a buffer to avoid reallocating memory. + eligible_storage_live: DenseBitSet, +} + +impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> + for StorageConflictVisitor<'a, 'tcx> +{ + fn visit_after_early_statement_effect( + &mut self, + _analysis: &MaybeRequiresStorage<'a, 'tcx>, + state: &DenseBitSet, + _statement: &Statement<'tcx>, + loc: Location, + ) { + self.apply_state(state, loc); + } + + fn visit_after_early_terminator_effect( + &mut self, + _analysis: &MaybeRequiresStorage<'a, 'tcx>, + state: &DenseBitSet, + _terminator: &Terminator<'tcx>, + loc: Location, + ) { + self.apply_state(state, loc); + } +} + +impl StorageConflictVisitor<'_, '_> { + fn apply_state(&mut self, state: &DenseBitSet, loc: Location) { + // Ignore unreachable blocks. + if let TerminatorKind::Unreachable = self.body.basic_blocks[loc.block].terminator().kind { + return; + } + + self.eligible_storage_live.clone_from(state); + self.eligible_storage_live.intersect(&**self.saved_locals); + + for local in self.eligible_storage_live.iter() { + self.local_conflicts.union_row_with(&self.eligible_storage_live, local); + } + + if self.eligible_storage_live.count() > 1 { + trace!("at {:?}, eligible_storage_live={:?}", loc, self.eligible_storage_live); + } + } +} + +#[tracing::instrument(level = "trace", skip(liveness, body))] +pub(super) fn compute_layout<'tcx>( + liveness: LivenessInfo, + body: &Body<'tcx>, +) -> ( + IndexVec, VariantIdx, FieldIdx)>>, + CoroutineLayout<'tcx>, + IndexVec>>, +) { + let LivenessInfo { + saved_locals, + live_locals_at_suspension_points, + source_info_at_suspension_points, + storage_conflicts, + storage_liveness, + } = liveness; + + // Gather live local types. + let mut tys: IndexVec> = saved_locals + .iter_enumerated() + .map(|(saved_local, local)| { + debug!("coroutine saved local {:?} => {:?}", saved_local, local); + + let decl = &body.local_decls[local]; + + // Do not `unwrap_crate_local` here, as post-borrowck cleanup may have already cleared + // the information. This is alright, since `ignore_for_traits` is only relevant when + // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer + // default. + let ignore_for_traits = match decl.local_info { + // Do not include raw pointers created from accessing `static` items, as those could + // well be re-created by another access to the same static. + ClearCrossCrate::Set(LocalInfo::StaticRef { is_thread_local, .. }) => { + !is_thread_local + } + // Fake borrows are only read by fake reads, so do not have any reality in + // post-analysis MIR. + ClearCrossCrate::Set(LocalInfo::FakeBorrow) => true, + _ => false, + }; + + CoroutineSavedTy { + ty: decl.ty, + source_info: decl.source_info, + ignore_for_traits, + // Will be set later when walking debuginfo. + debuginfo_name: None, + } + }) + .collect(); + + // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states. + // In debuginfo, these will correspond to the beginning (UNRESUMED) or end + // (RETURNED, POISONED) of the function. + let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span; + let mut variant_source_info: IndexVec = IndexVec::with_capacity( + CoroutineArgs::RESERVED_VARIANTS + live_locals_at_suspension_points.len(), + ); + variant_source_info.extend([ + SourceInfo::outermost(body_span.shrink_to_lo()), + SourceInfo::outermost(body_span.shrink_to_hi()), + SourceInfo::outermost(body_span.shrink_to_hi()), + ]); + + // Simple map from new to old indices to avoid repeatedly counting bits. + let reverse_local_map: IndexVec = saved_locals.iter().collect(); + + // Build the coroutine variant field list. + // Create a map from local indices to coroutine struct indices. + let mut variant_fields: IndexVec = IndexVec::from_elem_n( + IndexVec::new(), + CoroutineArgs::RESERVED_VARIANTS + live_locals_at_suspension_points.len(), + ); + let mut remap = IndexVec::from_elem_n(None, saved_locals.domain_size()); + for (live_locals, &source_info_at_suspension_point, (variant_index, fields)) in izip!( + &live_locals_at_suspension_points, + &source_info_at_suspension_points, + variant_fields.iter_enumerated_mut().skip(CoroutineArgs::RESERVED_VARIANTS) + ) { + *fields = live_locals.iter().collect(); + for (idx, &saved_local) in fields.iter_enumerated() { + // Note that if a field is included in multiple variants, we will + // just use the first one here. That's fine; fields do not move + // around inside coroutines, so it doesn't matter which variant + // index we access them by. + remap[reverse_local_map[saved_local]] = Some((tys[saved_local].ty, variant_index, idx)); + } + variant_source_info.push(source_info_at_suspension_point); + } + debug!(?variant_fields); + debug!(?storage_conflicts); + + for var in &body.var_debug_info { + let VarDebugInfoContents::Place(place) = &var.value else { continue }; + let Some(local) = place.as_local() else { continue }; + let Some(&Some((_, variant, field))) = remap.get(local) else { + continue; + }; + + let saved_local: CoroutineSavedLocal = variant_fields[variant][field]; + tys[saved_local].debuginfo_name.get_or_insert(var.name); + } + + let layout = + CoroutineLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; + debug!(?remap); + debug!(?layout); + debug!(?storage_liveness); + + (remap, layout, storage_liveness) +} + +#[instrument(level = "debug", skip(tcx), ret)] +pub(crate) fn mir_coroutine_witnesses<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> Option> { + let (body, _) = tcx.mir_promoted(def_id); + let body = body.borrow(); + let body = &*body; + + // The first argument is the coroutine type passed by value + let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; + + let movable = match *coroutine_ty.kind() { + ty::Coroutine(def_id, _) => tcx.coroutine_movability(def_id) == hir::Movability::Movable, + ty::Error(_) => return None, + _ => span_bug!(body.span, "unexpected coroutine type {}", coroutine_ty), + }; + + // The witness simply contains all locals live across suspend points. + + let always_live_locals = always_storage_live_locals(body); + let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); + + // Extract locals which are live across suspension point into `layout` + // `remap` gives a mapping from local indices onto coroutine struct indices + // `storage_liveness` tells us which locals have live storage at suspension points + let (_, coroutine_layout, _) = compute_layout(liveness_info, body); + + check_suspend_tys(tcx, &coroutine_layout, body); + check_field_tys_sized(tcx, &coroutine_layout, def_id); + + Some(coroutine_layout) +} + +fn check_field_tys_sized<'tcx>( + tcx: TyCtxt<'tcx>, + coroutine_layout: &CoroutineLayout<'tcx>, + def_id: LocalDefId, +) { + // No need to check if unsized_fn_params is disabled, + // since we will error during typeck. + if !tcx.features().unsized_fn_params() { + return; + } + + // FIXME(#132279): @lcnr believes that we may want to support coroutines + // whose `Sized`-ness relies on the hidden types of opaques defined by the + // parent function. In this case we'd have to be able to reveal only these + // opaques here. + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); + let param_env = tcx.param_env(def_id); + + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); + for field_ty in &coroutine_layout.field_tys { + ocx.register_bound( + ObligationCause::new( + field_ty.source_info.span, + def_id, + ObligationCauseCode::SizedCoroutineInterior(def_id), + ), + param_env, + field_ty.ty, + tcx.require_lang_item(hir::LangItem::Sized, field_ty.source_info.span), + ); + } + + let errors = ocx.evaluate_obligations_error_on_ambiguity(); + debug!(?errors); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(errors); + } +} + +fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &CoroutineLayout<'tcx>, body: &Body<'tcx>) { + let mut linted_tys = FxHashSet::default(); + + for (variant, yield_source_info) in + layout.variant_fields.iter().zip(&layout.variant_source_info) + { + debug!(?variant); + for &local in variant { + let decl = &layout.field_tys[local]; + debug!(?decl); + + if !decl.ignore_for_traits && linted_tys.insert(decl.ty) { + let Some(hir_id) = decl.source_info.scope.lint_root(&body.source_scopes) else { + continue; + }; + + check_must_not_suspend_ty( + tcx, + decl.ty, + hir_id, + SuspendCheckData { + source_span: decl.source_info.span, + yield_span: yield_source_info.span, + plural_len: 1, + ..Default::default() + }, + ); + } + } + } +} + +#[derive(Default)] +struct SuspendCheckData<'a> { + source_span: Span, + yield_span: Span, + descr_pre: &'a str, + descr_post: &'a str, + plural_len: usize, +} + +// Returns whether it emitted a diagnostic or not +// Note that this fn and the proceeding one are based on the code +// for creating must_use diagnostics +// +// Note that this technique was chosen over things like a `Suspend` marker trait +// as it is simpler and has precedent in the compiler +fn check_must_not_suspend_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + hir_id: hir::HirId, + data: SuspendCheckData<'_>, +) -> bool { + if ty.is_unit() { + return false; + } + + let plural_suffix = pluralize!(data.plural_len); + + debug!("Checking must_not_suspend for {}", ty); + + match *ty.kind() { + ty::Adt(_, args) if ty.is_box() => { + let boxed_ty = args.type_at(0); + let allocator_ty = args.type_at(1); + check_must_not_suspend_ty( + tcx, + boxed_ty, + hir_id, + SuspendCheckData { descr_pre: &format!("{}boxed ", data.descr_pre), ..data }, + ) || check_must_not_suspend_ty( + tcx, + allocator_ty, + hir_id, + SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data }, + ) + } + // FIXME(sized_hierarchy): This should be replaced with a requirement that types in + // coroutines implement `const Sized`. Scalable vectors are temporarily `Sized` while + // `feature(sized_hierarchy)` is not fully implemented, but in practice are + // non-`const Sized` and so do not have a known size at compilation time. Layout computation + // for a coroutine containing scalable vectors would be incorrect. + ty::Adt(def, _) if def.repr().scalable() => { + tcx.dcx() + .span_err(data.source_span, "scalable vectors cannot be held over await points"); + true + } + ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data), + // FIXME: support adding the attribute to TAITs + ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: def }, .. }) => { + let mut has_emitted = false; + for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() { + // We only look at the `DefId`, so it is safe to skip the binder here. + if let ty::ClauseKind::Trait(ref poly_trait_predicate) = + predicate.kind().skip_binder() + { + let def_id = poly_trait_predicate.trait_ref.def_id; + let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix); + if check_must_not_suspend_def( + tcx, + def_id, + hir_id, + SuspendCheckData { descr_pre, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Dynamic(binder, _) => { + let mut has_emitted = false; + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { + let def_id = trait_ref.def_id; + let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post); + if check_must_not_suspend_def( + tcx, + def_id, + hir_id, + SuspendCheckData { descr_post, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Tuple(fields) => { + let mut has_emitted = false; + for (i, ty) in fields.iter().enumerate() { + let descr_post = &format!(" in tuple element {i}"); + if check_must_not_suspend_ty( + tcx, + ty, + hir_id, + SuspendCheckData { descr_post, ..data }, + ) { + has_emitted = true; + } + } + has_emitted + } + ty::Array(ty, len) => { + let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); + check_must_not_suspend_ty( + tcx, + ty, + hir_id, + SuspendCheckData { + descr_pre, + // FIXME(must_not_suspend): This is wrong. We should handle printing unevaluated consts. + plural_len: len.try_to_target_usize(tcx).unwrap_or(0) as usize + 1, + ..data + }, + ) + } + // If drop tracking is enabled, we want to look through references, since the referent + // may not be considered live across the await point. + ty::Ref(_region, ty, _mutability) => { + let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix); + check_must_not_suspend_ty(tcx, ty, hir_id, SuspendCheckData { descr_pre, ..data }) + } + _ => false, + } +} + +fn check_must_not_suspend_def( + tcx: TyCtxt<'_>, + def_id: DefId, + hir_id: hir::HirId, + data: SuspendCheckData<'_>, +) -> bool { + if let Some(reason_str) = find_attr!(tcx, def_id, MustNotSupend {reason} => reason) { + let reason = reason_str.map(|s| MustNotSuspendReason { span: data.source_span, reason: s }); + tcx.emit_node_span_lint( + rustc_session::lint::builtin::MUST_NOT_SUSPEND, + hir_id, + data.source_span, + MustNotSupend { + tcx, + yield_sp: data.yield_span, + reason, + src_sp: data.source_span, + pre: data.descr_pre, + def_id, + post: data.descr_post, + }, + ); + + true + } else { + false + } +} From 62690a61004d70983648e9b7e337f115624afbde Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 31 May 2026 08:40:09 +0000 Subject: [PATCH 06/14] Move coroutine.rs to be a mod.rs --- .../rustc_mir_transform/src/{coroutine.rs => coroutine/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename compiler/rustc_mir_transform/src/{coroutine.rs => coroutine/mod.rs} (100%) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine/mod.rs similarity index 100% rename from compiler/rustc_mir_transform/src/coroutine.rs rename to compiler/rustc_mir_transform/src/coroutine/mod.rs From e3468ae5f97b5bc2fac1b98609d9303dcfffca3d Mon Sep 17 00:00:00 2001 From: cezarbbb Date: Tue, 2 Jun 2026 09:50:03 +0800 Subject: [PATCH 07/14] Promotes 5 Thumb-mode bare-metal Arm targets to Tier 2 --- .../src/spec/targets/thumbv7a_none_eabi.rs | 2 +- .../src/spec/targets/thumbv7a_none_eabihf.rs | 2 +- .../src/spec/targets/thumbv7r_none_eabi.rs | 2 +- .../src/spec/targets/thumbv7r_none_eabihf.rs | 2 +- .../src/spec/targets/thumbv8r_none_eabihf.rs | 2 +- .../docker/host-x86_64/dist-various-1/Dockerfile | 15 +++++++++++++++ src/doc/rustc/src/platform-support.md | 10 +++++----- .../rustc/src/platform-support/arm-none-eabi.md | 3 +++ .../src/platform-support/armv7a-none-eabi.md | 3 +-- .../src/platform-support/armv7r-none-eabi.md | 3 +-- .../src/platform-support/armv8r-none-eabihf.md | 3 +-- 11 files changed, 31 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs index 4e20f04173f0e..011307a50c346 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7a-none-eabi".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-A".into()), - tier: Some(3), + tier: Some(2), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs index bf4241a47277a..4baa73c3cdb8b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7a-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-A, hardfloat".into()), - tier: Some(3), + tier: Some(2), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs index 296a1d00bad3b..da66a53432003 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7r-none-eabi".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-R".into()), - tier: Some(3), + tier: Some(2), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs index 8d5ac8a2d0a36..d591db8faf6a8 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7r-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-R, hardfloat".into()), - tier: Some(3), + tier: Some(2), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs index 808287ffa3d64..459dff9c1aa9b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv8r-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv8-R, hardfloat".into()), - tier: Some(3), + tier: Some(2), host_tools: Some(false), std: Some(false), }, diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index 33b48de872711..415709d388a99 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -114,11 +114,16 @@ ENV TARGETS=$TARGETS,riscv32imafc-unknown-none-elf ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf ENV TARGETS=$TARGETS,riscv64gc-unknown-none-elf ENV TARGETS=$TARGETS,armv7r-none-eabi +ENV TARGETS=$TARGETS,thumbv7r-none-eabi ENV TARGETS=$TARGETS,armv7r-none-eabihf +ENV TARGETS=$TARGETS,thumbv7r-none-eabihf ENV TARGETS=$TARGETS,armv8r-none-eabihf +ENV TARGETS=$TARGETS,thumbv8r-none-eabihf ENV TARGETS=$TARGETS,thumbv7neon-unknown-linux-gnueabihf ENV TARGETS=$TARGETS,armv7a-none-eabi +ENV TARGETS=$TARGETS,thumbv7a-none-eabi ENV TARGETS=$TARGETS,armv7a-none-eabihf +ENV TARGETS=$TARGETS,thumbv7a-none-eabihf ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" \ CFLAGS_arm_unknown_linux_musleabi="-march=armv6 -marm" \ @@ -133,8 +138,18 @@ ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft CC_armv7a_none_eabihf=arm-none-eabi-gcc \ CFLAGS_armv7a_none_eabi=-march=armv7-a \ CFLAGS_armv7a_none_eabihf=-march=armv7-a+fp \ + CC_thumbv7a_none_eabi=arm-none-eabi-gcc \ + CC_thumbv7a_none_eabihf=arm-none-eabi-gcc \ + CFLAGS_thumbv7a_none_eabi=-march=armv7-a \ + CFLAGS_thumbv7a_none_eabihf="-march=armv7-a+fp -mfpu=vfpv3-d16" \ + CC_thumbv7r_none_eabi=arm-none-eabi-gcc \ + CC_thumbv7r_none_eabihf=arm-none-eabi-gcc \ + CFLAGS_thumbv7r_none_eabi=-march=armv7-r \ + CFLAGS_thumbv7r_none_eabihf="-march=armv7-r+fp -mfpu=vfpv3-d16" \ CC_armv8r_none_eabihf=arm-none-eabi-gcc \ CFLAGS_armv8r_none_eabihf="-march=armv8-r+fp.sp -mfpu=fp-armv8" \ + CC_thumbv8r_none_eabihf=arm-none-eabi-gcc \ + CFLAGS_thumbv8r_none_eabihf="-march=armv8-r+fp.sp -mfpu=fp-armv8" \ CC_aarch64_unknown_none_softfloat=aarch64-none-elf-gcc \ CFLAGS_aarch64_unknown_none_softfloat=-mstrict-align -march=armv8-a+nofp+nosimd \ CC_aarch64_unknown_none=aarch64-none-elf-gcc \ diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 26dd6b31b8991..7cbfb8dd11345 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -174,6 +174,11 @@ target | std | notes [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat [`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | Bare Armv8-R, hardfloat +[`thumbv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | Thumb-mode Bare Armv7-A +[`thumbv7a-none-eabihf`](platform-support/armv7a-none-eabi.md) | * | Thumb-mode Bare Armv7-A, hardfloat +[`thumbv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Thumb-mode Bare Armv7-R +[`thumbv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Thumb-mode Bare Armv7-R, hardfloat +[`thumbv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | Thumb-mode Bare Armv8-R, hardfloat `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2+, glibc 2.17, original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.5, original Pentium) [^x86_32-floats-x87] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] @@ -419,8 +424,6 @@ target | std | host | notes [`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare Armv5TE [`thumbv6-none-eabi`](platform-support/armv6-none-eabi.md) | * | | Thumb-mode Bare Armv6 [`thumbv6m-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv6M with NuttX -[`thumbv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | | Thumb-mode Bare Armv7-A -[`thumbv7a-none-eabihf`](platform-support/armv7a-none-eabi.md) | * | | Thumb-mode Bare Armv7-A, hardfloat [`thumbv7a-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX [`thumbv7a-nuttx-eabihf`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX, hardfloat `thumbv7a-pc-windows-msvc` | | | @@ -429,12 +432,9 @@ target | std | host | notes [`thumbv7em-nuttx-eabihf`](platform-support/nuttx.md) | ✓ | | ARMv7EM with NuttX, hardfloat [`thumbv7m-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv7M with NuttX `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode Armv7-A Linux with NEON, musl 1.2.5 -[`thumbv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | | Thumb-mode Bare Armv7-R -[`thumbv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | | Thumb-mode Bare Armv7-R, hardfloat [`thumbv8m.base-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv8M Baseline with NuttX [`thumbv8m.main-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv8M Mainline with NuttX [`thumbv8m.main-nuttx-eabihf`](platform-support/nuttx.md) | ✓ | | ARMv8M Mainline with NuttX, hardfloat -[`thumbv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Thumb-mode Bare Armv8-R, hardfloat [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly [`wasm32-wali-linux-musl`](platform-support/wasm32-wali-linux.md) | ? | | WebAssembly with [WALI](https://github.com/arjunr2/WALI) [`wasm32-wasip3`](platform-support/wasm32-wasip3.md) | ✓ | | WebAssembly with WASIp3 diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md index cf1fe9ed59ed6..5d22cef92d220 100644 --- a/src/doc/rustc/src/platform-support/arm-none-eabi.md +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -13,10 +13,13 @@ their own document. - Arm A-Profile Architectures - [`armv7a-none-eabi`](armv7a-none-eabi.md) + - [`thumbv7a-none-eabi` and `thumbv7a-none-eabihf`](armv7a-none-eabi.md) - Arm R-Profile Architectures - [`armv7r-none-eabi` and `armv7r-none-eabihf`](armv7r-none-eabi.md) - [`armebv7r-none-eabi` and `armebv7r-none-eabihf`](armebv7r-none-eabi.md) - [`armv8r-none-eabihf`](armv8r-none-eabihf.md) + - [`thumbv7r-none-eabi` and `thumbv7r-none-eabihf`](armv7r-none-eabi.md) + - [`thumbv8r-none-eabihf`](armv8r-none-eabihf.md) - Arm M-Profile Architectures - [`thumbv6m-none-eabi`](thumbv6m-none-eabi.md) - [`thumbv7m-none-eabi`](thumbv7m-none-eabi.md) diff --git a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md index 0fa09d3955ff3..73f2e303579a0 100644 --- a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md @@ -1,7 +1,6 @@ # `armv7a-none-eabi*` and `thumbv7a-none-eabi*` -* **Tier: 2** (`armv7a-none-eabi` and `armv7a-none-eabihf`) -* **Tier: 3** (`thumbv7a-none-eabi` and `thumbv7a-none-eabihf`) +* **Tier: 2** * **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the Armv7-A architecture family, supporting dual diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md index 5f95af44a7935..d4937052a95ce 100644 --- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md @@ -1,7 +1,6 @@ # `armv7r-none-eabi*` and `thumbv7r-none-eabi*` -* **Tier: 2** (`armv7r-none-eabi` and `armv7r-none-eabihf`) -* **Tier: 3** (`thumbv7r-none-eabi` and `thumbv7r-none-eabihf`) +* **Tier: 2** * **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the Armv7-R architecture family, supporting dual diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md index 1ff36b47beb2f..2f6d83e01b27d 100644 --- a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md +++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md @@ -1,7 +1,6 @@ # `armv8r-none-eabihf` and `thumbv8r-none-eabihf` -* **Tier: 2**: `armv8r-none-eabihf` -* **Tier: 3**: `thumbv8r-none-eabihf` +* **Tier: 2** * **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the Armv8-R architecture family, supporting dual From ac63a3e4aeb0a6d42918b942f7819eac0f149f8c Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Tue, 2 Jun 2026 15:26:17 +0000 Subject: [PATCH 08/14] Pacify doc-checker. --- compiler/rustc_mir_transform/src/coroutine/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/coroutine/layout.rs b/compiler/rustc_mir_transform/src/coroutine/layout.rs index ed997cc08a888..be8402f082e62 100644 --- a/compiler/rustc_mir_transform/src/coroutine/layout.rs +++ b/compiler/rustc_mir_transform/src/coroutine/layout.rs @@ -4,7 +4,7 @@ //! //! The state transform creates a `poll` method such that calling the coroutine `f()` is equivalent //! to: -//! ```rust (ignore) +//! ```ignore (example) //! fn initial_mir(state: CoroutineState, mut resume_arg: ResumeTy) { //! // Repeatedly poll the state machine. //! loop { From 9b7623a1621a3fedd1eb7f3cdac4b48e9f819013 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 25 May 2026 20:11:36 +0200 Subject: [PATCH 09/14] Remove -Zemscripten-wasm-eh This was necessary when transitioning from JS to wasm exception handling on Emscripten. Enough time has probably passed that we no longer need to support JS exception handling on Emscripten. This enables cleaning up a fair bit of code. --- compiler/rustc_codegen_llvm/src/context.rs | 20 --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 85 +---------- compiler/rustc_codegen_llvm/src/llvm_util.rs | 7 - compiler/rustc_codegen_llvm/src/type_.rs | 4 - compiler/rustc_codegen_ssa/src/back/link.rs | 8 +- compiler/rustc_codegen_ssa/src/base.rs | 1 - compiler/rustc_feature/src/builtin_attrs.rs | 1 - compiler/rustc_feature/src/unstable.rs | 2 - compiler/rustc_hir/src/lang_items.rs | 1 - compiler/rustc_hir/src/weak_lang_items.rs | 1 - compiler/rustc_interface/src/tests.rs | 1 - .../rustc_middle/src/middle/lang_items.rs | 8 +- compiler/rustc_passes/src/weak_lang_items.rs | 13 +- compiler/rustc_session/src/config/cfg.rs | 6 - compiler/rustc_session/src/options.rs | 2 - compiler/rustc_span/src/symbol.rs | 4 - library/panic_abort/src/lib.rs | 43 ------ library/panic_unwind/Cargo.toml | 4 - library/panic_unwind/src/emcc.rs | 135 ------------------ library/panic_unwind/src/lib.rs | 15 +- library/unwind/Cargo.toml | 2 +- library/unwind/src/lib.rs | 3 +- .../wasm32-unknown-emscripten.md | 3 +- .../src/compiler-flags/emscripten-wasm-eh.md | 6 - .../src/language-features/lang-items.md | 3 +- .../emscripten-catch-unwind-js-eh.rs | 71 --------- ...-wasm-eh.rs => emscripten-catch-unwind.rs} | 4 +- tests/codegen-llvm/terminating-catchpad.rs | 2 +- tests/codegen-llvm/wasm_exceptions.rs | 2 +- ...llowed-cli-cfgs.emscripten_wasm_eh_.stderr | 8 -- tests/ui/cfg/disallowed-cli-cfgs.rs | 2 - .../const-eval/const_panic_libcore_bin.rs | 2 - tests/ui/extern-flag/empty-extern-arg.rs | 1 - .../feature-gate-cfg-emscripten-wasm-eh.rs | 4 - ...feature-gate-cfg-emscripten-wasm-eh.stderr | 12 -- .../macros/macro-comma-behavior.core.stderr | 16 +-- tests/ui/macros/macro-comma-behavior.rs | 1 - .../ui/macros/macro-comma-behavior.std.stderr | 26 ++-- tests/ui/panic-handler/weak-lang-item.rs | 1 - tests/ui/panic-handler/weak-lang-item.stderr | 2 +- .../auxiliary/panic-runtime-lang-items.rs | 2 - tests/ui/range/issue-54505-no-std.rs | 3 - tests/ui/range/issue-54505-no-std.stderr | 26 ++-- 43 files changed, 56 insertions(+), 507 deletions(-) delete mode 100644 library/panic_unwind/src/emcc.rs delete mode 100644 src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md delete mode 100644 tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs rename tests/codegen-llvm/{emscripten-catch-unwind-wasm-eh.rs => emscripten-catch-unwind.rs} (96%) delete mode 100644 tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr delete mode 100644 tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs delete mode 100644 tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 6e0ff1c75149b..85a7f9cab73a4 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -26,7 +26,6 @@ use rustc_session::config::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet, }; use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, sym}; -use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{ Arch, CfgAbi, Env, FramePointer, HasTargetSpec, Os, RelocModel, SmallDataThresholdSupport, Target, TlsModel, @@ -136,7 +135,6 @@ pub(crate) struct FullCx<'ll, 'tcx> { pub dbg_cx: Option>, eh_personality: Cell>, - eh_catch_typeinfo: Cell>, pub rust_try_fn: Cell>, intrinsics: @@ -672,7 +670,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { coverage_cx, dbg_cx, eh_personality: Cell::new(None), - eh_catch_typeinfo: Cell::new(None), rust_try_fn: Cell::new(None), intrinsics: Default::default(), local_gen_sym_counter: Cell::new(0), @@ -1042,23 +1039,6 @@ impl<'ll> CodegenCx<'ll, '_> { } } } - - pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value { - if let Some(eh_catch_typeinfo) = self.eh_catch_typeinfo.get() { - return eh_catch_typeinfo; - } - let tcx = self.tcx; - assert!(self.sess().target.os == Os::Emscripten); - let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() { - Some(def_id) => self.get_static(def_id), - _ => { - let ty = self.type_struct(&[self.type_ptr(), self.type_ptr()], false); - self.declare_global(&mangle_internal_symbol(self.tcx, "rust_eh_catch_typeinfo"), ty) - } - }; - self.eh_catch_typeinfo.set(Some(eh_catch_typeinfo)); - eh_catch_typeinfo - } } impl CodegenCx<'_, '_> { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 1c7b415fd04c7..393837375769e 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -28,7 +28,7 @@ use rustc_session::lint::builtin::DEPRECATED_LLVM_INTRINSIC; use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate}; use rustc_target::callconv::PassMode; -use rustc_target::spec::{Arch, Os}; +use rustc_target::spec::Arch; use tracing::debug; use crate::abi::FnAbiLlvmExt; @@ -1356,8 +1356,6 @@ fn catch_unwind_intrinsic<'ll, 'tcx>( codegen_msvc_try(bx, try_func, data, catch_func) } else if wants_wasm_eh(bx.sess()) { codegen_wasm_try(bx, try_func, data, catch_func) - } else if bx.sess().target.os == Os::Emscripten { - codegen_emcc_try(bx, try_func, data, catch_func) } else { codegen_gnu_try(bx, try_func, data, catch_func) } @@ -1654,87 +1652,6 @@ fn codegen_gnu_try<'ll, 'tcx>( ret } -// Variant of codegen_gnu_try used for emscripten where Rust panics are -// implemented using C++ exceptions. Here we use exceptions of a specific type -// (`struct rust_panic`) to represent Rust panics. -fn codegen_emcc_try<'ll, 'tcx>( - bx: &mut Builder<'_, 'll, 'tcx>, - try_func: &'ll Value, - data: &'ll Value, - catch_func: &'ll Value, -) -> &'ll Value { - let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| { - // Codegens the shims described above: - // - // bx: - // invoke %try_func(%data) normal %normal unwind %catch - // - // normal: - // ret 0 - // - // catch: - // (%ptr, %selector) = landingpad - // %rust_typeid = @llvm.eh.typeid.for(@_ZTI10rust_panic) - // %is_rust_panic = %selector == %rust_typeid - // %catch_data = alloca { i8*, i8 } - // %catch_data[0] = %ptr - // %catch_data[1] = %is_rust_panic - // call %catch_func(%data, %catch_data) - // ret 1 - let then = bx.append_sibling_block("then"); - let catch = bx.append_sibling_block("catch"); - - let try_func = llvm::get_param(bx.llfn(), 0); - let data = llvm::get_param(bx.llfn(), 1); - let catch_func = llvm::get_param(bx.llfn(), 2); - let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None); - - bx.switch_to_block(then); - bx.ret(bx.const_bool(false)); - - // Type indicator for the exception being thrown. - // - // The first value in this tuple is a pointer to the exception object - // being thrown. The second value is a "selector" indicating which of - // the landing pad clauses the exception's type had been matched to. - bx.switch_to_block(catch); - let tydesc = bx.eh_catch_typeinfo(); - let lpad_ty = bx.type_struct(&[bx.type_ptr(), bx.type_i32()], false); - let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 2); - bx.add_clause(vals, tydesc); - bx.add_clause(vals, bx.const_null(bx.type_ptr())); - let ptr = bx.extract_value(vals, 0); - let selector = bx.extract_value(vals, 1); - - // Check if the typeid we got is the one for a Rust panic. - let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[bx.val_ty(tydesc)], &[tydesc]); - let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid); - let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool()); - - // We need to pass two values to catch_func (ptr and is_rust_panic), so - // create an alloca and pass a pointer to that. - let ptr_size = bx.tcx().data_layout.pointer_size(); - let ptr_align = bx.tcx().data_layout.pointer_align().abi; - let i8_align = bx.tcx().data_layout.i8_align; - // Required in order for there to be no padding between the fields. - assert!(i8_align <= ptr_align); - let catch_data = bx.alloca(2 * ptr_size, ptr_align); - bx.store(ptr, catch_data, ptr_align); - let catch_data_1 = bx.inbounds_ptradd(catch_data, bx.const_usize(ptr_size.bytes())); - bx.store(is_rust_panic, catch_data_1, i8_align); - - let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, catch_data], None, None); - bx.ret(bx.const_bool(true)); - }); - - // Note that no invoke is used here because by definition this function - // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); - ret -} - // Helper function to give a Block to a closure to codegen a shim function. // This is currently primarily used for the `try` intrinsic functions above. fn gen_fn<'a, 'll, 'tcx>( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index eb1efa31ae4ab..73b7f699b606d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -109,13 +109,6 @@ unsafe fn configure_llvm(sess: &Session) { add("-wasm-enable-eh", false); } - if sess.target.os == Os::Emscripten - && !sess.opts.unstable_opts.emscripten_wasm_eh - && sess.panic_strategy().unwinds() - { - add("-enable-emscripten-cxx-exceptions", false); - } - // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes // during inlining. Unfortunately these may block other optimizations. add("-preserve-alignment-assumptions-during-inlining=false", false); diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 796f3d9ef60ba..0d49971f52533 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -106,10 +106,6 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { - pub(crate) fn type_bool(&self) -> &'ll Type { - self.type_i8() - } - pub(crate) fn type_int_from_ty(&self, t: ty::IntTy) -> &'ll Type { match t { ty::IntTy::Isize => self.type_isize(), diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d54f9141d8225..c0308fecf0d93 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2774,13 +2774,7 @@ fn add_order_independent_options( } if sess.target.os == Os::Emscripten { - cmd.cc_arg(if sess.opts.unstable_opts.emscripten_wasm_eh { - "-fwasm-exceptions" - } else if sess.panic_strategy().unwinds() { - "-sDISABLE_EXCEPTION_CATCHING=0" - } else { - "-sDISABLE_EXCEPTION_CATCHING=1" - }); + cmd.cc_arg("-fwasm-exceptions"); } if flavor == LinkerFlavor::Llbc { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 78bc07869895a..bc4c2aef8da67 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -373,7 +373,6 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // us pub fn wants_wasm_eh(sess: &Session) -> bool { sess.target.is_like_wasm - && (sess.target.os != Os::Emscripten || sess.opts.unstable_opts.emscripten_wasm_eh) } /// Returns `true` if this session's target will use SEH-based unwinding. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 673ac38a1d338..72919028f1ce9 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -32,7 +32,6 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi), // this is consistent with naming of the compiler flag it's for (sym::fmt_debug, sym::fmt_debug, Features::fmt_debug), - (sym::emscripten_wasm_eh, sym::cfg_emscripten_wasm_eh, Features::cfg_emscripten_wasm_eh), ( sym::target_has_reliable_f16, sym::cfg_target_has_reliable_f16_f128, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 388482209cf9e..3040d016195d5 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -250,8 +250,6 @@ declare_features! ( (internal, allow_internal_unstable, "1.0.0", None), /// Allows using anonymous lifetimes in argument-position impl-trait. (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None), - /// Allows access to the emscripten_wasm_eh config, used by panic_unwind and unwind - (internal, cfg_emscripten_wasm_eh, "1.86.0", None), /// Allows checking whether or not the backend correctly supports unstable float types. (internal, cfg_target_has_reliable_f16_f128, "1.88.0", None), /// Allows identifying the `compiler_builtins` crate. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 4a3615e5421fe..2069b746b5a7f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -332,7 +332,6 @@ language_item_table! { Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); EhPersonality, sym::eh_personality, eh_personality, Target::Fn, GenericRequirement::None; - EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None; // Profiling markers for move/copy operations (used by -Z annotate-moves) CompilerMove, sym::compiler_move, compiler_move_fn, Target::Fn, GenericRequirement::Exact(2); diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index b4e548effd46d..85b0e3958c2d6 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -26,5 +26,4 @@ macro_rules! weak_lang_items { weak_lang_items! { PanicImpl, rust_begin_unwind; EhPersonality, rust_eh_personality; - EhCatchTypeinfo, rust_eh_catch_typeinfo; } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 0498d835df5f5..fc124348a202c 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -791,7 +791,6 @@ fn test_unstable_options_tracking_hash() { tracked!(dwarf_version, Some(5)); tracked!(embed_metadata, false); tracked!(embed_source, true); - tracked!(emscripten_wasm_eh, false); tracked!(export_executable_symbols, true); tracked!(fewer_names, Some(true)); tracked!(fixed_x18, true); diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 8a2595e2938b8..07153d688d477 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -109,13 +109,11 @@ impl<'tcx> TyCtxt<'tcx> { /// the case of panic=abort. In these situations some lang items are injected by /// crates and don't actually need to be defined in libstd. pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool { - // If we're not compiling with unwinding, we won't actually need these - // symbols. Other panic runtimes ensure that the relevant symbols are + // If we're not compiling with unwinding, we won't actually need this + // symbol. Other panic runtimes ensure that the relevant symbols are // available to link things together, but they're never exercised. match tcx.sess.panic_strategy() { - PanicStrategy::Abort => { - lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo - } + PanicStrategy::Abort => lang_item != LangItem::EhPersonality, PanicStrategy::Unwind => true, PanicStrategy::ImmediateAbort => false, } diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 4200003ea1d1a..2d5eee183aec4 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -8,7 +8,6 @@ use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use rustc_target::spec::Os; use crate::errors::{ MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd, UnknownExternLangItem, @@ -22,18 +21,12 @@ pub(crate) fn check_crate( items: &mut lang_items::LanguageItems, krate: &ast::Crate, ) { - // These are never called by user code, they're generated by the compiler. - // They will never implicitly be added to the `missing` array unless we do - // so here. + // This is never called by user code, it's generated by the compiler. It + // will never implicitly be added to the `missing` array unless we do so + // here. if items.eh_personality().is_none() { items.missing.push(LangItem::EhPersonality); } - if tcx.sess.target.os == Os::Emscripten - && items.eh_catch_typeinfo().is_none() - && !tcx.sess.opts.unstable_opts.emscripten_wasm_eh - { - items.missing.push(LangItem::EhCatchTypeinfo); - } visit::Visitor::visit_crate(&mut WeakLangItemVisitor { tcx, items }, krate); diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index d16ab59a02d9e..cd301bea4eebf 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -157,7 +157,6 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) { | (sym::target_has_reliable_f128_math, None | Some(_)) | (sym::target_thread_local, None) => disallow(cfg, "--target"), (sym::fmt_debug, None | Some(_)) => disallow(cfg, "-Z fmt-debug"), - (sym::emscripten_wasm_eh, None | Some(_)) => disallow(cfg, "-Z emscripten_wasm_eh"), _ => {} } } @@ -322,11 +321,6 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { ins_none!(sym::ub_checks); } - // Nightly-only implementation detail for the `panic_unwind` and `unwind` crates. - if sess.is_nightly_build() && sess.opts.unstable_opts.emscripten_wasm_eh { - ins_none!(sym::emscripten_wasm_eh); - } - if sess.contract_checks() { ins_none!(sym::contract_checks); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index de606458d048e..57db7a3eba3b7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2315,8 +2315,6 @@ options! { "embed source text in DWARF debug sections (default: no)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), - emscripten_wasm_eh: bool = (true, parse_bool, [TRACKED], - "Use WebAssembly error handling for wasm32-unknown-emscripten"), enforce_type_length_limit: bool = (false, parse_bool, [TRACKED], "enforce the type length limit when monomorphizing instances in codegen"), experimental_default_bounds: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7263680c302f1..cf295142d36b1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -577,7 +577,6 @@ symbols! { cfg_boolean_literals, cfg_contract_checks, cfg_doctest, - cfg_emscripten_wasm_eh, cfg_eval, cfg_overflow_checks, cfg_panic, @@ -854,7 +853,6 @@ symbols! { edition_panic, effective_target_features, effects, - eh_catch_typeinfo, eh_personality, eii, eii_declaration, @@ -871,7 +869,6 @@ symbols! { // to be detected if it accidentally does get used. empty: "", empty_braces: "{}", - emscripten_wasm_eh, enable, end, entry_nops, @@ -1701,7 +1698,6 @@ symbols! { rust_analyzer, rust_begin_unwind, rust_cold_cc, - rust_eh_catch_typeinfo, rust_eh_personality, rust_future, rust_logo, diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index d1706b6525295..e62d758e9e5d1 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -49,46 +49,3 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { __rust_abort() } - -// This... is a bit of an oddity. The tl;dr; is that this is required to link -// correctly, the longer explanation is below. -// -// Right now the binaries of core/std that we ship are all compiled with -// `-C panic=unwind`. This is done to ensure that the binaries are maximally -// compatible with as many situations as possible. The compiler, however, -// requires a "personality function" for all functions compiled with `-C -// panic=unwind`. This personality function is hardcoded to the symbol -// `rust_eh_personality` and is defined by the `eh_personality` lang item. -// -// So... why not just define that lang item here? Good question! The way that -// panic runtimes are linked in is actually a little subtle in that they're -// "sort of" in the compiler's crate store, but only actually linked if another -// isn't actually linked. This ends up meaning that both this crate and the -// panic_unwind crate can appear in the compiler's crate store, and if both -// define the `eh_personality` lang item then that'll hit an error. -// -// To handle this the compiler only requires the `eh_personality` is defined if -// the panic runtime being linked in is the unwinding runtime, and otherwise -// it's not required to be defined (rightfully so). In this case, however, this -// library just defines this symbol so there's at least some personality -// somewhere. -// -// Essentially this symbol is just defined to get wired up to core/std -// binaries, but it should never be called as we don't link in an unwinding -// runtime at all. -pub mod personalities { - // In the past this module used to contain stubs for the personality - // functions of various platforms, but these where removed when personality - // functions were moved to std. - - // This corresponds to the `eh_catch_typeinfo` lang item - // that's only used on Emscripten currently. - // - // Since panics don't generate exceptions and foreign exceptions are - // currently UB with -C panic=abort (although this may be subject to - // change), any catch_unwind calls will never use this typeinfo. - #[rustc_std_internal_symbol] - #[allow(non_upper_case_globals)] - #[cfg(target_os = "emscripten")] - static rust_eh_catch_typeinfo: [usize; 2] = [0; 2]; -} diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index 67fc919c42c2b..72c1041b46795 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -18,7 +18,3 @@ unwind = { path = "../unwind" } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2", default-features = false } - -[lints.rust.unexpected_cfgs] -level = "warn" -check-cfg = ['cfg(emscripten_wasm_eh)'] diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs deleted file mode 100644 index bad795a019c9a..0000000000000 --- a/library/panic_unwind/src/emcc.rs +++ /dev/null @@ -1,135 +0,0 @@ -//! Unwinding for *emscripten* target. -//! -//! Whereas Rust's usual unwinding implementation for Unix platforms -//! calls into the libunwind APIs directly, on Emscripten we instead -//! call into the C++ unwinding APIs. This is just an expedience since -//! Emscripten's runtime always implements those APIs and does not -//! implement libunwind. - -use alloc::boxed::Box; -use core::any::Any; -use core::sync::atomic::{AtomicBool, Ordering}; -use core::{intrinsics, ptr}; - -use unwind as uw; - -// This matches the layout of std::type_info in C++ -#[repr(C)] -struct TypeInfo { - vtable: *const usize, - name: *const u8, -} -unsafe impl Sync for TypeInfo {} - -unsafe extern "C" { - // The leading `\x01` byte here is actually a magical signal to LLVM to - // *not* apply any other mangling like prefixing with a `_` character. - // - // This symbol is the vtable used by C++'s `std::type_info`. Objects of type - // `std::type_info`, type descriptors, have a pointer to this table. Type - // descriptors are referenced by the C++ EH structures defined above and - // that we construct below. - // - // Note that the real size is larger than 3 usize, but we only need our - // vtable to point to the third element. - #[link_name = "\x01_ZTVN10__cxxabiv117__class_type_infoE"] - static CLASS_TYPE_INFO_VTABLE: [usize; 3]; -} - -// std::type_info for a rust_panic class -#[lang = "eh_catch_typeinfo"] -static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo { - // Normally we would use .as_ptr().add(2) but this doesn't work in a const context. - vtable: unsafe { &CLASS_TYPE_INFO_VTABLE[2] }, - // This intentionally doesn't use the normal name mangling scheme because - // we don't want C++ to be able to produce or catch Rust panics. - name: b"rust_panic\0".as_ptr(), -}; - -// NOTE(nbdd0121): The `canary` field is part of stable ABI. -#[repr(C)] -struct Exception { - // See `gcc.rs` on why this is present. We already have a static here so just use it. - canary: *const TypeInfo, - - // This is necessary because C++ code can capture our exception with - // std::exception_ptr and rethrow it multiple times, possibly even in - // another thread. - caught: AtomicBool, - - // This needs to be an Option because the object's lifetime follows C++ - // semantics: when catch_unwind moves the Box out of the exception it must - // still leave the exception object in a valid state because its destructor - // is still going to be called by __cxa_end_catch. - data: Option>, -} - -pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box { - // intrinsics::try actually gives us a pointer to this structure. - #[repr(C)] - struct CatchData { - ptr: *mut u8, - is_rust_panic: bool, - } - unsafe { - let catch_data = &*(ptr as *mut CatchData); - - let adjusted_ptr = __cxa_begin_catch(catch_data.ptr as *mut libc::c_void) as *mut Exception; - if !catch_data.is_rust_panic { - super::__rust_foreign_exception(); - } - - let canary = (&raw const (*adjusted_ptr).canary).read(); - if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) { - super::__rust_foreign_exception(); - } - - let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::Relaxed); - if was_caught { - // Since cleanup() isn't allowed to panic, we just abort instead. - intrinsics::abort(); - } - let out = (*adjusted_ptr).data.take().unwrap(); - __cxa_end_catch(); - out - } -} - -pub(crate) unsafe fn panic(data: Box) -> u32 { - unsafe { - let exception = __cxa_allocate_exception(size_of::()) as *mut Exception; - if exception.is_null() { - return uw::_URC_FATAL_PHASE1_ERROR as u32; - } - ptr::write( - exception, - Exception { - canary: &EXCEPTION_TYPE_INFO, - caught: AtomicBool::new(false), - data: Some(data), - }, - ); - __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup); - } -} - -extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> *mut libc::c_void { - unsafe { - if let Some(b) = (ptr as *mut Exception).read().data { - drop(b); - super::__rust_drop_panic(); - } - ptr - } -} - -unsafe extern "C" { - fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void; - fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void; - fn __cxa_end_catch(); - fn __cxa_throw( - thrown_exception: *mut libc::c_void, - tinfo: *const TypeInfo, - dest: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void, - ) -> !; -} diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index fc0a627d293f3..9d204a150dd45 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -2,11 +2,12 @@ //! //! This crate is an implementation of panics in Rust using "most native" stack //! unwinding mechanism of the platform this is being compiled for. This -//! essentially gets categorized into three buckets currently: +//! essentially gets categorized into four buckets currently: //! -//! 1. MSVC targets use SEH in the `seh.rs` file. -//! 2. Emscripten uses C++ exceptions in the `emcc.rs` file. -//! 3. All other targets use libunwind/libgcc in the `gcc.rs` file. +//! 1. When running inside miri, MSVC targets use Miri intrinsics in the `miri.rs` file. +//! 2. MSVC targets use SEH in the `seh.rs` file. +//! 3. Some targets use an aborting implementation in the `dummy.rs` or `hermit.rs` files. +//! 4. All other targets use libunwind/libgcc in the `gcc.rs` file. //! //! More documentation about each implementation can be found in the respective //! module. @@ -14,8 +15,6 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] -#![cfg_attr(all(target_os = "emscripten", not(emscripten_wasm_eh)), feature(lang_items))] -#![feature(cfg_emscripten_wasm_eh)] #![feature(core_intrinsics)] #![feature(panic_unwind)] #![feature(staged_api)] @@ -33,10 +32,6 @@ use core::any::Any; use core::panic::PanicPayload; cfg_select! { - all(target_os = "emscripten", not(emscripten_wasm_eh)) => { - #[path = "emcc.rs"] - mod imp; - } target_os = "hermit" => { #[path = "hermit.rs"] mod imp; diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index f02744a107082..1293c469d11c1 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -35,4 +35,4 @@ system-llvm-libunwind = [] [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = ['cfg(emscripten_wasm_eh)', 'cfg(target_arch, values("loongarch32"))'] +check-cfg = ['cfg(target_arch, values("loongarch32"))'] diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 22568d5f6f1f9..4e380d8894781 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -1,10 +1,9 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] -#![feature(cfg_emscripten_wasm_eh)] #![feature(link_cfg)] #![feature(staged_api)] #![cfg_attr( - all(target_family = "wasm", any(not(target_os = "emscripten"), emscripten_wasm_eh)), + target_family = "wasm", feature(link_llvm_intrinsics, simd_wasm64, asm_experimental_arch) )] #![allow(internal_features)] diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md index d5e3125fd3c79..0d15097468b17 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md @@ -160,8 +160,7 @@ which features are enabled. Note that Rust code compiled for `wasm32-unknown-emscripten` currently enables `-fwasm-exceptions` (legacy WASM exceptions) by default unless the Rust code is -compiled with `-Cpanic=abort`. It is possible to use JS exceptions by passing -the flag ``-Z emscripten-wasm-eh=false`` but this will be removed in the future. +compiled with `-Cpanic=abort`. Please refer to the [Emscripten ABI compatibility](#emscripten-abi-compatibility) section to ensure that the features that are enabled do not cause an ABI mismatch diff --git a/src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md b/src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md deleted file mode 100644 index eab29a1744b67..0000000000000 --- a/src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md +++ /dev/null @@ -1,6 +0,0 @@ -# `emscripten-wasm-eh` - -Use the WebAssembly exception handling ABI to unwind for the -`wasm32-unknown-emscripten`. If compiling with this setting, the `emcc` linker -should be invoked with `-fwasm-exceptions`. If linking with C/C++ files, the -C/C++ files should also be compiled with `-fwasm-exceptions`. diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index ee4d976dfd246..deb7fbca716c3 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -27,8 +27,7 @@ Some features provided by lang items: failure mechanisms of the compiler. This is often mapped to GCC's personality function (see the [`std` implementation][personality] for more information), but programs which don't trigger a panic can be assured that this function is - never called. Additionally, a `eh_catch_typeinfo` static is needed for certain - targets which implement Rust panics on top of C++ exceptions. + never called. - the traits in `core::marker` used to indicate types of various kinds; e.g. lang items `sized`, `sync` and `copy`. - memory allocation, see below. diff --git a/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs b/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs deleted file mode 100644 index 4f62d3e56a787..0000000000000 --- a/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs +++ /dev/null @@ -1,71 +0,0 @@ -//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten -Z emscripten-wasm-eh=false -//@ needs-llvm-components: webassembly - -// Emscripten has its own unique implementation of catch_unwind (in `codegen_emcc_try`), -// make sure it generates something reasonable. - -#![feature(no_core, lang_items, intrinsics, rustc_attrs)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} -#[lang = "freeze"] -trait Freeze {} -#[lang = "copy"] -trait Copy {} - -impl Copy for *mut T {} - -#[rustc_intrinsic] -const fn size_of() -> usize { - loop {} -} - -#[rustc_intrinsic] -unsafe fn catch_unwind( - try_fn: unsafe fn(_: *mut Data), - data: *mut Data, - catch_fn: unsafe fn(_: *mut Data, _: *mut u8), -) -> bool; - -// CHECK-LABEL: @ptr_size -#[no_mangle] -pub fn ptr_size() -> usize { - // CHECK: ret [[PTR_SIZE:.*]] - const { size_of::<*mut u8>() } -} - -// CHECK-LABEL: @test_catch_unwind -#[no_mangle] -pub unsafe fn test_catch_unwind( - try_fn: unsafe fn(_: *mut u8), - data: *mut u8, - catch_fn: unsafe fn(_: *mut u8, _: *mut u8), -) -> bool { - // CHECK: start: - // CHECK: [[ALLOCA:%.*]] = alloca - - // CHECK: catch.i: - // CHECK: [[LANDINGPAD:%.*]] = landingpad - // CHECK: [[EXCEPTION:%.*]] = extractvalue {{.*}} [[LANDINGPAD]], 0 - // CHECK: [[SELECTOR:%.*]] = extractvalue {{.*}} [[LANDINGPAD]], 1 - - // CHECK: [[IS_RUST_EXN:%.*]] = icmp eq {{.*}}[[SELECTOR]] - // CHECK: [[IS_RUST_EXN_I8:%.*]] = zext i1 [[IS_RUST_EXN]] to i8 - - // CHECK: store ptr [[EXCEPTION]], ptr [[ALLOCA]] - // CHECK: [[IS_RUST_SLOT:%.*]] = getelementptr inbounds{{( nuw)?}} i8, ptr [[ALLOCA]], [[PTR_SIZE]] - // CHECK: store i8 [[IS_RUST_EXN_I8]], ptr [[IS_RUST_SLOT]] - - // CHECK: call void %catch_fn(ptr %data, ptr nonnull [[ALLOCA]]) - - catch_unwind(try_fn, data, catch_fn) -} diff --git a/tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen-llvm/emscripten-catch-unwind.rs similarity index 96% rename from tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs rename to tests/codegen-llvm/emscripten-catch-unwind.rs index 25ac3181ba3b2..b3af16c4ed0ee 100644 --- a/tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs +++ b/tests/codegen-llvm/emscripten-catch-unwind.rs @@ -1,7 +1,7 @@ -//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten -Z emscripten-wasm-eh +//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten //@ needs-llvm-components: webassembly -// Emscripten catch_unwind using wasm exceptions +// Emscripten catch_unwind #![feature(no_core, lang_items, intrinsics, rustc_attrs)] #![crate_type = "lib"] diff --git a/tests/codegen-llvm/terminating-catchpad.rs b/tests/codegen-llvm/terminating-catchpad.rs index 7c98ea94fdc13..cea5d48ab99e5 100644 --- a/tests/codegen-llvm/terminating-catchpad.rs +++ b/tests/codegen-llvm/terminating-catchpad.rs @@ -1,5 +1,5 @@ //@ revisions: emscripten wasi seh -//@[emscripten] compile-flags: --target wasm32-unknown-emscripten -Z emscripten-wasm-eh +//@[emscripten] compile-flags: --target wasm32-unknown-emscripten //@[wasi] compile-flags: --target wasm32-wasip1 -C panic=unwind //@[seh] compile-flags: --target x86_64-pc-windows-msvc //@[emscripten] needs-llvm-components: webassembly diff --git a/tests/codegen-llvm/wasm_exceptions.rs b/tests/codegen-llvm/wasm_exceptions.rs index 48c9c0b50e3fb..b4c024e4ed0e6 100644 --- a/tests/codegen-llvm/wasm_exceptions.rs +++ b/tests/codegen-llvm/wasm_exceptions.rs @@ -1,6 +1,6 @@ //@ only-wasm32 //@ revisions: WASM WASMEXN -//@ [WASMEXN] compile-flags: -C panic=unwind -Z emscripten-wasm-eh +//@ [WASMEXN] compile-flags: -C panic=unwind #![crate_type = "lib"] #![feature(core_intrinsics, link_llvm_intrinsics)] diff --git a/tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr deleted file mode 100644 index 8b2ee0e5c0c3d..0000000000000 --- a/tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: unexpected `--cfg emscripten_wasm_eh` flag - | - = note: config `emscripten_wasm_eh` is only supposed to be controlled by `-Z emscripten_wasm_eh` - = note: manually setting a built-in cfg can and does create incoherent behaviors - = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default - -error: aborting due to 1 previous error - diff --git a/tests/ui/cfg/disallowed-cli-cfgs.rs b/tests/ui/cfg/disallowed-cli-cfgs.rs index 81f3d9313ef1f..57aed0016e971 100644 --- a/tests/ui/cfg/disallowed-cli-cfgs.rs +++ b/tests/ui/cfg/disallowed-cli-cfgs.rs @@ -9,7 +9,6 @@ //@ revisions: target_has_atomic_ target_has_atomic_primitive_alignment_ //@ revisions: target_has_atomic_load_store_ target_thread_local_ relocation_model_ //@ revisions: fmt_debug_ -//@ revisions: emscripten_wasm_eh_ //@ revisions: reliable_f16_ reliable_f16_math_ reliable_f128_ reliable_f128_math_ //@ [overflow_checks_]compile-flags: --cfg overflow_checks @@ -38,7 +37,6 @@ //@ [target_thread_local_]compile-flags: --cfg target_thread_local //@ [relocation_model_]compile-flags: --cfg relocation_model="a" //@ [fmt_debug_]compile-flags: --cfg fmt_debug="shallow" -//@ [emscripten_wasm_eh_]compile-flags: --cfg emscripten_wasm_eh //@ [reliable_f16_]compile-flags: --cfg target_has_reliable_f16 //@ [reliable_f16_math_]compile-flags: --cfg target_has_reliable_f16_math //@ [reliable_f128_]compile-flags: --cfg target_has_reliable_f128 diff --git a/tests/ui/consts/const-eval/const_panic_libcore_bin.rs b/tests/ui/consts/const-eval/const_panic_libcore_bin.rs index 90ae5165d233b..d6fbdb28d56a2 100644 --- a/tests/ui/consts/const-eval/const_panic_libcore_bin.rs +++ b/tests/ui/consts/const-eval/const_panic_libcore_bin.rs @@ -16,8 +16,6 @@ const X: () = unimplemented!(); #[lang = "eh_personality"] fn eh() {} -#[lang = "eh_catch_typeinfo"] -static EH_CATCH_TYPEINFO: u8 = 0; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { diff --git a/tests/ui/extern-flag/empty-extern-arg.rs b/tests/ui/extern-flag/empty-extern-arg.rs index 10cc3be71135e..d57edc6041247 100644 --- a/tests/ui/extern-flag/empty-extern-arg.rs +++ b/tests/ui/extern-flag/empty-extern-arg.rs @@ -2,7 +2,6 @@ //~^ ERROR cannot resolve a prelude import //@ compile-flags: --extern std= //@ needs-unwind since it affects the error output -//@ ignore-emscripten missing eh_catch_typeinfo lang item fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs deleted file mode 100644 index a13e7fa317f5b..0000000000000 --- a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ compile-flags: --check-cfg=cfg(emscripten_wasm_eh) -#[cfg(emscripten_wasm_eh)] -//~^ ERROR `cfg(emscripten_wasm_eh)` is experimental -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr deleted file mode 100644 index a829c9b93a566..0000000000000 --- a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `cfg(emscripten_wasm_eh)` is experimental and subject to change - --> $DIR/feature-gate-cfg-emscripten-wasm-eh.rs:2:7 - | -LL | #[cfg(emscripten_wasm_eh)] - | ^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(cfg_emscripten_wasm_eh)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/macro-comma-behavior.core.stderr b/tests/ui/macros/macro-comma-behavior.core.stderr index ac15e9fa8ea83..e84a33d1f8dee 100644 --- a/tests/ui/macros/macro-comma-behavior.core.stderr +++ b/tests/ui/macros/macro-comma-behavior.core.stderr @@ -1,47 +1,47 @@ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:21:23 + --> $DIR/macro-comma-behavior.rs:20:23 | LL | assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:24:23 + --> $DIR/macro-comma-behavior.rs:23:23 | LL | assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:30:29 + --> $DIR/macro-comma-behavior.rs:29:29 | LL | debug_assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:33:29 + --> $DIR/macro-comma-behavior.rs:32:29 | LL | debug_assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:52:19 + --> $DIR/macro-comma-behavior.rs:51:19 | LL | format_args!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:68:21 + --> $DIR/macro-comma-behavior.rs:67:21 | LL | unimplemented!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:77:24 + --> $DIR/macro-comma-behavior.rs:76:24 | LL | write!(f, "{}",)?; | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:81:26 + --> $DIR/macro-comma-behavior.rs:80:26 | LL | writeln!(f, "{}",)?; | ^^ diff --git a/tests/ui/macros/macro-comma-behavior.rs b/tests/ui/macros/macro-comma-behavior.rs index ea75fdd6842e1..5085f3c9cf83c 100644 --- a/tests/ui/macros/macro-comma-behavior.rs +++ b/tests/ui/macros/macro-comma-behavior.rs @@ -9,7 +9,6 @@ #[cfg(std)] use std::fmt; #[cfg(core)] use core::fmt; #[cfg(core)] #[lang = "eh_personality"] fn eh_personality() {} -#[cfg(core)] #[lang = "eh_catch_typeinfo"] static EH_CATCH_TYPEINFO: u8 = 0; #[cfg(core)] #[panic_handler] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} } // (see documentation of the similarly-named test in run-pass) diff --git a/tests/ui/macros/macro-comma-behavior.std.stderr b/tests/ui/macros/macro-comma-behavior.std.stderr index 7fd060e222498..e29737e0522a4 100644 --- a/tests/ui/macros/macro-comma-behavior.std.stderr +++ b/tests/ui/macros/macro-comma-behavior.std.stderr @@ -1,77 +1,77 @@ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:21:23 + --> $DIR/macro-comma-behavior.rs:20:23 | LL | assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:24:23 + --> $DIR/macro-comma-behavior.rs:23:23 | LL | assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:30:29 + --> $DIR/macro-comma-behavior.rs:29:29 | LL | debug_assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:33:29 + --> $DIR/macro-comma-behavior.rs:32:29 | LL | debug_assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:38:18 + --> $DIR/macro-comma-behavior.rs:37:18 | LL | eprint!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:43:20 + --> $DIR/macro-comma-behavior.rs:42:20 | LL | eprintln!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:48:18 + --> $DIR/macro-comma-behavior.rs:47:18 | LL | format!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:52:19 + --> $DIR/macro-comma-behavior.rs:51:19 | LL | format_args!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:59:17 + --> $DIR/macro-comma-behavior.rs:58:17 | LL | print!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:64:19 + --> $DIR/macro-comma-behavior.rs:63:19 | LL | println!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:68:21 + --> $DIR/macro-comma-behavior.rs:67:21 | LL | unimplemented!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:77:24 + --> $DIR/macro-comma-behavior.rs:76:24 | LL | write!(f, "{}",)?; | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:81:26 + --> $DIR/macro-comma-behavior.rs:80:26 | LL | writeln!(f, "{}",)?; | ^^ diff --git a/tests/ui/panic-handler/weak-lang-item.rs b/tests/ui/panic-handler/weak-lang-item.rs index a8f7aadf6c722..43a235fd6b418 100644 --- a/tests/ui/panic-handler/weak-lang-item.rs +++ b/tests/ui/panic-handler/weak-lang-item.rs @@ -1,7 +1,6 @@ //@ edition:2015 //@ aux-build:weak-lang-items.rs //@ needs-unwind since it affects the error output -//@ ignore-emscripten missing eh_catch_typeinfo lang item #![no_std] diff --git a/tests/ui/panic-handler/weak-lang-item.stderr b/tests/ui/panic-handler/weak-lang-item.stderr index eb5f4ad56ea31..5acd3e3187051 100644 --- a/tests/ui/panic-handler/weak-lang-item.stderr +++ b/tests/ui/panic-handler/weak-lang-item.stderr @@ -1,5 +1,5 @@ error[E0259]: the name `core` is defined multiple times - --> $DIR/weak-lang-item.rs:8:1 + --> $DIR/weak-lang-item.rs:7:1 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ `core` reimported here diff --git a/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs b/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs index 44137b85748fa..1a4346a410b47 100644 --- a/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs +++ b/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs @@ -11,5 +11,3 @@ use core::panic::PanicInfo; fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} -#[lang = "eh_catch_typeinfo"] -static EH_CATCH_TYPEINFO: u8 = 0; diff --git a/tests/ui/range/issue-54505-no-std.rs b/tests/ui/range/issue-54505-no-std.rs index 0c913f766b709..6ddfc7e231464 100644 --- a/tests/ui/range/issue-54505-no-std.rs +++ b/tests/ui/range/issue-54505-no-std.rs @@ -12,9 +12,6 @@ use core::ops::RangeBounds; #[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] #[lang = "eh_personality"] extern "C" fn eh_personality() {} -#[cfg(target_os = "emscripten")] -#[lang = "eh_catch_typeinfo"] -static EH_CATCH_TYPEINFO: u8 = 0; #[panic_handler] fn panic_handler(_: &core::panic::PanicInfo) -> ! { diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr index 866a82afb7e2f..456f9454e5404 100644 --- a/tests/ui/range/issue-54505-no-std.stderr +++ b/tests/ui/range/issue-54505-no-std.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:29:16 + --> $DIR/issue-54505-no-std.rs:26:16 | LL | take_range(0..1); | ---------- ^^^^ expected `&_`, found `Range<{integer}>` @@ -9,7 +9,7 @@ LL | take_range(0..1); = note: expected reference `&_` found struct `core::ops::Range<{integer}>` note: function defined here - --> $DIR/issue-54505-no-std.rs:25:4 + --> $DIR/issue-54505-no-std.rs:22:4 | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- @@ -19,7 +19,7 @@ LL | take_range(&(0..1)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:34:16 + --> $DIR/issue-54505-no-std.rs:31:16 | LL | take_range(1..); | ---------- ^^^ expected `&_`, found `RangeFrom<{integer}>` @@ -29,7 +29,7 @@ LL | take_range(1..); = note: expected reference `&_` found struct `core::ops::RangeFrom<{integer}>` note: function defined here - --> $DIR/issue-54505-no-std.rs:25:4 + --> $DIR/issue-54505-no-std.rs:22:4 | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- @@ -39,7 +39,7 @@ LL | take_range(&(1..)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:39:16 + --> $DIR/issue-54505-no-std.rs:36:16 | LL | take_range(..); | ---------- ^^ expected `&_`, found `RangeFull` @@ -49,12 +49,12 @@ LL | take_range(..); = note: expected reference `&_` found struct `RangeFull` note: function defined here - --> $DIR/issue-54505-no-std.rs:25:4 + --> $DIR/issue-54505-no-std.rs:22:4 | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals when `#![feature(default_field_values)]` is enabled; it is instead interpreted as a `std::ops::RangeFull` literal - --> $DIR/issue-54505-no-std.rs:39:16 + --> $DIR/issue-54505-no-std.rs:36:16 | LL | take_range(..); | ^^ @@ -64,7 +64,7 @@ LL | take_range(&(..)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:45:16 + --> $DIR/issue-54505-no-std.rs:42:16 | LL | take_range(0..=1); | ---------- ^^^^^ expected `&_`, found `RangeInclusive<{integer}>` @@ -74,7 +74,7 @@ LL | take_range(0..=1); = note: expected reference `&_` found struct `core::ops::RangeInclusive<{integer}>` note: function defined here - --> $DIR/issue-54505-no-std.rs:25:4 + --> $DIR/issue-54505-no-std.rs:22:4 | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- @@ -84,7 +84,7 @@ LL | take_range(&(0..=1)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:50:16 + --> $DIR/issue-54505-no-std.rs:47:16 | LL | take_range(..5); | ---------- ^^^ expected `&_`, found `RangeTo<{integer}>` @@ -94,7 +94,7 @@ LL | take_range(..5); = note: expected reference `&_` found struct `RangeTo<{integer}>` note: function defined here - --> $DIR/issue-54505-no-std.rs:25:4 + --> $DIR/issue-54505-no-std.rs:22:4 | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- @@ -104,7 +104,7 @@ LL | take_range(&(..5)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:55:16 + --> $DIR/issue-54505-no-std.rs:52:16 | LL | take_range(..=42); | ---------- ^^^^^ expected `&_`, found `RangeToInclusive<{integer}>` @@ -114,7 +114,7 @@ LL | take_range(..=42); = note: expected reference `&_` found struct `core::ops::RangeToInclusive<{integer}>` note: function defined here - --> $DIR/issue-54505-no-std.rs:25:4 + --> $DIR/issue-54505-no-std.rs:22:4 | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- From 3a850decb23b38befecba1d0a81641df9ecbbb10 Mon Sep 17 00:00:00 2001 From: Jarl Evanson Date: Tue, 2 Jun 2026 19:55:45 +0000 Subject: [PATCH 10/14] bootstrap: enable `clippy::mem_replace_with_default` --- src/bootstrap/src/core/build_steps/clippy.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 9e5bfd2e60e9c..d3b533c954293 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -607,6 +607,7 @@ impl Step for CI { "clippy::single_char_add_str".into(), "clippy::to_string_in_format_args".into(), "clippy::unconditional_recursion".into(), + "clippy::mem_replace_with_default".into(), ], forbid: vec![], }; From 3dacac8f4bb2d09de567e501c8b4a0d427b4d8a8 Mon Sep 17 00:00:00 2001 From: Jarl Evanson Date: Tue, 2 Jun 2026 20:37:47 +0000 Subject: [PATCH 11/14] compiler: fix `clippy::mem_replace_with_default` warnings --- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- compiler/rustc_middle/src/dep_graph/serialized.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 38bde976b1b02..37546d4aa056d 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1964,7 +1964,7 @@ impl Emitter for SharedEmitter { assert_eq!(diag.is_lint, None); // No sensible check for `diag.emitted_at`. - let args = mem::replace(&mut diag.args, DiagArgMap::default()); + let args = mem::take(&mut diag.args); drop( self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { span: diag.span.primary_spans().iter().map(|span| span.data()).collect::>(), diff --git a/compiler/rustc_middle/src/dep_graph/serialized.rs b/compiler/rustc_middle/src/dep_graph/serialized.rs index ef5e3d9268ad7..6d7f8e37e6c0a 100644 --- a/compiler/rustc_middle/src/dep_graph/serialized.rs +++ b/compiler/rustc_middle/src/dep_graph/serialized.rs @@ -738,7 +738,7 @@ impl EncoderState { // Prevent more indices from being allocated on this thread. local.remaining_node_index = 0; - let data = mem::replace(&mut local.encoder.data, Vec::new()); + let data = mem::take(&mut local.encoder.data); self.file.lock().as_mut().unwrap().emit_raw_bytes(&data); LocalEncoderResult { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 2371bf15756da..13dea1657339e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2573,7 +2573,7 @@ fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec) // directly, let's rather steal the contents of `src`. This makes the code // safe even if a panic occurs. - let mut buf = std::mem::replace(src, String::new()).into_bytes(); + let mut buf = std::mem::take(src).into_bytes(); let mut gap_len = 0; let mut tail = buf.as_mut_slice(); let mut cursor = 0; From c2b9f3955a25cd685184ee0168d7d1d7722d2d05 Mon Sep 17 00:00:00 2001 From: Mathis B <134849385+mathisbot@users.noreply.github.com> Date: Tue, 2 Jun 2026 19:48:58 +0100 Subject: [PATCH 12/14] windows: remove division-by-zero checks for performance counters this removes the panic path when dividing by the frequency. this also makes calls to Instant::now() faster. --- library/std/src/sys/pal/windows/time.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index b4b1d50a88896..2646ad28b84a2 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -20,7 +20,7 @@ pub fn intervals2dur(intervals: u64) -> Duration { pub mod perf_counter { use super::NANOS_PER_SEC; - use crate::sync::atomic::{Atomic, AtomicU64, Ordering}; + use crate::sync::atomic::{AtomicI64, Ordering}; use crate::sys::{c, cvt}; use crate::time::Duration; @@ -32,23 +32,32 @@ pub mod perf_counter { pub fn frequency() -> i64 { // Either the cached result of `QueryPerformanceFrequency` or `0` for - // uninitialized. Storing this as a single `AtomicU64` allows us to use + // uninitialized. Storing this as a single `AtomicI64` allows us to use // `Relaxed` operations, as we are only interested in the effects on a // single memory location. - static FREQUENCY: Atomic = AtomicU64::new(0); + static FREQUENCY: AtomicI64 = AtomicI64::new(0); let cached = FREQUENCY.load(Ordering::Relaxed); // If a previous thread has filled in this global state, use that. if cached != 0 { - return cached as i64; + return cached; } // ... otherwise learn for ourselves ... + frequency_init(&FREQUENCY) + } + + #[cold] + fn frequency_init(cache: &AtomicI64) -> i64 { let mut frequency = 0; unsafe { cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap(); } - FREQUENCY.store(frequency as u64, Ordering::Relaxed); + // SAFETY: According to the MSDN entry for `QueryPerformanceFrequency`, + // a value of 0 will never be returned starting from Windows XP. + unsafe { crate::hint::assert_unchecked(frequency != 0) } + + cache.store(frequency, Ordering::Relaxed); frequency } From b6a204f32b1008877556bcc0b089f9a0c3ce8532 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 2 Jun 2026 22:25:24 +0200 Subject: [PATCH 13/14] Rewrite target checking for `#[link]` --- .../src/attributes/link_attrs.rs | 3 +- compiler/rustc_passes/src/check_attr.rs | 18 +- compiler/rustc_passes/src/errors.rs | 5 +- tests/ui/attributes/malformed-attrs.rs | 2 +- tests/ui/attributes/malformed-attrs.stderr | 25 +- .../issue-43106-gating-of-builtin-attrs.rs | 38 +- ...issue-43106-gating-of-builtin-attrs.stderr | 553 +++++++++--------- tests/ui/malformed/malformed-regressions.rs | 4 +- .../ui/malformed/malformed-regressions.stderr | 33 +- 9 files changed, 343 insertions(+), 338 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 24798d94c56e2..bc500ddd48acf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -70,7 +70,8 @@ impl CombineAttributeParser for LinkParser { r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#, r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#, ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::ForeignMod)]); const STABILITY: AttributeStability = AttributeStability::Stable; fn extend( diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a265325fd8e77..d698a7ed4127a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -230,7 +230,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &AttributeKind::Sanitize { on_set, off_set, rtsan: _, span: attr_span } => { self.check_sanitize(attr_span, on_set | off_set, span, target); } - AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, span, target), + AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, target), AttributeKind::MacroExport { span, .. } => { self.check_macro_export(hir_id, *span, target) } @@ -1126,21 +1126,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[link]` is applied to an item other than a foreign module. - fn check_link(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { - if target == Target::ForeignMod - && let hir::Node::Item(item) = self.tcx.hir_node(hir_id) + fn check_link(&self, hir_id: HirId, attr_span: Span, target: Target) { + if target != Target::ForeignMod { + return; // Checked by attribute parser + } + + if let hir::Node::Item(item) = self.tcx.hir_node(hir_id) && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item && !matches!(abi, ExternAbi::Rust) { return; } - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::Link { span: (target != Target::ForeignMod).then_some(span) }, - ); + self.tcx.emit_node_span_lint(UNUSED_ATTRIBUTES, hir_id, attr_span, errors::Link); } /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 66c33b3e49756..97dd413e16cf6 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -183,10 +183,7 @@ pub(crate) struct BothFfiConstAndPure { #[warning( "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" )] -pub(crate) struct Link { - #[label("not an `extern` block")] - pub span: Option, -} +pub(crate) struct Link; #[derive(Diagnostic)] #[diag("#[rustc_legacy_const_generics] functions must only have const generics")] diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index 8eb1f3bcfd346..5823ea81bc7bd 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -80,7 +80,7 @@ //~^ ERROR malformed #[link] //~^ ERROR malformed -//~| WARN attribute should be applied to an `extern` block with non-Rust ABI +//~| WARN attribute cannot be used on //~| WARN previously accepted #[link_name] //~^ ERROR malformed diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 4026c49295138..9d82a84a45d4f 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -814,21 +814,6 @@ LL | | #[coroutine = 63] || {} LL | | } | |_- not a `const fn` -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/malformed-attrs.rs:81:1 - | -LL | #[link] - | ^^^^^^^ -... -LL | / fn test() { -LL | | #[coroutine = 63] || {} -... | -LL | | } - | |_- not an `extern` block - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: requested on the command line with `-W unused-attributes` - error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` --> $DIR/malformed-attrs.rs:41:1 | @@ -865,6 +850,7 @@ LL | | #[coroutine = 63] || {} ... | LL | | } | |_^ + = note: requested on the command line with `-W unused-attributes` error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` --> $DIR/malformed-attrs.rs:75:1 @@ -872,6 +858,15 @@ error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, ` LL | #[doc] | ^^^^^^ +warning: `#[link]` attribute cannot be used on functions + --> $DIR/malformed-attrs.rs:81:1 + | +LL | #[link] + | ^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: `#[link_name]` attribute cannot be used on functions --> $DIR/malformed-attrs.rs:85:1 | 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 8f3e98cfc2a7c..093fb3a4a8a03 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 @@ -1,4 +1,3 @@ -//~ NOTE not an `extern` block // This test enumerates as many compiler-builtin ungated attributes as // possible (that is, all the mutually compatible ones), and checks // that we get "expected" (*) warnings for each in the various weird @@ -67,8 +66,10 @@ //~| WARN previously accepted //~| HELP can only be applied to //~| HELP remove the attribute -#![link(name = "x")] //~ WARN attribute should be applied to an `extern` block -//~^ WARN this was previously accepted +#![link(name = "x")] //~ WARN attribute cannot be used on +//~| WARN this was previously accepted +//~| HELP can only be applied to foreign modules +//~| HELP remove the attribute #![link_name = "1900"] //~^ WARN attribute cannot be used on //~| WARN previously accepted @@ -683,35 +684,40 @@ mod link_section { // Note that this is a `check-pass` test, so it will never invoke the linker. #[link(name = "x")] -//~^ WARN attribute should be applied to an `extern` block +//~^ WARN attribute cannot be used on //~| WARN this was previously accepted +//~| HELP can only be applied to foreign modules +//~| HELP remove the attribute mod link { - //~^ NOTE not an `extern` block - mod inner { #![link(name = "x")] } - //~^ WARN attribute should be applied to an `extern` block + //~^ WARN attribute cannot be used on //~| WARN this was previously accepted - //~| NOTE not an `extern` block + //~| HELP can only be applied to foreign modules + //~| HELP remove the attribute #[link(name = "x")] fn f() { } - //~^ WARN attribute should be applied to an `extern` block + //~^ WARN attribute cannot be used on //~| WARN this was previously accepted - //~| NOTE not an `extern` block + //~| HELP can only be applied to foreign modules + //~| HELP remove the attribute #[link(name = "x")] struct S; - //~^ WARN attribute should be applied to an `extern` block + //~^ WARN attribute cannot be used on //~| WARN this was previously accepted - //~| NOTE not an `extern` block + //~| HELP can only be applied to foreign modules + //~| HELP remove the attribute #[link(name = "x")] type T = S; - //~^ WARN attribute should be applied to an `extern` block + //~^ WARN attribute cannot be used on //~| WARN this was previously accepted - //~| NOTE not an `extern` block + //~| HELP can only be applied to foreign modules + //~| HELP remove the attribute #[link(name = "x")] impl S { } - //~^ WARN attribute should be applied to an `extern` block + //~^ WARN attribute cannot be used on //~| WARN this was previously accepted - //~| NOTE not an `extern` block + //~| HELP can only be applied to foreign modules + //~| HELP remove the attribute #[link(name = "x")] extern "Rust" {} //~^ WARN attribute should be applied to an `extern` block 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 c2d4effb4b57e..816969df09dfb 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 @@ -1,5 +1,5 @@ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -7,216 +7,187 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:41:9 | LL | #![warn(x5400)] | ^^^^^ | note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:35:28 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:10 | LL | #![allow(x5300)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:11 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:11 | LL | #![forbid(x5200)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:9 | LL | #![deny(x5100)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:110:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:115:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:118:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:121:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:129:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:134:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:137:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:140:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:148:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:153:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:156:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:159:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:167:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:172:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:175:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:178:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:181:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1 - | -LL | #[link(name = "x")] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | / mod link { -LL | | -LL | | -LL | | mod inner { #![link(name = "x")] } -... | -LL | | } - | |_- not an `extern` block - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:9 - | -LL | #![warn(unused_attributes, unknown_lints)] - | ^^^^^^^^^^^^^^^^^ - -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 - | -LL | #![link(name = "x")] - | ^^^^^^^^^^^^^^^^^^^^ not an `extern` block - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:98:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:99:12 | LL | #![feature(rust1)] | ^^^^^ @@ -224,55 +195,20 @@ LL | #![feature(rust1)] = note: `#[warn(stable_features)]` on by default warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17 - | -LL | mod inner { #![link(name = "x")] } - | ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 - | -LL | #[link(name = "x")] fn f() { } - | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 - | -LL | #[link(name = "x")] struct S; - | ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 - | -LL | #[link(name = "x")] type T = S; - | ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5 - | -LL | #[link(name = "x")] impl S { } - | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 | LL | #[link(name = "x")] extern "Rust" {} | ^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +note: the lint level is defined here + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:35:9 + | +LL | #![warn(unused_attributes, unknown_lints)] + | ^^^^^^^^^^^^^^^^^ warning: `#[macro_use]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:189:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5 | LL | #[macro_use] fn f() { } | ^^^^^^^^^^^^ @@ -281,7 +217,7 @@ LL | #[macro_use] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[macro_use]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:195:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:5 | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ @@ -290,7 +226,7 @@ LL | #[macro_use] 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! warning: `#[macro_use]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ @@ -299,7 +235,7 @@ LL | #[macro_use] 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! warning: `#[macro_use]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:208:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ @@ -308,7 +244,7 @@ LL | #[macro_use] 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! warning: `#[macro_export]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:214:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:1 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ @@ -317,7 +253,7 @@ LL | #[macro_export] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[macro_export]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:220:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17 | LL | mod inner { #![macro_export] } | ^^^^^^^^^^^^^^^^ @@ -326,7 +262,7 @@ LL | mod inner { #![macro_export] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[macro_export]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:226:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 | LL | #[macro_export] fn f() { } | ^^^^^^^^^^^^^^^ @@ -335,7 +271,7 @@ LL | #[macro_export] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[macro_export]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:232:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:5 | LL | #[macro_export] struct S; | ^^^^^^^^^^^^^^^ @@ -344,7 +280,7 @@ LL | #[macro_export] 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! warning: `#[macro_export]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:238:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:239:5 | LL | #[macro_export] type T = S; | ^^^^^^^^^^^^^^^ @@ -353,7 +289,7 @@ LL | #[macro_export] 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! warning: `#[macro_export]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:244:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:5 | LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ @@ -362,7 +298,7 @@ LL | #[macro_export] 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! warning: `#[path]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:255:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:256:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ @@ -371,7 +307,7 @@ LL | #[path = "3800"] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[path]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:262:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ @@ -380,7 +316,7 @@ LL | #[path = "3800"] 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! warning: `#[path]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:267:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ @@ -389,7 +325,7 @@ LL | #[path = "3800"] 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! warning: `#[path]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:273:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:274:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ @@ -398,7 +334,7 @@ LL | #[path = "3800"] 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! warning: `#[automatically_derived]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:280:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:281:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -407,7 +343,7 @@ LL | #[automatically_derived] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[automatically_derived]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:287:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -416,7 +352,7 @@ LL | mod inner { #![automatically_derived] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[automatically_derived]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:292:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:293:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -425,7 +361,7 @@ LL | #[automatically_derived] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[automatically_derived]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:298:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:299:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -434,7 +370,7 @@ LL | #[automatically_derived] 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! warning: `#[automatically_derived]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:304:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:305:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -443,7 +379,7 @@ LL | #[automatically_derived] 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! warning: `#[automatically_derived]` attribute cannot be used on traits - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:310:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:311:5 | LL | #[automatically_derived] trait W { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -452,7 +388,7 @@ LL | #[automatically_derived] trait W { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[automatically_derived]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:316:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:317:5 | LL | #[automatically_derived] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -461,7 +397,7 @@ LL | #[automatically_derived] 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! warning: `#[no_mangle]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ @@ -470,7 +406,7 @@ LL | #[no_mangle] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[no_mangle]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:331:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:17 | LL | mod inner { #![no_mangle] } | ^^^^^^^^^^^^^ @@ -479,7 +415,7 @@ LL | mod inner { #![no_mangle] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[no_mangle]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:339:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:340:5 | LL | #[no_mangle] struct S; | ^^^^^^^^^^^^ @@ -488,7 +424,7 @@ LL | #[no_mangle] 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! warning: `#[no_mangle]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:346:5 | LL | #[no_mangle] type T = S; | ^^^^^^^^^^^^ @@ -497,7 +433,7 @@ LL | #[no_mangle] 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! warning: `#[no_mangle]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:352:5 | LL | #[no_mangle] impl S { } | ^^^^^^^^^^^^ @@ -506,7 +442,7 @@ LL | #[no_mangle] 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! warning: `#[no_mangle]` attribute cannot be used on required trait methods - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:359:9 | LL | #[no_mangle] fn foo(); | ^^^^^^^^^^^^ @@ -515,7 +451,7 @@ LL | #[no_mangle] fn foo(); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[no_mangle]` attribute cannot be used on provided trait methods - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:9 | LL | #[no_mangle] fn bar() {} | ^^^^^^^^^^^^ @@ -524,7 +460,7 @@ LL | #[no_mangle] fn bar() {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[should_panic]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:372:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ @@ -533,7 +469,7 @@ LL | #[should_panic] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[should_panic]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:378:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ @@ -542,7 +478,7 @@ LL | mod inner { #![should_panic] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[should_panic]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ @@ -551,7 +487,7 @@ LL | #[should_panic] 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! warning: `#[should_panic]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:393:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ @@ -560,7 +496,7 @@ LL | #[should_panic] 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! warning: `#[should_panic]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ @@ -569,7 +505,7 @@ LL | #[should_panic] 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! warning: `#[ignore]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:1 | LL | #[ignore] | ^^^^^^^^^ @@ -578,7 +514,7 @@ LL | #[ignore] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[ignore]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ @@ -587,7 +523,7 @@ LL | mod inner { #![ignore] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[ignore]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:419:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 | LL | #[ignore] struct S; | ^^^^^^^^^ @@ -596,7 +532,7 @@ LL | #[ignore] 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! warning: `#[ignore]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:425:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ @@ -605,7 +541,7 @@ LL | #[ignore] 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! warning: `#[ignore]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:431:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ @@ -614,7 +550,7 @@ LL | #[ignore] 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! warning: `#[no_implicit_prelude]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -623,7 +559,7 @@ LL | #[no_implicit_prelude] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[no_implicit_prelude]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:448:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -632,7 +568,7 @@ LL | #[no_implicit_prelude] 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! warning: `#[no_implicit_prelude]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:454:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -641,7 +577,7 @@ LL | #[no_implicit_prelude] 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! warning: `#[no_implicit_prelude]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:460:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:461:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -650,7 +586,7 @@ LL | #[no_implicit_prelude] 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! warning: `#[macro_escape]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ @@ -659,7 +595,7 @@ LL | #[macro_escape] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[macro_escape]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:481:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ @@ -668,7 +604,7 @@ LL | #[macro_escape] 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! warning: `#[macro_escape]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ @@ -677,7 +613,7 @@ LL | #[macro_escape] 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! warning: `#[macro_escape]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ @@ -686,13 +622,13 @@ LL | #[macro_escape] 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! warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:500:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:1 | LL | #[no_std] | ^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:1 | LL | / mod no_std { LL | | @@ -702,61 +638,61 @@ LL | | } | |_^ warning: the `#![no_std]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:504:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:15 | LL | #[no_std] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:5 | LL | #[no_std] struct S; | ^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:15 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:15 | LL | #[no_std] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:15 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:15 | LL | #[no_std] impl S { } | ^^^^^^^^^^ warning: `#[cold]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:542:1 | LL | #[cold] | ^^^^^^^ @@ -765,7 +701,7 @@ LL | #[cold] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[cold]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:548:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:549:17 | LL | mod inner { #![cold] } | ^^^^^^^^ @@ -774,7 +710,7 @@ LL | mod inner { #![cold] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[cold]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:556:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:557:5 | LL | #[cold] struct S; | ^^^^^^^ @@ -783,7 +719,7 @@ LL | #[cold] 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! warning: `#[cold]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:562:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:563:5 | LL | #[cold] type T = S; | ^^^^^^^ @@ -792,7 +728,7 @@ LL | #[cold] 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! warning: `#[cold]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:568:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:5 | LL | #[cold] impl S { } | ^^^^^^^ @@ -801,7 +737,7 @@ LL | #[cold] 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! warning: `#[link_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:575:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:1 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -810,7 +746,7 @@ LL | #[link_name = "1900"] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[link_name]` attribute cannot be used on foreign modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:582:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -819,7 +755,7 @@ LL | #[link_name = "1900"] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[link_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:589:17 | LL | mod inner { #![link_name="1900"] } | ^^^^^^^^^^^^^^^^^^^^ @@ -828,7 +764,7 @@ LL | mod inner { #![link_name="1900"] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[link_name]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:595:5 | LL | #[link_name = "1900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ @@ -837,7 +773,7 @@ LL | #[link_name = "1900"] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[link_name]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:600:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:5 | LL | #[link_name = "1900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ @@ -846,7 +782,7 @@ LL | #[link_name = "1900"] 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! warning: `#[link_name]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:607:5 | LL | #[link_name = "1900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ @@ -855,7 +791,7 @@ LL | #[link_name = "1900"] 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! warning: `#[link_name]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:612:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:613:5 | LL | #[link_name = "1900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^ @@ -864,7 +800,7 @@ LL | #[link_name = "1900"] 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! warning: `#[link_section]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:1 | LL | #[link_section = ",1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -873,7 +809,7 @@ 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! warning: `#[link_section]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:625:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:17 | LL | mod inner { #![link_section=",1800"] } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -882,7 +818,7 @@ 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! warning: `#[link_section]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:5 | LL | #[link_section = ",1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -891,7 +827,7 @@ 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! warning: `#[link_section]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:5 | LL | #[link_section = ",1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -900,7 +836,7 @@ 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! warning: `#[link_section]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5 | LL | #[link_section = ",1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -909,7 +845,7 @@ 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! warning: `#[link_section]` attribute cannot be used on traits - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 | LL | #[link_section = ",1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -918,7 +854,7 @@ 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! warning: `#[link_section]` attribute cannot be used on required trait methods - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:9 | LL | #[link_section = ",1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -926,8 +862,62 @@ LL | #[link_section = ",1800"] = help: `#[link_section]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: `#[link]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:686:1 + | +LL | #[link(name = "x")] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: `#[link]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:17 + | +LL | mod inner { #![link(name = "x")] } + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: `#[link]` attribute cannot be used on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5 + | +LL | #[link(name = "x")] fn f() { } + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: `#[link]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 + | +LL | #[link(name = "x")] struct S; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: `#[link]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5 + | +LL | #[link(name = "x")] type T = S; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: `#[link]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 + | +LL | #[link(name = "x")] impl S { } + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -936,7 +926,7 @@ 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! warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17 | LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ @@ -945,7 +935,7 @@ LL | mod inner { #![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! warning: `#[must_use]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | LL | #[must_use] type T = S; | ^^^^^^^^^^^ @@ -954,7 +944,7 @@ LL | #[must_use] 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! warning: `#[must_use]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5 | LL | #[must_use] impl S { } | ^^^^^^^^^^^ @@ -963,13 +953,13 @@ LL | #[must_use] 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! warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:1 | LL | / mod windows_subsystem { LL | | @@ -979,67 +969,67 @@ LL | | } | |_^ warning: the `#![windows_subsystem]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:17 | LL | mod inner { #![windows_subsystem="windows"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:5 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:38 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:778:5 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:778:38 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:5 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:38 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:5 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:38 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:1 | LL | / mod crate_name { LL | | @@ -1049,67 +1039,67 @@ LL | | } | |_^ warning: the `#![crate_name]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:800:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:800:28 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:28 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:28 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:28 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_type]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:1 | LL | / mod crate_type { LL | | @@ -1119,67 +1109,67 @@ LL | | } | |_^ warning: the `#![crate_type]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:821:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_type]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:28 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_type]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:28 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_type]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:28 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_type]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:28 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:835:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:841:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:837:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:1 | LL | / mod feature { LL | | @@ -1189,67 +1179,67 @@ LL | | } | |_^ warning: the `#![feature]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:845:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:842:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:848:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:842:23 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:848:23 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:23 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:23 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:850:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:856:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:850:23 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:856:23 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:854:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:854:23 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:23 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:866:1 | LL | #[no_main] | ^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:862:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:868:1 | LL | / mod no_main_1 { LL | | @@ -1259,67 +1249,67 @@ LL | | } | |_^ warning: the `#![no_main]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:870:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:873:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:16 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:873:16 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:877:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:16 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:877:16 | LL | #[no_main] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:881:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:16 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:881:16 | LL | #[no_main] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:16 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:16 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_builtins]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:884:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:890:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:886:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:1 | LL | / mod no_builtins { LL | | @@ -1329,67 +1319,67 @@ LL | | } | |_^ warning: the `#![no_builtins]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:888:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:894:17 | LL | mod inner { #![no_builtins] } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_builtins]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:891:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:897:5 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:891:20 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:897:20 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_builtins]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:895:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:901:5 | LL | #[no_builtins] struct S; | ^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:895:20 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:901:20 | LL | #[no_builtins] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_builtins]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:899:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:905:5 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:899:20 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:905:20 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_builtins]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:903:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:5 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:903:20 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:20 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:908:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:914:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:910:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:916:1 | LL | / mod recursion_limit { LL | | @@ -1399,67 +1389,67 @@ LL | | } | |_^ warning: the `#![recursion_limit]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:912:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:918:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:915:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:921:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:915:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:921:31 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:919:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:919:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:31 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:923:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:923:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:31 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:927:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:927:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:31 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:932:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:938:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:934:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:1 | LL | / mod type_length_limit { LL | | @@ -1469,61 +1459,61 @@ LL | | } | |_^ warning: the `#![type_length_limit]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:936:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:942:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:939:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:945:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:939:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:945:33 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:943:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:943:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:33 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:947:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:947:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:33 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:951:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:951:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:33 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^ warning: `#[should_panic]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:1 | LL | #![should_panic] | ^^^^^^^^^^^^^^^^ @@ -1532,7 +1522,7 @@ LL | #![should_panic] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[ignore]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:1 | LL | #![ignore] | ^^^^^^^^^^ @@ -1541,7 +1531,7 @@ LL | #![ignore] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[proc_macro_derive]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:61:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 | LL | #![proc_macro_derive(Test)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1550,7 +1540,7 @@ LL | #![proc_macro_derive(Test)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[cold]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 | LL | #![cold] | ^^^^^^^^ @@ -1558,8 +1548,17 @@ LL | #![cold] = help: `#[cold]` can only be applied to functions = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: `#[link]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 + | +LL | #![link(name = "x")] + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: `#[link_name]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:73:1 | LL | #![link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -1568,7 +1567,7 @@ LL | #![link_name = "1900"] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[link_section]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:77:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:78:1 | LL | #![link_section = ",1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1577,7 +1576,7 @@ 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! warning: `#[must_use]` attribute cannot be used on crates - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:82:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:83:1 | LL | #![must_use] | ^^^^^^^^^^^^ diff --git a/tests/ui/malformed/malformed-regressions.rs b/tests/ui/malformed/malformed-regressions.rs index 63b918520ec03..37824898f9d4d 100644 --- a/tests/ui/malformed/malformed-regressions.rs +++ b/tests/ui/malformed/malformed-regressions.rs @@ -6,8 +6,10 @@ #[inline = ""] //~ ERROR valid forms for the attribute are //~^ WARN this was previously accepted #[link] //~ ERROR malformed -//~^ WARN attribute should be applied to an `extern` block with non-Rust ABI +//~^ WARN attribute cannot be used on //~| WARN previously accepted #[link = ""] //~ ERROR malformed +//~^ WARN attribute cannot be used on +//~| WARN previously accepted fn main() {} diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index 283834a485525..b831ba4a58b75 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -16,18 +16,6 @@ LL | #[link = ""] | = note: for more information, visit -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/malformed-regressions.rs:8:1 - | -LL | #[link] - | ^^^^^^^ -... -LL | fn main() {} - | ------------ not an `extern` block - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: requested on the command line with `-W unused-attributes` - error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` --> $DIR/malformed-regressions.rs:3:1 | @@ -59,7 +47,26 @@ LL | #[inline = ""] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: aborting due to 5 previous errors; 1 warning emitted +warning: `#[link]` attribute cannot be used on functions + --> $DIR/malformed-regressions.rs:8:1 + | +LL | #[link] + | ^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: requested on the command line with `-W unused-attributes` + +warning: `#[link]` attribute cannot be used on functions + --> $DIR/malformed-regressions.rs:11:1 + | +LL | #[link = ""] + | ^^^^^^^^^^^^ + | + = help: `#[link]` can only be applied to foreign modules + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: aborting due to 5 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: From d8698f576ba4849df241d93a89b7e38baa1fa1e3 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 2 Jun 2026 23:20:21 +0200 Subject: [PATCH 14/14] Add a test for `#[link]` on macro calls --- tests/ui/attributes/attr-on-mac-call.rs | 3 +++ tests/ui/attributes/attr-on-mac-call.stderr | 27 ++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/tests/ui/attributes/attr-on-mac-call.rs b/tests/ui/attributes/attr-on-mac-call.rs index 2498682503e6b..67eca68c0dd29 100644 --- a/tests/ui/attributes/attr-on-mac-call.rs +++ b/tests/ui/attributes/attr-on-mac-call.rs @@ -69,6 +69,9 @@ fn main() { #[should_panic] //~^ WARN attribute cannot be used on macro calls //~| WARN previously accepted + #[link_name = "x"] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted unreachable!(); #[repr()] diff --git a/tests/ui/attributes/attr-on-mac-call.stderr b/tests/ui/attributes/attr-on-mac-call.stderr index 5881685313e96..26e3cd870e132 100644 --- a/tests/ui/attributes/attr-on-mac-call.stderr +++ b/tests/ui/attributes/attr-on-mac-call.stderr @@ -201,8 +201,17 @@ LL | #[should_panic] = help: `#[should_panic]` can only be applied to functions = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: `#[link_name]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:72:5 + | +LL | #[link_name = "x"] + | ^^^^^^^^^^^^^^^^^^ + | + = help: `#[link_name]` can be applied to foreign functions and foreign statics + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: `#[repr()]` attribute cannot be used on macro calls - --> $DIR/attr-on-mac-call.rs:74:5 + --> $DIR/attr-on-mac-call.rs:77:5 | LL | #[repr()] | ^^^^^^^^^ @@ -211,7 +220,7 @@ LL | #[repr()] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: unused attribute - --> $DIR/attr-on-mac-call.rs:74:5 + --> $DIR/attr-on-mac-call.rs:77:5 | LL | #[repr()] | ^^^^^^^^^ help: remove this attribute @@ -219,7 +228,7 @@ LL | #[repr()] = note: using `repr` with an empty list has no effect warning: `#[repr(u8)]` attribute cannot be used on macro calls - --> $DIR/attr-on-mac-call.rs:79:5 + --> $DIR/attr-on-mac-call.rs:82:5 | LL | #[repr(u8)] | ^^^^^^^^^^^ @@ -228,7 +237,7 @@ LL | #[repr(u8)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[repr(align(...))]` attribute cannot be used on macro calls - --> $DIR/attr-on-mac-call.rs:83:5 + --> $DIR/attr-on-mac-call.rs:86:5 | LL | #[repr(align(8))] | ^^^^^^^^^^^^^^^^^ @@ -237,7 +246,7 @@ LL | #[repr(align(8))] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[repr(packed)]` attribute cannot be used on macro calls - --> $DIR/attr-on-mac-call.rs:87:5 + --> $DIR/attr-on-mac-call.rs:90:5 | LL | #[repr(packed)] | ^^^^^^^^^^^^^^^ @@ -246,7 +255,7 @@ LL | #[repr(packed)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[repr(C)]` attribute cannot be used on macro calls - --> $DIR/attr-on-mac-call.rs:91:5 + --> $DIR/attr-on-mac-call.rs:94:5 | LL | #[repr(C)] | ^^^^^^^^^^ @@ -255,7 +264,7 @@ LL | #[repr(C)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[repr(Rust)]` attribute cannot be used on macro calls - --> $DIR/attr-on-mac-call.rs:95:5 + --> $DIR/attr-on-mac-call.rs:98:5 | LL | #[repr(Rust)] | ^^^^^^^^^^^^^ @@ -264,7 +273,7 @@ LL | #[repr(Rust)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[repr(simd)]` attribute cannot be used on macro calls - --> $DIR/attr-on-mac-call.rs:99:5 + --> $DIR/attr-on-mac-call.rs:102:5 | LL | #[repr(simd)] | ^^^^^^^^^^^^^ @@ -272,5 +281,5 @@ LL | #[repr(simd)] = help: `#[repr(simd)]` can only be applied to structs = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: 30 warnings emitted +warning: 31 warnings emitted