Skip to content

Commit e12e30b

Browse files
committed
Update the logic based on a RFC
1 parent 2d1fa8c commit e12e30b

File tree

6 files changed

+188
-69
lines changed

6 files changed

+188
-69
lines changed

compiler/rustc_passes/messages.ftl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ passes_attr_crate_level =
4949
passes_attr_only_in_functions =
5050
`{$attr}` attribute can only be used on functions
5151
52+
passes_attribute_not_allowed =
53+
The `[instruction_set]` attribute contains an invalid argument
54+
.label = Invalid argument in the `[instruction_set]` attribute
55+
5256
passes_autodiff_attr =
5357
`#[autodiff]` should be applied to a function
5458
.label = not a function
@@ -409,6 +413,10 @@ passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]
409413
410414
passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
411415
416+
passes_invalid_target_for_instruction_set =
417+
The `[instruction_set]` attribute is only allowed on functions
418+
.label = Invalid target for the `[instruction_set]` attribute
419+
412420
passes_lang_item_fn = {$name ->
413421
[panic_impl] `#[panic_handler]`
414422
*[other] `{$name}` lang item

compiler/rustc_passes/src/check_attr.rs

Lines changed: 100 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ use std::collections::hash_map::Entry;
1010
use rustc_ast::token::TokenKind;
1111
use rustc_ast::tokenstream::TokenTree;
1212
use rustc_ast::{
13-
AttrKind, AttrStyle, Attribute, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast,
13+
ast, AttrKind, AttrStyle, Attribute, LitKind, MetaItemInner, MetaItemKind, MetaItemLit,
1414
};
1515
use rustc_data_structures::fx::FxHashMap;
1616
use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
17-
use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
17+
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
1818
use rustc_hir::def_id::LocalModDefId;
1919
use rustc_hir::intravisit::{self, Visitor};
2020
use rustc_hir::{
21-
self as hir, self, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, Item, ItemKind,
22-
MethodKind, Safety, Target, TraitItem,
21+
self as hir, self, FnSig, ForeignItem, HirId, Item, ItemKind, MethodKind, Safety, Target,
22+
TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
2323
};
2424
use rustc_macros::LintDiagnostic;
2525
use rustc_middle::hir::nested_filter;
@@ -34,8 +34,8 @@ use rustc_session::lint::builtin::{
3434
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
3535
};
3636
use rustc_session::parse::feature_err;
37-
use rustc_span::symbol::{Symbol, kw, sym};
38-
use rustc_span::{BytePos, DUMMY_SP, Span};
37+
use rustc_span::symbol::{kw, sym, Symbol};
38+
use rustc_span::{BytePos, Span, DUMMY_SP};
3939
use rustc_target::abi::Size;
4040
use rustc_target::spec::abi::Abi;
4141
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -349,8 +349,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
349349
}
350350

351351
fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
352-
self.tcx
353-
.emit_node_span_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::IgnoredAttr { sym });
352+
self.tcx.emit_node_span_lint(
353+
UNUSED_ATTRIBUTES,
354+
hir_id,
355+
attr.span,
356+
errors::IgnoredAttr { sym },
357+
);
354358
}
355359

356360
/// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl.
@@ -1394,10 +1398,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
13941398
_ => {
13951399
// FIXME: #[cold] was previously allowed on non-functions and some crates used
13961400
// this, so only emit a warning.
1397-
self.tcx.emit_node_span_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::Cold {
1398-
span,
1399-
on_crate: hir_id == CRATE_HIR_ID,
1400-
});
1401+
self.tcx.emit_node_span_lint(
1402+
UNUSED_ATTRIBUTES,
1403+
hir_id,
1404+
attr.span,
1405+
errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID },
1406+
);
14011407
}
14021408
}
14031409
}
@@ -1412,9 +1418,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
14121418
return;
14131419
}
14141420

1415-
self.tcx.emit_node_span_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::Link {
1416-
span: (target != Target::ForeignMod).then_some(span),
1417-
});
1421+
self.tcx.emit_node_span_lint(
1422+
UNUSED_ATTRIBUTES,
1423+
hir_id,
1424+
attr.span,
1425+
errors::Link { span: (target != Target::ForeignMod).then_some(span) },
1426+
);
14181427
}
14191428

14201429
/// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
@@ -1884,7 +1893,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
18841893
|| (int_reprs == 1
18851894
&& is_c
18861895
&& item.is_some_and(|item| {
1887-
if let ItemLike::Item(item) = item { is_c_like_enum(item) } else { false }
1896+
if let ItemLike::Item(item) = item {
1897+
is_c_like_enum(item)
1898+
} else {
1899+
false
1900+
}
18881901
}))
18891902
{
18901903
self.tcx.emit_node_span_lint(
@@ -2224,10 +2237,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
22242237
return;
22252238
};
22262239

2227-
self.tcx.emit_node_span_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::Unused {
2228-
attr_span: attr.span,
2229-
note,
2230-
});
2240+
self.tcx.emit_node_span_lint(
2241+
UNUSED_ATTRIBUTES,
2242+
hir_id,
2243+
attr.span,
2244+
errors::Unused { attr_span: attr.span, note },
2245+
);
22312246
}
22322247

22332248
/// A best effort attempt to create an error for a mismatching proc macro signature.
@@ -2383,40 +2398,75 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
23832398
}
23842399
}
23852400

2386-
fn check_instruction_set(&self, attr: &Attribute, _item: Option<ItemLike<'_>>) {
2387-
if let AttrKind::Normal(ref p) = attr.kind {
2388-
let inner_tokens = p.item.args.inner_tokens();
2389-
let mut tokens = inner_tokens.trees();
2390-
2391-
// Valid item for `instruction_set()` is:
2392-
// - arm::a32
2393-
// - arm::t32
2394-
match (tokens.next(), tokens.next(), tokens.next()) {
2395-
(
2396-
Some(TokenTree::Token(first_token, _)),
2397-
Some(TokenTree::Token(second_token, _)),
2398-
Some(TokenTree::Token(third_token, _)),
2399-
) => match (first_token.ident(), second_token.kind.clone(), third_token.ident()) {
2400-
(Some(first_ident), TokenKind::PathSep, Some(third_ident))
2401-
if first_ident.0.name == sym::arm =>
2402-
{
2403-
if third_ident.0.name == sym::a32 || third_ident.0.name == sym::t32 {
2404-
return;
2405-
} else {
2406-
self.dcx().emit_err(errors::InvalidInstructionSet { span: attr.span });
2407-
}
2408-
}
2409-
_ => {
2410-
self.dcx().emit_err(errors::InvalidInstructionSet { span: attr.span });
2401+
fn check_instruction_set(&self, attr: &Attribute, item: Option<ItemLike<'_>>) {
2402+
// Ensure the attribute is applied to a function or closure
2403+
match item {
2404+
Some(ItemLike::Item(inner_item)) => match inner_item.kind {
2405+
ItemKind::Fn(_, _, _) => {
2406+
// Validate the tokens for `instruction_set()` attribute
2407+
if let AttrKind::Normal(ref p) = attr.kind {
2408+
let inner_tokens = p.item.args.inner_tokens();
2409+
let mut tokens = inner_tokens.trees();
2410+
2411+
match (tokens.next(), tokens.next(), tokens.next()) {
2412+
(
2413+
Some(TokenTree::Token(first_token, _)),
2414+
Some(TokenTree::Token(second_token, _)),
2415+
Some(TokenTree::Token(third_token, _)),
2416+
) => match (
2417+
first_token.ident(),
2418+
second_token.kind.clone(),
2419+
third_token.ident(),
2420+
) {
2421+
(Some(first_ident), TokenKind::PathSep, Some(third_ident))
2422+
if first_ident.0.name == sym::arm =>
2423+
{
2424+
if third_ident.0.name == sym::a32
2425+
|| third_ident.0.name == sym::t32
2426+
{
2427+
return;
2428+
} else {
2429+
self.dcx().emit_err(errors::InvalidInstructionSet {
2430+
span: attr.span,
2431+
});
2432+
}
2433+
}
2434+
_ => {
2435+
self.dcx().emit_err(errors::InvalidInstructionSet {
2436+
span: attr.span,
2437+
});
2438+
}
2439+
},
2440+
(None, None, None) => {
2441+
self.dcx()
2442+
.emit_err(errors::EmptyInstructionSet { span: attr.span });
2443+
}
2444+
_ => {
2445+
self.dcx()
2446+
.emit_err(errors::InvalidInstructionSet { span: attr.span });
2447+
}
2448+
};
24112449
}
2412-
},
2413-
(None, None, None) => {
2414-
self.dcx().emit_err(errors::EmptyInstructionSet { span: attr.span });
24152450
}
24162451
_ => {
2417-
self.dcx().emit_err(errors::InvalidInstructionSet { span: attr.span });
2452+
self.dcx().emit_err(errors::InvalidTargetForInstructionSet {
2453+
span: attr.span,
2454+
item_kind: inner_item.kind.descr(),
2455+
});
2456+
return;
24182457
}
2419-
};
2458+
},
2459+
Some(ItemLike::ForeignItem) => {
2460+
self.dcx().emit_err(errors::InvalidTargetForInstructionSet {
2461+
span: attr.span,
2462+
item_kind: "foreign item",
2463+
});
2464+
return;
2465+
}
2466+
None => {
2467+
self.dcx().emit_err(errors::AttributeNotAllowed { span: attr.span });
2468+
return;
2469+
}
24202470
}
24212471
}
24222472
}

compiler/rustc_passes/src/errors.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,13 +690,28 @@ pub(crate) struct Linkage {
690690
pub span: Span,
691691
}
692692

693+
#[derive(Diagnostic)]
694+
#[diag(passes_attribute_not_allowed)]
695+
pub(crate) struct AttributeNotAllowed {
696+
#[primary_span]
697+
pub span: Span,
698+
}
699+
693700
#[derive(Diagnostic)]
694701
#[diag(passes_invalid_instruction_set)]
695702
pub(crate) struct InvalidInstructionSet {
696703
#[primary_span]
697704
pub span: Span,
698705
}
699706

707+
#[derive(Diagnostic)]
708+
#[diag(passes_invalid_target_for_instruction_set)]
709+
pub(crate) struct InvalidTargetForInstructionSet {
710+
#[primary_span]
711+
pub span: Span,
712+
pub item_kind: &'static str,
713+
}
714+
700715
#[derive(Diagnostic)]
701716
#[diag(passes_empty_instruction_set)]
702717
pub(crate) struct EmptyInstructionSet {
Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,49 @@
11
#![feature(stmt_expr_attributes)]
22

3+
#[cfg(target_arch = "arm")] // OK
34
#[instruction_set(arm::a32)]
4-
type ValidA = ();
5+
fn valid_a() {}
56

7+
#[cfg(target_arch = "arm")] // OK
68
#[instruction_set(arm::t32)]
7-
type ValidB = ();
9+
fn valid_b() {}
810

9-
#[instruction_set(asdfasdf)] //~ ERROR `[instruction_set]` attribute argument should be valid
11+
#[cfg(target_arch = "arm")] // OK
12+
struct MyStruct;
13+
14+
#[cfg(target_arch = "arm")]
15+
impl MyStruct {
16+
#[instruction_set(arm::a32)] // OK
17+
fn inherent_method(&self) {}
18+
}
19+
20+
trait MyTrait {
21+
#[cfg(target_arch = "arm")]
22+
#[instruction_set(arm::a32)] // OK
23+
fn trait_method() {
24+
println!("Trait method default implementation");
25+
}
26+
}
27+
28+
struct A;
29+
impl MyTrait for A {
30+
#[cfg(target_arch = "arm")]
31+
#[instruction_set(arm::t32)] // OK
32+
fn trait_method() {
33+
println!("Trait impl method");
34+
}
35+
}
36+
37+
#[instruction_set(asdfasdf)] //~ ERROR The `[instruction_set]` attribute is only allowed on functions
1038
type InvalidA = ();
1139

12-
#[instruction_set(asdfasdf)] //~ ERROR `[instruction_set]` attribute argument should be valid
40+
#[instruction_set(asdfasdf)] //~ ERROR The `[instruction_set]` attribute is only allowed on functions
1341
mod InvalidB {}
1442

15-
#[instruction_set(asdfasdf)] //~ ERROR `[instruction_set]` attribute argument should be valid
43+
#[instruction_set(asdfasdf)] //~ ERROR The `[instruction_set]` attribute is only allowed on functions
1644
struct InvalidC;
1745

1846
#[instruction_set(asdfasdf)] //~ ERROR `[instruction_set]` attribute argument should be valid
19-
impl InvalidC {}
47+
fn invalid_d() {}
2048

2149
fn main() {}

tests/ui/attributes/instruction-set.stderr

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
error: `[instruction_set]` attribute argument should be valid
2-
--> $DIR/instruction-set.rs:9:1
1+
error: The `[instruction_set]` attribute is only allowed on functions
2+
--> $DIR/instruction-set.rs:37:1
33
|
44
LL | #[instruction_set(asdfasdf)]
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66

7-
error: `[instruction_set]` attribute argument should be valid
8-
--> $DIR/instruction-set.rs:12:1
7+
error: The `[instruction_set]` attribute is only allowed on functions
8+
--> $DIR/instruction-set.rs:40:1
99
|
1010
LL | #[instruction_set(asdfasdf)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212

13-
error: `[instruction_set]` attribute argument should be valid
14-
--> $DIR/instruction-set.rs:15:1
13+
error: The `[instruction_set]` attribute is only allowed on functions
14+
--> $DIR/instruction-set.rs:43:1
1515
|
1616
LL | #[instruction_set(asdfasdf)]
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1818

1919
error: `[instruction_set]` attribute argument should be valid
20-
--> $DIR/instruction-set.rs:18:1
20+
--> $DIR/instruction-set.rs:46:1
2121
|
2222
LL | #[instruction_set(asdfasdf)]
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)