Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit an error for invalid item of instruction_set #129002

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
37 changes: 14 additions & 23 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,42 +376,33 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
Some(InstructionSetAttr::ArmA32)
} else if segments[1] == sym::t32 {
Some(InstructionSetAttr::ArmT32)
} else if segments[1] != sym::a32 || segments[1] != sym::t32 {
struct_span_code_err!(
tcx.dcx(),
attr.span,
E0779,
"`[instruction_set]` attribute argument should be valid"
)
.emit();
None
} else {
unreachable!()
}
}
_ => {
[] => {
struct_span_code_err!(
tcx.dcx(),
attr.span,
E0779,
"invalid instruction set specified",
E0778,
"`[instruction_set]` requires an argument"
)
.emit();
None
}
_ => None,
}
}
[] => {
struct_span_code_err!(
tcx.dcx(),
attr.span,
E0778,
"`#[instruction_set]` requires an argument"
)
.emit();
None
}
_ => {
struct_span_code_err!(
tcx.dcx(),
attr.span,
E0779,
"cannot specify more than one instruction set"
)
.emit();
None
}
_ => None,
})
}
sym::repr => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0778.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Erroneous code example:
```compile_fail,E0778
#![feature(isa_attribute)]

#[instruction_set()] // error: expected one argument
#[instruction_set()] // error: `[instruction_set]` requires an argument
pub fn something() {}
fn main() {}
```
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0779.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Erroneous code example:
```compile_fail,E0779
#![feature(isa_attribute)]

#[instruction_set(intel::x64)] // error: invalid argument
#[instruction_set(intel::x64)] // error: `[instruction_set]` attribute argument
// should be valid
pub fn something() {}
fn main() {}
```
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ passes_attr_crate_level =
passes_attr_only_in_functions =
`{$attr}` attribute can only be used on functions

passes_attribute_not_allowed =
The `[instruction_set]` attribute contains an invalid argument
.label = Invalid argument in the `[instruction_set]` attribute

passes_autodiff_attr =
`#[autodiff]` should be applied to a function
.label = not a function
Expand Down Expand Up @@ -311,6 +315,10 @@ passes_duplicate_lang_item_crate_depends =
passes_empty_confusables =
expected at least one confusable name

passes_empty_instruction_set =
`[instruction_set]` requires an argument
.label = `[instruction_set]` requires an argument

passes_export_name =
attribute should be applied to a free function, impl method or static
.label = not a free function, impl method or static
Expand Down Expand Up @@ -400,10 +408,18 @@ passes_invalid_attr_at_crate_level =
passes_invalid_attr_at_crate_level_item =
the inner attribute doesn't annotate this {$kind}

passes_invalid_instruction_set =
`[instruction_set]` attribute argument should be valid
.label = `[instruction_set]` containes invalid argument

passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument

passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments

passes_invalid_target_for_instruction_set =
The `[instruction_set]` attribute is only allowed on functions
.label = Invalid target for the `[instruction_set]` attribute

passes_lang_item_fn = {$name ->
[panic_impl] `#[panic_handler]`
*[other] `{$name}` lang item
Expand Down
80 changes: 78 additions & 2 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use std::cell::Cell;
use std::collections::hash_map::Entry;

use rustc_ast::token::TokenKind;
use rustc_ast::tokenstream::TokenTree;
use rustc_ast::{
AttrKind, AttrStyle, Attribute, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast,
};
Expand All @@ -16,7 +18,7 @@ use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, B
use rustc_hir::def_id::LocalModDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{
self as hir, self, AssocItemKind, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId,
self, self as hir, AssocItemKind, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId,
Item, ItemKind, MethodKind, Safety, Target, TraitItem,
};
use rustc_macros::LintDiagnostic;
Expand Down Expand Up @@ -252,6 +254,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
[sym::linkage, ..] => self.check_linkage(attr, span, target),
[sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent( attr.span, span, attrs),
[sym::instruction_set, ..] => {
self.check_instruction_set(attr, item);
}
[
// ok
sym::allow
Expand All @@ -267,7 +272,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
| sym::used // handled elsewhere to restrict to static items
| sym::repr // handled elsewhere to restrict to type decls items
| sym::instruction_set // broken on stable!!!
| sym::windows_subsystem // broken on stable!!!
| sym::patchable_function_entry // FIXME(patchable_function_entry)
| sym::deprecated_safe // FIXME(deprecated_safe)
Expand Down Expand Up @@ -2404,6 +2408,78 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
}

fn check_instruction_set(&self, attr: &Attribute, item: Option<ItemLike<'_>>) {
// Ensure the attribute is applied to a function or closure
match item {
Some(ItemLike::Item(inner_item)) => match inner_item.kind {
ItemKind::Fn(_, _, _) => {
// Validate the tokens for `instruction_set()` attribute
if let AttrKind::Normal(ref p) = attr.kind {
let inner_tokens = p.item.args.inner_tokens();
let mut tokens = inner_tokens.trees();

match (tokens.next(), tokens.next(), tokens.next()) {
(
Some(TokenTree::Token(first_token, _)),
Some(TokenTree::Token(second_token, _)),
Some(TokenTree::Token(third_token, _)),
) => match (
first_token.ident(),
second_token.kind.clone(),
third_token.ident(),
) {
(Some(first_ident), TokenKind::PathSep, Some(third_ident))
if first_ident.0.name == sym::arm =>
{
if third_ident.0.name == sym::a32
|| third_ident.0.name == sym::t32
{
return;
} else {
self.dcx().emit_err(errors::InvalidInstructionSet {
span: attr.span,
});
}
}
_ => {
self.dcx().emit_err(errors::InvalidInstructionSet {
span: attr.span,
});
}
},
(None, None, None) => {
self.dcx()
.emit_err(errors::EmptyInstructionSet { span: attr.span });
}
_ => {
self.dcx()
.emit_err(errors::InvalidInstructionSet { span: attr.span });
}
};
}
}
_ => {
self.dcx().emit_err(errors::InvalidTargetForInstructionSet {
span: attr.span,
item_kind: inner_item.kind.descr(),
});
return;
}
},
Some(ItemLike::ForeignItem) => {
self.dcx().emit_err(errors::InvalidTargetForInstructionSet {
span: attr.span,
item_kind: "foreign item",
});
return;
}
None => {
self.dcx().emit_err(errors::AttributeNotAllowed { span: attr.span });
return;
}
}
}
}

impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
Expand Down
30 changes: 30 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,36 @@ pub(crate) struct Linkage {
#[primary_span]
pub attr_span: Span,
#[label]
#[label]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(passes_attribute_not_allowed)]
pub(crate) struct AttributeNotAllowed {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(passes_invalid_instruction_set)]
pub(crate) struct InvalidInstructionSet {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(passes_invalid_target_for_instruction_set)]
pub(crate) struct InvalidTargetForInstructionSet {
#[primary_span]
pub span: Span,
pub item_kind: &'static str,
}

#[derive(Diagnostic)]
#[diag(passes_empty_instruction_set)]
pub(crate) struct EmptyInstructionSet {
#[primary_span]
pub span: Span,
}

Expand Down
49 changes: 49 additions & 0 deletions tests/ui/attributes/instruction-set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#![feature(stmt_expr_attributes)]

#[cfg(target_arch = "arm")] // OK
#[instruction_set(arm::a32)]
fn valid_a() {}

#[cfg(target_arch = "arm")] // OK
#[instruction_set(arm::t32)]
fn valid_b() {}

#[cfg(target_arch = "arm")] // OK
struct MyStruct;

#[cfg(target_arch = "arm")]
impl MyStruct {
#[instruction_set(arm::a32)] // OK
fn inherent_method(&self) {}
}

trait MyTrait {
#[cfg(target_arch = "arm")]
#[instruction_set(arm::a32)] // OK
fn trait_method() {
println!("Trait method default implementation");
}
}

struct A;
impl MyTrait for A {
#[cfg(target_arch = "arm")]
#[instruction_set(arm::t32)] // OK
fn trait_method() {
println!("Trait impl method");
}
}

#[instruction_set(asdfasdf)] //~ ERROR The `[instruction_set]` attribute is only allowed on functions
type InvalidA = ();

#[instruction_set(asdfasdf)] //~ ERROR The `[instruction_set]` attribute is only allowed on functions
mod InvalidB {}

#[instruction_set(asdfasdf)] //~ ERROR The `[instruction_set]` attribute is only allowed on functions
struct InvalidC;

#[instruction_set(asdfasdf)] //~ ERROR `[instruction_set]` attribute argument should be valid
fn invalid_d() {}

fn main() {}
26 changes: 26 additions & 0 deletions tests/ui/attributes/instruction-set.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: The `[instruction_set]` attribute is only allowed on functions
--> $DIR/instruction-set.rs:37:1
|
LL | #[instruction_set(asdfasdf)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: The `[instruction_set]` attribute is only allowed on functions
--> $DIR/instruction-set.rs:40:1
|
LL | #[instruction_set(asdfasdf)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: The `[instruction_set]` attribute is only allowed on functions
--> $DIR/instruction-set.rs:43:1
|
LL | #[instruction_set(asdfasdf)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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

error: aborting due to 4 previous errors

Loading
Loading