Skip to main content

ctor/
parse.rs

1//! Parser for the `#[ctor]` macro.
2
3#[macro_export]
4#[doc(hidden)]
5macro_rules! __ctor_parse {
6    ( $($input:tt)* ) => {
7        $crate::__perform!(
8            ($($input)*),
9            $crate::__chain[
10                $crate::__parse_item[$crate::__ctor_features],
11                $crate::__extract_unsafe,
12                $crate::__ctor_parse_impl,
13            ]
14        );
15    };
16}
17
18#[macro_export]
19#[doc(hidden)]
20macro_rules! __ctor_parse_internal {
21    ( $features:path, $($input:tt)* ) => {
22        $crate::__perform!(
23            ($($input)*),
24            $crate::__chain[
25                $crate::__parse_item[$features],
26                $crate::__extract_unsafe,
27                $crate::__ctor_parse_impl,
28            ]
29        );
30    };
31}
32
33/// Parse a processed `ctor` item. This is intentionally verbose to avoid
34/// excessive nesting of macro calls in user code.
35#[macro_export]
36#[doc(hidden)]
37macro_rules! __ctor_parse_impl {
38    // Step 1: Feature check
39
40    ( @entry next=$next:path[$next_args:tt], input=(
41        features = (
42            anonymous = $anonymous:tt: $anonymous_spec:ident,
43            body_link_section = $body_link_section:tt: $body_link_section_spec:ident,
44            crate_path = $crate_path:tt: $crate_path_spec:ident,
45            export_name_prefix = $export_name_prefix:tt: $export_name_prefix_spec:ident,
46            link_section = $link_section:tt: $link_section_spec:ident,
47            naked = $naked:tt: $naked_spec:ident,
48            priority = $priority:tt: $priority_spec:ident,
49            priority_enabled = $priority_enabled:tt: $priority_enabled_spec:ident,
50            proc_macro = $proc_macro:tt: $proc_macro_spec:ident,
51            std = $std:tt: $std_spec:ident,
52            r#unsafe = $no_fail_on_missing_unsafe:tt: $no_fail_on_missing_unsafe_spec:ident,
53            used_linker = $used_linker:tt: $used_linker_spec:ident,
54        ),
55        self = $self:tt,
56        meta = $meta:tt,
57        unsafe = $unsafe:tt,
58        item = $item:tt
59    )) => {
60        // Process and validate the priority
61        $crate::__map_priority!(
62            @entry next=$crate::__ctor_parse_impl[[next=$next[$next_args], input=(
63                features = (
64                    anonymous = $anonymous,
65                    linker_options = (
66                        body_link_section = $body_link_section,
67                        export_name_prefix = $export_name_prefix,
68                        link_section = $link_section,
69                        used_linker = $used_linker,
70                    ),
71                    no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe,
72                ),
73                self = $self,
74                meta = $meta,
75                unsafe = $unsafe,
76                item = $item
77            )]], input=(
78                export_name_prefix = ($export_name_prefix: $export_name_prefix_spec),
79                link_section = ($link_section: $link_section_spec),
80                naked = ($naked: $naked_spec),
81                priority = ($priority: $priority_spec),
82                priority_enabled = ($priority_enabled: $priority_enabled_spec),
83            )
84        );
85    };
86
87    ( [next=$next:path[$next_args:tt], input=(
88        features = (
89            anonymous = $anonymous:tt,
90            linker_options = $linker_options:tt,
91            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
92        ),
93        self = $self:tt,
94        meta = $meta:tt,
95        unsafe = $unsafe:tt,
96        item = $item:tt
97    )], $priority:tt ) => {
98        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
99            features = (
100                anonymous = $anonymous,
101                linker_options = $linker_options,
102                no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe,
103                priority = $priority,
104            ),
105            self = $self,
106            meta = $meta,
107            unsafe = $unsafe,
108            item = $item
109        ));
110    };
111
112    // Step 2: Check function shape
113    ( @entry next=$next:path[$next_args:tt], input=(
114        features = (
115            anonymous = $anonymous:tt,
116            linker_options = $linker_options:tt,
117            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
118            priority = $priority:tt,
119        ),
120        self = $self:tt,
121        meta = $meta:tt,
122        unsafe = ($($unsafe:tt)?),
123        item = ($vis:vis $(unsafe)? $( extern $abi:literal )? fn $name:ident () $( -> () )? {
124            $($body:tt)*
125        })
126    ) ) => {
127        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
128            features = (
129                anonymous = $anonymous,
130                linker_options = $linker_options,
131                link_name = $name,
132                no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe,
133                priority = $priority,
134            ),
135            self = $self,
136            meta = $meta,
137            unsafe = ($($unsafe)?),
138            item = ($vis $($unsafe)? $( extern $abi )? fn $name () {
139                $($body)*
140            })
141        ));
142    };
143
144    ( @entry next=$next:path[$next_args:tt], input=(
145        features = (
146            anonymous = $anonymous:tt,
147            linker_options = $linker_options:tt,
148            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
149            priority = $priority:tt,
150        ),
151        self = $self:tt,
152        meta = $meta:tt,
153        unsafe = $unsafe:tt,
154        item = ($vis:vis static $ident:ident : $ty:ty = $(unsafe)? { $literal:literal };)
155    ) ) => {
156        compile_error!("Trivial const expressions are not supported. Remove the #[ctor] and use a regular `static`.");
157    };
158
159    // Allow dynamic #[ctor]s - a const expression determines the actual functions.
160    ( @entry next=$next:path[$next_args:tt], input=(
161        features = (
162            anonymous = $anonymous:tt,
163            linker_options = $linker_options:tt,
164            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
165            priority = $priority:tt,
166        ),
167        self = $self:tt,
168        meta = $meta:tt,
169        unsafe = $unsafe:tt,
170        item = ($vis:vis static $ident:ident : &[fn()] = const $body:block;)
171    ) ) => {
172        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
173            features = (
174                anonymous = $anonymous,
175                linker_options = $linker_options,
176                link_name = $ident,
177                no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe,
178                priority = $priority,
179            ),
180            self = $self,
181            meta = $meta,
182            unsafe = $unsafe,
183            item = ($vis static $ident : &[fn()] = const $body;)
184        ));
185    };
186
187    ( @entry next=$next:path[$next_args:tt], input=(
188        features = (
189            anonymous = $anonymous:tt,
190            linker_options = $linker_options:tt,
191            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
192            priority = $priority:tt,
193        ),
194        self = $self:tt,
195        meta = $meta:tt,
196        unsafe = $unsafe:tt,
197        item = ($vis:vis static $ident:ident : $ty:ty = $(unsafe)? const $body:block;)
198    ) ) => {
199        compile_error!("Static const expressions are not supported. Remove the #[ctor] and use a regular `static`.");
200    };
201
202    ( @entry next=$next:path[$next_args:tt], input=(
203        features = (
204            anonymous = $anonymous:tt,
205            linker_options = $linker_options:tt,
206            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
207            priority = $priority:tt,
208        ),
209        self = $self:tt,
210        meta = $meta:tt,
211        unsafe = $unsafe:tt,
212        item = ($vis:vis static $ident:ident : $ty:ty = $(unsafe)? $literal:literal;)
213    ) ) => {
214        compile_error!("Trivial const expressions are not supported. Remove the #[ctor] and use a regular `static`.");
215    };
216
217    ( @entry next=$next:path[$next_args:tt], input=(
218        features = (
219            anonymous = $anonymous:tt,
220            linker_options = $linker_options:tt,
221            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
222            priority = $priority:tt,
223        ),
224        self = $self:tt,
225        meta = $meta:tt,
226        unsafe = $unsafe:tt,
227        item = ($vis:vis static $ident:ident : &'static dyn $($rest:tt)*)
228    ) ) => {
229        compile_error!("&'static dyn types are not supported. Use a Box<dyn ...> instead.");
230    };
231
232    ( @entry next=$next:path[$next_args:tt], input=(
233        features = (
234            anonymous = $anonymous:tt,
235            linker_options = $linker_options:tt,
236            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
237            priority = $priority:tt,
238        ),
239        self = $self:tt,
240        meta = $meta:tt,
241        unsafe = $unsafe:tt,
242        item = ($vis:vis static $ident:ident : &'static (dyn $($dyn:tt)*) $($rest:tt)*)
243    ) ) => {
244        compile_error!("&'static dyn types are not supported. Use a Box<dyn ...> instead.");
245    };
246
247    ( @entry next=$next:path[$next_args:tt], input=(
248        features = (
249            anonymous = $anonymous:tt,
250            linker_options = $linker_options:tt,
251            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
252            priority = $priority:tt,
253        ),
254        self = $self:tt,
255        meta = $meta:tt,
256        unsafe = ($($unsafe:tt)?),
257        item = ($vis:vis static $ident:ident : & $lt:lifetime $ty:ty = $($body:tt)*)
258    ) ) => {
259        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
260            features = (
261                anonymous = $anonymous,
262                linker_options = $linker_options,
263                link_name = $ident,
264                no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe,
265                priority = $priority,
266            ),
267            self = $self,
268            meta = $meta,
269            unsafe = ($($unsafe)?),
270            item = ($vis static $ident : & $lt $ty = $($body)*)
271        ));
272    };
273
274    ( @entry next=$next:path[$next_args:tt], input=(
275        features = (
276            anonymous = $anonymous:tt,
277            linker_options = $linker_options:tt,
278            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
279            priority = $priority:tt,
280        ),
281        self = $self:tt,
282        meta = $meta:tt,
283        unsafe = ($($unsafe:tt)?),
284        item = ($vis:vis static $ident:ident : $ty:ty = $($body:tt)*)
285    ) ) => {
286        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
287            features = (
288                anonymous = $anonymous,
289                linker_options = $linker_options,
290                link_name = $ident,
291                no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe,
292                priority = $priority,
293            ),
294            self = $self,
295            meta = $meta,
296            unsafe = ($($unsafe)?),
297            item = ($vis static $ident : $ty = $($body)*)
298        ));
299    };
300
301    ( @entry next=$next:path[$next_args:tt], input=(
302        features = (
303            anonymous = $anonymous:tt,
304            linker_options = $linker_options:tt,
305            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
306            priority = $priority:tt,
307        ),
308        self = $self:tt,
309        meta = $meta:tt,
310        unsafe = $unsafe:tt,
311        item = ($item:item)
312    ) ) => {
313        compile_error!("Invalid ctor item. \
314            Expected a function with no args, \
315            return value, or type parameters or a static variable.\n\
316            Valid forms are:\n\
317             - [pub] [unsafe] [extern $abi] fn $name() { ... }\n\
318             - static $name : [&'static] $ty = [unsafe] { ... };");
319    };
320
321    // Step 3: Compute no_fail_on_missing_unsafe
322
323    // Compile error iff no_fail_on_missing_unsafe is not present AND unsafe is not present
324    ( @entry next=$next:path[$next_args:tt], input=(
325        features = (
326            anonymous = $anonymous:tt,
327            linker_options = $linker_options:tt,
328            link_name = $link_name:tt,
329            no_fail_on_missing_unsafe = (),
330            priority = $priority:tt,
331        ),
332        self = ( $macro_name:ident ),
333        meta = $meta:tt,
334        unsafe = (),
335        item = $item:tt
336    ) ) => {
337        compile_error!(concat!("Missing unsafe keyword in #[ctor] annotation. \
338        Use #[ctor(unsafe)]. This error can be suppressed by passing \
339        `--cfg linktime_no_fail_on_missing_unsafe` in `RUSTFLAGS` or placing this in your \
340        `config.toml` file.\n\n\
341        \n\
342        #[ctor]\n\
343        ^^^^^^^------- replace this with #[ctor(unsafe)]"));
344    };
345
346    ( @entry next=$next:path[$next_args:tt], input=(
347        features = (
348            anonymous = $anonymous:tt,
349            linker_options = $linker_options:tt,
350            link_name = $link_name:tt,
351            no_fail_on_missing_unsafe = (),
352            priority = $priority:tt,
353        ),
354        self = ($macro_name:ident ($($self:tt)*) ),
355        meta = $meta:tt,
356        unsafe = (),
357        item = $item:tt
358    ) ) => {
359        compile_error!(concat!("Missing unsafe keyword in #[ctor] annotation. \
360        Use #[ctor(unsafe, ", stringify!($($self)*), ")]. This error can be suppressed by passing \
361        `--cfg linktime_no_fail_on_missing_unsafe` in `RUSTFLAGS` or placing this in your \
362        `config.toml` file.\n\n\
363        \n\
364        #[ctor(", stringify!($($self)*), ")]\n\
365        ^------- replace this with #[ctor(unsafe, ", stringify!($($self)*), ")]\n"));
366    };
367
368    ( @entry next=$next:path[$next_args:tt], input=(
369        features = (
370            anonymous = $anonymous:tt,
371            linker_options = $linker_options:tt,
372            link_name = $link_name:tt,
373            no_fail_on_missing_unsafe = $no_fail_on_missing_unsafe:tt,
374            priority = $priority:tt,
375        ),
376        self = $self:tt,
377        meta = $meta:tt,
378        unsafe = $unsafe:tt,
379        item = $item:tt
380    ) ) => {
381        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
382            features = (
383                anonymous = $anonymous,
384                linker_options = $linker_options,
385                link_name = $link_name,
386                priority = $priority,
387            ),
388            meta = $meta,
389            unsafe = $unsafe,
390            item = $item
391        ));
392    };
393
394    // Step 4: Wrap in anonymous const
395    ( @entry next=$next:path[$next_args:tt], input=(
396        features = (
397            anonymous = (),
398            linker_options = $linker_options:tt,
399            link_name = $link_name:tt,
400            priority = $priority:tt,
401        ),
402        meta = $meta:tt,
403        unsafe = $unsafe:tt,
404        item = $item:tt
405    ) ) => {
406        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
407            features = (
408                linker_options = $linker_options,
409                link_name = $link_name,
410                priority = $priority,
411            ),
412            meta = $meta,
413            unsafe = $unsafe,
414            item = $item
415        ));
416    };
417    ( @entry next=$next:path[$next_args:tt], input=(
418        features = (
419            anonymous = anonymous,
420            linker_options = $linker_options:tt,
421            link_name = $link_name:tt,
422            priority = $priority:tt,
423        ),
424        meta = $meta:tt,
425        unsafe = $unsafe:tt,
426        item = $item:tt
427    ) ) => {
428        const _: () = {
429            $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
430                features = (
431                    linker_options = $linker_options,
432                    link_name = $link_name,
433                    priority = $priority,
434                ),
435                meta = $meta,
436                unsafe = $unsafe,
437                item = $item
438            ));
439        };
440    };
441
442    // Step 5: Compute used_linker
443    ( @entry next=$next:path[$next_args:tt], input=(
444        features = (
445            linker_options = (
446                body_link_section = $body_link_section:tt,
447                export_name_prefix = $export_name_prefix:tt,
448                link_section = $link_section:tt,
449                used_linker = (),
450            ),
451            link_name = $link_name:tt,
452            priority = $priority:tt,
453        ),
454        meta = $meta:tt,
455        unsafe = $unsafe:tt,
456        item = $item:tt
457    ) ) => {
458        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
459            features = (
460                linker_options = (
461                    body_link_section = $body_link_section,
462                    export_name_prefix = $export_name_prefix,
463                    link_section = $link_section,
464                    used_linker_meta = (#[used]),
465                ),
466                link_name = $link_name,
467                priority = $priority,
468            ),
469            meta = $meta,
470            unsafe = $unsafe,
471            item = $item
472        ));
473    };
474
475    ( @entry next=$next:path[$next_args:tt], input=(
476        features = (
477            linker_options = (
478                body_link_section = $body_link_section:tt,
479                export_name_prefix = $export_name_prefix:tt,
480                link_section = $link_section:tt,
481                used_linker = used_linker,
482            ),
483            link_name = $link_name:tt,
484            priority = $priority:tt,
485        ),
486        meta = $meta:tt,
487        unsafe = $unsafe:tt,
488        item = $item:tt
489    ) ) => {
490        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
491            features = (
492                linker_options = (
493                    body_link_section = $body_link_section,
494                    export_name_prefix = $export_name_prefix,
495                    link_section = $link_section,
496                    used_linker_meta = (#[used(linker)]),
497                ),
498                link_name = $link_name,
499                priority = $priority,
500            ),
501            meta = $meta,
502            unsafe = $unsafe,
503            item = $item
504        ));
505    };
506
507    // Step 6: Compute export name suffix
508
509    // No prefix, no computation
510    ( @entry next=$next:path[$next_args:tt], input=(
511        features = (
512            linker_options = (
513                body_link_section = $body_link_section:tt,
514                export_name_prefix = (),
515                link_section = $link_section:tt,
516                used_linker_meta = $used_linker_meta:tt,
517            ),
518            link_name = $link_name:tt,
519            priority = $priority:tt,
520        ),
521        meta = $meta:tt,
522        unsafe = $unsafe:tt,
523        item = $item:tt
524    ) ) => {
525        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
526            features = (
527                linker_options = (
528                    body_link_section = $body_link_section,
529                    export_name = (),
530                    link_section = $link_section,
531                    used_linker_meta = $used_linker_meta,
532                ),
533                priority = $priority,
534            ),
535            meta = $meta,
536            unsafe = $unsafe,
537            item = $item
538        ));
539    };
540
541    ( @entry next=$next:path[$next_args:tt], input=(
542        features = (
543            linker_options = (
544                body_link_section = $body_link_section:tt,
545                export_name_prefix = $export_name_prefix:tt,
546                link_section = $link_section:tt,
547                used_linker_meta = $used_linker_meta:tt,
548            ),
549            link_name = $link_name:tt,
550            priority = $priority:tt,
551        ),
552        meta = $meta:tt,
553        unsafe = $unsafe:tt,
554        item = $item:tt
555    ) ) => {
556        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
557            features = (
558                linker_options = (
559                    body_link_section = $body_link_section,
560                    export_name = (($export_name_prefix), ("_", env!("CARGO_PKG_NAME"), "_",
561                        ::core::module_path!(), "_",
562                        stringify!($link_name),
563                        "_L", line!(), "C", column!())),
564                    link_section = $link_section,
565                    used_linker_meta = $used_linker_meta,
566                ),
567                priority = $priority,
568            ),
569            meta = $meta,
570            unsafe = $unsafe,
571            item = $item
572        ));
573    };
574
575    // Step 7: Compute priority
576
577    // naked with no export name
578    ( @entry next=$next:path[$next_args:tt], input=(
579        features = (
580            linker_options = (
581                body_link_section = $body_link_section:tt,
582                export_name = (),
583                link_section = $link_section:tt,
584                used_linker_meta = $used_linker_meta:tt,
585            ),
586            priority = naked,
587        ),
588        meta = $meta:tt,
589        unsafe = $unsafe:tt,
590        item = $item:tt
591    ) ) => {
592        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
593            link_args = (
594                body_link_section = $body_link_section,
595                export_name = (),
596                link_section = ($link_section),
597                used = $used_linker_meta,
598            ),
599            meta = $meta,
600            unsafe = $unsafe,
601            item = $item
602        ));
603    };
604
605    // naked with export name
606    ( @entry next=$next:path[$next_args:tt], input=(
607        features = (
608            linker_options = (
609                body_link_section = $body_link_section:tt,
610                export_name = (($($prefix:tt)*), ($($suffix:tt)*)),
611                link_section = $link_section:tt,
612                used_linker_meta = $used_linker_meta:tt,
613            ),
614            priority = naked,
615        ),
616        meta = $meta:tt,
617        unsafe = $unsafe:tt,
618        item = $item:tt
619    ) ) => {
620        // AIX uses 80000000 as the priority
621        #[cfg(target_os = "aix")]
622        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
623            link_args = (
624                body_link_section = $body_link_section,
625                export_name = (concat!($($prefix)*, "80000000", $($suffix)*)),
626                link_section = ($link_section),
627                used = $used_linker_meta,
628            ),
629            meta = $meta,
630            unsafe = $unsafe,
631            item = $item
632        ));
633
634        #[cfg(not(target_os = "aix"))]
635        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
636            link_args = (
637                body_link_section = $body_link_section,
638                export_name = (concat!($($prefix)*, $($suffix)*)),
639                link_section = ($link_section),
640                used = $used_linker_meta,
641            ),
642            meta = $meta,
643            unsafe = $unsafe,
644            item = $item
645        ));
646    };
647
648    ( @entry next=$next:path[$next_args:tt], input=(
649        features = (
650            linker_options = (
651                body_link_section = $body_link_section:tt,
652                export_name = $export_name:tt,
653                link_section = $link_section:tt,
654                used_linker_meta = $used_linker_meta:tt,
655            ),
656            priority = $priority:tt,
657        ),
658        meta = $meta:tt,
659        unsafe = $unsafe:tt,
660        item = $item:tt
661    ) ) => {
662        #[cfg(target_vendor = "apple")]
663        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
664            link_args = (
665                body_link_section = $body_link_section,
666                export_name = $export_name,
667                priority = $priority,
668                used = $used_linker_meta,
669            ),
670            meta = $meta,
671            unsafe = $unsafe,
672            item = $item
673        ));
674
675        // Get a priority literal
676        #[cfg(not(target_vendor = "apple"))]
677        $crate::__priority_to_literal!($crate::__ctor_parse_impl,[
678            @priority next=$next[$next_args],
679            features = (
680                body_link_section = $body_link_section,
681                export_name = $export_name,
682                link_section = $link_section,
683                used_linker_meta = $used_linker_meta,
684            ),
685            meta = $meta,
686            unsafe = $unsafe,
687            item = $item
688        ] = $priority);
689    };
690
691    ( @entry next=$next:path[$next_args:tt], input=(
692        features = (
693            linker_options = (
694                body_link_section = $body_link_section:tt,
695                export_name = $export_name:tt,
696                link_section = $link_section:tt,
697                used_linker_meta = $used_linker_meta:tt,
698            ),
699            priority = $priority:tt,
700        ),
701        meta = $meta:tt,
702        unsafe = $unsafe:tt,
703        item = $item:tt
704    ) ) => {
705        compile_error!(concat!("Invalid priority: ", stringify!($priority)));
706    };
707
708    ( [@priority next=$next:path[$next_args:tt],
709        features = (
710            body_link_section = $body_link_section:tt,
711            export_name = (),
712            link_section = $link_section:tt,
713            used_linker_meta = $used_linker_meta:tt,
714        ),
715        meta = $meta:tt,
716        unsafe = $unsafe:tt,
717        item = $item:tt
718    ], ($($priority:tt)*)) => {
719        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
720            link_args = (
721                body_link_section = $body_link_section,
722                export_name = (),
723                link_section = (concat!($link_section, ".", $($priority)*)),
724                used = $used_linker_meta,
725            ),
726            meta = $meta,
727            unsafe = $unsafe,
728            item = $item
729        ));
730    };
731
732    ( [@priority next=$next:path[$next_args:tt],
733        features = (
734            body_link_section = $body_link_section:tt,
735            export_name = (($($prefix:tt)*), ($($suffix:tt)*)),
736            link_section = $link_section:tt,
737            used_linker_meta = $used_linker_meta:tt,
738        ),
739        meta = $meta:tt,
740        unsafe = $unsafe:tt,
741        item = $item:tt
742    ], ($($priority:tt)*)) => {
743        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
744            link_args = (
745                body_link_section = $body_link_section,
746                export_name = (concat!($($prefix)*, $($priority)*, $($suffix)*)),
747                link_section = (concat!($link_section, ".", $($priority)*)),
748                used = $used_linker_meta,
749            ),
750            meta = $meta,
751            unsafe = $unsafe,
752            item = $item
753        ));
754    };
755
756    // Step 8: Compute body link section meta
757    ( @entry next=$next:path[$next_args:tt], input=(
758        link_args = (
759            body_link_section = $($body_link_section:literal)? $( () )?,
760            $($link_args:tt)*
761        ),
762        meta = $meta:tt,
763        unsafe = $unsafe:tt,
764        item = $item:tt
765    ) ) => {
766        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
767            link_args = (
768                body_link_meta = ( $([link_section = $body_link_section])? ),
769                $($link_args)*
770            ),
771            body_link_meta = ( $([link_section = $body_link_section])? ),
772            meta = $meta,
773            unsafe = $unsafe,
774            item = $item
775        ));
776    };
777
778    // Step 9: Delegate on item type
779    ( @entry next=$next:path[$next_args:tt], input=(
780        link_args = $link_args:tt,
781        body_link_meta = ($($body_link_meta:tt)?),
782        meta = ($($meta:tt)*),
783        unsafe = ($($unsafe:tt)*),
784        item = ($vis:vis $(unsafe)? $( extern $abi:literal )? fn $name:ident () $( -> () )? {
785            $($body:tt)*
786        })
787    ) ) => {
788        $($meta)*
789        #[allow(dead_code)]
790        $vis $($unsafe)* $( extern $abi )? fn $name () {
791            // The outer function may be attached to a struct, so we generate an
792            // inner function that is freestanding and call it from both places.
793            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
794            $(#[allow(unsafe_code)] #$body_link_meta)?
795            $($unsafe)* $( extern $abi )? fn __ctor_private_inner() {
796                $($body)*
797            }
798
799            $crate::__ctor_parse_impl!(@ctor $link_args body={ $($unsafe)* { __ctor_private_inner() } });
800            $($unsafe)* { __ctor_private_inner() }
801        }
802    };
803
804    ( @entry next=$next:path[$next_args:tt], input=(
805        link_args = $link_args:tt,
806        body_link_meta = ($($body_link_meta:tt)?),
807        meta = ($($meta:tt)*),
808        unsafe = ($($unsafe:tt)*),
809        item = ($vis:vis static $ident:ident : &[fn()] = const $body:block;)
810    ) ) => {
811        $($meta)*
812        $vis static $ident: &[fn()] = /*const*/ {
813            const __EXTERN_C_FNS: [extern "C" fn(); $ident.len()] = {
814                use ::core::mem::MaybeUninit;
815                let mut array: MaybeUninit<[extern "C" fn(); $ident.len()]> = MaybeUninit::uninit();
816                let mut array_ptr: *mut extern "C" fn() = array.as_mut_ptr() as _;
817
818                extern "C" fn bind_array<const N: usize>() {
819                    $ident[N]()
820                }
821
822                unsafe {
823                    let array_ptr = array.as_mut_ptr() as *mut extern "C" fn();
824                    const LEN: usize = $ident.len();
825                    if LEN > 0 { array_ptr.add(0).write(bind_array::<0>); }
826                    if LEN > 1 { array_ptr.add(1).write(bind_array::<1>); }
827                    if LEN > 2 { array_ptr.add(2).write(bind_array::<2>); }
828                    if LEN > 3 { array_ptr.add(3).write(bind_array::<3>); }
829                    if LEN > 4 { array_ptr.add(4).write(bind_array::<4>); }
830                    if LEN > 5 { array_ptr.add(5).write(bind_array::<5>); }
831                    if LEN > 6 { array_ptr.add(6).write(bind_array::<6>); }
832                    if LEN > 7 { array_ptr.add(7).write(bind_array::<7>); }
833                    if LEN > 8 { array_ptr.add(8).write(bind_array::<8>); }
834                    if LEN > 9 { array_ptr.add(9).write(bind_array::<9>); }
835                    if LEN > 10 { array_ptr.add(10).write(bind_array::<10>); }
836                    if LEN > 11 { array_ptr.add(11).write(bind_array::<11>); }
837                    if LEN > 12 { array_ptr.add(12).write(bind_array::<12>); }
838                    if LEN > 13 { array_ptr.add(13).write(bind_array::<13>); }
839                    if LEN > 14 { array_ptr.add(14).write(bind_array::<14>); }
840                    if LEN > 15 { array_ptr.add(15).write(bind_array::<15>); }
841                    if LEN > 16 {
842                        panic!("Unexpected array length, expected <= 16");
843                    }
844                }
845                unsafe { array.assume_init() }
846            };
847            $crate::__ctor_parse_impl!(@ctor $link_args fns=__EXTERN_C_FNS);
848
849            $body
850        };
851    };
852
853    ( @entry next=$next:path[$next_args:tt], input=(
854        link_args = $link_args:tt,
855        body_link_meta = ($($body_link_meta:tt)?),
856        meta = ($($meta:tt)*),
857        unsafe = ($($unsafe:tt)*),
858        item = ($vis:vis static $ident:ident : & $lt:lifetime $ty:ty = &$($body:tt)*)
859    ) ) => {
860        $($meta)*
861        $vis static $ident: & $lt $crate::statics::Static<$ty> = {
862            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
863            $(#[allow(unsafe_code)] #$body_link_meta)?
864            fn init() -> $ty {
865                return $($body)*
866            }
867
868            static __STATIC_CTOR: $crate::statics::Static<$ty> = {
869                unsafe { $crate::statics::Static::<$ty>::new(init) }
870            };
871            &__STATIC_CTOR
872        };
873        $crate::__ctor_parse_impl!(@ctor $link_args body={ _ = &*$ident } );
874    };
875
876    ( @entry next=$next:path[$next_args:tt], input=(
877        link_args = $link_args:tt,
878        body_link_meta = ($($body_link_meta:tt)?),
879        meta = ($($meta:tt)*),
880        unsafe = ($($unsafe:tt)*),
881        item = ($vis:vis static $ident:ident : & $lt:lifetime $ty:ty = $($body:tt)*)
882    ) ) => {
883        $($meta)*
884        $vis static $ident: $crate::statics::Static<&'static $ty> = {
885            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
886            $(#[allow(unsafe_code)] #$body_link_meta)?
887            fn init() -> &'static $ty {
888                return $($body)*
889            }
890            unsafe { $crate::statics::Static::<&'static $ty>::new(init) }
891        };
892        $crate::__ctor_parse_impl!(@ctor $link_args body={ _ = &*$ident } );
893    };
894
895    ( @entry next=$next:path[$next_args:tt], input=(
896        link_args = $link_args:tt,
897        body_link_meta = ($($body_link_meta:tt)?),
898        meta = ($($meta:tt)*),
899        unsafe = ($($unsafe:tt)*),
900        item = ($vis:vis static $ident:ident : $ty:ty = $($body:tt)*)
901    ) ) => {
902        $($meta)*
903        $vis static $ident: $crate::statics::Static<$ty> = {
904            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
905            $(#[allow(unsafe_code)] #$body_link_meta)?
906            fn init() -> $ty {
907                return $($body)*
908            }
909            unsafe { $crate::statics::Static::<$ty>::new(init) }
910        };
911        $crate::__ctor_parse_impl!(@ctor $link_args body={ _ = &*$ident } );
912    };
913
914    // ctor definitions
915
916    // linux-style, one ctor
917    ( @ctor (
918        body_link_meta = ($($body_link_meta:tt)?),
919        export_name=(),
920        link_section=($($link_section:tt)*),
921        used=(#$used_linker_meta:tt),
922     ) body=$body:tt ) => {
923        const _: () = {
924            #[allow(unsafe_code)]
925            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
926            #[link_section = $($link_section)*]
927            #$used_linker_meta
928            static __CTOR_PRIVATE_REF: unsafe extern "C" fn() = {
929                #[allow(unused_unsafe)]
930                $(#[allow(unsafe_code)] #$body_link_meta)?
931                extern "C" fn __ctor_private() {
932                    #[cfg(all(target_family = "wasm", target_os = "unknown"))]
933                    {
934                        static DISARMED: ::core::sync::atomic::AtomicBool = ::core::sync::atomic::AtomicBool::new(false);
935                        if DISARMED.swap(true, ::core::sync::atomic::Ordering::Relaxed) {
936                            return;
937                        }
938                    }
939                    $body
940                }
941                __ctor_private
942            };
943        };
944    };
945
946    // linux-style, multiple ctor
947    ( @ctor (
948        body_link_meta = ($($body_link_meta:tt)?),
949        export_name=(),
950        link_section=($($link_section:tt)*),
951        used=(#$used_linker_meta:tt),
952     ) fns=$ident:ident ) => {
953        #[allow(unsafe_code)]
954        #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
955        #[link_section = $($link_section)*]
956        #$used_linker_meta
957        static __CTOR_PRIVATE_REF: unsafe extern "C" fn() = {
958            #[allow(unused_unsafe)]
959            $(#[allow(unsafe_code)] #$body_link_meta)?
960            extern "C" fn __ctor_private() {
961                #[cfg(all(target_family = "wasm", target_os = "unknown"))]
962                {
963                    static DISARMED: ::core::sync::atomic::AtomicBool = ::core::sync::atomic::AtomicBool::new(false);
964                    if DISARMED.swap(true, ::core::sync::atomic::Ordering::Relaxed) {
965                        return;
966                    }
967                }
968                for f in $ident {
969                    f();
970                }
971            }
972            __ctor_private
973        };
974    };
975
976    // "collect"-style, one ctor
977    ( @ctor (
978        body_link_meta = ($($body_link_meta:tt)?),
979        export_name=(),
980        priority=$priority:tt,
981        used=(#$used_linker_meta:tt),
982     ) body=$body:tt ) => {
983        const _: () = {
984            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
985            #[allow(unsafe_code, unused_unsafe)]
986            $(#$body_link_meta)?
987            extern "C" fn __ctor_private() {
988                #[cfg(all(target_family = "wasm", target_os = "unknown"))]
989                {
990                    static DISARMED: ::core::sync::atomic::AtomicBool = ::core::sync::atomic::AtomicBool::new(false);
991                    if DISARMED.swap(true, ::core::sync::atomic::Ordering::Relaxed) {
992                        return;
993                    }
994                }
995                $body
996            }
997
998            $crate::__register_ctor!(priority = $priority, fn = __ctor_private);
999        };
1000    };
1001
1002    // "collect"-style, multiple ctors
1003    ( @ctor (
1004        body_link_meta = ($($body_link_meta:tt)?),
1005        export_name=(),
1006        priority=$priority:tt,
1007        used=(#$used_linker_meta:tt),
1008     ) fns=$ident:ident ) => {
1009        const _: () = {
1010            $crate::__register_ctor!(priority = $priority, fn = (array $ident));
1011        };
1012    };
1013
1014    // AIX-style, one ctor
1015    ( @ctor (
1016        body_link_meta = ($($body_link_meta:tt)?),
1017        export_name=($($link_name:tt)*),
1018        link_section=$link_section:tt,
1019        used=(#$used_linker_meta:tt),
1020     ) body=$body:tt ) => {
1021        const _: () = {
1022            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
1023            #[allow(unused_unsafe, unsafe_code)]
1024            #[no_mangle]
1025            #[export_name = $($link_name)*]
1026            $(#$body_link_meta)?
1027            extern "C" fn __ctor_private() {
1028                #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1029                {
1030                    static DISARMED: ::core::sync::atomic::AtomicBool = ::core::sync::atomic::AtomicBool::new(false);
1031                    if DISARMED.swap(true, ::core::sync::atomic::Ordering::Relaxed) {
1032                        return;
1033                    }
1034                }
1035                $body
1036            }
1037        };
1038    };
1039
1040    // AIX-style, multiple ctor
1041    ( @ctor (
1042        body_link_meta = ($($body_link_meta:tt)?),
1043        export_name=($($link_name:tt)*),
1044        link_section=$link_section:tt,
1045        used=(#$used_linker_meta:tt),
1046     ) fns=$ident:ident ) => {
1047        const _: () = {
1048            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
1049            #[allow(unused_unsafe, unsafe_code)]
1050            #[no_mangle]
1051            #[export_name = $($link_name)*]
1052            $(#$body_link_meta)?
1053            extern "C" fn __ctor_private() {
1054                #[cfg(all(target_family = "wasm", target_os = "unknown"))]
1055                {
1056                    static DISARMED: ::core::sync::atomic::AtomicBool = ::core::sync::atomic::AtomicBool::new(false);
1057                    if DISARMED.swap(true, ::core::sync::atomic::Ordering::Relaxed) {
1058                        return;
1059                    }
1060                }
1061                for f in $ident {
1062                    f();
1063                }
1064            }
1065        };
1066    };
1067
1068    (@ctor $features:tt body=$body:tt) => {
1069        compile_error!(concat!("Invalid ctor features: ", stringify!($features)));
1070    };
1071}
1072
1073/// Map the priority input to a priority value. This is somewhat complex because
1074/// the default for priority changes based on whether priority is enabled and
1075/// whether link options are specified.
1076#[macro_export]
1077#[doc(hidden)]
1078macro_rules! __map_priority {
1079    // Priority specified, priority not enabled
1080    ( @entry next=$next:path[$next_args:tt], input=(
1081        export_name_prefix = $enp:tt,
1082        link_section = $ls:tt,
1083        naked = $naked:tt,
1084        priority = ($priority:tt: value),
1085        priority_enabled = ((), $pe_spec:ident),
1086    ) ) => {
1087        compile_error!(concat!("The crate \"priority\" feature was not enabled: `priority = ", stringify!($priority), "` is not supported."));
1088    };
1089
1090    // Priority unspecified, link options not, priority not enabled => naked
1091    ( @entry next=$next:path[$next_args:tt], input=(
1092        export_name_prefix = ($enp:tt: default),
1093        link_section = ($ls:tt: default),
1094        naked = ($naked:tt: default),
1095        priority = ($priority:tt: default),
1096        priority_enabled = ((): $pe_spec:ident),
1097    ) ) => {
1098        $next!($next_args, naked);
1099    };
1100
1101    // Priority unspecified, link options not, priority enabled => default (500)
1102    ( @entry next=$next:path[$next_args:tt], input=(
1103        export_name_prefix = ($enp:tt: default),
1104        link_section = ($ls:tt: default),
1105        naked = ($naked:tt: default),
1106        priority = ($priority:tt: default),
1107        priority_enabled = (priority_enabled: $pe_spec:ident),
1108    ) ) => {
1109        $next!($next_args, 500);
1110    };
1111
1112    // Priority specified (or default) = early, link options not, priority enabled
1113    ( @entry next=$next:path[$next_args:tt], input=(
1114        export_name_prefix = ($enp:tt: default),
1115        link_section = ($ls:tt: default),
1116        naked = ($naked:tt: default),
1117        priority = (early: $p_spec:ident),
1118        priority_enabled = $pe:tt,
1119    ) ) => {
1120        $next!($next_args, 101);
1121    };
1122
1123    // Priority specified (or default) = default, link options not, priority enabled
1124    ( @entry next=$next:path[$next_args:tt], input=(
1125        export_name_prefix = ($enp:tt: default),
1126        link_section = ($ls:tt: default),
1127        naked = ($naked:tt: default),
1128        priority = (default: $p_spec:ident),
1129        priority_enabled = $pe:tt,
1130    ) ) => {
1131        $next!($next_args, 500);
1132    };
1133
1134    // Priority specified = late, link options not, priority enabled
1135    ( @entry next=$next:path[$next_args:tt], input=(
1136        export_name_prefix = ($enp:tt: default),
1137        link_section = ($ls:tt: default),
1138        naked = ($naked:tt: default),
1139        priority = (late: $p_spec:ident),
1140        priority_enabled = $pe:tt,
1141    ) ) => {
1142        #[cfg(all(target_os = "aix", not(target_vendor = "apple")))]
1143        $next!($next_args, 89999999);
1144
1145        #[cfg(all(not(target_os = "aix"), not(target_vendor = "apple")))]
1146        $next!($next_args, 65535);
1147
1148        #[cfg(target_vendor = "apple")]
1149        $next!($next_args, ($crate::collect::LATE));
1150    };
1151
1152    // Priority specified, link options not, priority enabled
1153    ( @entry next=$next:path[$next_args:tt], input=(
1154        export_name_prefix = ($enp:tt: default),
1155        link_section = ($ls:tt: default),
1156        naked = ($naked:tt: default),
1157        priority = ($priority:tt: $p_spec:ident),
1158        priority_enabled = $pe:tt,
1159    ) ) => {
1160        $next!($next_args, $priority);
1161    };
1162
1163    // Priority specified, link options specified
1164    ( @entry next=$next:path[$next_args:tt], input=(
1165        export_name_prefix = $enp:tt,
1166        link_section = $ls:tt,
1167        naked = $naked:tt,
1168        priority = ($priority:tt: value),
1169        priority_enabled = $pe:tt,
1170    ) ) => {
1171        compile_error!(concat!("Priority must not be specified if naked, export_name_prefix, or link_section are specified."));
1172    };
1173
1174    // Priority unspecified, link options specified -> naked
1175    ( @entry next=$next:path[$next_args:tt], input=(
1176        export_name_prefix = $enp:tt,
1177        link_section = $ls:tt,
1178        naked = $naked:tt,
1179        priority = ($priority:tt: default),
1180        priority_enabled = $pe:tt,
1181    ) ) => {
1182        $next!($next_args, naked);
1183    };
1184
1185    // Naked specified
1186    ( @entry next=$next:path[$next_args:tt], input=(
1187        export_name_prefix = $enp:tt,
1188        link_section = $ls:tt,
1189        naked = (naked: value),
1190        priority = $priority:tt,
1191        priority_enabled = $pe:tt,
1192    ) ) => {
1193        $next!($next_args, naked);
1194    };
1195
1196    ( @entry next=$next:path[$next_args:tt], input=$input:tt ) => {
1197        compile_error!(concat!("Unexpected priority input: ", stringify!($input)));
1198    };
1199}