Skip to main content

dtor/macros/
mod.rs

1//! Shared macros for the `ctor` and `dtor` crates.
2
3#[doc(hidden)]
4#[allow(unused)]
5pub(crate) mod __support {
6    /// Return type for the constructor. Why is this needed?
7    ///
8    /// On Windows, `.CRT$XIA` … `.CRT$XIZ` constructors are required to return a `usize` value. We don't know
9    /// if the user is putting this function into a retval-requiring section or a non-retval section, so we
10    /// just return a `usize` value which is always valid and just ignored if not needed.
11    ///
12    /// Miri is pedantic about this, so we just return `()` if we're running under miri.
13    ///
14    /// See <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/initterm-initterm-e?view=msvc-170>
15    #[cfg(all(windows, not(miri)))]
16    pub type CtorRetType = usize;
17    #[cfg(any(not(windows), miri))]
18    pub type CtorRetType = ();
19
20    pub use crate::__ctor_call as ctor_call;
21    pub use crate::__ctor_entry as ctor_entry;
22    pub use crate::__ctor_link_section as ctor_link_section;
23    pub use crate::__ctor_link_section_attr as ctor_link_section_attr;
24    pub use crate::__ctor_parse as ctor_parse;
25    pub use crate::__dtor_entry as dtor_entry;
26    pub use crate::__dtor_parse_impl as dtor_parse_impl;
27    pub use crate::__get_priority as get_priority;
28    pub use crate::__if_has_feature as if_has_feature;
29    pub use crate::__if_unsafe as if_unsafe;
30    pub use crate::__priority_to_literal as priority_to_literal;
31    pub use crate::__unify_features as unify_features;
32
33    #[cfg(all(feature = "priority", target_vendor = "apple"))]
34    pub use ::link_section;
35
36    /// Define a link section when using the priority parameter on Apple
37    /// targets.
38    #[cfg(all(feature = "priority", target_vendor = "apple"))]
39    #[doc(hidden)]
40    pub mod explicit_ctor {
41        link_section::declarative::section!(
42            #[section]
43            pub static CTOR: link_section::TypedSection<(fn(), u16)>;
44        );
45
46        crate::__support::ctor_call!(features = [], {
47            // SAFETY: The CTOR section is only accessed in this function, and
48            // this function is only ever called once.
49            #[allow(unsafe_code)]
50            unsafe {
51                CTOR.as_mut_slice()
52                    .sort_unstable_by_key(|(_, priority)| *priority);
53            }
54            for (ctor, _) in CTOR {
55                ctor();
56            }
57        });
58    }
59}
60
61/// Parse a `#[ctor]`-annotated item as if it were a proc-macro.
62///
63/// This macro supports both the `fn` and `static` forms of the `#[ctor]`
64/// attribute, including attribute parameters.
65///
66/// ```rust
67/// # #[cfg(any())] // disabled due to code sharing between ctor/dtor
68/// # mod test {
69/// # use ctor::declarative::ctor;
70/// ctor! {
71///   /// Create a ctor with a link section
72/// # #[cfg(any())]
73///   #[ctor(link_section = ".ctors")]
74///   unsafe fn foo() { /* ... */ }
75/// }
76///
77/// ctor! {
78///   #[ctor]
79/// # #[cfg(any())]
80///   static FOO: std::collections::HashMap<u32, String> = unsafe {
81///     let mut m = std::collections::HashMap::new();
82///     m.insert(1, "foo".to_string());
83///     m
84///   };
85/// }
86/// # }
87/// ```
88#[doc(hidden)]
89#[macro_export]
90macro_rules! __ctor_parse {
91    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* pub ( $($extra:tt)* ) $($item:tt)*) => {
92        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], imeta=$(#[$imeta])*, vis=[pub($($extra)*)], item=$($item)*);
93    };
94    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* pub $($item:tt)*) => {
95        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], imeta=$(#[$imeta])*, vis=[pub], item=$($item)*);
96    };
97    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* fn $($item:tt)*) => {
98        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], imeta=$(#[$imeta])*, vis=[], item=fn $($item)*);
99    };
100    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* unsafe $($item:tt)*) => {
101        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], imeta=$(#[$imeta])*, vis=[], item=unsafe $($item)*);
102    };
103    (#[ctor $(($($meta:tt)*))?] $(#[$imeta:meta])* static $($item:tt)*) => {
104        $crate::__support::unify_features!(next=$crate::__support::ctor_entry, meta=[$($($meta)*)?], imeta=$(#[$imeta])*, vis=[], item=static $($item)*);
105    };
106    // Reorder attributes that aren't `#[ctor]`
107    (#[$imeta:meta] $($rest:tt)*) => {
108        $crate::__support::ctor_parse!(__reorder__(#[$imeta],), $($rest)*);
109    };
110    (__reorder__($(#[$imeta:meta],)*), #[ctor $(($($meta:tt)*))?] $($rest:tt)*) => {
111        $crate::__support::ctor_parse!(#[ctor $(($($meta)*))?] $(#[$imeta])* $($rest)*);
112    };
113    (__reorder__($(#[$imeta:meta],)*), #[$imeta2:meta] $($rest:tt)*) => {
114        $crate::__support::ctor_parse!(__reorder__($(#[$imeta],)*#[$imeta2],), $($rest)*);
115    };
116}
117
118/// Parse a `#[dtor]`-annotated item as if it were a proc-macro.
119///
120/// ```rust
121/// # #[cfg(any())] mod test {
122/// dtor! {
123///   #[dtor]
124///   unsafe fn foo() { /* ... */ }
125/// }
126/// # }
127#[doc(hidden)]
128#[macro_export]
129macro_rules! __dtor_parse_impl {
130    (#[dtor $(($($meta:tt)*))?] $(#[$imeta:meta])* pub ( $($extra:tt)* ) $($item:tt)*) => {
131        $crate::__support::unify_features!(next=$crate::__support::dtor_entry, meta=[$($($meta)*)?], imeta=$(#[$imeta])*, vis=[pub($($extra)*)], item=$($item)*);
132    };
133    (#[dtor $(($($meta:tt)*))?] $(#[$imeta:meta])* pub $($item:tt)*) => {
134        $crate::__support::unify_features!(next=$crate::__support::dtor_entry, meta=[$($($meta)*)?], imeta=$(#[$imeta])*, vis=[pub], item=$($item)*);
135    };
136    (#[dtor $(($($meta:tt)*))?] $(#[$imeta:meta])* fn $($item:tt)*) => {
137        $crate::__support::unify_features!(next=$crate::__support::dtor_entry, meta=[$($($meta)*)?], imeta=$(#[$imeta])*, vis=[], item=fn $($item)*);
138    };
139    (#[dtor $(($($meta:tt)*))?] $(#[$imeta:meta])* unsafe $($item:tt)*) => {
140        $crate::__support::unify_features!(next=$crate::__support::dtor_entry, meta=[$($($meta)*)?], imeta=$(#[$imeta])*, vis=[], item=unsafe $($item)*);
141    };
142    // Reorder attributes that aren't `#[dtor]`
143    (#[$imeta:meta] $($rest:tt)*) => {
144        $crate::__support::dtor_parse_impl!(__reorder__(#[$imeta],), $($rest)*);
145    };
146    (__reorder__($(#[$imeta:meta],)*), #[dtor $(($($meta:tt)*))?] $($rest:tt)*) => {
147        $crate::__support::dtor_parse_impl!(#[dtor $(($($meta)*))?] $(#[$imeta])* $($rest)*);
148    };
149    (__reorder__($(#[$imeta:meta],)*), #[$imeta2:meta] $($rest:tt)*) => {
150        $crate::__support::dtor_parse_impl!(__reorder__($(#[$imeta],)*#[$imeta2],), $($rest)*);
151    };
152}
153
154/// A macro that generates the appropriate feature extraction macros.
155macro_rules! declare_features {
156    ( $(#[doc = $doc1:literal])* crate = $crate_features:tt; $(#[doc = $doc2:literal])* attr = $attrs:tt; ) => {
157        declare_features!( __ crate $crate_features );
158    };
159
160    ( __ crate [$(
161        $( #[doc = $doc:literal] )*
162        $feature_name:ident $feature_name_str:literal = $feature_include_macro:ident ;
163    )*] ) => {
164        /// # Crate features
165        ///
166        $(
167            #[doc = concat!("<code>", stringify!($feature_name), "</code>: ")]
168            $( #[doc = $doc] )*
169            #[doc = "\n"]
170        )*
171        pub mod features {
172        }
173
174        $(
175        #[doc(hidden)]
176        #[macro_export]
177        #[cfg(feature = $feature_name_str)]
178        macro_rules! $feature_include_macro {
179            ($true:item $false:item) => {
180                $true
181            };
182        }
183
184        #[doc(hidden)]
185        #[macro_export]
186        #[cfg(not(feature = $feature_name_str))]
187        macro_rules! $feature_include_macro {
188            ($true:item $false:item) => {
189                $false
190            };
191        }
192        )*
193
194        #[doc(hidden)]
195        #[macro_export]
196        macro_rules! __features_expand {
197            (next=$next_macro:path, $args:tt) => {
198                $crate::__features_expand_all!(next=$next_macro, $args, $( $feature_name / $feature_include_macro )*);
199            };
200        }
201    };
202}
203
204declare_features!(
205    /// Crate features: name/name as string/include macro.
206    crate = [
207        /// Enable support for the standard library. This is required for static ctor variables, but not for functions.
208        std "std" = __include_std_feature;
209        /// Mark all ctor functions with `used(linker)`.
210        used_linker "used_linker" = __include_used_linker_feature;
211        /// Enable support for the proc-macro `#[ctor]` and `#[dtor]` attributes.
212        proc_macro "proc_macro" = __include_proc_macro_feature;
213        /// Do not warn when a ctor or dtor is missing the `unsafe` keyword.
214        no_warn_on_missing_unsafe "no_warn_on_missing_unsafe" = __include_no_warn_on_missing_unsafe_feature;
215        /// Enable support for the priority parameter.
216        priority "priority" = __include_priority_feature;
217    ];
218
219    /// Attributes.
220    attr = [
221        /// Marks a ctor/dtor as unsafe. This will become a warning in 1.0.
222        unsafe = [unsafe];
223        /// Place the initialization function pointer in a custom link section. This may cause the initialization function
224        /// to fail to run or run earlier or later than other `ctor` functions.
225        link_section = [link_section($section:literal)];
226        /// Specify a custom crate path for the `ctor` crate. Used when re-exporting the ctor macro.
227        crate_path = [crate_path = $path:path];
228        /// Make the ctor function anonymous.
229        anonymous = [anonymous];
230        /// Mark this function with `used(linker)`.
231        used_linker = [used(linker)];
232        /// Set the ctor priority to a given value.
233        priority = [priority = $priority:literal];
234    ];
235);
236
237/// Expands all of the crate features into the features list.
238#[macro_export]
239#[doc(hidden)]
240macro_rules! __features_expand_all {
241    // Entry
242    (next=$next:path, $args:tt, $($macro:tt)*) => {
243        $crate::__features_expand_all!(: [] $next, $args, $($macro)*);
244    };
245    (: [$($features:tt)*] $next:path, $args:tt, $first_macro_feature:ident / $first_macro:ident $($rest:tt)*) => {
246        $crate:: $first_macro !(
247            $crate::__features_expand_all!(: [$first_macro_feature,$($features)*] $next, $args, $($rest)*);
248            $crate::__features_expand_all!(: [$($features)*] $next, $args, $($rest)*);
249        );
250    };
251    // Exit
252    (: [$($features:tt)*] $next:path, $args:tt,) => {
253        $next!(features=[$($features)*], $args);
254    };
255}
256
257/// Extract #[ctor/dtor] attribute parameters and crate features and turn them
258/// into a unified feature array.
259///
260/// Supported attributes:
261///
262/// - `used(linker)` -> crate feature: `used_linker`
263/// - `std` -> crate feature: `std`
264/// - `link_section = ...` -> feature: `(link_section = ...)`
265/// - `crate_path = ...` -> feature: `(crate_path = ...)`
266#[doc(hidden)]
267#[macro_export]
268macro_rules! __unify_features {
269    // Entry
270    (next=$next_macro:path, meta=[$($meta:tt)*], $($rest:tt)*) => {
271        // Expand all crate features
272        $crate::__features_expand!(next=$crate::__unify_features, [next=$next_macro, meta=[$($meta)*], $($rest)*]);
273    };
274
275    // Post-expansion
276    (features=[$($features:tt)*], [next=$next_macro:path, meta=[$($meta:tt)*], $($rest:tt)*]) => {
277        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($meta)*], features=[$($features)*], $($rest)*);
278    };
279
280    // Parse meta into features
281    (continue, next=$next_macro:path, meta=[unsafe $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
282        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[no_warn_on_missing_unsafe,$($features)*], $($rest)*);
283    };
284    (continue, next=$next_macro:path, meta=[used(linker) $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
285        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[used_linker,$($features)*], $($rest)*);
286    };
287    (continue, next=$next_macro:path, meta=[link_section = $section:tt $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
288        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[(link_section=($section)),$($features)*], $($rest)*);
289    };
290    (continue, next=$next_macro:path, meta=[crate_path = $path:path $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
291        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[(crate_path=$path),$($features)*], $($rest)*);
292    };
293    (continue, next=$next_macro:path, meta=[anonymous $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
294        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[anonymous,$($features)*], $($rest)*);
295    };
296    (continue, next=$next_macro:path, meta=[priority = $priority:tt $(, $($meta:tt)* )?], features=[$($features:tt)*], $($rest:tt)*) => {
297        // Convert the priority to a literal
298        $crate::__support::priority_to_literal!($crate::__support::unify_features, (@priority next=$next_macro, meta=[$($($meta)*)?], features=[$($features)*], $($rest)*), $priority);
299    };
300    ((@priority next=$next_macro:path, meta=[$($meta:tt)*], features=[$($features:tt)*], $($rest:tt)*), $priority:tt) => {
301        $crate::__support::unify_features!(continue, next=$next_macro, meta=[$($($meta)*)?], features=[(priority=($priority)),$($features)*], $($rest)*);
302    };
303    (continue, next=$next_macro:path, meta=[$unknown_meta:meta $($meta:tt)*], features=[$($features:tt)*], $($rest:tt)*) => {
304        compile_error!(concat!("Unknown attribute parameter: ", stringify!($unknown_meta)));
305    };
306
307    (continue, next=$next_macro:path, meta=[], features=[$($features:tt)*], $($rest:tt)*) => {
308        $next_macro!(features=[$($features)*], $($rest)*);
309    };
310}
311
312/// If the features array contains the requested feature, generates `if_true`, else `if_false`.
313///
314/// This macro matches the features recursively.
315///
316/// Example: `[(link_section = ".ctors") , used_linker , no_warn_on_missing_unsafe ,]`
317#[doc(hidden)]
318#[macro_export]
319#[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
320macro_rules! __if_has_feature {
321    (std,                         [std,                               $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_true)* };
322    (used_linker,                 [used_linker,                       $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_true)* };
323    (no_warn_on_missing_unsafe,   [no_warn_on_missing_unsafe,         $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_true)* };
324    (anonymous,                   [anonymous,                         $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_true)* };
325    ((link_section(c)),           [(link_section=($section:literal)), $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { #[link_section = $section] $($if_true)* };
326    ((priority(p)),               [(priority=($priority:literal)),    $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_true)* };
327
328    // Fallback rules
329    ($anything:tt, [$x:ident, $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $crate::__support::if_has_feature!($anything, [$($rest)*], {$($if_true)*}, {$($if_false)*}); };
330    ($anything:tt, [($x:ident=$y:tt), $($rest:tt)*], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $crate::__support::if_has_feature!($anything, [$($rest)*], {$($if_true)*}, {$($if_false)*}); };
331    ($anything:tt, [], {$($if_true:tt)*}, {$($if_false:tt)*}) => { $($if_false)* };
332}
333
334#[doc(hidden)]
335#[macro_export]
336macro_rules! __if_unsafe {
337    (, {$($if_unsafe:tt)*}, {$($if_safe:tt)*}) => { $($if_safe)* };
338    (unsafe, {$($if_unsafe:tt)*}, {$($if_safe:tt)*}) => { $($if_unsafe)* };
339}
340
341#[doc(hidden)]
342#[macro_export]
343macro_rules! __get_priority {
344    ($next:path, $args:tt, [(priority=($priority:literal)), $($rest:tt)*]) => { $next!($args, (".", $priority)); };
345    ($next:path, $args:tt, [$x:ident, $($rest:tt)*])                       => { $crate::__support::get_priority!($next, $args, [$($rest)*]); };
346    ($next:path, $args:tt, [($x:ident=$y:tt), $($rest:tt)*])               => { $crate::__support::get_priority!($next, $args, [$($rest)*]); };
347    ($next:path, $args:tt, [])                                             => { $next!($args, ("")); };
348}
349
350#[doc(hidden)]
351#[macro_export]
352#[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
353macro_rules! __ctor_entry {
354    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=unsafe fn $($item:tt)*) => {
355        $crate::__support::ctor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=unsafe, item=fn $($item)*);
356    };
357    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=fn $($item:tt)*) => {
358        $crate::__support::ctor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=, item=fn $($item)*);
359    };
360    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=static $ident:ident : $ty:ty = $(unsafe)? $({ $lit:literal })? $($lit2:literal)? ;) => {
361        compile_error!(concat!("Use `const ", stringify!($ident), " = ", stringify!($($lit)?$($lit2)?), ";` or `static ", stringify!($ident), ": ", stringify!($ty), " = ", stringify!($($lit)?$($lit2)?), ";` instead"));
362    };
363    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=static $ident:ident : $ty:ty = unsafe $($item:tt)*) => {
364        $crate::__support::ctor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=unsafe, item=static $ident: $ty = $($item)*);
365    };
366    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=static $ident:ident : $ty:ty = $($item:tt)*) => {
367        $crate::__support::ctor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=, item=static $ident: $ty = $($item)*);
368    };
369    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
370        $crate::__support::if_has_feature!(anonymous, $features, {
371            $crate::__support::ctor_entry!(unnamed, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
372        }, {
373            $crate::__support::ctor_entry!(named, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
374        });
375    };
376    (unnamed,features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
377        const _: () = {
378            $crate::__support::ctor_entry!(named, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
379        };
380    };
381    (named, features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
382        $(#[$fnmeta])*
383        #[allow(unused)]
384        $($vis)* $($unsafe)? fn $ident() {
385            #[allow(unsafe_code)]
386            {
387                $crate::__support::if_unsafe!($($unsafe)?, {}, {
388                    $crate::__support::if_has_feature!( no_warn_on_missing_unsafe, $features, {}, {
389                        #[deprecated="ctor deprecation note:\n\n\
390                        Use of #[ctor] without `#[ctor(unsafe)]` or `unsafe fn` is deprecated. As code execution\n\
391                        before main is unsupported by most Rust runtime functions, these functions must be marked\n\
392                        `unsafe`."]
393                            const fn ctor_without_unsafe_is_deprecated() {}
394                            #[allow(unused)]
395                            static UNSAFE_WARNING: () = ctor_without_unsafe_is_deprecated();
396                    });
397                });
398
399                $crate::__support::ctor_call!(
400                    features=$features,
401                    { unsafe { $ident(); } }
402                );
403            }
404
405            #[cfg(target_family = "wasm")]
406            {
407                static __CTOR__INITIALIZED: ::core::sync::atomic::AtomicBool = ::core::sync::atomic::AtomicBool::new(false);
408                if __CTOR__INITIALIZED.swap(true, ::core::sync::atomic::Ordering::Relaxed) {
409                    return;
410                }
411            }
412
413            $block
414        }
415    };
416    (features=$features:tt, imeta=$(#[$imeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=static $ident:ident : $ty:ty = $block:block;) => {
417        $crate::__support::if_has_feature!(std, $features, {
418            #[allow(clippy::incompatible_msrv)] // MSRV for statics is 1.70
419            $(#[$imeta])*
420            $($vis)* static $ident: $ident::Static<$ty> = $ident::Static::<$ty> {
421                _storage: {
422                    $crate::__support::ctor_call!(
423                        features=$features,
424                        { _ = &*$ident; }
425                    );
426
427                    ::std::sync::OnceLock::new()
428                }
429            };
430
431            #[allow(clippy::incompatible_msrv)] // MSRV for statics is 1.70
432            impl ::core::ops::Deref for $ident::Static<$ty> {
433                type Target = $ty;
434                fn deref(&self) -> &$ty {
435                    fn init() -> $ty $block
436
437                    self._storage.get_or_init(move || {
438                        init()
439                    })
440                }
441            }
442
443            #[doc(hidden)]
444            #[allow(non_upper_case_globals, non_snake_case)]
445            #[allow(unsafe_code)]
446            mod $ident {
447                $crate::__support::if_unsafe!($($unsafe)?, {}, {
448                    $crate::__support::if_has_feature!( no_warn_on_missing_unsafe, $features, {}, {
449                        #[deprecated="ctor deprecation note:\n\n\
450                        Use of #[ctor] without `#[ctor(unsafe)]` is deprecated. As code execution before main\n\
451                        is unsupported by most Rust runtime functions, these functions must be marked\n\
452                        `unsafe`."]
453                            const fn ctor_without_unsafe_is_deprecated() {}
454                            #[allow(unused)]
455                            static UNSAFE_WARNING: () = ctor_without_unsafe_is_deprecated();
456                    });
457                });
458
459                #[allow(non_camel_case_types, unreachable_pub)]
460                pub struct Static<T> {
461                    #[allow(clippy::incompatible_msrv)] // MSRV for statics is 1.70
462                    pub _storage: ::std::sync::OnceLock<T>
463                }
464            }
465        }, {
466            compile_error!("`#[ctor]` on `static` items requires the `std` feature");
467        });
468    };
469}
470
471// Code note:
472
473// You might wonder why we don't use `__attribute__((destructor))`/etc for
474// dtor. Unfortunately mingw doesn't appear to properly support section-based
475// hooks for shutdown, ie:
476
477// https://github.com/Alexpux/mingw-w64/blob/d0d7f784833bbb0b2d279310ddc6afb52fe47a46/mingw-w64-crt/crt/crtdll.c
478
479// In addition, OSX has removed support for section-based shutdown hooks after
480// warning about it for a number of years:
481
482// https://reviews.llvm.org/D45578
483
484#[doc(hidden)]
485#[macro_export]
486macro_rules! __dtor_entry {
487    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=fn $ident:ident() $block:block) => {
488        $crate::__support::dtor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=, item=fn $ident() $block);
489    };
490    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], item=unsafe fn $ident:ident() $block:block) => {
491        $crate::__support::dtor_entry!(features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=unsafe, item=fn $ident() $block);
492    };
493    (features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
494        $crate::__support::if_has_feature!(anonymous, $features, {
495            $crate::__support::dtor_entry!(unnamed, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
496        }, {
497            $crate::__support::dtor_entry!(named, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
498        });
499    };
500    (unnamed, features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
501        const _: () = {
502            $crate::__support::dtor_entry!(named, features=$features, imeta=$(#[$fnmeta])*, vis=[$($vis)*], unsafe=$($unsafe)?, item=fn $ident() $block);
503        };
504    };
505    (named, features=$features:tt, imeta=$(#[$fnmeta:meta])*, vis=[$($vis:tt)*], unsafe=$($unsafe:ident)?, item=fn $ident:ident() $block:block) => {
506        $(#[$fnmeta])*
507        #[allow(unused)]
508        $($vis)* $($unsafe)? fn $ident() {
509            #[allow(unsafe_code)]
510            {
511                $crate::__support::if_unsafe!($($unsafe)?, {}, {
512                    $crate::__support::if_has_feature!( no_warn_on_missing_unsafe, $features, {}, {
513                        #[deprecated="dtor deprecation note:\n\n\
514                        Use of #[dtor] without `#[dtor(unsafe)]` or `unsafe fn` is deprecated. As code execution\n\
515                        before main is unsupported by most Rust runtime functions, these functions must be marked\n\
516                        `unsafe`."]
517                        const fn dtor_without_unsafe_is_deprecated() {}
518                        #[allow(unused)]
519                        static UNSAFE_WARNING: () = dtor_without_unsafe_is_deprecated();
520                    });
521                });
522
523                $crate::__support::ctor_call!(
524                    features=$features,
525                    { unsafe {
526                        // Maintain compatibility with earlier versions of dtor. For
527                        // ctor 1.0 we can remove `dtor` as a default and then make
528                        // this `at_library_exit` by default.
529                        #[cfg(target_vendor = "apple")]
530                        $crate::__support::at_library_exit(__dtor);
531                        #[cfg(not(target_vendor = "apple"))]
532                        $crate::__support::at_binary_exit(__dtor);
533                    } }
534                );
535
536                $crate::__support::ctor_link_section!(
537                    exit,
538                    features=$features,
539                    (""),
540
541                    /*unsafe*/ extern "C" fn __dtor() { unsafe { $ident() } }
542                );
543            }
544
545            $block
546        }
547    };
548}
549
550/// Annotate a block with its appropriate link section.
551#[doc(hidden)]
552#[macro_export]
553macro_rules! __ctor_call {
554    (features=$features:tt, { $($block:tt)+ } ) => {
555        $crate::__support::get_priority!($crate::__support::ctor_call, [features=$features, { $($block)+ }], $features);
556    };
557    ([features=$features:tt, { $($block:tt)+ }], ("")) => {
558        $crate::__support::ctor_call!(@next [features=$features, { $($block)+ }], (""));
559    };
560    ([features=$features:tt, { $($block:tt)+ }], (".", $priority:literal)) => {
561        #[cfg(target_vendor = "apple")]
562        $crate::__support::link_section::declarative::in_section!(
563            #[in_section($crate::__support::explicit_ctor::CTOR)]
564            static _: (fn(), u16) = ({ fn ctor() { $($block)+ }; ctor }, $priority);
565        );
566        #[cfg(not(target_vendor = "apple"))]
567        $crate::__support::ctor_call!(@next [features=$features, { $($block)+ }], (".", $priority));
568    };
569    (@next [features=$features:tt, { $($block:tt)+ }], $priority:tt) => {
570        $crate::__support::ctor_link_section!(
571            array,
572            features=$features,
573            $priority,
574
575            #[allow(non_upper_case_globals, non_snake_case)]
576            #[doc(hidden)]
577            static __CTOR_FUNCTION: /*unsafe*/ extern "C" fn() -> $crate::__support::CtorRetType =
578            {
579                $crate::__support::ctor_link_section!(
580                    startup,
581                    features=$features,
582                    (""),
583
584                    #[allow(non_snake_case)]
585                    /*unsafe*/ extern "C" fn __CTOR_FUNCTION_INNER() -> $crate::__support::CtorRetType {
586                        $($block)+;
587                        ::core::default::Default::default()
588                    }
589                );
590
591                __CTOR_FUNCTION_INNER
592            };
593        );
594    }
595}
596
597/// Annotate a block with its appropriate link section.
598#[doc(hidden)]
599#[macro_export]
600macro_rules! __ctor_link_section {
601    ($section:ident, features=$features:tt, $priority:tt, $($block:tt)+) => {
602        $crate::__support::if_has_feature!(used_linker, $features, {
603            $crate::__support::ctor_link_section_attr!($section, $features, used(linker), $priority, $($block)+);
604        }, {
605            $crate::__support::ctor_link_section_attr!($section, $features, used, $priority, $($block)+);
606        });
607
608        #[cfg(not(any(
609            target_os = "linux",
610            target_os = "android",
611            target_os = "freebsd",
612            target_os = "netbsd",
613            target_os = "openbsd",
614            target_os = "dragonfly",
615            target_os = "illumos",
616            target_os = "haiku",
617            target_vendor = "apple",
618            target_family = "wasm",
619            target_arch = "xtensa",
620            target_vendor = "pc"
621        )))]
622        compile_error!("#[ctor]/#[dtor] is not supported on the current target");
623    }
624}
625
626/// Apply either the default cfg-based link section attributes, or
627/// the overridden link_section attribute.
628#[doc(hidden)]
629#[macro_export]
630macro_rules! __ctor_link_section_attr {
631    (array, $features:tt, $used:meta, ($($priority:tt)*), $item:item) => {
632        $crate::__support::if_has_feature!((link_section(c)), $features, {
633            #[allow(unsafe_code)]
634            #[$used]
635            $item
636        }, {
637            #[allow(unsafe_code)]
638            $crate::__support::ctor_link_section_attr!(
639                [[any(
640                    target_os = "linux",
641                    target_os = "android",
642                    target_os = "freebsd",
643                    target_os = "netbsd",
644                    target_os = "openbsd",
645                    target_os = "dragonfly",
646                    target_os = "illumos",
647                    target_os = "haiku",
648                    target_family = "wasm"
649                ), (concat!(".init_array", $($priority)*))],
650                [target_arch = "xtensa", (concat!(".ctors", $($priority)*))],
651                // macOS/Darwin do not support the priority parameter in the link section
652                [target_vendor = "apple", (concat!("__DATA,__mod_init_func,mod_init_funcs"))],
653                [all(target_vendor = "pc", any(target_env = "gnu", target_env = "msvc")), (concat!(".CRT$XCU", $($priority)*))],
654                // cygwin support: rustc 1.85 does not like the explicit target_os = "cygwin" condition (https://github.com/mmastrac/rust-ctor/issues/356)
655                // We can work around this by excluding gnu and msvc target envs
656                [all(target_vendor = "pc", not(any(target_env = "gnu", target_env = "msvc"))), (concat!(".ctors", $($priority)*))]
657                ],
658                #[$used]
659                $item
660            );
661        });
662    };
663    (startup, $features:tt, $used:meta, $priority:tt, $item:item) => {
664        #[cfg(not(clippy))]
665        $crate::__support::ctor_link_section_attr!([[any(target_os = "linux", target_os = "android"), (".text.startup")]], $item);
666
667        #[cfg(clippy)]
668        $item
669    };
670    (exit, $features:tt, $used:meta, $priority:tt, $item:item) => {
671        #[cfg(not(clippy))]
672        $crate::__support::ctor_link_section_attr!([[any(target_os = "linux", target_os = "android"), (".text.exit")]], $item);
673
674        #[cfg(clippy)]
675        $item
676    };
677    ([$( [$cond:meta, ($($literal:tt)*) ] ),+], $item:item) => {
678        #[cfg(not(clippy))]
679        $( #[cfg_attr($cond, link_section = $($literal)*)] )+
680        $item
681
682        #[cfg(clippy)]
683        $item
684    };
685}
686
687#[cfg(target_vendor = "apple")]
688#[doc(hidden)]
689#[macro_export]
690macro_rules! __priority_to_literal {
691    ($n:path,$a:tt,$priority:literal) => {
692        $n!($a, $priority);
693    };
694}
695
696#[cfg(not(target_vendor = "apple"))]
697#[doc(hidden)]
698#[macro_export]
699macro_rules! __priority_to_literal {
700    ($n:path,$a:tt,0) => {
701        $n!($a, "000");
702    };
703    ($n:path,$a:tt,1) => {
704        $n!($a, "001");
705    };
706    ($n:path,$a:tt,2) => {
707        $n!($a, "002");
708    };
709    ($n:path,$a:tt,3) => {
710        $n!($a, "003");
711    };
712    ($n:path,$a:tt,4) => {
713        $n!($a, "004");
714    };
715    ($n:path,$a:tt,5) => {
716        $n!($a, "005");
717    };
718    ($n:path,$a:tt,6) => {
719        $n!($a, "006");
720    };
721    ($n:path,$a:tt,7) => {
722        $n!($a, "007");
723    };
724    ($n:path,$a:tt,8) => {
725        $n!($a, "008");
726    };
727    ($n:path,$a:tt,9) => {
728        $n!($a, "009");
729    };
730    ($n:path,$a:tt,10) => {
731        $n!($a, "010");
732    };
733    ($n:path,$a:tt,11) => {
734        $n!($a, "011");
735    };
736    ($n:path,$a:tt,12) => {
737        $n!($a, "012");
738    };
739    ($n:path,$a:tt,13) => {
740        $n!($a, "013");
741    };
742    ($n:path,$a:tt,14) => {
743        $n!($a, "014");
744    };
745    ($n:path,$a:tt,15) => {
746        $n!($a, "015");
747    };
748    ($n:path,$a:tt,16) => {
749        $n!($a, "016");
750    };
751    ($n:path,$a:tt,17) => {
752        $n!($a, "017");
753    };
754    ($n:path,$a:tt,18) => {
755        $n!($a, "018");
756    };
757    ($n:path,$a:tt,19) => {
758        $n!($a, "019");
759    };
760    ($n:path,$a:tt,20) => {
761        $n!($a, "020");
762    };
763    ($n:path,$a:tt,21) => {
764        $n!($a, "021");
765    };
766    ($n:path,$a:tt,22) => {
767        $n!($a, "022");
768    };
769    ($n:path,$a:tt,23) => {
770        $n!($a, "023");
771    };
772    ($n:path,$a:tt,24) => {
773        $n!($a, "024");
774    };
775    ($n:path,$a:tt,25) => {
776        $n!($a, "025");
777    };
778    ($n:path,$a:tt,26) => {
779        $n!($a, "026");
780    };
781    ($n:path,$a:tt,27) => {
782        $n!($a, "027");
783    };
784    ($n:path,$a:tt,28) => {
785        $n!($a, "028");
786    };
787    ($n:path,$a:tt,29) => {
788        $n!($a, "029");
789    };
790    ($n:path,$a:tt,30) => {
791        $n!($a, "030");
792    };
793    ($n:path,$a:tt,31) => {
794        $n!($a, "031");
795    };
796    ($n:path,$a:tt,32) => {
797        $n!($a, "032");
798    };
799    ($n:path,$a:tt,33) => {
800        $n!($a, "033");
801    };
802    ($n:path,$a:tt,34) => {
803        $n!($a, "034");
804    };
805    ($n:path,$a:tt,35) => {
806        $n!($a, "035");
807    };
808    ($n:path,$a:tt,36) => {
809        $n!($a, "036");
810    };
811    ($n:path,$a:tt,37) => {
812        $n!($a, "037");
813    };
814    ($n:path,$a:tt,38) => {
815        $n!($a, "038");
816    };
817    ($n:path,$a:tt,39) => {
818        $n!($a, "039");
819    };
820    ($n:path,$a:tt,40) => {
821        $n!($a, "040");
822    };
823    ($n:path,$a:tt,41) => {
824        $n!($a, "041");
825    };
826    ($n:path,$a:tt,42) => {
827        $n!($a, "042");
828    };
829    ($n:path,$a:tt,43) => {
830        $n!($a, "043");
831    };
832    ($n:path,$a:tt,44) => {
833        $n!($a, "044");
834    };
835    ($n:path,$a:tt,45) => {
836        $n!($a, "045");
837    };
838    ($n:path,$a:tt,46) => {
839        $n!($a, "046");
840    };
841    ($n:path,$a:tt,47) => {
842        $n!($a, "047");
843    };
844    ($n:path,$a:tt,48) => {
845        $n!($a, "048");
846    };
847    ($n:path,$a:tt,49) => {
848        $n!($a, "049");
849    };
850    ($n:path,$a:tt,50) => {
851        $n!($a, "050");
852    };
853    ($n:path,$a:tt,51) => {
854        $n!($a, "051");
855    };
856    ($n:path,$a:tt,52) => {
857        $n!($a, "052");
858    };
859    ($n:path,$a:tt,53) => {
860        $n!($a, "053");
861    };
862    ($n:path,$a:tt,54) => {
863        $n!($a, "054");
864    };
865    ($n:path,$a:tt,55) => {
866        $n!($a, "055");
867    };
868    ($n:path,$a:tt,56) => {
869        $n!($a, "056");
870    };
871    ($n:path,$a:tt,57) => {
872        $n!($a, "057");
873    };
874    ($n:path,$a:tt,58) => {
875        $n!($a, "058");
876    };
877    ($n:path,$a:tt,59) => {
878        $n!($a, "059");
879    };
880    ($n:path,$a:tt,60) => {
881        $n!($a, "060");
882    };
883    ($n:path,$a:tt,61) => {
884        $n!($a, "061");
885    };
886    ($n:path,$a:tt,62) => {
887        $n!($a, "062");
888    };
889    ($n:path,$a:tt,63) => {
890        $n!($a, "063");
891    };
892    ($n:path,$a:tt,64) => {
893        $n!($a, "064");
894    };
895    ($n:path,$a:tt,65) => {
896        $n!($a, "065");
897    };
898    ($n:path,$a:tt,66) => {
899        $n!($a, "066");
900    };
901    ($n:path,$a:tt,67) => {
902        $n!($a, "067");
903    };
904    ($n:path,$a:tt,68) => {
905        $n!($a, "068");
906    };
907    ($n:path,$a:tt,69) => {
908        $n!($a, "069");
909    };
910    ($n:path,$a:tt,70) => {
911        $n!($a, "070");
912    };
913    ($n:path,$a:tt,71) => {
914        $n!($a, "071");
915    };
916    ($n:path,$a:tt,72) => {
917        $n!($a, "072");
918    };
919    ($n:path,$a:tt,73) => {
920        $n!($a, "073");
921    };
922    ($n:path,$a:tt,74) => {
923        $n!($a, "074");
924    };
925    ($n:path,$a:tt,75) => {
926        $n!($a, "075");
927    };
928    ($n:path,$a:tt,76) => {
929        $n!($a, "076");
930    };
931    ($n:path,$a:tt,77) => {
932        $n!($a, "077");
933    };
934    ($n:path,$a:tt,78) => {
935        $n!($a, "078");
936    };
937    ($n:path,$a:tt,79) => {
938        $n!($a, "079");
939    };
940    ($n:path,$a:tt,80) => {
941        $n!($a, "080");
942    };
943    ($n:path,$a:tt,81) => {
944        $n!($a, "081");
945    };
946    ($n:path,$a:tt,82) => {
947        $n!($a, "082");
948    };
949    ($n:path,$a:tt,83) => {
950        $n!($a, "083");
951    };
952    ($n:path,$a:tt,84) => {
953        $n!($a, "084");
954    };
955    ($n:path,$a:tt,85) => {
956        $n!($a, "085");
957    };
958    ($n:path,$a:tt,86) => {
959        $n!($a, "086");
960    };
961    ($n:path,$a:tt,87) => {
962        $n!($a, "087");
963    };
964    ($n:path,$a:tt,88) => {
965        $n!($a, "088");
966    };
967    ($n:path,$a:tt,89) => {
968        $n!($a, "089");
969    };
970    ($n:path,$a:tt,90) => {
971        $n!($a, "090");
972    };
973    ($n:path,$a:tt,91) => {
974        $n!($a, "091");
975    };
976    ($n:path,$a:tt,92) => {
977        $n!($a, "092");
978    };
979    ($n:path,$a:tt,93) => {
980        $n!($a, "093");
981    };
982    ($n:path,$a:tt,94) => {
983        $n!($a, "094");
984    };
985    ($n:path,$a:tt,95) => {
986        $n!($a, "095");
987    };
988    ($n:path,$a:tt,96) => {
989        $n!($a, "096");
990    };
991    ($n:path,$a:tt,97) => {
992        $n!($a, "097");
993    };
994    ($n:path,$a:tt,98) => {
995        $n!($a, "098");
996    };
997    ($n:path,$a:tt,99) => {
998        $n!($a, "099");
999    };
1000    ($n:path,$a:tt,$priority:literal) => {
1001        $n!($a, $priority);
1002    };
1003}