Skip to content

Attribute cleanups #104861

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 1, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 38 additions & 34 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
@@ -479,20 +479,10 @@ pub struct Crate {
pub is_placeholder: bool,
}

/// Possible values inside of compile-time attribute lists.
///
/// E.g., the '..' in `#[name(..)]`.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum NestedMetaItem {
/// A full MetaItem, for recursive meta items.
MetaItem(MetaItem),
/// A literal.
///
/// E.g., `"foo"`, `64`, `true`.
Lit(MetaItemLit),
}

/// A spanned compile-time attribute item.
/// A semantic representation of a meta item. A meta item is a slightly
/// restricted form of an attribute -- it can only contain expressions in
/// certain leaf positions, rather than arbitrary token streams -- that is used
/// for most built-in attributes.
///
/// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -502,25 +492,39 @@ pub struct MetaItem {
pub span: Span,
}

/// A compile-time attribute item.
///
/// E.g., `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`.
/// The meta item kind, containing the data after the initial path.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum MetaItemKind {
/// Word meta item.
///
/// E.g., `test` as in `#[test]`.
/// E.g., `#[test]`, which lacks any arguments after `test`.
Word,

/// List meta item.
///
/// E.g., `derive(..)` as in `#[derive(..)]`.
/// E.g., `#[derive(..)]`, where the field represents the `..`.
List(Vec<NestedMetaItem>),

/// Name value meta item.
///
/// E.g., `feature = "foo"` as in `#[feature = "foo"]`.
/// E.g., `#[feature = "foo"]`, where the field represents the `"foo"`.
NameValue(MetaItemLit),
}

/// Values inside meta item lists.
///
/// E.g., each of `Clone`, `Copy` in `#[derive(Clone, Copy)]`.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum NestedMetaItem {
/// A full MetaItem, for recursive meta items.
MetaItem(MetaItem),

/// A literal.
///
/// E.g., `"foo"`, `64`, `true`.
Lit(MetaItemLit),
}

/// A block (`{ .. }`).
///
/// E.g., `{ .. }` as in `fn foo() { .. }`.
@@ -2570,17 +2574,10 @@ impl<D: Decoder> Decodable<D> for AttrId {
}
}

#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct AttrItem {
pub path: Path,
pub args: AttrArgs,
pub tokens: Option<LazyAttrTokenStream>,
}

/// A list of attributes.
pub type AttrVec = ThinVec<Attribute>;

/// Metadata associated with an item.
/// A syntax-level representation of an attribute.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct Attribute {
pub kind: AttrKind,
@@ -2591,12 +2588,6 @@ pub struct Attribute {
pub span: Span,
}

#[derive(Clone, Encodable, Decodable, Debug)]
pub struct NormalAttr {
pub item: AttrItem,
pub tokens: Option<LazyAttrTokenStream>,
}

#[derive(Clone, Encodable, Decodable, Debug)]
pub enum AttrKind {
/// A normal attribute.
@@ -2608,6 +2599,19 @@ pub enum AttrKind {
DocComment(CommentKind, Symbol),
}

#[derive(Clone, Encodable, Decodable, Debug)]
pub struct NormalAttr {
pub item: AttrItem,
pub tokens: Option<LazyAttrTokenStream>,
}

#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct AttrItem {
pub path: Path,
pub args: AttrArgs,
pub tokens: Option<LazyAttrTokenStream>,
}

/// `TraitRef`s appear in impls.
///
/// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all
171 changes: 54 additions & 117 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
//! 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::tokenstream::{LazyAttrTokenStream, TokenStream};
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;
@@ -223,11 +222,7 @@ impl AttrItem {
}

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> {
@@ -329,26 +324,13 @@ impl Attribute {
/* 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, lit_kind: LitKind, lit_span: Span) -> MetaItem {
let lit = MetaItemLit::from_lit_kind(lit_kind, lit_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>>);
@@ -406,21 +388,58 @@ pub fn mk_attr_from_item(
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(
@@ -438,23 +457,6 @@ pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
}

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>,
@@ -526,62 +528,6 @@ impl MetaItemKind {
}
}

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();
@@ -620,7 +566,7 @@ impl MetaItemKind {
}) => 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()
@@ -659,15 +605,6 @@ impl NestedMetaItem {
}
}

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>,
16 changes: 0 additions & 16 deletions compiler/rustc_ast/src/util/literal.rs
Original file line number Diff line number Diff line change
@@ -206,22 +206,6 @@ impl MetaItemLit {
token::Lit::from_token(token)
.and_then(|token_lit| MetaItemLit::from_token_lit(token_lit, token.span).ok())
}

/// Attempts to create a meta item literal from a `LitKind`.
/// This function is used when the original token doesn't exist (e.g. the literal is created
/// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
pub fn from_lit_kind(kind: LitKind, span: Span) -> MetaItemLit {
MetaItemLit { token_lit: kind.to_token_lit(), kind, span }
}

/// 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 {
17 changes: 7 additions & 10 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
@@ -1606,16 +1606,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
};

// `#[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,`
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
@@ -912,7 +912,7 @@ fn validate_generic_param_order(

impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_attribute(&mut self, attr: &Attribute) {
validate_attr::check_meta(&self.session.parse_sess, attr);
validate_attr::check_attr(&self.session.parse_sess, attr);
}

fn visit_expr(&mut self, expr: &'a Expr) {
19 changes: 11 additions & 8 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
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;
@@ -119,17 +119,20 @@ pub fn print_crate<'a>(
// 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);
}
}
@@ -1712,9 +1715,9 @@ impl<'a> State<'a> {
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);
4 changes: 1 addition & 3 deletions compiler/rustc_builtin_macros/src/alloc_error_handler.rs
Original file line number Diff line number Diff line change
@@ -95,9 +95,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
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)
6 changes: 1 addition & 5 deletions compiler/rustc_builtin_macros/src/assert/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use rustc_ast::{
attr,
ptr::P,
token,
tokenstream::{DelimSpan, TokenStream, TokenTree},
@@ -118,10 +117,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
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![
6 changes: 3 additions & 3 deletions compiler/rustc_builtin_macros/src/cfg_accessible.rs
Original file line number Diff line number Diff line change
@@ -37,10 +37,10 @@ impl MultiItemModifier for Expander {
_is_derive_const: bool,
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let template = AttributeTemplate { list: Some("path"), ..Default::default() };
let attr = &ecx.attribute(meta_item.clone());
validate_attr::check_builtin_attribute(
validate_attr::check_builtin_meta_item(
&ecx.sess.parse_sess,
attr,
&meta_item,
ast::AttrStyle::Outer,
sym::cfg_accessible,
template,
);
50 changes: 26 additions & 24 deletions compiler/rustc_builtin_macros/src/derive.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::cfg_eval::cfg_eval;

use rustc_ast as ast;
use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
use rustc_ast::{token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
use rustc_errors::{struct_span_err, Applicability};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
use rustc_feature::AttributeTemplate;
@@ -33,34 +33,36 @@ impl MultiItemModifier for Expander {
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
let template =
AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
let attr =
attr::mk_attr_outer(&sess.parse_sess.attr_id_generator, meta_item.clone());
validate_attr::check_builtin_attribute(
validate_attr::check_builtin_meta_item(
&sess.parse_sess,
&attr,
&meta_item,
ast::AttrStyle::Outer,
sym::derive,
template,
);

let mut resolutions: Vec<_> = attr
.meta_item_list()
.unwrap_or_default()
.into_iter()
.filter_map(|nested_meta| match nested_meta {
NestedMetaItem::MetaItem(meta) => Some(meta),
NestedMetaItem::Lit(lit) => {
// Reject `#[derive("Debug")]`.
report_unexpected_meta_item_lit(sess, &lit);
None
}
})
.map(|meta| {
// Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the paths.
report_path_args(sess, &meta);
meta.path
})
.map(|path| (path, dummy_annotatable(), None, self.0))
.collect();
let mut resolutions = match &meta_item.kind {
MetaItemKind::List(list) => {
list.iter()
.filter_map(|nested_meta| match nested_meta {
NestedMetaItem::MetaItem(meta) => Some(meta),
NestedMetaItem::Lit(lit) => {
// Reject `#[derive("Debug")]`.
report_unexpected_meta_item_lit(sess, &lit);
None
}
})
.map(|meta| {
// Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the
// paths.
report_path_args(sess, &meta);
meta.path.clone()
})
.map(|path| (path, dummy_annotatable(), None, self.0))
.collect()
}
_ => vec![],
};

// Do not configure or clone items unless necessary.
match &mut resolutions[..] {
3 changes: 1 addition & 2 deletions compiler/rustc_builtin_macros/src/deriving/clone.rs
Original file line number Diff line number Diff line change
@@ -68,8 +68,7 @@ pub fn expand_deriving_clone(
_ => 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),
12 changes: 6 additions & 6 deletions compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use crate::deriving::path_std;
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;

@@ -18,11 +18,11 @@ pub fn expand_deriving_eq(
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),
3 changes: 1 addition & 2 deletions compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
Original file line number Diff line number Diff line change
@@ -15,8 +15,7 @@ pub fn expand_deriving_ord(
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),
3 changes: 1 addition & 2 deletions compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
Original file line number Diff line number Diff line change
@@ -68,8 +68,7 @@ pub fn expand_deriving_partial_eq(

// 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(),
Original file line number Diff line number Diff line change
@@ -19,8 +19,7 @@ pub fn expand_deriving_partial_ord(
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,
3 changes: 1 addition & 2 deletions compiler/rustc_builtin_macros/src/deriving/default.rs
Original file line number Diff line number Diff line change
@@ -20,8 +20,7 @@ pub fn expand_deriving_default(
) {
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]),
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
@@ -718,7 +718,7 @@ impl<'a> TraitDef<'a> {
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);

2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/mod.rs
Original file line number Diff line number Diff line change
@@ -188,7 +188,7 @@ fn inject_impl_of_structural_trait(
.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,
4 changes: 1 addition & 3 deletions compiler/rustc_builtin_macros/src/global_allocator.rs
Original file line number Diff line number Diff line change
@@ -115,9 +115,7 @@ impl AllocFnFactory<'_, '_> {
}

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(
14 changes: 3 additions & 11 deletions compiler/rustc_builtin_macros/src/proc_macro_harness.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
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};
@@ -13,6 +10,7 @@ use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use smallvec::smallvec;
use std::mem;

struct ProcMacroDerive {
id: NodeId,
@@ -365,14 +363,8 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
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
});

4 changes: 2 additions & 2 deletions compiler/rustc_builtin_macros/src/standard_library_imports.rs
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ pub fn inject(
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),
),
);
@@ -79,7 +79,7 @@ pub fn inject(
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,
18 changes: 3 additions & 15 deletions compiler/rustc_builtin_macros/src/test.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
/// 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;
@@ -47,11 +46,7 @@ pub fn expand_test_case(
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
});

@@ -241,16 +236,9 @@ pub fn expand_test_or_bench(
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 =
14 changes: 6 additions & 8 deletions compiler/rustc_builtin_macros/src/test_harness.rs
Original file line number Diff line number Diff line change
@@ -185,13 +185,12 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
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()
@@ -309,8 +308,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
);

// #[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![]));
11 changes: 8 additions & 3 deletions compiler/rustc_builtin_macros/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rustc_ast::{Attribute, MetaItem};
use rustc_ast::{AttrStyle, Attribute, MetaItem};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_feature::AttributeTemplate;
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
@@ -8,8 +8,13 @@ use rustc_span::Symbol;
pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
// All the built-in macro attributes are "words" at the moment.
let template = AttributeTemplate { word: true, ..Default::default() };
let attr = ecx.attribute(meta_item.clone());
validate_attr::check_builtin_attribute(&ecx.sess.parse_sess, &attr, name, template);
validate_attr::check_builtin_meta_item(
&ecx.sess.parse_sess,
&meta_item,
AttrStyle::Outer,
name,
template,
);
}

/// Emit a warning if the item is annotated with the given attribute. This is used to diagnose when
22 changes: 16 additions & 6 deletions compiler/rustc_expand/src/build.rs
Original file line number Diff line number Diff line change
@@ -579,8 +579,6 @@ impl<'a> ExtCtxt<'a> {
attrs: ast::AttrVec,
kind: ast::ItemKind,
) -> P<ast::Item> {
// FIXME: Would be nice if our generated code didn't violate
// Rust coding conventions
P(ast::Item {
ident: name,
attrs,
@@ -618,11 +616,23 @@ impl<'a> ExtCtxt<'a> {
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)
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
@@ -1644,7 +1644,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
let mut span: Option<Span> = None;
while let Some(attr) = attrs.next() {
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
validate_attr::check_meta(&self.cx.sess.parse_sess, attr);
validate_attr::check_attr(&self.cx.sess.parse_sess, attr);

let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
span = Some(current_span);
43 changes: 26 additions & 17 deletions compiler/rustc_parse/src/validate_attr.rs
Original file line number Diff line number Diff line change
@@ -10,9 +10,9 @@ use rustc_errors::{Applicability, FatalError, PResult};
use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_session::parse::ParseSess;
use rustc_span::{sym, Symbol};
use rustc_span::{sym, Span, Symbol};

pub fn check_meta(sess: &ParseSess, attr: &Attribute) {
pub fn check_attr(sess: &ParseSess, attr: &Attribute) {
if attr.is_doc_comment() {
return;
}
@@ -115,25 +115,34 @@ pub fn check_builtin_attribute(
name: Symbol,
template: AttributeTemplate,
) {
// Some special attributes like `cfg` must be checked
// before the generic check, so we skip them here.
let should_skip = |name| name == sym::cfg;

match parse_meta(sess, attr) {
Ok(meta) => {
if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
emit_malformed_attribute(sess, attr, name, template);
}
}
Ok(meta) => check_builtin_meta_item(sess, &meta, attr.style, name, template),
Err(mut err) => {
err.emit();
}
}
}

pub fn check_builtin_meta_item(
sess: &ParseSess,
meta: &MetaItem,
style: ast::AttrStyle,
name: Symbol,
template: AttributeTemplate,
) {
// Some special attributes like `cfg` must be checked
// before the generic check, so we skip them here.
let should_skip = |name| name == sym::cfg;

if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
emit_malformed_attribute(sess, style, meta.span, name, template);
}
}

fn emit_malformed_attribute(
sess: &ParseSess,
attr: &Attribute,
style: ast::AttrStyle,
span: Span,
name: Symbol,
template: AttributeTemplate,
) {
@@ -147,7 +156,7 @@ fn emit_malformed_attribute(
let mut msg = "attribute must be of the form ".to_owned();
let mut suggestions = vec![];
let mut first = true;
let inner = if attr.style == ast::AttrStyle::Inner { "!" } else { "" };
let inner = if style == ast::AttrStyle::Inner { "!" } else { "" };
if template.word {
first = false;
let code = format!("#{}[{}]", inner, name);
@@ -172,12 +181,12 @@ fn emit_malformed_attribute(
suggestions.push(code);
}
if should_warn(name) {
sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, attr.span, ast::CRATE_NODE_ID, &msg);
sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, &msg);
} else {
sess.span_diagnostic
.struct_span_err(attr.span, &error_msg)
.struct_span_err(span, &error_msg)
.span_suggestions(
attr.span,
span,
if suggestions.len() == 1 {
"must be of the form"
} else {
@@ -196,7 +205,7 @@ pub fn emit_fatal_malformed_builtin_attribute(
name: Symbol,
) -> ! {
let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").template;
emit_malformed_attribute(sess, attr, name, template);
emit_malformed_attribute(sess, attr.style, attr.span, name, template);
// This is fatal, otherwise it will likely cause a cascade of other errors
// (and an error here is expected to be very rare).
FatalError.raise()
4 changes: 3 additions & 1 deletion src/test/ui/span/macro-ty-params.rs
Original file line number Diff line number Diff line change
@@ -9,5 +9,7 @@ macro_rules! foo { () => () }
fn main() {
foo::<T>!(); //~ ERROR generic arguments in macro path
foo::<>!(); //~ ERROR generic arguments in macro path
m!(Default<>); //~ ERROR unexpected generic arguments in path
m!(Default<>);
//~^ ERROR unexpected generic arguments in path
//~^^ ERROR generic arguments in macro path
}
8 changes: 7 additions & 1 deletion src/test/ui/span/macro-ty-params.stderr
Original file line number Diff line number Diff line change
@@ -16,5 +16,11 @@ error: unexpected generic arguments in path
LL | m!(Default<>);
| ^^

error: aborting due to 3 previous errors
error: generic arguments in macro path
--> $DIR/macro-ty-params.rs:12:15
|
LL | m!(Default<>);
| ^^

error: aborting due to 4 previous errors