Skip to main content

std_detect/detect/
macros.rs

1/// Forward a literal to the relevant `__is_feature_detected` function.
2#[macro_export]
3#[allow_internal_unstable(stdarch_internal)]
4#[unstable(feature = "stdarch_internal", issue = "none")]
5macro_rules! detect_feature {
6    ($feature:tt, $feature_lit:tt) => {
7        $crate::detect_feature!($feature, $feature_lit : $feature_lit)
8    };
9    ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => {
10        // Emit `true` if enabled at compile time
11        $(cfg!(target_feature = $target_feature_lit) ||)*
12            $crate::detect::__is_feature_detected::$feature()
13    };
14    ($feature:tt, $feature_lit:tt, without cfg check: true) => {
15        $crate::detect::__is_feature_detected::$feature()
16    };
17}
18
19/// Verify that all features are known by `cfg!`.
20#[allow(unused_macros, reason = "it's used in the features! macro below")]
21macro_rules! check_cfg_feature {
22    ($feature:tt, $feature_lit:tt) => {
23        check_cfg_feature!($feature, $feature_lit : $feature_lit)
24    };
25    ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => {
26        $(cfg!(target_feature = $target_feature_lit);)*
27    };
28    ($feature:tt, $feature_lit:tt, without cfg check: $feature_cfg_check:literal) => {
29        #[allow(unexpected_cfgs, reason = $feature_lit)]
30        { cfg!(target_feature = $feature_lit) }
31    };
32}
33
34/// Create the `is_*_feature_detected` macro for an architecture.
35// Make sure any additions to this macro are tested in
36// `tests/ui/std/is_arch_feature_detected.AARCH64.stderr`.
37#[allow(unused)]
38macro_rules! features {
39    (
40        // Target or target family name, for use in diagnostic messages
41        @TARGET: $target:ident;
42        // Cfg for which this macro should be allowed
43        @CFG: $cfg:meta;
44        // Name like `is_*_feature_detected`
45        @MACRO_NAME: $macro_name:ident;
46        // Docs and stability attributes
47        @MACRO_ATTRS: $(#[$macro_attrs:meta])*
48        // Synonyms, with possible deprecation
49        $(@BIND_FEATURE_NAME: $bind_feature:tt; $feature_impl:tt; $(#[$deprecate_attr:meta];)?)*
50        // Features that exist but can't be detected at runtime, so emit an error.
51        $(@NO_RUNTIME_DETECTION: $nort_feature:tt; )*
52        // List of features
53        $(@FEATURE: #[$stability_attr:meta] $feature:ident: $feature_lit:tt;
54            // Skip verifying that the feature is known by `cfg!`, which also skips emitting `true`
55            // if the feature is enabled at compile time.
56            $(without cfg check: $feature_cfg_check:tt;)?
57            // If this feature is always enabled by some other feature, we can avoid the cost of
58            // checking them separately by instead only checking the root features.
59            $(implied by target_features: [$($target_feature_lit:tt),*];)?
60            // Doc comment for the feature.
61            $(#[$feature_comment:meta])*)*
62    ) => {
63        // The current arch's version actually does the feature detection.
64        #[macro_export]
65        $(#[$macro_attrs])*
66        #[allow_internal_unstable(stdarch_internal)]
67        #[cfg($cfg)]
68        #[doc(cfg($cfg))]
69        macro_rules! $macro_name {
70            // Emit all known features
71            $(
72                ($feature_lit) => {
73                    $crate::detect_feature!(
74                        $feature,
75                        $feature_lit
76                        $(, without cfg check: $feature_cfg_check)?
77                        $(: $($target_feature_lit),*)?
78                    )
79                };
80            )*
81            // Emit all aliases, with a deprecation notice if applicable
82            $(
83                ($bind_feature) => {
84                    {
85                        $(
86                            #[$deprecate_attr] macro_rules! deprecated_feature { {} => {}; }
87                            deprecated_feature! {};
88                        )?
89                        $crate::$macro_name!($feature_impl)
90                    }
91                };
92            )*
93            // Emit an error for features that can't be detected at runtime
94            $(
95                ($nort_feature) => {
96                    compile_error!(
97                        concat!(
98                            stringify!($nort_feature),
99                            " feature cannot be detected at run-time"
100                        )
101                    )
102                };
103            )*
104            // Allow a trailing comma
105            ($t:tt,) => {
106                $crate::$macro_name!($t)
107            };
108            // Fallback, error for unknown target features
109            ($t:tt) => {
110                compile_error!(
111                    concat!("unknown ", stringify!($target), " target feature: ", $t)
112                )
113            };
114        }
115
116        // All other arches still validate the features, but also
117        $(#[$macro_attrs])*
118        #[macro_export]
119        #[cfg(not($cfg))]
120        #[doc(cfg($cfg))]
121        macro_rules! $macro_name {
122            // All known features get an error
123            $(
124                ($feature_lit) => {
125                    compile_error!(
126                        concat!(
127                            "This macro cannot be used on the current target. You can prevent\n\
128                            it from being used in other architectures by guarding it behind\n\
129                            a `cfg(", stringify!($cfg), ")`."
130                        )
131                    )
132                };
133            )*
134            // Forward deprecated features
135            $(
136                ($bind_feature) => { $crate::$macro_name!($feature_impl) };
137            )*
138            // Emit an error for features that can't be detected at runtime
139            $(
140                ($nort_feature) => {
141                    compile_error!(
142                        concat!(
143                            stringify!($nort_feature),
144                            " feature cannot be detected at run-time"
145                        )
146                    )
147                };
148            )*
149            // Allow a trailing comma
150            ($t:tt,) => {
151                    $crate::$macro_name!($t);
152            };
153            // Fallback, error for unknown target features
154            ($t:tt) => {
155                compile_error!(
156                    concat!("unknown ", stringify!($target), " target feature: ", $t)
157                )
158            };
159        }
160
161        #[deny(unexpected_cfgs)]
162        #[deny(unfulfilled_lint_expectations)]
163        const _: () = {
164            $(
165                check_cfg_feature!(
166                    $feature,
167                    $feature_lit
168                    $(, without cfg check: $feature_cfg_check)?
169                    $(: $($target_feature_lit),*)?)
170                ;
171            )*
172        };
173
174        /// Each variant denotes a position in a bitset for a particular feature.
175        ///
176        /// PLEASE: do not use this, it is an implementation detail subject
177        /// to change.
178        #[doc(hidden)]
179        #[allow(non_camel_case_types)]
180        #[derive(Copy, Clone)]
181        #[repr(u8)]
182        #[unstable(feature = "stdarch_internal", issue = "none")]
183        #[cfg($cfg)]
184        pub(crate) enum Feature {
185            $(
186                $(#[$feature_comment])*
187                $feature,
188            )*
189        }
190
191        #[cfg($cfg)]
192        impl Feature {
193            pub(crate) const ALL: &[Feature] = &[
194                $(Feature::$feature,)*
195            ];
196
197            pub(crate) fn to_str(self) -> &'static str {
198                match self {
199                    $(Feature::$feature => $feature_lit,)*
200                }
201            }
202
203            #[cfg(feature = "std_detect_env_override")]
204            pub(crate) fn from_str(s: &str) -> Result<Feature, ()> {
205                match s {
206                    $($feature_lit => Ok(Feature::$feature),)*
207                    _ => Err(())
208                }
209            }
210        }
211
212        /// Each function performs run-time feature detection for a single
213        /// feature. This allow us to use stability attributes on a per feature
214        /// basis.
215        ///
216        /// PLEASE: do not use this, it is an implementation detail subject
217        /// to change.
218        #[doc(hidden)]
219        #[cfg($cfg)]
220        pub mod __is_feature_detected {
221            $(
222
223                /// PLEASE: do not use this, it is an implementation detail
224                /// subject to change.
225                #[inline]
226                #[doc(hidden)]
227                #[$stability_attr]
228                pub fn $feature() -> bool {
229                    $crate::detect::check_for($crate::detect::Feature::$feature)
230                }
231            )*
232        }
233    };
234}