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}
;
34 use std
::cell
::{RefCell, Cell}
;
38 static USED_ATTRS
: RefCell
<Vec
<u64>> = RefCell
::new(Vec
::new());
39 static KNOWN_ATTRS
: RefCell
<Vec
<u64>> = RefCell
::new(Vec
::new());
44 UnknownMetaItem(Name
),
47 MultipleStabilityLevels
,
51 fn handle_errors(diag
: &Handler
, span
: Span
, error
: AttrError
) {
53 AttrError
::MultipleItem(item
) => span_err
!(diag
, span
, E0538
,
54 "multiple '{}' items", item
),
55 AttrError
::UnknownMetaItem(item
) => span_err
!(diag
, span
, E0541
,
56 "unknown meta item '{}'", item
),
57 AttrError
::MissingSince
=> span_err
!(diag
, span
, E0542
, "missing 'since'"),
58 AttrError
::MissingFeature
=> span_err
!(diag
, span
, E0546
, "missing 'feature'"),
59 AttrError
::MultipleStabilityLevels
=> span_err
!(diag
, span
, E0544
,
60 "multiple stability levels"),
61 AttrError
::UnsupportedLiteral
=> span_err
!(diag
, span
, E0565
, "unsupported literal"),
65 pub fn mark_used(attr
: &Attribute
) {
66 debug
!("Marking {:?} as used.", attr
);
67 let AttrId(id
) = attr
.id
;
68 USED_ATTRS
.with(|slot
| {
69 let idx
= (id
/ 64) as usize;
71 if slot
.borrow().len() <= idx
{
72 slot
.borrow_mut().resize(idx
+ 1, 0);
74 slot
.borrow_mut()[idx
] |= 1 << shift
;
78 pub fn is_used(attr
: &Attribute
) -> bool
{
79 let AttrId(id
) = attr
.id
;
80 USED_ATTRS
.with(|slot
| {
81 let idx
= (id
/ 64) as usize;
83 slot
.borrow().get(idx
).map(|bits
| bits
& (1 << shift
) != 0)
88 pub fn mark_known(attr
: &Attribute
) {
89 debug
!("Marking {:?} as known.", attr
);
90 let AttrId(id
) = attr
.id
;
91 KNOWN_ATTRS
.with(|slot
| {
92 let idx
= (id
/ 64) as usize;
94 if slot
.borrow().len() <= idx
{
95 slot
.borrow_mut().resize(idx
+ 1, 0);
97 slot
.borrow_mut()[idx
] |= 1 << shift
;
101 pub fn is_known(attr
: &Attribute
) -> bool
{
102 let AttrId(id
) = attr
.id
;
103 KNOWN_ATTRS
.with(|slot
| {
104 let idx
= (id
/ 64) as usize;
106 slot
.borrow().get(idx
).map(|bits
| bits
& (1 << shift
) != 0)
111 impl NestedMetaItem
{
112 /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
113 pub fn meta_item(&self) -> Option
<&MetaItem
> {
115 NestedMetaItemKind
::MetaItem(ref item
) => Some(&item
),
120 /// Returns the Lit if self is a NestedMetaItemKind::Literal.
121 pub fn literal(&self) -> Option
<&Lit
> {
123 NestedMetaItemKind
::Literal(ref lit
) => Some(&lit
),
128 /// Returns the Span for `self`.
129 pub fn span(&self) -> Span
{
133 /// Returns true if this list item is a MetaItem with a name of `name`.
134 pub fn check_name(&self, name
: &str) -> bool
{
135 self.meta_item().map_or(false, |meta_item
| meta_item
.check_name(name
))
138 /// Returns the name of the meta item, e.g. `foo` in `#[foo]`,
139 /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem
140 pub fn name(&self) -> Option
<Name
> {
141 self.meta_item().and_then(|meta_item
| Some(meta_item
.name()))
144 /// Gets the string value if self is a MetaItem and the MetaItem is a
145 /// MetaItemKind::NameValue variant containing a string, otherwise None.
146 pub fn value_str(&self) -> Option
<Symbol
> {
147 self.meta_item().and_then(|meta_item
| meta_item
.value_str())
150 /// Returns a name and single literal value tuple of the MetaItem.
151 pub fn name_value_literal(&self) -> Option
<(Name
, &Lit
)> {
152 self.meta_item().and_then(
153 |meta_item
| meta_item
.meta_item_list().and_then(
155 if meta_item_list
.len() == 1 {
156 let nested_item
= &meta_item_list
[0];
157 if nested_item
.is_literal() {
158 Some((meta_item
.name(), nested_item
.literal().unwrap()))
168 /// Returns a MetaItem if self is a MetaItem with Kind Word.
169 pub fn word(&self) -> Option
<&MetaItem
> {
170 self.meta_item().and_then(|meta_item
| if meta_item
.is_word() {
177 /// Gets a list of inner meta items from a list MetaItem type.
178 pub fn meta_item_list(&self) -> Option
<&[NestedMetaItem
]> {
179 self.meta_item().and_then(|meta_item
| meta_item
.meta_item_list())
182 /// Returns `true` if the variant is MetaItem.
183 pub fn is_meta_item(&self) -> bool
{
184 self.meta_item().is_some()
187 /// Returns `true` if the variant is Literal.
188 pub fn is_literal(&self) -> bool
{
189 self.literal().is_some()
192 /// Returns `true` if self is a MetaItem and the meta item is a word.
193 pub fn is_word(&self) -> bool
{
194 self.word().is_some()
197 /// Returns `true` if self is a MetaItem and the meta item is a ValueString.
198 pub fn is_value_str(&self) -> bool
{
199 self.value_str().is_some()
202 /// Returns `true` if self is a MetaItem and the meta item is a list.
203 pub fn is_meta_item_list(&self) -> bool
{
204 self.meta_item_list().is_some()
209 pub fn check_name(&self, name
: &str) -> bool
{
210 let matches
= self.path
== name
;
217 pub fn name(&self) -> Option
<Name
> {
218 match self.path
.segments
.len() {
219 1 => Some(self.path
.segments
[0].identifier
.name
),
224 pub fn value_str(&self) -> Option
<Symbol
> {
225 self.meta().and_then(|meta
| meta
.value_str())
228 pub fn meta_item_list(&self) -> Option
<Vec
<NestedMetaItem
>> {
230 Some(MetaItem { node: MetaItemKind::List(list), .. }
) => Some(list
),
235 pub fn is_word(&self) -> bool
{
236 self.path
.segments
.len() == 1 && self.tokens
.is_empty()
239 pub fn span(&self) -> Span
{
243 pub fn is_meta_item_list(&self) -> bool
{
244 self.meta_item_list().is_some()
247 /// Indicates if the attribute is a Value String.
248 pub fn is_value_str(&self) -> bool
{
249 self.value_str().is_some()
254 pub fn name(&self) -> Name
{
258 pub fn value_str(&self) -> Option
<Symbol
> {
260 MetaItemKind
::NameValue(ref v
) => {
262 LitKind
::Str(ref s
, _
) => Some((*s
).clone()),
270 pub fn meta_item_list(&self) -> Option
<&[NestedMetaItem
]> {
272 MetaItemKind
::List(ref l
) => Some(&l
[..]),
277 pub fn is_word(&self) -> bool
{
279 MetaItemKind
::Word
=> true,
284 pub fn span(&self) -> Span { self.span }
286 pub fn check_name(&self, name
: &str) -> bool
{
290 pub fn is_value_str(&self) -> bool
{
291 self.value_str().is_some()
294 pub fn is_meta_item_list(&self) -> bool
{
295 self.meta_item_list().is_some()
300 /// Extract the MetaItem from inside this Attribute.
301 pub fn meta(&self) -> Option
<MetaItem
> {
302 let mut tokens
= self.tokens
.trees().peekable();
304 name
: match self.path
.segments
.len() {
305 1 => self.path
.segments
[0].identifier
.name
,
308 node
: if let Some(node
) = MetaItemKind
::from_tokens(&mut tokens
) {
309 if tokens
.peek().is_some() {
320 pub fn parse
<'a
, T
, F
>(&self, sess
: &'a ParseSess
, mut f
: F
) -> PResult
<'a
, T
>
321 where F
: FnMut(&mut Parser
<'a
>) -> PResult
<'a
, T
>,
323 let mut parser
= Parser
::new(sess
, self.tokens
.clone(), None
, false);
324 let result
= f(&mut parser
)?
;
325 if parser
.token
!= token
::Eof
{
326 parser
.unexpected()?
;
331 pub fn parse_list
<'a
, T
, F
>(&self, sess
: &'a ParseSess
, mut f
: F
) -> PResult
<'a
, Vec
<T
>>
332 where F
: FnMut(&mut Parser
<'a
>) -> PResult
<'a
, T
>,
334 if self.tokens
.is_empty() {
335 return Ok(Vec
::new());
337 self.parse(sess
, |parser
| {
338 parser
.expect(&token
::OpenDelim(token
::Paren
))?
;
339 let mut list
= Vec
::new();
340 while !parser
.eat(&token
::CloseDelim(token
::Paren
)) {
341 list
.push(f(parser
)?
);
342 if !parser
.eat(&token
::Comma
) {
343 parser
.expect(&token
::CloseDelim(token
::Paren
))?
;
351 pub fn parse_meta
<'a
>(&self, sess
: &'a ParseSess
) -> PResult
<'a
, MetaItem
> {
352 if self.path
.segments
.len() > 1 {
353 sess
.span_diagnostic
.span_err(self.path
.span
, "expected ident, found path");
357 name
: self.path
.segments
.last().unwrap().identifier
.name
,
358 node
: self.parse(sess
, |parser
| parser
.parse_meta_item_kind())?
,
363 /// Convert self to a normal #[doc="foo"] comment, if it is a
364 /// comment like `///` or `/** */`. (Returns self unchanged for
365 /// non-sugared doc attributes.)
366 pub fn with_desugared_doc
<T
, F
>(&self, f
: F
) -> T
where
367 F
: FnOnce(&Attribute
) -> T
,
369 if self.is_sugared_doc
{
370 let comment
= self.value_str().unwrap();
371 let meta
= mk_name_value_item_str(
372 Symbol
::intern("doc"),
373 Symbol
::intern(&strip_doc_comment_decoration(&comment
.as_str())));
374 if self.style
== ast
::AttrStyle
::Outer
{
375 f(&mk_attr_outer(self.span
, self.id
, meta
))
377 f(&mk_attr_inner(self.span
, self.id
, meta
))
387 pub fn mk_name_value_item_str(name
: Name
, value
: Symbol
) -> MetaItem
{
388 let value_lit
= dummy_spanned(LitKind
::Str(value
, ast
::StrStyle
::Cooked
));
389 mk_spanned_name_value_item(DUMMY_SP
, name
, value_lit
)
392 pub fn mk_name_value_item(name
: Name
, value
: ast
::Lit
) -> MetaItem
{
393 mk_spanned_name_value_item(DUMMY_SP
, name
, value
)
396 pub fn mk_list_item(name
: Name
, items
: Vec
<NestedMetaItem
>) -> MetaItem
{
397 mk_spanned_list_item(DUMMY_SP
, name
, items
)
400 pub fn mk_list_word_item(name
: Name
) -> ast
::NestedMetaItem
{
401 dummy_spanned(NestedMetaItemKind
::MetaItem(mk_spanned_word_item(DUMMY_SP
, name
)))
404 pub fn mk_word_item(name
: Name
) -> MetaItem
{
405 mk_spanned_word_item(DUMMY_SP
, name
)
408 pub fn mk_spanned_name_value_item(sp
: Span
, name
: Name
, value
: ast
::Lit
) -> MetaItem
{
409 MetaItem { span: sp, name: name, node: MetaItemKind::NameValue(value) }
412 pub fn mk_spanned_list_item(sp
: Span
, name
: Name
, items
: Vec
<NestedMetaItem
>) -> MetaItem
{
413 MetaItem { span: sp, name: name, node: MetaItemKind::List(items) }
416 pub fn mk_spanned_word_item(sp
: Span
, name
: Name
) -> MetaItem
{
417 MetaItem { span: sp, name: name, node: MetaItemKind::Word }
422 thread_local
! { static NEXT_ATTR_ID: Cell<usize> = Cell::new(0) }
424 pub fn mk_attr_id() -> AttrId
{
425 let id
= NEXT_ATTR_ID
.with(|slot
| {
433 /// Returns an inner attribute with the given value.
434 pub fn mk_attr_inner(span
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
435 mk_spanned_attr_inner(span
, id
, item
)
438 /// Returns an innter attribute with the given value and span.
439 pub fn mk_spanned_attr_inner(sp
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
442 style
: ast
::AttrStyle
::Inner
,
443 path
: ast
::Path
::from_ident(item
.span
, ast
::Ident
::with_empty_ctxt(item
.name
)),
444 tokens
: item
.node
.tokens(item
.span
),
445 is_sugared_doc
: false,
451 /// Returns an outer attribute with the given value.
452 pub fn mk_attr_outer(span
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
453 mk_spanned_attr_outer(span
, id
, item
)
456 /// Returns an outer attribute with the given value and span.
457 pub fn mk_spanned_attr_outer(sp
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
460 style
: ast
::AttrStyle
::Outer
,
461 path
: ast
::Path
::from_ident(item
.span
, ast
::Ident
::with_empty_ctxt(item
.name
)),
462 tokens
: item
.node
.tokens(item
.span
),
463 is_sugared_doc
: false,
468 pub fn mk_sugared_doc_attr(id
: AttrId
, text
: Symbol
, span
: Span
) -> Attribute
{
469 let style
= doc_comment_style(&text
.as_str());
470 let lit
= respan(span
, LitKind
::Str(text
, ast
::StrStyle
::Cooked
));
474 path
: ast
::Path
::from_ident(span
, ast
::Ident
::from_str("doc")),
475 tokens
: MetaItemKind
::NameValue(lit
).tokens(span
),
476 is_sugared_doc
: true,
481 pub fn list_contains_name(items
: &[NestedMetaItem
], name
: &str) -> bool
{
482 items
.iter().any(|item
| {
483 item
.check_name(name
)
487 pub fn contains_name(attrs
: &[Attribute
], name
: &str) -> bool
{
488 attrs
.iter().any(|item
| {
489 item
.check_name(name
)
493 pub fn first_attr_value_str_by_name(attrs
: &[Attribute
], name
: &str) -> Option
<Symbol
> {
495 .find(|at
| at
.check_name(name
))
496 .and_then(|at
| at
.value_str())
499 /* Higher-level applications */
501 pub fn find_crate_name(attrs
: &[Attribute
]) -> Option
<Symbol
> {
502 first_attr_value_str_by_name(attrs
, "crate_name")
505 /// Find the value of #[export_name=*] attribute and check its validity.
506 pub fn find_export_name_attr(diag
: &Handler
, attrs
: &[Attribute
]) -> Option
<Symbol
> {
507 attrs
.iter().fold(None
, |ia
,attr
| {
508 if attr
.check_name("export_name") {
509 if let s@
Some(_
) = attr
.value_str() {
512 struct_span_err
!(diag
, attr
.span
, E0558
,
513 "export_name attribute has invalid format")
514 .span_label(attr
.span
,
515 &format
!("did you mean #[export_name=\"*\"]?"))
525 pub fn contains_extern_indicator(diag
: &Handler
, attrs
: &[Attribute
]) -> bool
{
526 contains_name(attrs
, "no_mangle") ||
527 find_export_name_attr(diag
, attrs
).is_some()
530 #[derive(Copy, Clone, PartialEq)]
531 pub enum InlineAttr
{
538 /// Determine what `#[inline]` attribute is present in `attrs`, if any.
539 pub fn find_inline_attr(diagnostic
: Option
<&Handler
>, attrs
: &[Attribute
]) -> InlineAttr
{
540 attrs
.iter().fold(InlineAttr
::None
, |ia
, attr
| {
541 if attr
.path
!= "inline" {
544 let meta
= match attr
.meta() {
545 Some(meta
) => meta
.node
,
549 MetaItemKind
::Word
=> {
553 MetaItemKind
::List(ref items
) => {
555 if items
.len() != 1 {
556 diagnostic
.map(|d
|{ span_err!(d, attr.span, E0534, "expected one argument"); }
);
558 } else if list_contains_name(&items
[..], "always") {
560 } else if list_contains_name(&items
[..], "never") {
564 span_err
!(d
, items
[0].span
, E0535
, "invalid argument");
575 /// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
576 pub fn requests_inline(attrs
: &[Attribute
]) -> bool
{
577 match find_inline_attr(None
, attrs
) {
578 InlineAttr
::Hint
| InlineAttr
::Always
=> true,
579 InlineAttr
::None
| InlineAttr
::Never
=> false,
583 /// Tests if a cfg-pattern matches the cfg set
584 pub fn cfg_matches(cfg
: &ast
::MetaItem
, sess
: &ParseSess
, features
: Option
<&Features
>) -> bool
{
586 ast
::MetaItemKind
::List(ref mis
) => {
587 for mi
in mis
.iter() {
588 if !mi
.is_meta_item() {
589 handle_errors(&sess
.span_diagnostic
, mi
.span
, AttrError
::UnsupportedLiteral
);
594 // The unwraps below may look dangerous, but we've already asserted
595 // that they won't fail with the loop above.
596 match &*cfg
.name
.as_str() {
597 "any" => mis
.iter().any(|mi
| {
598 cfg_matches(mi
.meta_item().unwrap(), sess
, features
)
600 "all" => mis
.iter().all(|mi
| {
601 cfg_matches(mi
.meta_item().unwrap(), sess
, features
)
605 span_err
!(sess
.span_diagnostic
, cfg
.span
, E0536
, "expected 1 cfg-pattern");
609 !cfg_matches(mis
[0].meta_item().unwrap(), sess
, features
)
612 span_err
!(sess
.span_diagnostic
, cfg
.span
, E0537
, "invalid predicate `{}`", p
);
617 ast
::MetaItemKind
::Word
| ast
::MetaItemKind
::NameValue(..) => {
618 if let (Some(feats
), Some(gated_cfg
)) = (features
, GatedCfg
::gate(cfg
)) {
619 gated_cfg
.check_and_emit(sess
, feats
);
621 sess
.config
.contains(&(cfg
.name(), cfg
.value_str()))
626 /// Represents the #[stable], #[unstable] and #[rustc_deprecated] attributes.
627 #[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
628 pub struct Stability
{
629 pub level
: StabilityLevel
,
631 pub rustc_depr
: Option
<RustcDeprecation
>,
634 /// The available stability levels.
635 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
636 pub enum StabilityLevel
{
637 // Reason for the current stability level and the relevant rust-lang issue
638 Unstable { reason: Option<Symbol>, issue: u32 }
,
639 Stable { since: Symbol }
,
642 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
643 pub struct RustcDeprecation
{
648 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
649 pub struct Deprecation
{
650 pub since
: Option
<Symbol
>,
651 pub note
: Option
<Symbol
>,
654 impl StabilityLevel
{
655 pub fn is_unstable(&self) -> bool { if let Unstable {..}
= *self { true }
else { false }
}
656 pub fn is_stable(&self) -> bool { if let Stable {..}
= *self { true }
else { false }
}
659 fn find_stability_generic
<'a
, I
>(diagnostic
: &Handler
,
663 where I
: Iterator
<Item
= &'a Attribute
>
665 let mut stab
: Option
<Stability
> = None
;
666 let mut rustc_depr
: Option
<RustcDeprecation
> = None
;
668 'outer
: for attr
in attrs_iter
{
669 if attr
.path
!= "rustc_deprecated" && attr
.path
!= "unstable" && attr
.path
!= "stable" {
670 continue // not a stability level
675 let meta
= attr
.meta();
676 if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }
) = meta
{
677 let meta
= meta
.as_ref().unwrap();
678 let get
= |meta
: &MetaItem
, item
: &mut Option
<Symbol
>| {
680 handle_errors(diagnostic
, meta
.span
, AttrError
::MultipleItem(meta
.name()));
683 if let Some(v
) = meta
.value_str() {
687 span_err
!(diagnostic
, meta
.span
, E0539
, "incorrect meta item");
692 match &*meta
.name
.as_str() {
693 "rustc_deprecated" => {
694 if rustc_depr
.is_some() {
695 span_err
!(diagnostic
, item_sp
, E0540
,
696 "multiple rustc_deprecated attributes");
700 let mut since
= None
;
701 let mut reason
= None
;
703 if let Some(mi
) = meta
.meta_item() {
704 match &*mi
.name().as_str() {
705 "since" => if !get(mi
, &mut since
) { continue 'outer }
,
706 "reason" => if !get(mi
, &mut reason
) { continue 'outer }
,
708 handle_errors(diagnostic
, mi
.span
,
709 AttrError
::UnknownMetaItem(mi
.name()));
714 handle_errors(diagnostic
, meta
.span
, AttrError
::UnsupportedLiteral
);
719 match (since
, reason
) {
720 (Some(since
), Some(reason
)) => {
721 rustc_depr
= Some(RustcDeprecation
{
727 handle_errors(diagnostic
, attr
.span(), AttrError
::MissingSince
);
731 span_err
!(diagnostic
, attr
.span(), E0543
, "missing 'reason'");
738 handle_errors(diagnostic
, attr
.span(), AttrError
::MultipleStabilityLevels
);
742 let mut feature
= None
;
743 let mut reason
= None
;
744 let mut issue
= None
;
746 if let Some(mi
) = meta
.meta_item() {
747 match &*mi
.name().as_str() {
748 "feature" => if !get(mi
, &mut feature
) { continue 'outer }
,
749 "reason" => if !get(mi
, &mut reason
) { continue 'outer }
,
750 "issue" => if !get(mi
, &mut issue
) { continue 'outer }
,
752 handle_errors(diagnostic
, meta
.span
,
753 AttrError
::UnknownMetaItem(mi
.name()));
758 handle_errors(diagnostic
, meta
.span
, AttrError
::UnsupportedLiteral
);
763 match (feature
, reason
, issue
) {
764 (Some(feature
), reason
, Some(issue
)) => {
765 stab
= Some(Stability
{
769 if let Ok(issue
) = issue
.as_str().parse() {
772 span_err
!(diagnostic
, attr
.span(), E0545
,
773 "incorrect 'issue'");
783 handle_errors(diagnostic
, attr
.span(), AttrError
::MissingFeature
);
787 span_err
!(diagnostic
, attr
.span(), E0547
, "missing 'issue'");
794 handle_errors(diagnostic
, attr
.span(), AttrError
::MultipleStabilityLevels
);
798 let mut feature
= None
;
799 let mut since
= None
;
801 if let NestedMetaItemKind
::MetaItem(ref mi
) = meta
.node
{
802 match &*mi
.name().as_str() {
803 "feature" => if !get(mi
, &mut feature
) { continue 'outer }
,
804 "since" => if !get(mi
, &mut since
) { continue 'outer }
,
806 handle_errors(diagnostic
, meta
.span
,
807 AttrError
::UnknownMetaItem(mi
.name()));
812 handle_errors(diagnostic
, meta
.span
, AttrError
::UnsupportedLiteral
);
817 match (feature
, since
) {
818 (Some(feature
), Some(since
)) => {
819 stab
= Some(Stability
{
828 handle_errors(diagnostic
, attr
.span(), AttrError
::MissingFeature
);
832 handle_errors(diagnostic
, attr
.span(), AttrError
::MissingSince
);
840 span_err
!(diagnostic
, attr
.span(), E0548
, "incorrect stability attribute type");
845 // Merge the deprecation info into the stability info
846 if let Some(rustc_depr
) = rustc_depr
{
847 if let Some(ref mut stab
) = stab
{
848 stab
.rustc_depr
= Some(rustc_depr
);
850 span_err
!(diagnostic
, item_sp
, E0549
,
851 "rustc_deprecated attribute must be paired with \
852 either stable or unstable attribute");
859 fn find_deprecation_generic
<'a
, I
>(diagnostic
: &Handler
,
862 -> Option
<Deprecation
>
863 where I
: Iterator
<Item
= &'a Attribute
>
865 let mut depr
: Option
<Deprecation
> = None
;
867 'outer
: for attr
in attrs_iter
{
868 if attr
.path
!= "deprecated" {
875 span_err
!(diagnostic
, item_sp
, E0550
, "multiple deprecated attributes");
879 depr
= if let Some(metas
) = attr
.meta_item_list() {
880 let get
= |meta
: &MetaItem
, item
: &mut Option
<Symbol
>| {
882 handle_errors(diagnostic
, meta
.span
, AttrError
::MultipleItem(meta
.name()));
885 if let Some(v
) = meta
.value_str() {
889 span_err
!(diagnostic
, meta
.span
, E0551
, "incorrect meta item");
894 let mut since
= None
;
897 if let NestedMetaItemKind
::MetaItem(ref mi
) = meta
.node
{
898 match &*mi
.name().as_str() {
899 "since" => if !get(mi
, &mut since
) { continue 'outer }
,
900 "note" => if !get(mi
, &mut note
) { continue 'outer }
,
902 handle_errors(diagnostic
, meta
.span
,
903 AttrError
::UnknownMetaItem(mi
.name()));
908 handle_errors(diagnostic
, meta
.span
, AttrError
::UnsupportedLiteral
);
913 Some(Deprecation {since: since, note: note}
)
915 Some(Deprecation{since: None, note: None}
)
922 /// Find the first stability attribute. `None` if none exists.
923 pub fn find_stability(diagnostic
: &Handler
, attrs
: &[Attribute
],
924 item_sp
: Span
) -> Option
<Stability
> {
925 find_stability_generic(diagnostic
, attrs
.iter(), item_sp
)
928 /// Find the deprecation attribute. `None` if none exists.
929 pub fn find_deprecation(diagnostic
: &Handler
, attrs
: &[Attribute
],
930 item_sp
: Span
) -> Option
<Deprecation
> {
931 find_deprecation_generic(diagnostic
, attrs
.iter(), item_sp
)
935 /// Parse #[repr(...)] forms.
937 /// Valid repr contents: any of the primitive integral type names (see
938 /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
939 /// the same discriminant size that the corresponding C enum would or C
940 /// structure layout, and `packed` to remove padding.
941 pub fn find_repr_attrs(diagnostic
: &Handler
, attr
: &Attribute
) -> Vec
<ReprAttr
> {
942 let mut acc
= Vec
::new();
943 if attr
.path
== "repr" {
944 if let Some(items
) = attr
.meta_item_list() {
947 if !item
.is_meta_item() {
948 handle_errors(diagnostic
, item
.span
, AttrError
::UnsupportedLiteral
);
952 let mut recognised
= false;
953 if let Some(mi
) = item
.word() {
954 let word
= &*mi
.name().as_str();
955 let hint
= match word
{
956 // Can't use "extern" because it's not a lexical identifier.
957 "C" => Some(ReprExtern
),
958 "packed" => Some(ReprPacked
),
959 "simd" => Some(ReprSimd
),
960 _
=> match int_type_of_word(word
) {
961 Some(ity
) => Some(ReprInt(ity
)),
968 if let Some(h
) = hint
{
972 } else if let Some((name
, value
)) = item
.name_value_literal() {
975 let mut align_error
= None
;
976 if let ast
::LitKind
::Int(align
, ast
::LitIntType
::Unsuffixed
) = value
.node
{
977 if align
.is_power_of_two() {
978 // rustc::ty::layout::Align restricts align to <= 32768
980 acc
.push(ReprAlign(align
as u16));
982 align_error
= Some("larger than 32768");
985 align_error
= Some("not a power of two");
988 align_error
= Some("not an unsuffixed integer");
990 if let Some(align_error
) = align_error
{
991 span_err
!(diagnostic
, item
.span
, E0589
,
992 "invalid `repr(align)` attribute: {}", align_error
);
997 // Not a word we recognize
998 span_err
!(diagnostic
, item
.span
, E0552
,
999 "unrecognized representation hint");
1007 fn int_type_of_word(s
: &str) -> Option
<IntType
> {
1009 "i8" => Some(SignedInt(ast
::IntTy
::I8
)),
1010 "u8" => Some(UnsignedInt(ast
::UintTy
::U8
)),
1011 "i16" => Some(SignedInt(ast
::IntTy
::I16
)),
1012 "u16" => Some(UnsignedInt(ast
::UintTy
::U16
)),
1013 "i32" => Some(SignedInt(ast
::IntTy
::I32
)),
1014 "u32" => Some(UnsignedInt(ast
::UintTy
::U32
)),
1015 "i64" => Some(SignedInt(ast
::IntTy
::I64
)),
1016 "u64" => Some(UnsignedInt(ast
::UintTy
::U64
)),
1017 "i128" => Some(SignedInt(ast
::IntTy
::I128
)),
1018 "u128" => Some(UnsignedInt(ast
::UintTy
::U128
)),
1019 "isize" => Some(SignedInt(ast
::IntTy
::Is
)),
1020 "usize" => Some(UnsignedInt(ast
::UintTy
::Us
)),
1025 #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
1034 #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
1036 SignedInt(ast
::IntTy
),
1037 UnsignedInt(ast
::UintTy
)
1042 pub fn is_signed(self) -> bool
{
1044 SignedInt(..) => true,
1045 UnsignedInt(..) => false
1051 fn tokens(&self) -> TokenStream
{
1052 let ident
= TokenTree
::Token(self.span
, Token
::Ident(Ident
::with_empty_ctxt(self.name
)));
1053 TokenStream
::concat(vec
![ident
.into(), self.node
.tokens(self.span
)])
1056 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<MetaItem
>
1057 where I
: Iterator
<Item
= TokenTree
>,
1059 let (mut span
, name
) = match tokens
.next() {
1060 Some(TokenTree
::Token(span
, Token
::Ident(ident
))) => (span
, ident
.name
),
1061 Some(TokenTree
::Token(_
, Token
::Interpolated(ref nt
))) => match **nt
{
1062 token
::Nonterminal
::NtIdent(ident
) => (ident
.span
, ident
.node
.name
),
1063 token
::Nonterminal
::NtMeta(ref meta
) => return Some(meta
.clone()),
1068 let node
= match MetaItemKind
::from_tokens(tokens
) {
1072 if let Some(last_span
) = node
.last_span() {
1073 span
.hi
= last_span
.hi
;
1075 Some(MetaItem { name: name, span: span, node: node }
)
1080 fn last_span(&self) -> Option
<Span
> {
1082 MetaItemKind
::Word
=> None
,
1083 MetaItemKind
::List(ref list
) => list
.last().map(NestedMetaItem
::span
),
1084 MetaItemKind
::NameValue(ref lit
) => Some(lit
.span
),
1088 pub fn tokens(&self, span
: Span
) -> TokenStream
{
1090 MetaItemKind
::Word
=> TokenStream
::empty(),
1091 MetaItemKind
::NameValue(ref lit
) => {
1092 TokenStream
::concat(vec
![TokenTree
::Token(span
, Token
::Eq
).into(), lit
.tokens()])
1094 MetaItemKind
::List(ref list
) => {
1095 let mut tokens
= Vec
::new();
1096 for (i
, item
) in list
.iter().enumerate() {
1098 tokens
.push(TokenTree
::Token(span
, Token
::Comma
).into());
1100 tokens
.push(item
.node
.tokens());
1102 TokenTree
::Delimited(span
, Delimited
{
1103 delim
: token
::Paren
,
1104 tts
: TokenStream
::concat(tokens
).into(),
1110 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<MetaItemKind
>
1111 where I
: Iterator
<Item
= TokenTree
>,
1113 let delimited
= match tokens
.peek().cloned() {
1114 Some(TokenTree
::Token(_
, token
::Eq
)) => {
1116 return if let Some(TokenTree
::Token(span
, token
)) = tokens
.next() {
1117 LitKind
::from_token(token
)
1118 .map(|lit
| MetaItemKind
::NameValue(Spanned { node: lit, span: span }
))
1123 Some(TokenTree
::Delimited(_
, ref delimited
)) if delimited
.delim
== token
::Paren
=> {
1127 _
=> return Some(MetaItemKind
::Word
),
1130 let mut tokens
= delimited
.into_trees().peekable();
1131 let mut result
= Vec
::new();
1132 while let Some(..) = tokens
.peek() {
1133 match NestedMetaItemKind
::from_tokens(&mut tokens
) {
1134 Some(item
) => result
.push(Spanned { span: item.span(), node: item }
),
1135 None
=> return None
,
1137 match tokens
.next() {
1138 None
| Some(TokenTree
::Token(_
, Token
::Comma
)) => {}
1142 Some(MetaItemKind
::List(result
))
1146 impl NestedMetaItemKind
{
1147 fn span(&self) -> Span
{
1149 NestedMetaItemKind
::MetaItem(ref item
) => item
.span
,
1150 NestedMetaItemKind
::Literal(ref lit
) => lit
.span
,
1154 fn tokens(&self) -> TokenStream
{
1156 NestedMetaItemKind
::MetaItem(ref item
) => item
.tokens(),
1157 NestedMetaItemKind
::Literal(ref lit
) => lit
.tokens(),
1161 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<NestedMetaItemKind
>
1162 where I
: Iterator
<Item
= TokenTree
>,
1164 if let Some(TokenTree
::Token(span
, token
)) = tokens
.peek().cloned() {
1165 if let Some(node
) = LitKind
::from_token(token
) {
1167 return Some(NestedMetaItemKind
::Literal(Spanned { node: node, span: span }
));
1171 MetaItem
::from_tokens(tokens
).map(NestedMetaItemKind
::MetaItem
)
1176 fn tokens(&self) -> TokenStream
{
1177 TokenTree
::Token(self.span
, self.node
.token()).into()
1182 fn token(&self) -> Token
{
1186 LitKind
::Str(string
, ast
::StrStyle
::Cooked
) => {
1187 let mut escaped
= String
::new();
1188 for ch
in string
.as_str().chars() {
1189 escaped
.extend(ch
.escape_unicode());
1191 Token
::Literal(token
::Lit
::Str_(Symbol
::intern(&escaped
)), None
)
1193 LitKind
::Str(string
, ast
::StrStyle
::Raw(n
)) => {
1194 Token
::Literal(token
::Lit
::StrRaw(string
, n
), None
)
1196 LitKind
::ByteStr(ref bytes
) => {
1197 let string
= bytes
.iter().cloned().flat_map(ascii
::escape_default
)
1198 .map(Into
::<char>::into
).collect
::<String
>();
1199 Token
::Literal(token
::Lit
::ByteStr(Symbol
::intern(&string
)), None
)
1201 LitKind
::Byte(byte
) => {
1202 let string
: String
= ascii
::escape_default(byte
).map(Into
::<char>::into
).collect();
1203 Token
::Literal(token
::Lit
::Byte(Symbol
::intern(&string
)), None
)
1205 LitKind
::Char(ch
) => {
1206 let string
: String
= ch
.escape_default().map(Into
::<char>::into
).collect();
1207 Token
::Literal(token
::Lit
::Char(Symbol
::intern(&string
)), None
)
1209 LitKind
::Int(n
, ty
) => {
1210 let suffix
= match ty
{
1211 ast
::LitIntType
::Unsigned(ty
) => Some(Symbol
::intern(ty
.ty_to_string())),
1212 ast
::LitIntType
::Signed(ty
) => Some(Symbol
::intern(ty
.ty_to_string())),
1213 ast
::LitIntType
::Unsuffixed
=> None
,
1215 Token
::Literal(token
::Lit
::Integer(Symbol
::intern(&n
.to_string())), suffix
)
1217 LitKind
::Float(symbol
, ty
) => {
1218 Token
::Literal(token
::Lit
::Float(symbol
), Some(Symbol
::intern(ty
.ty_to_string())))
1220 LitKind
::FloatUnsuffixed(symbol
) => Token
::Literal(token
::Lit
::Float(symbol
), None
),
1221 LitKind
::Bool(value
) => Token
::Ident(Ident
::with_empty_ctxt(Symbol
::intern(match value
{
1228 fn from_token(token
: Token
) -> Option
<LitKind
> {
1230 Token
::Ident(ident
) if ident
.name
== "true" => Some(LitKind
::Bool(true)),
1231 Token
::Ident(ident
) if ident
.name
== "false" => Some(LitKind
::Bool(false)),
1232 Token
::Interpolated(ref nt
) => match **nt
{
1233 token
::NtExpr(ref v
) => match v
.node
{
1234 ExprKind
::Lit(ref lit
) => Some(lit
.node
.clone()),
1239 Token
::Literal(lit
, suf
) => {
1240 let (suffix_illegal
, result
) = parse
::lit_token(lit
, suf
, None
);
1241 if suffix_illegal
&& suf
.is_some() {
1251 pub trait HasAttrs
: Sized
{
1252 fn attrs(&self) -> &[ast
::Attribute
];
1253 fn map_attrs
<F
: FnOnce(Vec
<ast
::Attribute
>) -> Vec
<ast
::Attribute
>>(self, f
: F
) -> Self;
1256 impl<T
: HasAttrs
> HasAttrs
for Spanned
<T
> {
1257 fn attrs(&self) -> &[ast
::Attribute
] { self.node.attrs() }
1258 fn map_attrs
<F
: FnOnce(Vec
<ast
::Attribute
>) -> Vec
<ast
::Attribute
>>(self, f
: F
) -> Self {
1259 Spanned { node: self.node.map_attrs(f), span: self.span }
1263 impl HasAttrs
for Vec
<Attribute
> {
1264 fn attrs(&self) -> &[Attribute
] {
1267 fn map_attrs
<F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>>(self, f
: F
) -> Self {
1272 impl HasAttrs
for ThinVec
<Attribute
> {
1273 fn attrs(&self) -> &[Attribute
] {
1276 fn map_attrs
<F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>>(self, f
: F
) -> Self {
1277 f(self.into()).into()
1281 impl<T
: HasAttrs
+ '
static> HasAttrs
for P
<T
> {
1282 fn attrs(&self) -> &[Attribute
] {
1285 fn map_attrs
<F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>>(self, f
: F
) -> Self {
1286 self.map(|t
| t
.map_attrs(f
))
1290 impl HasAttrs
for StmtKind
{
1291 fn attrs(&self) -> &[Attribute
] {
1293 StmtKind
::Local(ref local
) => local
.attrs(),
1294 StmtKind
::Item(..) => &[],
1295 StmtKind
::Expr(ref expr
) | StmtKind
::Semi(ref expr
) => expr
.attrs(),
1296 StmtKind
::Mac(ref mac
) => {
1297 let (_
, _
, ref attrs
) = **mac
;
1303 fn map_attrs
<F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>>(self, f
: F
) -> Self {
1305 StmtKind
::Local(local
) => StmtKind
::Local(local
.map_attrs(f
)),
1306 StmtKind
::Item(..) => self,
1307 StmtKind
::Expr(expr
) => StmtKind
::Expr(expr
.map_attrs(f
)),
1308 StmtKind
::Semi(expr
) => StmtKind
::Semi(expr
.map_attrs(f
)),
1309 StmtKind
::Mac(mac
) => StmtKind
::Mac(mac
.map(|(mac
, style
, attrs
)| {
1310 (mac
, style
, attrs
.map_attrs(f
))
1316 impl HasAttrs
for Stmt
{
1317 fn attrs(&self) -> &[ast
::Attribute
] { self.node.attrs() }
1318 fn map_attrs
<F
: FnOnce(Vec
<ast
::Attribute
>) -> Vec
<ast
::Attribute
>>(self, f
: F
) -> Self {
1319 Stmt { id: self.id, node: self.node.map_attrs(f), span: self.span }
1323 macro_rules
! derive_has_attrs
{
1324 ($
($ty
:path
),*) => { $
(
1325 impl HasAttrs
for $ty
{
1326 fn attrs(&self) -> &[Attribute
] {
1330 fn map_attrs
<F
>(mut self, f
: F
) -> Self
1331 where F
: FnOnce(Vec
<Attribute
>) -> Vec
<Attribute
>,
1333 self.attrs
= self.attrs
.map_attrs(f
);
1341 Item
, Expr
, Local
, ast
::ForeignItem
, ast
::StructField
, ast
::ImplItem
, ast
::TraitItem
, ast
::Arm
,
1342 ast
::Field
, ast
::FieldPat
, ast
::Variant_