Skip to content

Commit

Permalink
Auto merge of #40346 - jseyfried:path_and_tokenstream_attr, r=nrc
Browse files Browse the repository at this point in the history
`TokenStream`-based attributes, paths in attribute and derive macro invocations

This PR
 - refactors `Attribute` to use  `Path` and `TokenStream` instead of `MetaItem`.
 - supports macro invocation paths for attribute procedural macros.
   - e.g. `#[::foo::attr_macro] struct S;`, `#[cfg_attr(all(), foo::attr_macro)] struct S;`
 - supports macro invocation paths for derive procedural macros.
   - e.g. `#[derive(foo::Bar, super::Baz)] struct S;`
 - supports arbitrary tokens as arguments to attribute procedural macros.
   - e.g. `#[foo::attr_macro arbitrary + tokens] struct S;`
 - supports using arbitrary tokens in "inert attributes" with derive procedural macros.
   - e.g. `#[derive(Foo)] struct S(#[inert arbitrary + tokens] i32);`
where `#[proc_macro_derive(Foo, attributes(inert))]`

r? @nrc
  • Loading branch information
bors committed Mar 19, 2017
2 parents bfc49b1 + 85e02bd commit 9c15de4
Show file tree
Hide file tree
Showing 56 changed files with 883 additions and 539 deletions.
11 changes: 6 additions & 5 deletions src/librustc/hir/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,12 @@ impl<'a> CheckAttrVisitor<'a> {
}

fn check_attribute(&self, attr: &ast::Attribute, target: Target) {
let name: &str = &attr.name().as_str();
match name {
"inline" => self.check_inline(attr, target),
"repr" => self.check_repr(attr, target),
_ => (),
if let Some(name) = attr.name() {
match &*name.as_str() {
"inline" => self.check_inline(attr, target),
"repr" => self.check_repr(attr, target),
_ => (),
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,7 +1296,7 @@ impl<'a> LoweringContext<'a> {
let attrs = self.lower_attrs(&i.attrs);
let mut vis = self.lower_visibility(&i.vis);
if let ItemKind::MacroDef(ref tts) = i.node {
if i.attrs.iter().any(|attr| attr.name() == "macro_export") {
if i.attrs.iter().any(|attr| attr.path == "macro_export") {
self.exported_macros.push(hir::MacroDef {
name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(),
});
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,14 +408,14 @@ pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec<Result<(ast::Name, Level, S
pub fn gather_attr(attr: &ast::Attribute) -> Vec<Result<(ast::Name, Level, Span), Span>> {
let mut out = vec![];

let level = match Level::from_str(&attr.name().as_str()) {
let level = match attr.name().and_then(|name| Level::from_str(&name.as_str())) {
None => return out,
Some(lvl) => lvl,
};

let meta = unwrap_or!(attr.meta(), return out);
attr::mark_used(attr);

let meta = &attr.value;
let metas = if let Some(metas) = meta.meta_item_list() {
metas
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
} else {
// Emit errors for non-staged-api crates.
for attr in attrs {
let tag = attr.name();
let tag = unwrap_or!(attr.name(), continue);
if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" {
attr::mark_used(attr);
self.tcx.sess.span_err(attr.span(), "stability attributes may not be used \
Expand Down Expand Up @@ -402,7 +402,7 @@ impl<'a, 'tcx> Index<'tcx> {

let mut is_staged_api = false;
for attr in &krate.attrs {
if attr.name() == "stable" || attr.name() == "unstable" {
if attr.path == "stable" || attr.path == "unstable" {
is_staged_api = true;
break
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
.filter(|a| a.check_name("rustc_on_unimplemented"))
.next()
{
let err_sp = item.meta().span.substitute_dummy(span);
let err_sp = item.span.substitute_dummy(span);
let trait_str = self.tcx.item_path_str(trait_ref.def_id);
if let Some(istring) = item.value_str() {
let istring = &*istring.as_str();
Expand Down
55 changes: 14 additions & 41 deletions src/librustc_incremental/calculate_svh/svh_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,15 @@ use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId};
use syntax::attr;
use syntax::parse::token;
use syntax::symbol::{Symbol, InternedString};
use syntax::symbol::InternedString;
use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
use syntax::tokenstream;
use rustc::hir;
use rustc::hir::*;
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit as visit;
use rustc::hir::intravisit::{self as visit, Visitor};
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv;
use std::hash::{Hash, Hasher};

use super::def_path_hash::DefPathHashes;
Expand Down Expand Up @@ -559,7 +558,7 @@ macro_rules! hash_span {
});
}

impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> {
if self.hash_bodies {
visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir)
Expand Down Expand Up @@ -960,50 +959,24 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
}
}

fn hash_meta_item(&mut self, meta_item: &ast::MetaItem) {
debug!("hash_meta_item: st={:?}", self.st);

// ignoring span information, it doesn't matter here
self.hash_discriminant(&meta_item.node);
meta_item.name.as_str().len().hash(self.st);
meta_item.name.as_str().hash(self.st);

match meta_item.node {
ast::MetaItemKind::Word => {}
ast::MetaItemKind::NameValue(ref lit) => saw_lit(lit).hash(self.st),
ast::MetaItemKind::List(ref items) => {
// Sort subitems so the hash does not depend on their order
let indices = self.indices_sorted_by(&items, |p| {
(p.name().map(Symbol::as_str), fnv::hash(&p.literal().map(saw_lit)))
});
items.len().hash(self.st);
for (index, &item_index) in indices.iter().enumerate() {
index.hash(self.st);
let nested_meta_item: &ast::NestedMetaItemKind = &items[item_index].node;
self.hash_discriminant(nested_meta_item);
match *nested_meta_item {
ast::NestedMetaItemKind::MetaItem(ref meta_item) => {
self.hash_meta_item(meta_item);
}
ast::NestedMetaItemKind::Literal(ref lit) => {
saw_lit(lit).hash(self.st);
}
}
}
}
}
}

pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) {
debug!("hash_attributes: st={:?}", self.st);
let indices = self.indices_sorted_by(attributes, |attr| attr.name());

for i in indices {
let attr = &attributes[i];
if !attr.is_sugared_doc &&
!IGNORED_ATTRIBUTES.contains(&&*attr.value.name().as_str()) {
match attr.name() {
Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue,
_ => {}
};
if !attr.is_sugared_doc {
SawAttribute(attr.style).hash(self.st);
self.hash_meta_item(&attr.value);
for segment in &attr.path.segments {
SawIdent(segment.identifier.name.as_str()).hash(self.st);
}
for tt in attr.tokens.trees() {
self.hash_token_tree(&tt);
}
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_incremental/persist/dirty_clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {

impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode<DefId> {
for item in attr.meta_item_list().unwrap_or(&[]) {
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
if item.check_name(LABEL) {
let value = expect_associated_value(self.tcx, item);
let value = expect_associated_value(self.tcx, &item);
match DepNode::from_label_string(&value.as_str(), def_id) {
Ok(def_id) => return def_id,
Err(()) => {
Expand Down Expand Up @@ -331,9 +331,9 @@ fn check_config(tcx: TyCtxt, attr: &Attribute) -> bool {
debug!("check_config(attr={:?})", attr);
let config = &tcx.sess.parse_sess.config;
debug!("check_config: config={:?}", config);
for item in attr.meta_item_list().unwrap_or(&[]) {
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
if item.check_name(CFG) {
let value = expect_associated_value(tcx, item);
let value = expect_associated_value(tcx, &item);
debug!("check_config: searching for cfg {:?}", value);
return config.contains(&(value, None));
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ impl MissingDoc {
}
}

let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
let has_doc = attrs.iter().any(|a| a.is_value_str() && a.check_name("doc"));
if !has_doc {
cx.span_lint(MISSING_DOCS,
sp,
Expand Down Expand Up @@ -635,7 +635,7 @@ impl LintPass for DeprecatedAttr {

impl EarlyLintPass for DeprecatedAttr {
fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) {
let name = attr.name();
let name = unwrap_or!(attr.name(), return);
for &&(n, _, ref g) in &self.depr_attrs {
if name == n {
if let &AttributeGate::Gated(Stability::Deprecated(link),
Expand Down Expand Up @@ -1121,8 +1121,8 @@ impl LintPass for UnstableFeatures {

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures {
fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) {
if attr.meta().check_name("feature") {
if let Some(items) = attr.meta().meta_item_list() {
if attr.check_name("feature") {
if let Some(items) = attr.meta_item_list() {
for item in items {
ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature");
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#![feature(slice_patterns)]
#![feature(staged_api)]

#[macro_use]
extern crate syntax;
#[macro_use]
extern crate rustc;
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ impl LintPass for UnusedAttributes {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
debug!("checking attribute: {:?}", attr);
let name = unwrap_or!(attr.name(), return);

// Note that check_name() marks the attribute as used if it matches.
for &(ref name, ty, _) in BUILTIN_ATTRIBUTES {
Expand All @@ -294,13 +295,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
// Is it a builtin attribute that must be used at the crate level?
let known_crate = BUILTIN_ATTRIBUTES.iter()
.find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel)
.find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel)
.is_some();

// Has a plugin registered this attribute as one which must be used at
// the crate level?
let plugin_crate = plugin_attributes.iter()
.find(|&&(ref x, t)| attr.name() == &**x && AttributeType::CrateLevel == t)
.find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t)
.is_some();
if known_crate || plugin_crate {
let msg = match attr.style {
Expand Down
8 changes: 5 additions & 3 deletions src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,9 +973,11 @@ impl<'a> CrateLoader<'a> {

impl<'a> CrateLoader<'a> {
pub fn preprocess(&mut self, krate: &ast::Crate) {
for attr in krate.attrs.iter().filter(|m| m.name() == "link_args") {
if let Some(linkarg) = attr.value_str() {
self.cstore.add_used_link_args(&linkarg.as_str());
for attr in &krate.attrs {
if attr.path == "link_args" {
if let Some(linkarg) = attr.value_str() {
self.cstore.add_used_link_args(&linkarg.as_str());
}
}
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/librustc_metadata/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,12 @@ impl CrateMetadata {
}

pub fn is_staged_api(&self) -> bool {
self.get_item_attrs(CRATE_DEF_INDEX)
.iter()
.any(|attr| attr.name() == "stable" || attr.name() == "unstable")
for attr in self.get_item_attrs(CRATE_DEF_INDEX) {
if attr.path == "stable" || attr.path == "unstable" {
return true;
}
}
false
}

pub fn is_allocator(&self) -> bool {
Expand Down
4 changes: 1 addition & 3 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
ItemKind::Mod(_) => {
// Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
attr::first_attr_value_str_by_name(&item.attrs, "path");
if let Some(attr) =
item.attrs.iter().find(|attr| attr.name() == "warn_directory_ownership") {
if item.attrs.iter().any(|attr| attr.check_name("warn_directory_ownership")) {
let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP;
let msg = "cannot declare a new module at this location";
self.session.add_lint(lint, item.id, item.span, msg.to_string());
attr::mark_used(attr);
}
}
ItemKind::Union(ref vdata, _) => {
Expand Down
7 changes: 5 additions & 2 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,7 @@ pub struct Resolver<'a> {

privacy_errors: Vec<PrivacyError<'a>>,
ambiguity_errors: Vec<AmbiguityError<'a>>,
gated_errors: FxHashSet<Span>,
disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,

arenas: &'a ResolverArenas<'a>,
Expand Down Expand Up @@ -1355,6 +1356,7 @@ impl<'a> Resolver<'a> {

privacy_errors: Vec::new(),
ambiguity_errors: Vec::new(),
gated_errors: FxHashSet(),
disallowed_shadowing: Vec::new(),

arenas: arenas,
Expand Down Expand Up @@ -3359,8 +3361,9 @@ impl<'a> Resolver<'a> {
if self.proc_macro_enabled { return; }

for attr in attrs {
let maybe_binding = self.builtin_macros.get(&attr.name()).cloned().or_else(|| {
let ident = Ident::with_empty_ctxt(attr.name());
let name = unwrap_or!(attr.name(), continue);
let maybe_binding = self.builtin_macros.get(&name).cloned().or_else(|| {
let ident = Ident::with_empty_ctxt(name);
self.resolve_lexical_macro_path_segment(ident, MacroNS, None).ok()
});

Expand Down
Loading

0 comments on commit 9c15de4

Please sign in to comment.