]> git.lizzy.rs Git - rust.git/blob - library/core/src/internal_macros.rs
Rollup merge of #91133 - terrarier2111:unsafe-diagnostic, r=jackh726
[rust.git] / library / core / src / internal_macros.rs
1 // implements the unary operator "op &T"
2 // based on "op T" where T is expected to be `Copy`able
3 macro_rules! forward_ref_unop {
4     (impl $imp:ident, $method:ident for $t:ty) => {
5         forward_ref_unop!(impl $imp, $method for $t,
6                 #[stable(feature = "rust1", since = "1.0.0")]);
7     };
8     (impl const $imp:ident, $method:ident for $t:ty) => {
9         forward_ref_unop!(impl const $imp, $method for $t,
10                 #[stable(feature = "rust1", since = "1.0.0")]);
11     };
12     // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
13     (impl const $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
14         #[$attr]
15         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
16         impl const $imp for &$t {
17             type Output = <$t as $imp>::Output;
18
19             #[inline]
20             fn $method(self) -> <$t as $imp>::Output {
21                 $imp::$method(*self)
22             }
23         }
24     };
25     (impl $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
26         #[$attr]
27         impl $imp for &$t {
28             type Output = <$t as $imp>::Output;
29
30             #[inline]
31             fn $method(self) -> <$t as $imp>::Output {
32                 $imp::$method(*self)
33             }
34         }
35     }
36 }
37
38 // implements binary operators "&T op U", "T op &U", "&T op &U"
39 // based on "T op U" where T and U are expected to be `Copy`able
40 macro_rules! forward_ref_binop {
41     (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
42         forward_ref_binop!(impl $imp, $method for $t, $u,
43                 #[stable(feature = "rust1", since = "1.0.0")]);
44     };
45     (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
46         forward_ref_binop!(impl const $imp, $method for $t, $u,
47                 #[stable(feature = "rust1", since = "1.0.0")]);
48     };
49     // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
50     (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
51         #[$attr]
52         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
53         impl<'a> const $imp<$u> for &'a $t {
54             type Output = <$t as $imp<$u>>::Output;
55
56             #[inline]
57             fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
58                 $imp::$method(*self, other)
59             }
60         }
61
62         #[$attr]
63         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
64         impl const $imp<&$u> for $t {
65             type Output = <$t as $imp<$u>>::Output;
66
67             #[inline]
68             fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
69                 $imp::$method(self, *other)
70             }
71         }
72
73         #[$attr]
74         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
75         impl const $imp<&$u> for &$t {
76             type Output = <$t as $imp<$u>>::Output;
77
78             #[inline]
79             fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
80                 $imp::$method(*self, *other)
81             }
82         }
83     };
84     (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
85         #[$attr]
86         impl<'a> $imp<$u> for &'a $t {
87             type Output = <$t as $imp<$u>>::Output;
88
89             #[inline]
90             fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
91                 $imp::$method(*self, other)
92             }
93         }
94
95         #[$attr]
96         impl $imp<&$u> for $t {
97             type Output = <$t as $imp<$u>>::Output;
98
99             #[inline]
100             fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
101                 $imp::$method(self, *other)
102             }
103         }
104
105         #[$attr]
106         impl $imp<&$u> for &$t {
107             type Output = <$t as $imp<$u>>::Output;
108
109             #[inline]
110             fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
111                 $imp::$method(*self, *other)
112             }
113         }
114     }
115 }
116
117 // implements "T op= &U", based on "T op= U"
118 // where U is expected to be `Copy`able
119 macro_rules! forward_ref_op_assign {
120     (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
121         forward_ref_op_assign!(impl $imp, $method for $t, $u,
122                 #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
123     };
124     (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
125         forward_ref_op_assign!(impl const $imp, $method for $t, $u,
126                 #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
127     };
128     // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
129     (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
130         #[$attr]
131         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
132         impl const $imp<&$u> for $t {
133             #[inline]
134             fn $method(&mut self, other: &$u) {
135                 $imp::$method(self, *other);
136             }
137         }
138     };
139     (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
140         #[$attr]
141         impl $imp<&$u> for $t {
142             #[inline]
143             fn $method(&mut self, other: &$u) {
144                 $imp::$method(self, *other);
145             }
146         }
147     }
148 }
149
150 /// Create a zero-size type similar to a closure type, but named.
151 macro_rules! impl_fn_for_zst {
152     ($(
153         $( #[$attr: meta] )*
154         struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
155             |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
156             $body: block;
157     )+) => {
158         $(
159             $( #[$attr] )*
160             struct $Name;
161
162             impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
163                 #[inline]
164                 extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
165                     $body
166                 }
167             }
168
169             impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
170                 #[inline]
171                 extern "rust-call" fn call_mut(
172                     &mut self,
173                     ($( $arg, )*): ($( $ArgTy, )*)
174                 ) -> $ReturnTy {
175                     Fn::call(&*self, ($( $arg, )*))
176                 }
177             }
178
179             impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
180                 type Output = $ReturnTy;
181
182                 #[inline]
183                 extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
184                     Fn::call(&self, ($( $arg, )*))
185                 }
186             }
187         )+
188     }
189 }
190
191 /// A macro for defining `#[cfg]` if-else statements.
192 ///
193 /// `cfg_if` is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade
194 /// of `#[cfg]` cases, emitting the implementation which matches first.
195 ///
196 /// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code without having to
197 /// rewrite each clause multiple times.
198 ///
199 /// # Example
200 ///
201 /// ```
202 /// cfg_if! {
203 ///     if #[cfg(unix)] {
204 ///         fn foo() { /* unix specific functionality */ }
205 ///     } else if #[cfg(target_pointer_width = "32")] {
206 ///         fn foo() { /* non-unix, 32-bit functionality */ }
207 ///     } else {
208 ///         fn foo() { /* fallback implementation */ }
209 ///     }
210 /// }
211 ///
212 /// # fn main() {}
213 /// ```
214 // This is a copy of `cfg_if!` from the `cfg_if` crate.
215 // The recursive invocations should use $crate if this is ever exported.
216 macro_rules! cfg_if {
217     // match if/else chains with a final `else`
218     (
219         $(
220             if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
221         ) else+
222         else { $( $e_tokens:tt )* }
223     ) => {
224         cfg_if! {
225             @__items () ;
226             $(
227                 (( $i_meta ) ( $( $i_tokens )* )) ,
228             )+
229             (() ( $( $e_tokens )* )) ,
230         }
231     };
232
233     // match if/else chains lacking a final `else`
234     (
235         if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
236         $(
237             else if #[cfg( $e_meta:meta )] { $( $e_tokens:tt )* }
238         )*
239     ) => {
240         cfg_if! {
241             @__items () ;
242             (( $i_meta ) ( $( $i_tokens )* )) ,
243             $(
244                 (( $e_meta ) ( $( $e_tokens )* )) ,
245             )*
246         }
247     };
248
249     // Internal and recursive macro to emit all the items
250     //
251     // Collects all the previous cfgs in a list at the beginning, so they can be
252     // negated. After the semicolon is all the remaining items.
253     (@__items ( $( $_:meta , )* ) ; ) => {};
254     (
255         @__items ( $( $no:meta , )* ) ;
256         (( $( $yes:meta )? ) ( $( $tokens:tt )* )) ,
257         $( $rest:tt , )*
258     ) => {
259         // Emit all items within one block, applying an appropriate #[cfg]. The
260         // #[cfg] will require all `$yes` matchers specified and must also negate
261         // all previous matchers.
262         #[cfg(all(
263             $( $yes , )?
264             not(any( $( $no ),* ))
265         ))]
266         cfg_if! { @__identity $( $tokens )* }
267
268         // Recurse to emit all other items in `$rest`, and when we do so add all
269         // our `$yes` matchers to the list of `$no` matchers as future emissions
270         // will have to negate everything we just matched as well.
271         cfg_if! {
272             @__items ( $( $no , )* $( $yes , )? ) ;
273             $( $rest , )*
274         }
275     };
276
277     // Internal macro to make __apply work out right for different match types,
278     // because of how macros match/expand stuff.
279     (@__identity $( $tokens:tt )* ) => {
280         $( $tokens )*
281     };
282 }