dtor/macros/
mod.rs

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