From e79036d17fa8037f9f3f7e98a9b4ef80fb943ca7 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 26 Sep 2019 11:00:53 +0100 Subject: hir: Disallow `target_feature` on constants This commit fixes an ICE when `target_feature` is applied to constants. Signed-off-by: David Wood --- src/librustc/hir/check_attr.rs | 72 +++++++++++----- src/test/ui/attributes/multiple-invalid.rs | 10 +++ src/test/ui/attributes/multiple-invalid.stderr | 21 +++++ src/test/ui/target-feature-gate.rs | 35 -------- src/test/ui/target-feature-gate.stderr | 12 --- src/test/ui/target-feature-wrong.rs | 48 ----------- src/test/ui/target-feature-wrong.stderr | 50 ------------ src/test/ui/target-feature/gate.rs | 35 ++++++++ src/test/ui/target-feature/gate.stderr | 12 +++ src/test/ui/target-feature/invalid-attribute.rs | 73 +++++++++++++++++ .../ui/target-feature/invalid-attribute.stderr | 95 ++++++++++++++++++++++ 11 files changed, 298 insertions(+), 165 deletions(-) create mode 100644 src/test/ui/attributes/multiple-invalid.rs create mode 100644 src/test/ui/attributes/multiple-invalid.stderr delete mode 100644 src/test/ui/target-feature-gate.rs delete mode 100644 src/test/ui/target-feature-gate.stderr delete mode 100644 src/test/ui/target-feature-wrong.rs delete mode 100644 src/test/ui/target-feature-wrong.stderr create mode 100644 src/test/ui/target-feature/gate.rs create mode 100644 src/test/ui/target-feature/gate.stderr create mode 100644 src/test/ui/target-feature/invalid-attribute.rs create mode 100644 src/test/ui/target-feature/invalid-attribute.stderr diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 1df09429e51..283ab0103ec 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 || target == Target::Const { + 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 00000000000..ae044eb843b --- /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 00000000000..9bd29f15dbc --- /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-gate.rs b/src/test/ui/target-feature-gate.rs deleted file mode 100644 index bc7f7caa107..00000000000 --- a/src/test/ui/target-feature-gate.rs +++ /dev/null @@ -1,35 +0,0 @@ -// ignore-arm -// ignore-aarch64 -// ignore-wasm -// ignore-emscripten -// ignore-mips -// ignore-mips64 -// ignore-powerpc -// ignore-powerpc64 -// ignore-powerpc64le -// ignore-sparc -// ignore-sparc64 -// ignore-s390x -// gate-test-sse4a_target_feature -// gate-test-powerpc_target_feature -// gate-test-avx512_target_feature -// gate-test-tbm_target_feature -// gate-test-arm_target_feature -// gate-test-aarch64_target_feature -// gate-test-hexagon_target_feature -// gate-test-mips_target_feature -// gate-test-mmx_target_feature -// gate-test-wasm_target_feature -// gate-test-adx_target_feature -// gate-test-cmpxchg16b_target_feature -// gate-test-movbe_target_feature -// gate-test-rtm_target_feature -// gate-test-f16c_target_feature -// min-llvm-version 6.0 - -#[target_feature(enable = "avx512bw")] -//~^ ERROR: currently unstable -unsafe fn foo() { -} - -fn main() {} diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature-gate.stderr deleted file mode 100644 index 9f17110b6d8..00000000000 --- a/src/test/ui/target-feature-gate.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/target-feature-gate.rs:30:18 - | -LL | #[target_feature(enable = "avx512bw")] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/44839 - = help: add `#![feature(avx512_target_feature)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature-wrong.rs deleted file mode 100644 index 646a98763e1..00000000000 --- a/src/test/ui/target-feature-wrong.rs +++ /dev/null @@ -1,48 +0,0 @@ -// ignore-arm -// ignore-aarch64 -// ignore-wasm -// ignore-emscripten -// ignore-mips -// ignore-mips64 -// ignore-powerpc -// ignore-powerpc64 -// ignore-powerpc64le -// ignore-s390x -// ignore-sparc -// ignore-sparc64 - -#![feature(target_feature)] - -#[target_feature = "+sse2"] -//~^ ERROR malformed `target_feature` attribute -#[target_feature(enable = "foo")] -//~^ ERROR not valid for this target -//~| NOTE `foo` is not valid for this target -#[target_feature(bar)] -//~^ ERROR malformed `target_feature` attribute -#[target_feature(disable = "baz")] -//~^ ERROR malformed `target_feature` attribute -unsafe fn foo() {} - -#[target_feature(enable = "sse2")] -//~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions -//~| NOTE can only be applied to `unsafe` functions -fn bar() {} -//~^ NOTE not an `unsafe` function - -#[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function -mod another {} -//~^ NOTE not a function - -#[inline(always)] -//~^ ERROR: cannot use `#[inline(always)]` -#[target_feature(enable = "sse2")] -unsafe fn test() {} - -fn main() { - unsafe { - foo(); - bar(); - } -} diff --git a/src/test/ui/target-feature-wrong.stderr b/src/test/ui/target-feature-wrong.stderr deleted file mode 100644 index 47ca5a5ca47..00000000000 --- 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 new file mode 100644 index 00000000000..bc7f7caa107 --- /dev/null +++ b/src/test/ui/target-feature/gate.rs @@ -0,0 +1,35 @@ +// ignore-arm +// ignore-aarch64 +// ignore-wasm +// ignore-emscripten +// ignore-mips +// ignore-mips64 +// ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-sparc +// ignore-sparc64 +// ignore-s390x +// gate-test-sse4a_target_feature +// gate-test-powerpc_target_feature +// gate-test-avx512_target_feature +// gate-test-tbm_target_feature +// gate-test-arm_target_feature +// gate-test-aarch64_target_feature +// gate-test-hexagon_target_feature +// gate-test-mips_target_feature +// gate-test-mmx_target_feature +// gate-test-wasm_target_feature +// gate-test-adx_target_feature +// gate-test-cmpxchg16b_target_feature +// gate-test-movbe_target_feature +// gate-test-rtm_target_feature +// gate-test-f16c_target_feature +// min-llvm-version 6.0 + +#[target_feature(enable = "avx512bw")] +//~^ ERROR: currently unstable +unsafe fn foo() { +} + +fn main() {} diff --git a/src/test/ui/target-feature/gate.stderr b/src/test/ui/target-feature/gate.stderr new file mode 100644 index 00000000000..05dbc6e90ad --- /dev/null +++ b/src/test/ui/target-feature/gate.stderr @@ -0,0 +1,12 @@ +error[E0658]: the target feature `avx512bw` is currently unstable + --> $DIR/gate.rs:30:18 + | +LL | #[target_feature(enable = "avx512bw")] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44839 + = help: add `#![feature(avx512_target_feature)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/target-feature/invalid-attribute.rs b/src/test/ui/target-feature/invalid-attribute.rs new file mode 100644 index 00000000000..46680336632 --- /dev/null +++ b/src/test/ui/target-feature/invalid-attribute.rs @@ -0,0 +1,73 @@ +// ignore-arm +// ignore-aarch64 +// ignore-wasm +// ignore-emscripten +// ignore-mips +// ignore-mips64 +// ignore-powerpc +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-s390x +// ignore-sparc +// ignore-sparc64 + +#![feature(target_feature)] + +#[target_feature = "+sse2"] +//~^ ERROR malformed `target_feature` attribute +#[target_feature(enable = "foo")] +//~^ ERROR not valid for this target +//~| NOTE `foo` is not valid for this target +#[target_feature(bar)] +//~^ ERROR malformed `target_feature` attribute +#[target_feature(disable = "baz")] +//~^ ERROR malformed `target_feature` attribute +unsafe fn foo() {} + +#[target_feature(enable = "sse2")] +//~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions +//~| NOTE can only be applied to `unsafe` functions +fn bar() {} +//~^ NOTE not an `unsafe` function + +#[target_feature(enable = "sse2")] +//~^ ERROR attribute should be applied to a function +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")] +unsafe fn test() {} + +fn main() { + unsafe { + foo(); + bar(); + } +} 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 00000000000..abfe5dd2197 --- /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 + -- cgit 1.4.1-3-g733a5 From c3368bdfa498f0c8fb2267dfb0cb804df8ec6dbb Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 26 Sep 2019 17:03:29 +0100 Subject: hir: stop checking codegen fn attrs for constants See linked comment[1] for context. 1: https://github.com/rust-lang/rust/pull/64809#discussion_r328662933 Signed-off-by: David Wood --- src/librustc/hir/check_attr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 283ab0103ec..fcd53780631 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -112,7 +112,7 @@ impl CheckAttrVisitor<'tcx> { return; } - if target == Target::Fn || target == Target::Const { + if target == Target::Fn { self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id)); } -- cgit 1.4.1-3-g733a5