dtor/macros/
mod.rs

1#[doc(hidden)]
2#[allow(unused)]
3pub mod __support {
4    pub use crate::__ctor_entry as ctor_entry;
5    pub use crate::__ctor_link_section as ctor_link_section;
6    pub use crate::__ctor_link_section_attr as ctor_link_section_attr;
7    pub use crate::__ctor_parse as ctor_parse;
8    pub use crate::__dtor_entry as dtor_entry;
9    pub use crate::__dtor_parse as dtor_parse;
10    pub use crate::__if_has_feature as if_has_feature;
11    pub use crate::__if_unsafe as if_unsafe;
12    pub use crate::__include_no_warn_on_missing_unsafe_feature as include_no_warn_on_missing_unsafe_feature;
13    pub use crate::__include_used_linker_feature as include_used_linker_feature;
14    pub use crate::__unify_features as unify_features;
15}
16
17/// Parse a `#[ctor]`-annotated item as if it were a proc-macro.
18///
19/// This macro supports both the `fn` and `static` forms of the `#[ctor]`
20/// attribute, including attribute parameters.
21///
22/// ```rust
23/// # #[cfg(any())] // disabled due to code sharing between ctor/dtor
24/// # mod test {
25/// # use ctor::declarative::ctor;
26/// ctor! {
27///   /// Create a ctor with a link section
28/// # #[cfg(any())]
29///   #[ctor(link_section = ".ctors")]
30///   unsafe fn foo() { /* ... */ }
31/// }
32///
33/// ctor! {
34///   #[ctor]
35/// # #[cfg(any())]
36///   static FOO: std::collections::HashMap<u32, String> = unsafe {
37///     let mut m = std::collections::HashMap::new();
38///     m.insert(1, "foo".to_string());
39///     m
40///   };
41/// }
42/// # }
43/// ```
44#[doc(hidden)]
45#[macro_export]
46macro_rules! __ctor_parse {
47    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* pub ( $($extra:tt)* ) $($item:tt)*) => {
48        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], features=[], imeta=$(#[$imeta])*, vis=[pub($($extra)*)], item=$($item)*);
49    };
50    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* pub $($item:tt)*) => {
51        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], features=[], imeta=$(#[$imeta])*, vis=[pub], item=$($item)*);
52    };
53    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* fn $($item:tt)*) => {
54        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], features=[], imeta=$(#[$imeta])*, vis=[], item=fn $($item)*);
55    };
56    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* unsafe $($item:tt)*) => {
57        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], features=[], imeta=$(#[$imeta])*, vis=[], item=unsafe $($item)*);
58    };
59    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* static $($item:tt)*) => {
60        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], features=[], imeta=$(#[$imeta])*, vis=[], item=static $($item)*);
61    };
62    // Reorder attributes that aren't `#[ctor]`
63    (#[$imeta:meta] $($rest:tt)*) => {
64        $crate::__support::ctor_parse!(__reorder__(#[$imeta],), $($rest)*);
65    };
66    (__reorder__($(#[$imeta:meta],)*), #[ctor $(($($meta:tt)*))?] $($rest:tt)*) => {
67        $crate::__support::ctor_parse!(#[ctor $(($($meta)*))?] $(#[$imeta])* $($rest)*);
68    };
69    (__reorder__($(#[$imeta:meta],)*), #[$imeta2:meta] $($rest:tt)*) => {
70        $crate::__support::ctor_parse!(__reorder__($(#[$imeta],)*#[$imeta2],), $($rest)*);
71    };
72}
73
74/// Parse a `#[dtor]`-annotated item as if it were a proc-macro.
75///
76/// ```rust
77/// # #[cfg(any())] mod test {
78/// dtor! {
79///   #[dtor]
80///   unsafe fn foo() { /* ... */ }
81/// }
82/// # }
83#[doc(hidden)]
84#[macro_export]
85macro_rules! __dtor_parse {
86    (#[dtor $(($($meta:tt)*))?] $(#[$imeta:meta])* pub ( $($extra:tt)* ) $($item:tt)*) => {
87        $crate::__support::unify_features!(next=$crate::__support::dtor_entry, meta=[$($($meta)*)?], features=[], imeta=$(#[$imeta])*, vis=[pub($($extra)*)], item=$($item)*);
88    };
89    (#[dtor $(($($meta:tt)*))?] $(#[$imeta:meta])* pub $($item:tt)*) => {
90        $crate::__support::unify_features!(next=$crate::__support::dtor_entry, meta=[$($($meta)*)?], features=[], imeta=$(#[$imeta])*, vis=[pub], item=$($item)*);
91    };
92    (#[dtor $(($($meta:tt)*))?] $(#[$imeta:meta])* fn $($item:tt)*) => {
93        $crate::__support::unify_features!(next=$crate::__support::dtor_entry, meta=[$($($meta)*)?], features=[], imeta=$(#[$imeta])*, vis=[], item=fn $($item)*);
94    };
95    (#[dtor $(($($meta:tt)*))?] $(#[$imeta:meta])* unsafe $($item:tt)*) => {
96        $crate::__support::unify_features!(next=$crate::__support::dtor_entry, meta=[$($($meta)*)?], features=[], imeta=$(#[$imeta])*, vis=[], item=unsafe $($item)*);
97    };
98    // Reorder attributes that aren't `#[dtor]`
99    (#[$imeta:meta] $($rest:tt)*) => {
100        $crate::__support::dtor_parse!(__reorder__(#[$imeta],), $($rest)*);
101    };
102    (__reorder__($(#[$imeta:meta],)*), #[dtor $(($($meta:tt)*))?] $($rest:tt)*) => {
103        $crate::__support::dtor_parse!(#[dtor $(($($meta)*))?] $(#[$imeta])* $($rest)*);
104    };
105    (__reorder__($(#[$imeta:meta],)*), #[$imeta2:meta] $($rest:tt)*) => {
106        $crate::__support::dtor_parse!(__reorder__($(#[$imeta],)*#[$imeta2],), $($rest)*);
107    };
108}
109
110/// Extract #[ctor/dtor] attribute parameters and crate features and turn them
111/// into a unified feature array.
112///
113/// Supported attributes:
114///
115/// - `used(linker)` -> feature: `used_linker`
116/// - `link_section = ...` -> feature: `(link_section = ...)`
117/// - `crate_path = ...` -> feature: `(crate_path = ...)`
118#[doc(hidden)]
119#[macro_export]
120macro_rules! __unify_features {
121    // Entry
122    (next=$next_macro:path, meta=[$($meta:tt)*], features=[$($features:tt)*], $($rest:tt)*) => {
123        $crate::__support::unify_features!(used_linker, next=$next_macro, meta=[$($meta)*], features=[$($features)*], $($rest)*);
124    };
125
126    // Add used_linker feature if cfg(feature="used_linker")
127    (used_linker, next=$next_macro:path, meta=[$($meta:tt)*], features=[$($features:tt)*], $($rest:tt)*) => {
128        $crate::__support::include_used_linker_feature!(
129            $crate::__support::unify_features!(__no_warn_on_missing_unsafe, next=$next_macro, meta=[$($meta)*], features=[used_linker,$($features)*], $($rest)*);
130            $crate::__support::unify_features!(__no_warn_on_missing_unsafe, next=$next_macro, meta=[$($meta)*], features=[$($features)*], $($rest)*);
131        );
132    };
133    // Add __no_warn_on_missing_unsafe feature if cfg(feature="__no_warn_on_missing_unsafe")
134    (__no_warn_on_missing_unsafe, next=$next_macro:path, meta=[$($meta:tt)*], features=[$($features:tt)*], $($rest:tt)*) => {
135        $crate::__support::include_used_linker_feature!(
136            $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($meta)*], features=[__no_warn_on_missing_unsafe,$($features)*], $($rest)*);
137            $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($meta)*], features=[$($features)*], $($rest)*);
138        );
139    };
140
141    // Parse meta into features
142    (continue, next=$next_macro:path, meta=[used(linker) $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
143        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[used_linker,$($features)*], $($rest)*);
144    };
145    (continue, next=$next_macro:path, meta=[link_section = $section:tt $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
146        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[(link_section=$section),$($features)*], $($rest)*);
147    };
148    (continue, next=$next_macro:path, meta=[crate_path = $path:path $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
149        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[(crate_path=$path),$($features)*], $($rest)*);
150    };
151    (continue, next=$next_macro:path, meta=[anonymous $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
152        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[anonymous,$($features)*], $($rest)*);
153    };
154    (continue, next=$next_macro:path, meta=[$unknown_meta:meta $($meta:tt)*], features=[$($features:tt)*], $($rest:tt)*) => {
155        compile_error!(concat!("Unknown attribute parameter: ", stringify!($unknown_meta)));
156    };
157
158    (continue, next=$next_macro:path, meta=[], features=[$($features:tt)*], $($rest:tt)*) => {
159        $next_macro!(features=[$($features)*], $($rest)*);
160    };
161}
162
163#[doc(hidden)]
164#[macro_export]
165#[cfg(feature = "used_linker")]
166macro_rules! __include_used_linker_feature {
167    ($true:item $false:item) => {
168        $true
169    };
170}
171
172#[doc(hidden)]
173#[macro_export]
174#[cfg(not(feature = "used_linker"))]
175macro_rules! __include_used_linker_feature {
176    ($true:item $false:item) => {
177        $false
178    };
179}
180
181#[doc(hidden)]
182#[macro_export]
183#[cfg(feature = "__no_warn_on_missing_unsafe")]
184macro_rules! __include_no_warn_on_missing_unsafe_feature {
185    ($true:item $false:item) => {
186        $true
187    };
188}
189
190#[doc(hidden)]
191#[macro_export]
192#[cfg(not(feature = "__no_warn_on_missing_unsafe"))]
193macro_rules! __include_no_warn_on_missing_unsafe_feature {
194    ($true:item $false:item) => {
195        $false
196    };
197}
198
199/// If the features array contains the requested feature, generates `if_true`, else `if_false`.
200///
201/// This macro matches the features recursively.
202///
203/// Example: `[(link_section = ".ctors") , used_linker , __warn_on_missing_unsafe ,]`
204#[doc(hidden)]
205#[macro_export]
206#[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
207macro_rules! __if_has_feature {
208    (used_linker,                 [used_linker,                     $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_true)* };
209    (__no_warn_on_missing_unsafe, [__no_warn_on_missing_unsafe,     $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_true)* };
210    (anonymous,                   [anonymous,                       $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_true)* };
211    ((link_section(c)),           [(link_section=$section:literal), $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { #[link_section = $section] $($if_true)* };
212
213    // Fallback rules
214    ($anything:tt, [$x:ident, $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $crate::__support::if_has_feature!($anything, [$($rest)*], {$($if_true)*}, {$($if_false)*}); };
215    ($anything:tt, [($x:ident=$y:expr), $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $crate::__support::if_has_feature!($anything, [$($rest)*], {$($if_true)*}, {$($if_false)*}); };
216    ($anything:tt, [], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_false)* };
217}
218
219#[doc(hidden)]
220#[macro_export]
221macro_rules! __if_unsafe {
222    (, {$($if_unsafe:tt)*}, {$($if_safe:tt)*}) => { $($if_safe)* };
223    (unsafe, {$($if_unsafe:tt)*}, {$($if_safe:tt)*}) => { $($if_unsafe)* };
224}
225
226#[doc(hidden)]
227#[macro_export]
228#[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
229macro_rules! __ctor_entry {
230    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=unsafe fn $($item:tt)*) => {
231        $crate::__support::ctor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=unsafe, item=fn $($item)*);
232    };
233    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=fn $($item:tt)*) => {
234        $crate::__support::ctor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=, item=fn $($item)*);
235    };
236    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=static $ident:ident : $ty:ty = $(unsafe)? $({ $lit:literal })? $($lit2:literal)? ;) => {
237        compile_error!(concat!("Use `const ", stringify!($ident), " = ", stringify!($($lit)?$($lit2)?), ";` or `static ", stringify!($ident), ": ", stringify!($ty), " = ", stringify!($($lit)?$($lit2)?), ";` instead"));
238    };
239    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=static $ident:ident : $ty:ty = unsafe $($item:tt)*) => {
240        $crate::__support::ctor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=unsafe, item=static $ident: $ty = $($item)*);
241    };
242    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=static $ident:ident : $ty:ty = $($item:tt)*) => {
243        $crate::__support::ctor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=, item=static $ident: $ty = $($item)*);
244    };
245    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
246        $crate::__support::if_has_feature!(anonymous, $features, {
247            $crate::__support::ctor_entry!(unnamed, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
248        }, {
249            $crate::__support::ctor_entry!(named, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
250        });
251    };
252    (unnamed,features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
253        const _: () = {
254            $crate::__support::ctor_entry!(named, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
255        };
256    };
257    (named, features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
258        #[cfg(target_family="wasm")]
259        $(#[$fnmeta])*
260        #[allow(unused)]
261        #[::wasm_bindgen::prelude::wasm_bindgen(start)]
262        $($vis)* fn $ident() {
263            $block
264        }
265
266        #[cfg(not(target_family="wasm"))]
267        $(#[$fnmeta])*
268        #[allow(unused)]
269        $($vis)* $($unsafe)? fn $ident() {
270            #[allow(unsafe_code)]
271            {
272                $crate::__support::if_unsafe!($($unsafe)?, {}, {
273                    $crate::__support::if_has_feature!( __warn_on_missing_unsafe, $features, {
274                        #[deprecated="ctor deprecation note:\n\n \
275                        Use of #[ctor] without `unsafe fn` is deprecated. As code execution before main\n\
276                        is unsupported by most Rust runtime functions, these functions must be marked\n\
277                        `unsafe`."]
278                            const fn ctor_without_unsafe_is_deprecated() {}
279                            #[allow(unused)]
280                            static UNSAFE_WARNING: () = ctor_without_unsafe_is_deprecated();
281                    }, {});
282                });
283
284                $crate::__support::ctor_link_section!(
285                    array,
286                    features=$features,
287
288                    #[allow(non_upper_case_globals, non_snake_case)]
289                    #[doc(hidden)]
290                    static f: /*unsafe*/ extern "C" fn() -> usize =
291                    {
292                        $crate::__support::ctor_link_section!(
293                            startup,
294                            features=$features,
295
296                            #[allow(non_snake_case)]
297                            /*unsafe*/ extern "C" fn f() -> usize { unsafe { $ident(); 0 } }
298                        );
299
300                        f
301                    };
302                );
303            }
304
305            $block
306        }
307    };
308    (features=$features:tt, imeta=$(#[$imeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=static $ident:ident : $ty:ty = $block:block;) => {
309        $(#[$imeta])*
310        $($vis)* static $ident: $ident::Static<$ty> = $ident::Static::<$ty> {
311            _storage: {
312                #[cfg(target_family="wasm")]
313                #[::wasm_bindgen::prelude::wasm_bindgen(start)]
314                fn init() {
315                    _ = &*$ident;
316                }
317
318                #[cfg(not(target_family="wasm"))]
319                $crate::__support::ctor_link_section!(
320                    array,
321                    features=$features,
322
323                    #[allow(non_upper_case_globals, non_snake_case)]
324                    #[doc(hidden)]
325                    static f: /*unsafe*/ extern "C" fn() -> usize =
326                    {
327                        $crate::__support::ctor_link_section!(
328                            startup,
329                            features=$features,
330
331                            #[allow(non_snake_case)]
332                            /*unsafe*/ extern "C" fn f() -> usize { _ = &*$ident; 0 }
333                        );
334
335                        f
336                    };
337                );
338
339                ::std::sync::OnceLock::new()
340            }
341        };
342
343        impl ::core::ops::Deref for $ident::Static<$ty> {
344            type Target = $ty;
345            fn deref(&self) -> &$ty {
346                fn init() -> $ty $block
347
348                self._storage.get_or_init(move || {
349                    init()
350                })
351            }
352        }
353
354        #[doc(hidden)]
355        #[allow(non_upper_case_globals, non_snake_case)]
356        #[allow(unsafe_code)]
357        mod $ident {
358            $crate::__support::if_unsafe!($($unsafe)?, {}, {
359                $crate::__support::if_has_feature!( __warn_on_missing_unsafe, $features, {
360                    #[deprecated="ctor deprecation note:\n\n \
361                    Use of #[ctor] without `unsafe { ... }` is deprecated. As code execution before main\n\
362                    is unsupported by most Rust runtime functions, these functions must be marked\n\
363                    `unsafe`."]
364                        const fn ctor_without_unsafe_is_deprecated() {}
365                        #[allow(unused)]
366                        static UNSAFE_WARNING: () = ctor_without_unsafe_is_deprecated();
367                }, {});
368            });
369
370            #[allow(non_camel_case_types, unreachable_pub)]
371            pub struct Static<T> {
372                pub _storage: ::std::sync::OnceLock<T>
373            }
374        }
375    };
376}
377
378// Code note:
379
380// You might wonder why we don't use `__attribute__((destructor))`/etc for
381// dtor. Unfortunately mingw doesn't appear to properly support section-based
382// hooks for shutdown, ie:
383
384// https://github.com/Alexpux/mingw-w64/blob/d0d7f784833bbb0b2d279310ddc6afb52fe47a46/mingw-w64-crt/crt/crtdll.c
385
386// In addition, OSX has removed support for section-based shutdown hooks after
387// warning about it for a number of years:
388
389// https://reviews.llvm.org/D45578
390
391#[doc(hidden)]
392#[macro_export]
393macro_rules! __dtor_entry {
394    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=fn $ident:ident() $block:block) => {
395        $crate::__support::dtor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=, item=fn $ident() $block);
396    };
397    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=unsafe fn $ident:ident() $block:block) => {
398        $crate::__support::dtor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=unsafe, item=fn $ident() $block);
399    };
400    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
401        $crate::__support::if_has_feature!(anonymous, $features, {
402            $crate::__support::dtor_entry!(unnamed, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
403        }, {
404            $crate::__support::dtor_entry!(named, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
405        });
406    };
407    (unnamed, features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
408        const _: () = {
409            $crate::__support::dtor_entry!(named, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
410        };
411    };
412    (named, features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
413        $(#[$fnmeta])*
414        #[allow(unused)]
415        $($vis)* $($unsafe)? fn $ident() {
416            #[allow(unsafe_code)]
417            {
418                $crate::__support::if_unsafe!($($unsafe)?, {}, {
419                    $crate::__support::if_has_feature!( __warn_on_missing_unsafe, $features, {
420                        #[deprecated="dtor deprecation note:\n\n \
421                        Use of #[dtor] without `unsafe fn` is deprecated. As code execution after main\n\
422                        is unsupported by most Rust runtime functions, these functions must be marked\n\
423                        `unsafe`."]
424                        const fn dtor_without_unsafe_is_deprecated() {}
425                        #[allow(unused)]
426                        static UNSAFE_WARNING: () = dtor_without_unsafe_is_deprecated();
427                    }, {});
428                });
429
430                $crate::__support::ctor_link_section!(
431                    array,
432                    features=$features,
433
434                    #[allow(non_upper_case_globals, non_snake_case)]
435                    #[doc(hidden)]
436                    static f: /*unsafe*/ extern "C" fn() -> usize =
437                    {
438                        $crate::__support::ctor_link_section!(
439                            startup,
440                            features=$features,
441
442                            #[allow(non_snake_case)]
443                            /*unsafe*/ extern "C" fn f() -> usize { unsafe { do_atexit(__dtor); 0 } }
444                        );
445
446                        f
447                    };
448                );
449
450                $crate::__support::ctor_link_section!(
451                    exit,
452                    features=$features,
453
454                    /*unsafe*/ extern "C" fn __dtor(
455                        #[cfg(target_vendor = "apple")] _: *const u8
456                    ) { unsafe { $ident() } }
457                );
458
459                #[cfg(not(target_vendor = "apple"))]
460                #[inline(always)]
461                unsafe fn do_atexit(cb: unsafe extern fn()) {
462                    /*unsafe*/ extern "C" {
463                        fn atexit(cb: unsafe extern fn());
464                    }
465                    unsafe {
466                        atexit(cb);
467                    }
468                }
469
470                // For platforms that have __cxa_atexit, we register the dtor as scoped to dso_handle
471                #[cfg(target_vendor = "apple")]
472                #[inline(always)]
473                unsafe fn do_atexit(cb: /*unsafe*/ extern "C" fn(_: *const u8)) {
474                    /*unsafe*/ extern "C" {
475                        static __dso_handle: *const u8;
476                        fn __cxa_atexit(cb: /*unsafe*/ extern "C" fn(_: *const u8), arg: *const u8, dso_handle: *const u8);
477                    }
478                    unsafe {
479                        __cxa_atexit(cb, core::ptr::null(), __dso_handle);
480                    }
481                }
482            }
483
484            $block
485        }
486    };
487}
488
489/// Annotate a block with its appropriate link section.
490#[doc(hidden)]
491#[macro_export]
492macro_rules! __ctor_link_section {
493    ($section:ident, features=$features:tt, $($block:tt)+) => {
494        $crate::__support::if_has_feature!(used_linker, $features, {
495            $crate::__support::ctor_link_section_attr!($section, $features, used(linker), $($block)+);
496        }, {
497            $crate::__support::ctor_link_section_attr!($section, $features, used, $($block)+);
498        });
499
500        #[cfg(not(any(
501            target_os = "linux",
502            target_os = "android",
503            target_os = "freebsd",
504            target_os = "netbsd",
505            target_os = "openbsd",
506            target_os = "dragonfly",
507            target_os = "illumos",
508            target_os = "haiku",
509            target_vendor = "apple",
510            windows
511        )))]
512        compile_error!("#[ctor]/#[dtor] is not supported on the current target");
513    }
514}
515
516/// Apply either the default cfg-based link section attributes, or
517/// the overridden link_section attribute.
518#[doc(hidden)]
519#[macro_export]
520macro_rules! __ctor_link_section_attr {
521    (array, $features:tt, $used:meta, $item:item) => {
522        $crate::__support::if_has_feature!((link_section(c)), $features, {
523            #[allow(unsafe_code)]
524            #[$used]
525            $item
526        }, {
527            #[allow(unsafe_code)]
528            $crate::__support::ctor_link_section_attr!(
529                [[any(
530                    target_os = "linux",
531                    target_os = "android",
532                    target_os = "freebsd",
533                    target_os = "netbsd",
534                    target_os = "openbsd",
535                    target_os = "dragonfly",
536                    target_os = "illumos",
537                    target_os = "haiku"
538                ), ".init_array"],
539                [target_vendor = "apple", "__DATA,__mod_init_func"],
540                [windows, ".CRT$XCU"]],
541                #[$used]
542                $item
543            );
544        });
545    };
546    (startup, $features:tt, $used:meta, $item:item) => {
547        #[cfg(not(clippy))]
548        $crate::__support::ctor_link_section_attr!([[any(target_os = "linux", target_os = "android"), ".text.startup"]], $item);
549
550        #[cfg(clippy)]
551        $item
552    };
553    (exit, $features:tt, $used:meta, $item:item) => {
554        #[cfg(not(clippy))]
555        $crate::__support::ctor_link_section_attr!([[any(target_os = "linux", target_os = "android"), ".text.exit"]], $item);
556
557        #[cfg(clippy)]
558        $item
559    };
560    ([$( [$cond:meta, $literal:literal ] ),+], $item:item) => {
561        $( #[cfg_attr($cond, link_section = $literal)] )+
562        $item
563    };
564}