]>
Commit | Line | Data |
---|---|---|
8faf50e0 XL |
1 | //! Parsing and validation of builtin attributes |
2 | ||
3dfed10e | 3 | use rustc_ast::{self as ast, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem}; |
74b04a01 | 4 | use rustc_ast_pretty::pprust; |
3dfed10e | 5 | use rustc_errors::{struct_span_err, Applicability}; |
dfeec247 | 6 | use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; |
60c5eb7d | 7 | use rustc_macros::HashStable_Generic; |
74b04a01 | 8 | use rustc_session::parse::{feature_err, ParseSess}; |
3dfed10e | 9 | use rustc_session::Session; |
dfeec247 XL |
10 | use rustc_span::hygiene::Transparency; |
11 | use rustc_span::{symbol::sym, symbol::Symbol, Span}; | |
12 | use std::num::NonZeroU32; | |
60c5eb7d XL |
13 | |
14 | pub fn is_builtin_attr(attr: &Attribute) -> bool { | |
dfeec247 | 15 | attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() |
60c5eb7d | 16 | } |
8faf50e0 XL |
17 | |
18 | enum AttrError { | |
9fa01778 XL |
19 | MultipleItem(String), |
20 | UnknownMetaItem(String, &'static [&'static str]), | |
8faf50e0 | 21 | MissingSince, |
3dfed10e | 22 | NonIdentFeature, |
8faf50e0 XL |
23 | MissingFeature, |
24 | MultipleStabilityLevels, | |
a1dfa0c6 | 25 | UnsupportedLiteral(&'static str, /* is_bytestr */ bool), |
8faf50e0 XL |
26 | } |
27 | ||
a1dfa0c6 XL |
28 | fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { |
29 | let diag = &sess.span_diagnostic; | |
8faf50e0 | 30 | match error { |
dfeec247 XL |
31 | AttrError::MultipleItem(item) => { |
32 | struct_span_err!(diag, span, E0538, "multiple '{}' items", item).emit(); | |
33 | } | |
8faf50e0 | 34 | AttrError::UnknownMetaItem(item, expected) => { |
dfeec247 | 35 | let expected = expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>(); |
8faf50e0 XL |
36 | struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item) |
37 | .span_label(span, format!("expected one of {}", expected.join(", "))) | |
38 | .emit(); | |
39 | } | |
74b04a01 XL |
40 | AttrError::MissingSince => { |
41 | struct_span_err!(diag, span, E0542, "missing 'since'").emit(); | |
42 | } | |
3dfed10e XL |
43 | AttrError::NonIdentFeature => { |
44 | struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit(); | |
45 | } | |
dfeec247 XL |
46 | AttrError::MissingFeature => { |
47 | struct_span_err!(diag, span, E0546, "missing 'feature'").emit(); | |
48 | } | |
49 | AttrError::MultipleStabilityLevels => { | |
50 | struct_span_err!(diag, span, E0544, "multiple stability levels").emit(); | |
51 | } | |
52 | AttrError::UnsupportedLiteral(msg, is_bytestr) => { | |
a1dfa0c6 XL |
53 | let mut err = struct_span_err!(diag, span, E0565, "{}", msg); |
54 | if is_bytestr { | |
55 | if let Ok(lint_str) = sess.source_map().span_to_snippet(span) { | |
9fa01778 | 56 | err.span_suggestion( |
a1dfa0c6 XL |
57 | span, |
58 | "consider removing the prefix", | |
74b04a01 | 59 | lint_str[1..].to_string(), |
a1dfa0c6 XL |
60 | Applicability::MaybeIncorrect, |
61 | ); | |
62 | } | |
63 | } | |
64 | err.emit(); | |
65 | } | |
8faf50e0 XL |
66 | } |
67 | } | |
68 | ||
c295e0f8 | 69 | #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] |
8faf50e0 XL |
70 | pub enum InlineAttr { |
71 | None, | |
72 | Hint, | |
73 | Always, | |
74 | Never, | |
75 | } | |
76 | ||
c295e0f8 | 77 | #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)] |
29967ef6 XL |
78 | pub enum InstructionSetAttr { |
79 | ArmA32, | |
80 | ArmT32, | |
81 | } | |
82 | ||
c295e0f8 | 83 | #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] |
9fa01778 XL |
84 | pub enum OptimizeAttr { |
85 | None, | |
86 | Speed, | |
87 | Size, | |
88 | } | |
89 | ||
f9f354fc XL |
90 | /// Represents the following attributes: |
91 | /// | |
92 | /// - `#[stable]` | |
93 | /// - `#[unstable]` | |
3dfed10e | 94 | #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] |
ba9703b0 | 95 | #[derive(HashStable_Generic)] |
8faf50e0 XL |
96 | pub struct Stability { |
97 | pub level: StabilityLevel, | |
98 | pub feature: Symbol, | |
60c5eb7d XL |
99 | } |
100 | ||
f9f354fc | 101 | /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. |
3dfed10e | 102 | #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] |
ba9703b0 | 103 | #[derive(HashStable_Generic)] |
60c5eb7d XL |
104 | pub struct ConstStability { |
105 | pub level: StabilityLevel, | |
106 | pub feature: Symbol, | |
0bf4aa26 XL |
107 | /// whether the function has a `#[rustc_promotable]` attribute |
108 | pub promotable: bool, | |
8faf50e0 XL |
109 | } |
110 | ||
111 | /// The available stability levels. | |
29967ef6 | 112 | #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] |
ba9703b0 | 113 | #[derive(HashStable_Generic)] |
8faf50e0 XL |
114 | pub enum StabilityLevel { |
115 | // Reason for the current stability level and the relevant rust-lang issue | |
60c5eb7d | 116 | Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool }, |
8faf50e0 XL |
117 | Stable { since: Symbol }, |
118 | } | |
119 | ||
120 | impl StabilityLevel { | |
121 | pub fn is_unstable(&self) -> bool { | |
1b1a35ee | 122 | matches!(self, StabilityLevel::Unstable { .. }) |
8faf50e0 XL |
123 | } |
124 | pub fn is_stable(&self) -> bool { | |
1b1a35ee | 125 | matches!(self, StabilityLevel::Stable { .. }) |
8faf50e0 XL |
126 | } |
127 | } | |
128 | ||
416331ca XL |
129 | /// Collects stability info from all stability attributes in `attrs`. |
130 | /// Returns `None` if no stability attributes are found. | |
dfeec247 | 131 | pub fn find_stability( |
3dfed10e | 132 | sess: &Session, |
dfeec247 XL |
133 | attrs: &[Attribute], |
134 | item_sp: Span, | |
6a06907d | 135 | ) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) { |
a1dfa0c6 | 136 | find_stability_generic(sess, attrs.iter(), item_sp) |
8faf50e0 XL |
137 | } |
138 | ||
dfeec247 | 139 | fn find_stability_generic<'a, I>( |
3dfed10e | 140 | sess: &Session, |
dfeec247 XL |
141 | attrs_iter: I, |
142 | item_sp: Span, | |
6a06907d | 143 | ) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) |
dfeec247 XL |
144 | where |
145 | I: Iterator<Item = &'a Attribute>, | |
8faf50e0 | 146 | { |
9fa01778 | 147 | use StabilityLevel::*; |
8faf50e0 | 148 | |
6a06907d XL |
149 | let mut stab: Option<(Stability, Span)> = None; |
150 | let mut const_stab: Option<(ConstStability, Span)> = None; | |
0bf4aa26 | 151 | let mut promotable = false; |
6a06907d | 152 | |
3dfed10e | 153 | let diagnostic = &sess.parse_sess.span_diagnostic; |
8faf50e0 XL |
154 | |
155 | 'outer: for attr in attrs_iter { | |
156 | if ![ | |
48663c56 | 157 | sym::rustc_const_unstable, |
60c5eb7d | 158 | sym::rustc_const_stable, |
48663c56 XL |
159 | sym::unstable, |
160 | sym::stable, | |
161 | sym::rustc_promotable, | |
dfeec247 XL |
162 | ] |
163 | .iter() | |
164 | .any(|&s| attr.has_name(s)) | |
165 | { | |
166 | continue; // not a stability level | |
8faf50e0 XL |
167 | } |
168 | ||
8faf50e0 | 169 | let meta = attr.meta(); |
0bf4aa26 | 170 | |
60c5eb7d | 171 | if attr.has_name(sym::rustc_promotable) { |
0bf4aa26 XL |
172 | promotable = true; |
173 | } | |
b7449926 | 174 | // attributes with data |
e74abb32 | 175 | else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta { |
8faf50e0 XL |
176 | let meta = meta.as_ref().unwrap(); |
177 | let get = |meta: &MetaItem, item: &mut Option<Symbol>| { | |
178 | if item.is_some() { | |
e74abb32 | 179 | handle_errors( |
3dfed10e | 180 | &sess.parse_sess, |
e74abb32 XL |
181 | meta.span, |
182 | AttrError::MultipleItem(pprust::path_to_string(&meta.path)), | |
183 | ); | |
dfeec247 | 184 | return false; |
8faf50e0 XL |
185 | } |
186 | if let Some(v) = meta.value_str() { | |
187 | *item = Some(v); | |
188 | true | |
189 | } else { | |
dfeec247 | 190 | struct_span_err!(diagnostic, meta.span, E0539, "incorrect meta item").emit(); |
8faf50e0 XL |
191 | false |
192 | } | |
193 | }; | |
194 | ||
60c5eb7d XL |
195 | let meta_name = meta.name_or_empty(); |
196 | match meta_name { | |
dfeec247 | 197 | sym::rustc_const_unstable | sym::unstable => { |
60c5eb7d | 198 | if meta_name == sym::unstable && stab.is_some() { |
3dfed10e XL |
199 | handle_errors( |
200 | &sess.parse_sess, | |
201 | attr.span, | |
202 | AttrError::MultipleStabilityLevels, | |
203 | ); | |
dfeec247 | 204 | break; |
60c5eb7d | 205 | } else if meta_name == sym::rustc_const_unstable && const_stab.is_some() { |
3dfed10e XL |
206 | handle_errors( |
207 | &sess.parse_sess, | |
208 | attr.span, | |
209 | AttrError::MultipleStabilityLevels, | |
210 | ); | |
dfeec247 | 211 | break; |
8faf50e0 XL |
212 | } |
213 | ||
214 | let mut feature = None; | |
215 | let mut reason = None; | |
216 | let mut issue = None; | |
74b04a01 | 217 | let mut issue_num = None; |
416331ca | 218 | let mut is_soft = false; |
8faf50e0 XL |
219 | for meta in metas { |
220 | if let Some(mi) = meta.meta_item() { | |
48663c56 | 221 | match mi.name_or_empty() { |
dfeec247 XL |
222 | sym::feature => { |
223 | if !get(mi, &mut feature) { | |
224 | continue 'outer; | |
225 | } | |
226 | } | |
227 | sym::reason => { | |
228 | if !get(mi, &mut reason) { | |
229 | continue 'outer; | |
230 | } | |
231 | } | |
232 | sym::issue => { | |
233 | if !get(mi, &mut issue) { | |
234 | continue 'outer; | |
235 | } | |
74b04a01 XL |
236 | |
237 | // These unwraps are safe because `get` ensures the meta item | |
238 | // is a name/value pair string literal. | |
239 | issue_num = match &*issue.unwrap().as_str() { | |
240 | "none" => None, | |
241 | issue => { | |
242 | let emit_diag = |msg: &str| { | |
243 | struct_span_err!( | |
244 | diagnostic, | |
245 | mi.span, | |
246 | E0545, | |
247 | "`issue` must be a non-zero numeric string \ | |
248 | or \"none\"", | |
249 | ) | |
250 | .span_label( | |
fc512014 | 251 | mi.name_value_literal_span().unwrap(), |
74b04a01 XL |
252 | msg, |
253 | ) | |
254 | .emit(); | |
255 | }; | |
256 | match issue.parse() { | |
1b1a35ee | 257 | Ok(0) => { |
74b04a01 XL |
258 | emit_diag( |
259 | "`issue` must not be \"0\", \ | |
260 | use \"none\" instead", | |
261 | ); | |
262 | continue 'outer; | |
263 | } | |
264 | Ok(num) => NonZeroU32::new(num), | |
265 | Err(err) => { | |
266 | emit_diag(&err.to_string()); | |
267 | continue 'outer; | |
268 | } | |
269 | } | |
270 | } | |
271 | }; | |
dfeec247 | 272 | } |
416331ca XL |
273 | sym::soft => { |
274 | if !mi.is_word() { | |
275 | let msg = "`soft` should not have any arguments"; | |
3dfed10e | 276 | sess.parse_sess.span_diagnostic.span_err(mi.span, msg); |
416331ca XL |
277 | } |
278 | is_soft = true; | |
279 | } | |
8faf50e0 XL |
280 | _ => { |
281 | handle_errors( | |
3dfed10e | 282 | &sess.parse_sess, |
532ac7d7 | 283 | meta.span(), |
8faf50e0 | 284 | AttrError::UnknownMetaItem( |
e74abb32 | 285 | pprust::path_to_string(&mi.path), |
dfeec247 | 286 | &["feature", "reason", "issue", "soft"], |
8faf50e0 XL |
287 | ), |
288 | ); | |
dfeec247 | 289 | continue 'outer; |
8faf50e0 XL |
290 | } |
291 | } | |
292 | } else { | |
a1dfa0c6 | 293 | handle_errors( |
3dfed10e | 294 | &sess.parse_sess, |
532ac7d7 | 295 | meta.span(), |
dfeec247 | 296 | AttrError::UnsupportedLiteral("unsupported literal", false), |
a1dfa0c6 | 297 | ); |
dfeec247 | 298 | continue 'outer; |
8faf50e0 XL |
299 | } |
300 | } | |
301 | ||
302 | match (feature, reason, issue) { | |
74b04a01 | 303 | (Some(feature), reason, Some(_)) => { |
3dfed10e XL |
304 | if !rustc_lexer::is_ident(&feature.as_str()) { |
305 | handle_errors( | |
306 | &sess.parse_sess, | |
307 | attr.span, | |
308 | AttrError::NonIdentFeature, | |
309 | ); | |
310 | continue; | |
311 | } | |
74b04a01 | 312 | let level = Unstable { reason, issue: issue_num, is_soft }; |
60c5eb7d | 313 | if sym::unstable == meta_name { |
6a06907d | 314 | stab = Some((Stability { level, feature }, attr.span)); |
60c5eb7d | 315 | } else { |
6a06907d XL |
316 | const_stab = Some(( |
317 | ConstStability { level, feature, promotable: false }, | |
318 | attr.span, | |
319 | )); | |
60c5eb7d | 320 | } |
8faf50e0 XL |
321 | } |
322 | (None, _, _) => { | |
3dfed10e | 323 | handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature); |
dfeec247 | 324 | continue; |
8faf50e0 XL |
325 | } |
326 | _ => { | |
dfeec247 XL |
327 | struct_span_err!(diagnostic, attr.span, E0547, "missing 'issue'") |
328 | .emit(); | |
329 | continue; | |
8faf50e0 XL |
330 | } |
331 | } | |
332 | } | |
dfeec247 | 333 | sym::rustc_const_stable | sym::stable => { |
60c5eb7d | 334 | if meta_name == sym::stable && stab.is_some() { |
3dfed10e XL |
335 | handle_errors( |
336 | &sess.parse_sess, | |
337 | attr.span, | |
338 | AttrError::MultipleStabilityLevels, | |
339 | ); | |
dfeec247 XL |
340 | break; |
341 | } else if meta_name == sym::rustc_const_stable && const_stab.is_some() { | |
3dfed10e XL |
342 | handle_errors( |
343 | &sess.parse_sess, | |
344 | attr.span, | |
345 | AttrError::MultipleStabilityLevels, | |
346 | ); | |
dfeec247 | 347 | break; |
8faf50e0 XL |
348 | } |
349 | ||
350 | let mut feature = None; | |
351 | let mut since = None; | |
352 | for meta in metas { | |
532ac7d7 | 353 | match meta { |
dfeec247 XL |
354 | NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() { |
355 | sym::feature => { | |
356 | if !get(mi, &mut feature) { | |
357 | continue 'outer; | |
a1dfa0c6 | 358 | } |
8faf50e0 | 359 | } |
dfeec247 XL |
360 | sym::since => { |
361 | if !get(mi, &mut since) { | |
362 | continue 'outer; | |
363 | } | |
364 | } | |
365 | _ => { | |
366 | handle_errors( | |
3dfed10e | 367 | &sess.parse_sess, |
dfeec247 XL |
368 | meta.span(), |
369 | AttrError::UnknownMetaItem( | |
370 | pprust::path_to_string(&mi.path), | |
371 | &["since", "note"], | |
372 | ), | |
373 | ); | |
374 | continue 'outer; | |
375 | } | |
a1dfa0c6 | 376 | }, |
532ac7d7 | 377 | NestedMetaItem::Literal(lit) => { |
a1dfa0c6 | 378 | handle_errors( |
3dfed10e | 379 | &sess.parse_sess, |
a1dfa0c6 | 380 | lit.span, |
dfeec247 | 381 | AttrError::UnsupportedLiteral("unsupported literal", false), |
a1dfa0c6 | 382 | ); |
dfeec247 | 383 | continue 'outer; |
8faf50e0 | 384 | } |
8faf50e0 XL |
385 | } |
386 | } | |
387 | ||
388 | match (feature, since) { | |
389 | (Some(feature), Some(since)) => { | |
dfeec247 | 390 | let level = Stable { since }; |
60c5eb7d | 391 | if sym::stable == meta_name { |
6a06907d | 392 | stab = Some((Stability { level, feature }, attr.span)); |
60c5eb7d | 393 | } else { |
6a06907d XL |
394 | const_stab = Some(( |
395 | ConstStability { level, feature, promotable: false }, | |
396 | attr.span, | |
397 | )); | |
60c5eb7d | 398 | } |
8faf50e0 XL |
399 | } |
400 | (None, _) => { | |
3dfed10e | 401 | handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature); |
dfeec247 | 402 | continue; |
8faf50e0 XL |
403 | } |
404 | _ => { | |
3dfed10e | 405 | handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince); |
dfeec247 | 406 | continue; |
8faf50e0 XL |
407 | } |
408 | } | |
409 | } | |
dfeec247 | 410 | _ => unreachable!(), |
8faf50e0 | 411 | } |
8faf50e0 XL |
412 | } |
413 | } | |
414 | ||
0bf4aa26 | 415 | // Merge the const-unstable info into the stability info |
1b1a35ee | 416 | if promotable { |
6a06907d | 417 | if let Some((ref mut stab, _)) = const_stab { |
48663c56 | 418 | stab.promotable = promotable; |
0bf4aa26 | 419 | } else { |
dfeec247 XL |
420 | struct_span_err!( |
421 | diagnostic, | |
422 | item_sp, | |
423 | E0717, | |
1b1a35ee XL |
424 | "`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` \ |
425 | or a `rustc_const_stable` attribute" | |
dfeec247 XL |
426 | ) |
427 | .emit(); | |
0bf4aa26 XL |
428 | } |
429 | } | |
430 | ||
60c5eb7d | 431 | (stab, const_stab) |
8faf50e0 XL |
432 | } |
433 | ||
3dfed10e XL |
434 | pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> { |
435 | sess.first_attr_value_str_by_name(attrs, sym::crate_name) | |
8faf50e0 XL |
436 | } |
437 | ||
438 | /// Tests if a cfg-pattern matches the cfg set | |
439 | pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool { | |
f9f354fc XL |
440 | eval_condition(cfg, sess, features, &mut |cfg| { |
441 | try_gate_cfg(cfg, sess, features); | |
dfeec247 XL |
442 | let error = |span, msg| { |
443 | sess.span_diagnostic.span_err(span, msg); | |
444 | true | |
445 | }; | |
532ac7d7 XL |
446 | if cfg.path.segments.len() != 1 { |
447 | return error(cfg.path.span, "`cfg` predicate key must be an identifier"); | |
8faf50e0 | 448 | } |
e74abb32 | 449 | match &cfg.kind { |
8faf50e0 XL |
450 | MetaItemKind::List(..) => { |
451 | error(cfg.span, "unexpected parentheses after `cfg` predicate key") | |
452 | } | |
e74abb32 | 453 | MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { |
a1dfa0c6 XL |
454 | handle_errors( |
455 | sess, | |
456 | lit.span, | |
457 | AttrError::UnsupportedLiteral( | |
458 | "literal in `cfg` predicate value must be a string", | |
dfeec247 | 459 | lit.kind.is_bytestr(), |
a1dfa0c6 XL |
460 | ), |
461 | ); | |
462 | true | |
8faf50e0 XL |
463 | } |
464 | MetaItemKind::NameValue(..) | MetaItemKind::Word => { | |
9fa01778 XL |
465 | let ident = cfg.ident().expect("multi-segment cfg predicate"); |
466 | sess.config.contains(&(ident.name, cfg.value_str())) | |
8faf50e0 XL |
467 | } |
468 | } | |
469 | }) | |
470 | } | |
471 | ||
f9f354fc | 472 | fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) { |
3dfed10e | 473 | let gate = find_gated_cfg(|sym| cfg.has_name(sym)); |
f9f354fc XL |
474 | if let (Some(feats), Some(gated_cfg)) = (features, gate) { |
475 | gate_cfg(&gated_cfg, cfg.span, sess, feats); | |
476 | } | |
477 | } | |
478 | ||
60c5eb7d XL |
479 | fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) { |
480 | let (cfg, feature, has_feature) = gated_cfg; | |
481 | if !has_feature(features) && !cfg_span.allows_unstable(*feature) { | |
482 | let explain = format!("`cfg({})` is experimental and subject to change", cfg); | |
74b04a01 | 483 | feature_err(sess, *feature, cfg_span, &explain).emit(); |
60c5eb7d XL |
484 | } |
485 | } | |
486 | ||
5869c6ff XL |
487 | #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] |
488 | struct Version { | |
489 | major: u16, | |
490 | minor: u16, | |
491 | patch: u16, | |
492 | } | |
493 | ||
494 | fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> { | |
495 | let mut components = s.split('-'); | |
496 | let d = components.next()?; | |
497 | if !allow_appendix && components.next().is_some() { | |
498 | return None; | |
499 | } | |
500 | let mut digits = d.splitn(3, '.'); | |
501 | let major = digits.next()?.parse().ok()?; | |
502 | let minor = digits.next()?.parse().ok()?; | |
503 | let patch = digits.next().unwrap_or("0").parse().ok()?; | |
504 | Some(Version { major, minor, patch }) | |
505 | } | |
506 | ||
8faf50e0 XL |
507 | /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to |
508 | /// evaluate individual items. | |
60c5eb7d XL |
509 | pub fn eval_condition( |
510 | cfg: &ast::MetaItem, | |
511 | sess: &ParseSess, | |
f9f354fc | 512 | features: Option<&Features>, |
60c5eb7d XL |
513 | eval: &mut impl FnMut(&ast::MetaItem) -> bool, |
514 | ) -> bool { | |
e74abb32 | 515 | match cfg.kind { |
f9f354fc XL |
516 | ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => { |
517 | try_gate_cfg(cfg, sess, features); | |
518 | let (min_version, span) = match &mis[..] { | |
519 | [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => { | |
520 | (sym, span) | |
521 | } | |
522 | [NestedMetaItem::Literal(Lit { span, .. }) | |
523 | | NestedMetaItem::MetaItem(MetaItem { span, .. })] => { | |
524 | sess.span_diagnostic | |
525 | .struct_span_err(*span, "expected a version literal") | |
526 | .emit(); | |
527 | return false; | |
528 | } | |
529 | [..] => { | |
530 | sess.span_diagnostic | |
531 | .struct_span_err(cfg.span, "expected single version literal") | |
532 | .emit(); | |
533 | return false; | |
534 | } | |
535 | }; | |
5869c6ff | 536 | let min_version = match parse_version(&min_version.as_str(), false) { |
f9f354fc XL |
537 | Some(ver) => ver, |
538 | None => { | |
5869c6ff XL |
539 | sess.span_diagnostic |
540 | .struct_span_warn( | |
541 | *span, | |
542 | "unknown version literal format, assuming it refers to a future version", | |
543 | ) | |
544 | .emit(); | |
f9f354fc XL |
545 | return false; |
546 | } | |
547 | }; | |
5869c6ff | 548 | let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap(); |
f9f354fc | 549 | |
5869c6ff XL |
550 | // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details |
551 | if sess.assume_incomplete_release { | |
552 | rustc_version > min_version | |
553 | } else { | |
554 | rustc_version >= min_version | |
555 | } | |
f9f354fc | 556 | } |
8faf50e0 XL |
557 | ast::MetaItemKind::List(ref mis) => { |
558 | for mi in mis.iter() { | |
559 | if !mi.is_meta_item() { | |
a1dfa0c6 XL |
560 | handle_errors( |
561 | sess, | |
532ac7d7 | 562 | mi.span(), |
dfeec247 | 563 | AttrError::UnsupportedLiteral("unsupported literal", false), |
a1dfa0c6 | 564 | ); |
8faf50e0 XL |
565 | return false; |
566 | } | |
567 | } | |
568 | ||
569 | // The unwraps below may look dangerous, but we've already asserted | |
570 | // that they won't fail with the loop above. | |
48663c56 | 571 | match cfg.name_or_empty() { |
f9f354fc XL |
572 | sym::any => mis |
573 | .iter() | |
574 | .any(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)), | |
575 | sym::all => mis | |
576 | .iter() | |
577 | .all(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)), | |
48663c56 | 578 | sym::not => { |
8faf50e0 | 579 | if mis.len() != 1 { |
dfeec247 XL |
580 | struct_span_err!( |
581 | sess.span_diagnostic, | |
582 | cfg.span, | |
583 | E0536, | |
584 | "expected 1 cfg-pattern" | |
585 | ) | |
586 | .emit(); | |
8faf50e0 XL |
587 | return false; |
588 | } | |
589 | ||
f9f354fc | 590 | !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval) |
dfeec247 | 591 | } |
9fa01778 | 592 | _ => { |
dfeec247 XL |
593 | struct_span_err!( |
594 | sess.span_diagnostic, | |
595 | cfg.span, | |
596 | E0537, | |
e74abb32 XL |
597 | "invalid predicate `{}`", |
598 | pprust::path_to_string(&cfg.path) | |
dfeec247 XL |
599 | ) |
600 | .emit(); | |
8faf50e0 XL |
601 | false |
602 | } | |
603 | } | |
8faf50e0 | 604 | } |
dfeec247 | 605 | ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => eval(cfg), |
8faf50e0 XL |
606 | } |
607 | } | |
608 | ||
fc512014 | 609 | #[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic)] |
8faf50e0 XL |
610 | pub struct Deprecation { |
611 | pub since: Option<Symbol>, | |
3dfed10e | 612 | /// The note to issue a reason. |
8faf50e0 | 613 | pub note: Option<Symbol>, |
3dfed10e XL |
614 | /// A text snippet used to completely replace any use of the deprecated item in an expression. |
615 | /// | |
616 | /// This is currently unstable. | |
617 | pub suggestion: Option<Symbol>, | |
618 | ||
619 | /// Whether to treat the since attribute as being a Rust version identifier | |
620 | /// (rather than an opaque string). | |
621 | pub is_since_rustc_version: bool, | |
8faf50e0 XL |
622 | } |
623 | ||
9fa01778 | 624 | /// Finds the deprecation attribute. `None` if none exists. |
29967ef6 XL |
625 | pub fn find_deprecation(sess: &Session, attrs: &[Attribute]) -> Option<(Deprecation, Span)> { |
626 | find_deprecation_generic(sess, attrs.iter()) | |
8faf50e0 XL |
627 | } |
628 | ||
29967ef6 | 629 | fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Deprecation, Span)> |
dfeec247 XL |
630 | where |
631 | I: Iterator<Item = &'a Attribute>, | |
8faf50e0 | 632 | { |
29967ef6 | 633 | let mut depr: Option<(Deprecation, Span)> = None; |
3dfed10e | 634 | let diagnostic = &sess.parse_sess.span_diagnostic; |
8faf50e0 XL |
635 | |
636 | 'outer: for attr in attrs_iter { | |
94222f64 | 637 | if !(attr.has_name(sym::deprecated) || attr.has_name(sym::rustc_deprecated)) { |
9fa01778 | 638 | continue; |
8faf50e0 XL |
639 | } |
640 | ||
29967ef6 XL |
641 | if let Some((_, span)) = &depr { |
642 | struct_span_err!(diagnostic, attr.span, E0550, "multiple deprecated attributes") | |
643 | .span_label(attr.span, "repeated deprecation attribute") | |
644 | .span_label(*span, "first deprecation attribute") | |
645 | .emit(); | |
dfeec247 | 646 | break; |
8faf50e0 XL |
647 | } |
648 | ||
e74abb32 XL |
649 | let meta = match attr.meta() { |
650 | Some(meta) => meta, | |
651 | None => continue, | |
652 | }; | |
3dfed10e XL |
653 | let mut since = None; |
654 | let mut note = None; | |
655 | let mut suggestion = None; | |
656 | match &meta.kind { | |
657 | MetaItemKind::Word => {} | |
658 | MetaItemKind::NameValue(..) => note = meta.value_str(), | |
9fa01778 XL |
659 | MetaItemKind::List(list) => { |
660 | let get = |meta: &MetaItem, item: &mut Option<Symbol>| { | |
661 | if item.is_some() { | |
a1dfa0c6 | 662 | handle_errors( |
3dfed10e | 663 | &sess.parse_sess, |
e74abb32 XL |
664 | meta.span, |
665 | AttrError::MultipleItem(pprust::path_to_string(&meta.path)), | |
a1dfa0c6 | 666 | ); |
dfeec247 | 667 | return false; |
a1dfa0c6 | 668 | } |
9fa01778 XL |
669 | if let Some(v) = meta.value_str() { |
670 | *item = Some(v); | |
671 | true | |
672 | } else { | |
673 | if let Some(lit) = meta.name_value_literal() { | |
674 | handle_errors( | |
3dfed10e | 675 | &sess.parse_sess, |
9fa01778 XL |
676 | lit.span, |
677 | AttrError::UnsupportedLiteral( | |
678 | "literal in `deprecated` \ | |
679 | value must be a string", | |
dfeec247 | 680 | lit.kind.is_bytestr(), |
9fa01778 XL |
681 | ), |
682 | ); | |
683 | } else { | |
dfeec247 XL |
684 | struct_span_err!(diagnostic, meta.span, E0551, "incorrect meta item") |
685 | .emit(); | |
9fa01778 | 686 | } |
a1dfa0c6 | 687 | |
9fa01778 XL |
688 | false |
689 | } | |
690 | }; | |
691 | ||
9fa01778 | 692 | for meta in list { |
532ac7d7 | 693 | match meta { |
dfeec247 XL |
694 | NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() { |
695 | sym::since => { | |
696 | if !get(mi, &mut since) { | |
697 | continue 'outer; | |
9fa01778 | 698 | } |
a1dfa0c6 | 699 | } |
94222f64 | 700 | sym::note if attr.has_name(sym::deprecated) => { |
3dfed10e XL |
701 | if !get(mi, &mut note) { |
702 | continue 'outer; | |
703 | } | |
704 | } | |
94222f64 | 705 | sym::reason if attr.has_name(sym::rustc_deprecated) => { |
dfeec247 XL |
706 | if !get(mi, &mut note) { |
707 | continue 'outer; | |
708 | } | |
709 | } | |
94222f64 | 710 | sym::suggestion if attr.has_name(sym::rustc_deprecated) => { |
3dfed10e XL |
711 | if !get(mi, &mut suggestion) { |
712 | continue 'outer; | |
713 | } | |
714 | } | |
dfeec247 XL |
715 | _ => { |
716 | handle_errors( | |
3dfed10e | 717 | &sess.parse_sess, |
dfeec247 XL |
718 | meta.span(), |
719 | AttrError::UnknownMetaItem( | |
720 | pprust::path_to_string(&mi.path), | |
94222f64 | 721 | if attr.has_name(sym::deprecated) { |
3dfed10e XL |
722 | &["since", "note"] |
723 | } else { | |
724 | &["since", "reason", "suggestion"] | |
725 | }, | |
dfeec247 XL |
726 | ), |
727 | ); | |
728 | continue 'outer; | |
729 | } | |
730 | }, | |
532ac7d7 | 731 | NestedMetaItem::Literal(lit) => { |
9fa01778 | 732 | handle_errors( |
3dfed10e | 733 | &sess.parse_sess, |
9fa01778 XL |
734 | lit.span, |
735 | AttrError::UnsupportedLiteral( | |
736 | "item in `deprecated` must be a key/value pair", | |
737 | false, | |
738 | ), | |
739 | ); | |
dfeec247 | 740 | continue 'outer; |
9fa01778 | 741 | } |
a1dfa0c6 | 742 | } |
8faf50e0 | 743 | } |
3dfed10e XL |
744 | } |
745 | } | |
8faf50e0 | 746 | |
94222f64 | 747 | if suggestion.is_some() && attr.has_name(sym::deprecated) { |
3dfed10e XL |
748 | unreachable!("only allowed on rustc_deprecated") |
749 | } | |
750 | ||
94222f64 | 751 | if attr.has_name(sym::rustc_deprecated) { |
3dfed10e XL |
752 | if since.is_none() { |
753 | handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince); | |
754 | continue; | |
9fa01778 | 755 | } |
3dfed10e XL |
756 | |
757 | if note.is_none() { | |
758 | struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit(); | |
759 | continue; | |
760 | } | |
761 | } | |
762 | ||
94222f64 | 763 | let is_since_rustc_version = attr.has_name(sym::rustc_deprecated); |
29967ef6 | 764 | depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span)); |
8faf50e0 XL |
765 | } |
766 | ||
767 | depr | |
768 | } | |
769 | ||
3dfed10e | 770 | #[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone)] |
8faf50e0 XL |
771 | pub enum ReprAttr { |
772 | ReprInt(IntType), | |
773 | ReprC, | |
774 | ReprPacked(u32), | |
775 | ReprSimd, | |
776 | ReprTransparent, | |
777 | ReprAlign(u32), | |
74b04a01 | 778 | ReprNoNiche, |
8faf50e0 XL |
779 | } |
780 | ||
3dfed10e XL |
781 | #[derive(Eq, PartialEq, Debug, Copy, Clone)] |
782 | #[derive(Encodable, Decodable, HashStable_Generic)] | |
8faf50e0 XL |
783 | pub enum IntType { |
784 | SignedInt(ast::IntTy), | |
dfeec247 | 785 | UnsignedInt(ast::UintTy), |
8faf50e0 XL |
786 | } |
787 | ||
788 | impl IntType { | |
789 | #[inline] | |
790 | pub fn is_signed(self) -> bool { | |
9fa01778 | 791 | use IntType::*; |
8faf50e0 XL |
792 | |
793 | match self { | |
794 | SignedInt(..) => true, | |
dfeec247 | 795 | UnsignedInt(..) => false, |
8faf50e0 XL |
796 | } |
797 | } | |
798 | } | |
799 | ||
800 | /// Parse #[repr(...)] forms. | |
801 | /// | |
802 | /// Valid repr contents: any of the primitive integral type names (see | |
803 | /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use | |
804 | /// the same discriminant size that the corresponding C enum would or C | |
c295e0f8 | 805 | /// structure layout, `packed` to remove padding, and `transparent` to delegate representation |
8faf50e0 | 806 | /// concerns to the only non-ZST field. |
3dfed10e | 807 | pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { |
9fa01778 | 808 | use ReprAttr::*; |
8faf50e0 XL |
809 | |
810 | let mut acc = Vec::new(); | |
3dfed10e | 811 | let diagnostic = &sess.parse_sess.span_diagnostic; |
60c5eb7d | 812 | if attr.has_name(sym::repr) { |
8faf50e0 | 813 | if let Some(items) = attr.meta_item_list() { |
8faf50e0 | 814 | for item in items { |
8faf50e0 | 815 | let mut recognised = false; |
9fa01778 | 816 | if item.is_word() { |
48663c56 XL |
817 | let hint = match item.name_or_empty() { |
818 | sym::C => Some(ReprC), | |
819 | sym::packed => Some(ReprPacked(1)), | |
820 | sym::simd => Some(ReprSimd), | |
821 | sym::transparent => Some(ReprTransparent), | |
74b04a01 | 822 | sym::no_niche => Some(ReprNoNiche), |
136023e0 XL |
823 | sym::align => { |
824 | let mut err = struct_span_err!( | |
825 | diagnostic, | |
826 | item.span(), | |
827 | E0589, | |
828 | "invalid `repr(align)` attribute: `align` needs an argument" | |
829 | ); | |
830 | err.span_suggestion( | |
831 | item.span(), | |
832 | "supply an argument here", | |
833 | "align(...)".to_string(), | |
834 | Applicability::HasPlaceholders, | |
835 | ); | |
836 | err.emit(); | |
837 | recognised = true; | |
838 | None | |
839 | } | |
532ac7d7 | 840 | name => int_type_of_word(name).map(ReprInt), |
8faf50e0 XL |
841 | }; |
842 | ||
843 | if let Some(h) = hint { | |
844 | recognised = true; | |
845 | acc.push(h); | |
846 | } | |
847 | } else if let Some((name, value)) = item.name_value_literal() { | |
8faf50e0 | 848 | let mut literal_error = None; |
48663c56 | 849 | if name == sym::align { |
8faf50e0 | 850 | recognised = true; |
e74abb32 | 851 | match parse_alignment(&value.kind) { |
8faf50e0 | 852 | Ok(literal) => acc.push(ReprAlign(literal)), |
dfeec247 | 853 | Err(message) => literal_error = Some(message), |
8faf50e0 | 854 | }; |
dfeec247 | 855 | } else if name == sym::packed { |
8faf50e0 | 856 | recognised = true; |
e74abb32 | 857 | match parse_alignment(&value.kind) { |
8faf50e0 | 858 | Ok(literal) => acc.push(ReprPacked(literal)), |
dfeec247 | 859 | Err(message) => literal_error = Some(message), |
8faf50e0 | 860 | }; |
136023e0 XL |
861 | } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche) |
862 | || int_type_of_word(name).is_some() | |
863 | { | |
864 | recognised = true; | |
865 | struct_span_err!( | |
866 | diagnostic, | |
867 | item.span(), | |
868 | E0552, | |
869 | "invalid representation hint: `{}` does not take a parenthesized argument list", | |
870 | name.to_ident_string(), | |
871 | ).emit(); | |
8faf50e0 XL |
872 | } |
873 | if let Some(literal_error) = literal_error { | |
dfeec247 XL |
874 | struct_span_err!( |
875 | diagnostic, | |
876 | item.span(), | |
877 | E0589, | |
136023e0 XL |
878 | "invalid `repr({})` attribute: {}", |
879 | name.to_ident_string(), | |
dfeec247 XL |
880 | literal_error |
881 | ) | |
882 | .emit(); | |
8faf50e0 | 883 | } |
29967ef6 | 884 | } else if let Some(meta_item) = item.meta_item() { |
136023e0 XL |
885 | if let MetaItemKind::NameValue(ref value) = meta_item.kind { |
886 | if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) { | |
887 | let name = meta_item.name_or_empty().to_ident_string(); | |
29967ef6 XL |
888 | recognised = true; |
889 | let mut err = struct_span_err!( | |
890 | diagnostic, | |
891 | item.span(), | |
892 | E0693, | |
136023e0 XL |
893 | "incorrect `repr({})` attribute format", |
894 | name, | |
29967ef6 XL |
895 | ); |
896 | match value.kind { | |
897 | ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { | |
898 | err.span_suggestion( | |
899 | item.span(), | |
900 | "use parentheses instead", | |
136023e0 | 901 | format!("{}({})", name, int), |
29967ef6 XL |
902 | Applicability::MachineApplicable, |
903 | ); | |
8faf50e0 | 904 | } |
29967ef6 XL |
905 | ast::LitKind::Str(s, _) => { |
906 | err.span_suggestion( | |
907 | item.span(), | |
908 | "use parentheses instead", | |
136023e0 | 909 | format!("{}({})", name, s), |
29967ef6 XL |
910 | Applicability::MachineApplicable, |
911 | ); | |
912 | } | |
913 | _ => {} | |
8faf50e0 | 914 | } |
29967ef6 | 915 | err.emit(); |
136023e0 XL |
916 | } else { |
917 | if matches!( | |
918 | meta_item.name_or_empty(), | |
919 | sym::C | sym::simd | sym::transparent | sym::no_niche | |
920 | ) || int_type_of_word(meta_item.name_or_empty()).is_some() | |
921 | { | |
922 | recognised = true; | |
923 | struct_span_err!( | |
924 | diagnostic, | |
925 | meta_item.span, | |
926 | E0552, | |
927 | "invalid representation hint: `{}` does not take a value", | |
928 | meta_item.name_or_empty().to_ident_string(), | |
929 | ) | |
930 | .emit(); | |
931 | } | |
932 | } | |
933 | } else if let MetaItemKind::List(_) = meta_item.kind { | |
934 | if meta_item.has_name(sym::align) { | |
935 | recognised = true; | |
936 | struct_span_err!( | |
937 | diagnostic, | |
938 | meta_item.span, | |
939 | E0693, | |
940 | "incorrect `repr(align)` attribute format: \ | |
941 | `align` takes exactly one argument in parentheses" | |
942 | ) | |
943 | .emit(); | |
944 | } else if meta_item.has_name(sym::packed) { | |
945 | recognised = true; | |
946 | struct_span_err!( | |
947 | diagnostic, | |
948 | meta_item.span, | |
949 | E0552, | |
950 | "incorrect `repr(packed)` attribute format: \ | |
951 | `packed` takes exactly one parenthesized argument, \ | |
952 | or no parentheses at all" | |
953 | ) | |
954 | .emit(); | |
955 | } else if matches!( | |
956 | meta_item.name_or_empty(), | |
957 | sym::C | sym::simd | sym::transparent | sym::no_niche | |
958 | ) || int_type_of_word(meta_item.name_or_empty()).is_some() | |
959 | { | |
960 | recognised = true; | |
961 | struct_span_err!( | |
962 | diagnostic, | |
963 | meta_item.span, | |
964 | E0552, | |
965 | "invalid representation hint: `{}` does not take a parenthesized argument list", | |
966 | meta_item.name_or_empty().to_ident_string(), | |
967 | ).emit(); | |
8faf50e0 XL |
968 | } |
969 | } | |
970 | } | |
971 | if !recognised { | |
136023e0 XL |
972 | // Not a word we recognize. This will be caught and reported by |
973 | // the `check_mod_attrs` pass, but this pass doesn't always run | |
974 | // (e.g. if we only pretty-print the source), so we have to gate | |
975 | // the `delay_span_bug` call as follows: | |
976 | if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) { | |
977 | diagnostic.delay_span_bug(item.span(), "unrecognized representation hint"); | |
978 | } | |
8faf50e0 XL |
979 | } |
980 | } | |
981 | } | |
982 | } | |
983 | acc | |
984 | } | |
985 | ||
48663c56 | 986 | fn int_type_of_word(s: Symbol) -> Option<IntType> { |
9fa01778 | 987 | use IntType::*; |
8faf50e0 XL |
988 | |
989 | match s { | |
48663c56 XL |
990 | sym::i8 => Some(SignedInt(ast::IntTy::I8)), |
991 | sym::u8 => Some(UnsignedInt(ast::UintTy::U8)), | |
992 | sym::i16 => Some(SignedInt(ast::IntTy::I16)), | |
993 | sym::u16 => Some(UnsignedInt(ast::UintTy::U16)), | |
994 | sym::i32 => Some(SignedInt(ast::IntTy::I32)), | |
995 | sym::u32 => Some(UnsignedInt(ast::UintTy::U32)), | |
996 | sym::i64 => Some(SignedInt(ast::IntTy::I64)), | |
997 | sym::u64 => Some(UnsignedInt(ast::UintTy::U64)), | |
998 | sym::i128 => Some(SignedInt(ast::IntTy::I128)), | |
999 | sym::u128 => Some(UnsignedInt(ast::UintTy::U128)), | |
1000 | sym::isize => Some(SignedInt(ast::IntTy::Isize)), | |
1001 | sym::usize => Some(UnsignedInt(ast::UintTy::Usize)), | |
dfeec247 | 1002 | _ => None, |
8faf50e0 XL |
1003 | } |
1004 | } | |
416331ca XL |
1005 | |
1006 | pub enum TransparencyError { | |
1007 | UnknownTransparency(Symbol, Span), | |
1008 | MultipleTransparencyAttrs(Span, Span), | |
1009 | } | |
1010 | ||
1011 | pub fn find_transparency( | |
dfeec247 | 1012 | attrs: &[Attribute], |
ba9703b0 | 1013 | macro_rules: bool, |
416331ca XL |
1014 | ) -> (Transparency, Option<TransparencyError>) { |
1015 | let mut transparency = None; | |
1016 | let mut error = None; | |
1017 | for attr in attrs { | |
94222f64 | 1018 | if attr.has_name(sym::rustc_macro_transparency) { |
416331ca XL |
1019 | if let Some((_, old_span)) = transparency { |
1020 | error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span)); | |
1021 | break; | |
1022 | } else if let Some(value) = attr.value_str() { | |
dfeec247 | 1023 | transparency = Some(( |
3dfed10e XL |
1024 | match value { |
1025 | sym::transparent => Transparency::Transparent, | |
1026 | sym::semitransparent => Transparency::SemiTransparent, | |
1027 | sym::opaque => Transparency::Opaque, | |
dfeec247 XL |
1028 | _ => { |
1029 | error = Some(TransparencyError::UnknownTransparency(value, attr.span)); | |
1030 | continue; | |
1031 | } | |
1032 | }, | |
1033 | attr.span, | |
1034 | )); | |
416331ca XL |
1035 | } |
1036 | } | |
1037 | } | |
ba9703b0 | 1038 | let fallback = if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }; |
416331ca XL |
1039 | (transparency.map_or(fallback, |t| t.0), error) |
1040 | } | |
74b04a01 XL |
1041 | |
1042 | pub fn allow_internal_unstable<'a>( | |
3dfed10e | 1043 | sess: &'a Session, |
1b1a35ee | 1044 | attrs: &'a [Attribute], |
6a06907d | 1045 | ) -> impl Iterator<Item = Symbol> + 'a { |
29967ef6 XL |
1046 | allow_unstable(sess, attrs, sym::allow_internal_unstable) |
1047 | } | |
1048 | ||
1049 | pub fn rustc_allow_const_fn_unstable<'a>( | |
1050 | sess: &'a Session, | |
1051 | attrs: &'a [Attribute], | |
6a06907d | 1052 | ) -> impl Iterator<Item = Symbol> + 'a { |
29967ef6 XL |
1053 | allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable) |
1054 | } | |
1055 | ||
1056 | fn allow_unstable<'a>( | |
1057 | sess: &'a Session, | |
1058 | attrs: &'a [Attribute], | |
1059 | symbol: Symbol, | |
6a06907d | 1060 | ) -> impl Iterator<Item = Symbol> + 'a { |
29967ef6 | 1061 | let attrs = sess.filter_by_name(attrs, symbol); |
1b1a35ee XL |
1062 | let list = attrs |
1063 | .filter_map(move |attr| { | |
1064 | attr.meta_item_list().or_else(|| { | |
1065 | sess.diagnostic().span_err( | |
1066 | attr.span, | |
29967ef6 | 1067 | &format!("`{}` expects a list of feature names", symbol.to_ident_string()), |
1b1a35ee XL |
1068 | ); |
1069 | None | |
1070 | }) | |
1071 | }) | |
1072 | .flatten(); | |
1073 | ||
6a06907d | 1074 | list.into_iter().filter_map(move |it| { |
74b04a01 XL |
1075 | let name = it.ident().map(|ident| ident.name); |
1076 | if name.is_none() { | |
29967ef6 XL |
1077 | sess.diagnostic().span_err( |
1078 | it.span(), | |
1079 | &format!("`{}` expects feature names", symbol.to_ident_string()), | |
1080 | ); | |
74b04a01 XL |
1081 | } |
1082 | name | |
6a06907d | 1083 | }) |
74b04a01 | 1084 | } |
136023e0 XL |
1085 | |
1086 | pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> { | |
1087 | if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { | |
1088 | if literal.is_power_of_two() { | |
1089 | // rustc_middle::ty::layout::Align restricts align to <= 2^29 | |
1090 | if *literal <= 1 << 29 { Ok(*literal as u32) } else { Err("larger than 2^29") } | |
1091 | } else { | |
1092 | Err("not a power of two") | |
1093 | } | |
1094 | } else { | |
1095 | Err("not an unsuffixed integer") | |
1096 | } | |
1097 | } |