Skip to main content

dtor/
parse.rs

1#[macro_export]
2#[doc(hidden)]
3macro_rules! __dtor_parse {
4    ( $($input:tt)* ) => {
5        $crate::__perform!(
6            ($($input)*),
7            $crate::__chain[
8                $crate::__parse_item[$crate::__dtor_features],
9                $crate::__extract_unsafe,
10                $crate::__dtor_parse_impl,
11            ]
12        );
13    };
14}
15
16/// Parse a processed `dtor` item. This is intentionally verbose to avoid
17/// excessive nesting of macro calls in user code.
18#[macro_export]
19#[doc(hidden)]
20macro_rules! __dtor_parse_impl {
21    // Step 0: Check function shape and features
22
23    // fn
24    ( @entry next=$next:path[$next_args:tt], input=(
25        features = (
26            anonymous = $anonymous:tt,
27            crate_path = $crate_path:tt,
28            ctor_export_name_prefix = $ctor_export_name_prefix:tt,
29            ctor_link_section = $ctor_link_section:tt,
30            default_term_method = $default_term_method:tt,
31            default_unload_method = $default_unload_method:tt,
32            export_name_prefix = $export_name_prefix:tt,
33            link_section = $link_section:tt,
34            method = $method:tt,
35            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
36            proc_macro = $proc_macro:tt,
37            std = $std:tt,
38            used_linker = $used_linker:tt,
39        ),
40        meta = $meta:tt,
41        unsafe = ($($unsafe:tt)*),
42        item = ($vis:vis $(unsafe)? $( extern $abi:literal )? fn $name:ident () $( -> () )? {
43            $($body:tt)*
44        })
45    ) ) => {
46        $crate::__dtor_parse_impl!(@checkfail method=$method);
47
48        $crate::__dtor_parse_impl!(@entry next=$next[$next_args], input=(
49            features = (
50                anonymous = $anonymous,
51                ctor_export_name_prefix = $ctor_export_name_prefix,
52                ctor_link_section = $ctor_link_section,
53                default_term_method = $default_term_method,
54                default_unload_method = $default_unload_method,
55                export_name_prefix = $export_name_prefix,
56                link_section = $link_section,
57                method = $method,
58                no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe,
59                used_linker = $used_linker,
60            ),
61            meta = $meta,
62            unsafe = ($($unsafe)*),
63            item = ($vis $($unsafe)* $( extern $abi )? fn $name () {
64                $($body)*
65            })
66        ));
67    };
68
69    ( @checkfail method=term ) => {};
70    ( @checkfail method=unload ) => {};
71    ( @checkfail method=at_module_exit ) => {};
72    ( @checkfail method=at_binary_exit ) => {};
73    ( @checkfail method=linker ) => {};
74    ( @checkfail method=$any:tt ) => {
75        compile_error!(concat!("Invalid dtor method: ", stringify!($any)));
76    };
77
78    ( @checkfail $($rest:tt)* ) => {};
79
80    ( @entry next=$next:path[$next_args:tt], input=(
81        features = (
82            anonymous = $anonymous:tt,
83            crate_path = $crate_path:tt,
84            ctor_export_name_prefix = $ctor_export_name_prefix:tt,
85            ctor_link_section = $ctor_link_section:tt,
86            default_term_method = $default_term_method:tt,
87            default_unload_method = $default_unload_method:tt,
88            export_name_prefix = $export_name_prefix:tt,
89            link_section = $link_section:tt,
90            method = $method:tt,
91            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
92            proc_macro = $proc_macro:tt,
93            std = $std:tt,
94            used_linker = $used_linker:tt,
95        ),
96        meta = $meta:tt,
97        unsafe = $unsafe:tt,
98        item = ($item:item)
99    ) ) => {
100        compile_error!("Invalid dtor function. \
101            Expected a function with no args, \
102            return value, or type parameters.\n\
103            Valid forms are: [pub] [unsafe] [extern $abi] fn $name() { ... }");
104    };
105
106    // Step 1: Compute method
107
108    // Delegate term -> default_term_method
109    ( @entry next=$next:path[$next_args:tt], input=(
110        features = (
111            anonymous = $anonymous:tt,
112            ctor_export_name_prefix = $ctor_export_name_prefix:tt,
113            ctor_link_section = $ctor_link_section:tt,
114            default_term_method = $default_term_method:tt,
115            default_unload_method = $default_unload_method:tt,
116            export_name_prefix = $export_name_prefix:tt,
117            link_section = $link_section:tt,
118            method = term,
119            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
120            used_linker = $used_linker:tt,
121        ),
122        meta = $meta:tt,
123        unsafe = $unsafe:tt,
124        item = $item:tt
125    ) ) => {
126        // method = term
127        $crate::__dtor_parse_impl(@entry next=$next[$next_args], input=(
128            features = (
129                anonymous = $anonymous,
130                method = ($default_term_method $ctor_export_name_prefix $ctor_link_section $export_name_prefix $link_section),
131                no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe,
132                used_linker = $used_linker,
133            ),
134            meta = $meta,
135            unsafe = $unsafe,
136            item = $item
137        ));
138    };
139
140    // Delegate unload -> default_unload_method
141    ( @entry next=$next:path[$next_args:tt], input=(
142        features = (
143            anonymous = $anonymous:tt,
144            ctor_export_name_prefix = $ctor_export_name_prefix:tt,
145            ctor_link_section = $ctor_link_section:tt,
146            default_term_method = $default_term_method:tt,
147            default_unload_method = $default_unload_method:tt,
148            export_name_prefix = $export_name_prefix:tt,
149            link_section = $link_section:tt,
150            method = unload,
151            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
152            used_linker = $used_linker:tt,
153        ),
154        meta = $meta:tt,
155        unsafe = $unsafe:tt,
156        item = $item:tt
157    ) ) => {
158        // method = unload
159        $crate::__dtor_parse_impl!(@entry next=$next[$next_args], input=(
160            features = (
161                anonymous = $anonymous,
162                method = ($default_unload_method $ctor_export_name_prefix $ctor_link_section $export_name_prefix $link_section),
163                no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe,
164                used_linker = $used_linker,
165            ),
166            meta = $meta,
167            unsafe = $unsafe,
168            item = $item
169        ));
170    };
171
172    // Other methods, pass through
173    ( @entry next=$next:path[$next_args:tt], input=(
174        features = (
175            anonymous = $anonymous:tt,
176            ctor_export_name_prefix = $ctor_export_name_prefix:tt,
177            ctor_link_section = $ctor_link_section:tt,
178            default_term_method = $default_term_method:tt,
179            default_unload_method = $default_unload_method:tt,
180            export_name_prefix = $export_name_prefix:tt,
181            link_section = $link_section:tt,
182            method = $method:tt,
183            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
184            used_linker = $used_linker:tt,
185        ),
186        meta = $meta:tt,
187        unsafe = $unsafe:tt,
188        item = $item:tt
189    ) ) => {
190        // method = other
191        $crate::__dtor_parse_impl!(@entry next=$next[$next_args], input=(
192            features = (
193                anonymous = $anonymous,
194                method = ($method $ctor_export_name_prefix $ctor_link_section $export_name_prefix $link_section),
195                no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe,
196                used_linker = $used_linker,
197            ),
198            meta = $meta,
199            unsafe = $unsafe,
200            item = $item
201        ));
202    };
203
204    // Step 2: warn on missing unsafe
205
206    // warn iff no_warn_on_missing_unsafe is not present AND unsafe is not present
207    ( @entry next=$next:path[$next_args:tt], input=(
208        features = (
209            anonymous = $anonymous:tt,
210            method = $method:tt,
211            no_warn_on_missing_unsafe = (),
212            used_linker = $used_linker:tt,
213        ),
214        meta = $meta:tt,
215        unsafe = (),
216        item = $item:tt
217    ) ) => {
218        const _: () = {
219            #[deprecated="dtor deprecation note:\n\n\
220            Use of #[dtor] without `#[dtor(unsafe)]` or `unsafe fn` is deprecated. As code execution\n\
221            before main is unsupported by most Rust runtime functions, these functions must be marked\n\
222            `unsafe`."]
223            const fn dtor_without_unsafe_is_deprecated() {}
224            #[allow(unused)]
225            static UNSAFE_WARNING: () = {
226                dtor_without_unsafe_is_deprecated()
227            };
228        };
229
230        $crate::__dtor_parse_impl!(@entry next=$next[$next_args], input=(
231            features = (
232                anonymous = $anonymous,
233                method = $method,
234                used_linker = $used_linker,
235            ),
236            meta = $meta,
237            unsafe = (),
238            item = $item
239        ));
240    };
241
242    // If no_warn_on_missing_unsafe, ignore
243    ( @entry next=$next:path[$next_args:tt], input=(
244        features = (
245            anonymous = $anonymous:tt,
246            method = $method:tt,
247            no_warn_on_missing_unsafe = $no_warn_on_missing_unsafe:tt,
248            used_linker = $used_linker:tt,
249        ),
250        meta = $meta:tt,
251        unsafe = $unsafe:tt,
252        item = $item:tt
253    ) ) => {
254        $crate::__dtor_parse_impl!(@entry next=$next[$next_args], input=(
255            features = (
256                anonymous = $anonymous,
257                method = $method,
258                used_linker = $used_linker,
259            ),
260            meta = $meta,
261            unsafe = $unsafe,
262            item = $item
263        ));
264    };
265
266    // Step 3: Wrap anonymous if needed
267    ( @entry next=$next:path[$next_args:tt], input=(
268        features = (
269            anonymous = anonymous,
270            method = $method:tt,
271            used_linker = $used_linker:tt,
272        ),
273        meta = $meta:tt,
274        unsafe = $unsafe:tt,
275        item = $item:tt
276    ) ) => {
277        // Anonymous function
278        const _: () = {
279            $crate::__dtor_parse_impl!(@entry next=$next[$next_args], input=(
280                features = (
281                    method = $method,
282                    used_linker = $used_linker,
283                ),
284                meta = $meta,
285                unsafe = $unsafe,
286                item = $item
287            ));
288        };
289    };
290
291    ( @entry next=$next:path[$next_args:tt], input=(
292        features = (
293            anonymous = (),
294            method = $method:tt,
295            used_linker = $used_linker:tt,
296        ),
297        meta = $meta:tt,
298        unsafe = $unsafe:tt,
299        item = $item:tt
300    ) ) => {
301        $crate::__dtor_parse_impl!(@entry next=$next[$next_args], input=(
302            features = (
303                method = $method,
304                used_linker = $used_linker,
305            ),
306            meta = $meta,
307            unsafe = $unsafe,
308            item = $item
309        ));
310    };
311
312    // Step 4: Compute used_linker
313    ( @entry next=$next:path[$next_args:tt], input=(
314        features = (
315            method = $method:tt,
316            used_linker = (),
317        ),
318        meta = $meta:tt,
319        unsafe = $unsafe:tt,
320        item = $item:tt
321    ) ) => {
322        $crate::__dtor_parse_impl!(@entry next=$next[$next_args], input=(
323            features = (
324                method = $method,
325                used_linker_meta = (#[used]),
326            ),
327            meta = $meta,
328            unsafe = $unsafe,
329            item = $item
330        ));
331    };
332
333    ( @entry next=$next:path[$next_args:tt], input=(
334        features = (
335            method = $method:tt,
336            used_linker = used_linker,
337        ),
338        meta = $meta:tt,
339        unsafe = $unsafe:tt,
340        item = $item:tt
341    ) ) => {
342        $crate::__dtor_parse_impl!(@entry next=$next[$next_args], input=(
343            features = (
344                method = $method,
345                used_linker_meta = (#[used(linker)]),
346            ),
347            meta = $meta,
348            unsafe = $unsafe,
349            item = $item
350        ));
351    };
352
353    // Step 5: Delegate on method (at_module_exit, at_binary_exit, link_section)
354    ( @entry next=$next:path[$next_args:tt], input=(
355        features = (
356            method = ($method:tt $ctor_export_name_prefix:tt $ctor_link_section:tt $export_name_prefix:tt $link_section:tt),
357            used_linker_meta = (#$used_linker_meta:tt),
358        ),
359        meta = ($($meta:tt)*),
360        unsafe = ($($unsafe:tt)*),
361        item = ($vis:vis $(unsafe)? $( extern $abi:literal )? fn $name:ident $args:tt $( -> () )? {
362            $($body:tt)*
363        })
364    ) ) => {
365        $($meta)*
366        $vis $($unsafe)* $( extern $abi )? fn $name $args {
367            $crate::__dtor_parse_impl!(@dtor next=$next[$next_args], input=(
368                features = (
369                    ctor_export_name_prefix = $ctor_export_name_prefix,
370                    ctor_link_section = $ctor_link_section,
371                    export_name_prefix = $export_name_prefix,
372                    link_section = $link_section,
373                    method = $method,
374                    used_linker_meta = (#$used_linker_meta),
375                ),
376                item = $name,
377                unsafe = ($($unsafe)*)
378            ));
379
380            $($body)*
381        }
382    };
383
384    // dtor
385
386    ( @dtor next=$next:path[$next_args:tt], input=(
387        features = (
388            ctor_export_name_prefix = $ctor_export_name_prefix:tt,
389            ctor_link_section = $ctor_link_section:tt,
390            export_name_prefix = (),
391            link_section = $link_section:tt,
392            method = linker,
393            used_linker_meta = (#$used_linker_meta:tt),
394        ),
395        item = $name:ident,
396        unsafe = ($($unsafe:tt)*)
397    ) ) => {
398        const _: () = {
399            #[link_section = $link_section]
400            #$used_linker_meta
401            static __DTOR_PRIVATE_REF: extern "C" fn() = {
402                extern "C" fn __dtor_private() {
403                    $($unsafe)* { $name() }
404                }
405                __dtor_private
406            };
407        };
408    };
409
410    ( @dtor next=$next:path[$next_args:tt], input=(
411        features = (
412            ctor_export_name_prefix = $ctor_export_name_prefix:tt,
413            ctor_link_section = $ctor_link_section:tt,
414            export_name_prefix = $export_name_prefix:tt,
415            link_section = $link_section:tt,
416            method = linker,
417            used_linker_meta = (#$used_linker_meta:tt),
418        ),
419        item = $name:ident,
420        unsafe = ($($unsafe:tt)*)
421    ) ) => {
422        const _: () = {
423            #[no_mangle]
424            #[export_name = concat!($export_name_prefix, "_",
425                env!("CARGO_PKG_NAME"),
426                "_",
427                module_path!(),
428                "_",
429                stringify!($name),
430                "_L",
431                line!(),
432                "C",
433                column!())]
434            extern "C" fn __dtor_private() {
435                $($unsafe)* { $name() }
436            }
437        };
438    };
439
440    ( @dtor next=$next:path[$next_args:tt], input=(
441        features = (
442            ctor_export_name_prefix = (),
443            ctor_link_section = $ctor_link_section:tt,
444            export_name_prefix = $export_name_prefix:tt,
445            link_section = $link_section:tt,
446            method = $method:ident,
447            used_linker_meta = (#$used_linker_meta:tt),
448        ),
449        item = $name:ident,
450        unsafe = ($($unsafe:tt)*)
451    ) ) => {
452        const _: () = {
453            #[link_section = $ctor_link_section]
454            #$used_linker_meta
455            static __CTOR_PRIVATE_REF: unsafe extern "C" fn() = {
456                unsafe extern "C" fn __ctor_private() {
457                    $crate::__support::$method(__dtor_private);
458                }
459                extern "C" fn __dtor_private() {
460                    $($unsafe)* { $name() }
461                }
462                __ctor_private
463            };
464        };
465    };
466
467    ( @dtor next=$next:path[$next_args:tt], input=(
468        features = (
469            ctor_export_name_prefix = $ctor_export_name_prefix:tt,
470            ctor_link_section = $ctor_link_section:tt,
471            export_name_prefix = $export_name_prefix:tt,
472            link_section = $link_section:tt,
473            method = $method:ident,
474            used_linker_meta = (#$used_linker_meta:tt),
475        ),
476        item = $name:ident,
477        unsafe = ($($unsafe:tt)*)
478    ) ) => {
479        const _: () = {
480            #[no_mangle]
481            #[export_name = concat!($ctor_export_name_prefix, "_",
482                env!("CARGO_PKG_NAME"),
483                "_",
484                module_path!(),
485                "_",
486                stringify!($name),
487                "_L",
488                line!(),
489                "C",
490                column!())]
491            unsafe extern "C" fn __ctor_private() {
492                $crate::__support::$method(__dtor_private);
493            }
494
495            extern "C" fn __dtor_private() {
496                $($unsafe)* { $name() }
497            }
498        };
499    };
500
501    ( @entry next=$next:path[$next_args:tt], input=$input:tt ) => {
502        compile_error!(concat!("Invalid dtor input: ", stringify!($input)));
503    };
504}