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    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((family("aarch64")) ($($if: tt)*)) $($rest: tt)*) => {
129        {
130            #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))]
131            {
132                $crate::target_feature_dispatch!(
133                    @__tgtfeat_dispatch_arch_clause (family("aarch64")) ($($opts),*)
134                    ($($else)*) ($($if)*)
135                )
136            }
137            #[cfg(not(any(target_arch = "aarch64", target_arch = "arm64ec")))]
138            {
139                $crate::target_feature_dispatch!(
140                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
141                    ($($else)*) $($rest)*
142                )
143            }
144        }
145    };
146    // `if`: family("riscv") → any(target_arch = "riscv32", target_arch = "riscv64")
147    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((family("riscv")) ($($if: tt)*)) $($rest: tt)*) => {
148        {
149            #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
150            {
151                $crate::target_feature_dispatch!(
152                    @__tgtfeat_dispatch_arch_clause (family("riscv")) ($($opts),*)
153                    ($($else)*) ($($if)*)
154                )
155            }
156            #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
157            {
158                $crate::target_feature_dispatch!(
159                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
160                    ($($else)*) $($rest)*
161                )
162            }
163        }
164    };
165    // `if`: family("x86") → any(target_arch = "x86", target_arch = "x86_64")
166    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((family("x86")) ($($if: tt)*)) $($rest: tt)*) => {
167        {
168            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
169            {
170                $crate::target_feature_dispatch!(
171                    @__tgtfeat_dispatch_arch_clause (family("x86")) ($($opts),*)
172                    ($($else)*) ($($if)*)
173                )
174            }
175            #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
176            {
177                $crate::target_feature_dispatch!(
178                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
179                    ($($else)*) $($rest)*
180                )
181            }
182        }
183    };
184    // `if`: class("arm") → any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm")
185    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("arm")) ($($if: tt)*)) $($rest: tt)*) => {
186        {
187            #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm"))]
188            {
189                $crate::target_feature_dispatch!(
190                    @__tgtfeat_dispatch_arch_clause (class("arm")) ($($opts),*)
191                    ($($else)*) ($($if)*)
192                )
193            }
194            #[cfg(not(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm")))]
195            {
196                $crate::target_feature_dispatch!(
197                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
198                    ($($else)*) $($rest)*
199                )
200            }
201        }
202    };
203    // `if`: class("mips") → any(target_arch = "mips", target_arch = "mips64", target_arch = "mips32r6", target_arch = "mips64r6")
204    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("mips")) ($($if: tt)*)) $($rest: tt)*) => {
205        {
206            #[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "mips32r6", target_arch = "mips64r6"))]
207            {
208                $crate::target_feature_dispatch!(
209                    @__tgtfeat_dispatch_arch_clause (class("mips")) ($($opts),*)
210                    ($($else)*) ($($if)*)
211                )
212            }
213            #[cfg(not(any(target_arch = "mips", target_arch = "mips64", target_arch = "mips32r6", target_arch = "mips64r6")))]
214            {
215                $crate::target_feature_dispatch!(
216                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
217                    ($($else)*) $($rest)*
218                )
219            }
220        }
221    };
222    // `if`: class("mips-classic") → any(target_arch = "mips", target_arch = "mips64")
223    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("mips-classic")) ($($if: tt)*)) $($rest: tt)*) => {
224        {
225            #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
226            {
227                $crate::target_feature_dispatch!(
228                    @__tgtfeat_dispatch_arch_clause (class("mips-classic")) ($($opts),*)
229                    ($($else)*) ($($if)*)
230                )
231            }
232            #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
233            {
234                $crate::target_feature_dispatch!(
235                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
236                    ($($else)*) $($rest)*
237                )
238            }
239        }
240    };
241    // `if`: class("mipsr6") → any(target_arch = "mips32r6", target_arch = "mips64r6")
242    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("mipsr6")) ($($if: tt)*)) $($rest: tt)*) => {
243        {
244            #[cfg(any(target_arch = "mips32r6", target_arch = "mips64r6"))]
245            {
246                $crate::target_feature_dispatch!(
247                    @__tgtfeat_dispatch_arch_clause (class("mipsr6")) ($($opts),*)
248                    ($($else)*) ($($if)*)
249                )
250            }
251            #[cfg(not(any(target_arch = "mips32r6", target_arch = "mips64r6")))]
252            {
253                $crate::target_feature_dispatch!(
254                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
255                    ($($else)*) $($rest)*
256                )
257            }
258        }
259    };
260    // `if`: class("powerpc") → any(target_arch = "powerpc", target_arch = "powerpc64")
261    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("powerpc")) ($($if: tt)*)) $($rest: tt)*) => {
262        {
263            #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
264            {
265                $crate::target_feature_dispatch!(
266                    @__tgtfeat_dispatch_arch_clause (class("powerpc")) ($($opts),*)
267                    ($($else)*) ($($if)*)
268                )
269            }
270            #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
271            {
272                $crate::target_feature_dispatch!(
273                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
274                    ($($else)*) $($rest)*
275                )
276            }
277        }
278    };
279    // `if`: class("sparc") → any(target_arch = "sparc", target_arch = "sparc64")
280    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("sparc")) ($($if: tt)*)) $($rest: tt)*) => {
281        {
282            #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
283            {
284                $crate::target_feature_dispatch!(
285                    @__tgtfeat_dispatch_arch_clause (class("sparc")) ($($opts),*)
286                    ($($else)*) ($($if)*)
287                )
288            }
289            #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))]
290            {
291                $crate::target_feature_dispatch!(
292                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
293                    ($($else)*) $($rest)*
294                )
295            }
296        }
297    };
298    // `if`: class("wasm") → any(target_arch = "wasm32", target_arch = "wasm64")
299    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) ((class("wasm")) ($($if: tt)*)) $($rest: tt)*) => {
300        {
301            #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
302            {
303                $crate::target_feature_dispatch!(
304                    @__tgtfeat_dispatch_arch_clause (class("wasm")) ($($opts),*)
305                    ($($else)*) ($($if)*)
306                )
307            }
308            #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
309            {
310                $crate::target_feature_dispatch!(
311                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
312                    ($($else)*) $($rest)*
313                )
314            }
315        }
316    };
317    // `if`: Generic (others): pass to the final step below.
318    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*) (($($arch: tt $(($arch_arg: tt))?)||+) ($($if: tt)*)) $($rest: tt)*) => {
319        $crate::target_feature_dispatch!(
320            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
321            (() ($($arch$(($arch_arg))?)||+) ($($if)*)) $($rest)*
322        )
323    };
324    // `else`
325    (@__tgtfeat_dispatch_arch_chain ($($opts: meta),*) ($($else: tt)*)) => {
326        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($else)*)
327    };
328
329    /*
330        Architecture-specific `if`-`else` chain: `if` (final step)
331        Conversion to regular list of architectures.
332    */
333    // family("aarch64") → "aarch64" || "arm64ec"
334    (
335        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
336        (($($added: tt,)*) (family("aarch64") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
337    ) => {
338        $crate::target_feature_dispatch!(
339            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
340            (($($added,)* "aarch64", "arm64ec",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
341            $($rest)*
342        )
343    };
344    // family("riscv") → "riscv32" || "riscv64"
345    (
346        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
347        (($($added: tt,)*) (family("riscv") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
348    ) => {
349        $crate::target_feature_dispatch!(
350            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
351            (($($added,)* "riscv32", "riscv64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
352            $($rest)*
353        )
354    };
355    // family("x86") → "x86" || "x86_64"
356    (
357        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
358        (($($added: tt,)*) (family("x86") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
359    ) => {
360        $crate::target_feature_dispatch!(
361            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
362            (($($added,)* "x86", "x86_64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
363            $($rest)*
364        )
365    };
366    // class("arm") → "aarch64" || "arm64ec" || "arm"
367    (
368        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
369        (($($added: tt,)*) (class("arm") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
370    ) => {
371        $crate::target_feature_dispatch!(
372            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
373            (($($added,)* "aarch64", "arm64ec", "arm",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
374            $($rest)*
375        )
376    };
377    // class("mips") → "mips" || "mips64" || "mips32r6" || "mips64r6"
378    (
379        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
380        (($($added: tt,)*) (class("mips") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
381    ) => {
382        $crate::target_feature_dispatch!(
383            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
384            (($($added,)* "mips", "mips64", "mips32r6", "mips64r6",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
385            $($rest)*
386        )
387    };
388    // class("mips-classic") → "mips" || "mips64"
389    (
390        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
391        (($($added: tt,)*) (class("mips-classic") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
392    ) => {
393        $crate::target_feature_dispatch!(
394            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
395            (($($added,)* "mips", "mips64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
396            $($rest)*
397        )
398    };
399    // class("mipsr6") → "mips32r6" || "mips64r6"
400    (
401        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
402        (($($added: tt,)*) (class("mipsr6") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
403    ) => {
404        $crate::target_feature_dispatch!(
405            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
406            (($($added,)* "mips32r6", "mips64r6",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
407            $($rest)*
408        )
409    };
410    // class("powerpc") → "powerpc" || "powerpc64"
411    (
412        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
413        (($($added: tt,)*) (class("powerpc") $(|| $($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,)* "powerpc", "powerpc64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
418            $($rest)*
419        )
420    };
421    // class("sparc") → "sparc" || "sparc64"
422    (
423        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
424        (($($added: tt,)*) (class("sparc") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
425    ) => {
426        $crate::target_feature_dispatch!(
427            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
428            (($($added,)* "sparc", "sparc64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
429            $($rest)*
430        )
431    };
432    // class("wasm") → "wasm32" || "wasm64"
433    (
434        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
435        (($($added: tt,)*) (class("wasm") $(|| $($arch2: tt $(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
436    ) => {
437        $crate::target_feature_dispatch!(
438            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
439            (($($added,)* "wasm32", "wasm64",) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
440            $($rest)*
441        )
442    };
443    // Others
444    (
445        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
446        (($($added: tt,)*) ($arch1: tt ($arch1_arg: tt) $(|| $($arch2: tt$(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
447    ) => {
448        compile_error!(concat!("Invalid architecture specifier: ", stringify!($arch1($arch1_arg))));
449    };
450    (
451        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
452        (($($added: tt,)*) ($arch1: tt $(|| $($arch2: tt$(($arch2_arg: tt))?)||+)?) ($($if: tt)*)) $($rest: tt)*
453    ) => {
454        $crate::target_feature_dispatch!(
455            @__tgtfeat_dispatch_arch_chain_2 ($($opts),*) ($($else)*)
456            (($($added,)* $arch1,) ($($($arch2$(($arch2_arg))?)||+)?) ($($if)*))
457            $($rest)*
458        )
459    };
460    // Architectural branch conversion is completed.
461    (
462        @__tgtfeat_dispatch_arch_chain_2 ($($opts: meta),*) ($($else: tt)*)
463        (($($added: tt,)+) () ($($if: tt)*)) $($rest: tt)*
464    ) => {
465        {
466            #[cfg(any($(target_arch = $added),+))]
467            {
468                $crate::target_feature_dispatch!(
469                    @__tgtfeat_dispatch_arch_clause ($($added)||+) ($($opts),*)
470                    ($($else)*) ($($if)*)
471                )
472            }
473            #[cfg(not(any($(target_arch = $added),+)))]
474            {
475                $crate::target_feature_dispatch!(
476                    @__tgtfeat_dispatch_arch_chain ($($opts),*)
477                    ($($else)*) $($rest)*
478                )
479            }
480        }
481    };
482
483    /*
484        Architecture-specific clause (one of architectural `if`).
485
486        If the `else` clause is missing, fallback for static dispatching is of
487        the root and fallback for dynamic dispatching is none
488        (meaning, do the "last resort" static dispatching as a fallback).
489
490        If the `else` clause exists, it is always used as the final fallback
491        (for both static and dynamic dispatching methods).
492
493        If one of the following is specified:
494
495        1.  ( EXPR )
496        2.  { /* statements (results in an expression) */ }
497        3.  (empty)
498
499        This is an architecture-only dispatch.
500    */
501    // `if`-`else` chain without `else`.
502    (
503        @__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*)
504        ($(if $($feat: tt)&&+ { $($if: tt)* })else+)
505    ) => {
506        $crate::target_feature_dispatch!(
507            @__tgtfeat_dispatch_feat_chain_entry
508            ($($arch$(($arch_arg))?)||+) ($($opts),*)
509            ($($else1)*) (@__tgtfeat_dispatch_no_fallback)
510            $((($($feat)&&+) ($($if)*)))+
511        )
512    };
513    // `if`-`else` chain with invalid `else`.
514    (
515        @__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*)
516        ($(if $($feat: tt)&&+ { $($if: tt)* })else+ else { @__tgtfeat_dispatch_no_fallback })
517    ) => {
518        compile_error!("invalid feature-specific `else` clause");
519    };
520    // `if`-`else` chain with `else`.
521    (
522        @__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*)
523        ($(if $($feat: tt)&&+ { $($if: tt)* })else+ else { $($else2: tt)* })
524    ) => {
525        $crate::target_feature_dispatch!(
526            @__tgtfeat_dispatch_feat_chain_entry
527            ($($arch$(($arch_arg))?)||+) ($($opts),*)
528            ($($else2)*) ($($else2)*)
529            $((($($feat)&&+) ($($if)*)))+
530        )
531    };
532    // Architecture-only dispatch: Single expression enclosed by parens.
533    (@__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*) (($expr: expr))) => {
534        $expr
535    };
536    // Architecture-only dispatch: Single block results in an expression.
537    (@__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*) ({$($tt: tt)*})) => {
538        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($tt)*)
539    };
540    // Architecture-only dispatch: Empty (handle as returning the unit value).
541    (@__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*) ()) => {
542        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr ())
543    };
544    // Invalid architecture clause.
545    (@__tgtfeat_dispatch_arch_clause ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) ($($else1: tt)*) ($($tt: tt)*)) => {
546        compile_error!("unsupported or invalid architecture clause");
547    };
548
549    /*
550        Feature-specific `if`-`else` chain (entrypoint).
551        Determine dispatching based on the architecture.
552
553        $else_sta is used on fallback static dispatch path.
554        $else_dyn is either fallback on dynamic dispatch path or
555        special keyword "@__tgtfeat_dispatch_no_fallback" meaning none.
556    */
557    // Arm / AArch64 (64-bit): AArch64 + Arm64EC
558    (@__tgtfeat_dispatch_feat_chain_entry (family("aarch64")) ($($opts: meta),*) $($rest: tt)+) => {
559        $crate::target_feature_dispatch!(
560            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
561            (::std::arch::is_aarch64_feature_detected) $($rest)+
562        )
563    };
564    (@__tgtfeat_dispatch_feat_chain_entry ("aarch64") ($($opts: meta),*) $($rest: tt)+) => {
565        $crate::target_feature_dispatch!(
566            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
567            (::std::arch::is_aarch64_feature_detected) $($rest)+
568        )
569    };
570    (@__tgtfeat_dispatch_feat_chain_entry ("arm64ec") ($($opts: meta),*) $($rest: tt)+) => {
571        $crate::target_feature_dispatch!(
572            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
573            (::std::arch::is_aarch64_feature_detected) $($rest)+
574        )
575    };
576    // RISC-V (32-bit and 64-bit)
577    (@__tgtfeat_dispatch_feat_chain_entry (family("riscv")) ($($opts: meta),*) $($rest: tt)+) => {
578        $crate::target_feature_dispatch!(
579            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
580            (::std::arch::is_riscv_feature_detected) $($rest)+
581        )
582    };
583    (@__tgtfeat_dispatch_feat_chain_entry ("riscv32") ($($opts: meta),*) $($rest: tt)+) => {
584        $crate::target_feature_dispatch!(
585            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
586            (::std::arch::is_riscv_feature_detected) $($rest)+
587        )
588    };
589    (@__tgtfeat_dispatch_feat_chain_entry ("riscv64") ($($opts: meta),*) $($rest: tt)+) => {
590        $crate::target_feature_dispatch!(
591            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
592            (::std::arch::is_riscv_feature_detected) $($rest)+
593        )
594    };
595    // x86 (32-bit and 64-bit)
596    (@__tgtfeat_dispatch_feat_chain_entry (family("x86")) ($($opts: meta),*) $($rest: tt)+) => {
597        $crate::target_feature_dispatch!(
598            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
599            (::std::arch::is_x86_feature_detected) $($rest)+
600        )
601    };
602    (@__tgtfeat_dispatch_feat_chain_entry ("x86") ($($opts: meta),*) $($rest: tt)+) => {
603        $crate::target_feature_dispatch!(
604            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
605            (::std::arch::is_x86_feature_detected) $($rest)+
606        )
607    };
608    (@__tgtfeat_dispatch_feat_chain_entry ("x86_64") ($($opts: meta),*) $($rest: tt)+) => {
609        $crate::target_feature_dispatch!(
610            @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($($opts),*)
611            (::std::arch::is_x86_feature_detected) $($rest)+
612        )
613    };
614    // Arm (32-bit)
615    (@__tgtfeat_dispatch_feat_chain_entry ("arm") ($($opts: meta),*) $($rest: tt)+) => {
616        $crate::target_feature_dispatch!(
617            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
618            (::std::arch::is_arm_feature_detected) $($rest)+
619        )
620    };
621    // LoongArch (64-bit)
622    (@__tgtfeat_dispatch_feat_chain_entry ("loongarch64") ($($opts: meta),*) $($rest: tt)+) => {
623        $crate::target_feature_dispatch!(
624            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
625            (::std::arch::is_loongarch_feature_detected) $($rest)+
626        )
627    };
628    // MIPS (32-bit)
629    (@__tgtfeat_dispatch_feat_chain_entry ("mips") ($($opts: meta),*) $($rest: tt)+) => {
630        $crate::target_feature_dispatch!(
631            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
632            (::std::arch::is_mips_feature_detected) $($rest)+
633        )
634    };
635    // MIPS (64-bit)
636    (@__tgtfeat_dispatch_feat_chain_entry ("mips64") ($($opts: meta),*) $($rest: tt)+) => {
637        $crate::target_feature_dispatch!(
638            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
639            (::std::arch::is_mips64_feature_detected) $($rest)+
640        )
641    };
642    // PowerPC (32-bit)
643    (@__tgtfeat_dispatch_feat_chain_entry ("powerpc") ($($opts: meta),*) $($rest: tt)+) => {
644        $crate::target_feature_dispatch!(
645            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
646            (::std::arch::is_powerpc_feature_detected) $($rest)+
647        )
648    };
649    // PowerPC (64-bit)
650    (@__tgtfeat_dispatch_feat_chain_entry ("powerpc64") ($($opts: meta),*) $($rest: tt)+) => {
651        $crate::target_feature_dispatch!(
652            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
653            (::std::arch::is_powerpc64_feature_detected) $($rest)+
654        )
655    };
656    // s390x (z/Architecture starting with IBM zSeries; 64-bit)
657    (@__tgtfeat_dispatch_feat_chain_entry ("s390x") ($($opts: meta),*) $($rest: tt)+) => {
658        $crate::target_feature_dispatch!(
659            @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($($opts),*)
660            (::std::arch::is_s390x_feature_detected) $($rest)+
661        )
662    };
663    // Arm (32-bit and 64-bit)
664    (@__tgtfeat_dispatch_feat_chain_entry (class("arm")) ($($opts: meta),*) $($rest: tt)+) => {
665        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
666    };
667    // MIPS (32-bit and 64-bit)
668    (@__tgtfeat_dispatch_feat_chain_entry (class("mips")) ($($opts: meta),*) $($rest: tt)+) => {
669        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
670    };
671    // MIPS (32-bit and 64-bit) - classic variant
672    (@__tgtfeat_dispatch_feat_chain_entry (class("mips-classic")) ($($opts: meta),*) $($rest: tt)+) => {
673        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
674    };
675    // MIPS (32-bit and 64-bit) - ISA Release 6
676    (@__tgtfeat_dispatch_feat_chain_entry (class("mipsr6")) ($($opts: meta),*) $($rest: tt)+) => {
677        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
678    };
679    // PowerPC (32-bit and 64-bit)
680    (@__tgtfeat_dispatch_feat_chain_entry (class("powerpc")) ($($opts: meta),*) $($rest: tt)+) => {
681        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
682    };
683    // SPARC (32-bit and 64-bit)
684    (@__tgtfeat_dispatch_feat_chain_entry (class("sparc")) ($($opts: meta),*) $($rest: tt)+) => {
685        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
686    };
687    // WebAssembly (32-bit and 64-bit)
688    (@__tgtfeat_dispatch_feat_chain_entry (class("wasm")) ($($opts: meta),*) $($rest: tt)+) => {
689        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
690    };
691    // Others (use static dispatching only)
692    (@__tgtfeat_dispatch_feat_chain_entry ($($arch: tt $(($arch_arg: tt))?)||+) ($($opts: meta),*) $($rest: tt)+) => {
693        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_dispatch_static ($($opts),*) $($rest)+)
694    };
695
696    /*
697        Feature-specific `if`-`else` chain (with specific dispatching).
698    */
699    // Dynamic dispatching (if enabled).
700    (
701        @__tgtfeat_dispatch_feat_chain_dispatch_dyn ($dyn: meta, $nightly: meta) ($detect: path)
702        ($($else_sta: tt)*) ($($else_dyn: tt)*) $($rest: tt)+
703    ) => {
704        {
705            #[cfg($dyn)]
706            {
707                $crate::target_feature_dispatch!(
708                    @__tgtfeat_dispatch_feat_chain_dynamic
709                    ($detect)
710                    ($($else_sta)*) ($($else_dyn)*) $($rest)+
711                )
712            }
713            #[cfg(not($dyn))]
714            {
715                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_static ($($else_sta)*) $($rest)+)
716            }
717        }
718    };
719    // Dynamic dispatching only on Nightly (and if enabled).
720    (
721        @__tgtfeat_dispatch_feat_chain_dispatch_dyn_nightly ($dyn: meta, $nightly: meta) ($detect: path)
722        ($($else_sta: tt)*) ($($else_dyn: tt)*) $($rest: tt)+
723    ) => {
724        {
725            #[cfg(all($dyn, $nightly))]
726            {
727                $crate::target_feature_dispatch!(
728                    @__tgtfeat_dispatch_feat_chain_dynamic
729                    ($detect)
730                    ($($else_sta)*) ($($else_dyn)*) $($rest)+
731                )
732            }
733            #[cfg(not(all($dyn, $nightly)))]
734            {
735                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_static ($($else_sta)*) $($rest)+)
736            }
737        }
738    };
739    // Static (only) dispatching.
740    (
741        @__tgtfeat_dispatch_feat_chain_dispatch_static ($dyn: meta, $nightly: meta)
742        ($($else_sta: tt)*) ($($else_dyn: tt)*) $($rest: tt)+
743    ) => {
744        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_feat_chain_static ($($else_sta)*) $($rest)+)
745    };
746
747    /*
748        Feature-specific dynamic dispatching.
749    */
750    // No feature-specific fallback
751    // (use static dispatching with global fallback).
752    (
753        @__tgtfeat_dispatch_feat_chain_dynamic ($detect: path)
754        ($($else_sta: tt)*) (@__tgtfeat_dispatch_no_fallback) $((($($feat: tt)&&+) ($($if: tt)*)))+
755    ) => {
756        $(
757            if $({$detect!($feat)})&&+ {
758                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($if)*)
759            }
760        )else+
761        else {
762            $crate::target_feature_dispatch!(
763                @__tgtfeat_dispatch_feat_chain_static
764                ($($else_sta)*) $((($($feat)&&+) ($($if)*)))+
765            )
766        }
767    };
768    // Architecture-specific fallback is specified
769    // (always use local fallback).
770    (
771        @__tgtfeat_dispatch_feat_chain_dynamic ($detect: path)
772        ($($else_sta: tt)*) ($($else_dyn: tt)*) $((($($feat: tt)&&+) ($($if: tt)*)))+
773    ) => {
774        $(
775            if $({$detect!($feat)})&&+ {
776                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($if)*)
777            }
778        )else+
779        else {
780            $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($else_dyn)*)
781        }
782    };
783
784    /*
785        Feature-specific static dispatching.
786    */
787    // `if`
788    (@__tgtfeat_dispatch_feat_chain_static ($($else: tt)*) (($($feat: tt)&&+) ($($if: tt)*)) $($rest: tt)*) => {
789        {
790            #[cfg(all($(target_feature = $feat),+))]
791            {
792                $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($if)*)
793            }
794            #[cfg(not(all($(target_feature = $feat),+)))]
795            {
796                $crate::target_feature_dispatch!(
797                    @__tgtfeat_dispatch_feat_chain_static
798                    ($($else)*) $($rest)*
799                )
800            }
801        }
802    };
803    // `else`
804    (@__tgtfeat_dispatch_feat_chain_static ($($else: tt)*)) => {
805        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr $($else)*)
806    };
807
808    // Coerce tokens into an expression (Rust 2024 needs handling for ConstBlockExpression).
809    (@__tgtfeat_dispatch_as_expr const { $expr: expr } ) => { const { $expr } };
810    (@__tgtfeat_dispatch_as_expr const $($tt: tt)+) => { $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr { const $($tt)+ } ) };
811    (@__tgtfeat_dispatch_as_expr $expr: expr) => { $expr };
812    // If empty, substitute with the unit value.
813    (@__tgtfeat_dispatch_as_expr) => { () };
814    // If the next coercion (STMTS → { STMTS }) did not make an expression,
815    // raise a compile error.
816    (@__tgtfeat_dispatch_as_expr {$($tt: tt)+}) => {
817        compile_error!(concat!("failed to parse { ", stringify!($($tt)+), "} as expression"));
818    };
819    // Coercion for series of statements (STMTS → { STMTS }).
820    (@__tgtfeat_dispatch_as_expr $($tt: tt)+) => {
821        $crate::target_feature_dispatch!(@__tgtfeat_dispatch_as_expr { $($tt)+ } )
822    };
823}