//! Functions dealing with attributes and meta items.
use crate::ast;
-use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, Attribute};
-use crate::ast::{DelimArgs, LitKind, MetaItemLit};
-use crate::ast::{MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
-use crate::ast::{Path, PathSegment};
+use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute};
+use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit};
+use crate::ast::{MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
+use crate::ast::{Path, PathSegment, StrStyle, DUMMY_NODE_ID};
use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter, Token};
use crate::tokenstream::{DelimSpan, Spacing, TokenTree};
use crate::util::comments;
use rustc_data_structures::sync::WorkerLocal;
use rustc_index::bit_set::GrowableBitSet;
-use rustc_span::source_map::BytePos;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
use std::cell::Cell;
}
pub fn meta(&self, span: Span) -> Option<MetaItem> {
- Some(MetaItem {
- path: self.path.clone(),
- kind: MetaItemKind::from_attr_args(&self.args)?,
- span,
- })
+ Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
/* Constructors */
pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem {
- let lit_kind = LitKind::Str(str, ast::StrStyle::Cooked);
- mk_name_value_item(ident, lit_kind, str_span)
+ mk_name_value_item(ident, LitKind::Str(str, ast::StrStyle::Cooked), str_span)
}
pub fn mk_name_value_item(ident: Ident, kind: LitKind, lit_span: Span) -> MetaItem {
let lit = MetaItemLit { token_lit: kind.to_token_lit(), kind, span: lit_span };
let span = ident.span.to(lit_span);
- MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) }
-}
-
-pub fn mk_list_item(ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
- MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) }
-}
-
-pub fn mk_word_item(ident: Ident) -> MetaItem {
- MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word }
-}
-
-pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
- NestedMetaItem::MetaItem(mk_word_item(ident))
+ MetaItem { path: Path::from_ident(ident), kind: MetaItemKind::NameValue(lit), span }
}
pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
span: Span,
) -> Attribute {
Attribute {
- kind: AttrKind::Normal(P(ast::NormalAttr { item, tokens })),
+ kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
id: g.mk_attr_id(),
style,
span,
}
}
-/// Returns an inner attribute with the given value and span.
-pub fn mk_attr_inner(g: &AttrIdGenerator, item: MetaItem) -> Attribute {
- mk_attr(g, AttrStyle::Inner, item.path, item.kind.attr_args(item.span), item.span)
+pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
+ let path = Path::from_ident(Ident::new(name, span));
+ let args = AttrArgs::Empty;
+ mk_attr(g, style, path, args, span)
+}
+
+pub fn mk_attr_name_value_str(
+ g: &AttrIdGenerator,
+ style: AttrStyle,
+ name: Symbol,
+ val: Symbol,
+ span: Span,
+) -> Attribute {
+ let lit = LitKind::Str(val, StrStyle::Cooked).to_token_lit();
+ let expr = P(Expr {
+ id: DUMMY_NODE_ID,
+ kind: ExprKind::Lit(lit),
+ span,
+ attrs: AttrVec::new(),
+ tokens: None,
+ });
+ let path = Path::from_ident(Ident::new(name, span));
+ let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
+ mk_attr(g, style, path, args, span)
}
-/// Returns an outer attribute with the given value and span.
-pub fn mk_attr_outer(g: &AttrIdGenerator, item: MetaItem) -> Attribute {
- mk_attr(g, AttrStyle::Outer, item.path, item.kind.attr_args(item.span), item.span)
+pub fn mk_attr_nested_word(
+ g: &AttrIdGenerator,
+ style: AttrStyle,
+ outer: Symbol,
+ inner: Symbol,
+ span: Span,
+) -> Attribute {
+ let inner_tokens = TokenStream::new(vec![TokenTree::Token(
+ Token::from_ast_ident(Ident::new(inner, span)),
+ Spacing::Alone,
+ )]);
+ let outer_ident = Ident::new(outer, span);
+ let path = Path::from_ident(outer_ident);
+ let attr_args = AttrArgs::Delimited(DelimArgs {
+ dspan: DelimSpan::from_single(span),
+ delim: MacDelimiter::Parenthesis,
+ tokens: inner_tokens,
+ });
+ mk_attr(g, style, path, attr_args, span)
}
pub fn mk_doc_comment(
}
impl MetaItem {
- fn token_trees(&self) -> Vec<TokenTree> {
- let mut idents = vec![];
- let mut last_pos = BytePos(0_u32);
- for (i, segment) in self.path.segments.iter().enumerate() {
- let is_first = i == 0;
- if !is_first {
- let mod_sep_span =
- Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt(), None);
- idents.push(TokenTree::token_alone(token::ModSep, mod_sep_span));
- }
- idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident), Spacing::Alone));
- last_pos = segment.ident.span.hi();
- }
- idents.extend(self.kind.token_trees(self.span));
- idents
- }
-
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
where
I: Iterator<Item = TokenTree>,
}
}
- pub fn attr_args(&self, span: Span) -> AttrArgs {
- match self {
- MetaItemKind::Word => AttrArgs::Empty,
- MetaItemKind::NameValue(lit) => {
- let expr = P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- kind: ast::ExprKind::Lit(lit.token_lit.clone()),
- span: lit.span,
- attrs: ast::AttrVec::new(),
- tokens: None,
- });
- AttrArgs::Eq(span, AttrArgsEq::Ast(expr))
- }
- MetaItemKind::List(list) => {
- let mut tts = Vec::new();
- for (i, item) in list.iter().enumerate() {
- if i > 0 {
- tts.push(TokenTree::token_alone(token::Comma, span));
- }
- tts.extend(item.token_trees())
- }
- AttrArgs::Delimited(DelimArgs {
- dspan: DelimSpan::from_single(span),
- delim: MacDelimiter::Parenthesis,
- tokens: TokenStream::new(tts),
- })
- }
- }
- }
-
- fn token_trees(&self, span: Span) -> Vec<TokenTree> {
- match self {
- MetaItemKind::Word => vec![],
- MetaItemKind::NameValue(lit) => {
- vec![
- TokenTree::token_alone(token::Eq, span),
- TokenTree::Token(lit.to_token(), Spacing::Alone),
- ]
- }
- MetaItemKind::List(list) => {
- let mut tokens = Vec::new();
- for (i, item) in list.iter().enumerate() {
- if i > 0 {
- tokens.push(TokenTree::token_alone(token::Comma, span));
- }
- tokens.extend(item.token_trees())
- }
- vec![TokenTree::Delimited(
- DelimSpan::from_single(span),
- Delimiter::Parenthesis,
- TokenStream::new(tokens),
- )]
- }
- }
- }
-
fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
let mut tokens = tokens.into_trees().peekable();
let mut result = Vec::new();
}) => MetaItemKind::list_from_tokens(tokens.clone()),
AttrArgs::Delimited(..) => None,
AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind {
- ast::ExprKind::Lit(token_lit) => {
+ ExprKind::Lit(token_lit) => {
// Turn failures to `None`, we'll get parse errors elsewhere.
MetaItemLit::from_token_lit(token_lit, expr.span)
.ok()
}
}
- fn token_trees(&self) -> Vec<TokenTree> {
- match self {
- NestedMetaItem::MetaItem(item) => item.token_trees(),
- NestedMetaItem::Lit(lit) => {
- vec![TokenTree::Token(lit.to_token(), Spacing::Alone)]
- }
- }
- }
-
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
where
I: Iterator<Item = TokenTree>,
token::Lit::from_token(token)
.and_then(|token_lit| MetaItemLit::from_token_lit(token_lit, token.span).ok())
}
-
- /// Losslessly convert a meta item literal into a token.
- pub fn to_token(&self) -> Token {
- let kind = match self.token_lit.kind {
- token::Bool => token::Ident(self.token_lit.symbol, false),
- _ => token::Literal(self.token_lit),
- };
- Token::new(kind, self.span)
- }
}
fn strip_underscores(symbol: Symbol) -> Symbol {
};
// `#[allow(unreachable_code)]`
- let attr = {
- // `allow(unreachable_code)`
- let allow = {
- let allow_ident = Ident::new(sym::allow, self.lower_span(span));
- let uc_ident = Ident::new(sym::unreachable_code, self.lower_span(span));
- let uc_nested = attr::mk_nested_word_item(uc_ident);
- attr::mk_list_item(allow_ident, vec![uc_nested])
- };
- attr::mk_attr_outer(&self.tcx.sess.parse_sess.attr_id_generator, allow)
- };
+ let attr = attr::mk_attr_nested_word(
+ &self.tcx.sess.parse_sess.attr_id_generator,
+ AttrStyle::Outer,
+ sym::allow,
+ sym::unreachable_code,
+ self.lower_span(span),
+ );
let attrs: AttrVec = thin_vec![attr];
// `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
use rustc_span::edition::Edition;
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
-use rustc_span::{BytePos, FileName, Span};
+use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
use rustc_ast::attr::AttrIdGenerator;
use std::borrow::Cow;
// of the feature gate, so we fake them up here.
// `#![feature(prelude_import)]`
- let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import));
- let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]);
- let fake_attr = attr::mk_attr_inner(g, list);
+ let fake_attr = attr::mk_attr_nested_word(
+ g,
+ ast::AttrStyle::Inner,
+ sym::feature,
+ sym::prelude_import,
+ DUMMY_SP,
+ );
s.print_attribute(&fake_attr);
// Currently, in Rust 2018 we don't have `extern crate std;` at the crate
// root, so this is not needed, and actually breaks things.
if edition == Edition::Edition2015 {
// `#![no_std]`
- let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std));
- let fake_attr = attr::mk_attr_inner(g, no_std_meta);
+ let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP);
s.print_attribute(&fake_attr);
}
}
where_clause: ast::WhereClause {
has_where_token: false,
predicates: Vec::new(),
- span: rustc_span::DUMMY_SP,
+ span: DUMMY_SP,
},
- span: rustc_span::DUMMY_SP,
+ span: DUMMY_SP,
};
let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
self.print_fn(decl, header, name, &generics);
body,
}));
- let special = sym::rustc_std_internal_symbol;
- let special = cx.meta_word(span, special);
- let attrs = thin_vec![cx.attribute(special)];
+ let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)];
let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind);
cx.stmt_item(sig_span, item)
use rustc_ast::{
- attr,
ptr::P,
token,
tokenstream::{DelimSpan, TokenStream, TokenTree},
self.cx.item(
self.span,
Ident::empty(),
- thin_vec![self.cx.attribute(attr::mk_list_item(
- Ident::new(sym::allow, self.span),
- vec![attr::mk_nested_word_item(Ident::new(sym::unused_imports, self.span))],
- ))],
+ thin_vec![self.cx.attr_nested_word(sym::allow, sym::unused_imports, self.span)],
ItemKind::Use(UseTree {
prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])),
kind: UseTreeKind::Nested(vec![
_ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
}
- let inline = cx.meta_word(span, sym::inline);
- let attrs = thin_vec![cx.attribute(inline)];
+ let attrs = thin_vec![cx.attr_word(sym::inline, span)];
let trait_def = TraitDef {
span,
path: path_std!(clone::Clone),
use rustc_ast::{self as ast, MetaItem};
use rustc_data_structures::fx::FxHashSet;
use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::sym;
use rustc_span::Span;
use thin_vec::thin_vec;
is_const: bool,
) {
let span = cx.with_def_site_ctxt(span);
- let inline = cx.meta_word(span, sym::inline);
- let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span));
- let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]);
- let no_coverage = cx.meta_word(span, sym::no_coverage);
- let attrs = thin_vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)];
+ let attrs = thin_vec![
+ cx.attr_word(sym::inline, span),
+ cx.attr_nested_word(sym::doc, sym::hidden, span),
+ cx.attr_word(sym::no_coverage, span)
+ ];
let trait_def = TraitDef {
span,
path: path_std!(cmp::Eq),
push: &mut dyn FnMut(Annotatable),
is_const: bool,
) {
- let inline = cx.meta_word(span, sym::inline);
- let attrs = thin_vec![cx.attribute(inline)];
+ let attrs = thin_vec![cx.attr_word(sym::inline, span)];
let trait_def = TraitDef {
span,
path: path_std!(cmp::Ord),
// No need to generate `ne`, the default suffices, and not generating it is
// faster.
- let inline = cx.meta_word(span, sym::inline);
- let attrs = thin_vec![cx.attribute(inline)];
+ let attrs = thin_vec![cx.attr_word(sym::inline, span)];
let methods = vec![MethodDef {
name: sym::eq,
generics: Bounds::empty(),
let ret_ty =
Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
- let inline = cx.meta_word(span, sym::inline);
- let attrs = thin_vec![cx.attribute(inline)];
+ let attrs = thin_vec![cx.attr_word(sym::inline, span)];
let partial_cmp_def = MethodDef {
name: sym::partial_cmp,
) {
item.visit_with(&mut DetectNonVariantDefaultAttr { cx });
- let inline = cx.meta_word(span, sym::inline);
- let attrs = thin_vec![cx.attribute(inline)];
+ let attrs = thin_vec![cx.attr_word(sym::inline, span)];
let trait_def = TraitDef {
span,
path: Path::new(vec![kw::Default, sym::Default]),
let path = cx.path_all(self.span, false, vec![type_ident], self_params);
let self_type = cx.ty_path(path);
- let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
+ let attr = cx.attr_word(sym::automatically_derived, self.span);
let attrs = thin_vec![attr];
let opt_trait_ref = Some(trait_ref);
.cloned(),
);
// Mark as `automatically_derived` to avoid some silly lints.
- attrs.push(cx.attribute(cx.meta_word(span, sym::automatically_derived)));
+ attrs.push(cx.attr_word(sym::automatically_derived, span));
let newitem = cx.item(
span,
}
fn attrs(&self) -> AttrVec {
- let special = sym::rustc_std_internal_symbol;
- let special = self.cx.meta_word(self.span, special);
- thin_vec![self.cx.attribute(special)]
+ thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)]
}
fn arg_ty(
-use std::mem;
-
-use rustc_ast::attr;
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, NodeId};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use smallvec::smallvec;
+use std::mem;
struct ProcMacroDerive {
id: NodeId,
cx.expr_array_ref(span, decls),
)
.map(|mut i| {
- let attr = cx.meta_word(span, sym::rustc_proc_macro_decls);
- i.attrs.push(cx.attribute(attr));
-
- let deprecated_attr = attr::mk_nested_word_item(Ident::new(sym::deprecated, span));
- let allow_deprecated_attr =
- attr::mk_list_item(Ident::new(sym::allow, span), vec![deprecated_attr]);
- i.attrs.push(cx.attribute(allow_deprecated_attr));
-
+ i.attrs.push(cx.attr_word(sym::rustc_proc_macro_decls, span));
+ i.attrs.push(cx.attr_nested_word(sym::allow, sym::deprecated, span));
i
});
cx.item(
span,
ident,
- thin_vec![cx.attribute(cx.meta_word(span, sym::macro_use))],
+ thin_vec![cx.attr_word(sym::macro_use, span)],
ast::ItemKind::ExternCrate(None),
),
);
let use_item = cx.item(
span,
Ident::empty(),
- thin_vec![cx.attribute(cx.meta_word(span, sym::prelude_import))],
+ thin_vec![cx.attr_word(sym::prelude_import, span)],
ast::ItemKind::Use(ast::UseTree {
prefix: cx.path(span, import_path),
kind: ast::UseTreeKind::Glob,
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
use rustc_ast as ast;
-use rustc_ast::attr;
use rustc_ast::ptr::P;
use rustc_ast_pretty::pprust;
use rustc_errors::Applicability;
tokens: None,
};
item.ident.span = item.ident.span.with_ctxt(sp.ctxt());
- item.attrs.push(ecx.attribute(attr::mk_name_value_item_str(
- Ident::new(sym::rustc_test_marker, sp),
- test_path_symbol,
- sp,
- )));
+ item.attrs.push(ecx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, sp));
item
});
Ident::new(item.ident.name, sp),
thin_vec![
// #[cfg(test)]
- cx.attribute(attr::mk_list_item(
- Ident::new(sym::cfg, attr_sp),
- vec![attr::mk_nested_word_item(Ident::new(sym::test, attr_sp))],
- )),
+ cx.attr_nested_word(sym::cfg, sym::test, attr_sp),
// #[rustc_test_marker = "test_case_sort_key"]
- cx.attribute(attr::mk_name_value_item_str(
- Ident::new(sym::rustc_test_marker, attr_sp),
- test_path_symbol,
- attr_sp,
- )),
+ cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp),
]
.into(),
// const $ident: test::TestDescAndFn =
let item = match entry_point_type(self.sess, &item, self.depth) {
EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
- let allow_ident = Ident::new(sym::allow, self.def_site);
- let dc_nested =
- attr::mk_nested_word_item(Ident::new(sym::dead_code, self.def_site));
- let allow_dead_code_item = attr::mk_list_item(allow_ident, vec![dc_nested]);
- let allow_dead_code = attr::mk_attr_outer(
+ let allow_dead_code = attr::mk_attr_nested_word(
&self.sess.parse_sess.attr_id_generator,
- allow_dead_code_item,
+ ast::AttrStyle::Outer,
+ sym::allow,
+ sym::dead_code,
+ self.def_site,
);
let attrs = attrs
.into_iter()
);
// #[rustc_main]
- let main_meta = ecx.meta_word(sp, sym::rustc_main);
- let main_attr = ecx.attribute(main_meta);
+ let main_attr = ecx.attr_word(sym::rustc_main, sp);
// pub fn main() { ... }
let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![]));
self.item(span, name, AttrVec::new(), ast::ItemKind::Const(def, ty, Some(expr)))
}
- pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute {
- attr::mk_attr_outer(&self.sess.parse_sess.attr_id_generator, mi)
+ // Builds `#[name]`.
+ pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute {
+ let g = &self.sess.parse_sess.attr_id_generator;
+ attr::mk_attr_word(g, ast::AttrStyle::Outer, name, span)
}
- pub fn meta_word(&self, sp: Span, w: Symbol) -> ast::MetaItem {
- attr::mk_word_item(Ident::new(w, sp))
+ // Builds `#[name = val]`.
+ //
+ // Note: `span` is used for both the identifer and the value.
+ pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute {
+ let g = &self.sess.parse_sess.attr_id_generator;
+ attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span)
+ }
+
+ // Builds `#[outer(inner)]`.
+ pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute {
+ let g = &self.sess.parse_sess.attr_id_generator;
+ attr::mk_attr_nested_word(g, ast::AttrStyle::Outer, outer, inner, span)
}
}