From 6635005c3c9bff5d46ad5ef58eb15a49a2a49c58 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 14:53:14 +0000 Subject: [PATCH 01/11] Specify of_trait in Target::Impl. --- compiler/rustc_hir/src/target.rs | 11 +- compiler/rustc_passes/src/check_attr.rs | 16 +- compiler/rustc_passes/src/lang_items.rs | 2 +- .../check-doc-alias-attr-location.stderr | 4 +- tests/ui/attributes/positions/used.stderr | 2 +- .../issue-43106-gating-of-builtin-attrs.rs | 6 + ...issue-43106-gating-of-builtin-attrs.stderr | 258 +++++++++--------- tests/ui/lint/unused/unused-attr-duplicate.rs | 4 +- .../lint/unused/unused-attr-duplicate.stderr | 36 +-- .../unused/unused_attributes-must_use.stderr | 4 +- .../check-doc-alias-attr-location.stderr | 4 +- 11 files changed, 184 insertions(+), 163 deletions(-) diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 601898023fc39..5e13c8ec11ff9 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -41,7 +41,7 @@ pub enum Target { Union, Trait, TraitAlias, - Impl, + Impl { of_trait: bool }, Expression, Statement, Arm, @@ -86,7 +86,7 @@ impl Target { | Target::Union | Target::Trait | Target::TraitAlias - | Target::Impl + | Target::Impl { .. } | Target::Expression | Target::Statement | Target::Arm @@ -119,7 +119,7 @@ impl Target { ItemKind::Union(..) => Target::Union, ItemKind::Trait(..) => Target::Trait, ItemKind::TraitAlias(..) => Target::TraitAlias, - ItemKind::Impl { .. } => Target::Impl, + ItemKind::Impl(imp_) => Target::Impl { of_trait: imp_.of_trait.is_some() }, } } @@ -141,7 +141,7 @@ impl Target { DefKind::Union => Target::Union, DefKind::Trait => Target::Trait, DefKind::TraitAlias => Target::TraitAlias, - DefKind::Impl { .. } => Target::Impl, + DefKind::Impl { of_trait } => Target::Impl { of_trait }, _ => panic!("impossible case reached"), } } @@ -196,7 +196,8 @@ impl Target { Target::Union => "union", Target::Trait => "trait", Target::TraitAlias => "trait alias", - Target::Impl => "implementation block", + Target::Impl { of_trait: false } => "inherent implementation block", + Target::Impl { of_trait: true } => "trait implementation block", Target::Expression => "expression", Target::Statement => "statement", Target::Arm => "match arm", diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9a96749f3e7fd..8809ac4680885 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -338,7 +338,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn) } [sym::automatically_derived, ..] => { - self.check_generic_attr_unparsed(hir_id, attr, target, Target::Impl) + self.check_generic_attr_unparsed(hir_id, attr, target, Target::Impl{of_trait:true}) } [sym::proc_macro, ..] => { self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) @@ -479,7 +479,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr: &Attribute, item: Option>, ) { - if !matches!(target, Target::Impl) + if !matches!(target, Target::Impl { .. }) || matches!( item, Some(ItemLike::Item(hir::Item { kind: hir::ItemKind::Impl(_impl),.. })) @@ -583,7 +583,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::Fn | Target::Closure | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) - | Target::Impl + | Target::Impl { .. } | Target::Mod => return, // These are "functions", but they aren't allowed because they don't @@ -974,9 +974,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let span = meta.span(); if let Some(location) = match target { Target::AssocTy => { - let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id; - let containing_item = self.tcx.hir_expect_item(parent_def_id); - if Target::from_item(containing_item) == Target::Impl { + if let DefKind::Impl { .. } = + self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id)) + { Some("type alias in implementation block") } else { None @@ -999,7 +999,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::Arm | Target::ForeignMod | Target::Closure - | Target::Impl + | Target::Impl { .. } | Target::WherePredicate => Some(target.name()), Target::ExternCrate | Target::Use @@ -1575,7 +1575,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let article = match target { Target::ExternCrate | Target::Enum - | Target::Impl + | Target::Impl { .. } | Target::Expression | Target::Arm | Target::AssocConst diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 3afed9784de51..6fac01827a499 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -287,7 +287,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { ast::ItemKind::Union(..) => Target::Union, ast::ItemKind::Trait(_) => Target::Trait, ast::ItemKind::TraitAlias(..) => Target::TraitAlias, - ast::ItemKind::Impl(_) => Target::Impl, + ast::ItemKind::Impl(imp_) => Target::Impl { of_trait: imp_.of_trait.is_some() }, ast::ItemKind::MacroDef(..) => Target::MacroDef, ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => { unreachable!("macros should have been expanded") diff --git a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr index 85c9516236c94..9d3ce5e63ef73 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr @@ -4,13 +4,13 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module LL | #[doc(alias = "foo")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on implementation block +error: `#[doc(alias = "...")]` isn't allowed on inherent implementation block --> $DIR/check-doc-alias-attr-location.rs:10:7 | LL | #[doc(alias = "bar")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on implementation block +error: `#[doc(alias = "...")]` isn't allowed on trait implementation block --> $DIR/check-doc-alias-attr-location.rs:16:7 | LL | #[doc(alias = "foobar")] diff --git a/tests/ui/attributes/positions/used.stderr b/tests/ui/attributes/positions/used.stderr index 96dd43a3a937f..64460c178cb03 100644 --- a/tests/ui/attributes/positions/used.stderr +++ b/tests/ui/attributes/positions/used.stderr @@ -28,7 +28,7 @@ error: attribute must be applied to a `static` variable LL | #[used] | ^^^^^^^ LL | impl Bar for Foo {} - | ------------------- but this is a implementation block + | ------------------- but this is a trait implementation block error: attribute must be applied to a `static` variable --> $DIR/used.rs:21:5 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 d07201ebbd1aa..9740eaaf1e93a 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 @@ -269,7 +269,13 @@ mod automatically_derived { #[automatically_derived] type T = S; //~^ WARN `#[automatically_derived] + #[automatically_derived] trait W { } + //~^ WARN `#[automatically_derived] + #[automatically_derived] impl S { } + //~^ WARN `#[automatically_derived] + + #[automatically_derived] impl W for S { } } #[no_mangle] 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 5d7d1caeeab0b..c0935fe2a145e 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:391:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ 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:388:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ @@ -198,14 +198,14 @@ note: the lint level is defined here LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on (unspecified--this is a compiler bug) --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:281:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ @@ -220,31 +220,31 @@ LL | | } = 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]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:315:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:321:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:339:1 | LL | #[ignore] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:368:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:1 | LL | #[no_std] | ^^^^^^^^^ warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:1 | LL | #[cold] | ^^^^^^^ @@ -260,7 +260,7 @@ LL | | } = 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 a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -276,7 +276,7 @@ LL | | } = 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 a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:1 | LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ LL | | } = 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:544:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:1 | LL | #[link()] | ^^^^^^^^^ @@ -308,55 +308,55 @@ LL | | } = 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]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:595:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:1 | LL | #[must_use] | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:608:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -495,32 +495,44 @@ warning: `#[path]` only has an effect on modules LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on (unspecified--this is a compiler bug) --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on (unspecified--this is a compiler bug) --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on (unspecified--this is a compiler bug) --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on implementation blocks +warning: `#[automatically_derived]` only has an effect on (unspecified--this is a compiler bug) --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `#[automatically_derived]` only has an effect on (unspecified--this is a compiler bug) + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5 + | +LL | #[automatically_derived] trait W { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[automatically_derived]` only has an effect on (unspecified--this is a compiler bug) + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5 + | +LL | #[automatically_derived] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ + warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:280:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:17 | LL | mod inner { #![no_mangle] } | ------------^^^^^^^^^^^^^-- not a free function, impl method or static @@ -528,7 +540,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: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:287:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:293:5 | LL | #[no_mangle] struct S; | ^^^^^^^^^^^^ --------- not a free function, impl method or static @@ -536,7 +548,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: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:292:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:298:5 | LL | #[no_mangle] type T = S; | ^^^^^^^^^^^^ ----------- not a free function, impl method or static @@ -544,7 +556,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: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:297:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:303:5 | LL | #[no_mangle] impl S { } | ^^^^^^^^^^^^ ---------- not a free function, impl method or static @@ -552,7 +564,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: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:303:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:309:9 | LL | #[no_mangle] fn foo(); | ^^^^^^^^^^^^ --------- not a free function, impl method or static @@ -560,7 +572,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: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:308:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:9 | LL | #[no_mangle] fn bar() {} | ^^^^^^^^^^^^ ----------- not a free function, impl method or static @@ -568,163 +580,163 @@ 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]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:318:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:323:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:336:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:371:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:410:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:17 | LL | mod inner { #![cold] } | ------------^^^^^^^^-- not a function definition @@ -732,7 +744,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: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:5 | LL | #[cold] struct S; | ^^^^^^^ --------- not a function definition @@ -740,7 +752,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: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5 | LL | #[cold] type T = S; | ^^^^^^^ ----------- not a function definition @@ -748,7 +760,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: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:467:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:5 | LL | #[cold] impl S { } | ^^^^^^^ ---------- not a function definition @@ -756,7 +768,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: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -766,13 +778,13 @@ LL | extern "C" { } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! help: try `#[link(name = "1900")]` instead - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:17 | LL | mod inner { #![link_name="1900"] } | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static @@ -780,7 +792,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: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5 | LL | #[link_name = "1900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static @@ -788,7 +800,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: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5 | LL | #[link_name = "1900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static @@ -796,7 +808,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: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 | LL | #[link_name = "1900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static @@ -804,7 +816,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: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:506:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:5 | LL | #[link_name = "1900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static @@ -812,7 +824,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: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:524:17 | LL | mod inner { #![link_section="1800"] } | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static @@ -820,7 +832,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: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:525:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:531:5 | LL | #[link_section = "1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static @@ -828,7 +840,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: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:530:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:5 | LL | #[link_section = "1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static @@ -836,7 +848,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: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:535:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5 | LL | #[link_section = "1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static @@ -844,7 +856,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: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:556:17 | LL | mod inner { #![link()] } | ------------^^^^^^^^^^-- not an `extern` block @@ -852,7 +864,7 @@ LL | mod inner { #![link()] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:561:5 | LL | #[link()] fn f() { } | ^^^^^^^^^ ---------- not an `extern` block @@ -860,7 +872,7 @@ LL | #[link()] 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: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:560:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:566:5 | LL | #[link()] struct S; | ^^^^^^^^^ --------- not an `extern` block @@ -868,7 +880,7 @@ LL | #[link()] 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: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:565:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:571:5 | LL | #[link()] type T = S; | ^^^^^^^^^ ----------- not an `extern` block @@ -876,7 +888,7 @@ LL | #[link()] 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: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:570:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5 | LL | #[link()] impl S { } | ^^^^^^^^^ ---------- not an `extern` block @@ -884,7 +896,7 @@ LL | #[link()] 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: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:575:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5 | LL | #[link()] extern "Rust" {} | ^^^^^^^^^ @@ -892,259 +904,259 @@ LL | #[link()] 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! warning: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:597:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:17 | LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ warning: `#[must_use]` has no effect when applied to a type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:5 | LL | #[must_use] type T = S; | ^^^^^^^^^^^ -warning: `#[must_use]` has no effect when applied to an implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:5 +warning: `#[must_use]` has no effect when applied to an inherent implementation block + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5 | LL | #[must_use] impl S { } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:17 | LL | mod inner { #![windows_subsystem="windows"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:5 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:632:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:666:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:17 | LL | mod inner { #![no_builtins] } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 | LL | #[no_builtins] struct S; | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1157,5 +1169,5 @@ LL | #![feature(rust1)] | = note: `#[warn(stable_features)]` on by default -warning: 171 warnings emitted +warning: 173 warnings emitted diff --git a/tests/ui/lint/unused/unused-attr-duplicate.rs b/tests/ui/lint/unused/unused-attr-duplicate.rs index bf94a42f6e0cf..cfa6c2b4228cd 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.rs +++ b/tests/ui/lint/unused/unused-attr-duplicate.rs @@ -66,9 +66,11 @@ fn t1() {} #[non_exhaustive] //~ ERROR unused attribute pub struct X; +trait Trait {} + #[automatically_derived] #[automatically_derived] //~ ERROR unused attribute -impl X {} +impl Trait for X {} #[inline(always)] #[inline(never)] //~ ERROR unused attribute diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 2310c12c80b56..708cd9c0c7543 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -41,13 +41,13 @@ 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! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:70:1 + --> $DIR/unused-attr-duplicate.rs:72:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:69:1 + --> $DIR/unused-attr-duplicate.rs:71:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -191,100 +191,100 @@ LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:74:1 + --> $DIR/unused-attr-duplicate.rs:76:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:73:1 + --> $DIR/unused-attr-duplicate.rs:75:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:77:1 + --> $DIR/unused-attr-duplicate.rs:79:1 | LL | #[cold] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:76:1 + --> $DIR/unused-attr-duplicate.rs:78:1 | LL | #[cold] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:79:1 + --> $DIR/unused-attr-duplicate.rs:81:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:78:1 + --> $DIR/unused-attr-duplicate.rs:80:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:86:5 + --> $DIR/unused-attr-duplicate.rs:88:5 | LL | #[link_name = "this_does_not_exist"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:88:5 + --> $DIR/unused-attr-duplicate.rs:90:5 | LL | #[link_name = "rust_dbg_extern_identity_u32"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:92:1 + --> $DIR/unused-attr-duplicate.rs:94:1 | LL | #[export_name = "exported_symbol_name"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:94:1 + --> $DIR/unused-attr-duplicate.rs:96:1 | LL | #[export_name = "exported_symbol_name2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:98:1 + --> $DIR/unused-attr-duplicate.rs:100:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:97:1 + --> $DIR/unused-attr-duplicate.rs:99:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:102:1 + --> $DIR/unused-attr-duplicate.rs:104:1 | LL | #[used] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:101:1 + --> $DIR/unused-attr-duplicate.rs:103:1 | LL | #[used] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:105:1 + --> $DIR/unused-attr-duplicate.rs:107:1 | LL | #[link_section = ".text"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:108:1 + --> $DIR/unused-attr-duplicate.rs:110:1 | LL | #[link_section = ".bss"] | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 28fd8eeb8cbdc..862ffa42d8083 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -45,7 +45,7 @@ error: `#[must_use]` has no effect when applied to a static item LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an implementation block +error: `#[must_use]` has no effect when applied to an inherent implementation block --> $DIR/unused_attributes-must_use.rs:33:1 | LL | #[must_use] @@ -69,7 +69,7 @@ error: `#[must_use]` has no effect when applied to a type parameter LL | fn qux<#[must_use] T>(_: T) {} | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an implementation block +error: `#[must_use]` has no effect when applied to an trait implementation block --> $DIR/unused_attributes-must_use.rs:79:1 | LL | #[must_use] diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr index 23c93a4ed8bdb..4244c11eb3eb4 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr @@ -10,13 +10,13 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module LL | #[doc(alias = "foo")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on implementation block +error: `#[doc(alias = "...")]` isn't allowed on inherent implementation block --> $DIR/check-doc-alias-attr-location.rs:12:7 | LL | #[doc(alias = "bar")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on implementation block +error: `#[doc(alias = "...")]` isn't allowed on trait implementation block --> $DIR/check-doc-alias-attr-location.rs:18:7 | LL | #[doc(alias = "foobar")] From f748e9ef22d85eaea75e4f61cbd6fe5e5e5c0a6e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 14:24:30 +0000 Subject: [PATCH 02/11] Warn useless deprecation in check_attr. --- compiler/rustc_hir/src/target.rs | 18 ++++++++++++------ compiler/rustc_passes/src/check_attr.rs | 25 ++++++++++++++++++++++++- compiler/rustc_passes/src/stability.rs | 16 ++-------------- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 5e13c8ec11ff9..d617f44f8d8e4 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -51,7 +51,7 @@ pub enum Target { ForeignFn, ForeignStatic, ForeignTy, - GenericParam(GenericParamKind), + GenericParam { kind: GenericParamKind, has_default: bool }, MacroDef, Param, PatField, @@ -93,7 +93,7 @@ impl Target { | Target::ForeignFn | Target::ForeignStatic | Target::ForeignTy - | Target::GenericParam(_) + | Target::GenericParam { .. } | Target::MacroDef | Target::Param | Target::PatField @@ -169,11 +169,17 @@ impl Target { pub fn from_generic_param(generic_param: &hir::GenericParam<'_>) -> Target { match generic_param.kind { - hir::GenericParamKind::Type { .. } => Target::GenericParam(GenericParamKind::Type), + hir::GenericParamKind::Type { default, .. } => Target::GenericParam { + kind: GenericParamKind::Type, + has_default: default.is_some(), + }, hir::GenericParamKind::Lifetime { .. } => { - Target::GenericParam(GenericParamKind::Lifetime) + Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false } } - hir::GenericParamKind::Const { .. } => Target::GenericParam(GenericParamKind::Const), + hir::GenericParamKind::Const { default, .. } => Target::GenericParam { + kind: GenericParamKind::Const, + has_default: default.is_some(), + }, } } @@ -211,7 +217,7 @@ impl Target { Target::ForeignFn => "foreign function", Target::ForeignStatic => "foreign static item", Target::ForeignTy => "foreign type", - Target::GenericParam(kind) => match kind { + Target::GenericParam { kind, has_default: _ } => match kind { GenericParamKind::Type => "type parameter", GenericParamKind::Lifetime => "lifetime parameter", GenericParamKind::Const => "const parameter", diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8809ac4680885..8c62c5d3087cf 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -36,6 +36,7 @@ use rustc_session::lint; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, + USELESS_DEPRECATED, }; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; @@ -1020,7 +1021,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::ForeignFn | Target::ForeignStatic | Target::ForeignTy - | Target::GenericParam(..) + | Target::GenericParam { .. } | Target::MacroDef | Target::PatField | Target::ExprField => None, @@ -2283,6 +2284,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> { errors::Deprecated, ); } + Target::Impl { of_trait: true } + | Target::GenericParam { has_default: false, kind: _ } => { + self.tcx.emit_node_span_lint( + USELESS_DEPRECATED, + hir_id, + attr.span(), + errors::DeprecatedAnnotationHasNoEffect { span: attr.span() }, + ); + } + Target::AssocConst | Target::Method(..) | Target::AssocTy + if matches!( + self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id)), + DefKind::Impl { of_trait: true } + ) => + { + self.tcx.emit_node_span_lint( + USELESS_DEPRECATED, + hir_id, + attr.span(), + errors::DeprecatedAnnotationHasNoEffect { span: attr.span() }, + ); + } _ => {} } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index a30655d32a7e5..daaccab1974ac 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -27,9 +27,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; -use rustc_session::lint::builtin::{ - DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED, -}; +use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL}; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, info}; @@ -125,19 +123,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); let mut is_deprecated = false; - if let Some((depr, span)) = &depr { + if let Some((depr, _)) = &depr { is_deprecated = true; - if matches!(kind, AnnotationKind::Prohibited | AnnotationKind::DeprecationProhibited) { - let hir_id = self.tcx.local_def_id_to_hir_id(def_id); - self.tcx.emit_node_span_lint( - USELESS_DEPRECATED, - hir_id, - *span, - errors::DeprecatedAnnotationHasNoEffect { span: *span }, - ); - } - // `Deprecation` is just two pointers, no need to intern it let depr_entry = DeprecationEntry::local(*depr, def_id); self.index.depr_map.insert(def_id, depr_entry); From 7fac4f4fe1a10d335f694c1163250402005dbdef Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 18 Jan 2022 21:01:07 +0100 Subject: [PATCH 03/11] Querify lookup_deprecation_entry. --- compiler/rustc_middle/src/middle/stability.rs | 5 -- compiler/rustc_passes/src/stability.rs | 79 +++++++++---------- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 99faba7b2c0ae..9c2528ca4103b 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -73,7 +73,6 @@ pub struct Index { pub stab_map: LocalDefIdMap, pub const_stab_map: LocalDefIdMap, pub default_body_stab_map: LocalDefIdMap, - pub depr_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -101,10 +100,6 @@ impl Index { pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option { self.default_body_stab_map.get(&def_id).copied() } - - pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option { - self.depr_map.get(&def_id).cloned() - } } pub fn report_unstable( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index daaccab1974ac..1e9e85855ba08 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -89,13 +89,40 @@ impl InheritStability { } } +fn inherit_deprecation(def_kind: DefKind) -> InheritDeprecation { + match def_kind { + DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => InheritDeprecation::No, + _ => InheritDeprecation::Yes, + } +} + +fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let depr = attrs::find_attr!(attrs, + AttributeKind::Deprecation { deprecation, span: _ } => *deprecation + ); + + let Some(depr) = depr else { + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let parent_id = tcx.opt_local_parent(def_id)?; + let parent_depr = tcx.lookup_deprecation_entry(parent_id)?; + info!("tagging child {:?} as deprecated from parent", def_id); + return Some(parent_depr); + } + + return None; + }; + + // `Deprecation` is just two pointers, no need to intern it + Some(DeprecationEntry::local(depr, def_id)) +} + /// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, parent_stab: Option, parent_const_stab: Option, - parent_depr: Option, in_trait_impl: bool, } @@ -119,24 +146,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - let depr = attrs::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span)); + let depr = self.tcx.lookup_deprecation_entry(def_id); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); - let mut is_deprecated = false; - if let Some((depr, _)) = &depr { - is_deprecated = true; - - // `Deprecation` is just two pointers, no need to intern it - let depr_entry = DeprecationEntry::local(*depr, def_id); - self.index.depr_map.insert(def_id, depr_entry); - } else if let Some(parent_depr) = self.parent_depr { - if inherit_deprecation.yes() { - is_deprecated = true; - info!("tagging child {:?} as deprecated from parent", def_id); - self.index.depr_map.insert(def_id, parent_depr); - } - } - if !self.tcx.features().staged_api() { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. @@ -152,12 +164,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - self.recurse_with_stability_attrs( - depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), - None, - None, - visit_children, - ); + self.recurse_with_stability_attrs(None, None, visit_children); return; } @@ -166,11 +173,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let body_stab = attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); - if let Some((depr, span)) = &depr - && depr.is_since_rustc_version() + if let Some(depr) = &depr + && depr.attr.is_since_rustc_version() && stab.is_none() + && let Some(depr_span) = attrs::find_attr!(attrs, + AttributeKind::Deprecation { span, .. } => *span + ) { - self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span }); + self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: depr_span }); } if let Some(body_stab) = body_stab { @@ -183,7 +193,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let stab = stab.map(|(stab, span)| { // Error if prohibited, or can't inherit anything from a container. if kind == AnnotationKind::Prohibited - || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated) + || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some()) { self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp }); } @@ -195,7 +205,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let ( &Some(DeprecatedSince::RustcVersion(dep_since)), &attrs::StabilityLevel::Stable { since: stab_since, .. }, - ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level) + ) = (&depr.as_ref().map(|d| d.attr.since), &stab.level) { match stab_since { StableSince::Current => { @@ -343,7 +353,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } self.recurse_with_stability_attrs( - depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), stab, inherit_const_stability.yes().then_some(const_stab).flatten(), visit_children, @@ -352,19 +361,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn recurse_with_stability_attrs( &mut self, - depr: Option, stab: Option, const_stab: Option, f: impl FnOnce(&mut Self), ) { // These will be `Some` if this item changes the corresponding stability attribute. - let mut replaced_parent_depr = None; let mut replaced_parent_stab = None; let mut replaced_parent_const_stab = None; - if let Some(depr) = depr { - replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr))); - } if let Some(stab) = stab { replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab))); } @@ -375,9 +379,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { f(self); - if let Some(orig_parent_depr) = replaced_parent_depr { - self.parent_depr = orig_parent_depr; - } if let Some(orig_parent_stab) = replaced_parent_stab { self.parent_stab = orig_parent_stab; } @@ -679,7 +680,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { stab_map: Default::default(), const_stab_map: Default::default(), default_body_stab_map: Default::default(), - depr_map: Default::default(), implications: Default::default(), }; @@ -689,7 +689,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { index: &mut index, parent_stab: None, parent_const_stab: None, - parent_depr: None, in_trait_impl: false, }; @@ -741,7 +740,7 @@ pub(crate) fn provide(providers: &mut Providers) { lookup_stability: |tcx, id| tcx.stability().local_stability(id), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id), - lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id), + lookup_deprecation_entry, ..*providers }; } From 21ba49cad7f64bd6799b83c61f5253900d081bca Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 14:33:04 +0000 Subject: [PATCH 04/11] Check stability attributes are compatible in `check_unused_or_stable_features`. --- compiler/rustc_passes/src/stability.rs | 342 +++++++++--------- ...rustc-const-stability-require-const.stderr | 48 +-- 2 files changed, 203 insertions(+), 187 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 1e9e85855ba08..4a3fdef2d8151 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -6,8 +6,8 @@ use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; use rustc_attr_data_structures::{ - self as attrs, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, - Stability, StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, + self as attrs, AttributeKind, ConstStability, DeprecatedSince, Stability, StabilityLevel, + StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; @@ -29,7 +29,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL}; use rustc_span::{Span, Symbol, sym}; -use tracing::{debug, info}; +use tracing::{debug, info, instrument}; use crate::errors; @@ -96,6 +96,39 @@ fn inherit_deprecation(def_kind: DefKind) -> InheritDeprecation { } } +fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind { + let def_kind = tcx.def_kind(def_id); + match def_kind { + // Inherent impls and foreign modules serve only as containers for other items, + // they don't have their own stability. They still can be annotated as unstable + // and propagate this unstability to children, but this annotation is completely + // optional. They inherit stability from their parents when unannotated. + DefKind::Impl { of_trait: false } | DefKind::ForeignMod => AnnotationKind::Container, + DefKind::Impl { of_trait: true } => AnnotationKind::DeprecationProhibited, + + // Allow stability attributes on default generic arguments. + DefKind::TyParam | DefKind::ConstParam => { + match &tcx.hir_node_by_def_id(def_id).expect_generic_param().kind { + hir::GenericParamKind::Type { default: Some(_), .. } + | hir::GenericParamKind::Const { default: Some(_), .. } => { + AnnotationKind::Container + } + _ => AnnotationKind::Prohibited, + } + } + + // Impl items in trait impls cannot have stability. + DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst => { + match tcx.def_kind(tcx.local_parent(def_id)) { + DefKind::Impl { of_trait: true } => AnnotationKind::Prohibited, + _ => AnnotationKind::Required, + } + } + + _ => AnnotationKind::Required, + } +} + fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); let depr = attrs::find_attr!(attrs, @@ -123,7 +156,6 @@ struct Annotator<'a, 'tcx> { index: &'a mut Index, parent_stab: Option, parent_const_stab: Option, - in_trait_impl: bool, } impl<'a, 'tcx> Annotator<'a, 'tcx> { @@ -133,9 +165,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn annotate( &mut self, def_id: LocalDefId, - item_sp: Span, fn_sig: Option<&'tcx hir::FnSig<'tcx>>, - kind: AnnotationKind, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, inherit_from_parent: InheritStability, @@ -146,7 +176,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - let depr = self.tcx.lookup_deprecation_entry(def_id); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); if !self.tcx.features().staged_api() { @@ -169,20 +198,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // # Regular and body stability - let stab = attrs::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span)); + let stab = + attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); let body_stab = attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); - if let Some(depr) = &depr - && depr.attr.is_since_rustc_version() - && stab.is_none() - && let Some(depr_span) = attrs::find_attr!(attrs, - AttributeKind::Deprecation { span, .. } => *span - ) - { - self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: depr_span }); - } - if let Some(body_stab) = body_stab { // FIXME: check that this item can have body stability @@ -190,52 +210,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { debug!(?self.index.default_body_stab_map); } - let stab = stab.map(|(stab, span)| { - // Error if prohibited, or can't inherit anything from a container. - if kind == AnnotationKind::Prohibited - || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some()) - { - self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp }); - } - + if let Some(stab) = stab { debug!("annotate: found {:?}", stab); - // Check if deprecated_since < stable_since. If it is, - // this is *almost surely* an accident. - if let ( - &Some(DeprecatedSince::RustcVersion(dep_since)), - &attrs::StabilityLevel::Stable { since: stab_since, .. }, - ) = (&depr.as_ref().map(|d| d.attr.since), &stab.level) - { - match stab_since { - StableSince::Current => { - self.tcx - .dcx() - .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); - } - StableSince::Version(stab_since) => { - if dep_since < stab_since { - self.tcx - .dcx() - .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); - } - } - StableSince::Err => { - // An error already reported. Assume the unparseable stabilization - // version is older than the deprecation version. - } - } - } - - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab { - if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { - self.tcx - .dcx() - .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); - } - } if let Stability { level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, feature, @@ -245,8 +222,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } self.index.stab_map.insert(def_id, stab); - stab - }); + } if stab.is_none() { debug!("annotate: stab not found, parent = {:?}", self.parent_stab); @@ -261,54 +237,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // # Const stability - let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span)); - - // If the current node is a function with const stability attributes (directly given or - // implied), check if the function/method is const or the parent impl block is const. - if let Some(fn_sig) = fn_sig - && !fn_sig.header.is_const() - && const_stab.is_some() - { - self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); - } - - // If this is marked const *stable*, it must also be regular-stable. - if let Some((const_stab, const_span)) = const_stab - && let Some(fn_sig) = fn_sig - && const_stab.is_const_stable() - && !stab.is_some_and(|s| s.is_stable()) - { - self.tcx - .dcx() - .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); - } - - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Some(( - PartialConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }, - const_span, - )) = const_stab - { - if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { - self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { - span: const_span, - item_sp, - }); - } - } - - if let Some((stab, span)) = &const_stab - && stab.is_const_stable() - && const_stability_indirect - { - self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span: *span }); - } + let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); // After checking the immediate attributes, get rid of the span and compute implied // const stability: inherit feature gate from regular stability. - let mut const_stab = const_stab - .map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect)); + let mut const_stab = + const_stab.map(|stab| ConstStability::from_partial(stab, const_stability_indirect)); // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && @@ -399,33 +333,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - let orig_in_trait_impl = self.in_trait_impl; - let mut kind = AnnotationKind::Required; let mut const_stab_inherit = InheritConstStability::No; let mut fn_sig = None; match i.kind { - // Inherent impls and foreign modules serve only as containers for other items, - // they don't have their own stability. They still can be annotated as unstable - // and propagate this instability to children, but this annotation is completely - // optional. They inherit stability from their parents when unannotated. - hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) - | hir::ItemKind::ForeignMod { .. } => { - self.in_trait_impl = false; - kind = AnnotationKind::Container; - } hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => { - self.in_trait_impl = true; - kind = AnnotationKind::DeprecationProhibited; const_stab_inherit = InheritConstStability::Yes; } hir::ItemKind::Struct(_, _, ref sd) => { if let Some(ctor_def_id) = sd.ctor_def_id() { self.annotate( ctor_def_id, - i.span, None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, @@ -441,15 +360,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { self.annotate( i.owner_id.def_id, - i.span, fn_sig, - kind, InheritDeprecation::Yes, const_stab_inherit, InheritStability::No, |v| intravisit::walk_item(v, i), ); - self.in_trait_impl = orig_in_trait_impl; } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { @@ -460,9 +376,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { self.annotate( ti.owner_id.def_id, - ti.span, fn_sig, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, @@ -473,9 +387,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - let kind = - if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required }; - let fn_sig = match ii.kind { hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig), _ => None, @@ -483,9 +394,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { self.annotate( ii.owner_id.def_id, - ii.span, fn_sig, - kind, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, @@ -498,9 +407,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { self.annotate( var.def_id, - var.span, None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, @@ -508,9 +415,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { if let Some(ctor_def_id) = var.data.ctor_def_id() { v.annotate( ctor_def_id, - var.span, None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, @@ -526,9 +431,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { self.annotate( s.def_id, - s.span, None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, @@ -545,9 +448,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { }; self.annotate( i.owner_id.def_id, - i.span, fn_sig, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, @@ -558,18 +459,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - let kind = match &p.kind { - // Allow stability attributes on default generic arguments. - hir::GenericParamKind::Type { default: Some(_), .. } - | hir::GenericParamKind::Const { default: Some(_), .. } => AnnotationKind::Container, - _ => AnnotationKind::Prohibited, - }; - self.annotate( p.def_id, - p.span, None, - kind, InheritDeprecation::No, InheritConstStability::No, InheritStability::No, @@ -586,6 +478,125 @@ struct MissingStabilityAnnotations<'tcx> { } impl<'tcx> MissingStabilityAnnotations<'tcx> { + #[instrument(level = "trace", skip(self))] + fn check_compatible_stability(&self, def_id: LocalDefId, item_sp: Span) { + if !self.tcx.features().staged_api() { + return; + } + + let depr = self.tcx.lookup_deprecation_entry(def_id); + let stab = self.tcx.lookup_stability(def_id); + let const_stab = self.tcx.lookup_const_stability(def_id); + + macro_rules! find_attr_span { + ($name:ident) => {{ + let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); + attrs::find_attr!(attrs, AttributeKind::$name { span, .. } => *span) + }} + } + + if stab.is_none() + && depr.map_or(false, |d| d.attr.is_since_rustc_version()) + && let Some(span) = find_attr_span!(Deprecation) + { + self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span }); + } + + if let Some(stab) = stab { + // Error if prohibited, or can't inherit anything from a container. + let kind = annotation_kind(self.tcx, def_id); + if kind == AnnotationKind::Prohibited + || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some()) + { + if let Some(span) = find_attr_span!(Stability) { + self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp }); + } + } + + // Check if deprecated_since < stable_since. If it is, + // this is *almost surely* an accident. + if let Some(depr) = depr + && let DeprecatedSince::RustcVersion(dep_since) = depr.attr.since + && let attrs::StabilityLevel::Stable { since: stab_since, .. } = stab.level + && let Some(span) = find_attr_span!(Stability) + { + match stab_since { + StableSince::Current => { + self.tcx + .dcx() + .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); + } + StableSince::Version(stab_since) => { + if dep_since < stab_since { + self.tcx + .dcx() + .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); + } + } + StableSince::Err => { + // An error already reported. Assume the unparseable stabilization + // version is older than the deprecation version. + } + } + } + + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab + && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() + && let Some(span) = find_attr_span!(Stability) + { + self.tcx + .dcx() + .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); + } + } + + // If the current node is a function with const stability attributes (directly given or + // implied), check if the function/method is const or the parent impl block is const. + let fn_sig = self.tcx.hir_node_by_def_id(def_id).fn_sig(); + if let Some(fn_sig) = fn_sig + && !fn_sig.header.is_const() + && const_stab.is_some() + && find_attr_span!(ConstStability).is_some() + { + self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); + } + + // If this is marked const *stable*, it must also be regular-stable. + if let Some(const_stab) = const_stab + && let Some(fn_sig) = fn_sig + && const_stab.is_const_stable() + && !stab.is_some_and(|s| s.is_stable()) + && let Some(const_span) = find_attr_span!(ConstStability) + { + self.tcx + .dcx() + .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); + } + + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if let Some(ConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }) = + const_stab + && let Some(const_span) = find_attr_span!(ConstStability) + && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() + { + self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { + span: const_span, + item_sp, + }); + } + + if let Some(stab) = &const_stab + && stab.is_const_stable() + && stab.const_stable_indirect + && let Some(span) = find_attr_span!(ConstStability) + { + self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span }); + } + } + fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { let stab = self.tcx.stability().local_stability(def_id); if !self.tcx.sess.is_test_crate() @@ -621,6 +632,8 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { + self.check_compatible_stability(i.owner_id.def_id, i.span); + // Inherent impls and foreign modules serve only as containers for other items, // they don't have their own stability. They still can be annotated as unstable // and propagate this instability to children, but this annotation is completely @@ -640,11 +653,13 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { + self.check_compatible_stability(ti.owner_id.def_id, ti.span); self.check_missing_stability(ti.owner_id.def_id, ti.span); intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { + self.check_compatible_stability(ii.owner_id.def_id, ii.span); let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { self.check_missing_stability(ii.owner_id.def_id, ii.span); @@ -654,6 +669,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { + self.check_compatible_stability(var.def_id, var.span); self.check_missing_stability(var.def_id, var.span); if let Some(ctor_def_id) = var.data.ctor_def_id() { self.check_missing_stability(ctor_def_id, var.span); @@ -662,17 +678,24 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { + self.check_compatible_stability(s.def_id, s.span); self.check_missing_stability(s.def_id, s.span); intravisit::walk_field_def(self, s); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { + self.check_compatible_stability(i.owner_id.def_id, i.span); self.check_missing_stability(i.owner_id.def_id, i.span); intravisit::walk_foreign_item(self, i); } - // Note that we don't need to `check_missing_stability` for default generic parameters, - // as we assume that any default generic parameters without attributes are automatically - // stable (assuming they have not inherited instability from their parent). + + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + self.check_compatible_stability(p.def_id, p.span); + // Note that we don't need to `check_missing_stability` for default generic parameters, + // as we assume that any default generic parameters without attributes are automatically + // stable (assuming they have not inherited instability from their parent). + intravisit::walk_generic_param(self, p); + } } fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { @@ -684,13 +707,8 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { }; { - let mut annotator = Annotator { - tcx, - index: &mut index, - parent_stab: None, - parent_const_stab: None, - in_trait_impl: false, - }; + let mut annotator = + Annotator { tcx, index: &mut index, parent_stab: None, parent_const_stab: None }; // If the `-Z force-unstable-if-unmarked` flag is passed then we provide // a parent stability annotation which indicates that this is private @@ -714,9 +732,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { annotator.annotate( CRATE_DEF_ID, - tcx.hir_span(CRATE_HIR_ID), None, - AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr index 4b13826584dcc..8d10bddaa45fa 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.stderr +++ b/tests/ui/consts/rustc-const-stability-require-const.stderr @@ -22,30 +22,6 @@ help: make the function or method const LL | pub fn bar() {} | ^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` - --> $DIR/rustc-const-stability-require-const.rs:21:5 - | -LL | pub fn salad(&self) -> &'static str { "mmmmmm" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function or method const - --> $DIR/rustc-const-stability-require-const.rs:21:5 - | -LL | pub fn salad(&self) -> &'static str { "mmmmmm" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` - --> $DIR/rustc-const-stability-require-const.rs:26:5 - | -LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function or method const - --> $DIR/rustc-const-stability-require-const.rs:26:5 - | -LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` --> $DIR/rustc-const-stability-require-const.rs:32:1 | @@ -86,5 +62,29 @@ LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] LL | pub const fn barfoo_unstable() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:21:5 + | +LL | pub fn salad(&self) -> &'static str { "mmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:21:5 + | +LL | pub fn salad(&self) -> &'static str { "mmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:26:5 + | +LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:26:5 + | +LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 8 previous errors From 879213fcc3d4a7c10b92a57c62ad9b7c8fef8f75 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 13 Jul 2025 11:30:30 +0000 Subject: [PATCH 05/11] Check for already stable features in check_attr. --- compiler/rustc_passes/src/check_attr.rs | 43 ++++++++++++++++--- compiler/rustc_passes/src/errors.rs | 4 +- compiler/rustc_passes/src/stability.rs | 27 +----------- ...ute-rejects-already-stable-features.stderr | 22 +++++----- 4 files changed, 51 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8c62c5d3087cf..1c51477c20f6f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -11,11 +11,17 @@ use std::slice; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; -use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr}; +use rustc_attr_data_structures::{ + AttributeKind, InlineAttr, PartialConstStability, ReprAttr, Stability, StabilityLevel, + find_attr, +}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; -use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; +use rustc_feature::{ + ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, + BuiltinAttribute, +}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; @@ -156,9 +162,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_confusables(*first_span, target); } Attribute::Parsed( - AttributeKind::Stability { span, .. } - | AttributeKind::ConstStability { span, .. }, - ) => self.check_stability_promotable(*span, target), + AttributeKind::Stability { + span: attr_span, + stability: Stability { level, feature }, + } + | AttributeKind::ConstStability { + span: attr_span, + stability: PartialConstStability { level, feature, .. }, + }, + ) => self.check_stability(*attr_span, span, level, *feature, target), Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} // handled separately below Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => { self.check_inline(hir_id, *attr_span, span, kind, target) @@ -2250,13 +2262,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_stability_promotable(&self, span: Span, target: Target) { + fn check_stability( + &self, + attr_span: Span, + item_span: Span, + level: &StabilityLevel, + feature: Symbol, + target: Target, + ) { match target { Target::Expression => { - self.dcx().emit_err(errors::StabilityPromotable { attr_span: span }); + self.dcx().emit_err(errors::StabilityPromotable { attr_span }); } _ => {} } + + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if level.is_unstable() + && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() + { + self.tcx + .dcx() + .emit_err(errors::UnstableAttrForAlreadyStableFeature { attr_span, item_span }); + } } fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4ad615a2abfc8..c5ed418ec697e 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1356,9 +1356,9 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature { #[primary_span] #[label] #[help] - pub span: Span, + pub attr_span: Span, #[label(passes_item)] - pub item_sp: Span, + pub item_span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4a3fdef2d8151..7c32749850574 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -11,7 +11,7 @@ use rustc_attr_data_structures::{ }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; -use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature}; +use rustc_feature::{EnabledLangFeature, EnabledLibFeature}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::hir_id::CRATE_HIR_ID; @@ -478,6 +478,7 @@ struct MissingStabilityAnnotations<'tcx> { } impl<'tcx> MissingStabilityAnnotations<'tcx> { + /// Verify that deprecation and stability attributes make sense with one another. #[instrument(level = "trace", skip(self))] fn check_compatible_stability(&self, def_id: LocalDefId, item_sp: Span) { if !self.tcx.features().staged_api() { @@ -539,17 +540,6 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } } } - - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab - && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() - && let Some(span) = find_attr_span!(Stability) - { - self.tcx - .dcx() - .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); - } } // If the current node is a function with const stability attributes (directly given or @@ -575,19 +565,6 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); } - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Some(ConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }) = - const_stab - && let Some(const_span) = find_attr_span!(ConstStability) - && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() - { - self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { - span: const_span, - item_sp, - }); - } - if let Some(stab) = &const_stab && stab.is_const_stable() && stab.const_stable_indirect diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr index 319056a9c8898..d599523c7274d 100644 --- a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr +++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr @@ -1,31 +1,31 @@ error: can't mark as unstable using an already stable feature - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 | -LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable LL | const fn my_fun() {} | -------------------- the stability attribute annotates this item | help: consider removing the attribute - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 | -LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: can't mark as unstable using an already stable feature - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 | +LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable LL | const fn my_fun() {} | -------------------- the stability attribute annotates this item | help: consider removing the attribute - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 | -LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors From 541bceb2baa7b46a47d26b01b70d4621bdf7a207 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 30 Jan 2023 20:47:11 +0000 Subject: [PATCH 06/11] Querify lookup_default_body_stability. --- compiler/rustc_middle/src/middle/stability.rs | 5 --- compiler/rustc_passes/src/stability.rs | 32 +++++++++++-------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 9c2528ca4103b..1c90fa66423bd 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -72,7 +72,6 @@ pub struct Index { /// are filled by the annotator. pub stab_map: LocalDefIdMap, pub const_stab_map: LocalDefIdMap, - pub default_body_stab_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -96,10 +95,6 @@ impl Index { pub fn local_const_stability(&self, def_id: LocalDefId) -> Option { self.const_stab_map.get(&def_id).copied() } - - pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option { - self.default_body_stab_map.get(&def_id).copied() - } } pub fn report_unstable( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 7c32749850574..4591271ea1c41 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -6,8 +6,8 @@ use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; use rustc_attr_data_structures::{ - self as attrs, AttributeKind, ConstStability, DeprecatedSince, Stability, StabilityLevel, - StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, + self as attrs, AttributeKind, ConstStability, DefaultBodyStability, DeprecatedSince, Stability, + StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; @@ -150,6 +150,20 @@ fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, + def_id: LocalDefId, +) -> Option { + if !tcx.features().staged_api() { + return None; + } + + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + // FIXME: check that this item can have body stability + attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability) +} + /// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -197,18 +211,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { return; } - // # Regular and body stability + // # Regular stability let stab = attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); - let body_stab = - attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); - - if let Some(body_stab) = body_stab { - // FIXME: check that this item can have body stability - - self.index.default_body_stab_map.insert(def_id, body_stab); - debug!(?self.index.default_body_stab_map); - } if let Some(stab) = stab { debug!("annotate: found {:?}", stab); @@ -679,7 +684,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { let mut index = Index { stab_map: Default::default(), const_stab_map: Default::default(), - default_body_stab_map: Default::default(), implications: Default::default(), }; @@ -732,7 +736,7 @@ pub(crate) fn provide(providers: &mut Providers) { stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability: |tcx, id| tcx.stability().local_stability(id), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), - lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id), + lookup_default_body_stability, lookup_deprecation_entry, ..*providers }; From 4758e36c5ee5fda6d747717e8b948f3e5aad3f49 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:15:25 +0000 Subject: [PATCH 07/11] Querify lookup_stability. --- compiler/rustc_middle/src/middle/stability.rs | 5 - compiler/rustc_passes/src/stability.rs | 225 +++++++++--------- 2 files changed, 107 insertions(+), 123 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 1c90fa66423bd..9ac7ab6447477 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -70,7 +70,6 @@ impl DeprecationEntry { pub struct Index { /// This is mostly a cache, except the stabilities of local items /// are filled by the annotator. - pub stab_map: LocalDefIdMap, pub const_stab_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute @@ -88,10 +87,6 @@ pub struct Index { } impl Index { - pub fn local_stability(&self, def_id: LocalDefId) -> Option { - self.stab_map.get(&def_id).copied() - } - pub fn local_const_stability(&self, def_id: LocalDefId) -> Option { self.const_stab_map.get(&def_id).copied() } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4591271ea1c41..28c812f23e22c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -150,6 +150,78 @@ fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option InheritStability { + match def_kind { + DefKind::Field | DefKind::Variant | DefKind::Ctor(..) => InheritStability::Yes, + _ => InheritStability::No, + } +} + +/// If the `-Z force-unstable-if-unmarked` flag is passed then we provide +/// a parent stability annotation which indicates that this is private +/// with the `rustc_private` feature. This is intended for use when +/// compiling `librustc_*` crates themselves so we can leverage crates.io +/// while maintaining the invariant that all sysroot crates are unstable +/// by default and are unable to be used. +const FORCE_UNSTABLE: Stability = Stability { + level: attrs::StabilityLevel::Unstable { + reason: UnstableReason::Default, + issue: NonZero::new(27812), + is_soft: false, + implied_by: None, + old_name: None, + }, + feature: sym::rustc_private, +}; + +#[instrument(level = "debug", skip(tcx))] +fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + // Propagate unstability. This can happen even for non-staged-api crates in case + // -Zforce-unstable-if-unmarked is set. + if !tcx.features().staged_api() { + if !tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + return None; + } + + let Some(parent) = tcx.opt_local_parent(def_id) else { return Some(FORCE_UNSTABLE) }; + + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let parent = tcx.lookup_stability(parent)?; + if parent.is_unstable() { + return Some(parent); + } + } + + return None; + } + + // # Regular stability + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let stab = + attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); + + if let Some(stab) = stab { + return Some(stab); + } + + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let Some(parent) = tcx.opt_local_parent(def_id) else { + return tcx + .sess + .opts + .unstable_opts + .force_unstable_if_unmarked + .then_some(FORCE_UNSTABLE); + }; + let parent = tcx.lookup_stability(parent)?; + if parent.is_unstable() || inherit_stability(tcx.def_kind(def_id)).yes() { + return Some(parent); + } + } + + None +} + #[instrument(level = "debug", skip(tcx))] fn lookup_default_body_stability( tcx: TyCtxt<'_>, @@ -168,7 +240,6 @@ fn lookup_default_body_stability( struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, - parent_stab: Option, parent_const_stab: Option, } @@ -182,7 +253,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn_sig: Option<&'tcx hir::FnSig<'tcx>>, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, - inherit_from_parent: InheritStability, visit_children: F, ) where F: FnOnce(&mut Self), @@ -190,14 +260,16 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); + let stab = self.tcx.lookup_stability(def_id); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); if !self.tcx.features().staged_api() { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. - if let Some(stab) = self.parent_stab { + if let Some(parent_def_id) = self.tcx.opt_local_parent(def_id) + && let Some(stab) = self.tcx.lookup_stability(parent_def_id) + { if inherit_deprecation.yes() && stab.is_unstable() { - self.index.stab_map.insert(def_id, stab); if fn_sig.is_some_and(|s| s.header.is_const()) { self.index.const_stab_map.insert( def_id, @@ -207,39 +279,18 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - self.recurse_with_stability_attrs(None, None, visit_children); + self.recurse_with_stability_attrs(None, visit_children); return; } - // # Regular stability - let stab = - attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); - - if let Some(stab) = stab { - debug!("annotate: found {:?}", stab); - - if let Stability { - level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, - feature, - } = stab - { - self.index.implications.insert(implied_by, feature); - } - - self.index.stab_map.insert(def_id, stab); - } - - if stab.is_none() { - debug!("annotate: stab not found, parent = {:?}", self.parent_stab); - if let Some(stab) = self.parent_stab { - if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() { - self.index.stab_map.insert(def_id, stab); - } - } + if let Some(Stability { + level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, + feature, + }) = stab + { + self.index.implications.insert(implied_by, feature); } - let final_stab = self.index.stab_map.get(&def_id); - // # Const stability let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); @@ -253,7 +304,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && // We only ever inherit unstable features. let Some(inherit_regular_stab) = - final_stab.filter(|s| s.is_unstable()) + stab.filter(|s| s.is_unstable()) { const_stab = Some(ConstStability { // We subject these implicitly-const functions to recursive const stability. @@ -292,7 +343,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } self.recurse_with_stability_attrs( - stab, inherit_const_stability.yes().then_some(const_stab).flatten(), visit_children, ); @@ -300,17 +350,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn recurse_with_stability_attrs( &mut self, - stab: Option, const_stab: Option, f: impl FnOnce(&mut Self), ) { // These will be `Some` if this item changes the corresponding stability attribute. - let mut replaced_parent_stab = None; let mut replaced_parent_const_stab = None; - if let Some(stab) = stab { - replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab))); - } if let Some(const_stab) = const_stab { replaced_parent_const_stab = Some(replace(&mut self.parent_const_stab, Some(const_stab))); @@ -318,9 +363,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { f(self); - if let Some(orig_parent_stab) = replaced_parent_stab { - self.parent_stab = orig_parent_stab; - } if let Some(orig_parent_const_stab) = replaced_parent_const_stab { self.parent_const_stab = orig_parent_const_stab; } @@ -352,7 +394,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { None, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::Yes, |_| {}, ) } @@ -368,7 +409,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, const_stab_inherit, - InheritStability::No, |v| intravisit::walk_item(v, i), ); } @@ -384,7 +424,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| { intravisit::walk_trait_item(v, ti); }, @@ -402,7 +441,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| { intravisit::walk_impl_item(v, ii); }, @@ -410,40 +448,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.annotate( - var.def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::Yes, - |v| { - if let Some(ctor_def_id) = var.data.ctor_def_id() { - v.annotate( - ctor_def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::Yes, - |_| {}, - ); - } + self.annotate(var.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + if let Some(ctor_def_id) = var.data.ctor_def_id() { + v.annotate( + ctor_def_id, + None, + InheritDeprecation::Yes, + InheritConstStability::No, + |_| {}, + ); + } - intravisit::walk_variant(v, var) - }, - ) + intravisit::walk_variant(v, var) + }) } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.annotate( - s.def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::Yes, - |v| { - intravisit::walk_field_def(v, s); - }, - ); + self.annotate(s.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + intravisit::walk_field_def(v, s); + }); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { @@ -456,7 +479,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| { intravisit::walk_foreign_item(v, i); }, @@ -464,16 +486,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.annotate( - p.def_id, - None, - InheritDeprecation::No, - InheritConstStability::No, - InheritStability::No, - |v| { - intravisit::walk_generic_param(v, p); - }, - ); + self.annotate(p.def_id, None, InheritDeprecation::No, InheritConstStability::No, |v| { + intravisit::walk_generic_param(v, p); + }); } } @@ -580,7 +595,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { - let stab = self.tcx.stability().local_stability(def_id); + let stab = self.tcx.lookup_stability(def_id); if !self.tcx.sess.is_test_crate() && stab.is_none() && self.effective_visibilities.is_reachable(def_id) @@ -681,42 +696,16 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { - let mut index = Index { - stab_map: Default::default(), - const_stab_map: Default::default(), - implications: Default::default(), - }; + let mut index = Index { const_stab_map: Default::default(), implications: Default::default() }; { - let mut annotator = - Annotator { tcx, index: &mut index, parent_stab: None, parent_const_stab: None }; - - // If the `-Z force-unstable-if-unmarked` flag is passed then we provide - // a parent stability annotation which indicates that this is private - // with the `rustc_private` feature. This is intended for use when - // compiling `librustc_*` crates themselves so we can leverage crates.io - // while maintaining the invariant that all sysroot crates are unstable - // by default and are unable to be used. - if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { - let stability = Stability { - level: attrs::StabilityLevel::Unstable { - reason: UnstableReason::Default, - issue: NonZero::new(27812), - is_soft: false, - implied_by: None, - old_name: None, - }, - feature: sym::rustc_private, - }; - annotator.parent_stab = Some(stability); - } + let mut annotator = Annotator { tcx, index: &mut index, parent_const_stab: None }; annotator.annotate( CRATE_DEF_ID, None, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| tcx.hir_walk_toplevel_module(v), ); } @@ -734,7 +723,7 @@ pub(crate) fn provide(providers: &mut Providers) { check_mod_unstable_api_usage, stability_index, stability_implications: |tcx, _| tcx.stability().implications.clone(), - lookup_stability: |tcx, id| tcx.stability().local_stability(id), + lookup_stability, lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), lookup_default_body_stability, lookup_deprecation_entry, @@ -1009,7 +998,7 @@ fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { }; let def_id = owner.def_id; - let Some(stab) = tcx.stability().local_stability(def_id) else { + let Some(stab) = tcx.lookup_stability(def_id) else { return false; }; From 43f08a4e2102faad127c11bec19eb205f9a78c4c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:41:16 +0000 Subject: [PATCH 08/11] Querify lookup_const_stability. --- compiler/rustc_middle/src/middle/stability.rs | 11 +- compiler/rustc_passes/src/stability.rs | 284 +++++++----------- 2 files changed, 110 insertions(+), 185 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 9ac7ab6447477..2dcf10deb54c5 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -10,7 +10,7 @@ use rustc_attr_data_structures::{ use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_feature::GateIssue; -use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, HirId}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_session::Session; @@ -68,9 +68,6 @@ impl DeprecationEntry { /// A stability index, giving the stability level for items and methods. #[derive(HashStable, Debug)] pub struct Index { - /// This is mostly a cache, except the stabilities of local items - /// are filled by the annotator. - pub const_stab_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -86,12 +83,6 @@ pub struct Index { pub implications: UnordMap, } -impl Index { - pub fn local_const_stability(&self, def_id: LocalDefId) -> Option { - self.const_stab_map.get(&def_id).copied() - } -} - pub fn report_unstable( sess: &Session, feature: Symbol, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 28c812f23e22c..d18615ad78668 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1,7 +1,6 @@ //! A pass that annotates every item and method with its stability level, //! propagating default levels lexically from parent to children ast nodes. -use std::mem::replace; use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; @@ -96,6 +95,19 @@ fn inherit_deprecation(def_kind: DefKind) -> InheritDeprecation { } } +fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> InheritConstStability { + let def_kind = tcx.def_kind(def_id); + match def_kind { + DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + match tcx.def_kind(tcx.local_parent(def_id)) { + DefKind::Impl { of_trait: true } => InheritConstStability::Yes, + _ => InheritConstStability::No, + } + } + _ => InheritConstStability::No, + } +} + fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind { let def_kind = tcx.def_kind(def_id); match def_kind { @@ -236,50 +248,96 @@ fn lookup_default_body_stability( attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability) } +#[instrument(level = "debug", skip(tcx))] +fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + if !tcx.features().staged_api() { + // Propagate unstability. This can happen even for non-staged-api crates in case + // -Zforce-unstable-if-unmarked is set. + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let parent = tcx.opt_local_parent(def_id)?; + let parent_stab = tcx.lookup_stability(parent)?; + if parent_stab.is_unstable() + && let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig() + && fn_sig.header.is_const() + { + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let const_stability_indirect = + find_attr!(attrs, AttributeKind::ConstStabilityIndirect); + return Some(ConstStability::unmarked(const_stability_indirect, parent_stab)); + } + } + + return None; + } + + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); + let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); + + // After checking the immediate attributes, get rid of the span and compute implied + // const stability: inherit feature gate from regular stability. + let mut const_stab = const_stab + .map(|const_stab| ConstStability::from_partial(const_stab, const_stability_indirect)); + + // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. + if let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig() + && fn_sig.header.is_const() + && const_stab.is_none() + // We only ever inherit unstable features. + && let Some(inherit_regular_stab) = tcx.lookup_stability(def_id) + && inherit_regular_stab.is_unstable() + { + const_stab = Some(ConstStability { + // We subject these implicitly-const functions to recursive const stability. + const_stable_indirect: true, + promotable: false, + level: inherit_regular_stab.level, + feature: inherit_regular_stab.feature, + }); + } + + // Now that everything is computed, insert it into the table. + if let Some(const_stab) = const_stab { + return Some(const_stab); + } + + // `impl const Trait for Type` items forward their const stability to their + // immediate children. + // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? + // Currently, once that is set, we do not inherit anything from the parent any more. + if inherit_const_stability(tcx, def_id).yes() { + let parent = tcx.opt_local_parent(def_id)?; + let parent = tcx.lookup_const_stability(parent)?; + if parent.is_const_unstable() { + return Some(parent); + } + } + + None +} + /// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, - parent_const_stab: Option, } impl<'a, 'tcx> Annotator<'a, 'tcx> { /// Determine the stability for a node based on its attributes and inherited stability. The /// stability is recorded in the index and used as the parent. If the node is a function, /// `fn_sig` is its signature. - fn annotate( - &mut self, - def_id: LocalDefId, - fn_sig: Option<&'tcx hir::FnSig<'tcx>>, - inherit_deprecation: InheritDeprecation, - inherit_const_stability: InheritConstStability, - visit_children: F, - ) where + #[instrument(level = "trace", skip(self, visit_children))] + fn annotate(&mut self, def_id: LocalDefId, visit_children: F) + where F: FnOnce(&mut Self), { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); let stab = self.tcx.lookup_stability(def_id); - let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); if !self.tcx.features().staged_api() { - // Propagate unstability. This can happen even for non-staged-api crates in case - // -Zforce-unstable-if-unmarked is set. - if let Some(parent_def_id) = self.tcx.opt_local_parent(def_id) - && let Some(stab) = self.tcx.lookup_stability(parent_def_id) - { - if inherit_deprecation.yes() && stab.is_unstable() { - if fn_sig.is_some_and(|s| s.header.is_const()) { - self.index.const_stab_map.insert( - def_id, - ConstStability::unmarked(const_stability_indirect, stab), - ); - } - } - } - - self.recurse_with_stability_attrs(None, visit_children); + visit_children(self); return; } @@ -293,32 +351,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // # Const stability - let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); - - // After checking the immediate attributes, get rid of the span and compute implied - // const stability: inherit feature gate from regular stability. - let mut const_stab = - const_stab.map(|stab| ConstStability::from_partial(stab, const_stability_indirect)); - - // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. - if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && - // We only ever inherit unstable features. - let Some(inherit_regular_stab) = - stab.filter(|s| s.is_unstable()) - { - const_stab = Some(ConstStability { - // We subject these implicitly-const functions to recursive const stability. - const_stable_indirect: true, - promotable: false, - level: inherit_regular_stab.level, - feature: inherit_regular_stab.feature, - }); - } - - // Now that everything is computed, insert it into the table. - const_stab.inspect(|const_stab| { - self.index.const_stab_map.insert(def_id, *const_stab); - }); + let const_stab = self.tcx.lookup_const_stability(def_id); if let Some(ConstStability { level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, @@ -329,43 +362,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.index.implications.insert(implied_by, feature); } - // `impl const Trait for Type` items forward their const stability to their - // immediate children. - // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? - // Currently, once that is set, we do not inherit anything from the parent any more. - if const_stab.is_none() { - debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab); - if let Some(parent) = self.parent_const_stab { - if parent.is_const_unstable() { - self.index.const_stab_map.insert(def_id, parent); - } - } - } - - self.recurse_with_stability_attrs( - inherit_const_stability.yes().then_some(const_stab).flatten(), - visit_children, - ); - } - - fn recurse_with_stability_attrs( - &mut self, - const_stab: Option, - f: impl FnOnce(&mut Self), - ) { - // These will be `Some` if this item changes the corresponding stability attribute. - let mut replaced_parent_const_stab = None; - - if let Some(const_stab) = const_stab { - replaced_parent_const_stab = - Some(replace(&mut self.parent_const_stab, Some(const_stab))); - } - - f(self); - - if let Some(orig_parent_const_stab) = replaced_parent_const_stab { - self.parent_const_stab = orig_parent_const_stab; - } + visit_children(self) } } @@ -380,83 +377,34 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - let mut const_stab_inherit = InheritConstStability::No; - let mut fn_sig = None; - match i.kind { - hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => { - const_stab_inherit = InheritConstStability::Yes; - } hir::ItemKind::Struct(_, _, ref sd) => { if let Some(ctor_def_id) = sd.ctor_def_id() { - self.annotate( - ctor_def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - |_| {}, - ) + self.annotate(ctor_def_id, |_| {}) } } - hir::ItemKind::Fn { sig: ref item_fn_sig, .. } => { - fn_sig = Some(item_fn_sig); - } _ => {} } - self.annotate( - i.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - const_stab_inherit, - |v| intravisit::walk_item(v, i), - ); + self.annotate(i.owner_id.def_id, |v| intravisit::walk_item(v, i)); } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - let fn_sig = match ti.kind { - hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig), - _ => None, - }; - - self.annotate( - ti.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| { - intravisit::walk_trait_item(v, ti); - }, - ); + self.annotate(ti.owner_id.def_id, |v| { + intravisit::walk_trait_item(v, ti); + }); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - let fn_sig = match ii.kind { - hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig), - _ => None, - }; - - self.annotate( - ii.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| { - intravisit::walk_impl_item(v, ii); - }, - ); + self.annotate(ii.owner_id.def_id, |v| { + intravisit::walk_impl_item(v, ii); + }); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.annotate(var.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + self.annotate(var.def_id, |v| { if let Some(ctor_def_id) = var.data.ctor_def_id() { - v.annotate( - ctor_def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - |_| {}, - ); + v.annotate(ctor_def_id, |_| {}); } intravisit::walk_variant(v, var) @@ -464,29 +412,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.annotate(s.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + self.annotate(s.def_id, |v| { intravisit::walk_field_def(v, s); }); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - let fn_sig = match &i.kind { - rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig), - _ => None, - }; - self.annotate( - i.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| { - intravisit::walk_foreign_item(v, i); - }, - ); + self.annotate(i.owner_id.def_id, |v| { + intravisit::walk_foreign_item(v, i); + }); } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.annotate(p.def_id, None, InheritDeprecation::No, InheritConstStability::No, |v| { + self.annotate(p.def_id, |v| { intravisit::walk_generic_param(v, p); }); } @@ -594,8 +532,10 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } } + #[instrument(level = "debug", skip(self))] fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { let stab = self.tcx.lookup_stability(def_id); + self.tcx.ensure_ok().lookup_const_stability(def_id); if !self.tcx.sess.is_test_crate() && stab.is_none() && self.effective_visibilities.is_reachable(def_id) @@ -696,18 +636,12 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { - let mut index = Index { const_stab_map: Default::default(), implications: Default::default() }; + let mut index = Index { implications: Default::default() }; { - let mut annotator = Annotator { tcx, index: &mut index, parent_const_stab: None }; - - annotator.annotate( - CRATE_DEF_ID, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| tcx.hir_walk_toplevel_module(v), - ); + let mut annotator = Annotator { tcx, index: &mut index }; + + annotator.annotate(CRATE_DEF_ID, |v| tcx.hir_walk_toplevel_module(v)); } index } @@ -724,7 +658,7 @@ pub(crate) fn provide(providers: &mut Providers) { stability_index, stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability, - lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), + lookup_const_stability, lookup_default_body_stability, lookup_deprecation_entry, ..*providers From 6dad5e8de06e19e8751ccb780fec25c5cd3d7e97 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:57:57 +0000 Subject: [PATCH 09/11] Simplify annotator. --- compiler/rustc_passes/src/stability.rs | 88 +++++++++----------------- 1 file changed, 30 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index d18615ad78668..978c2f5a6a4a6 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -28,7 +28,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL}; use rustc_span::{Span, Symbol, sym}; -use tracing::{debug, info, instrument}; +use tracing::{info, instrument}; use crate::errors; @@ -326,43 +326,23 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { /// Determine the stability for a node based on its attributes and inherited stability. The /// stability is recorded in the index and used as the parent. If the node is a function, /// `fn_sig` is its signature. - #[instrument(level = "trace", skip(self, visit_children))] - fn annotate(&mut self, def_id: LocalDefId, visit_children: F) - where - F: FnOnce(&mut Self), - { - let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); - debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - - let stab = self.tcx.lookup_stability(def_id); - + #[instrument(level = "trace", skip(self))] + fn annotate(&mut self, def_id: LocalDefId) { if !self.tcx.features().staged_api() { - visit_children(self); return; } - if let Some(Stability { - level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, - feature, - }) = stab + if let Some(stability) = self.tcx.lookup_stability(def_id) + && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, feature); + self.index.implications.insert(implied_by, stability.feature); } - // # Const stability - - let const_stab = self.tcx.lookup_const_stability(def_id); - - if let Some(ConstStability { - level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, - feature, - .. - }) = const_stab + if let Some(stability) = self.tcx.lookup_const_stability(def_id) + && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, feature); + self.index.implications.insert(implied_by, stability.feature); } - - visit_children(self) } } @@ -380,53 +360,48 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { match i.kind { hir::ItemKind::Struct(_, _, ref sd) => { if let Some(ctor_def_id) = sd.ctor_def_id() { - self.annotate(ctor_def_id, |_| {}) + self.annotate(ctor_def_id); } } _ => {} } - self.annotate(i.owner_id.def_id, |v| intravisit::walk_item(v, i)); + self.annotate(i.owner_id.def_id); + intravisit::walk_item(self, i) } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.annotate(ti.owner_id.def_id, |v| { - intravisit::walk_trait_item(v, ti); - }); + self.annotate(ti.owner_id.def_id); + intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - self.annotate(ii.owner_id.def_id, |v| { - intravisit::walk_impl_item(v, ii); - }); + self.annotate(ii.owner_id.def_id); + intravisit::walk_impl_item(self, ii); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.annotate(var.def_id, |v| { - if let Some(ctor_def_id) = var.data.ctor_def_id() { - v.annotate(ctor_def_id, |_| {}); - } + self.annotate(var.def_id); + if let Some(ctor_def_id) = var.data.ctor_def_id() { + self.annotate(ctor_def_id); + } - intravisit::walk_variant(v, var) - }) + intravisit::walk_variant(self, var) } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.annotate(s.def_id, |v| { - intravisit::walk_field_def(v, s); - }); + self.annotate(s.def_id); + intravisit::walk_field_def(self, s); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.annotate(i.owner_id.def_id, |v| { - intravisit::walk_foreign_item(v, i); - }); + self.annotate(i.owner_id.def_id); + intravisit::walk_foreign_item(self, i); } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.annotate(p.def_id, |v| { - intravisit::walk_generic_param(v, p); - }); + self.annotate(p.def_id); + intravisit::walk_generic_param(self, p); } } @@ -637,12 +612,9 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { let mut index = Index { implications: Default::default() }; - - { - let mut annotator = Annotator { tcx, index: &mut index }; - - annotator.annotate(CRATE_DEF_ID, |v| tcx.hir_walk_toplevel_module(v)); - } + let mut annotator = Annotator { tcx, index: &mut index }; + annotator.annotate(CRATE_DEF_ID); + tcx.hir_walk_toplevel_module(&mut annotator); index } From 9fb80b1b5b813d127a65b7cf60dc82b378ac6b53 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:58:33 +0000 Subject: [PATCH 10/11] Retire stability_index query. --- compiler/rustc_interface/src/passes.rs | 1 - compiler/rustc_middle/src/middle/stability.rs | 19 ------------- compiler/rustc_middle/src/query/mod.rs | 19 +++++++++---- compiler/rustc_middle/src/ty/context.rs | 6 +--- compiler/rustc_passes/src/stability.rs | 28 ++++++++----------- 5 files changed, 26 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a438cde018c63..998661d635a47 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1065,7 +1065,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // This marks the corresponding crate-level attributes // as used, and ensures that their values are valid. tcx.ensure_ok().limits(()); - tcx.ensure_ok().stability_index(()); } ); }); diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 2dcf10deb54c5..dc9311188e809 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -7,7 +7,6 @@ use rustc_ast::NodeId; use rustc_attr_data_structures::{ self as attrs, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; -use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_feature::GateIssue; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -65,24 +64,6 @@ impl DeprecationEntry { } } -/// A stability index, giving the stability level for items and methods. -#[derive(HashStable, Debug)] -pub struct Index { - /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` - /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute - /// exists, then this map will have a `impliee -> implier` entry. - /// - /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should - /// specify their implications (both `implies` and `implied_by`). If only one of the two - /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this - /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is - /// reported, only the `#[stable]` attribute information is available, so the map is necessary - /// to know that the feature implies another feature. If it were reversed, and the `#[stable]` - /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of - /// unstable feature" error for a feature that was implied. - pub implications: UnordMap, -} - pub fn report_unstable( sess: &Session, feature: Symbol, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 842d118449a55..6a64838149338 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -112,7 +112,7 @@ use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::EffectiveVisibilities; use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg}; -use crate::middle::stability::{self, DeprecationEntry}; +use crate::middle::stability::DeprecationEntry; use crate::mir::interpret::{ EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId, LitToConstInput, @@ -2162,6 +2162,18 @@ rustc_queries! { separate_provide_extern arena_cache } + /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` + /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute + /// exists, then this map will have a `impliee -> implier` entry. + /// + /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should + /// specify their implications (both `implies` and `implied_by`). If only one of the two + /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this + /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is + /// reported, only the `#[stable]` attribute information is available, so the map is necessary + /// to know that the feature implies another feature. If it were reversed, and the `#[stable]` + /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of + /// unstable feature" error for a feature that was implied. query stability_implications(_: CrateNum) -> &'tcx UnordMap { arena_cache desc { "calculating the implications between `#[unstable]` features defined in a crate" } @@ -2268,11 +2280,6 @@ rustc_queries! { desc { "fetching potentially unused trait imports" } } - query stability_index(_: ()) -> &'tcx stability::Index { - arena_cache - eval_always - desc { "calculating the stability index for the local crate" } - } /// All available crates in the graph, including those that should not be user-facing /// (such as private crates). query crates(_: ()) -> &'tcx [CrateNum] { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98b2ce01d89b2..bb603f2e0fe33 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -65,7 +65,7 @@ use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, Canonica use crate::lint::lint_level; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature}; -use crate::middle::{resolve_bound_vars, stability}; +use crate::middle::resolve_bound_vars; use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::query::plumbing::QuerySystem; @@ -1799,10 +1799,6 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn stability(self) -> &'tcx stability::Index { - self.stability_index(()) - } - pub fn features(self) -> &'tcx rustc_feature::Features { self.features_query(()) } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 978c2f5a6a4a6..6c88c453b4563 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -19,10 +19,8 @@ use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, T use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; -use rustc_middle::middle::stability::{ - AllowUnstable, Deprecated, DeprecationEntry, EvalResult, Index, -}; -use rustc_middle::query::Providers; +use rustc_middle::middle::stability::{AllowUnstable, Deprecated, DeprecationEntry, EvalResult}; +use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; @@ -317,12 +315,12 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { +struct Annotator<'tcx> { tcx: TyCtxt<'tcx>, - index: &'a mut Index, + implications: UnordMap, } -impl<'a, 'tcx> Annotator<'a, 'tcx> { +impl<'tcx> Annotator<'tcx> { /// Determine the stability for a node based on its attributes and inherited stability. The /// stability is recorded in the index and used as the parent. If the node is a function, /// `fn_sig` is its signature. @@ -335,18 +333,18 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(stability) = self.tcx.lookup_stability(def_id) && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, stability.feature); + self.implications.insert(implied_by, stability.feature); } if let Some(stability) = self.tcx.lookup_const_stability(def_id) && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, stability.feature); + self.implications.insert(implied_by, stability.feature); } } } -impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for Annotator<'tcx> { /// Because stability levels are scoped lexically, we want to walk /// nested items in the context of the outer item, so enable /// deep-walking. @@ -610,12 +608,11 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } } -fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { - let mut index = Index { implications: Default::default() }; - let mut annotator = Annotator { tcx, index: &mut index }; +fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap { + let mut annotator = Annotator { tcx, implications: Default::default() }; annotator.annotate(CRATE_DEF_ID); tcx.hir_walk_toplevel_module(&mut annotator); - index + annotator.implications } /// Cross-references the feature names of unstable APIs with enabled @@ -627,8 +624,7 @@ fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_unstable_api_usage, - stability_index, - stability_implications: |tcx, _| tcx.stability().implications.clone(), + stability_implications, lookup_stability, lookup_const_stability, lookup_default_body_stability, From 2890684a24b2d0386701d119a5ae7bdcd35b4e61 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 30 Jan 2022 15:41:35 +0100 Subject: [PATCH 11/11] Integrate stable feature checking into a query. --- compiler/rustc_interface/src/passes.rs | 5 -- compiler/rustc_passes/src/stability.rs | 69 +++++++++++-------- ...issue-43106-gating-of-builtin-attrs.stderr | 16 ++--- .../ui/lint/lint-stability-deprecated.stderr | 20 +++--- tests/ui/lint/lint-stability.stderr | 18 ++--- tests/ui/missing/missing-stability.stderr | 9 +-- .../effective_visibilities_invariants.stderr | 2 +- tests/ui/privacy/issue-113860-1.stderr | 18 ++--- tests/ui/privacy/issue-113860-2.stderr | 18 ++--- tests/ui/privacy/issue-113860.stderr | 18 ++--- .../missing-const-stability.stderr | 14 ++-- .../stability-attribute-sanity-3.stderr | 6 +- 12 files changed, 93 insertions(+), 120 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 998661d635a47..fb6897c7d8958 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1054,11 +1054,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { tcx.ensure_ok().check_mod_unstable_api_usage(module); }); }, - { - sess.time("unused_lib_feature_checking", || { - rustc_passes::stability::check_unused_or_stable_features(tcx) - }); - }, { // We force these queries to run, // since they might not otherwise get called. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6c88c453b4563..05b4ba27441d6 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -13,7 +13,6 @@ use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; use rustc_feature::{EnabledLangFeature, EnabledLibFeature}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; -use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; @@ -411,7 +410,7 @@ struct MissingStabilityAnnotations<'tcx> { impl<'tcx> MissingStabilityAnnotations<'tcx> { /// Verify that deprecation and stability attributes make sense with one another. #[instrument(level = "trace", skip(self))] - fn check_compatible_stability(&self, def_id: LocalDefId, item_sp: Span) { + fn check_compatible_stability(&self, def_id: LocalDefId) { if !self.tcx.features().staged_api() { return; } @@ -441,6 +440,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some()) { if let Some(span) = find_attr_span!(Stability) { + let item_sp = self.tcx.def_span(def_id); self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp }); } } @@ -452,6 +452,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { && let attrs::StabilityLevel::Stable { since: stab_since, .. } = stab.level && let Some(span) = find_attr_span!(Stability) { + let item_sp = self.tcx.def_span(def_id); match stab_since { StableSince::Current => { self.tcx @@ -506,7 +507,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } #[instrument(level = "debug", skip(self))] - fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { + fn check_missing_stability(&self, def_id: LocalDefId) { let stab = self.tcx.lookup_stability(def_id); self.tcx.ensure_ok().lookup_const_stability(def_id); if !self.tcx.sess.is_test_crate() @@ -514,11 +515,12 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { && self.effective_visibilities.is_reachable(def_id) { let descr = self.tcx.def_descr(def_id.to_def_id()); + let span = self.tcx.def_span(def_id); self.tcx.dcx().emit_err(errors::MissingStabilityAttr { span, descr }); } } - fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) { + fn check_missing_const_stability(&self, def_id: LocalDefId) { let is_const = self.tcx.is_const_fn(def_id.to_def_id()) || (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait && self.tcx.is_const_trait(def_id.to_def_id())); @@ -528,6 +530,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { && self.effective_visibilities.is_reachable(def_id) && self.tcx.lookup_const_stability(def_id).is_none() { + let span = self.tcx.def_span(def_id); let descr = self.tcx.def_descr(def_id.to_def_id()); self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr }); } @@ -542,7 +545,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - self.check_compatible_stability(i.owner_id.def_id, i.span); + self.check_compatible_stability(i.owner_id.def_id); // Inherent impls and foreign modules serve only as containers for other items, // they don't have their own stability. They still can be annotated as unstable @@ -553,54 +556,54 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) | hir::ItemKind::ForeignMod { .. } ) { - self.check_missing_stability(i.owner_id.def_id, i.span); + self.check_missing_stability(i.owner_id.def_id); } // Ensure stable `const fn` have a const stability attribute. - self.check_missing_const_stability(i.owner_id.def_id, i.span); + self.check_missing_const_stability(i.owner_id.def_id); intravisit::walk_item(self, i) } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.check_compatible_stability(ti.owner_id.def_id, ti.span); - self.check_missing_stability(ti.owner_id.def_id, ti.span); + self.check_compatible_stability(ti.owner_id.def_id); + self.check_missing_stability(ti.owner_id.def_id); intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - self.check_compatible_stability(ii.owner_id.def_id, ii.span); + self.check_compatible_stability(ii.owner_id.def_id); let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { - self.check_missing_stability(ii.owner_id.def_id, ii.span); - self.check_missing_const_stability(ii.owner_id.def_id, ii.span); + self.check_missing_stability(ii.owner_id.def_id); + self.check_missing_const_stability(ii.owner_id.def_id); } intravisit::walk_impl_item(self, ii); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.check_compatible_stability(var.def_id, var.span); - self.check_missing_stability(var.def_id, var.span); + self.check_compatible_stability(var.def_id); + self.check_missing_stability(var.def_id); if let Some(ctor_def_id) = var.data.ctor_def_id() { - self.check_missing_stability(ctor_def_id, var.span); + self.check_missing_stability(ctor_def_id); } intravisit::walk_variant(self, var); } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.check_compatible_stability(s.def_id, s.span); - self.check_missing_stability(s.def_id, s.span); + self.check_compatible_stability(s.def_id); + self.check_missing_stability(s.def_id); intravisit::walk_field_def(self, s); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.check_compatible_stability(i.owner_id.def_id, i.span); - self.check_missing_stability(i.owner_id.def_id, i.span); + self.check_compatible_stability(i.owner_id.def_id); + self.check_missing_stability(i.owner_id.def_id); intravisit::walk_foreign_item(self, i); } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.check_compatible_stability(p.def_id, p.span); + self.check_compatible_stability(p.def_id); // Note that we don't need to `check_missing_stability` for default generic parameters, // as we assume that any default generic parameters without attributes are automatically // stable (assuming they have not inherited instability from their parent). @@ -619,6 +622,21 @@ fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap, module_def_id: LocalModDefId) { tcx.hir_visit_item_likes_in_module(module_def_id, &mut Checker { tcx }); + + let is_staged_api = + tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api(); + if is_staged_api { + let effective_visibilities = &tcx.effective_visibilities(()); + let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities }; + if module_def_id.is_top_level_module() { + missing.check_missing_stability(CRATE_DEF_ID); + } + tcx.hir_visit_item_likes_in_module(module_def_id, &mut missing); + } + + if module_def_id.is_top_level_module() { + check_unused_or_stable_features(tcx) + } } pub(crate) fn provide(providers: &mut Providers) { @@ -969,16 +987,9 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> { /// Given the list of enabled features that were not language features (i.e., that /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. +// This is `pub` for rustdoc. rustc should call it through `check_mod_unstable_api_usage`. pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { - let is_staged_api = - tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api(); - if is_staged_api { - let effective_visibilities = &tcx.effective_visibilities(()); - let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities }; - missing.check_missing_stability(CRATE_DEF_ID, tcx.hir_span(CRATE_HIR_ID)); - tcx.hir_walk_toplevel_module(&mut missing); - tcx.hir_visit_all_item_likes_in_crate(&mut missing); - } + let _prof_timer = tcx.sess.timer("unused_lib_feature_checking"); let enabled_lang_features = tcx.features().enabled_lang_features(); let mut lang_features = UnordSet::default(); 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 c0935fe2a145e..96da43a76f075 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 @@ -417,6 +417,14 @@ 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: 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:85:12 + | +LL | #![feature(rust1)] + | ^^^^^ + | + = note: `#[warn(stable_features)]` on by default + warning: `#[macro_use]` only has an effect on `extern crate` and modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5 | @@ -1161,13 +1169,5 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -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:85:12 - | -LL | #![feature(rust1)] - | ^^^^^ - | - = note: `#[warn(stable_features)]` on by default - warning: 173 warnings emitted diff --git a/tests/ui/lint/lint-stability-deprecated.stderr b/tests/ui/lint/lint-stability-deprecated.stderr index 51205ff434062..0399fab746ec4 100644 --- a/tests/ui/lint/lint-stability-deprecated.stderr +++ b/tests/ui/lint/lint-stability-deprecated.stderr @@ -1,8 +1,8 @@ -warning: use of deprecated function `lint_stability::deprecated`: text - --> $DIR/lint-stability-deprecated.rs:24:9 +warning: use of deprecated associated type `lint_stability::TraitWithAssociatedTypes::TypeDeprecated`: text + --> $DIR/lint-stability-deprecated.rs:97:48 | -LL | deprecated(); - | ^^^^^^^^^^ +LL | struct S2(T::TypeDeprecated); + | ^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-stability-deprecated.rs:6:9 @@ -10,6 +10,12 @@ note: the lint level is defined here LL | #![warn(deprecated)] | ^^^^^^^^^^ +warning: use of deprecated function `lint_stability::deprecated`: text + --> $DIR/lint-stability-deprecated.rs:24:9 + | +LL | deprecated(); + | ^^^^^^^^^^ + warning: use of deprecated method `lint_stability::Trait::trait_deprecated`: text --> $DIR/lint-stability-deprecated.rs:29:16 | @@ -316,12 +322,6 @@ warning: use of deprecated function `this_crate::MethodTester::test_method_body: LL | fn_in_body(); | ^^^^^^^^^^ -warning: use of deprecated associated type `lint_stability::TraitWithAssociatedTypes::TypeDeprecated`: text - --> $DIR/lint-stability-deprecated.rs:97:48 - | -LL | struct S2(T::TypeDeprecated); - | ^^^^^^^^^^^^^^^^^ - warning: use of deprecated associated type `lint_stability::TraitWithAssociatedTypes::TypeDeprecated`: text --> $DIR/lint-stability-deprecated.rs:101:13 | diff --git a/tests/ui/lint/lint-stability.stderr b/tests/ui/lint/lint-stability.stderr index a22fce70a4ad5..a147854db3d51 100644 --- a/tests/ui/lint/lint-stability.stderr +++ b/tests/ui/lint/lint-stability.stderr @@ -1,3 +1,12 @@ +error[E0658]: use of unstable library feature `unstable_test_feature` + --> $DIR/lint-stability.rs:88:48 + | +LL | struct S1(T::TypeUnstable); + | ^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable_test_feature)]` 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[E0658]: use of unstable library feature `unstable_test_feature` --> $DIR/lint-stability.rs:17:5 | @@ -367,15 +376,6 @@ LL | let _ = Unstable::StableVariant; = help: add `#![feature(unstable_test_feature)]` 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[E0658]: use of unstable library feature `unstable_test_feature` - --> $DIR/lint-stability.rs:88:48 - | -LL | struct S1(T::TypeUnstable); - | ^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable_test_feature)]` 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[E0658]: use of unstable library feature `unstable_test_feature` --> $DIR/lint-stability.rs:92:13 | diff --git a/tests/ui/missing/missing-stability.stderr b/tests/ui/missing/missing-stability.stderr index 659f8c78cae6d..bf8046c4e122d 100644 --- a/tests/ui/missing/missing-stability.stderr +++ b/tests/ui/missing/missing-stability.stderr @@ -1,17 +1,14 @@ error: function has missing stability attribute --> $DIR/missing-stability.rs:8:1 | -LL | / pub fn unmarked() { -LL | | -LL | | () -LL | | } - | |_^ +LL | pub fn unmarked() { + | ^^^^^^^^^^^^^^^^^ error: function has missing stability attribute --> $DIR/missing-stability.rs:22:5 | LL | pub fn unmarked() {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/privacy/effective_visibilities_invariants.stderr b/tests/ui/privacy/effective_visibilities_invariants.stderr index 64d0402f84e62..97bee1e2d8d36 100644 --- a/tests/ui/privacy/effective_visibilities_invariants.stderr +++ b/tests/ui/privacy/effective_visibilities_invariants.stderr @@ -23,7 +23,7 @@ error: module has missing stability attribute --> $DIR/effective_visibilities_invariants.rs:5:1 | LL | pub mod m {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/privacy/issue-113860-1.stderr b/tests/ui/privacy/issue-113860-1.stderr index dad9ebadf0459..764c9f4925bed 100644 --- a/tests/ui/privacy/issue-113860-1.stderr +++ b/tests/ui/privacy/issue-113860-1.stderr @@ -20,28 +20,20 @@ LL | | fn main() {} error: trait has missing stability attribute --> $DIR/issue-113860-1.rs:4:1 | -LL | / pub trait Trait { -LL | | -LL | | fn fun() {} -LL | | -LL | | } - | |_^ +LL | pub trait Trait { + | ^^^^^^^^^^^^^^^ error: implementation has missing stability attribute --> $DIR/issue-113860-1.rs:10:1 | -LL | / impl Trait for u8 { -LL | | -LL | | pub(self) fn fun() {} -LL | | -LL | | } - | |_^ +LL | impl Trait for u8 { + | ^^^^^^^^^^^^^^^^^ error: associated function has missing stability attribute --> $DIR/issue-113860-1.rs:6:5 | LL | fn fun() {} - | ^^^^^^^^^^^ + | ^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/privacy/issue-113860-2.stderr b/tests/ui/privacy/issue-113860-2.stderr index 9805c22dbdf58..d0847aa2b49dd 100644 --- a/tests/ui/privacy/issue-113860-2.stderr +++ b/tests/ui/privacy/issue-113860-2.stderr @@ -20,28 +20,20 @@ LL | | fn main() {} error: trait has missing stability attribute --> $DIR/issue-113860-2.rs:4:1 | -LL | / pub trait Trait { -LL | | -LL | | type X; -LL | | -LL | | } - | |_^ +LL | pub trait Trait { + | ^^^^^^^^^^^^^^^ error: implementation has missing stability attribute --> $DIR/issue-113860-2.rs:10:1 | -LL | / impl Trait for u8 { -LL | | -LL | | pub(self) type X = Self; -LL | | -LL | | } - | |_^ +LL | impl Trait for u8 { + | ^^^^^^^^^^^^^^^^^ error: associated type has missing stability attribute --> $DIR/issue-113860-2.rs:6:5 | LL | type X; - | ^^^^^^^ + | ^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/privacy/issue-113860.stderr b/tests/ui/privacy/issue-113860.stderr index 88efcae4a8577..d7a15255b1574 100644 --- a/tests/ui/privacy/issue-113860.stderr +++ b/tests/ui/privacy/issue-113860.stderr @@ -20,28 +20,20 @@ LL | | fn main() {} error: trait has missing stability attribute --> $DIR/issue-113860.rs:4:1 | -LL | / pub trait Trait { -LL | | -LL | | const X: u32; -LL | | -LL | | } - | |_^ +LL | pub trait Trait { + | ^^^^^^^^^^^^^^^ error: implementation has missing stability attribute --> $DIR/issue-113860.rs:10:1 | -LL | / impl Trait for u8 { -LL | | -LL | | pub(self) const X: u32 = 3; -LL | | -LL | | } - | |_^ +LL | impl Trait for u8 { + | ^^^^^^^^^^^^^^^^^ error: associated constant has missing stability attribute --> $DIR/issue-113860.rs:6:5 | LL | const X: u32; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr index 09461e6fb54d6..c2dfdbd70cd69 100644 --- a/tests/ui/stability-attribute/missing-const-stability.stderr +++ b/tests/ui/stability-attribute/missing-const-stability.stderr @@ -2,29 +2,25 @@ error: function has missing const stability attribute --> $DIR/missing-const-stability.rs:7:1 | LL | pub const fn foo() {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: trait has missing const stability attribute --> $DIR/missing-const-stability.rs:24:1 | -LL | / pub trait Bar { -LL | | -LL | | #[stable(feature = "stable", since = "1.0.0")] -LL | | fn fun(); -LL | | } - | |_^ +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error: function has missing const stability attribute --> $DIR/missing-const-stability.rs:37:1 | LL | pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: associated function has missing const stability attribute --> $DIR/missing-const-stability.rs:16:5 | LL | pub const fn foo() {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr index a6d1ebf29458e..d33bb53360bcf 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr @@ -1,10 +1,8 @@ error: macro has missing stability attribute --> $DIR/stability-attribute-sanity-3.rs:8:1 | -LL | / macro_rules! mac { -LL | | () => () -LL | | } - | |_^ +LL | macro_rules! mac { + | ^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error