rust-lang/rust · #164648
parse inline and rustc_force_inline with same parser
compiler/rustc_attr_parsing/src/attributes/inline.rs135 + / 104 −
@@ -3,125 +3,156 @@ use rustc_feature::AttributeStability; use rustc_lint_defs::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNUSED_ATTRIBUTES}; use super::prelude::*;-use crate::diagnostics::{InlineForceInlineConflict, InlineIgnoredForExported};+use crate::diagnostics::{InlineForceInlineConflict, InlineIgnoredForExported, UnusedMultiple}; -pub(crate) struct InlineParser;+#[derive(Default)]+pub(crate) struct InlineParser(Option<(InlineAttr, Span)>); -impl SingleAttributeParser for InlineParser {- const PATH: &[Symbol] = &[sym::inline];- const ON_DUPLICATE: OnDuplicate = 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(AssocCtxt::Impl { of_trait: false })),- Warn(Target::AssocConst(AssocCtxt::Trait)),- Warn(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),- Warn(Target::MacroCall),- ]);- const TEMPLATE: AttributeTemplate = template!(- Word,- List: &["always", "never"],- "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"- );- const STABILITY: AttributeStability = AttributeStability::Stable;+impl AttributeParser for InlineParser {+ const ATTRIBUTES: AcceptMapping<Self> = &[+ (+ &[sym::inline],+ template!(+ Word,+ List: &["always", "never"],+ "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"+ ),+ AttributeStability::Stable,+ |this, cx, args| {+ cx.check_target(+ "",+ &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(AssocCtxt::Impl { of_trait: false })),+ Warn(Target::AssocConst(AssocCtxt::Trait)),+ Warn(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),+ Warn(Target::MacroCall),+ ]),+ ); - fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {- match args {- ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),- ArgParser::List(list) => {- let l = cx.expect_single(list)?;+ let inline_span = cx.attr_span;+ let attr = match args {+ ArgParser::NoArgs => InlineAttr::Hint,+ ArgParser::List(list) => {+ let Some(l) = cx.expect_single(list) else { return }; - match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {- Some(sym::always) => {- Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))+ match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {+ Some(sym::always) => InlineAttr::Always,+ Some(sym::never) => InlineAttr::Never,+ _ => {+ cx.adcx().expected_specific_argument(+ l.span(),+ &[sym::always, sym::never],+ );+ return;+ }+ } }- Some(sym::never) => {- Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))+ ArgParser::NameValue(_) => {+ cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);+ return; }- _ => {- cx.adcx().expected_specific_argument(l.span(), &[sym::always, sym::never]);- None+ };++ match this.0 {+ None => this.0 = Some((attr, inline_span)),+ Some((InlineAttr::Force { .. }, force_inline_span)) => {+ cx.emit_err(InlineForceInlineConflict { inline_span, force_inline_span });+ }+ Some((_, first_inline_span)) => {+ cx.warn_unused_duplicate_future_error(first_inline_span, inline_span); } }- }- ArgParser::NameValue(_) => {- cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);- None- }- }- }+ },+ ),+ (+ &[sym::rustc_force_inline],+ template!(Word, List: &["reason"], NameValueStr: "reason"),+ unstable!(+ rustc_attrs,+ "the `rustc_force_inline` attribute forces a free function to be inlined"+ ),+ |this, cx, args| {+ cx.check_target(+ "",+ &AllowedTargets::AllowList(&[+ Allow(Target::Fn),+ Allow(Target::Method(MethodKind::Inherent)),+ ]),+ );+ let force_inline_span = cx.attr_span;+ let reason = match args {+ ArgParser::NoArgs => None,+ ArgParser::List(list) => {+ let Some(l) = cx.expect_single(list) else { return }; - fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {- let exported = cx.parsed_attrs.iter().any(|attr| {- let Attribute::Parsed(kind) = attr else { return false };- kind.is_extern_indicator()- });- if matches!(- cx.target,- Target::Fn- | Target::Closure- | Target::Method(- MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent,- )- ) && !find_attr!(cx.parsed_attrs, Inline(InlineAttr::Never, _))- && exported- {- cx.emit_lint(UNUSED_ATTRIBUTES, InlineIgnoredForExported, attr_span);- }- }-}--pub(crate) struct RustcForceInlineParser;+ let Some(reason) = cx.expect_string_literal(l) else { return }; -impl SingleAttributeParser for RustcForceInlineParser {- const PATH: &[Symbol] = &[sym::rustc_force_inline];- const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[- Allow(Target::Fn),- Allow(Target::Method(MethodKind::Inherent)),- ]);- const STABILITY: AttributeStability = unstable!(- rustc_attrs,- "the `rustc_force_inline` attribute forces a free function to be inlined"- );- const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");+ Some(reason)+ }+ ArgParser::NameValue(v) => cx.expect_string_literal(v),+ }; - fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {- let reason = match args {- ArgParser::NoArgs => None,- ArgParser::List(list) => {- let l = cx.expect_single(list)?;+ let attr = InlineAttr::Force { attr_span: cx.attr_span, reason }; - let reason = cx.expect_string_literal(l)?;+ match this.0 {+ None => this.0 = Some((attr, force_inline_span)),+ Some((InlineAttr::Force { .. }, first_force_inline_span)) => {+ cx.emit_err(UnusedMultiple {+ this: force_inline_span,+ other: first_force_inline_span,+ name: sym::rustc_force_inline,+ });+ }+ Some((_, inline_span)) => {+ cx.emit_err(InlineForceInlineConflict { inline_span, force_inline_span });+ }+ }+ },+ ),+ ]; - Some(reason)- }- ArgParser::NameValue(v) => cx.expect_string_literal(v),- };+ const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::ManuallyChecked; - Some(AttributeKind::Inline(- InlineAttr::Force { attr_span: cx.attr_span, reason },- cx.attr_span,- ))+ fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {+ self.0.map(|(a, s)| AttributeKind::Inline(a, s)) } - fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {- let Some(inline_span) = find_attr!(cx.parsed_attrs, Inline(attr, span) if !matches!(attr, InlineAttr::Force { .. }) => span)- else {- return;- };-- cx.emit_err(InlineForceInlineConflict {- inline_span: *inline_span,- force_inline_span: attr_span,- });+ fn deferred_finalize_check(+ &self,+ ) -> Option<(fn(&mut FinalizeCheckContext<'_, '_>, Span), Span)> {+ Some((+ |cx: &mut FinalizeCheckContext<'_, '_>, span| {+ let exported = cx.parsed_attrs.iter().any(|attr| {+ let Attribute::Parsed(kind) = attr else { return false };+ kind.is_extern_indicator()+ });+ if matches!(+ cx.target,+ Target::Fn+ | Target::Closure+ | Target::Method(+ MethodKind::Trait { body: true }+ | MethodKind::TraitImpl+ | MethodKind::Inherent,+ )+ ) && !find_attr!(cx.parsed_attrs, Inline(InlineAttr::Never, _))+ && exported+ {+ cx.emit_lint(UNUSED_ATTRIBUTES, InlineIgnoredForExported, span);+ }+ },+ self.0?.1,+ )) } }compiler/rustc_attr_parsing/src/context.rs1 + / 2 −
@@ -167,6 +167,7 @@ attribute_parsers!( ConfusablesParser, ConstStabilityParser, DocParser,+ InlineParser, LintParser, MacroUseParser, NakedParser,@@ -213,7 +214,6 @@ attribute_parsers!( Single<DoNotRecommendParser>, Single<ExportNameParser>, Single<IgnoreParser>,- Single<InlineParser>, Single<InstructionSetParser>, Single<InstrumentFnParser>, Single<LangParser>,@@ -243,7 +243,6 @@ attribute_parsers!( Single<RustcDummyParser>, Single<RustcDumpDefPathParser>, Single<RustcDumpSymbolNameParser>,- Single<RustcForceInlineParser>, Single<RustcIfThisChangedParser>, Single<RustcLegacyConstGenericsParser>, Single<RustcLintOptDenyFieldAccessParser>,tests/ui/attributes/attribute-on-wrong-item-inline-repr.stderr18 + / 18 −
@@ -7,6 +7,15 @@ LL | let _a = 4; | = help: the `inline` attribute can only be applied to functions +error: the `inline` attribute cannot be used on statements+ --> $DIR/attribute-on-wrong-item-inline-repr.rs:12:7+ |+LL | #[inline(XYZ)]+ | ^^^^^^+LL | let _b = 4;+ |+ = help: the `inline` attribute can only be applied to functions+ error[E0539]: malformed `inline` attribute input --> $DIR/attribute-on-wrong-item-inline-repr.rs:12:7 |@@ -28,15 +37,6 @@ LL - #[inline(XYZ)] LL + #[inline(never)] | -error: the `inline` attribute cannot be used on statements- --> $DIR/attribute-on-wrong-item-inline-repr.rs:12:7- |-LL | #[inline(XYZ)]- | ^^^^^^-LL | let _b = 4;- |- = help: the `inline` attribute can only be applied to functions- error[E0539]: malformed `repr` attribute input --> $DIR/attribute-on-wrong-item-inline-repr.rs:17:7 |@@ -65,6 +65,15 @@ LL | #[repr] | = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations> +error: the `inline` attribute cannot be used on expressions+ --> $DIR/attribute-on-wrong-item-inline-repr.rs:33:7+ |+LL | #[inline(ABC)]+ | ^^^^^^+LL | foo();+ |+ = help: the `inline` attribute can only be applied to functions+ error[E0539]: malformed `inline` attribute input --> $DIR/attribute-on-wrong-item-inline-repr.rs:33:7 |@@ -86,15 +95,6 @@ LL - #[inline(ABC)] LL + #[inline(never)] | -error: the `inline` attribute cannot be used on expressions- --> $DIR/attribute-on-wrong-item-inline-repr.rs:33:7- |-LL | #[inline(ABC)]- | ^^^^^^-LL | foo();- |- = help: the `inline` attribute can only be applied to functions- error[E0539]: malformed `repr` attribute input --> $DIR/attribute-on-wrong-item-inline-repr.rs:38:16 |