Skip to content

Commit 9881ee7

Browse files
committed
Move check_target_feature into the attribute parser
Use `TargetFeatureParser` to reject `#[target_feature]` on functions marked as lang items (via `#[lang = "..."]` or `#[panic_handler]`), replacing `check_target_feature` in `rustc_passes`.
1 parent 4429659 commit 9881ee7

9 files changed

Lines changed: 86 additions & 87 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::attributes::AttributeSafety;
1010
use crate::session_diagnostics::{
1111
EmptyExportName, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass,
1212
NullOnObjcSelector, ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
13-
SanitizeInvalidStatic,
13+
SanitizeInvalidStatic, TargetFeatureOnLangItem,
1414
};
1515
use crate::target_checking::Policy::AllowSilent;
1616

@@ -513,26 +513,22 @@ fn parse_tf_attribute(
513513
features
514514
}
515515

516-
pub(crate) struct TargetFeatureParser;
517-
518-
impl CombineAttributeParser for TargetFeatureParser {
519-
type Item = (Symbol, Span);
520-
const PATH: &[Symbol] = &[sym::target_feature];
521-
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
522-
features: items,
523-
attr_span: span,
524-
was_forced: false,
525-
};
526-
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
527-
const STABILITY: AttributeStability = AttributeStability::Stable;
528-
529-
fn extend(
530-
cx: &mut AcceptContext<'_, '_>,
531-
args: &ArgParser,
532-
) -> impl IntoIterator<Item = Self::Item> {
533-
parse_tf_attribute(cx, args)
534-
}
516+
#[derive(Default)]
517+
pub(crate) struct TargetFeatureParser {
518+
features: ThinVec<(Symbol, Span)>,
519+
first_span: Option<Span>,
520+
}
535521

522+
impl AttributeParser for TargetFeatureParser {
523+
const ATTRIBUTES: AcceptMapping<Self> = &[(
524+
&[sym::target_feature],
525+
template!(List: &["enable = \"feat1, feat2\""]),
526+
AttributeStability::Stable,
527+
|this, cx, args| {
528+
this.first_span.get_or_insert(cx.attr_span);
529+
this.features.extend(parse_tf_attribute(cx, args));
530+
},
531+
)];
536532
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
537533
Allow(Target::Fn),
538534
Allow(Target::Method(MethodKind::Inherent)),
@@ -544,6 +540,38 @@ impl CombineAttributeParser for TargetFeatureParser {
544540
Warn(Target::MacroDef),
545541
Warn(Target::MacroCall),
546542
]);
543+
544+
fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
545+
let first_span = self.first_span?;
546+
547+
// `#[target_feature]` is incompatible with lang item functions,
548+
// except on WASM where calling target-feature functions is safe (see #84988).
549+
if matches!(
550+
cx.target,
551+
Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
552+
) && !cx.sess().target.is_like_wasm
553+
&& !cx.sess().opts.actually_rustdoc
554+
{
555+
// `#[panic_handler]` is checked first so it takes priority in the diagnostic.
556+
let lang_kind = cx
557+
.all_attrs
558+
.iter()
559+
.find_map(|a| [sym::panic_handler, sym::lang].into_iter().find(|&s| a.word_is(s)));
560+
if let Some(kind) = lang_kind {
561+
cx.emit_err(TargetFeatureOnLangItem {
562+
attr_span: first_span,
563+
kind,
564+
item_span: cx.target_span,
565+
});
566+
}
567+
}
568+
569+
Some(AttributeKind::TargetFeature {
570+
features: self.features,
571+
attr_span: first_span,
572+
was_forced: false,
573+
})
574+
}
547575
}
548576

549577
pub(crate) struct ForceTargetFeatureParser;

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,9 @@ attribute_parsers!(
172172
Combine<RustcDumpLayoutParser>,
173173
Combine<RustcMirParser>,
174174
Combine<RustcThenThisWouldNeedParser>,
175-
Combine<TargetFeatureParser>,
176175
Combine<UnstableFeatureBoundParser>,
177176
Combine<UnstableRemovedParser>,
177+
TargetFeatureParser,
178178
// tidy-alphabetical-end
179179

180180
// tidy-alphabetical-start

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,26 @@ pub(crate) struct DocAttributeNotAttribute {
7373
pub attribute: Symbol,
7474
}
7575

76+
#[derive(Diagnostic)]
77+
#[diag(
78+
"`#[target_feature]` cannot be applied to a {$kind ->
79+
[panic_handler] `#[panic_handler]`
80+
*[other] lang item
81+
} function"
82+
)]
83+
pub(crate) struct TargetFeatureOnLangItem {
84+
#[primary_span]
85+
pub attr_span: Span,
86+
pub kind: Symbol,
87+
#[label(
88+
"{$kind ->
89+
[panic_handler] `#[panic_handler]`
90+
*[other] lang item
91+
} function is not allowed to have `#[target_feature]`"
92+
)]
93+
pub item_span: Span,
94+
}
95+
7696
#[derive(Diagnostic)]
7797
#[diag("missing 'since'", code = E0542)]
7898
pub(crate) struct MissingSince {

compiler/rustc_passes/src/check_attr.rs

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
203203
AttributeKind::Deprecated { span: attr_span, .. } => {
204204
self.check_deprecated(hir_id, *attr_span, target)
205205
}
206-
AttributeKind::TargetFeature { attr_span, .. } => {
207-
self.check_target_feature(hir_id, *attr_span, target, attrs)
208-
}
209206
AttributeKind::RustcDumpObjectLifetimeDefaults => {
210207
self.check_dump_object_lifetime_defaults(hir_id);
211208
}
@@ -405,6 +402,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
405402
AttributeKind::ShouldPanic { .. } => (),
406403
AttributeKind::Splat(..) => (),
407404
AttributeKind::Stability { .. } => (),
405+
AttributeKind::TargetFeature { .. } => {}
408406
AttributeKind::TestRunner(..) => (),
409407
AttributeKind::ThreadLocal => (),
410408
AttributeKind::TypeLengthLimit { .. } => (),
@@ -798,37 +796,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
798796
}
799797
}
800798

801-
/// Checks if the `#[target_feature]` attribute on `item` is valid.
802-
fn check_target_feature(
803-
&self,
804-
hir_id: HirId,
805-
attr_span: Span,
806-
target: Target,
807-
attrs: &[Attribute],
808-
) {
809-
match target {
810-
Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
811-
| Target::Fn => {
812-
// `#[target_feature]` is not allowed in lang items.
813-
if let Some(lang_item) = find_attr!(attrs, Lang(lang ) => lang)
814-
// Calling functions with `#[target_feature]` is
815-
// not unsafe on WASM, see #84988
816-
&& !self.tcx.sess.target.is_like_wasm
817-
&& !self.tcx.sess.opts.actually_rustdoc
818-
{
819-
let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
820-
821-
self.dcx().emit_err(diagnostics::LangItemWithTargetFeature {
822-
attr_span,
823-
name: lang_item.name(),
824-
sig_span: sig.span,
825-
});
826-
}
827-
}
828-
_ => {}
829-
}
830-
}
831-
832799
fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) {
833800
if let Some(location) = match target {
834801
Target::AssocTy => {

compiler/rustc_passes/src/diagnostics.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -378,26 +378,6 @@ pub(crate) struct LangItemWithTrackCaller {
378378
pub sig_span: Span,
379379
}
380380

381-
#[derive(Diagnostic)]
382-
#[diag(
383-
"{$name ->
384-
[panic_impl] `#[panic_handler]`
385-
*[other] `{$name}` lang item
386-
} function is not allowed to have `#[target_feature]`"
387-
)]
388-
pub(crate) struct LangItemWithTargetFeature {
389-
#[primary_span]
390-
pub attr_span: Span,
391-
pub name: Symbol,
392-
#[label(
393-
"{$name ->
394-
[panic_impl] `#[panic_handler]`
395-
*[other] `{$name}` lang item
396-
} function is not allowed to have `#[target_feature]`"
397-
)]
398-
pub sig_span: Span,
399-
}
400-
401381
#[derive(Diagnostic)]
402382
#[diag("`{$name}` lang item must be applied to a {$expected_target}", code = E0718)]
403383
pub(crate) struct LangItemOnIncorrectTarget {

tests/ui/lang-items/start_lang_item_with_target_feature.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub trait Sized: MetaSized {}
1818

1919
#[lang = "start"]
2020
#[target_feature(enable = "avx2")]
21-
//~^ ERROR `start` lang item function is not allowed to have `#[target_feature]`
21+
//~^ ERROR #[target_feature]` cannot be applied to a lang item function
2222
fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
2323
0
2424
}
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
error: `start` lang item function is not allowed to have `#[target_feature]`
1+
error: `#[target_feature]` cannot be applied to a lang item function
22
--> $DIR/start_lang_item_with_target_feature.rs:20:1
33
|
4-
LL | #[target_feature(enable = "avx2")]
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | #[target_feature(enable = "avx2")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
LL |
7-
LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
8-
| ------------------------------------------------------------------------------------------- `start` lang item function is not allowed to have `#[target_feature]`
7+
LL | / fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
8+
LL | | 0
9+
LL | | }
10+
| |_- lang item function is not allowed to have `#[target_feature]`
911

1012
error: aborting due to 1 previous error
1113

tests/ui/panic-handler/panic-handler-with-target-feature.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use core::panic::PanicInfo;
88

99
#[panic_handler]
1010
#[target_feature(enable = "avx2")]
11-
//~^ ERROR `#[panic_handler]` function is not allowed to have `#[target_feature]`
11+
//~^ ERROR `#[target_feature]` cannot be applied to a `#[panic_handler]` function
1212
fn panic(info: &PanicInfo) -> ! {
1313
unimplemented!();
1414
}
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
error: `#[panic_handler]` function is not allowed to have `#[target_feature]`
1+
error: `#[target_feature]` cannot be applied to a `#[panic_handler]` function
22
--> $DIR/panic-handler-with-target-feature.rs:10:1
33
|
4-
LL | #[target_feature(enable = "avx2")]
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | #[target_feature(enable = "avx2")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
LL |
7-
LL | fn panic(info: &PanicInfo) -> ! {
8-
| ------------------------------- `#[panic_handler]` function is not allowed to have `#[target_feature]`
7+
LL | / fn panic(info: &PanicInfo) -> ! {
8+
LL | | unimplemented!();
9+
LL | | }
10+
| |_- `#[panic_handler]` function is not allowed to have `#[target_feature]`
911

1012
error: aborting due to 1 previous error
1113

0 commit comments

Comments
 (0)