Skip to content

Commit fa55d7d

Browse files
committed
Modify #[simd_test] to enable const-testing
add const-safe version of `assert_eq`
1 parent b912c6e commit fa55d7d

File tree

5 files changed

+75
-30
lines changed

5 files changed

+75
-30
lines changed

crates/core_arch/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
funnel_shifts,
3737
avx10_target_feature,
3838
const_trait_impl,
39-
const_cmp
39+
const_cmp,
40+
const_eval_select
4041
)]
4142
#![cfg_attr(test, feature(test, abi_vectorcall, stdarch_internal))]
4243
#![deny(clippy::missing_inline_in_public_items)]

crates/core_arch/src/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
#[macro_use]
66
mod macros;
77

8+
#[cfg(test)]
9+
mod test;
10+
#[cfg(test)]
11+
use test::assert_eq_const;
12+
813
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64", doc))]
914
mod riscv_shared;
1015

crates/core_arch/src/simd.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ macro_rules! simd_ty {
5454
}
5555
}
5656

57-
impl core::cmp::PartialEq for $id {
57+
#[rustc_const_unstable(feature = "stdarch_const_intrinsics", issue = "none")]
58+
const impl core::cmp::PartialEq for $id {
5859
#[inline]
5960
fn eq(&self, other: &Self) -> bool {
6061
self.as_array() == other.as_array()
@@ -112,7 +113,8 @@ macro_rules! simd_m_ty {
112113
}
113114
}
114115

115-
impl core::cmp::PartialEq for $id {
116+
#[rustc_const_unstable(feature = "stdarch_const_intrinsics", issue = "none")]
117+
const impl core::cmp::PartialEq for $id {
116118
#[inline]
117119
fn eq(&self, other: &Self) -> bool {
118120
self.as_array() == other.as_array()

crates/core_arch/src/test.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use crate::fmt::Debug;
2+
3+
#[allow(unused)]
4+
pub(crate) fn assert_eq_rt<T: PartialEq + Debug>(a: &T, b: &T) {
5+
std::assert_eq!(a, b)
6+
}
7+
8+
#[allow(unused)]
9+
macro_rules! assert_eq_const {
10+
($a:expr, $b:expr $(,)?) => {{
11+
#[rustc_const_unstable(feature = "stdarch_const_intrinsics", issue = "none")]
12+
const fn assert_eq_ct<T: [const] PartialEq>(a: &T, b: &T) {
13+
assert!(a == b, concat!("`", stringify!($a), "` != `", stringify!($b), "`"));
14+
}
15+
16+
$crate::intrinsics::const_eval_select((&$a, &$b), assert_eq_ct, $crate::core_arch::test::assert_eq_rt);
17+
}};
18+
($a:expr, $b:expr, $($t:tt)+) => {
19+
::std::assert_eq!($a, $b, $($t)+)
20+
};
21+
}
22+
23+
pub(crate) use assert_eq_const;

crates/simd-test-macro/src/lib.rs

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,41 @@
77
#[macro_use]
88
extern crate quote;
99

10-
use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
10+
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
1111
use quote::ToTokens;
1212
use std::env;
1313

14-
fn string(s: &str) -> TokenTree {
15-
Literal::string(s).into()
16-
}
17-
1814
#[proc_macro_attribute]
1915
pub fn simd_test(
2016
attr: proc_macro::TokenStream,
2117
item: proc_macro::TokenStream,
2218
) -> proc_macro::TokenStream {
2319
let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();
24-
if tokens.len() != 3 {
25-
panic!("expected #[simd_test(enable = \"feature\")]");
26-
}
27-
match &tokens[0] {
28-
TokenTree::Ident(tt) if *tt == "enable" => {}
29-
_ => panic!("expected #[simd_test(enable = \"feature\")]"),
30-
}
31-
match &tokens[1] {
32-
TokenTree::Punct(tt) if tt.as_char() == '=' => {}
33-
_ => panic!("expected #[simd_test(enable = \"feature\")]"),
34-
}
35-
let enable_feature = match &tokens[2] {
36-
TokenTree::Literal(tt) => tt.to_string(),
37-
_ => panic!("expected #[simd_test(enable = \"feature\")]"),
20+
let (target_features, target_feature_attr) = match &tokens[..] {
21+
[] => (Vec::new(), TokenStream::new()),
22+
[
23+
TokenTree::Ident(enable),
24+
TokenTree::Punct(equals),
25+
TokenTree::Literal(literal),
26+
] if enable == "enable" && equals.as_char() == '=' => {
27+
let enable_feature = literal.to_string();
28+
let enable_feature = enable_feature.trim_start_matches('"').trim_end_matches('"');
29+
let target_features: Vec<_> = enable_feature
30+
.replace('+', "")
31+
.split(',')
32+
.map(String::from)
33+
.collect();
34+
35+
(
36+
target_features,
37+
quote! {
38+
#[target_feature(enable = #enable_feature)]
39+
},
40+
)
41+
}
42+
_ => panic!("expected #[simd_test(enable = \"feature\")] or #[simd_test]"),
3843
};
39-
let enable_feature = enable_feature.trim_start_matches('"').trim_end_matches('"');
40-
let target_features: Vec<String> = enable_feature
41-
.replace('+', "")
42-
.split(',')
43-
.map(String::from)
44-
.collect();
4544

46-
let enable_feature = string(enable_feature);
4745
let mut item = syn::parse_macro_input!(item as syn::ItemFn);
4846
let item_attrs = std::mem::take(&mut item.attrs);
4947
let name = &item.sig.ident;
@@ -102,13 +100,28 @@ pub fn simd_test(
102100
TokenStream::new()
103101
};
104102

103+
let (const_test, const_stability) = if item.sig.constness.is_some() {
104+
(
105+
quote! {
106+
const _: () = unsafe { #name() };
107+
},
108+
quote! {
109+
#[rustc_const_unstable(feature = "stdarch_const_intrinsics", issue = "none")]
110+
},
111+
)
112+
} else {
113+
(TokenStream::new(), TokenStream::new())
114+
};
115+
105116
let ret: TokenStream = quote_spanned! {
106117
proc_macro2::Span::call_site() =>
107118
#[allow(non_snake_case)]
108119
#[test]
109120
#maybe_ignore
110121
#(#item_attrs)*
111122
fn #name() {
123+
#const_test
124+
112125
let mut missing_features = ::std::vec::Vec::new();
113126
#detect_missing_features
114127
if missing_features.is_empty() {
@@ -118,7 +131,8 @@ pub fn simd_test(
118131
::stdarch_test::assert_skip_test_ok(stringify!(#name), &missing_features);
119132
}
120133

121-
#[target_feature(enable = #enable_feature)]
134+
#target_feature_attr
135+
#const_stability
122136
#item
123137
}
124138
};

0 commit comments

Comments
 (0)