target_feature_dispatch/
lib.rs

1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: Copyright (C) 2025 Tsukasa OI <floss_rust@irq.a4lg.com>.
3
4#![doc = include_str!("../docs/readme.md")]
5// no_std by default.
6#![no_std]
7// Unsafe code is not allowed.  Forbid it unless in the tests and documentation.
8#![deny(unsafe_code)]
9#![cfg_attr(not(any(test, doc)), forbid(unsafe_code))]
10// In the code maintenance mode, disallow all warnings.
11#![cfg_attr(feature = "maint-code", deny(warnings))]
12// Non-test code requires documents.
13#![cfg_attr(not(test), warn(missing_docs, clippy::missing_docs_in_private_items))]
14// Unless in the maintenance mode, allow unknown lints / old lint names.
15#![cfg_attr(
16    not(feature = "maint-lints"),
17    allow(unknown_lints, renamed_and_removed_lints)
18)]
19
20// Import std on documentation.
21#[cfg(doc)]
22extern crate std;
23
24#[doc = include_str!("../docs/target_feature_dispatch.md")]
25#[macro_export]
26macro_rules! target_feature_dispatch {
27    /*
28        Public Interface.
29
30        Dynamic dispatching: default-disabled (any())
31        Nightly features:    default-disabled (any())
32        Non-fallback paths:  default-enabled  (all())
33    */
34    ($(#[$($pseudo_meta: tt)+])* $(if $($arch: tt $(($arch_arg: tt))?)||+ { $($if: tt)* })else+ else { $($else: tt)* }) => {
35        $crate::target_feature_dispatch!(
36            @__tgtfeat_dispatch_parse_options
37            (any(), any(), all())
38            $(#[$($pseudo_meta)+])*
39            ($($else)*) $((($($arch$(($arch_arg))?)||+) ($($if)*)))+
40        )
41    };
42
43    /*
44        Parse options.
45    */
46    // Unconditional "dynamic".
47    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[dynamic] $($rest: tt)+) => {
48        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_parse_options (all(), $nightly, $dispatch) $($rest)+)
49    };
50    // Unconditional "static".
51    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[static] $($rest: tt)+) => {
52        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_parse_options (any(), $nightly, $dispatch) $($rest)+)
53    };
54    // Unconditional "unstable".
55    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[unstable] $($rest: tt)+) => {
56        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_parse_options ($dyn, all(), $dispatch) $($rest)+)
57    };
58    // Unconditional "stable".
59    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[stable] $($rest: tt)+) => {
60        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_parse_options ($dyn, any(), $dispatch) $($rest)+)
61    };
62    // Conditional "dynamic".
63    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[cfg_attr($meta: meta, dynamic)] $($rest: tt)+) => {
64        $crate::target_feature_dispatch!(
65            @__tgtfeat_dispatch_parse_options
66            (any($dyn, $meta), $nightly, $dispatch)
67            $($rest)+
68        )
69    };
70    // Conditional "static".
71    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[cfg_attr($meta: meta, static)] $($rest: tt)+) => {
72        $crate::target_feature_dispatch!(
73            @__tgtfeat_dispatch_parse_options
74            (all($dyn, not($meta)), $nightly, $dispatch)
75            $($rest)+
76        )
77    };
78    // Conditional "unstable".
79    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[cfg_attr($meta: meta, unstable)] $($rest: tt)+) => {
80        $crate::target_feature_dispatch!(
81            @__tgtfeat_dispatch_parse_options
82            ($dyn, any($nightly, $meta), $dispatch)
83            $($rest)+
84        )
85    };
86    // Conditional "stable".
87    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[cfg_attr($meta: meta, stable)] $($rest: tt)+) => {
88        $crate::target_feature_dispatch!(
89            @__tgtfeat_dispatch_parse_options
90            ($dyn, all($nightly, not($meta)), $dispatch)
91            $($rest)+
92        )
93    };
94    // Conditional non-fallback paths.
95    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[cfg_non_fallback($meta: meta)] $($rest: tt)+) => {
96        $crate::target_feature_dispatch!(
97            @__tgtfeat_dispatch_parse_options
98            ($dyn, $nightly, all($dispatch, $meta))
99            $($rest)+
100        )
101    };
102    // Invalid pseudo-attribute.
103    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) #[$($pmeta: tt)+] $($rest: tt)+) => {
104        compile_error!(concat!("invalid pseudo-attribute: ", stringify!(#[$($pmeta)+])));
105    };
106    // No more options (pass to the architecture-specific chain).
107    (@__tgtfeat_dispatch_parse_options ($dyn: meta, $nightly: meta, $dispatch: meta) ($($else: tt)*) $(($($ifs: tt)+))+) => {
108        {
109            #[cfg($dispatch)]
110            {
111                $crate::target_feature_dispatch!(
112                    @__tgtfeat_dispatch_arch_chain ($dyn, $nightly)
113                    ($($else)*) $(($($ifs)+))+
114                )
115            }
116            #[cfg(not($dispatch))]
117            {
118                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($else)*)
119            }
120        }
121    };
122
123    /*
124        Architecture-specific `if`-`else` chain.
125        Note that families are also parsed in @__tgtfeat_dispatch_arch_chain_2.
126    */
127    // `if`: family("aarch64") → any(target_arch = "aarch64", [target_arch = "arm64ec"])
128    // Depend on the `arch-arm64ec` feature.
129    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((family("aarch64")) ($($if: tt)*)) $($rest: tt)*) => {
130        $crate::__tgtfeat_dispatch_class_helper_arm64ec!(@__tgtfeat_dispatch_arch_chain ($($opts),*) ($($else)*) ((family("aarch64")) ($($if)*)) $($rest)*)
131    };
132    // `if`: family("riscv") → any(target_arch = "riscv32", target_arch = "riscv64")
133    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((family("riscv")) ($($if: tt)*)) $($rest: tt)*) => {
134        {
135            #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
136            {
137                $crate::target_feature_dispatch!(
138                    @__tgtfeat_dispatch_arch_clause (family("riscv")) ($($opts),*)
139                    ($($else)*) ($($if)*)
140                )
141            }
142            #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
143            {
144                $crate::target_feature_dispatch!(
145                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
146                    ($($else)*) $($rest)*
147                )
148            }
149        }
150    };
151    // `if`: family("x86") → any(target_arch = "x86", target_arch = "x86_64")
152    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((family("x86")) ($($if: tt)*)) $($rest: tt)*) => {
153        {
154            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
155            {
156                $crate::target_feature_dispatch!(
157                    @__tgtfeat_dispatch_arch_clause (family("x86")) ($($opts),*)
158                    ($($else)*) ($($if)*)
159                )
160            }
161            #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
162            {
163                $crate::target_feature_dispatch!(
164                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
165                    ($($else)*) $($rest)*
166                )
167            }
168        }
169    };
170    // `if`: class("arm") → any(target_arch = "aarch64", [target_arch = "arm64ec"], target_arch = "arm")
171    // Depend on the `arch-arm64ec` feature.
172    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("arm")) ($($if: tt)*)) $($rest: tt)*) => {
173        $crate::__tgtfeat_dispatch_class_helper_arm64ec!(@__tgtfeat_dispatch_arch_chain ($($opts),*) ($($else)*) ((class("arm")) ($($if)*)) $($rest)*)
174    };
175    // `if`: class("mips") → any(target_arch = "mips", target_arch = "mips64", [target_arch = "mips32r6"], [target_arch = "mips64r6"])
176    // Depend on the `arch-mips-r6` feature.
177    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("mips")) ($($if: tt)*)) $($rest: tt)*) => {
178        $crate::__tgtfeat_dispatch_class_helper_mips_r6!(@__tgtfeat_dispatch_arch_chain ($($opts),*) ($($else)*) ((class("mips")) ($($if)*)) $($rest)*)
179    };
180    // `if`: class("mips-classic") → any(target_arch = "mips", target_arch = "mips64")
181    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("mips-classic")) ($($if: tt)*)) $($rest: tt)*) => {
182        {
183            #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
184            {
185                $crate::target_feature_dispatch!(
186                    @__tgtfeat_dispatch_arch_clause (class("mips-classic")) ($($opts),*)
187                    ($($else)*) ($($if)*)
188                )
189            }
190            #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
191            {
192                $crate::target_feature_dispatch!(
193                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
194                    ($($else)*) $($rest)*
195                )
196            }
197        }
198    };
199    // `if`: class("mipsr6") → any(target_arch = "mips32r6", target_arch = "mips64r6")
200    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("mipsr6")) ($($if: tt)*)) $($rest: tt)*) => {
201        {
202            #[cfg(any(target_arch = "mips32r6", target_arch = "mips64r6"))]
203            {
204                $crate::target_feature_dispatch!(
205                    @__tgtfeat_dispatch_arch_clause (class("mipsr6")) ($($opts),*)
206                    ($($else)*) ($($if)*)
207                )
208            }
209            #[cfg(not(any(target_arch = "mips32r6", target_arch = "mips64r6")))]
210            {
211                $crate::target_feature_dispatch!(
212                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
213                    ($($else)*) $($rest)*
214                )
215            }
216        }
217    };
218    // `if`: class("powerpc") → any(target_arch = "powerpc", target_arch = "powerpc64")
219    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("powerpc")) ($($if: tt)*)) $($rest: tt)*) => {
220        {
221            #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
222            {
223                $crate::target_feature_dispatch!(
224                    @__tgtfeat_dispatch_arch_clause (class("powerpc")) ($($opts),*)
225                    ($($else)*) ($($if)*)
226                )
227            }
228            #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
229            {
230                $crate::target_feature_dispatch!(
231                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
232                    ($($else)*) $($rest)*
233                )
234            }
235        }
236    };
237    // `if`: class("sparc") → any(target_arch = "sparc", target_arch = "sparc64")
238    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("sparc")) ($($if: tt)*)) $($rest: tt)*) => {
239        {
240            #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
241            {
242                $crate::target_feature_dispatch!(
243                    @__tgtfeat_dispatch_arch_clause (class("sparc")) ($($opts),*)
244                    ($($else)*) ($($if)*)
245                )
246            }
247            #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))]
248            {
249                $crate::target_feature_dispatch!(
250                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
251                    ($($else)*) $($rest)*
252                )
253            }
254        }
255    };
256    // `if`: class("wasm") → any(target_arch = "wasm32", target_arch = "wasm64")
257    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("wasm")) ($($if: tt)*)) $($rest: tt)*) => {
258        {
259            #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
260            {
261                $crate::target_feature_dispatch!(
262                    @__tgtfeat_dispatch_arch_clause (class("wasm")) ($($opts),*)
263                    ($($else)*) ($($if)*)
264                )
265            }
266            #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
267            {
268                $crate::target_feature_dispatch!(
269                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
270                    ($($else)*) $($rest)*
271                )
272            }
273        }
274    };
275    // `if`: Generic (others): pass to the final step below.
276    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) (($($arch: tt $(($arch_arg: tt))?)||+) ($($if: tt)*)) $($rest: tt)*) => {
277        $crate::target_feature_dispatch!(
278            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
279            (() ($($arch$(($arch_arg))?)||+) ($($if)*)) $($rest)*
280        )
281    };
282    // `else`
283    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*)) => {
284        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($else)*)
285    };
286
287    /*
288        Architecture-specific `if`-`else` chain: `if` (final step)
289        Conversion to regular list of architectures.
290    */
291    // family("aarch64") → "aarch64" || ["arm64ec"]
292    // Depend on the `arch-arm64ec` feature.
293    (
294        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
295        (($($added: tt,)*) (family("aarch64") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
296    ) => {
297        $crate::__tgtfeat_dispatch_class_helper_arm64ec!(
298            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
299            (($($added,)*) (family("aarch64") $(|| $($arch2 $(($arch2_arg))?)||+)?) ($($if)*))
300            $($rest)*
301        )
302    };
303    // family("riscv") → "riscv32" || "riscv64"
304    (
305        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
306        (($($added: tt,)*) (family("riscv") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
307    ) => {
308        $crate::target_feature_dispatch!(
309            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
310            (($($added,)* "riscv32", "riscv64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
311            $($rest)*
312        )
313    };
314    // family("x86") → "x86" || "x86_64"
315    (
316        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
317        (($($added: tt,)*) (family("x86") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
318    ) => {
319        $crate::target_feature_dispatch!(
320            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
321            (($($added,)* "x86", "x86_64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
322            $($rest)*
323        )
324    };
325    // class("arm") → "aarch64" || ["arm64ec"] || "arm"
326    // Depend on the `arch-arm64ec` feature.
327    (
328        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
329        (($($added: tt,)*) (class("arm") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
330    ) => {
331        $crate::__tgtfeat_dispatch_class_helper_arm64ec!(
332            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
333            (($($added,)*) (class("arm") $(|| $($arch2 $(($arch2_arg))?)||+)?) ($($if)*))
334            $($rest)*
335        )
336    };
337    // class("mips") → "mips" || "mips64" || ["mips32r6"] || ["mips64r6"]
338    // Depend on the `arch-mips-r6` feature.
339    (
340        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
341        (($($added: tt,)*) (class("mips") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
342    ) => {
343        $crate::__tgtfeat_dispatch_class_helper_mips_r6!(
344            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
345            (($($added,)*) (class("mips") $(|| $($arch2 $(($arch2_arg))?)||+)?) ($($if)*))
346            $($rest)*
347        )
348    };
349    // class("mips-classic") → "mips" || "mips64"
350    (
351        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
352        (($($added: tt,)*) (class("mips-classic") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
353    ) => {
354        $crate::target_feature_dispatch!(
355            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
356            (($($added,)* "mips", "mips64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
357            $($rest)*
358        )
359    };
360    // class("mipsr6") → "mips32r6" || "mips64r6"
361    (
362        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
363        (($($added: tt,)*) (class("mipsr6") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
364    ) => {
365        $crate::target_feature_dispatch!(
366            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
367            (($($added,)* "mips32r6", "mips64r6",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
368            $($rest)*
369        )
370    };
371    // class("powerpc") → "powerpc" || "powerpc64"
372    (
373        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
374        (($($added: tt,)*) (class("powerpc") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
375    ) => {
376        $crate::target_feature_dispatch!(
377            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
378            (($($added,)* "powerpc", "powerpc64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
379            $($rest)*
380        )
381    };
382    // class("sparc") → "sparc" || "sparc64"
383    (
384        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
385        (($($added: tt,)*) (class("sparc") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
386    ) => {
387        $crate::target_feature_dispatch!(
388            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
389            (($($added,)* "sparc", "sparc64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
390            $($rest)*
391        )
392    };
393    // class("wasm") → "wasm32" || "wasm64"
394    (
395        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
396        (($($added: tt,)*) (class("wasm") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
397    ) => {
398        $crate::target_feature_dispatch!(
399            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
400            (($($added,)* "wasm32", "wasm64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
401            $($rest)*
402        )
403    };
404    // Others
405    (
406        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
407        (($($added: tt,)*) ($arch1: tt ($arch1_arg: tt) $(|| $($arch2: tt$(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
408    ) => {
409        compile_error!(concat!("Invalid architecture specifier: ", stringify!($arch1($arch1_arg))));
410    };
411    (
412        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
413        (($($added: tt,)*) ($arch1: tt $(|| $($arch2: tt$(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
414    ) => {
415        $crate::target_feature_dispatch!(
416            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
417            (($($added,)* $arch1,) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
418            $($rest)*
419        )
420    };
421    // Architectural branch conversion is completed.
422    (
423        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
424        (($($added: tt,)+) () ($($if: tt)*)) $($rest: tt)*
425    ) => {
426        {
427            #[cfg(any($(target_arch = $added),+))]
428            {
429                $crate::target_feature_dispatch!(
430                    @__tgtfeat_dispatch_arch_clause ($($added)||+) ($($opts),*)
431                    ($($else)*) ($($if)*)
432                )
433            }
434            #[cfg(not(any($(target_arch = $added),+)))]
435            {
436                $crate::target_feature_dispatch!(
437                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
438                    ($($else)*) $($rest)*
439                )
440            }
441        }
442    };
443
444    /*
445        Architecture-specific clause (one of architectural `if`).
446
447        If the `else` clause is missing, fallback for static dispatching is of
448        the root and fallback for dynamic dispatching is none
449        (meaning, do the "last resort" static dispatching as a fallback).
450
451        If the `else` clause exists, it is always used as the final fallback
452        (for both static and dynamic dispatching methods).
453
454        If one of the following is specified:
455
456        1.  ( EXPR )
457        2.  { /* statements (results in an expression) */ }
458        3.  (empty)
459
460        This is an architecture-only dispatch.
461    */
462    // `if`-`else` chain without `else`.
463    (
464        @__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*)
465        ($(if $($feat: tt)&&+ { $($if: tt)* })else+)
466    ) => {
467        $crate::target_feature_dispatch!(
468            @__tgtfeat_dispatch_feat_chain_entry
469            ($($arch$(($arch_arg))?)||+) ($($opts),*)
470            ($($else1)*) (@__tgtfeat_dispatch_no_fallback)
471            $((($($feat)&&+) ($($if)*)))+
472        )
473    };
474    // `if`-`else` chain with invalid `else`.
475    (
476        @__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*)
477        ($(if $($feat: tt)&&+ { $($if: tt)* })else+ else { @__tgtfeat_dispatch_no_fallback })
478    ) => {
479        compile_error!("invalid feature-specific `else` clause");
480    };
481    // `if`-`else` chain with `else`.
482    (
483        @__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*)
484        ($(if $($feat: tt)&&+ { $($if: tt)* })else+ else { $($else2: tt)* })
485    ) => {
486        $crate::target_feature_dispatch!(
487            @__tgtfeat_dispatch_feat_chain_entry
488            ($($arch$(($arch_arg))?)||+) ($($opts),*)
489            ($($else2)*) ($($else2)*)
490            $((($($feat)&&+) ($($if)*)))+
491        )
492    };
493    // Architecture-only dispatch: Single expression enclosed by parens.
494    (@__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*) (($expr: expr))) => {
495        $expr
496    };
497    // Architecture-only dispatch: Single block results in an expression.
498    (@__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*) ({$($tt: tt)*})) => {
499        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($tt)*)
500    };
501    // Architecture-only dispatch: Empty (handle as returning the unit value).
502    (@__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*) ()) => {
503        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr ())
504    };
505    // Invalid architecture clause.
506    (@__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*) ($($tt: tt)*)) => {
507        compile_error!("unsupported or invalid architecture clause");
508    };
509
510    /*
511        Feature-specific `if`-`else` chain (entrypoint).
512        Determine dispatching based on the architecture.
513
514        $else_sta is used on fallback static dispatch path.
515        $else_dyn is either fallback on dynamic dispatch path or
516        special keyword "@__tgtfeat_dispatch_no_fallback" meaning none.
517    */
518    // Arm / AArch64 (64-bit): AArch64 + Arm64EC
519    (@__tgtfeat_dispatch_feat_chain_entry (family("aarch64")) ($($opts: meta),*) $($rest: tt)+) => {
520        $crate::target_feature_dispatch!(
521            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
522            (::std::arch::is_aarch64_feature_detected) $($rest)+
523        )
524    };
525    (@__tgtfeat_dispatch_feat_chain_entry ("aarch64") ($($opts: meta),*) $($rest: tt)+) => {
526        $crate::target_feature_dispatch!(
527            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
528            (::std::arch::is_aarch64_feature_detected) $($rest)+
529        )
530    };
531    (@__tgtfeat_dispatch_feat_chain_entry ("arm64ec") ($($opts: meta),*) $($rest: tt)+) => {
532        $crate::target_feature_dispatch!(
533            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
534            (::std::arch::is_aarch64_feature_detected) $($rest)+
535        )
536    };
537    // RISC-V (32-bit and 64-bit)
538    // Depend on the `stable-std-riscv` feature.
539    (@__tgtfeat_dispatch_feat_chain_entry (family("riscv")) ($($opts: meta),*) $($rest: tt)+) => {
540        $crate::__tgtfeat_dispatch_dispatch_helper_riscv!(($($opts),*) $($rest)+)
541    };
542    (@__tgtfeat_dispatch_feat_chain_entry ("riscv32") ($($opts: meta),*) $($rest: tt)+) => {
543        $crate::__tgtfeat_dispatch_dispatch_helper_riscv!(($($opts),*) $($rest)+)
544    };
545    (@__tgtfeat_dispatch_feat_chain_entry ("riscv64") ($($opts: meta),*) $($rest: tt)+) => {
546        $crate::__tgtfeat_dispatch_dispatch_helper_riscv!(($($opts),*) $($rest)+)
547    };
548    // x86 (32-bit and 64-bit)
549    (@__tgtfeat_dispatch_feat_chain_entry (family("x86")) ($($opts: meta),*) $($rest: tt)+) => {
550        $crate::target_feature_dispatch!(
551            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
552            (::std::arch::is_x86_feature_detected) $($rest)+
553        )
554    };
555    (@__tgtfeat_dispatch_feat_chain_entry ("x86") ($($opts: meta),*) $($rest: tt)+) => {
556        $crate::target_feature_dispatch!(
557            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
558            (::std::arch::is_x86_feature_detected) $($rest)+
559        )
560    };
561    (@__tgtfeat_dispatch_feat_chain_entry ("x86_64") ($($opts: meta),*) $($rest: tt)+) => {
562        $crate::target_feature_dispatch!(
563            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
564            (::std::arch::is_x86_feature_detected) $($rest)+
565        )
566    };
567    // Arm (32-bit)
568    (@__tgtfeat_dispatch_feat_chain_entry ("arm") ($($opts: meta),*) $($rest: tt)+) => {
569        $crate::target_feature_dispatch!(
570            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
571            (::std::arch::is_arm_feature_detected) $($rest)+
572        )
573    };
574    // LoongArch (64-bit)
575    (@__tgtfeat_dispatch_feat_chain_entry ("loongarch64") ($($opts: meta),*) $($rest: tt)+) => {
576        $crate::target_feature_dispatch!(
577            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
578            (::std::arch::is_loongarch_feature_detected) $($rest)+
579        )
580    };
581    // MIPS (32-bit)
582    (@__tgtfeat_dispatch_feat_chain_entry ("mips") ($($opts: meta),*) $($rest: tt)+) => {
583        $crate::target_feature_dispatch!(
584            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
585            (::std::arch::is_mips_feature_detected) $($rest)+
586        )
587    };
588    // MIPS (64-bit)
589    (@__tgtfeat_dispatch_feat_chain_entry ("mips64") ($($opts: meta),*) $($rest: tt)+) => {
590        $crate::target_feature_dispatch!(
591            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
592            (::std::arch::is_mips64_feature_detected) $($rest)+
593        )
594    };
595    // PowerPC (32-bit)
596    (@__tgtfeat_dispatch_feat_chain_entry ("powerpc") ($($opts: meta),*) $($rest: tt)+) => {
597        $crate::target_feature_dispatch!(
598            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
599            (::std::arch::is_powerpc_feature_detected) $($rest)+
600        )
601    };
602    // PowerPC (64-bit)
603    (@__tgtfeat_dispatch_feat_chain_entry ("powerpc64") ($($opts: meta),*) $($rest: tt)+) => {
604        $crate::target_feature_dispatch!(
605            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
606            (::std::arch::is_powerpc64_feature_detected) $($rest)+
607        )
608    };
609    // s390x (z/Architecture starting with IBM zSeries; 64-bit)
610    (@__tgtfeat_dispatch_feat_chain_entry ("s390x") ($($opts: meta),*) $($rest: tt)+) => {
611        $crate::target_feature_dispatch!(
612            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
613            (::std::arch::is_s390x_feature_detected) $($rest)+
614        )
615    };
616    // Arm (32-bit and 64-bit)
617    (@__tgtfeat_dispatch_feat_chain_entry (class("arm")) ($($opts: meta),*) $($rest: tt)+) => {
618        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
619    };
620    // MIPS (32-bit and 64-bit)
621    (@__tgtfeat_dispatch_feat_chain_entry (class("mips")) ($($opts: meta),*) $($rest: tt)+) => {
622        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
623    };
624    // MIPS (32-bit and 64-bit) - classic variant
625    (@__tgtfeat_dispatch_feat_chain_entry (class("mips-classic")) ($($opts: meta),*) $($rest: tt)+) => {
626        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
627    };
628    // MIPS (32-bit and 64-bit) - ISA Release 6
629    (@__tgtfeat_dispatch_feat_chain_entry (class("mipsr6")) ($($opts: meta),*) $($rest: tt)+) => {
630        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
631    };
632    // PowerPC (32-bit and 64-bit)
633    (@__tgtfeat_dispatch_feat_chain_entry (class("powerpc")) ($($opts: meta),*) $($rest: tt)+) => {
634        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
635    };
636    // SPARC (32-bit and 64-bit)
637    (@__tgtfeat_dispatch_feat_chain_entry (class("sparc")) ($($opts: meta),*) $($rest: tt)+) => {
638        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
639    };
640    // WebAssembly (32-bit and 64-bit)
641    (@__tgtfeat_dispatch_feat_chain_entry (class("wasm")) ($($opts: meta),*) $($rest: tt)+) => {
642        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
643    };
644    // Others (use static dispatching only)
645    (@__tgtfeat_dispatch_feat_chain_entry ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) $($rest: tt)+) => {
646        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
647    };
648
649    /*
650        Feature-specific `if`-`else` chain (with specific dispatching).
651    */
652    // Dynamic dispatching (if enabled).
653    (
654        @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($dyn: meta, $nightly: meta) ($detect: path)
655        ($($else_sta: tt)*) ($($else_dyn: tt)*) $($rest: tt)+
656    ) => {
657        {
658            #[cfg($dyn)]
659            {
660                $crate::target_feature_dispatch!(
661                    @__tgtfeat_dispatch_feat_chain_dynamic
662                    ($detect)
663                    ($($else_sta)*) ($($else_dyn)*) $($rest)+
664                )
665            }
666            #[cfg(not($dyn))]
667            {
668                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_static ($($else_sta)*) $($rest)+)
669            }
670        }
671    };
672    // Dynamic dispatching only on Nightly (and if enabled).
673    (
674        @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($dyn: meta, $nightly: meta) ($detect: path)
675        ($($else_sta: tt)*) ($($else_dyn: tt)*) $($rest: tt)+
676    ) => {
677        {
678            #[cfg(all($dyn, $nightly))]
679            {
680                $crate::target_feature_dispatch!(
681                    @__tgtfeat_dispatch_feat_chain_dynamic
682                    ($detect)
683                    ($($else_sta)*) ($($else_dyn)*) $($rest)+
684                )
685            }
686            #[cfg(not(all($dyn, $nightly)))]
687            {
688                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_static ($($else_sta)*) $($rest)+)
689            }
690        }
691    };
692    // Static (only) dispatching.
693    (
694        @__tgtfeat_dispatch_feat_chain_dispatch_static ($dyn: meta, $nightly: meta)
695        ($($else_sta: tt)*) ($($else_dyn: tt)*) $($rest: tt)+
696    ) => {
697        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_static ($($else_sta)*) $($rest)+)
698    };
699
700    /*
701        Feature-specific dynamic dispatching.
702    */
703    // No feature-specific fallback
704    // (use static dispatching with global fallback).
705    (
706        @__tgtfeat_dispatch_feat_chain_dynamic ($detect: path)
707        ($($else_sta: tt)*) (@__tgtfeat_dispatch_no_fallback) $((($($feat: tt)&&+) ($($if: tt)*)))+
708    ) => {
709        $(
710            if $({$detect!($feat)})&&+ {
711                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($if)*)
712            }
713        )else+
714        else {
715            $crate::target_feature_dispatch!(
716                @__tgtfeat_dispatch_feat_chain_static
717                ($($else_sta)*) $((($($feat)&&+) ($($if)*)))+
718            )
719        }
720    };
721    // Architecture-specific fallback is specified
722    // (always use local fallback).
723    (
724        @__tgtfeat_dispatch_feat_chain_dynamic ($detect: path)
725        ($($else_sta: tt)*) ($($else_dyn: tt)*) $((($($feat: tt)&&+) ($($if: tt)*)))+
726    ) => {
727        $(
728            if $({$detect!($feat)})&&+ {
729                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($if)*)
730            }
731        )else+
732        else {
733            $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($else_dyn)*)
734        }
735    };
736
737    /*
738        Feature-specific static dispatching.
739    */
740    // `if`
741    (@__tgtfeat_dispatch_feat_chain_static ($($else: tt)*) (($($feat: tt)&&+) ($($if: tt)*)) $($rest: tt)*) => {
742        {
743            #[cfg(all($(target_feature = $feat),+))]
744            {
745                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($if)*)
746            }
747            #[cfg(not(all($(target_feature = $feat),+)))]
748            {
749                $crate::target_feature_dispatch!(
750                    @__tgtfeat_dispatch_feat_chain_static
751                    ($($else)*) $($rest)*
752                )
753            }
754        }
755    };
756    // `else`
757    (@__tgtfeat_dispatch_feat_chain_static ($($else: tt)*)) => {
758        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($else)*)
759    };
760
761    // Coerce tokens into an expression.
762    (@__tgtfeat_dispatch_as_expr $expr: expr) => { $expr };
763    // If empty, substitute with the unit value.
764    (@__tgtfeat_dispatch_as_expr) => { () };
765    // If the next coercion (STMTS → { STMTS }) did not make an expression,
766    // raise a compile error.
767    (@__tgtfeat_dispatch_as_expr {$($tt: tt)+}) => {
768        compile_error!(concat!("failed to parse { ", stringify!($($tt)+), "} as expression"));
769    };
770    // Coercion for series of statements (STMTS → { STMTS }).
771    (@__tgtfeat_dispatch_as_expr $($tt: tt)+) => {
772        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr { $($tt)+ } )
773    };
774}
775
776/// Dispatch helper for RISC-V (MSRV 1.78).
777#[cfg(feature = "stable-std-riscv")]
778#[doc(hidden)]
779#[macro_export]
780macro_rules! __tgtfeat_dispatch_dispatch_helper_riscv {
781    (($($opts: meta),*) $($rest: tt)+) => {
782        $crate::target_feature_dispatch!(
783            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
784            (::std::arch::is_riscv_feature_detected) $($rest)+
785        )
786    }
787}
788
789/// Dispatch helper for RISC-V (MSRV 1.78).
790#[cfg(not(feature = "stable-std-riscv"))]
791#[doc(hidden)]
792#[macro_export]
793macro_rules! __tgtfeat_dispatch_dispatch_helper_riscv {
794    (($($opts: meta),*) $($rest: tt)+) => {
795        $crate::target_feature_dispatch!(
796            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
797            (::std::arch::is_riscv_feature_detected) $($rest)+
798        )
799    }
800}
801
802/// Architecture Grouping helper for MIPS (MSRV 1.73).
803#[cfg(feature = "arch-mips-r6")]
804#[doc(hidden)]
805#[macro_export]
806macro_rules! __tgtfeat_dispatch_class_helper_mips_r6 {
807    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("mips")) ($($if: tt)*)) $($rest: tt)*) => {
808        {
809            #[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "mips32r6", target_arch = "mips64r6"))]
810            {
811                $crate::target_feature_dispatch!(
812                    @__tgtfeat_dispatch_arch_clause (class("mips")) ($($opts),*)
813                    ($($else)*) ($($if)*)
814                )
815            }
816            #[cfg(not(any(target_arch = "mips", target_arch = "mips64", target_arch = "mips32r6", target_arch = "mips64r6")))]
817            {
818                $crate::target_feature_dispatch!(
819                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
820                    ($($else)*) $($rest)*
821                )
822            }
823        }
824    };
825    (
826        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
827        (($($added: tt,)*) (class("mips") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
828    ) => {
829        $crate::target_feature_dispatch!(
830            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
831            (($($added,)* "mips", "mips64", "mips32r6", "mips64r6",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
832            $($rest)*
833        )
834    };
835}
836
837/// Architecture Grouping helper for MIPS (MSRV 1.73).
838#[cfg(not(feature = "arch-mips-r6"))]
839#[doc(hidden)]
840#[macro_export]
841macro_rules! __tgtfeat_dispatch_class_helper_mips_r6 {
842    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("mips")) ($($if: tt)*)) $($rest: tt)*) => {
843        {
844            #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
845            {
846                $crate::target_feature_dispatch!(
847                    @__tgtfeat_dispatch_arch_clause (class("mips")) ($($opts),*)
848                    ($($else)*) ($($if)*)
849                )
850            }
851            #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
852            {
853                $crate::target_feature_dispatch!(
854                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
855                    ($($else)*) $($rest)*
856                )
857            }
858        }
859    };
860    (
861        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
862        (($($added: tt,)*) (class("mips") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
863    ) => {
864        $crate::target_feature_dispatch!(
865            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
866            (($($added,)* "mips", "mips64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
867            $($rest)*
868        )
869    };
870}
871
872/// Architecture Grouping helper for Arm64EC (MSRV 1.78).
873#[cfg(feature = "arch-arm64ec")]
874#[doc(hidden)]
875#[macro_export]
876macro_rules! __tgtfeat_dispatch_class_helper_arm64ec {
877    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((family("aarch64")) ($($if: tt)*)) $($rest: tt)*) => {
878        {
879            #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))]
880            {
881                $crate::target_feature_dispatch!(
882                    @__tgtfeat_dispatch_arch_clause (family("aarch64")) ($($opts),*)
883                    ($($else)*) ($($if)*)
884                )
885            }
886            #[cfg(not(any(target_arch = "aarch64", target_arch = "arm64ec")))]
887            {
888                $crate::target_feature_dispatch!(
889                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
890                    ($($else)*) $($rest)*
891                )
892            }
893        }
894    };
895    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("arm")) ($($if: tt)*)) $($rest: tt)*) => {
896        {
897            #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm"))]
898            {
899                $crate::target_feature_dispatch!(
900                    @__tgtfeat_dispatch_arch_clause (class("arm")) ($($opts),*)
901                    ($($else)*) ($($if)*)
902                )
903            }
904            #[cfg(not(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm")))]
905            {
906                $crate::target_feature_dispatch!(
907                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
908                    ($($else)*) $($rest)*
909                )
910            }
911        }
912    };
913    (
914        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
915        (($($added: tt,)*) (family("aarch64") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
916    ) => {
917        $crate::target_feature_dispatch!(
918            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
919            (($($added,)* "aarch64", "arm64ec",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
920            $($rest)*
921        )
922    };
923    (
924        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
925        (($($added: tt,)*) (class("arm") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
926    ) => {
927        $crate::target_feature_dispatch!(
928            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
929            (($($added,)* "aarch64", "arm64ec", "arm",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
930            $($rest)*
931        )
932    };
933}
934
935/// Architecture Grouping helper for Arm64EC (MSRV 1.78).
936#[cfg(not(feature = "arch-arm64ec"))]
937#[doc(hidden)]
938#[macro_export]
939macro_rules! __tgtfeat_dispatch_class_helper_arm64ec {
940    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((family("aarch64")) ($($if: tt)*)) $($rest: tt)*) => {
941        {
942            #[cfg(any(target_arch = "aarch64"))]
943            {
944                $crate::target_feature_dispatch!(
945                    @__tgtfeat_dispatch_arch_clause (family("aarch64")) ($($opts),*)
946                    ($($else)*) ($($if)*)
947                )
948            }
949            #[cfg(not(any(target_arch = "aarch64")))]
950            {
951                $crate::target_feature_dispatch!(
952                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
953                    ($($else)*) $($rest)*
954                )
955            }
956        }
957    };
958    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("arm")) ($($if: tt)*)) $($rest: tt)*) => {
959        {
960            #[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
961            {
962                $crate::target_feature_dispatch!(
963                    @__tgtfeat_dispatch_arch_clause (class("arm")) ($($opts),*)
964                    ($($else)*) ($($if)*)
965                )
966            }
967            #[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
968            {
969                $crate::target_feature_dispatch!(
970                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
971                    ($($else)*) $($rest)*
972                )
973            }
974        }
975    };
976    (
977        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
978        (($($added: tt,)*) (family("aarch64") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
979    ) => {
980        $crate::target_feature_dispatch!(
981            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
982            (($($added,)* "aarch64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
983            $($rest)*
984        )
985    };
986    (
987        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
988        (($($added: tt,)*) (class("arm") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
989    ) => {
990        $crate::target_feature_dispatch!(
991            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
992            (($($added,)* "aarch64", "arm",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
993            $($rest)*
994        )
995    };
996}