diff options
Diffstat (limited to 'compiler/rustc_attr_parsing')
29 files changed, 666 insertions, 56 deletions
diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index cec9d62e656..bac89373b67 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index de22ea322c7..4fb66a81652 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -10,6 +10,12 @@ attr_parsing_empty_attribute = unused attribute .suggestion = remove this attribute +attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target} + .help = `#[{$name}]` can {$only}be applied to {$applied} +attr_parsing_invalid_target_lint = `#[{$name}]` attribute cannot be used on {$target} + .warn = {-attr_parsing_previously_accepted} + .help = `#[{$name}]` can {$only}be applied to {$applied} + attr_parsing_empty_confusables = expected at least one confusable name attr_parsing_expected_one_cfg_pattern = diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index b3393e93de8..4d995027814 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -2,10 +2,12 @@ use std::iter; use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::AttributeKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; @@ -15,6 +17,12 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser { type Item = (Symbol, Span); const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::AllowInternalUnstable(items, span); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::MacroDef), + Allow(Target::Fn), + Warn(Target::Field), + Warn(Target::Arm), + ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); fn extend<'c>( @@ -32,6 +40,11 @@ impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser { const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound]; type Item = (Symbol, Span); const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Trait), + ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); fn extend<'c>( @@ -53,6 +66,13 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser { type Item = Symbol; const CONVERT: ConvertFn<Self::Item> = |items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); fn extend<'c>( diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs index ab9330216f6..88540384621 100644 --- a/compiler/rustc_attr_parsing/src/attributes/body.rs +++ b/compiler/rustc_attr_parsing/src/attributes/body.rs @@ -1,15 +1,18 @@ //! Attributes that can be found in function body. +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use super::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; +use crate::context::MaybeWarn::Allow; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct CoroutineParser; impl<S: Stage> NoArgsAttributeParser<S> for CoroutineParser { const PATH: &[Symbol] = &[sym::coroutine]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]); const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span); } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index a9f77195d1b..6ea073896c2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,5 +1,6 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, CoverageAttrKind, OptimizeAttr, UsedBy}; +use rustc_hir::{MethodKind, Target}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -7,7 +8,8 @@ use super::{ AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; -use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport}; @@ -17,6 +19,13 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser { const PATH: &[Symbol] = &[sym::optimize]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Closure), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Method(MethodKind::Inherent)), + ]); const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { @@ -49,6 +58,15 @@ pub(crate) struct ColdParser; impl<S: Stage> NoArgsAttributeParser<S> for ColdParser { const PATH: &[Symbol] = &[sym::cold]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::ForeignFn), + Allow(Target::Closure), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold; } @@ -58,6 +76,17 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser { const PATH: &[Symbol] = &[sym::coverage]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Closure), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Mod), + Allow(Target::Crate), + ]); const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { @@ -97,6 +126,16 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser { const PATH: &[rustc_span::Symbol] = &[sym::export_name]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Static), + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Warn(Target::Field), + Warn(Target::Arm), + Warn(Target::MacroDef), + ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { @@ -138,6 +177,12 @@ impl<S: Stage> AttributeParser<S> for NakedParser { this.span = Some(cx.attr_span); } })]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + ]); fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { // FIXME(jdonszelmann): upgrade this list to *parsed* attributes @@ -230,6 +275,18 @@ pub(crate) struct TrackCallerParser; impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser { const PATH: &[Symbol] = &[sym::track_caller]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::ForeignFn), + Allow(Target::Closure), + Warn(Target::MacroDef), + Warn(Target::Arm), + Warn(Target::Field), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller; } @@ -237,6 +294,12 @@ pub(crate) struct NoMangleParser; impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser { const PATH: &[Symbol] = &[sym::no_mangle]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Fn), + Allow(Target::Static), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::TraitImpl)), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle; } @@ -310,6 +373,7 @@ impl<S: Stage> AttributeParser<S> for UsedParser { } }, )]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker` @@ -373,4 +437,15 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser { } features } + + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Warn(Target::Statement), + Warn(Target::Field), + Warn(Target::Arm), + Warn(Target::MacroDef), + ]); } diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index edd22172ca2..00f949c82c5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -1,12 +1,13 @@ use rustc_feature::template; use rustc_hir::attrs::AttributeKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use super::{AcceptMapping, AttributeParser}; -use crate::context::{FinalizeContext, Stage}; +use crate::context::MaybeWarn::Allow; +use crate::context::{AllowedTargets, FinalizeContext, Stage}; use crate::session_diagnostics; - #[derive(Default)] pub(crate) struct ConfusablesParser { confusables: ThinVec<Symbol>, @@ -41,6 +42,8 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser { this.first_span.get_or_insert(cx.attr_span); }, )]; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if self.confusables.is_empty() { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index e57ea8bbb5c..8101c91460f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,13 +1,14 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation}; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use super::util::parse_version; use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Error}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; - pub(crate) struct DeprecationParser; fn get<S: Stage>( @@ -38,6 +39,30 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser { const PATH: &[Symbol] = &[sym::deprecated]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Fn), + Allow(Target::Mod), + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::Const), + Allow(Target::Static), + Allow(Target::MacroDef), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::TyAlias), + Allow(Target::Use), + Allow(Target::ForeignFn), + Allow(Target::Field), + Allow(Target::Trait), + Allow(Target::AssocTy), + Allow(Target::AssocConst), + Allow(Target::Variant), + Allow(Target::Impl { of_trait: false }), //FIXME This does not make sense + Allow(Target::Crate), + Error(Target::WherePredicate), + ]); const TEMPLATE: AttributeTemplate = template!( Word, List: &[r#"since = "version""#, r#"note = "reason""#, r#"since = "version", note = "reason""#], diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index bbcd9ab530c..85842b1b5c5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -3,14 +3,14 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct DummyParser; impl<S: Stage> SingleAttributeParser<S> for DummyParser { const PATH: &[Symbol] = &[sym::rustc_dummy]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser<'_>) -> Option<AttributeKind> { diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index e9a45f20bff..6a659a95b85 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -5,19 +5,34 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, InlineAttr}; use rustc_hir::lints::AttributeLintKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Symbol, sym}; use super::{AcceptContext, AttributeOrder, OnDuplicate}; use crate::attributes::SingleAttributeParser; -use crate::context::Stage; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct InlineParser; impl<S: Stage> SingleAttributeParser<S> for InlineParser { const PATH: &'static [Symbol] = &[sym::inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Closure), + Allow(Target::Delegation { mac: false }), + Warn(Target::Method(MethodKind::Trait { body: false })), + Warn(Target::ForeignFn), + Warn(Target::Field), + Warn(Target::MacroDef), + Warn(Target::Arm), + Warn(Target::AssocConst), + ]); const TEMPLATE: AttributeTemplate = template!( Word, List: &["always", "never"], @@ -63,6 +78,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser { const PATH: &'static [Symbol] = &[sym::rustc_force_inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index e4ced2e37c5..552b9dfabc2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,21 +1,26 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_hir::attrs::{AttributeKind, Linkage}; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; -use crate::context::{AcceptContext, Stage, parse_single_integer}; +use crate::context::MaybeWarn::Allow; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage, parse_single_integer}; use crate::parser::ArgParser; use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection}; - pub(crate) struct LinkNameParser; impl<S: Stage> SingleAttributeParser<S> for LinkNameParser { const PATH: &[Symbol] = &[sym::link_name]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), + ]); const TEMPLATE: AttributeTemplate = template!( NameValueStr: "name", "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute" @@ -41,6 +46,8 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser { const PATH: &[Symbol] = &[sym::link_section]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Static), Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!( NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute" @@ -70,6 +77,7 @@ pub(crate) struct ExportStableParser; impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser { const PATH: &[Symbol] = &[sym::export_stable]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable; } @@ -77,6 +85,7 @@ pub(crate) struct FfiConstParser; impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser { const PATH: &[Symbol] = &[sym::ffi_const]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst; } @@ -84,6 +93,7 @@ pub(crate) struct FfiPureParser; impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser { const PATH: &[Symbol] = &[sym::ffi_pure]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure; } @@ -91,6 +101,12 @@ pub(crate) struct StdInternalSymbolParser; impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser { const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::ForeignFn), + Allow(Target::Static), + Allow(Target::ForeignStatic), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol; } @@ -100,6 +116,8 @@ impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser { const PATH: &[Symbol] = &[sym::link_ordinal]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!( List: &["ordinal"], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute" @@ -138,6 +156,16 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Static), + Allow(Target::ForeignStatic), + Allow(Target::ForeignFn), + ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: [ "available_externally", diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 9530fec07d6..2b586d4003c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -1,13 +1,21 @@ use rustc_hir::attrs::AttributeKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::MaybeWarn::{Allow, Error}; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct AsPtrParser; impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser { const PATH: &[Symbol] = &[sym::rustc_as_ptr]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr; } @@ -15,6 +23,11 @@ pub(crate) struct PubTransparentParser; impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser { const PATH: &[Symbol] = &[sym::rustc_pub_transparent]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent; } @@ -22,6 +35,11 @@ pub(crate) struct PassByValueParser; impl<S: Stage> NoArgsAttributeParser<S> for PassByValueParser { const PATH: &[Symbol] = &[sym::rustc_pass_by_value]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::TyAlias), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue; } @@ -29,5 +47,10 @@ pub(crate) struct AutomaticallyDerivedParser; impl<S: Stage> NoArgsAttributeParser<S> for AutomaticallyDerivedParser { const PATH: &[Symbol] = &[sym::automatically_derived]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Impl { of_trait: true }), + Error(Target::Crate), + Error(Target::WherePredicate), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::AutomaticallyDerived; } diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs index 868c113a6d1..242e2f2c1bc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs +++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs @@ -1,13 +1,15 @@ +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::MaybeWarn::Allow; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct LoopMatchParser; impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser { const PATH: &[Symbol] = &[sym::loop_match]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::LoopMatch; } @@ -15,5 +17,6 @@ pub(crate) struct ConstContinueParser; impl<S: Stage> NoArgsAttributeParser<S> for ConstContinueParser { const PATH: &[Symbol] = &[sym::const_continue]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstContinue; } diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index a1166bf9ac5..c9b5dd35fa1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,18 +1,20 @@ use rustc_errors::DiagArgValue; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::{AttributeKind, MacroUseArgs}; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use crate::attributes::{AcceptMapping, AttributeParser, NoArgsAttributeParser, OnDuplicate}; -use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::context::MaybeWarn::{Allow, Error, Warn}; +use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; - pub(crate) struct MacroEscapeParser; impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser { const PATH: &[Symbol] = &[sym::macro_escape]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS; const CREATE: fn(Span) -> AttributeKind = AttributeKind::MacroEscape; } @@ -35,6 +37,12 @@ const MACRO_USE_TEMPLATE: AttributeTemplate = template!( Word, List: &["name1, name2, ..."], "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute" ); +const MACRO_USE_ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Mod), + Allow(Target::ExternCrate), + Allow(Target::Crate), + Error(Target::WherePredicate), +]); impl<S: Stage> AttributeParser<S> for MacroUseParser { const ATTRIBUTES: AcceptMapping<Self, S> = &[( @@ -111,6 +119,7 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser { } }, )]; + const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state }) @@ -122,5 +131,11 @@ pub(crate) struct AllowInternalUnsafeParser; impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser { const PATH: &[Symbol] = &[sym::allow_internal_unsafe]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::MacroDef), + Warn(Target::Field), + Warn(Target::Arm), + ]); const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span); } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index f7946ade6d2..ed5d1d92b8c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -21,7 +21,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; -use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics::UnusedMultiple; @@ -80,6 +80,8 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static { /// If an attribute has this symbol, the `accept` function will be called on it. const ATTRIBUTES: AcceptMapping<Self, S>; + const ALLOWED_TARGETS: AllowedTargets; + /// The parser has gotten a chance to accept the attributes on an item, /// here it can produce an attribute. /// @@ -116,6 +118,8 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static { /// and this specified whether to, for example, warn or error on the other one. const ON_DUPLICATE: OnDuplicate<S>; + const ALLOWED_TARGETS: AllowedTargets; + /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; @@ -163,6 +167,7 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> } }, )]; + const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { Some(self.1?.0) @@ -247,6 +252,7 @@ pub(crate) enum AttributeOrder { pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static { const PATH: &[Symbol]; const ON_DUPLICATE: OnDuplicate<S>; + const ALLOWED_TARGETS: AllowedTargets; /// Create the [`AttributeKind`] given attribute's [`Span`]. const CREATE: fn(Span) -> AttributeKind; @@ -264,6 +270,7 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without const PATH: &[Symbol] = T::PATH; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE; + const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { @@ -293,6 +300,8 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static { /// where `x` is a vec of these individual reprs. const CONVERT: ConvertFn<Self::Item>; + const ALLOWED_TARGETS: AllowedTargets; + /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; @@ -324,15 +333,13 @@ impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> { } impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> { - const ATTRIBUTES: AcceptMapping<Self, S> = &[( - T::PATH, - <T as CombineAttributeParser<S>>::TEMPLATE, - |group: &mut Combine<T, S>, cx, args| { + const ATTRIBUTES: AcceptMapping<Self, S> = + &[(T::PATH, T::TEMPLATE, |group: &mut Combine<T, S>, cx, args| { // Keep track of the span of the first attribute, for diagnostics group.first_span.get_or_insert(cx.attr_span); group.items.extend(T::extend(cx, args)) - }, - )]; + })]; + const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if let Some(first_span) = self.first_span { diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index c88bb5a69e5..b6cfc780590 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -4,16 +4,16 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; - pub(crate) struct MustUseParser; impl<S: Stage> SingleAttributeParser<S> for MustUseParser { const PATH: &[Symbol] = &[sym::must_use]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const TEMPLATE: AttributeTemplate = template!( Word, NameValueStr: "reason", "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute" diff --git a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs index 40f8d00685e..589faf38f73 100644 --- a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs @@ -1,13 +1,16 @@ +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::MaybeWarn::Allow; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct NoImplicitPreludeParser; impl<S: Stage> NoArgsAttributeParser<S> for NoImplicitPreludeParser { const PATH: &[rustc_span::Symbol] = &[sym::no_implicit_prelude]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoImplicitPrelude; } diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 361ac8e959d..41e9ca4de41 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,13 +1,22 @@ +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct NonExhaustiveParser; impl<S: Stage> NoArgsAttributeParser<S> for NonExhaustiveParser { const PATH: &[Symbol] = &[sym::non_exhaustive]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Enum), + Allow(Target::Struct), + Allow(Target::Variant), + Warn(Target::Field), + Warn(Target::Arm), + Warn(Target::MacroDef), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; } diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index c1c3de8cbfc..f9191d1abed 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -1,17 +1,20 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Error}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct PathParser; impl<S: Stage> SingleAttributeParser<S> for PathParser { const PATH: &[Symbol] = &[sym::path]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Error(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!( NameValueStr: "file", "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute" diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index b267980914c..4624fa36287 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -1,4 +1,5 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; @@ -6,13 +7,15 @@ use thin_vec::ThinVec; use crate::attributes::{ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct ProcMacroParser; impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser { const PATH: &[Symbol] = &[sym::proc_macro]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro; } @@ -20,6 +23,8 @@ pub(crate) struct ProcMacroAttributeParser; impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser { const PATH: &[Symbol] = &[sym::proc_macro_attribute]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute; } @@ -28,6 +33,8 @@ impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser { const PATH: &[Symbol] = &[sym::proc_macro_derive]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!( List: &["TraitName", "TraitName, attributes(name1, name2, ...)"], "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros" @@ -48,6 +55,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser { const PATH: &[Symbol] = &[sym::rustc_builtin_macro]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const TEMPLATE: AttributeTemplate = template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]); diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 996d2af5f37..7ab58ed9347 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -2,14 +2,15 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, IntType, ReprAttr}; +use rustc_hir::{MethodKind, Target}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::Allow; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser}; use crate::session_diagnostics; use crate::session_diagnostics::IncorrectReprFormatGenericCause; - /// Parse #[repr(...)] forms. /// /// Valid repr contents: any of the primitive integral type names (see @@ -60,6 +61,10 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser { reprs } + + //FIXME Still checked fully in `check_attr.rs` + //This one is slightly more complicated because the allowed targets depend on the arguments + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); } macro_rules! int_pat { @@ -318,6 +323,14 @@ impl AlignParser { impl<S: Stage> AttributeParser<S> for AlignParser { const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::ForeignFn), + ]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { let (align, span) = self.0?; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 1a668b4416f..efd7b650e44 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1,17 +1,19 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage, parse_single_integer}; +use crate::context::MaybeWarn::Allow; +use crate::context::{AcceptContext, AllowedTargets, Stage, parse_single_integer}; use crate::parser::ArgParser; - pub(crate) struct RustcLayoutScalarValidRangeStart; impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart { const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["start"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { @@ -26,6 +28,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEnd { const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["end"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { @@ -40,6 +43,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser { const PATH: &[rustc_span::Symbol] = &[sym::rustc_object_lifetime_default]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index 70a8a002099..d4ad861a3a2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -2,11 +2,11 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::{ALL_TARGETS, AllowedTargets, Stage}; pub(crate) struct MayDangleParser; impl<S: Stage> NoArgsAttributeParser<S> for MayDangleParser { const PATH: &[Symbol] = &[sym::may_dangle]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle; } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index c6707f5048b..5a26178f84b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -4,15 +4,16 @@ use rustc_errors::ErrorGuaranteed; use rustc_feature::template; use rustc_hir::attrs::AttributeKind; use rustc_hir::{ - DefaultBodyStability, PartialConstStability, Stability, StabilityLevel, StableSince, - UnstableReason, VERSION_PLACEHOLDER, + DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel, + StableSince, Target, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_span::{Ident, Span, Symbol, sym}; use super::util::parse_version; use super::{AcceptMapping, AttributeParser, OnDuplicate}; use crate::attributes::NoArgsAttributeParser; -use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::context::MaybeWarn::Allow; +use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -26,6 +27,35 @@ macro_rules! reject_outside_std { }; } +const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Impl { of_trait: true }), + Allow(Target::MacroDef), + Allow(Target::Crate), + Allow(Target::Mod), + Allow(Target::Use), // FIXME I don't think this does anything? + Allow(Target::Const), + Allow(Target::AssocConst), + Allow(Target::AssocTy), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::TyAlias), + Allow(Target::Variant), + Allow(Target::Field), + Allow(Target::Param), + Allow(Target::Static), + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), +]); + #[derive(Default)] pub(crate) struct StabilityParser { allowed_through_unstable_modules: Option<Symbol>, @@ -87,6 +117,7 @@ impl<S: Stage> AttributeParser<S> for StabilityParser { }, ), ]; + const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS; fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if let Some(atum) = self.allowed_through_unstable_modules { @@ -142,6 +173,7 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser { } }, )]; + const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { let (stability, span) = self.stability?; @@ -154,6 +186,10 @@ pub(crate) struct ConstStabilityIndirectParser; impl<S: Stage> NoArgsAttributeParser<S> for ConstStabilityIndirectParser { const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + ]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect; } @@ -213,6 +249,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser { this.promotable = true; }), ]; + const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS; fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if self.promotable { diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 3267855fb0d..8b666c3868b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -1,18 +1,21 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::AttributeLintKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Error}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct IgnoreParser; impl<S: Stage> SingleAttributeParser<S> for IgnoreParser { const PATH: &[Symbol] = &[sym::ignore]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]); const TEMPLATE: AttributeTemplate = template!( Word, NameValueStr: "reason", "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute" @@ -54,6 +57,8 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser { const PATH: &[Symbol] = &[sym::should_panic]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]); const TEMPLATE: AttributeTemplate = template!( Word, List: &[r#"expected = "reason""#], NameValueStr: "reason", "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute" diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 8514d799aa4..ee9d7ba99cd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -2,19 +2,21 @@ use core::mem; use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::AttributeKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct SkipDuringMethodDispatchParser; impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser { const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]); @@ -58,6 +60,7 @@ pub(crate) struct ParenSugarParser; impl<S: Stage> NoArgsAttributeParser<S> for ParenSugarParser { const PATH: &[Symbol] = &[sym::rustc_paren_sugar]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ParenSugar; } @@ -65,6 +68,7 @@ pub(crate) struct TypeConstParser; impl<S: Stage> NoArgsAttributeParser<S> for TypeConstParser { const PATH: &[Symbol] = &[sym::type_const]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocConst)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst; } @@ -74,6 +78,12 @@ pub(crate) struct MarkerParser; impl<S: Stage> NoArgsAttributeParser<S> for MarkerParser { const PATH: &[Symbol] = &[sym::marker]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Trait), + Warn(Target::Field), + Warn(Target::Arm), + Warn(Target::MacroDef), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::Marker; } @@ -81,6 +91,7 @@ pub(crate) struct DenyExplicitImplParser; impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser { const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl; } @@ -88,6 +99,7 @@ pub(crate) struct DoNotImplementViaObjectParser; impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser { const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject; } @@ -98,6 +110,7 @@ pub(crate) struct ConstTraitParser; impl<S: Stage> NoArgsAttributeParser<S> for ConstTraitParser { const PATH: &[Symbol] = &[sym::const_trait]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstTrait; } @@ -107,6 +120,7 @@ pub(crate) struct SpecializationTraitParser; impl<S: Stage> NoArgsAttributeParser<S> for SpecializationTraitParser { const PATH: &[Symbol] = &[sym::rustc_specialization_trait]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::SpecializationTrait; } @@ -114,6 +128,7 @@ pub(crate) struct UnsafeSpecializationMarkerParser; impl<S: Stage> NoArgsAttributeParser<S> for UnsafeSpecializationMarkerParser { const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::UnsafeSpecializationMarker; } @@ -123,6 +138,7 @@ pub(crate) struct CoinductiveParser; impl<S: Stage> NoArgsAttributeParser<S> for CoinductiveParser { const PATH: &[Symbol] = &[sym::rustc_coinductive]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::Coinductive; } @@ -130,6 +146,8 @@ pub(crate) struct AllowIncoherentImplParser; impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser { const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl; } @@ -137,6 +155,7 @@ pub(crate) struct CoherenceIsCoreParser; impl<S: Stage> NoArgsAttributeParser<S> for CoherenceIsCoreParser { const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore; } @@ -144,6 +163,8 @@ pub(crate) struct FundamentalParser; impl<S: Stage> NoArgsAttributeParser<S> for FundamentalParser { const PATH: &[Symbol] = &[sym::fundamental]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Struct), Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental; } @@ -151,5 +172,6 @@ pub(crate) struct PointeeParser; impl<S: Stage> NoArgsAttributeParser<S> for PointeeParser { const PATH: &[Symbol] = &[sym::pointee]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee; } diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index d4d68eb8b27..0ffcf434b52 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,12 +1,13 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::hygiene::Transparency; use rustc_span::{Symbol, sym}; use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::Allow; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct TransparencyParser; // FIXME(jdonszelmann): make these proper diagnostics @@ -18,6 +19,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser { const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); }); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["transparent", "semitransparent", "opaque"]); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6045a8b28a2..bebe3350c4e 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -3,13 +3,16 @@ use std::collections::BTreeMap; use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; +use itertools::Itertools; use private::Sealed; use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId}; use rustc_errors::{DiagCtxtHandle, Diagnostic}; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; +use rustc_hir::{ + AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId, MethodKind, Target, +}; use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -61,8 +64,11 @@ use crate::attributes::traits::{ }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; +use crate::context::MaybeWarn::{Allow, Error, Warn}; use crate::parser::{ArgParser, MetaItemParser, PathParser}; -use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; +use crate::session_diagnostics::{ + AttributeParseError, AttributeParseErrorReason, InvalidTarget, UnknownMetaItem, +}; type GroupType<S> = LazyLock<GroupTypeInner<S>>; @@ -74,6 +80,7 @@ struct GroupTypeInner<S: Stage> { struct GroupTypeInnerAccept<S: Stage> { template: AttributeTemplate, accept_fn: AcceptFn<S>, + allowed_targets: AllowedTargets, } type AcceptFn<S> = @@ -121,7 +128,8 @@ macro_rules! attribute_parsers { STATE_OBJECT.with_borrow_mut(|s| { accept_fn(s, cx, args) }) - }) + }), + allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS, }); } @@ -643,6 +651,64 @@ impl ShouldEmit { } } +#[derive(Debug)] +pub(crate) enum AllowedTargets { + AllowList(&'static [MaybeWarn]), + AllowListWarnRest(&'static [MaybeWarn]), +} + +pub(crate) enum AllowedResult { + Allowed, + Warn, + Error, +} + +impl AllowedTargets { + pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult { + match self { + AllowedTargets::AllowList(list) => { + if list.contains(&Allow(target)) { + AllowedResult::Allowed + } else if list.contains(&Warn(target)) { + AllowedResult::Warn + } else { + AllowedResult::Error + } + } + AllowedTargets::AllowListWarnRest(list) => { + if list.contains(&Allow(target)) { + AllowedResult::Allowed + } else if list.contains(&Error(target)) { + AllowedResult::Error + } else { + AllowedResult::Warn + } + } + } + } + + pub(crate) fn allowed_targets(&self) -> Vec<Target> { + match self { + AllowedTargets::AllowList(list) => list, + AllowedTargets::AllowListWarnRest(list) => list, + } + .iter() + .filter_map(|target| match target { + Allow(target) => Some(*target), + Warn(_) => None, + Error(_) => None, + }) + .collect() + } +} + +#[derive(Debug, Eq, PartialEq)] +pub(crate) enum MaybeWarn { + Allow(Target), + Warn(Target), + Error(Target), +} + /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. pub struct AttributeParser<'sess, S: Stage = Late> { @@ -691,6 +757,7 @@ impl<'sess> AttributeParser<'sess, Early> { attrs, target_span, target_node_id, + Target::Crate, // Does not matter, we're not going to emit errors anyways OmitDoc::Skip, std::convert::identity, |_lint| { @@ -777,6 +844,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attrs: &[ast::Attribute], target_span: Span, target_id: S::Id, + target: Target, omit_doc: OmitDoc, lower_span: impl Copy + Fn(Span) -> Span, @@ -848,7 +916,48 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attr_path: path.get_attribute_path(), }; - (accept.accept_fn)(&mut cx, args) + (accept.accept_fn)(&mut cx, args); + + if self.stage.should_emit().should_emit() { + match accept.allowed_targets.is_allowed(target) { + AllowedResult::Allowed => {} + AllowedResult::Warn => { + let allowed_targets = + accept.allowed_targets.allowed_targets(); + let (applied, only) = allowed_targets_applied( + allowed_targets, + target, + self.features, + ); + emit_lint(AttributeLint { + id: target_id, + span: attr.span, + kind: AttributeLintKind::InvalidTarget { + name: parts[0], + target, + only: if only { "only " } else { "" }, + applied, + }, + }); + } + AllowedResult::Error => { + let allowed_targets = + accept.allowed_targets.allowed_targets(); + let (applied, only) = allowed_targets_applied( + allowed_targets, + target, + self.features, + ); + self.dcx().emit_err(InvalidTarget { + span: attr.span, + name: parts[0], + target: target.plural_name(), + only: if only { "only " } else { "" }, + applied, + }); + } + } + } } } else { // If we're here, we must be compiling a tool attribute... Or someone @@ -936,6 +1045,132 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } } +/// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to. +/// Does some heuristic-based filtering to remove uninteresting targets, and formats the targets into a string +pub(crate) fn allowed_targets_applied( + mut allowed_targets: Vec<Target>, + target: Target, + features: Option<&Features>, +) -> (String, bool) { + // Remove unstable targets from `allowed_targets` if their features are not enabled + if let Some(features) = features { + if !features.fn_delegation() { + allowed_targets.retain(|t| !matches!(t, Target::Delegation { .. })); + } + if !features.stmt_expr_attributes() { + allowed_targets.retain(|t| !matches!(t, Target::Expression | Target::Statement)); + } + } + + // We define groups of "similar" targets. + // If at least two of the targets are allowed, and the `target` is not in the group, + // we collapse the entire group to a single entry to simplify the target list + const FUNCTION_LIKE: &[Target] = &[ + Target::Fn, + Target::Closure, + Target::ForeignFn, + Target::Method(MethodKind::Inherent), + Target::Method(MethodKind::Trait { body: false }), + Target::Method(MethodKind::Trait { body: true }), + Target::Method(MethodKind::TraitImpl), + ]; + const METHOD_LIKE: &[Target] = &[ + Target::Method(MethodKind::Inherent), + Target::Method(MethodKind::Trait { body: false }), + Target::Method(MethodKind::Trait { body: true }), + Target::Method(MethodKind::TraitImpl), + ]; + const IMPL_LIKE: &[Target] = + &[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }]; + const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum]; + + let mut added_fake_targets = Vec::new(); + filter_targets( + &mut allowed_targets, + FUNCTION_LIKE, + "functions", + target, + &mut added_fake_targets, + ); + filter_targets(&mut allowed_targets, METHOD_LIKE, "methods", target, &mut added_fake_targets); + filter_targets(&mut allowed_targets, IMPL_LIKE, "impl blocks", target, &mut added_fake_targets); + filter_targets(&mut allowed_targets, ADT_LIKE, "data types", target, &mut added_fake_targets); + + // If there is now only 1 target left, show that as the only possible target + ( + added_fake_targets + .iter() + .copied() + .chain(allowed_targets.iter().map(|t| t.plural_name())) + .join(", "), + allowed_targets.len() + added_fake_targets.len() == 1, + ) +} + +fn filter_targets( + allowed_targets: &mut Vec<Target>, + target_group: &'static [Target], + target_group_name: &'static str, + target: Target, + added_fake_targets: &mut Vec<&'static str>, +) { + if target_group.contains(&target) { + return; + } + if allowed_targets.iter().filter(|at| target_group.contains(at)).count() < 2 { + return; + } + allowed_targets.retain(|t| !target_group.contains(t)); + added_fake_targets.push(target_group_name); +} + +/// This is the list of all targets to which a attribute can be applied +/// This is used for: +/// - `rustc_dummy`, which can be applied to all targets +/// - Attributes that are not parted to the new target system yet can use this list as a placeholder +pub(crate) const ALL_TARGETS: &'static [MaybeWarn] = &[ + Allow(Target::ExternCrate), + Allow(Target::Use), + Allow(Target::Static), + Allow(Target::Const), + Allow(Target::Fn), + Allow(Target::Closure), + Allow(Target::Mod), + Allow(Target::ForeignMod), + Allow(Target::GlobalAsm), + Allow(Target::TyAlias), + Allow(Target::Enum), + Allow(Target::Variant), + Allow(Target::Struct), + Allow(Target::Field), + Allow(Target::Union), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Expression), + Allow(Target::Statement), + Allow(Target::Arm), + Allow(Target::AssocConst), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::AssocTy), + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), + Allow(Target::ForeignTy), + Allow(Target::MacroDef), + Allow(Target::Param), + Allow(Target::PatField), + Allow(Target::ExprField), + Allow(Target::WherePredicate), + Allow(Target::MacroCall), + Allow(Target::Crate), + Allow(Target::Delegation { mac: false }), + Allow(Target::Delegation { mac: true }), +]; + /// Parse a single integer. /// /// Used by attributes that take a single integer as argument, such as diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 22f5531bc80..733225bab59 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -1,6 +1,7 @@ use rustc_errors::{DiagArgValue, LintEmitter}; -use rustc_hir::HirId; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_hir::{HirId, Target}; +use rustc_span::sym; use crate::session_diagnostics; @@ -34,5 +35,25 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi *first_span, session_diagnostics::EmptyAttributeList { attr_span: *first_span }, ), + &AttributeLintKind::InvalidTarget { name, target, ref applied, only } => lint_emitter + .emit_node_span_lint( + // This check is here because `deprecated` had its own lint group and removing this would be a breaking change + if name == sym::deprecated + && ![Target::Closure, Target::Expression, Target::Statement, Target::Arm] + .contains(&target) + { + rustc_session::lint::builtin::USELESS_DEPRECATED + } else { + rustc_session::lint::builtin::UNUSED_ATTRIBUTES + }, + *id, + *span, + session_diagnostics::InvalidTargetLint { + name, + target: target.plural_name(), + applied: applied.clone(), + only, + }, + ), } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 41179844152..95e85667cd6 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -480,6 +480,29 @@ pub(crate) struct EmptyAttributeList { pub attr_span: Span, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_invalid_target_lint)] +#[warning] +#[help] +pub(crate) struct InvalidTargetLint { + pub name: Symbol, + pub target: &'static str, + pub applied: String, + pub only: &'static str, +} + +#[derive(Diagnostic)] +#[help] +#[diag(attr_parsing_invalid_target)] +pub(crate) struct InvalidTarget { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub target: &'static str, + pub applied: String, + pub only: &'static str, +} + #[derive(Diagnostic)] #[diag(attr_parsing_invalid_alignment_value, code = E0589)] pub(crate) struct InvalidAlignmentValue { |
