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    ( @entry next=$next:path[$next_args:tt], input=(
40        features = (
41            anonymous = $anonymous:tt,
42            crate_path = $crate_path:tt,
43            dtor = $dtor:tt,
44            export_name_prefix = $export_name_prefix:tt,
45            link_section = $link_section:tt,
46            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
47            priority = $priority:tt,
48            priority_enabled = $priority_enabled:tt,
49            proc_macro = $proc_macro:tt,
50            std = $std:tt,
51            used_linker = $used_linker:tt,
52        ),
53        meta = $meta:tt,
54        unsafe = $unsafe:tt,
55        item = $item:tt
56    )) => {
57        $crate::__ctor_parse_impl!(@checkfail priority=$priority priority_enabled=priority_enabled);
58
59        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
60            features = (
61                anonymous = $anonymous,
62                export_name_prefix = $export_name_prefix,
63                link_section = $link_section,
64                no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe,
65                priority = $priority,
66                used_linker = $used_linker,
67            ),
68            meta = $meta,
69            unsafe = $unsafe,
70            item = $item
71        ));
72    };
73
74    ( @checkfail priority=() priority_enabled=$any:tt ) => {};
75    ( @checkfail priority=$any:tt priority_enabled=priority_enabled ) => {};
76    ( @checkfail priority=$any1:tt priority_enabled=$any2:tt ) => {
77        compile_error!("The priority feature is not enabled, so `priority = N` is not supported.");
78    };
79
80    ( @checkfail $($rest:tt)* ) => {};
81
82    // Step 2: Check function shape
83    ( @entry next=$next:path[$next_args:tt], input=(
84        features = (
85            anonymous = $anonymous:tt,
86            export_name_prefix = $export_name_prefix:tt,
87            link_section = $link_section:tt,
88            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
89            priority = $priority:tt,
90            used_linker = $used_linker:tt,
91        ),
92        meta = $meta:tt,
93        unsafe = ($($unsafe:tt)?),
94        item = ($vis:vis $(unsafe)? $( extern $abi:literal )? fn $name:ident () $( -> () )? {
95            $($body:tt)*
96        })
97    ) ) => {
98        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
99            features = (
100                anonymous = $anonymous,
101                link_name = $name,
102                export_name_prefix = $export_name_prefix,
103                link_section = $link_section,
104                no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe,
105                priority = $priority,
106                used_linker = $used_linker,
107            ),
108            meta = $meta,
109            unsafe = ($($unsafe)?),
110            item = ($vis $($unsafe)? $( extern $abi )? fn $name () {
111                $($body)*
112            })
113        ));
114    };
115
116    ( @entry next=$next:path[$next_args:tt], input=(
117        features = (
118            anonymous = $anonymous:tt,
119            export_name_prefix = $export_name_prefix:tt,
120            link_section = $link_section:tt,
121            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
122            priority = $priority:tt,
123            used_linker = $used_linker:tt,
124        ),
125        meta = $meta:tt,
126        unsafe = $unsafe:tt,
127        item = ($vis:vis static $ident:ident : $ty:ty = $(unsafe)? { $literal:literal };)
128    ) ) => {
129        compile_error!("Trivial const expressions are not supported. Remove the #[ctor] and use a regular `static`.");
130    };
131
132    ( @entry next=$next:path[$next_args:tt], input=(
133        features = (
134            anonymous = $anonymous:tt,
135            export_name_prefix = $export_name_prefix:tt,
136            link_section = $link_section:tt,
137            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
138            priority = $priority:tt,
139            used_linker = $used_linker:tt,
140        ),
141        meta = $meta:tt,
142        unsafe = $unsafe:tt,
143        item = ($vis:vis static $ident:ident : $ty:ty = $(unsafe)? const $body:block;)
144    ) ) => {
145        compile_error!("Trivial const expressions are not supported. Remove the #[ctor] and use a regular `static`.");
146    };
147
148    ( @entry next=$next:path[$next_args:tt], input=(
149        features = (
150            anonymous = $anonymous:tt,
151            export_name_prefix = $export_name_prefix:tt,
152            link_section = $link_section:tt,
153            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
154            priority = $priority:tt,
155            used_linker = $used_linker:tt,
156        ),
157        meta = $meta:tt,
158        unsafe = $unsafe:tt,
159        item = ($vis:vis static $ident:ident : $ty:ty = $(unsafe)? $literal:literal;)
160    ) ) => {
161        compile_error!("Trivial const expressions are not supported. Remove the #[ctor] and use a regular `static`.");
162    };
163
164    ( @entry next=$next:path[$next_args:tt], input=(
165        features = (
166            anonymous = $anonymous:tt,
167            export_name_prefix = $export_name_prefix:tt,
168            link_section = $link_section:tt,
169            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
170            priority = $priority:tt,
171            used_linker = $used_linker:tt,
172        ),
173        meta = $meta:tt,
174        unsafe = ($($unsafe:tt)?),
175        item = ($vis:vis static $ident:ident : $ty:ty = $(unsafe)? { $($body:tt)* };)
176    ) ) => {
177        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
178            features = (
179                anonymous = $anonymous,
180                link_name = $ident,
181                export_name_prefix = $export_name_prefix,
182                link_section = $link_section,
183                no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe,
184                priority = $priority,
185                used_linker = $used_linker,
186            ),
187            meta = $meta,
188            unsafe = ($($unsafe)?),
189            item = ($vis static $ident : $ty = $($unsafe)? { $($body)* };)
190        ));
191    };
192
193    ( @entry next=$next:path[$next_args:tt], input=(
194        features = (
195            anonymous = $anonymous:tt,
196            export_name_prefix = $export_name_prefix:tt,
197            link_section = $link_section:tt,
198            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
199            priority = $priority:tt,
200            used_linker = $used_linker:tt,
201        ),
202        meta = $meta:tt,
203        unsafe = $unsafe:tt,
204        item = ($item:item)
205    ) ) => {
206        compile_error!("Invalid ctor item. \
207            Expected a function with no args, \
208            return value, or type parameters or a static variable.\n\
209            Valid forms are:\n\
210             - [pub] [unsafe] [extern $abi] fn $name() { ... }\n\
211             - static $name : $ty = [unsafe] { ... };");
212    };
213
214    // Step 3: Compute no_warn_on_missing_unsafe
215
216    // warn iff no_warn_on_missing_unsafe is not present AND unsafe is not present
217    ( @entry next=$next:path[$next_args:tt], input=(
218        features = (
219            anonymous = $anonymous:tt,
220            link_name = $link_name:tt,
221            export_name_prefix = $export_name_prefix:tt,
222            link_section = $link_section:tt,
223            no_warn_on_missing_unsafe = (),
224            priority = $priority:tt,
225            used_linker = $used_linker:tt,
226        ),
227        meta = $meta:tt,
228        unsafe = (),
229        item = $item:tt
230    ) ) => {
231        const _: () = {
232            #[deprecated="ctor deprecation note:\n\n\
233            Use of #[ctor] without `#[ctor(unsafe)]` or `unsafe fn` is deprecated. As code execution\n\
234            before main is unsupported by most Rust runtime functions, these functions must be marked\n\
235            `unsafe`."]
236            const fn ctor_without_unsafe_is_deprecated() {}
237            #[allow(unused)]
238            static UNSAFE_WARNING: () = {
239                ctor_without_unsafe_is_deprecated()
240            };
241        };
242
243        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
244            features = (
245                anonymous = $anonymous,
246                link_name = $link_name,
247                export_name_prefix = $export_name_prefix,
248                link_section = $link_section,
249                priority = $priority,
250                used_linker = $used_linker,
251            ),
252            meta = $meta,
253            unsafe = (),
254            item = $item
255        ));
256    };
257
258    ( @entry next=$next:path[$next_args:tt], input=(
259        features = (
260            anonymous = $anonymous:tt,
261            link_name = $link_name:tt,
262            export_name_prefix = $export_name_prefix:tt,
263            link_section = $link_section:tt,
264            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
265            priority = $priority:tt,
266            used_linker = $used_linker:tt,
267        ),
268        meta = $meta:tt,
269        unsafe = $unsafe:tt,
270        item = $item:tt
271    ) ) => {
272        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
273            features = (
274                anonymous = $anonymous,
275                link_name = $link_name,
276                export_name_prefix = $export_name_prefix,
277                link_section = $link_section,
278                priority = $priority,
279                used_linker = $used_linker,
280            ),
281            meta = $meta,
282            unsafe = $unsafe,
283            item = $item
284        ));
285    };
286
287    // Step 4: Wrap in anonymous const
288    ( @entry next=$next:path[$next_args:tt], input=(
289        features = (
290            anonymous = (),
291            link_name = $link_name:tt,
292            export_name_prefix = $export_name_prefix:tt,
293            link_section = $link_section:tt,
294            priority = $priority:tt,
295            used_linker = $used_linker:tt,
296        ),
297        meta = $meta:tt,
298        unsafe = $unsafe:tt,
299        item = $item:tt
300    ) ) => {
301        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
302            features = (
303                link_name = $link_name,
304                export_name_prefix = $export_name_prefix,
305                link_section = $link_section,
306                priority = $priority,
307                used_linker = $used_linker,
308            ),
309            meta = $meta,
310            unsafe = $unsafe,
311            item = $item
312        ));
313    };
314    ( @entry next=$next:path[$next_args:tt], input=(
315        features = (
316            anonymous = anonymous,
317            link_name = $link_name:tt,
318            export_name_prefix = $export_name_prefix:tt,
319            link_section = $link_section:tt,
320            priority = $priority:tt,
321            used_linker = $used_linker:tt,
322        ),
323        meta = $meta:tt,
324        unsafe = $unsafe:tt,
325        item = $item:tt
326    ) ) => {
327        const _: () = {
328            $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
329                features = (
330                    link_name = $link_name,
331                    export_name_prefix = $export_name_prefix,
332                    link_section = $link_section,
333                    priority = $priority,
334                    used_linker = $used_linker,
335                ),
336                meta = $meta,
337                unsafe = $unsafe,
338                item = $item
339            ));
340        };
341    };
342
343    // Step 5: Compute used_linker
344    ( @entry next=$next:path[$next_args:tt], input=(
345        features = (
346            link_name = $link_name:tt,
347            export_name_prefix = $export_name_prefix:tt,
348            link_section = $link_section:tt,
349            priority = $priority:tt,
350            used_linker = (),
351        ),
352        meta = $meta:tt,
353        unsafe = $unsafe:tt,
354        item = $item:tt
355    ) ) => {
356        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
357            features = (
358                link_name = $link_name,
359                export_name_prefix = $export_name_prefix,
360                link_section = $link_section,
361                priority = $priority,
362                used_linker_meta = (#[used]),
363            ),
364            meta = $meta,
365            unsafe = $unsafe,
366            item = $item
367        ));
368    };
369
370    ( @entry next=$next:path[$next_args:tt], input=(
371        features = (
372            link_name = $link_name:tt,
373            export_name_prefix = $export_name_prefix:tt,
374            link_section = $link_section:tt,
375            priority = $priority:tt,
376            used_linker = used_linker,
377        ),
378        meta = $meta:tt,
379        unsafe = $unsafe:tt,
380        item = $item:tt
381    ) ) => {
382        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
383            features = (
384                link_name = $link_name,
385                export_name_prefix = $export_name_prefix,
386                link_section = $link_section,
387                priority = $priority,
388                used_linker_meta = (#[used(linker)]),
389            ),
390            meta = $meta,
391            unsafe = $unsafe,
392            item = $item
393        ));
394    };
395
396    // Step 6: Compute link_name
397
398    // No prefix, no computation
399    ( @entry next=$next:path[$next_args:tt], input=(
400        features = (
401            link_name = $link_name:tt,
402            export_name_prefix = (),
403            link_section = $link_section:tt,
404            priority = $priority:tt,
405            used_linker_meta = $used_linker_meta:tt,
406        ),
407        meta = $meta:tt,
408        unsafe = $unsafe:tt,
409        item = $item:tt
410    ) ) => {
411        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
412            features = (
413                link_name = (),
414                link_section = $link_section,
415                priority = $priority,
416                used_linker_meta = $used_linker_meta,
417            ),
418            meta = $meta,
419            unsafe = $unsafe,
420            item = $item
421        ));
422    };
423
424    ( @entry next=$next:path[$next_args:tt], input=(
425        features = (
426            link_name = $link_name:tt,
427            export_name_prefix = $export_name_prefix:tt,
428            link_section = $link_section:tt,
429            priority = (),
430            used_linker_meta = $used_linker_meta:tt,
431        ),
432        meta = $meta:tt,
433        unsafe = $unsafe:tt,
434        item = $item:tt
435    ) ) => {
436        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
437            features = (
438                link_name = (concat!($export_name_prefix,
439                    "0_",
440                    env!("CARGO_PKG_NAME"), "_",
441                    ::core::module_path!(), "_",
442                    stringify!($link_name),
443                    "_L", line!(), "C", column!())),
444                link_section = $link_section,
445                priority = (),
446                used_linker_meta = $used_linker_meta,
447            ),
448            meta = $meta,
449            unsafe = $unsafe,
450            item = $item
451        ));
452    };
453
454    ( @entry next=$next:path[$next_args:tt], input=(
455        features = (
456            link_name = $link_name:tt,
457            export_name_prefix = $export_name_prefix:tt,
458            link_section = $link_section:tt,
459            priority = $priority:tt,
460            used_linker_meta = $used_linker_meta:tt,
461        ),
462        meta = $meta:tt,
463        unsafe = $unsafe:tt,
464        item = $item:tt
465    ) ) => {
466        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
467            features = (
468                link_name = (concat!($export_name_prefix,
469                    $priority, "_",
470                    env!("CARGO_PKG_NAME"), "_",
471                    ::core::module_path!(), "_",
472                    stringify!($link_name),
473                    "_L", line!(), "C", column!())),
474                link_section = $link_section,
475                priority = $priority,
476                used_linker_meta = $used_linker_meta,
477            ),
478            meta = $meta,
479            unsafe = $unsafe,
480            item = $item
481        ));
482    };
483
484    // Step 7: Compute priority
485
486    // No priority, no prefix, flow through to used_linker_meta
487    ( @entry next=$next:path[$next_args:tt], input=(
488        features = (
489            link_name = $link_name:tt,
490            link_section = $link_section:tt,
491            priority = (),
492            used_linker_meta = $used_linker_meta:tt,
493        ),
494        meta = $meta:tt,
495        unsafe = $unsafe:tt,
496        item = $item:tt
497    ) ) => {
498        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
499            link_args = (
500                link_name = $link_name,
501                link_section = ($link_section),
502                used = $used_linker_meta,
503            ),
504            meta = $meta,
505            unsafe = $unsafe,
506            item = $item
507        ));
508    };
509
510    ( @entry next=$next:path[$next_args:tt], input=(
511        features = (
512            link_name = $link_name:tt,
513            link_section = $link_section:tt,
514            priority = $priority:tt,
515            used_linker_meta = $used_linker_meta:tt,
516        ),
517        meta = $meta:tt,
518        unsafe = $unsafe:tt,
519        item = $item:tt
520    ) ) => {
521        #[cfg(target_vendor = "apple")]
522        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
523            link_args = (
524                link_name = $link_name,
525                priority = $priority,
526                used = $used_linker_meta,
527            ),
528            meta = $meta,
529            unsafe = $unsafe,
530            item = $item
531        ));
532
533        // Get a priority literal
534        #[cfg(not(target_vendor = "apple"))]
535        $crate::__priority_to_literal!($crate::__ctor_parse_impl,[
536            @priority next=$next[$next_args],
537            features = (
538                link_name = $link_name,
539                link_section = $link_section,
540                used_linker_meta = $used_linker_meta,
541            ),
542            meta = $meta,
543            unsafe = $unsafe,
544            item = $item
545        ] = $priority);
546    };
547
548    ( [@priority next=$next:path[$next_args:tt],
549        features = (
550            link_name = $link_name:tt,
551            link_section = $link_section:tt,
552            used_linker_meta = $used_linker_meta:tt,
553        ),
554        meta = $meta:tt,
555        unsafe = $unsafe:tt,
556        item = $item:tt
557    ], ($($priority:tt)*)) => {
558        $crate::__ctor_parse_impl!(@entry next=$next[$next_args], input=(
559            link_args = (
560                link_name = $link_name,
561                link_section = (concat!($link_section, ".", $($priority)*)),
562                used = $used_linker_meta,
563            ),
564            meta = $meta,
565            unsafe = $unsafe,
566            item = $item
567        ));
568    };
569
570    // Step 8: Delegate on item type
571    ( @entry next=$next:path[$next_args:tt], input=(
572        link_args = $link_args:tt,
573        meta = ($($meta:tt)*),
574        unsafe = ($($unsafe:tt)*),
575        item = ($vis:vis $(unsafe)? $( extern $abi:literal )? fn $name:ident () $( -> () )? {
576            $($body:tt)*
577        })
578    ) ) => {
579        $($meta)*
580        $vis $($unsafe)* $( extern $abi )? fn $name () {
581            $crate::__ctor_parse_impl!(@ctor $link_args body={ $($unsafe)* { $name() } });
582            $($body)*
583        }
584    };
585
586    ( @entry next=$next:path[$next_args:tt], input=(
587        link_args = $link_args:tt,
588        meta = ($($meta:tt)*),
589        unsafe = ($($unsafe:tt)*),
590        item = ($vis:vis static $ident:ident : $ty:ty = $(unsafe)? { $($body:tt)* };)
591    ) ) => {
592        $($meta)*
593        $vis static $ident: $crate::statics::Static<$ty> = {
594            fn init() -> $ty {
595                $($unsafe)* {$($body)*}
596            }
597            unsafe { $crate::statics::Static::<$ty>::new(init) }
598        };
599        $crate::__ctor_parse_impl!(@ctor $link_args body={ _ = &*$ident } );
600    };
601
602    ( @ctor (
603        link_name=(),
604        link_section=($($link_section:tt)*),
605        used=(#$used_linker_meta:tt),
606     ) body=$body:tt ) => {
607        const _: () = {
608            #[allow(unsafe_code)]
609            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
610            #[link_section = $($link_section)*]
611            #$used_linker_meta
612            static __CTOR_PRIVATE_REF: unsafe extern "C" fn() = {
613                #[allow(unused_unsafe)]
614                extern "C" fn __ctor_private() {
615                    $body
616                }
617                __ctor_private
618            };
619        };
620    };
621
622    ( @ctor (
623        link_name=(),
624        priority=$priority:tt,
625        used=(#$used_linker_meta:tt),
626     ) body=$body:tt ) => {
627        const _: () = {
628            #[allow(unused_unsafe)]
629            fn __ctor_private() {
630                $body
631            }
632
633            $crate::__support::in_section!(
634                #[in_section(unsafe, type = (fn(), u16), name = CTOR)]
635                static __CTOR_ENTRY: (fn(), u16) = (__ctor_private, $priority);
636            );
637        };
638    };
639
640    ( @ctor (
641        link_name=($($link_name:tt)*),
642        link_section=$link_section:tt,
643        used=(#$used_linker_meta:tt),
644     ) body=$body:tt ) => {
645        const _: () = {
646            #[allow(unsafe_code)]
647            #[cfg_attr(clippy, allow(unknown_lints, unsafe_attr_outside_unsafe))]
648            const _: () = {
649                #[allow(unused_unsafe)]
650                #[no_mangle]
651                #[export_name = $($link_name)*]
652                extern "C" fn __ctor_private() {
653                    $body
654                }
655                __ctor_private
656            };
657        };
658    };
659}