diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index c946118b1ea19..d5e956555bdfb 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -93,30 +93,35 @@ 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, @@ -124,13 +129,21 @@ impl CheckAttrVisitor<'tcx> { "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, @@ -138,25 +151,44 @@ impl CheckAttrVisitor<'tcx> { "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: diff --git a/src/test/ui/attributes/multiple-invalid.rs b/src/test/ui/attributes/multiple-invalid.rs new file mode 100644 index 0000000000000..ae044eb843bd9 --- /dev/null +++ b/src/test/ui/attributes/multiple-invalid.rs @@ -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() { } diff --git a/src/test/ui/attributes/multiple-invalid.stderr b/src/test/ui/attributes/multiple-invalid.stderr new file mode 100644 index 0000000000000..9bd29f15dbcca --- /dev/null +++ b/src/test/ui/attributes/multiple-invalid.stderr @@ -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`. diff --git a/src/test/ui/target-feature-wrong.stderr b/src/test/ui/target-feature-wrong.stderr deleted file mode 100644 index 47ca5a5ca478c..0000000000000 --- a/src/test/ui/target-feature-wrong.stderr +++ /dev/null @@ -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 - diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature/gate.rs similarity index 100% rename from src/test/ui/target-feature-gate.rs rename to src/test/ui/target-feature/gate.rs diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature/gate.stderr similarity index 91% rename from src/test/ui/target-feature-gate.stderr rename to src/test/ui/target-feature/gate.stderr index 9f17110b6d874..05dbc6e90adc8 100644 --- a/src/test/ui/target-feature-gate.stderr +++ b/src/test/ui/target-feature/gate.stderr @@ -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")] | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature/invalid-attribute.rs similarity index 62% rename from src/test/ui/target-feature-wrong.rs rename to src/test/ui/target-feature/invalid-attribute.rs index 646a98763e1b3..46680336632f9 100644 --- a/src/test/ui/target-feature-wrong.rs +++ b/src/test/ui/target-feature/invalid-attribute.rs @@ -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")] diff --git a/src/test/ui/target-feature/invalid-attribute.stderr b/src/test/ui/target-feature/invalid-attribute.stderr new file mode 100644 index 0000000000000..abfe5dd219770 --- /dev/null +++ b/src/test/ui/target-feature/invalid-attribute.stderr @@ -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 +