| #![deny(rust_2018_idioms)] | |
| #[macro_use] | |
| extern crate quote; | |
| #[macro_use] | |
| extern crate syn; | |
| use proc_macro::TokenStream; | |
| use std::{fs::File, io::Read, path::Path}; | |
| use syn::ext::IdentExt; | |
| use syn::parse::Parser as _; | |
| #[proc_macro] | |
| pub fn x86_functions(input: TokenStream) -> TokenStream { | |
| functions(input, &["core_arch/src/x86", "core_arch/src/x86_64"]) | |
| } | |
| #[proc_macro] | |
| pub fn arm_functions(input: TokenStream) -> TokenStream { | |
| functions( | |
| input, | |
| &[ | |
| "core_arch/src/arm", | |
| "core_arch/src/aarch64", | |
| "core_arch/src/arm_shared/neon", | |
| ], | |
| ) | |
| } | |
| #[proc_macro] | |
| pub fn mips_functions(input: TokenStream) -> TokenStream { | |
| functions(input, &["core_arch/src/mips"]) | |
| } | |
| fn functions(input: TokenStream, dirs: &[&str]) -> TokenStream { | |
| let dir = Path::new(env!("CARGO_MANIFEST_DIR")); | |
| let root = dir.parent().expect("root-dir not found"); | |
| let mut files = Vec::new(); | |
| for dir in dirs { | |
| walk(&root.join(dir), &mut files); | |
| } | |
| assert!(!files.is_empty()); | |
| let mut functions = Vec::new(); | |
| for &mut (ref mut file, ref path) in &mut files { | |
| for mut item in file.items.drain(..) { | |
| match item { | |
| syn::Item::Fn(f) => functions.push((f, path)), | |
| syn::Item::Mod(ref mut m) => { | |
| if let Some(ref mut m) = m.content { | |
| for i in m.1.drain(..) { | |
| if let syn::Item::Fn(f) = i { | |
| functions.push((f, path)) | |
| } | |
| } | |
| } | |
| } | |
| _ => (), | |
| } | |
| } | |
| } | |
| assert!(!functions.is_empty()); | |
| let mut tests = std::collections::HashSet::<String>::new(); | |
| for f in &functions { | |
| let id = format!("{}", f.0.sig.ident); | |
| if id.starts_with("test_") { | |
| tests.insert(id); | |
| } | |
| } | |
| assert!(!tests.is_empty()); | |
| functions.retain(|(f, _)| matches!(f.vis, syn::Visibility::Public(_))); | |
| assert!(!functions.is_empty()); | |
| let input = proc_macro2::TokenStream::from(input); | |
| let functions = functions | |
| .iter() | |
| .map(|&(ref f, path)| { | |
| let name = &f.sig.ident; | |
| // println!("{name}"); | |
| let mut arguments = Vec::new(); | |
| let mut const_arguments = Vec::new(); | |
| for input in f.sig.inputs.iter() { | |
| let ty = match *input { | |
| syn::FnArg::Typed(ref c) => &c.ty, | |
| _ => panic!("invalid argument on {name}"), | |
| }; | |
| arguments.push(to_type(ty)); | |
| } | |
| for generic in f.sig.generics.params.iter() { | |
| match *generic { | |
| syn::GenericParam::Const(ref c) => const_arguments.push(to_type(&c.ty)), | |
| syn::GenericParam::Type(ref _t) => (), | |
| _ => panic!("invalid generic argument on {name}"), | |
| }; | |
| } | |
| let ret = match f.sig.output { | |
| syn::ReturnType::Default => quote! { None }, | |
| syn::ReturnType::Type(_, ref t) => { | |
| let ty = to_type(t); | |
| quote! { Some(#ty) } | |
| } | |
| }; | |
| let instrs = find_instrs(&f.attrs); | |
| let target_feature = if let Some(i) = find_target_feature(&f.attrs) { | |
| quote! { Some(#i) } | |
| } else { | |
| quote! { None } | |
| }; | |
| let required_const = find_required_const("rustc_args_required_const", &f.attrs); | |
| let mut legacy_const_generics = | |
| find_required_const("rustc_legacy_const_generics", &f.attrs); | |
| if !required_const.is_empty() && !legacy_const_generics.is_empty() { | |
| panic!( | |
| "Can't have both #[rustc_args_required_const] and \ | |
| #[rustc_legacy_const_generics]" | |
| ); | |
| } | |
| // Newer intrinsics don't have `rustc_legacy_const_generics` - assume they belong at | |
| // the end of the argument list | |
| if required_const.is_empty() && legacy_const_generics.is_empty() { | |
| legacy_const_generics = | |
| (arguments.len()..(arguments.len() + const_arguments.len())).collect(); | |
| } | |
| // The list of required consts, used to verify the arguments, comes from either the | |
| // `rustc_args_required_const` or the `rustc_legacy_const_generics` attribute. | |
| let required_const = if required_const.is_empty() { | |
| legacy_const_generics.clone() | |
| } else { | |
| required_const | |
| }; | |
| legacy_const_generics.sort(); | |
| for (idx, ty) in legacy_const_generics | |
| .into_iter() | |
| .zip(const_arguments.into_iter()) | |
| { | |
| arguments.insert(idx, ty); | |
| } | |
| // Strip leading underscore from fn name when building a test | |
| // `_mm_foo` -> `mm_foo` such that the test name is `test_mm_foo`. | |
| let test_name = name.to_string(); | |
| let test_name = test_name.trim_start_matches('_'); | |
| let has_test = tests.contains(&format!("test_{test_name}")) | |
| // SVE load/store tests start with `test` or `_with_` | |
| || tests.iter().any(|t| t.starts_with(&format!("test_{test_name}")) | |
| || t.ends_with(&format!("_with_{test_name}"))); | |
| let doc = find_doc(&f.attrs); | |
| quote! { | |
| Function { | |
| name: stringify!(#name), | |
| arguments: &[#(#arguments),*], | |
| ret: #ret, | |
| target_feature: #target_feature, | |
| instrs: &[#(#instrs),*], | |
| file: stringify!(#path), | |
| required_const: &[#(#required_const),*], | |
| has_test: #has_test, | |
| doc: #doc | |
| } | |
| } | |
| }) | |
| .collect::<Vec<_>>(); | |
| let ret = quote! { #input: &[Function] = &[#(#functions),*]; }; | |
| // println!("{ret}"); | |
| ret.into() | |
| } | |
| fn to_type(t: &syn::Type) -> proc_macro2::TokenStream { | |
| match *t { | |
| syn::Type::Path(ref p) => match extract_path_ident(&p.path).to_string().as_ref() { | |
| // x86 ... | |
| "__m128" => quote! { &M128 }, | |
| "__m128bh" => quote! { &M128BH }, | |
| "__m128d" => quote! { &M128D }, | |
| "__m128h" => quote! { &M128H }, | |
| "__m128i" => quote! { &M128I }, | |
| "__m256" => quote! { &M256 }, | |
| "__m256bh" => quote! { &M256BH }, | |
| "__m256d" => quote! { &M256D }, | |
| "__m256h" => quote! { &M256H }, | |
| "__m256i" => quote! { &M256I }, | |
| "__m512" => quote! { &M512 }, | |
| "__m512bh" => quote! { &M512BH }, | |
| "__m512d" => quote! { &M512D }, | |
| "__m512h" => quote! { &M512H }, | |
| "__m512i" => quote! { &M512I }, | |
| "__mmask8" => quote! { &MMASK8 }, | |
| "__mmask16" => quote! { &MMASK16 }, | |
| "__mmask32" => quote! { &MMASK32 }, | |
| "__mmask64" => quote! { &MMASK64 }, | |
| "_MM_CMPINT_ENUM" => quote! { &MM_CMPINT_ENUM }, | |
| "_MM_MANTISSA_NORM_ENUM" => quote! { &MM_MANTISSA_NORM_ENUM }, | |
| "_MM_MANTISSA_SIGN_ENUM" => quote! { &MM_MANTISSA_SIGN_ENUM }, | |
| "_MM_PERM_ENUM" => quote! { &MM_PERM_ENUM }, | |
| "__tile1024i" => quote! { &TILE1024I }, | |
| "bool" => quote! { &BOOL }, | |
| "bf16" => quote! { &BF16 }, | |
| "f16" => quote! { &F16 }, | |
| "f32" => quote! { &F32 }, | |
| "f64" => quote! { &F64 }, | |
| "i16" => quote! { &I16 }, | |
| "i32" => quote! { &I32 }, | |
| "i64" => quote! { &I64 }, | |
| "i8" => quote! { &I8 }, | |
| "u16" => quote! { &U16 }, | |
| "u32" => quote! { &U32 }, | |
| "u64" => quote! { &U64 }, | |
| "u128" => quote! { &U128 }, | |
| "usize" => quote! { &USIZE }, | |
| "u8" => quote! { &U8 }, | |
| "p8" => quote! { &P8 }, | |
| "p16" => quote! { &P16 }, | |
| "Ordering" => quote! { &ORDERING }, | |
| "CpuidResult" => quote! { &CPUID }, | |
| // arm ... | |
| "int8x4_t" => quote! { &I8X4 }, | |
| "int8x8_t" => quote! { &I8X8 }, | |
| "int8x8x2_t" => quote! { &I8X8X2 }, | |
| "int8x8x3_t" => quote! { &I8X8X3 }, | |
| "int8x8x4_t" => quote! { &I8X8X4 }, | |
| "int8x16x2_t" => quote! { &I8X16X2 }, | |
| "int8x16x3_t" => quote! { &I8X16X3 }, | |
| "int8x16x4_t" => quote! { &I8X16X4 }, | |
| "int8x16_t" => quote! { &I8X16 }, | |
| "int16x2_t" => quote! { &I16X2 }, | |
| "int16x4_t" => quote! { &I16X4 }, | |
| "int16x4x2_t" => quote! { &I16X4X2 }, | |
| "int16x4x3_t" => quote! { &I16X4X3 }, | |
| "int16x4x4_t" => quote! { &I16X4X4 }, | |
| "int16x8_t" => quote! { &I16X8 }, | |
| "int16x8x2_t" => quote! { &I16X8X2 }, | |
| "int16x8x3_t" => quote! { &I16X8X3 }, | |
| "int16x8x4_t" => quote! { &I16X8X4 }, | |
| "int32x2_t" => quote! { &I32X2 }, | |
| "int32x2x2_t" => quote! { &I32X2X2 }, | |
| "int32x2x3_t" => quote! { &I32X2X3 }, | |
| "int32x2x4_t" => quote! { &I32X2X4 }, | |
| "int32x4_t" => quote! { &I32X4 }, | |
| "int32x4x2_t" => quote! { &I32X4X2 }, | |
| "int32x4x3_t" => quote! { &I32X4X3 }, | |
| "int32x4x4_t" => quote! { &I32X4X4 }, | |
| "int64x1_t" => quote! { &I64X1 }, | |
| "int64x1x2_t" => quote! { &I64X1X2 }, | |
| "int64x1x3_t" => quote! { &I64X1X3 }, | |
| "int64x1x4_t" => quote! { &I64X1X4 }, | |
| "int64x2_t" => quote! { &I64X2 }, | |
| "int64x2x2_t" => quote! { &I64X2X2 }, | |
| "int64x2x3_t" => quote! { &I64X2X3 }, | |
| "int64x2x4_t" => quote! { &I64X2X4 }, | |
| "uint8x8_t" => quote! { &U8X8 }, | |
| "uint8x4_t" => quote! { &U8X4 }, | |
| "uint8x8x2_t" => quote! { &U8X8X2 }, | |
| "uint8x16x2_t" => quote! { &U8X16X2 }, | |
| "uint8x16x3_t" => quote! { &U8X16X3 }, | |
| "uint8x16x4_t" => quote! { &U8X16X4 }, | |
| "uint8x8x3_t" => quote! { &U8X8X3 }, | |
| "uint8x8x4_t" => quote! { &U8X8X4 }, | |
| "uint8x16_t" => quote! { &U8X16 }, | |
| "uint16x4_t" => quote! { &U16X4 }, | |
| "uint16x4x2_t" => quote! { &U16X4X2 }, | |
| "uint16x4x3_t" => quote! { &U16X4X3 }, | |
| "uint16x4x4_t" => quote! { &U16X4X4 }, | |
| "uint16x8_t" => quote! { &U16X8 }, | |
| "uint16x8x2_t" => quote! { &U16X8X2 }, | |
| "uint16x8x3_t" => quote! { &U16X8X3 }, | |
| "uint16x8x4_t" => quote! { &U16X8X4 }, | |
| "uint32x2_t" => quote! { &U32X2 }, | |
| "uint32x2x2_t" => quote! { &U32X2X2 }, | |
| "uint32x2x3_t" => quote! { &U32X2X3 }, | |
| "uint32x2x4_t" => quote! { &U32X2X4 }, | |
| "uint32x4_t" => quote! { &U32X4 }, | |
| "uint32x4x2_t" => quote! { &U32X4X2 }, | |
| "uint32x4x3_t" => quote! { &U32X4X3 }, | |
| "uint32x4x4_t" => quote! { &U32X4X4 }, | |
| "uint64x1_t" => quote! { &U64X1 }, | |
| "uint64x1x2_t" => quote! { &U64X1X2 }, | |
| "uint64x1x3_t" => quote! { &U64X1X3 }, | |
| "uint64x1x4_t" => quote! { &U64X1X4 }, | |
| "uint64x2_t" => quote! { &U64X2 }, | |
| "uint64x2x2_t" => quote! { &U64X2X2 }, | |
| "uint64x2x3_t" => quote! { &U64X2X3 }, | |
| "uint64x2x4_t" => quote! { &U64X2X4 }, | |
| "float16x2_t" => quote! { &F16X2 }, | |
| "float16x4_t" => quote! { &F16X4 }, | |
| "float16x4x2_t" => quote! { &F16X4X2 }, | |
| "float16x4x3_t" => quote! { &F16X4X3 }, | |
| "float16x4x4_t" => quote! { &F16X4X4 }, | |
| "float16x8_t" => quote! { &F16X8 }, | |
| "float16x8x2_t" => quote! { &F16X8X2 }, | |
| "float16x8x3_t" => quote! { &F16X8X3 }, | |
| "float16x8x4_t" => quote! { &F16X8X4 }, | |
| "float32x2_t" => quote! { &F32X2 }, | |
| "float32x2x2_t" => quote! { &F32X2X2 }, | |
| "float32x2x3_t" => quote! { &F32X2X3 }, | |
| "float32x2x4_t" => quote! { &F32X2X4 }, | |
| "float32x4_t" => quote! { &F32X4 }, | |
| "float32x4x2_t" => quote! { &F32X4X2 }, | |
| "float32x4x3_t" => quote! { &F32X4X3 }, | |
| "float32x4x4_t" => quote! { &F32X4X4 }, | |
| "float64x1_t" => quote! { &F64X1 }, | |
| "float64x1x2_t" => quote! { &F64X1X2 }, | |
| "float64x1x3_t" => quote! { &F64X1X3 }, | |
| "float64x1x4_t" => quote! { &F64X1X4 }, | |
| "float64x2_t" => quote! { &F64X2 }, | |
| "float64x2x2_t" => quote! { &F64X2X2 }, | |
| "float64x2x3_t" => quote! { &F64X2X3 }, | |
| "float64x2x4_t" => quote! { &F64X2X4 }, | |
| "poly8x8_t" => quote! { &POLY8X8 }, | |
| "poly8x8x2_t" => quote! { &POLY8X8X2 }, | |
| "poly8x8x3_t" => quote! { &POLY8X8X3 }, | |
| "poly8x8x4_t" => quote! { &POLY8X8X4 }, | |
| "poly8x16x2_t" => quote! { &POLY8X16X2 }, | |
| "poly8x16x3_t" => quote! { &POLY8X16X3 }, | |
| "poly8x16x4_t" => quote! { &POLY8X16X4 }, | |
| "p64" => quote! { &P64 }, | |
| "poly64x1_t" => quote! { &POLY64X1 }, | |
| "poly64x2_t" => quote! { &POLY64X2 }, | |
| "poly8x16_t" => quote! { &POLY8X16 }, | |
| "poly16x4_t" => quote! { &POLY16X4 }, | |
| "poly16x4x2_t" => quote! { &P16X4X2 }, | |
| "poly16x4x3_t" => quote! { &P16X4X3 }, | |
| "poly16x4x4_t" => quote! { &P16X4X4 }, | |
| "poly16x8_t" => quote! { &POLY16X8 }, | |
| "poly16x8x2_t" => quote! { &P16X8X2 }, | |
| "poly16x8x3_t" => quote! { &P16X8X3 }, | |
| "poly16x8x4_t" => quote! { &P16X8X4 }, | |
| "poly64x1x2_t" => quote! { &P64X1X2 }, | |
| "poly64x1x3_t" => quote! { &P64X1X3 }, | |
| "poly64x1x4_t" => quote! { &P64X1X4 }, | |
| "poly64x2x2_t" => quote! { &P64X2X2 }, | |
| "poly64x2x3_t" => quote! { &P64X2X3 }, | |
| "poly64x2x4_t" => quote! { &P64X2X4 }, | |
| "p128" => quote! { &P128 }, | |
| "v16i8" => quote! { &v16i8 }, | |
| "v8i16" => quote! { &v8i16 }, | |
| "v4i32" => quote! { &v4i32 }, | |
| "v2i64" => quote! { &v2i64 }, | |
| "v16u8" => quote! { &v16u8 }, | |
| "v8u16" => quote! { &v8u16 }, | |
| "v4u32" => quote! { &v4u32 }, | |
| "v2u64" => quote! { &v2u64 }, | |
| "v8f16" => quote! { &v8f16 }, | |
| "v4f32" => quote! { &v4f32 }, | |
| "v2f64" => quote! { &v2f64 }, | |
| "svbool_t" => quote! { &SVBOOL }, | |
| "svint8_t" => quote! { &SVI8 }, | |
| "svint8x2_t" => quote! { &SVI8X2 }, | |
| "svint8x3_t" => quote! { &SVI8X3 }, | |
| "svint8x4_t" => quote! { &SVI8X4 }, | |
| "svint16_t" => quote! { &SVI16 }, | |
| "svint16x2_t" => quote! { &SVI16X2 }, | |
| "svint16x3_t" => quote! { &SVI16X3 }, | |
| "svint16x4_t" => quote! { &SVI16X4 }, | |
| "svint32_t" => quote! { &SVI32 }, | |
| "svint32x2_t" => quote! { &SVI32X2 }, | |
| "svint32x3_t" => quote! { &SVI32X3 }, | |
| "svint32x4_t" => quote! { &SVI32X4 }, | |
| "svint64_t" => quote! { &SVI64 }, | |
| "svint64x2_t" => quote! { &SVI64X2 }, | |
| "svint64x3_t" => quote! { &SVI64X3 }, | |
| "svint64x4_t" => quote! { &SVI64X4 }, | |
| "svuint8_t" => quote! { &SVU8 }, | |
| "svuint8x2_t" => quote! { &SVU8X2 }, | |
| "svuint8x3_t" => quote! { &SVU8X3 }, | |
| "svuint8x4_t" => quote! { &SVU8X4 }, | |
| "svuint16_t" => quote! { &SVU16 }, | |
| "svuint16x2_t" => quote! { &SVU16X2 }, | |
| "svuint16x3_t" => quote! { &SVU16X3 }, | |
| "svuint16x4_t" => quote! { &SVU16X4 }, | |
| "svuint32_t" => quote! { &SVU32 }, | |
| "svuint32x2_t" => quote! { &SVU32X2 }, | |
| "svuint32x3_t" => quote! { &SVU32X3 }, | |
| "svuint32x4_t" => quote! { &SVU32X4 }, | |
| "svuint64_t" => quote! { &SVU64 }, | |
| "svuint64x2_t" => quote! { &SVU64X2 }, | |
| "svuint64x3_t" => quote! { &SVU64X3 }, | |
| "svuint64x4_t" => quote! { &SVU64X4 }, | |
| "svfloat32_t" => quote! { &SVF32 }, | |
| "svfloat32x2_t" => quote! { &SVF32X2 }, | |
| "svfloat32x3_t" => quote! { &SVF32X3 }, | |
| "svfloat32x4_t" => quote! { &SVF32X4 }, | |
| "svfloat64_t" => quote! { &SVF64 }, | |
| "svfloat64x2_t" => quote! { &SVF64X2 }, | |
| "svfloat64x3_t" => quote! { &SVF64X3 }, | |
| "svfloat64x4_t" => quote! { &SVF64X4 }, | |
| "svprfop" => quote! { &SVPRFOP }, | |
| "svpattern" => quote! { &SVPATTERN }, | |
| // Generic types | |
| "T" => quote! { &GENERICT }, | |
| "U" => quote! { &GENERICU }, | |
| s => panic!("unsupported type: \"{s}\""), | |
| }, | |
| syn::Type::Ptr(syn::TypePtr { | |
| ref elem, | |
| ref mutability, | |
| .. | |
| }) | |
| | syn::Type::Reference(syn::TypeReference { | |
| ref elem, | |
| ref mutability, | |
| .. | |
| }) => { | |
| // Both pointers and references can have a mut token (*mut and &mut) | |
| if mutability.is_some() { | |
| let tokens = to_type(elem); | |
| quote! { &Type::MutPtr(#tokens) } | |
| } else { | |
| // If they don't (*const or &) then they are "const" | |
| let tokens = to_type(elem); | |
| quote! { &Type::ConstPtr(#tokens) } | |
| } | |
| } | |
| syn::Type::Slice(_) => panic!("unsupported slice"), | |
| syn::Type::Array(_) => panic!("unsupported array"), | |
| syn::Type::Tuple(_) => quote! { &TUPLE }, | |
| syn::Type::Never(_) => quote! { &NEVER }, | |
| _ => panic!("unsupported type"), | |
| } | |
| } | |
| fn extract_path_ident(path: &syn::Path) -> syn::Ident { | |
| if path.leading_colon.is_some() { | |
| panic!("unsupported leading colon in path") | |
| } | |
| if path.segments.len() != 1 { | |
| panic!("unsupported path that needs name resolution") | |
| } | |
| match path.segments.first().expect("segment not found").arguments { | |
| syn::PathArguments::None => {} | |
| _ => panic!("unsupported path that has path arguments"), | |
| } | |
| path.segments | |
| .first() | |
| .expect("segment not found") | |
| .ident | |
| .clone() | |
| } | |
| fn walk(root: &Path, files: &mut Vec<(syn::File, String)>) { | |
| for file in root.read_dir().unwrap() { | |
| let file = file.unwrap(); | |
| if file.file_type().unwrap().is_dir() { | |
| walk(&file.path(), files); | |
| continue; | |
| } | |
| let path = file.path(); | |
| if path.extension().and_then(std::ffi::OsStr::to_str) != Some("rs") { | |
| continue; | |
| } | |
| if path.file_name().and_then(std::ffi::OsStr::to_str) == Some("test.rs") { | |
| continue; | |
| } | |
| let mut contents = String::new(); | |
| File::open(&path) | |
| .unwrap_or_else(|_| panic!("can't open file at path: {}", path.display())) | |
| .read_to_string(&mut contents) | |
| .expect("failed to read file to string"); | |
| files.push(( | |
| syn::parse_str::<syn::File>(&contents).expect("failed to parse"), | |
| path.display().to_string(), | |
| )); | |
| } | |
| } | |
| fn find_instrs(attrs: &[syn::Attribute]) -> Vec<String> { | |
| struct AssertInstr { | |
| instr: Option<String>, | |
| } | |
| // A small custom parser to parse out the instruction in `assert_instr`. | |
| // | |
| // TODO: should probably just reuse `Invoc` from the `assert-instr-macro` | |
| // crate. | |
| impl syn::parse::Parse for AssertInstr { | |
| fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { | |
| let _ = input.parse::<syn::Meta>().unwrap(); | |
| let _ = input.parse::<Token![,]>().unwrap(); | |
| match input.parse::<syn::Ident>() { | |
| Ok(ident) if ident == "assert_instr" => {} | |
| _ => { | |
| while !input.is_empty() { | |
| // consume everything | |
| drop(input.parse::<proc_macro2::TokenStream>()); | |
| } | |
| return Ok(Self { instr: None }); | |
| } | |
| } | |
| let instrs; | |
| parenthesized!(instrs in input); | |
| let mut instr = String::new(); | |
| while !instrs.is_empty() { | |
| if let Ok(lit) = instrs.parse::<syn::LitStr>() { | |
| instr.push_str(&lit.value()); | |
| } else if let Ok(ident) = instrs.call(syn::Ident::parse_any) { | |
| instr.push_str(&ident.to_string()); | |
| } else if instrs.parse::<Token![.]>().is_ok() { | |
| instr.push('.'); | |
| } else if instrs.parse::<Token![,]>().is_ok() { | |
| // consume everything remaining | |
| drop(instrs.parse::<proc_macro2::TokenStream>()); | |
| break; | |
| } else { | |
| return Err(input.error("failed to parse instruction")); | |
| } | |
| } | |
| Ok(Self { instr: Some(instr) }) | |
| } | |
| } | |
| attrs | |
| .iter() | |
| .filter_map(|a| { | |
| if let syn::Meta::List(ref l) = a.meta { | |
| if l.path.is_ident("cfg_attr") { | |
| Some(l) | |
| } else { | |
| None | |
| } | |
| } else { | |
| None | |
| } | |
| }) | |
| .filter_map(|l| syn::parse2::<AssertInstr>(l.tokens.clone()).unwrap().instr) | |
| .collect() | |
| } | |
| fn find_target_feature(attrs: &[syn::Attribute]) -> Option<syn::Lit> { | |
| attrs | |
| .iter() | |
| .flat_map(|a| { | |
| #[allow(clippy::collapsible_if)] | |
| if let syn::Meta::List(ref l) = a.meta { | |
| if l.path.is_ident("target_feature") { | |
| if let Ok(l) = | |
| syn::punctuated::Punctuated::<syn::Meta, Token![,]>::parse_terminated | |
| .parse2(l.tokens.clone()) | |
| { | |
| return l; | |
| } | |
| } | |
| } | |
| syn::punctuated::Punctuated::new() | |
| }) | |
| .find_map(|m| match m { | |
| syn::Meta::NameValue(i) if i.path.is_ident("enable") => { | |
| if let syn::Expr::Lit(lit) = i.value { | |
| Some(lit.lit) | |
| } else { | |
| None | |
| } | |
| } | |
| _ => None, | |
| }) | |
| } | |
| fn find_doc(attrs: &[syn::Attribute]) -> String { | |
| attrs | |
| .iter() | |
| .filter_map(|a| { | |
| #[allow(clippy::collapsible_if)] | |
| if let syn::Meta::NameValue(ref l) = a.meta { | |
| if l.path.is_ident("doc") { | |
| if let syn::Expr::Lit(syn::ExprLit { | |
| lit: syn::Lit::Str(ref s), | |
| .. | |
| }) = l.value | |
| { | |
| return Some(s.value()); | |
| } | |
| } | |
| } | |
| None | |
| }) | |
| .collect() | |
| } | |
| fn find_required_const(name: &str, attrs: &[syn::Attribute]) -> Vec<usize> { | |
| attrs | |
| .iter() | |
| .filter_map(|a| { | |
| if let syn::Meta::List(ref l) = a.meta { | |
| Some(l) | |
| } else { | |
| None | |
| } | |
| }) | |
| .flat_map(|l| { | |
| if l.path.segments[0].ident == name { | |
| syn::parse2::<RustcArgsRequiredConst>(l.tokens.clone()) | |
| .unwrap() | |
| .args | |
| } else { | |
| Vec::new() | |
| } | |
| }) | |
| .collect() | |
| } | |
| struct RustcArgsRequiredConst { | |
| args: Vec<usize>, | |
| } | |
| impl syn::parse::Parse for RustcArgsRequiredConst { | |
| fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { | |
| let list = syn::punctuated::Punctuated::<syn::LitInt, Token![,]>::parse_terminated(input)?; | |
| Ok(Self { | |
| args: list | |
| .into_iter() | |
| .map(|a| a.base10_parse::<usize>()) | |
| .collect::<syn::Result<_>>()?, | |
| }) | |
| } | |
| } |