summaryrefslogtreecommitdiffstats
path: root/src/test/ui/target-feature
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/target-feature')
-rw-r--r--src/test/ui/target-feature/aarch64-neon-works.rs23
-rw-r--r--src/test/ui/target-feature/feature-hierarchy.rs58
-rw-r--r--src/test/ui/target-feature/gate.rs36
-rw-r--r--src/test/ui/target-feature/gate.stderr12
-rw-r--r--src/test/ui/target-feature/invalid-attribute.rs97
-rw-r--r--src/test/ui/target-feature/invalid-attribute.stderr136
-rw-r--r--src/test/ui/target-feature/missing-plusminus-2.rs6
-rw-r--r--src/test/ui/target-feature/missing-plusminus-2.stderr6
-rw-r--r--src/test/ui/target-feature/missing-plusminus.rs2
-rw-r--r--src/test/ui/target-feature/missing-plusminus.stderr6
-rw-r--r--src/test/ui/target-feature/no-llvm-leaks.rs64
-rw-r--r--src/test/ui/target-feature/rust-specific-name-no-warnings.rs5
-rw-r--r--src/test/ui/target-feature/similar-feature-suggestion.rs6
-rw-r--r--src/test/ui/target-feature/similar-feature-suggestion.stderr7
-rw-r--r--src/test/ui/target-feature/tied-features-cli.one.stderr4
-rw-r--r--src/test/ui/target-feature/tied-features-cli.rs20
-rw-r--r--src/test/ui/target-feature/tied-features-cli.three.stderr4
-rw-r--r--src/test/ui/target-feature/tied-features-cli.two.stderr4
-rw-r--r--src/test/ui/target-feature/tied-features.rs34
-rw-r--r--src/test/ui/target-feature/tied-features.stderr18
-rw-r--r--src/test/ui/target-feature/wasm-safe.rs44
21 files changed, 592 insertions, 0 deletions
diff --git a/src/test/ui/target-feature/aarch64-neon-works.rs b/src/test/ui/target-feature/aarch64-neon-works.rs
new file mode 100644
index 000000000..3878806fd
--- /dev/null
+++ b/src/test/ui/target-feature/aarch64-neon-works.rs
@@ -0,0 +1,23 @@
+// only-aarch64
+// run-pass
+#![allow(dead_code)]
+use std::arch::*;
+use std::arch::aarch64::*;
+
+// Smoke test to verify aarch64 code that enables NEON compiles.
+fn main() {
+ let _zero = if is_aarch64_feature_detected!("neon") {
+ unsafe {
+ let zeros = zero_vector();
+ vgetq_lane_u8::<1>(zeros)
+ }
+ } else {
+ 0
+ };
+}
+
+
+#[target_feature(enable = "neon")]
+unsafe fn zero_vector() -> uint8x16_t {
+ vmovq_n_u8(0)
+}
diff --git a/src/test/ui/target-feature/feature-hierarchy.rs b/src/test/ui/target-feature/feature-hierarchy.rs
new file mode 100644
index 000000000..5fbd5e8a2
--- /dev/null
+++ b/src/test/ui/target-feature/feature-hierarchy.rs
@@ -0,0 +1,58 @@
+// revisions: aarch64-neon aarch64-sve2
+// [aarch64-neon] compile-flags: -Ctarget-feature=+neon --target=aarch64-unknown-linux-gnu
+// [aarch64-neon] needs-llvm-components: aarch64
+// [aarch64-sve2] compile-flags: -Ctarget-feature=-neon,+sve2 --target=aarch64-unknown-linux-gnu
+// [aarch64-sve2] needs-llvm-components: aarch64
+// build-pass
+#![no_core]
+#![crate_type = "rlib"]
+#![feature(intrinsics, rustc_attrs, no_core, lang_items, staged_api)]
+#![stable(feature = "test", since = "1.0.0")]
+
+// Tests vetting "feature hierarchies" in the cases where we impose them.
+
+// Supporting minimal rust core code
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+impl Copy for bool {}
+
+extern "rust-intrinsic" {
+ #[rustc_const_stable(feature = "test", since = "1.0.0")]
+ fn unreachable() -> !;
+}
+
+#[rustc_builtin_macro]
+macro_rules! cfg {
+ ($($cfg:tt)*) => {};
+}
+
+// Test code
+const fn do_or_die(cond: bool) {
+ if cond {
+ } else {
+ unsafe { unreachable() }
+ }
+}
+
+macro_rules! assert {
+ ($x:expr $(,)?) => {
+ const _: () = do_or_die($x);
+ };
+}
+
+
+#[cfg(aarch64_neon)]
+fn check_neon_not_sve2() {
+ // This checks that a normal aarch64 target doesn't suddenly jump up the feature hierarchy.
+ assert!(cfg!(target_feature = "neon"));
+ assert!(cfg!(not(target_feature = "sve2")));
+}
+
+#[cfg(aarch64_sve2)]
+fn check_sve2_includes_neon() {
+ // This checks that aarch64's sve2 includes neon
+ assert!(cfg!(target_feature = "neon"));
+ assert!(cfg!(target_feature = "sve2"));
+}
diff --git a/src/test/ui/target-feature/gate.rs b/src/test/ui/target-feature/gate.rs
new file mode 100644
index 000000000..2382c98f8
--- /dev/null
+++ b/src/test/ui/target-feature/gate.rs
@@ -0,0 +1,36 @@
+// ignore-arm
+// ignore-aarch64
+// ignore-wasm
+// ignore-emscripten
+// ignore-mips
+// ignore-mips64
+// ignore-powerpc
+// ignore-powerpc64
+// ignore-powerpc64le
+// ignore-riscv64
+// 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-hexagon_target_feature
+// gate-test-mips_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
+// gate-test-riscv_target_feature
+// gate-test-ermsb_target_feature
+// gate-test-bpf_target_feature
+// gate-test-aarch64_ver_target_feature
+
+#[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 000000000..ee542b60a
--- /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:32:18
+ |
+LL | #[target_feature(enable = "avx512bw")]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #44839 <https://github.com/rust-lang/rust/issues/44839> for more information
+ = 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 000000000..ad1b6e96b
--- /dev/null
+++ b/src/test/ui/target-feature/invalid-attribute.rs
@@ -0,0 +1,97 @@
+// ignore-arm
+// ignore-aarch64
+// ignore-wasm
+// ignore-emscripten
+// ignore-mips
+// ignore-mips64
+// ignore-powerpc
+// ignore-powerpc64
+// ignore-powerpc64le
+// ignore-riscv64
+// ignore-s390x
+// ignore-sparc
+// ignore-sparc64
+
+#![warn(unused_attributes)]
+
+#[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 see issue #69098
+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 {
+//~^ NOTE not a function
+ f1: u16,
+ f2: u16,
+}
+
+#[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() {}
+
+trait Quux {
+ fn foo();
+}
+
+impl Quux for Foo {
+ #[target_feature(enable = "sse2")]
+ //~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions
+ //~| NOTE see issue #69098
+ fn foo() {}
+ //~^ NOTE not an `unsafe` function
+}
+
+fn main() {
+ #[target_feature(enable = "sse2")]
+ //~^ ERROR attribute should be applied to a function
+ unsafe {
+ foo();
+ bar();
+ }
+ //~^^^^ NOTE not a function
+
+ #[target_feature(enable = "sse2")]
+ //~^ ERROR attribute should be applied to a function
+ || {};
+ //~^ NOTE not a function
+}
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 000000000..889ced975
--- /dev/null
+++ b/src/test/ui/target-feature/invalid-attribute.stderr
@@ -0,0 +1,136 @@
+error: malformed `target_feature` attribute input
+ --> $DIR/invalid-attribute.rs:17: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:19:18
+ |
+LL | #[target_feature(enable = "foo")]
+ | ^^^^^^^^^^^^^^ `foo` is not valid for this target
+
+error: malformed `target_feature` attribute input
+ --> $DIR/invalid-attribute.rs:22:18
+ |
+LL | #[target_feature(bar)]
+ | ^^^ help: must be of the form: `enable = ".."`
+
+error: malformed `target_feature` attribute input
+ --> $DIR/invalid-attribute.rs:24:18
+ |
+LL | #[target_feature(disable = "baz")]
+ | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
+
+error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
+ --> $DIR/invalid-attribute.rs:28:1
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | fn bar() {}
+ | -------- not an `unsafe` function
+ |
+ = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information
+ = help: add `#![feature(target_feature_11)]` to the crate attributes to enable
+
+error: attribute should be applied to a function definition
+ --> $DIR/invalid-attribute.rs:34:1
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | mod another {}
+ | -------------- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/invalid-attribute.rs:39:1
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | const FOO: usize = 7;
+ | --------------------- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/invalid-attribute.rs:44:1
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | struct Foo;
+ | ----------- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/invalid-attribute.rs:49:1
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | enum Bar {}
+ | ----------- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/invalid-attribute.rs:54:1
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | / union Qux {
+LL | |
+LL | | f1: u16,
+LL | | f2: u16,
+LL | | }
+ | |_- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/invalid-attribute.rs:62:1
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | trait Baz {}
+ | ------------ not a function definition
+
+error: cannot use `#[inline(always)]` with `#[target_feature]`
+ --> $DIR/invalid-attribute.rs:67:1
+ |
+LL | #[inline(always)]
+ | ^^^^^^^^^^^^^^^^^
+
+error: attribute should be applied to a function definition
+ --> $DIR/invalid-attribute.rs:85:5
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | / unsafe {
+LL | | foo();
+LL | | bar();
+LL | | }
+ | |_____- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/invalid-attribute.rs:93:5
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | || {};
+ | ----- not a function definition
+
+error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
+ --> $DIR/invalid-attribute.rs:77:5
+ |
+LL | #[target_feature(enable = "sse2")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | fn foo() {}
+ | -------- not an `unsafe` function
+ |
+ = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information
+ = help: add `#![feature(target_feature_11)]` to the crate attributes to enable
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/target-feature/missing-plusminus-2.rs b/src/test/ui/target-feature/missing-plusminus-2.rs
new file mode 100644
index 000000000..131687289
--- /dev/null
+++ b/src/test/ui/target-feature/missing-plusminus-2.rs
@@ -0,0 +1,6 @@
+// compile-flags: -Ctarget-feature=rdrand --crate-type=rlib --target=x86_64-unknown-linux-gnu
+// build-pass
+// needs-llvm-components: x86
+
+#![feature(no_core)]
+#![no_core]
diff --git a/src/test/ui/target-feature/missing-plusminus-2.stderr b/src/test/ui/target-feature/missing-plusminus-2.stderr
new file mode 100644
index 000000000..5ed2652a0
--- /dev/null
+++ b/src/test/ui/target-feature/missing-plusminus-2.stderr
@@ -0,0 +1,6 @@
+warning: unknown feature specified for `-Ctarget-feature`: `rdrand`
+ |
+ = note: features must begin with a `+` to enable or `-` to disable it
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/target-feature/missing-plusminus.rs b/src/test/ui/target-feature/missing-plusminus.rs
new file mode 100644
index 000000000..efee65929
--- /dev/null
+++ b/src/test/ui/target-feature/missing-plusminus.rs
@@ -0,0 +1,2 @@
+// compile-flags: -Ctarget-feature=banana --crate-type=rlib
+// build-pass
diff --git a/src/test/ui/target-feature/missing-plusminus.stderr b/src/test/ui/target-feature/missing-plusminus.stderr
new file mode 100644
index 000000000..93abf3508
--- /dev/null
+++ b/src/test/ui/target-feature/missing-plusminus.stderr
@@ -0,0 +1,6 @@
+warning: unknown feature specified for `-Ctarget-feature`: `banana`
+ |
+ = note: features must begin with a `+` to enable or `-` to disable it
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/target-feature/no-llvm-leaks.rs b/src/test/ui/target-feature/no-llvm-leaks.rs
new file mode 100644
index 000000000..5a71b2166
--- /dev/null
+++ b/src/test/ui/target-feature/no-llvm-leaks.rs
@@ -0,0 +1,64 @@
+// revisions: aarch64 x86-64
+// [aarch64] compile-flags: -Ctarget-feature=+neon,+fp16,+fhm --target=aarch64-unknown-linux-gnu
+// [aarch64] needs-llvm-components: aarch64
+// [x86-64] compile-flags: -Ctarget-feature=+sse4.2,+rdrand --target=x86_64-unknown-linux-gnu
+// [x86-64] needs-llvm-components: x86
+// build-pass
+#![no_core]
+#![crate_type = "rlib"]
+#![feature(intrinsics, rustc_attrs, no_core, lang_items, staged_api)]
+#![stable(feature = "test", since = "1.0.0")]
+
+// Supporting minimal rust core code
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+impl Copy for bool {}
+
+extern "rust-intrinsic" {
+ #[rustc_const_stable(feature = "test", since = "1.0.0")]
+ fn unreachable() -> !;
+}
+
+#[rustc_builtin_macro]
+macro_rules! cfg {
+ ($($cfg:tt)*) => {};
+}
+
+// Test code
+const fn do_or_die(cond: bool) {
+ if cond {
+ } else {
+ unsafe { unreachable() }
+ }
+}
+
+macro_rules! assert {
+ ($x:expr $(,)?) => {
+ const _: () = do_or_die($x);
+ };
+}
+
+
+#[cfg(target_arch = "aarch64")]
+fn check_aarch64() {
+ // This checks that the rustc feature name is used, not the LLVM feature.
+ assert!(cfg!(target_feature = "neon"));
+ assert!(cfg!(not(target_feature = "fp-armv8")));
+ assert!(cfg!(target_feature = "fhm"));
+ assert!(cfg!(not(target_feature = "fp16fml")));
+ assert!(cfg!(target_feature = "fp16"));
+ assert!(cfg!(not(target_feature = "fullfp16")));
+}
+
+#[cfg(target_arch = "x86_64")]
+fn check_x86_64() {
+ // This checks that the rustc feature name is used, not the LLVM feature.
+ assert!(cfg!(target_feature = "rdrand"));
+ assert!(cfg!(not(target_feature = "rdrnd")));
+
+ // Likewise: We enable LLVM's crc32 feature with SSE4.2, but Rust says it's just SSE4.2
+ assert!(cfg!(target_feature = "sse4.2"));
+ assert!(cfg!(not(target_feature = "crc32")));
+}
diff --git a/src/test/ui/target-feature/rust-specific-name-no-warnings.rs b/src/test/ui/target-feature/rust-specific-name-no-warnings.rs
new file mode 100644
index 000000000..1708a71a9
--- /dev/null
+++ b/src/test/ui/target-feature/rust-specific-name-no-warnings.rs
@@ -0,0 +1,5 @@
+// build-pass
+// only-x86
+// compile-flags: -C target-feature=+pclmulqdq
+
+fn main() {}
diff --git a/src/test/ui/target-feature/similar-feature-suggestion.rs b/src/test/ui/target-feature/similar-feature-suggestion.rs
new file mode 100644
index 000000000..4e4e2160c
--- /dev/null
+++ b/src/test/ui/target-feature/similar-feature-suggestion.rs
@@ -0,0 +1,6 @@
+// compile-flags: -Ctarget-feature=+rdrnd --crate-type=rlib --target=x86_64-unknown-linux-gnu
+// build-pass
+// needs-llvm-components: x86
+
+#![feature(no_core)]
+#![no_core]
diff --git a/src/test/ui/target-feature/similar-feature-suggestion.stderr b/src/test/ui/target-feature/similar-feature-suggestion.stderr
new file mode 100644
index 000000000..2f376065f
--- /dev/null
+++ b/src/test/ui/target-feature/similar-feature-suggestion.stderr
@@ -0,0 +1,7 @@
+warning: unknown feature specified for `-Ctarget-feature`: `rdrnd`
+ |
+ = note: it is still passed through to the codegen backend
+ = help: you might have meant: `rdrand`
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/target-feature/tied-features-cli.one.stderr b/src/test/ui/target-feature/tied-features-cli.one.stderr
new file mode 100644
index 000000000..0cc901eec
--- /dev/null
+++ b/src/test/ui/target-feature/tied-features-cli.one.stderr
@@ -0,0 +1,4 @@
+error: target features paca, pacg must all be enabled or disabled together
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/target-feature/tied-features-cli.rs b/src/test/ui/target-feature/tied-features-cli.rs
new file mode 100644
index 000000000..72b7e3da5
--- /dev/null
+++ b/src/test/ui/target-feature/tied-features-cli.rs
@@ -0,0 +1,20 @@
+// revisions: one two three
+// compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
+// needs-llvm-components: aarch64
+//
+//
+// [one] check-fail
+// [one] compile-flags: -C target-feature=+paca
+// [two] check-fail
+// [two] compile-flags: -C target-feature=-pacg,+pacg
+// [three] check-fail
+// [three] compile-flags: -C target-feature=+paca,+pacg,-paca
+// [four] build-pass
+// [four] compile-flags: -C target-feature=-paca,+pacg -C target-feature=+paca
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized {}
+
+fn main() {}
diff --git a/src/test/ui/target-feature/tied-features-cli.three.stderr b/src/test/ui/target-feature/tied-features-cli.three.stderr
new file mode 100644
index 000000000..0cc901eec
--- /dev/null
+++ b/src/test/ui/target-feature/tied-features-cli.three.stderr
@@ -0,0 +1,4 @@
+error: target features paca, pacg must all be enabled or disabled together
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/target-feature/tied-features-cli.two.stderr b/src/test/ui/target-feature/tied-features-cli.two.stderr
new file mode 100644
index 000000000..0cc901eec
--- /dev/null
+++ b/src/test/ui/target-feature/tied-features-cli.two.stderr
@@ -0,0 +1,4 @@
+error: target features paca, pacg must all be enabled or disabled together
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/target-feature/tied-features.rs b/src/test/ui/target-feature/tied-features.rs
new file mode 100644
index 000000000..15f01505e
--- /dev/null
+++ b/src/test/ui/target-feature/tied-features.rs
@@ -0,0 +1,34 @@
+// build-fail
+// compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
+// needs-llvm-components: aarch64
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized {}
+
+// FIXME: this should not need to be public.
+pub fn main() {
+ #[target_feature(enable = "pacg")]
+ //~^ ERROR must all be either enabled or disabled together
+ unsafe fn inner() {}
+
+ unsafe {
+ foo();
+ bar();
+ baz();
+ inner();
+ }
+}
+
+#[target_feature(enable = "paca")]
+//~^ ERROR must all be either enabled or disabled together
+unsafe fn foo() {}
+
+
+#[target_feature(enable = "paca,pacg")]
+unsafe fn bar() {}
+
+#[target_feature(enable = "paca")]
+#[target_feature(enable = "pacg")]
+unsafe fn baz() {}
diff --git a/src/test/ui/target-feature/tied-features.stderr b/src/test/ui/target-feature/tied-features.stderr
new file mode 100644
index 000000000..525c90843
--- /dev/null
+++ b/src/test/ui/target-feature/tied-features.stderr
@@ -0,0 +1,18 @@
+error: the target features paca, pacg must all be either enabled or disabled together
+ --> $DIR/tied-features.rs:12:5
+ |
+LL | #[target_feature(enable = "pacg")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add the missing features in a `target_feature` attribute
+
+error: the target features paca, pacg must all be either enabled or disabled together
+ --> $DIR/tied-features.rs:24:1
+ |
+LL | #[target_feature(enable = "paca")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add the missing features in a `target_feature` attribute
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/target-feature/wasm-safe.rs b/src/test/ui/target-feature/wasm-safe.rs
new file mode 100644
index 000000000..4b868684a
--- /dev/null
+++ b/src/test/ui/target-feature/wasm-safe.rs
@@ -0,0 +1,44 @@
+// only-wasm32
+// check-pass
+
+#![feature(wasm_target_feature)]
+#![allow(dead_code)]
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn foo() {}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+extern "C" fn bar() {}
+
+trait A {
+ fn foo();
+ fn bar(&self);
+}
+
+struct B;
+
+impl B {
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn foo() {}
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn bar(&self) {}
+}
+
+impl A for B {
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn foo() {}
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn bar(&self) {}
+}
+
+fn no_features_enabled_on_this_function() {
+ bar();
+ foo();
+ B.bar();
+ B::foo();
+ <B as A>::foo();
+ <B as A>::bar(&B);
+}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn main() {}