Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 135 additions & 104 deletions compiler/rustc_attr_parsing/src/attributes/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
))
}
}
3 changes: 1 addition & 2 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ attribute_parsers!(
ConfusablesParser,
ConstStabilityParser,
DocParser,
InlineParser,
LintParser,
MacroUseParser,
NakedParser,
Expand Down Expand Up @@ -213,7 +214,6 @@ attribute_parsers!(
Single<DoNotRecommendParser>,
Single<ExportNameParser>,
Single<IgnoreParser>,
Single<InlineParser>,
Single<InstructionSetParser>,
Single<InstrumentFnParser>,
Single<LangParser>,
Expand Down Expand Up @@ -243,7 +243,6 @@ attribute_parsers!(
Single<RustcDummyParser>,
Single<RustcDumpDefPathParser>,
Single<RustcDumpSymbolNameParser>,
Single<RustcForceInlineParser>,
Single<RustcIfThisChangedParser>,
Single<RustcLegacyConstGenericsParser>,
Single<RustcLintOptDenyFieldAccessParser>,
Expand Down
36 changes: 18 additions & 18 deletions tests/ui/attributes/attribute-on-wrong-item-inline-repr.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand All @@ -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
|
Expand Down Expand Up @@ -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
|
Expand All @@ -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
|
Expand Down
Loading