1 //! Implementation of the `#[simd_test]` macro
3 //! This macro expands to a `#[test]` function which tests the local machine
4 //! for the appropriate cfg before calling the inner test function.
6 extern crate proc_macro
;
7 extern crate proc_macro2
;
11 use proc_macro2
::{Delimiter, Ident, Literal, Span, TokenStream, TokenTree}
;
15 fn string(s
: &str) -> TokenTree
{
16 Literal
::string(s
).into()
19 #[proc_macro_attribute]
21 attr
: proc_macro
::TokenStream
,
22 item
: proc_macro
::TokenStream
,
23 ) -> proc_macro
::TokenStream
{
24 let tokens
= TokenStream
::from(attr
).into_iter().collect
::<Vec
<_
>>();
25 if tokens
.len() != 3 {
26 panic
!("expected #[simd_test(enable = \"feature\")]");
29 TokenTree
::Ident(tt
) if *tt
== "enable" => {}
30 _
=> panic
!("expected #[simd_test(enable = \"feature\")]"),
33 TokenTree
::Punct(tt
) if tt
.as_char() == '
='
=> {}
34 _
=> panic
!("expected #[simd_test(enable = \"feature\")]"),
36 let enable_feature
= match &tokens
[2] {
37 TokenTree
::Literal(tt
) => tt
.to_string(),
38 _
=> panic
!("expected #[simd_test(enable = \"feature\")]"),
40 let enable_feature
= enable_feature
.trim_start_matches('
"').trim_end_matches('"'
);
41 let target_features
: Vec
<String
> = enable_feature
47 let enable_feature
= string(enable_feature
);
48 let item
= TokenStream
::from(item
);
49 let name
= find_name(item
.clone());
51 let name
: TokenStream
= name
54 .unwrap_or_else(|_
| panic
!("failed to parse name: {}", name
.to_string()));
56 let target
= env
::var("TARGET").expect(
57 "TARGET environment variable should be set for rustc (e.g. TARGET=x86_64-apple-darwin cargo test)"
59 let mut force_test
= false;
60 let macro_test
= match target
63 .unwrap_or_else(|| panic
!("target triple contained no \"-\": {}", target
))
65 "i686" | "x86_64" | "i586" => "is_x86_feature_detected",
66 "arm" | "armv7" => "is_arm_feature_detected",
67 "aarch64" => "is_aarch64_feature_detected",
68 "powerpc" | "powerpcle" => "is_powerpc_feature_detected",
69 "powerpc64" | "powerpc64le" => "is_powerpc64_feature_detected",
70 "mips" | "mipsel" | "mipsisa32r6" | "mipsisa32r6el" => {
72 // On MIPS CI run-time feature detection always returns false due
73 // to this qemu bug: https://bugs.launchpad.net/qemu/+bug/1754372
75 // This is a workaround to force the MIPS tests to always run on
78 "is_mips_feature_detected"
80 "mips64" | "mips64el" | "mipsisa64r6" | "mipsisa64r6el" => {
83 "is_mips64_feature_detected"
85 t
=> panic
!("unknown target: {}", t
),
87 let macro_test
= Ident
::new(macro_test
, Span
::call_site());
89 let mut cfg_target_features
= TokenStream
::new();
90 for feature
in target_features
{
91 let q
= quote_spanned
! {
92 proc_macro2
::Span
::call_site() =>
93 #macro_test!(#feature) &&
95 q
.to_tokens(&mut cfg_target_features
);
97 let q
= quote
! { true }
;
98 q
.to_tokens(&mut cfg_target_features
);
100 let test_norun
= std
::env
::var("STDSIMD_TEST_NORUN").is_ok();
101 let maybe_ignore
= if test_norun
{
107 let ret
: TokenStream
= quote_spanned
! {
108 proc_macro2
::Span
::call_site() =>
109 #[allow(non_snake_case)]
113 if #force_test | (#cfg_target_features) {
114 let v
= unsafe { #name() }
;
117 ::stdarch_test
::assert_skip_test_ok(stringify
!(#name));
120 #[target_feature(enable = #enable_feature)]
127 fn find_name(item
: TokenStream
) -> Ident
{
128 let mut tokens
= item
.into_iter();
129 while let Some(tok
) = tokens
.next() {
130 if let TokenTree
::Ident(word
) = tok
{
137 fn get_ident(tt
: TokenTree
) -> Option
<Ident
> {
139 TokenTree
::Ident(i
) => Some(i
),
140 TokenTree
::Group(g
) if g
.delimiter() == Delimiter
::None
=> {
141 get_ident(g
.stream().into_iter().next()?
)
150 .expect("failed to find function name")