1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // Functions dealing with attributes and meta items
13 pub use self::StabilityLevel
::*;
14 pub use self::ReprAttr
::*;
15 pub use self::IntType
::*;
18 use ast
::{AttrId, Attribute, Name, Ident}
;
19 use ast
::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}
;
20 use ast
::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind}
;
21 use codemap
::{Spanned, respan, dummy_spanned}
;
22 use syntax_pos
::{Span, DUMMY_SP}
;
24 use feature_gate
::{Features, GatedCfg}
;
25 use parse
::lexer
::comments
::{doc_comment_style, strip_doc_comment_decoration}
;
26 use parse
::parser
::Parser
;
27 use parse
::{self, ParseSess, PResult}
;
28 use parse
::token
::{self, Token}
;
31 use tokenstream
::{TokenStream, TokenTree, Delimited}
;
39 UnknownMetaItem(Name
),
42 MultipleStabilityLevels
,
46 fn handle_errors(diag
: &Handler
, span
: Span
, error
: AttrError
) {
48 AttrError
::MultipleItem(item
) => span_err
!(diag
, span
, E0538
,
49 "multiple '{}' items", item
),
50 AttrError
::UnknownMetaItem(item
) => span_err
!(diag
, span
, E0541
,
51 "unknown meta item '{}'", item
),
52 AttrError
::MissingSince
=> span_err
!(diag
, span
, E0542
, "missing 'since'"),
53 AttrError
::MissingFeature
=> span_err
!(diag
, span
, E0546
, "missing 'feature'"),
54 AttrError
::MultipleStabilityLevels
=> span_err
!(diag
, span
, E0544
,
55 "multiple stability levels"),
56 AttrError
::UnsupportedLiteral
=> span_err
!(diag
, span
, E0565
, "unsupported literal"),
60 pub fn mark_used(attr
: &Attribute
) {
61 debug
!("Marking {:?} as used.", attr
);
62 let AttrId(id
) = attr
.id
;
63 GLOBALS
.with(|globals
| {
64 let mut slot
= globals
.used_attrs
.lock();
65 let idx
= (id
/ 64) as usize;
67 if slot
.len() <= idx
{
68 slot
.resize(idx
+ 1, 0);
70 slot
[idx
] |= 1 << shift
;
74 pub fn is_used(attr
: &Attribute
) -> bool
{
75 let AttrId(id
) = attr
.id
;
76 GLOBALS
.with(|globals
| {
77 let slot
= globals
.used_attrs
.lock();
78 let idx
= (id
/ 64) as usize;
80 slot
.get(idx
).map(|bits
| bits
& (1 << shift
) != 0)
85 pub fn mark_known(attr
: &Attribute
) {
86 debug
!("Marking {:?} as known.", attr
);
87 let AttrId(id
) = attr
.id
;
88 GLOBALS
.with(|globals
| {
89 let mut slot
= globals
.known_attrs
.lock();
90 let idx
= (id
/ 64) as usize;
92 if slot
.len() <= idx
{
93 slot
.resize(idx
+ 1, 0);
95 slot
[idx
] |= 1 << shift
;
99 pub fn is_known(attr
: &Attribute
) -> bool
{
100 let AttrId(id
) = attr
.id
;
101 GLOBALS
.with(|globals
| {
102 let slot
= globals
.known_attrs
.lock();
103 let idx
= (id
/ 64) as usize;
105 slot
.get(idx
).map(|bits
| bits
& (1 << shift
) != 0)
110 impl NestedMetaItem
{
111 /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
112 pub fn meta_item(&self) -> Option
<&MetaItem
> {
114 NestedMetaItemKind
::MetaItem(ref item
) => Some(item
),
119 /// Returns the Lit if self is a NestedMetaItemKind::Literal.
120 pub fn literal(&self) -> Option
<&Lit
> {
122 NestedMetaItemKind
::Literal(ref lit
) => Some(lit
),
127 /// Returns the Span for `self`.
128 pub fn span(&self) -> Span
{
132 /// Returns true if this list item is a MetaItem with a name of `name`.
133 pub fn check_name(&self, name
: &str) -> bool
{
134 self.meta_item().map_or(false, |meta_item
| meta_item
.check_name(name
))
137 /// Returns the name of the meta item, e.g. `foo` in `#[foo]`,
138 /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem
139 pub fn name(&self) -> Option
<Name
> {
140 self.meta_item().and_then(|meta_item
| Some(meta_item
.name()))
143 /// Gets the string value if self is a MetaItem and the MetaItem is a
144 /// MetaItemKind::NameValue variant containing a string, otherwise None.
145 pub fn value_str(&self) -> Option
<Symbol
> {
146 self.meta_item().and_then(|meta_item
| meta_item
.value_str())
149 /// Returns a name and single literal value tuple of the MetaItem.
150 pub fn name_value_literal(&self) -> Option
<(Name
, &Lit
)> {
151 self.meta_item().and_then(
152 |meta_item
| meta_item
.meta_item_list().and_then(
154 if meta_item_list
.len() == 1 {
155 let nested_item
= &meta_item_list
[0];
156 if nested_item
.is_literal() {
157 Some((meta_item
.name(), nested_item
.literal().unwrap()))
167 /// Returns a MetaItem if self is a MetaItem with Kind Word.
168 pub fn word(&self) -> Option
<&MetaItem
> {
169 self.meta_item().and_then(|meta_item
| if meta_item
.is_word() {
176 /// Gets a list of inner meta items from a list MetaItem type.
177 pub fn meta_item_list(&self) -> Option
<&[NestedMetaItem
]> {
178 self.meta_item().and_then(|meta_item
| meta_item
.meta_item_list())
181 /// Returns `true` if the variant is MetaItem.
182 pub fn is_meta_item(&self) -> bool
{
183 self.meta_item().is_some()
186 /// Returns `true` if the variant is Literal.
187 pub fn is_literal(&self) -> bool
{
188 self.literal().is_some()
191 /// Returns `true` if self is a MetaItem and the meta item is a word.
192 pub fn is_word(&self) -> bool
{
193 self.word().is_some()
196 /// Returns `true` if self is a MetaItem and the meta item is a ValueString.
197 pub fn is_value_str(&self) -> bool
{
198 self.value_str().is_some()
201 /// Returns `true` if self is a MetaItem and the meta item is a list.
202 pub fn is_meta_item_list(&self) -> bool
{
203 self.meta_item_list().is_some()
208 pub fn check_name(&self, name
: &str) -> bool
{
209 let matches
= self.path
== name
;
216 pub fn name(&self) -> Option
<Name
> {
217 match self.path
.segments
.len() {
218 1 => Some(self.path
.segments
[0].identifier
.name
),
223 pub fn value_str(&self) -> Option
<Symbol
> {
224 self.meta().and_then(|meta
| meta
.value_str())
227 pub fn meta_item_list(&self) -> Option
<Vec
<NestedMetaItem
>> {
229 Some(MetaItem { node: MetaItemKind::List(list), .. }
) => Some(list
),
234 pub fn is_word(&self) -> bool
{
235 self.path
.segments
.len() == 1 && self.tokens
.is_empty()
238 pub fn span(&self) -> Span
{
242 pub fn is_meta_item_list(&self) -> bool
{
243 self.meta_item_list().is_some()
246 /// Indicates if the attribute is a Value String.
247 pub fn is_value_str(&self) -> bool
{
248 self.value_str().is_some()
253 pub fn name(&self) -> Name
{
257 pub fn value_str(&self) -> Option
<Symbol
> {
259 MetaItemKind
::NameValue(ref v
) => {
261 LitKind
::Str(ref s
, _
) => Some(*s
),
269 pub fn meta_item_list(&self) -> Option
<&[NestedMetaItem
]> {
271 MetaItemKind
::List(ref l
) => Some(&l
[..]),
276 pub fn is_word(&self) -> bool
{
278 MetaItemKind
::Word
=> true,
283 pub fn span(&self) -> Span { self.span }
285 pub fn check_name(&self, name
: &str) -> bool
{
289 pub fn is_value_str(&self) -> bool
{
290 self.value_str().is_some()
293 pub fn is_meta_item_list(&self) -> bool
{
294 self.meta_item_list().is_some()
299 /// Extract the MetaItem from inside this Attribute.
300 pub fn meta(&self) -> Option
<MetaItem
> {
301 let mut tokens
= self.tokens
.trees().peekable();
303 name
: match self.path
.segments
.len() {
304 1 => self.path
.segments
[0].identifier
.name
,
307 node
: if let Some(node
) = MetaItemKind
::from_tokens(&mut tokens
) {
308 if tokens
.peek().is_some() {
319 pub fn parse
<'a
, T
, F
>(&self, sess
: &'a ParseSess
, mut f
: F
) -> PResult
<'a
, T
>
320 where F
: FnMut(&mut Parser
<'a
>) -> PResult
<'a
, T
>,
322 let mut parser
= Parser
::new(sess
, self.tokens
.clone(), None
, false, false);
323 let result
= f(&mut parser
)?
;
324 if parser
.token
!= token
::Eof
{
325 parser
.unexpected()?
;
330 pub fn parse_list
<'a
, T
, F
>(&self, sess
: &'a ParseSess
, mut f
: F
) -> PResult
<'a
, Vec
<T
>>
331 where F
: FnMut(&mut Parser
<'a
>) -> PResult
<'a
, T
>,
333 if self.tokens
.is_empty() {
334 return Ok(Vec
::new());
336 self.parse(sess
, |parser
| {
337 parser
.expect(&token
::OpenDelim(token
::Paren
))?
;
338 let mut list
= Vec
::new();
339 while !parser
.eat(&token
::CloseDelim(token
::Paren
)) {
340 list
.push(f(parser
)?
);
341 if !parser
.eat(&token
::Comma
) {
342 parser
.expect(&token
::CloseDelim(token
::Paren
))?
;
350 pub fn parse_meta
<'a
>(&self, sess
: &'a ParseSess
) -> PResult
<'a
, MetaItem
> {
351 if self.path
.segments
.len() > 1 {
352 sess
.span_diagnostic
.span_err(self.path
.span
, "expected ident, found path");
356 name
: self.path
.segments
.last().unwrap().identifier
.name
,
357 node
: self.parse(sess
, |parser
| parser
.parse_meta_item_kind())?
,
362 /// Convert self to a normal #[doc="foo"] comment, if it is a
363 /// comment like `///` or `/** */`. (Returns self unchanged for
364 /// non-sugared doc attributes.)
365 pub fn with_desugared_doc
<T
, F
>(&self, f
: F
) -> T
where
366 F
: FnOnce(&Attribute
) -> T
,
368 if self.is_sugared_doc
{
369 let comment
= self.value_str().unwrap();
370 let meta
= mk_name_value_item_str(
371 Symbol
::intern("doc"),
372 Symbol
::intern(&strip_doc_comment_decoration(&comment
.as_str())));
373 let mut attr
= if self.style
== ast
::AttrStyle
::Outer
{
374 mk_attr_outer(self.span
, self.id
, meta
)
376 mk_attr_inner(self.span
, self.id
, meta
)
378 attr
.is_sugared_doc
= true;
388 pub fn mk_name_value_item_str(name
: Name
, value
: Symbol
) -> MetaItem
{
389 let value_lit
= dummy_spanned(LitKind
::Str(value
, ast
::StrStyle
::Cooked
));
390 mk_spanned_name_value_item(DUMMY_SP
, name
, value_lit
)
393 pub fn mk_name_value_item(name
: Name
, value
: ast
::Lit
) -> MetaItem
{
394 mk_spanned_name_value_item(DUMMY_SP
, name
, value
)
397 pub fn mk_list_item(name
: Name
, items
: Vec
<NestedMetaItem
>) -> MetaItem
{
398 mk_spanned_list_item(DUMMY_SP
, name
, items
)
401 pub fn mk_list_word_item(name
: Name
) -> ast
::NestedMetaItem
{
402 dummy_spanned(NestedMetaItemKind
::MetaItem(mk_spanned_word_item(DUMMY_SP
, name
)))
405 pub fn mk_word_item(name
: Name
) -> MetaItem
{
406 mk_spanned_word_item(DUMMY_SP
, name
)
409 pub fn mk_spanned_name_value_item(sp
: Span
, name
: Name
, value
: ast
::Lit
) -> MetaItem
{
410 MetaItem { span: sp, name: name, node: MetaItemKind::NameValue(value) }
413 pub fn mk_spanned_list_item(sp
: Span
, name
: Name
, items
: Vec
<NestedMetaItem
>) -> MetaItem
{
414 MetaItem { span: sp, name: name, node: MetaItemKind::List(items) }
417 pub fn mk_spanned_word_item(sp
: Span
, name
: Name
) -> MetaItem
{
418 MetaItem { span: sp, name: name, node: MetaItemKind::Word }
421 pub fn mk_attr_id() -> AttrId
{
422 use std
::sync
::atomic
::AtomicUsize
;
423 use std
::sync
::atomic
::Ordering
;
425 static NEXT_ATTR_ID
: AtomicUsize
= AtomicUsize
::new(0);
427 let id
= NEXT_ATTR_ID
.fetch_add(1, Ordering
::SeqCst
);
428 assert
!(id
!= ::std
::usize::MAX
);
432 /// Returns an inner attribute with the given value.
433 pub fn mk_attr_inner(span
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
434 mk_spanned_attr_inner(span
, id
, item
)
437 /// Returns an inner attribute with the given value and span.
438 pub fn mk_spanned_attr_inner(sp
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
441 style
: ast
::AttrStyle
::Inner
,
442 path
: ast
::Path
::from_ident(item
.span
, ast
::Ident
::with_empty_ctxt(item
.name
)),
443 tokens
: item
.node
.tokens(item
.span
),
444 is_sugared_doc
: false,
450 /// Returns an outer attribute with the given value.
451 pub fn mk_attr_outer(span
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
452 mk_spanned_attr_outer(span
, id
, item
)
455 /// Returns an outer attribute with the given value and span.
456 pub fn mk_spanned_attr_outer(sp
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
459 style
: ast
::AttrStyle
::Outer
,
460 path
: ast
::Path
::from_ident(item
.span
, ast
::Ident
::with_empty_ctxt(item
.name
)),
461 tokens
: item
.node
.tokens(item
.span
),
462 is_sugared_doc
: false,
467 pub fn mk_sugared_doc_attr(id
: AttrId
, text
: Symbol
, span
: Span
) -> Attribute
{
468 let style
= doc_comment_style(&text
.as_str());
469 let lit
= respan(span
, LitKind
::Str(text
, ast
::StrStyle
::Cooked
));
473 path
: ast
::Path
::from_ident(span
, ast
::Ident
::from_str("doc")),
474 tokens
: MetaItemKind
::NameValue(lit
).tokens(span
),
475 is_sugared_doc
: true,
480 pub fn list_contains_name(items
: &[NestedMetaItem
], name
: &str) -> bool
{
481 items
.iter().any(|item
| {
482 item
.check_name(name
)
486 pub fn contains_name(attrs
: &[Attribute
], name
: &str) -> bool
{
487 attrs
.iter().any(|item
| {
488 item
.check_name(name
)
492 pub fn find_by_name
<'a
>(attrs
: &'a
[Attribute
], name
: &str) -> Option
<&'a Attribute
> {
493 attrs
.iter().find(|attr
| attr
.check_name(name
))
496 pub fn first_attr_value_str_by_name(attrs
: &[Attribute
], name
: &str) -> Option
<Symbol
> {
498 .find(|at
| at
.check_name(name
))
499 .and_then(|at
| at
.value_str())
502 /// Check if `attrs` contains an attribute like `#![feature(feature_name)]`.
503 /// This will not perform any "sanity checks" on the form of the attributes.
504 pub fn contains_feature_attr(attrs
: &[Attribute
], feature_name
: &str) -> bool
{
505 attrs
.iter().any(|item
| {
506 item
.check_name("feature") &&
507 item
.meta_item_list().map(|list
| {
508 list
.iter().any(|mi
| {
509 mi
.word().map(|w
| w
.name() == feature_name
)
516 /* Higher-level applications */
518 pub fn find_crate_name(attrs
: &[Attribute
]) -> Option
<Symbol
> {
519 first_attr_value_str_by_name(attrs
, "crate_name")
522 #[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
523 pub enum InlineAttr
{
530 #[derive(Copy, Clone, PartialEq)]
531 pub enum UnwindAttr
{
536 /// Determine what `#[unwind]` attribute is present in `attrs`, if any.
537 pub fn find_unwind_attr(diagnostic
: Option
<&Handler
>, attrs
: &[Attribute
]) -> Option
<UnwindAttr
> {
538 let syntax_error
= |attr
: &Attribute
| {
541 span_err
!(d
, attr
.span
, E0633
, "malformed `#[unwind]` attribute");
546 attrs
.iter().fold(None
, |ia
, attr
| {
547 if attr
.path
!= "unwind" {
550 let meta
= match attr
.meta() {
551 Some(meta
) => meta
.node
,
555 MetaItemKind
::Word
=> {
558 MetaItemKind
::List(ref items
) => {
560 if items
.len() != 1 {
562 } else if list_contains_name(&items
[..], "allowed") {
563 Some(UnwindAttr
::Allowed
)
564 } else if list_contains_name(&items
[..], "aborts") {
565 Some(UnwindAttr
::Aborts
)
576 /// Tests if a cfg-pattern matches the cfg set
577 pub fn cfg_matches(cfg
: &ast
::MetaItem
, sess
: &ParseSess
, features
: Option
<&Features
>) -> bool
{
578 eval_condition(cfg
, sess
, &mut |cfg
| {
579 if let (Some(feats
), Some(gated_cfg
)) = (features
, GatedCfg
::gate(cfg
)) {
580 gated_cfg
.check_and_emit(sess
, feats
);
582 sess
.config
.contains(&(cfg
.name(), cfg
.value_str()))
586 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
587 /// evaluate individual items.
588 pub fn eval_condition
<F
>(cfg
: &ast
::MetaItem
, sess
: &ParseSess
, eval
: &mut F
)
590 where F
: FnMut(&ast
::MetaItem
) -> bool
593 ast
::MetaItemKind
::List(ref mis
) => {
594 for mi
in mis
.iter() {
595 if !mi
.is_meta_item() {
596 handle_errors(&sess
.span_diagnostic
, mi
.span
, AttrError
::UnsupportedLiteral
);
601 // The unwraps below may look dangerous, but we've already asserted
602 // that they won't fail with the loop above.
603 match &*cfg
.name
.as_str() {
604 "any" => mis
.iter().any(|mi
| {
605 eval_condition(mi
.meta_item().unwrap(), sess
, eval
)
607 "all" => mis
.iter().all(|mi
| {
608 eval_condition(mi
.meta_item().unwrap(), sess
, eval
)
612 span_err
!(sess
.span_diagnostic
, cfg
.span
, E0536
, "expected 1 cfg-pattern");
616 !eval_condition(mis
[0].meta_item().unwrap(), sess
, eval
)
619 span_err
!(sess
.span_diagnostic
, cfg
.span
, E0537
, "invalid predicate `{}`", p
);
624 ast
::MetaItemKind
::Word
| ast
::MetaItemKind
::NameValue(..) => {
630 /// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
631 #[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
632 pub struct Stability
{
633 pub level
: StabilityLevel
,
635 pub rustc_depr
: Option
<RustcDeprecation
>,
636 pub rustc_const_unstable
: Option
<RustcConstUnstable
>,
639 /// The available stability levels.
640 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
641 pub enum StabilityLevel
{
642 // Reason for the current stability level and the relevant rust-lang issue
643 Unstable { reason: Option<Symbol>, issue: u32 }
,
644 Stable { since: Symbol }
,
647 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
648 pub struct RustcDeprecation
{
653 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
654 pub struct RustcConstUnstable
{
658 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
659 pub struct Deprecation
{
660 pub since
: Option
<Symbol
>,
661 pub note
: Option
<Symbol
>,
664 impl StabilityLevel
{
665 pub fn is_unstable(&self) -> bool { if let Unstable {..}
= *self { true }
else { false }
}
666 pub fn is_stable(&self) -> bool { if let Stable {..}
= *self { true }
else { false }
}
669 fn find_stability_generic
<'a
, I
>(diagnostic
: &Handler
,
673 where I
: Iterator
<Item
= &'a Attribute
>
675 let mut stab
: Option
<Stability
> = None
;
676 let mut rustc_depr
: Option
<RustcDeprecation
> = None
;
677 let mut rustc_const_unstable
: Option
<RustcConstUnstable
> = None
;
679 'outer
: for attr
in attrs_iter
{
682 "rustc_const_unstable",
685 ].iter().any(|&s
| attr
.path
== s
) {
686 continue // not a stability level
691 let meta
= attr
.meta();
692 if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }
) = meta
{
693 let meta
= meta
.as_ref().unwrap();
694 let get
= |meta
: &MetaItem
, item
: &mut Option
<Symbol
>| {
696 handle_errors(diagnostic
, meta
.span
, AttrError
::MultipleItem(meta
.name()));
699 if let Some(v
) = meta
.value_str() {
703 span_err
!(diagnostic
, meta
.span
, E0539
, "incorrect meta item");
708 macro_rules
! get_meta
{
709 ($
($name
:ident
),+) => {
711 let mut $name
= None
;
714 if let Some(mi
) = meta
.meta_item() {
715 match &*mi
.name().as_str() {
718 => if !get(mi
, &mut $name
) { continue 'outer }
,
721 handle_errors(diagnostic
, mi
.span
,
722 AttrError
::UnknownMetaItem(mi
.name()));
727 handle_errors(diagnostic
, meta
.span
, AttrError
::UnsupportedLiteral
);
734 match &*meta
.name
.as_str() {
735 "rustc_deprecated" => {
736 if rustc_depr
.is_some() {
737 span_err
!(diagnostic
, item_sp
, E0540
,
738 "multiple rustc_deprecated attributes");
742 get_meta
!(since
, reason
);
744 match (since
, reason
) {
745 (Some(since
), Some(reason
)) => {
746 rustc_depr
= Some(RustcDeprecation
{
752 handle_errors(diagnostic
, attr
.span(), AttrError
::MissingSince
);
756 span_err
!(diagnostic
, attr
.span(), E0543
, "missing 'reason'");
761 "rustc_const_unstable" => {
762 if rustc_const_unstable
.is_some() {
763 span_err
!(diagnostic
, item_sp
, E0553
,
764 "multiple rustc_const_unstable attributes");
769 if let Some(feature
) = feature
{
770 rustc_const_unstable
= Some(RustcConstUnstable
{
774 span_err
!(diagnostic
, attr
.span(), E0629
, "missing 'feature'");
780 handle_errors(diagnostic
, attr
.span(), AttrError
::MultipleStabilityLevels
);
784 let mut feature
= None
;
785 let mut reason
= None
;
786 let mut issue
= None
;
788 if let Some(mi
) = meta
.meta_item() {
789 match &*mi
.name().as_str() {
790 "feature" => if !get(mi
, &mut feature
) { continue 'outer }
,
791 "reason" => if !get(mi
, &mut reason
) { continue 'outer }
,
792 "issue" => if !get(mi
, &mut issue
) { continue 'outer }
,
794 handle_errors(diagnostic
, meta
.span
,
795 AttrError
::UnknownMetaItem(mi
.name()));
800 handle_errors(diagnostic
, meta
.span
, AttrError
::UnsupportedLiteral
);
805 match (feature
, reason
, issue
) {
806 (Some(feature
), reason
, Some(issue
)) => {
807 stab
= Some(Stability
{
811 if let Ok(issue
) = issue
.as_str().parse() {
814 span_err
!(diagnostic
, attr
.span(), E0545
,
815 "incorrect 'issue'");
822 rustc_const_unstable
: None
,
826 handle_errors(diagnostic
, attr
.span(), AttrError
::MissingFeature
);
830 span_err
!(diagnostic
, attr
.span(), E0547
, "missing 'issue'");
837 handle_errors(diagnostic
, attr
.span(), AttrError
::MultipleStabilityLevels
);
841 let mut feature
= None
;
842 let mut since
= None
;
844 if let NestedMetaItemKind
::MetaItem(ref mi
) = meta
.node
{
845 match &*mi
.name().as_str() {
846 "feature" => if !get(mi
, &mut feature
) { continue 'outer }
,
847 "since" => if !get(mi
, &mut since
) { continue 'outer }
,
849 handle_errors(diagnostic
, meta
.span
,
850 AttrError
::UnknownMetaItem(mi
.name()));
855 handle_errors(diagnostic
, meta
.span
, AttrError
::UnsupportedLiteral
);
860 match (feature
, since
) {
861 (Some(feature
), Some(since
)) => {
862 stab
= Some(Stability
{
868 rustc_const_unstable
: None
,
872 handle_errors(diagnostic
, attr
.span(), AttrError
::MissingFeature
);
876 handle_errors(diagnostic
, attr
.span(), AttrError
::MissingSince
);
884 span_err
!(diagnostic
, attr
.span(), E0548
, "incorrect stability attribute type");
889 // Merge the deprecation info into the stability info
890 if let Some(rustc_depr
) = rustc_depr
{
891 if let Some(ref mut stab
) = stab
{
892 stab
.rustc_depr
= Some(rustc_depr
);
894 span_err
!(diagnostic
, item_sp
, E0549
,
895 "rustc_deprecated attribute must be paired with \
896 either stable or unstable attribute");
900 // Merge the const-unstable info into the stability info
901 if let Some(rustc_const_unstable
) = rustc_const_unstable
{
902 if let Some(ref mut stab
) = stab
{
903 stab
.rustc_const_unstable
= Some(rustc_const_unstable
);
905 span_err
!(diagnostic
, item_sp
, E0630
,
906 "rustc_const_unstable attribute must be paired with \
907 either stable or unstable attribute");
914 fn find_deprecation_generic
<'a
, I
>(diagnostic
: &Handler
,
917 -> Option
<Deprecation
>
918 where I
: Iterator
<Item
= &'a Attribute
>
920 let mut depr
: Option
<Deprecation
> = None
;
922 'outer
: for attr
in attrs_iter
{
923 if attr
.path
!= "deprecated" {
930 span_err
!(diagnostic
, item_sp
, E0550
, "multiple deprecated attributes");
934 depr
= if let Some(metas
) = attr
.meta_item_list() {
935 let get
= |meta
: &MetaItem
, item
: &mut Option
<Symbol
>| {
937 handle_errors(diagnostic
, meta
.span
, AttrError
::MultipleItem(meta
.name()));
940 if let Some(v
) = meta
.value_str() {
944 span_err
!(diagnostic
, meta
.span
, E0551
, "incorrect meta item");
949 let mut since
= None
;
952 if let NestedMetaItemKind
::MetaItem(ref mi
) = meta
.node
{
953 match &*mi
.name().as_str() {
954 "since" => if !get(mi
, &mut since
) { continue 'outer }
,
955 "note" => if !get(mi
, &mut note
) { continue 'outer }
,
957 handle_errors(diagnostic
, meta
.span
,
958 AttrError
::UnknownMetaItem(mi
.name()));
963 handle_errors(diagnostic
, meta
.span
, AttrError
::UnsupportedLiteral
);
968 Some(Deprecation {since: since, note: note}
)
970 Some(Deprecation{since: None, note: None}
)
977 /// Find the first stability attribute. `None` if none exists.
978 pub fn find_stability(diagnostic
: &Handler
, attrs
: &[Attribute
],
979 item_sp
: Span
) -> Option
<Stability
> {
980 find_stability_generic(diagnostic
, attrs
.iter(), item_sp
)
983 /// Find the deprecation attribute. `None` if none exists.
984 pub fn find_deprecation(diagnostic
: &Handler
, attrs
: &[Attribute
],
985 item_sp
: Span
) -> Option
<Deprecation
> {
986 find_deprecation_generic(diagnostic
, attrs
.iter(), item_sp
)
990 /// Parse #[repr(...)] forms.
992 /// Valid repr contents: any of the primitive integral type names (see
993 /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
994 /// the same discriminant size that the corresponding C enum would or C
995 /// structure layout, `packed` to remove padding, and `transparent` to elegate representation
996 /// concerns to the only non-ZST field.
997 pub fn find_repr_attrs(diagnostic
: &Handler
, attr
: &Attribute
) -> Vec
<ReprAttr
> {
998 let mut acc
= Vec
::new();
999 if attr
.path
== "repr" {
1000 if let Some(items
) = attr
.meta_item_list() {
1003 if !item
.is_meta_item() {
1004 handle_errors(diagnostic
, item
.span
, AttrError
::UnsupportedLiteral
);
1008 let mut recognised
= false;
1009 if let Some(mi
) = item
.word() {
1010 let word
= &*mi
.name().as_str();
1011 let hint
= match word
{
1013 "packed" => Some(ReprPacked
),
1014 "simd" => Some(ReprSimd
),
1015 "transparent" => Some(ReprTransparent
),
1016 _
=> match int_type_of_word(word
) {
1017 Some(ity
) => Some(ReprInt(ity
)),
1024 if let Some(h
) = hint
{
1028 } else if let Some((name
, value
)) = item
.name_value_literal() {
1029 if name
== "align" {
1031 let mut align_error
= None
;
1032 if let ast
::LitKind
::Int(align
, ast
::LitIntType
::Unsuffixed
) = value
.node
{
1033 if align
.is_power_of_two() {
1034 // rustc::ty::layout::Align restricts align to <= 2147483647
1035 if align
<= 2147483647 {
1036 acc
.push(ReprAlign(align
as u32));
1038 align_error
= Some("larger than 2147483647");
1041 align_error
= Some("not a power of two");
1044 align_error
= Some("not an unsuffixed integer");
1046 if let Some(align_error
) = align_error
{
1047 span_err
!(diagnostic
, item
.span
, E0589
,
1048 "invalid `repr(align)` attribute: {}", align_error
);
1053 // Not a word we recognize
1054 span_err
!(diagnostic
, item
.span
, E0552
,
1055 "unrecognized representation hint");
1063 fn int_type_of_word(s
: &str) -> Option
<IntType
> {
1065 "i8" => Some(SignedInt(ast
::IntTy
::I8
)),
1066 "u8" => Some(UnsignedInt(ast
::UintTy
::U8
)),
1067 "i16" => Some(SignedInt(ast
::IntTy
::I16
)),
1068 "u16" => Some(UnsignedInt(ast
::UintTy
::U16
)),
1069 "i32" => Some(SignedInt(ast
::IntTy
::I32
)),
1070 "u32" => Some(UnsignedInt(ast
::UintTy
::U32
)),
1071 "i64" => Some(SignedInt(ast
::IntTy
::I64
)),
1072 "u64" => Some(UnsignedInt(ast
::UintTy
::U64
)),
1073 "i128" => Some(SignedInt(ast
::IntTy
::I128
)),
1074 "u128" => Some(UnsignedInt(ast
::UintTy
::U128
)),
1075 "isize" => Some(SignedInt(ast
::IntTy
::Isize
)),
1076 "usize" => Some(UnsignedInt(ast
::UintTy
::Usize
)),
1081 #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
1091 #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
1093 SignedInt(ast
::IntTy
),
1094 UnsignedInt(ast
::UintTy
)
1099 pub fn is_signed(self) -> bool
{
1101 SignedInt(..) => true,
1102 UnsignedInt(..) => false
1108 fn tokens(&self) -> TokenStream
{
1109 let ident
= TokenTree
::Token(self.span
,
1110 Token
::from_ast_ident(Ident
::with_empty_ctxt(self.name
)));
1111 TokenStream
::concat(vec
![ident
.into(), self.node
.tokens(self.span
)])
1114 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<MetaItem
>
1115 where I
: Iterator
<Item
= TokenTree
>,
1117 let (span
, name
) = match tokens
.next() {
1118 Some(TokenTree
::Token(span
, Token
::Ident(ident
, _
))) => (span
, ident
.name
),
1119 Some(TokenTree
::Token(_
, Token
::Interpolated(ref nt
))) => match nt
.0 {
1120 token
::Nonterminal
::NtIdent(ident
, _
) => (ident
.span
, ident
.node
.name
),
1121 token
::Nonterminal
::NtMeta(ref meta
) => return Some(meta
.clone()),
1126 let list_closing_paren_pos
= tokens
.peek().map(|tt
| tt
.span().hi());
1127 let node
= MetaItemKind
::from_tokens(tokens
)?
;
1128 let hi
= match node
{
1129 MetaItemKind
::NameValue(ref lit
) => lit
.span
.hi(),
1130 MetaItemKind
::List(..) => list_closing_paren_pos
.unwrap_or(span
.hi()),
1133 Some(MetaItem { name, node, span: span.with_hi(hi) }
)
1138 pub fn tokens(&self, span
: Span
) -> TokenStream
{
1140 MetaItemKind
::Word
=> TokenStream
::empty(),
1141 MetaItemKind
::NameValue(ref lit
) => {
1142 TokenStream
::concat(vec
![TokenTree
::Token(span
, Token
::Eq
).into(), lit
.tokens()])
1144 MetaItemKind
::List(ref list
) => {
1145 let mut tokens
= Vec
::new();
1146 for (i
, item
) in list
.iter().enumerate() {
1148 tokens
.push(TokenTree
::Token(span
, Token
::Comma
).into());
1150 tokens
.push(item
.node
.tokens());
1152 TokenTree
::Delimited(span
, Delimited
{
1153 delim
: token
::Paren
,
1154 tts
: TokenStream
::concat(tokens
).into(),
1160 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<MetaItemKind
>
1161 where I
: Iterator
<Item
= TokenTree
>,
1163 let delimited
= match tokens
.peek().cloned() {
1164 Some(TokenTree
::Token(_
, token
::Eq
)) => {
1166 return if let Some(TokenTree
::Token(span
, token
)) = tokens
.next() {
1167 LitKind
::from_token(token
)
1168 .map(|lit
| MetaItemKind
::NameValue(Spanned { node: lit, span: span }
))
1173 Some(TokenTree
::Delimited(_
, ref delimited
)) if delimited
.delim
== token
::Paren
=> {
1177 _
=> return Some(MetaItemKind
::Word
),
1180 let mut tokens
= delimited
.into_trees().peekable();
1181 let mut result
= Vec
::new();
1182 while let Some(..) = tokens
.peek() {
1183 let item
= NestedMetaItemKind
::from_tokens(&mut tokens
)?
;
1184 result
.push(respan(item
.span(), item
));
1185 match tokens
.next() {
1186 None
| Some(TokenTree
::Token(_
, Token
::Comma
)) => {}
1190 Some(MetaItemKind
::List(result
))
1194 impl NestedMetaItemKind
{
1195 fn span(&self) -> Span
{
1197 NestedMetaItemKind
::MetaItem(ref item
) => item
.span
,
1198 NestedMetaItemKind
::Literal(ref lit
) => lit
.span
,
1202 fn tokens(&self) -> TokenStream
{
1204 NestedMetaItemKind
::MetaItem(ref item
) => item
.tokens(),
1205 NestedMetaItemKind
::Literal(ref lit
) => lit
.tokens(),
1209 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<NestedMetaItemKind
>
1210 where I
: Iterator
<Item
= TokenTree
>,
1212 if let Some(TokenTree
::Token(span
, token
)) = tokens
.peek().cloned() {
1213 if let Some(node
) = LitKind
::from_token(token
) {
1215 return Some(NestedMetaItemKind
::Literal(respan(span
, node
)));
1219 MetaItem
::from_tokens(tokens
).map(NestedMetaItemKind
::MetaItem
)
1224 fn tokens(&self) -> TokenStream
{
1225 TokenTree
::Token(self.span
, self.node
.token()).into()
1230 fn token(&self) -> Token
{
1234 LitKind
::Str(string
, ast
::StrStyle
::Cooked
) => {
1235 let mut escaped
= String
::new();
1236 for ch
in string
.as_str().chars() {
1237 escaped
.extend(ch
.escape_unicode());
1239 Token
::Literal(token
::Lit
::Str_(Symbol
::intern(&escaped
)), None
)
1241 LitKind
::Str(string
, ast
::StrStyle
::Raw(n
)) => {
1242 Token
::Literal(token
::Lit
::StrRaw(string
, n
), None
)
1244 LitKind
::ByteStr(ref bytes
) => {
1245 let string
= bytes
.iter().cloned().flat_map(ascii
::escape_default
)
1246 .map(Into
::<char>::into
).collect
::<String
>();
1247 Token
::Literal(token
::Lit
::ByteStr(Symbol
::intern(&string
)), None
)
1249 LitKind
::Byte(byte
) => {
1250 let string
: String
= ascii
::escape_default(byte
).map(Into
::<char>::into
).collect();
1251 Token
::Literal(token
::Lit
::Byte(Symbol
::intern(&string
)), None
)
1253 LitKind
::Char(ch
) => {
1254 let string
: String
= ch
.escape_default().map(Into
::<char>::into
).collect();
1255 Token
::Literal(token
::Lit
::Char(Symbol
::intern(&string
)), None
)
1257 LitKind
::Int(n
, ty
) => {
1258 let suffix
= match ty
{
1259 ast
::LitIntType
::Unsigned(ty
) => Some(Symbol
::intern(ty
.ty_to_string())),
1260 ast
::LitIntType
::Signed(ty
) => Some(Symbol
::intern(ty
.ty_to_string())),
1261 ast
::LitIntType
::Unsuffixed
=> None
,
1263 Token
::Literal(token
::Lit
::Integer(Symbol
::intern(&n
.to_string())), suffix
)
1265 LitKind
::Float(symbol
, ty
) => {
1266 Token
::Literal(token
::Lit
::Float(symbol
), Some(Symbol
::intern(ty
.ty_to_string())))
1268 LitKind
::FloatUnsuffixed(symbol
) => Token
::Literal(token
::Lit
::Float(symbol
), None
),
1269 LitKind
::Bool(value
) => Token
::Ident(Ident
::with_empty_ctxt(Symbol
::intern(if value
{
1277 fn from_token(token
: Token
) -> Option
<LitKind
> {
1279 Token
::Ident(ident
, false) if ident
.name
== "true" => Some(LitKind
::Bool(true)),
1280 Token
::Ident(ident
, false) if ident
.name
== "false" => Some(LitKind
::Bool(false)),
1281 Token
::Interpolated(ref nt
) => match nt
.0 {
1282 token
::NtExpr(ref v
) => match v
.node
{
1283 ExprKind
::Lit(ref lit
) => Some(lit
.node
.clone()),
1288 Token
::Literal(lit
, suf
) => {
1289 let (suffix_illegal
, result
) = parse
::lit_token(lit
, suf
, None
);
1290 if suffix_illegal
&& suf
.is_some() {
1300 pub trait HasAttrs
: Sized
{
1301 fn attrs(&self) -> &[ast
::Attribute
];
1302 fn map_attrs
<F
: FnOnce(Vec
<ast
::Attribute
>) -> Vec
<ast
::Attribute
>>(self, f
: F
) -> Self;
1305 impl<T
: HasAttrs
> HasAttrs
for Spanned
<T
> {
1306 fn attrs(&self) -> &[ast
::Attribute
] { self.node.attrs() }
1307 fn map_attrs
<F
: FnOnce(Vec
<ast
::Attribute
>) -> Vec
<ast
::Attribute
>>(self, f
: F
) -> Self {
1308 respan(self.span
, self.node
.map_attrs(f
))
1312 impl HasAttrs
for Vec
<Attribute
> {
1313 fn attrs(&self) -> &[Attribute
] {
1316 fn map_attrs
<F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>>(self, f
: F
) -> Self {
1321 impl HasAttrs
for ThinVec
<Attribute
> {
1322 fn attrs(&self) -> &[Attribute
] {
1325 fn map_attrs
<F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>>(self, f
: F
) -> Self {
1326 f(self.into()).into()
1330 impl<T
: HasAttrs
+ '
static> HasAttrs
for P
<T
> {
1331 fn attrs(&self) -> &[Attribute
] {
1334 fn map_attrs
<F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>>(self, f
: F
) -> Self {
1335 self.map(|t
| t
.map_attrs(f
))
1339 impl HasAttrs
for StmtKind
{
1340 fn attrs(&self) -> &[Attribute
] {
1342 StmtKind
::Local(ref local
) => local
.attrs(),
1343 StmtKind
::Item(..) => &[],
1344 StmtKind
::Expr(ref expr
) | StmtKind
::Semi(ref expr
) => expr
.attrs(),
1345 StmtKind
::Mac(ref mac
) => {
1346 let (_
, _
, ref attrs
) = **mac
;
1352 fn map_attrs
<F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>>(self, f
: F
) -> Self {
1354 StmtKind
::Local(local
) => StmtKind
::Local(local
.map_attrs(f
)),
1355 StmtKind
::Item(..) => self,
1356 StmtKind
::Expr(expr
) => StmtKind
::Expr(expr
.map_attrs(f
)),
1357 StmtKind
::Semi(expr
) => StmtKind
::Semi(expr
.map_attrs(f
)),
1358 StmtKind
::Mac(mac
) => StmtKind
::Mac(mac
.map(|(mac
, style
, attrs
)| {
1359 (mac
, style
, attrs
.map_attrs(f
))
1365 impl HasAttrs
for Stmt
{
1366 fn attrs(&self) -> &[ast
::Attribute
] { self.node.attrs() }
1367 fn map_attrs
<F
: FnOnce(Vec
<ast
::Attribute
>) -> Vec
<ast
::Attribute
>>(self, f
: F
) -> Self {
1368 Stmt { id: self.id, node: self.node.map_attrs(f), span: self.span }
1372 macro_rules
! derive_has_attrs
{
1373 ($
($ty
:path
),*) => { $
(
1374 impl HasAttrs
for $ty
{
1375 fn attrs(&self) -> &[Attribute
] {
1379 fn map_attrs
<F
>(mut self, f
: F
) -> Self
1380 where F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>,
1382 self.attrs
= self.attrs
.map_attrs(f
);
1390 Item
, Expr
, Local
, ast
::ForeignItem
, ast
::StructField
, ast
::ImplItem
, ast
::TraitItem
, ast
::Arm
,
1391 ast
::Field
, ast
::FieldPat
, ast
::Variant_