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