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

hir: Disallow target_feature on constants #64809

Merged
merged 2 commits into from
Sep 28, 2019
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
72 changes: 52 additions & 20 deletions src/librustc/hir/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,70 +93,102 @@ struct CheckAttrVisitor<'tcx> {
impl CheckAttrVisitor<'tcx> {
/// Checks any attribute.
fn check_attributes(&self, item: &hir::Item, target: Target) {
if target == Target::Fn || target == Target::Const {
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();
}

let mut is_valid = true;
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)
} else if attr.check_name(sym::non_exhaustive) {
self.check_non_exhaustive(attr, item, target)
} else if attr.check_name(sym::marker) {
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 {
self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id));
}

self.check_repr(item, target);
self.check_used(item, target);
}

/// Checks if an `#[inline]` is applied to a function or a closure.
fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) {
/// 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) -> bool {
if target != Target::Fn && target != Target::Closure {
struct_span_err!(self.tcx.sess,
attr.span,
E0518,
"attribute should be applied to function or closure")
.span_label(*span, "not a function or closure")
.emit();
false
} else {
true
}
}

/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid.
fn check_non_exhaustive(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) {
/// 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,
) -> bool {
match target {
Target::Struct | Target::Enum => { /* Valid */ },
Target::Struct | Target::Enum => true,
_ => {
struct_span_err!(self.tcx.sess,
attr.span,
E0701,
"attribute can only be applied to a struct or enum")
.span_label(item.span, "not a struct or enum")
.emit();
return;
false
}
}
}

/// Checks if the `#[marker]` attribute on an `item` is valid.
fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) {
/// 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) -> bool {
match target {
Target::Trait => { /* Valid */ },
Target::Trait => true,
_ => {
self.tcx.sess
.struct_span_err(attr.span, "attribute can only be applied to a trait")
.span_label(item.span, "not a trait")
.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.
fn check_repr(&self, item: &hir::Item, target: Target) {
// Extract the names of all repr hints, e.g., [foo, bar, align] for:
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/attributes/multiple-invalid.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 21 additions & 0 deletions src/test/ui/attributes/multiple-invalid.stderr
Original file line number Diff line number Diff line change
@@ -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`.
50 changes: 0 additions & 50 deletions src/test/ui/target-feature-wrong.stderr

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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")]
| ^^^^^^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,31 @@ fn bar() {}
mod another {}
//~^ 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)]
//~^ ERROR: cannot use `#[inline(always)]`
#[target_feature(enable = "sse2")]
Expand Down
95 changes: 95 additions & 0 deletions src/test/ui/target-feature/invalid-attribute.stderr
Original file line number Diff line number Diff line change
@@ -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