hir: Disallow target_feature
on constants
This commit fixes an ICE when `target_feature` is applied to constants. Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
parent
37538aa136
commit
e79036d17f
8 changed files with 204 additions and 71 deletions
|
@ -93,30 +93,35 @@ struct CheckAttrVisitor<'tcx> {
|
||||||
impl CheckAttrVisitor<'tcx> {
|
impl CheckAttrVisitor<'tcx> {
|
||||||
/// Checks any attribute.
|
/// Checks any attribute.
|
||||||
fn check_attributes(&self, item: &hir::Item, target: Target) {
|
fn check_attributes(&self, item: &hir::Item, target: Target) {
|
||||||
if target == Target::Fn || target == Target::Const {
|
let mut is_valid = true;
|
||||||
self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id));
|
|
||||||
} else if let Some(a) = item.attrs.iter().find(|a| a.check_name(sym::target_feature)) {
|
|
||||||
self.tcx.sess.struct_span_err(a.span, "attribute should be applied to a function")
|
|
||||||
.span_label(item.span, "not a function")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
for attr in &item.attrs {
|
for attr in &item.attrs {
|
||||||
if attr.check_name(sym::inline) {
|
is_valid &= if attr.check_name(sym::inline) {
|
||||||
self.check_inline(attr, &item.span, target)
|
self.check_inline(attr, &item.span, target)
|
||||||
} else if attr.check_name(sym::non_exhaustive) {
|
} else if attr.check_name(sym::non_exhaustive) {
|
||||||
self.check_non_exhaustive(attr, item, target)
|
self.check_non_exhaustive(attr, item, target)
|
||||||
} else if attr.check_name(sym::marker) {
|
} else if attr.check_name(sym::marker) {
|
||||||
self.check_marker(attr, item, target)
|
self.check_marker(attr, item, target)
|
||||||
}
|
} else if attr.check_name(sym::target_feature) {
|
||||||
|
self.check_target_feature(attr, item, target)
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if !is_valid {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if target == Target::Fn || target == Target::Const {
|
||||||
|
self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_repr(item, target);
|
self.check_repr(item, target);
|
||||||
self.check_used(item, target);
|
self.check_used(item, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if an `#[inline]` is applied to a function or a closure.
|
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
|
||||||
fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) {
|
fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) -> bool {
|
||||||
if target != Target::Fn && target != Target::Closure {
|
if target != Target::Fn && target != Target::Closure {
|
||||||
struct_span_err!(self.tcx.sess,
|
struct_span_err!(self.tcx.sess,
|
||||||
attr.span,
|
attr.span,
|
||||||
|
@ -124,13 +129,21 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
"attribute should be applied to function or closure")
|
"attribute should be applied to function or closure")
|
||||||
.span_label(*span, "not a function or closure")
|
.span_label(*span, "not a function or closure")
|
||||||
.emit();
|
.emit();
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid.
|
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
|
||||||
fn check_non_exhaustive(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) {
|
fn check_non_exhaustive(
|
||||||
|
&self,
|
||||||
|
attr: &hir::Attribute,
|
||||||
|
item: &hir::Item,
|
||||||
|
target: Target,
|
||||||
|
) -> bool {
|
||||||
match target {
|
match target {
|
||||||
Target::Struct | Target::Enum => { /* Valid */ },
|
Target::Struct | Target::Enum => true,
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(self.tcx.sess,
|
struct_span_err!(self.tcx.sess,
|
||||||
attr.span,
|
attr.span,
|
||||||
|
@ -138,25 +151,44 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
"attribute can only be applied to a struct or enum")
|
"attribute can only be applied to a struct or enum")
|
||||||
.span_label(item.span, "not a struct or enum")
|
.span_label(item.span, "not a struct or enum")
|
||||||
.emit();
|
.emit();
|
||||||
return;
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the `#[marker]` attribute on an `item` is valid.
|
/// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
|
||||||
fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) {
|
fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
|
||||||
match target {
|
match target {
|
||||||
Target::Trait => { /* Valid */ },
|
Target::Trait => true,
|
||||||
_ => {
|
_ => {
|
||||||
self.tcx.sess
|
self.tcx.sess
|
||||||
.struct_span_err(attr.span, "attribute can only be applied to a trait")
|
.struct_span_err(attr.span, "attribute can only be applied to a trait")
|
||||||
.span_label(item.span, "not a trait")
|
.span_label(item.span, "not a trait")
|
||||||
.emit();
|
.emit();
|
||||||
return;
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid.
|
||||||
|
fn check_target_feature(
|
||||||
|
&self,
|
||||||
|
attr: &hir::Attribute,
|
||||||
|
item: &hir::Item,
|
||||||
|
target: Target,
|
||||||
|
) -> bool {
|
||||||
|
match target {
|
||||||
|
Target::Fn => true,
|
||||||
|
_ => {
|
||||||
|
self.tcx.sess
|
||||||
|
.struct_span_err(attr.span, "attribute should be applied to a function")
|
||||||
|
.span_label(item.span, "not a function")
|
||||||
|
.emit();
|
||||||
|
false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if the `#[repr]` attributes on `item` are valid.
|
/// Checks if the `#[repr]` attributes on `item` are valid.
|
||||||
fn check_repr(&self, item: &hir::Item, target: Target) {
|
fn check_repr(&self, item: &hir::Item, target: Target) {
|
||||||
// Extract the names of all repr hints, e.g., [foo, bar, align] for:
|
// Extract the names of all repr hints, e.g., [foo, bar, align] for:
|
||||||
|
|
10
src/test/ui/attributes/multiple-invalid.rs
Normal file
10
src/test/ui/attributes/multiple-invalid.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// This test checks that all expected errors occur when there are multiple invalid attributes
|
||||||
|
// on an item.
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
//~^ ERROR attribute should be applied to function or closure [E0518]
|
||||||
|
#[target_feature(enable = "sse2")]
|
||||||
|
//~^ ERROR attribute should be applied to a function
|
||||||
|
const FOO: u8 = 0;
|
||||||
|
|
||||||
|
fn main() { }
|
21
src/test/ui/attributes/multiple-invalid.stderr
Normal file
21
src/test/ui/attributes/multiple-invalid.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0518]: attribute should be applied to function or closure
|
||||||
|
--> $DIR/multiple-invalid.rs:4:1
|
||||||
|
|
|
||||||
|
LL | #[inline]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | const FOO: u8 = 0;
|
||||||
|
| ------------------ not a function or closure
|
||||||
|
|
||||||
|
error: attribute should be applied to a function
|
||||||
|
--> $DIR/multiple-invalid.rs:6:1
|
||||||
|
|
|
||||||
|
LL | #[target_feature(enable = "sse2")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | const FOO: u8 = 0;
|
||||||
|
| ------------------ not a function
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0518`.
|
|
@ -1,50 +0,0 @@
|
||||||
error: malformed `target_feature` attribute input
|
|
||||||
--> $DIR/target-feature-wrong.rs:16:1
|
|
||||||
|
|
|
||||||
LL | #[target_feature = "+sse2"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
|
|
||||||
|
|
||||||
error: the feature named `foo` is not valid for this target
|
|
||||||
--> $DIR/target-feature-wrong.rs:18:18
|
|
||||||
|
|
|
||||||
LL | #[target_feature(enable = "foo")]
|
|
||||||
| ^^^^^^^^^^^^^^ `foo` is not valid for this target
|
|
||||||
|
|
||||||
error: malformed `target_feature` attribute input
|
|
||||||
--> $DIR/target-feature-wrong.rs:21:18
|
|
||||||
|
|
|
||||||
LL | #[target_feature(bar)]
|
|
||||||
| ^^^ help: must be of the form: `enable = ".."`
|
|
||||||
|
|
||||||
error: malformed `target_feature` attribute input
|
|
||||||
--> $DIR/target-feature-wrong.rs:23:18
|
|
||||||
|
|
|
||||||
LL | #[target_feature(disable = "baz")]
|
|
||||||
| ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
|
|
||||||
|
|
||||||
error: `#[target_feature(..)]` can only be applied to `unsafe` functions
|
|
||||||
--> $DIR/target-feature-wrong.rs:27:1
|
|
||||||
|
|
|
||||||
LL | #[target_feature(enable = "sse2")]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions
|
|
||||||
...
|
|
||||||
LL | fn bar() {}
|
|
||||||
| ----------- not an `unsafe` function
|
|
||||||
|
|
||||||
error: attribute should be applied to a function
|
|
||||||
--> $DIR/target-feature-wrong.rs:33:1
|
|
||||||
|
|
|
||||||
LL | #[target_feature(enable = "sse2")]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
LL |
|
|
||||||
LL | mod another {}
|
|
||||||
| -------------- not a function
|
|
||||||
|
|
||||||
error: cannot use `#[inline(always)]` with `#[target_feature]`
|
|
||||||
--> $DIR/target-feature-wrong.rs:38:1
|
|
||||||
|
|
|
||||||
LL | #[inline(always)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0658]: the target feature `avx512bw` is currently unstable
|
error[E0658]: the target feature `avx512bw` is currently unstable
|
||||||
--> $DIR/target-feature-gate.rs:30:18
|
--> $DIR/gate.rs:30:18
|
||||||
|
|
|
|
||||||
LL | #[target_feature(enable = "avx512bw")]
|
LL | #[target_feature(enable = "avx512bw")]
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
|
@ -35,6 +35,31 @@ fn bar() {}
|
||||||
mod another {}
|
mod another {}
|
||||||
//~^ NOTE not a function
|
//~^ NOTE not a function
|
||||||
|
|
||||||
|
#[target_feature(enable = "sse2")]
|
||||||
|
//~^ ERROR attribute should be applied to a function
|
||||||
|
const FOO: usize = 7;
|
||||||
|
//~^ NOTE not a function
|
||||||
|
|
||||||
|
#[target_feature(enable = "sse2")]
|
||||||
|
//~^ ERROR attribute should be applied to a function
|
||||||
|
struct Foo;
|
||||||
|
//~^ NOTE not a function
|
||||||
|
|
||||||
|
#[target_feature(enable = "sse2")]
|
||||||
|
//~^ ERROR attribute should be applied to a function
|
||||||
|
enum Bar { }
|
||||||
|
//~^ NOTE not a function
|
||||||
|
|
||||||
|
#[target_feature(enable = "sse2")]
|
||||||
|
//~^ ERROR attribute should be applied to a function
|
||||||
|
union Qux { f1: u16, f2: u16 }
|
||||||
|
//~^ NOTE not a function
|
||||||
|
|
||||||
|
#[target_feature(enable = "sse2")]
|
||||||
|
//~^ ERROR attribute should be applied to a function
|
||||||
|
trait Baz { }
|
||||||
|
//~^ NOTE not a function
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
//~^ ERROR: cannot use `#[inline(always)]`
|
//~^ ERROR: cannot use `#[inline(always)]`
|
||||||
#[target_feature(enable = "sse2")]
|
#[target_feature(enable = "sse2")]
|
95
src/test/ui/target-feature/invalid-attribute.stderr
Normal file
95
src/test/ui/target-feature/invalid-attribute.stderr
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
error: malformed `target_feature` attribute input
|
||||||
|
--> $DIR/invalid-attribute.rs:16:1
|
||||||
|
|
|
||||||
|
LL | #[target_feature = "+sse2"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
|
||||||
|
|
||||||
|
error: the feature named `foo` is not valid for this target
|
||||||
|
--> $DIR/invalid-attribute.rs:18:18
|
||||||
|
|
|
||||||
|
LL | #[target_feature(enable = "foo")]
|
||||||
|
| ^^^^^^^^^^^^^^ `foo` is not valid for this target
|
||||||
|
|
||||||
|
error: malformed `target_feature` attribute input
|
||||||
|
--> $DIR/invalid-attribute.rs:21:18
|
||||||
|
|
|
||||||
|
LL | #[target_feature(bar)]
|
||||||
|
| ^^^ help: must be of the form: `enable = ".."`
|
||||||
|
|
||||||
|
error: malformed `target_feature` attribute input
|
||||||
|
--> $DIR/invalid-attribute.rs:23:18
|
||||||
|
|
|
||||||
|
LL | #[target_feature(disable = "baz")]
|
||||||
|
| ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
|
||||||
|
|
||||||
|
error: `#[target_feature(..)]` can only be applied to `unsafe` functions
|
||||||
|
--> $DIR/invalid-attribute.rs:27:1
|
||||||
|
|
|
||||||
|
LL | #[target_feature(enable = "sse2")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions
|
||||||
|
...
|
||||||
|
LL | fn bar() {}
|
||||||
|
| ----------- not an `unsafe` function
|
||||||
|
|
||||||
|
error: attribute should be applied to a function
|
||||||
|
--> $DIR/invalid-attribute.rs:33:1
|
||||||
|
|
|
||||||
|
LL | #[target_feature(enable = "sse2")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | mod another {}
|
||||||
|
| -------------- not a function
|
||||||
|
|
||||||
|
error: attribute should be applied to a function
|
||||||
|
--> $DIR/invalid-attribute.rs:38:1
|
||||||
|
|
|
||||||
|
LL | #[target_feature(enable = "sse2")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | const FOO: usize = 7;
|
||||||
|
| --------------------- not a function
|
||||||
|
|
||||||
|
error: attribute should be applied to a function
|
||||||
|
--> $DIR/invalid-attribute.rs:43:1
|
||||||
|
|
|
||||||
|
LL | #[target_feature(enable = "sse2")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | struct Foo;
|
||||||
|
| ----------- not a function
|
||||||
|
|
||||||
|
error: attribute should be applied to a function
|
||||||
|
--> $DIR/invalid-attribute.rs:48:1
|
||||||
|
|
|
||||||
|
LL | #[target_feature(enable = "sse2")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | enum Bar { }
|
||||||
|
| ------------ not a function
|
||||||
|
|
||||||
|
error: attribute should be applied to a function
|
||||||
|
--> $DIR/invalid-attribute.rs:53:1
|
||||||
|
|
|
||||||
|
LL | #[target_feature(enable = "sse2")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | union Qux { f1: u16, f2: u16 }
|
||||||
|
| ------------------------------ not a function
|
||||||
|
|
||||||
|
error: attribute should be applied to a function
|
||||||
|
--> $DIR/invalid-attribute.rs:58:1
|
||||||
|
|
|
||||||
|
LL | #[target_feature(enable = "sse2")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | trait Baz { }
|
||||||
|
| ------------- not a function
|
||||||
|
|
||||||
|
error: cannot use `#[inline(always)]` with `#[target_feature]`
|
||||||
|
--> $DIR/invalid-attribute.rs:63:1
|
||||||
|
|
|
||||||
|
LL | #[inline(always)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 12 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue