about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2016-11-09 20:51:18 +0200
committerGitHub <noreply@github.com>2016-11-09 20:51:18 +0200
commit5ebd7c50a0b9236af4389b00c97b00a59d9fa747 (patch)
tree7ae11942986307fad0aa452b5ee4a9db0cb89e9f /src/libsyntax
parent3d2ffa06ea4e04dbda99d7038e9afd04c040b472 (diff)
parent134ef4f7933b87efdc04eac3e8d9a530d56d9cfe (diff)
downloadrust-5ebd7c50a0b9236af4389b00c97b00a59d9fa747.tar.gz
rust-5ebd7c50a0b9236af4389b00c97b00a59d9fa747.zip
Rollup merge of #37614 - keeperofdakeys:proc_macro, r=jseyfried
macros 1.1: Allow proc_macro functions to declare attributes to be mark as used

This PR allows proc macro functions to declare attribute names that should be marked as used when attached to the deriving item. There are a few questions for this PR.

- Currently this uses a separate attribute named `#[proc_macro_attributes(..)]`, is this the best choice?
- In order to make this work, the `check_attribute` function had to be modified to not error on attributes marked as used. This is a pretty large change in semantics, is there a better way to do this?
- I've got a few clones where I don't know if I need them (like turning `item` into a `TokenStream`), can these be avoided?
- Is switching to `MultiItemDecorator` the right thing here?

Also fixes https://github.com/rust-lang/rust/issues/37563.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/attr.rs26
-rw-r--r--src/libsyntax/feature_gate.rs10
2 files changed, 31 insertions, 5 deletions
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 0335f210347..57a936bf9b0 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -32,7 +32,8 @@ use std::cell::{RefCell, Cell};
 use std::collections::HashSet;
 
 thread_local! {
-    static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new())
+    static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new());
+    static KNOWN_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new());
 }
 
 enum AttrError {
@@ -81,6 +82,29 @@ pub fn is_used(attr: &Attribute) -> bool {
     })
 }
 
+pub fn mark_known(attr: &Attribute) {
+    debug!("Marking {:?} as known.", attr);
+    let AttrId(id) = attr.node.id;
+    KNOWN_ATTRS.with(|slot| {
+        let idx = (id / 64) as usize;
+        let shift = id % 64;
+        if slot.borrow().len() <= idx {
+            slot.borrow_mut().resize(idx + 1, 0);
+        }
+        slot.borrow_mut()[idx] |= 1 << shift;
+    });
+}
+
+pub fn is_known(attr: &Attribute) -> bool {
+    let AttrId(id) = attr.node.id;
+    KNOWN_ATTRS.with(|slot| {
+        let idx = (id / 64) as usize;
+        let shift = id % 64;
+        slot.borrow().get(idx).map(|bits| bits & (1 << shift) != 0)
+            .unwrap_or(false)
+    })
+}
+
 impl NestedMetaItem {
     /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
     pub fn meta_item(&self) -> Option<&P<MetaItem>> {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 8ac3f9e5e54..a6493872338 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -421,11 +421,11 @@ macro_rules! cfg_fn {
 }
 
 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
-    KNOWN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
+    BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
 }
 
 // Attributes that have a special meaning to rustc or rustdoc
-pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
+pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
     // Normal attributes
 
     ("warn", Normal, Ungated),
@@ -800,12 +800,12 @@ impl<'a> Context<'a> {
     fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
         debug!("check_attribute(attr = {:?})", attr);
         let name = &*attr.name();
-        for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES {
+        for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
             if n == name {
                 if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
                     gate_feature_fn!(self, has_feature, attr.span, name, desc);
                 }
-                debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
+                debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage);
                 return;
             }
         }
@@ -825,6 +825,8 @@ impl<'a> Context<'a> {
                            are reserved for internal compiler diagnostics");
         } else if name.starts_with("derive_") {
             gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
+        } else if attr::is_known(attr) {
+            debug!("check_attribute: {:?} is known", name);
         } else {
             // Only run the custom attribute lint during regular
             // feature gate checking. Macro gating runs