Skip to content

Commit 2cc61ee

Browse files
committed
Allow using inert attributes from proc_macro_derives with #![feature(proc_macro)].
1 parent 4b413bc commit 2cc61ee

File tree

18 files changed

+274
-281
lines changed

18 files changed

+274
-281
lines changed

Diff for: src/librustc_metadata/creader.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -616,10 +616,9 @@ impl<'a> CrateLoader<'a> {
616616
trait_name: &str,
617617
expand: fn(TokenStream) -> TokenStream,
618618
attributes: &[&'static str]) {
619-
let attrs = attributes.iter().cloned().map(Symbol::intern).collect();
620-
let derive = SyntaxExtension::ProcMacroDerive(
621-
Box::new(ProcMacroDerive::new(expand, attrs))
622-
);
619+
let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
620+
let derive = ProcMacroDerive::new(expand, attrs.clone());
621+
let derive = SyntaxExtension::ProcMacroDerive(Box::new(derive), attrs);
623622
self.0.push((Symbol::intern(trait_name), Rc::new(derive)));
624623
}
625624

Diff for: src/librustc_resolve/macros.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
2727
use syntax::ext::expand::{Expansion, mark_tts};
2828
use syntax::ext::hygiene::Mark;
2929
use syntax::ext::tt::macro_rules;
30-
use syntax::feature_gate::{self, emit_feature_err, GateIssue, is_builtin_attr};
30+
use syntax::feature_gate::{self, emit_feature_err, GateIssue};
3131
use syntax::fold::{self, Folder};
3232
use syntax::ptr::P;
3333
use syntax::symbol::{Symbol, keywords};
@@ -130,12 +130,16 @@ impl<'a> base::Resolver for Resolver<'a> {
130130
self.whitelisted_legacy_custom_derives.contains(&name)
131131
}
132132

133-
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
133+
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]) {
134134
let invocation = self.invocations[&mark];
135135
self.collect_def_ids(invocation, expansion);
136136

137137
self.current_module = invocation.module.get();
138138
self.current_module.unresolved_invocations.borrow_mut().remove(&mark);
139+
self.current_module.unresolved_invocations.borrow_mut().extend(derives);
140+
for &derive in derives {
141+
self.invocations.insert(derive, invocation);
142+
}
139143
let mut visitor = BuildReducedGraphVisitor {
140144
resolver: self,
141145
legacy_scope: LegacyScope::Invocation(invocation),
@@ -172,7 +176,9 @@ impl<'a> base::Resolver for Resolver<'a> {
172176
ImportResolver { resolver: self }.resolve_imports()
173177
}
174178

175-
fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
179+
// Resolves attribute and derive legacy macros from `#![plugin(..)]`.
180+
fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>)
181+
-> Option<ast::Attribute> {
176182
for i in 0..attrs.len() {
177183
match self.builtin_macros.get(&attrs[i].name()).cloned() {
178184
Some(binding) => match *binding.get_macro(self) {
@@ -183,10 +189,6 @@ impl<'a> base::Resolver for Resolver<'a> {
183189
},
184190
None => {}
185191
}
186-
187-
if self.proc_macro_enabled && !is_builtin_attr(&attrs[i]) {
188-
return Some(attrs.remove(i));
189-
}
190192
}
191193

192194
// Check for legacy derives
@@ -212,7 +214,7 @@ impl<'a> base::Resolver for Resolver<'a> {
212214
} else {
213215
attrs[i].value = ast::MetaItem {
214216
name: attrs[i].name(),
215-
span: span,
217+
span: attrs[i].span,
216218
node: ast::MetaItemKind::List(traits),
217219
};
218220
}
@@ -279,7 +281,7 @@ impl<'a> base::Resolver for Resolver<'a> {
279281
Ok(binding) => Ok(binding.get_macro(self)),
280282
Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined),
281283
_ => {
282-
let msg = format!("macro undefined: '{}!'", name);
284+
let msg = format!("macro undefined: `{}`", name);
283285
let mut err = self.session.struct_span_err(span, &msg);
284286
self.suggest_macro_name(&name.as_str(), &mut err);
285287
err.emit();
@@ -294,13 +296,6 @@ impl<'a> base::Resolver for Resolver<'a> {
294296
result
295297
}
296298

297-
fn resolve_builtin_macro(&mut self, tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy> {
298-
match self.builtin_macros.get(&tname).cloned() {
299-
Some(binding) => Ok(binding.get_macro(self)),
300-
None => Err(Determinacy::Undetermined),
301-
}
302-
}
303-
304299
fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
305300
-> Result<Rc<SyntaxExtension>, Determinacy> {
306301
let ast::Path { span, .. } = *path;

Diff for: src/libsyntax/ext/base.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ pub enum SyntaxExtension {
514514
/// The input is the annotated item.
515515
/// Allows generating code to implement a Trait for a given struct
516516
/// or enum item.
517-
ProcMacroDerive(Box<MultiItemModifier>),
517+
ProcMacroDerive(Box<MultiItemModifier>, Vec<Symbol> /* inert attribute names */),
518518

519519
/// An attribute-like procedural macro that derives a builtin trait.
520520
BuiltinDerive(BuiltinDeriveFn),
@@ -528,15 +528,15 @@ pub trait Resolver {
528528
fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item>;
529529
fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool;
530530

531-
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
531+
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]);
532532
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
533533
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
534534

535535
fn resolve_imports(&mut self);
536-
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
536+
// Resolves attribute and derive legacy macros from `#![plugin(..)]`.
537+
fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
537538
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
538539
-> Result<Rc<SyntaxExtension>, Determinacy>;
539-
fn resolve_builtin_macro(&mut self, tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy>;
540540
fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
541541
-> Result<Rc<SyntaxExtension>, Determinacy>;
542542
}
@@ -555,19 +555,16 @@ impl Resolver for DummyResolver {
555555
fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item }
556556
fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false }
557557

558-
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
558+
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, _derives: &[Mark]) {}
559559
fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
560560
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
561561

562562
fn resolve_imports(&mut self) {}
563-
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
563+
fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
564564
fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
565565
-> Result<Rc<SyntaxExtension>, Determinacy> {
566566
Err(Determinacy::Determined)
567567
}
568-
fn resolve_builtin_macro(&mut self, _tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy> {
569-
Err(Determinacy::Determined)
570-
}
571568
fn resolve_derive_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
572569
-> Result<Rc<SyntaxExtension>, Determinacy> {
573570
Err(Determinacy::Determined)

Diff for: src/libsyntax/ext/derive.rs

+35-135
Original file line numberDiff line numberDiff line change
@@ -8,124 +8,42 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use ast::Name;
12-
use attr;
13-
use ast::{self, NestedMetaItem}; use ext::base::{ExtCtxt, SyntaxExtension};
14-
use codemap;
11+
use attr::HasAttrs;
12+
use {ast, codemap};
13+
use ext::base::ExtCtxt;
1514
use ext::build::AstBuilder;
1615
use symbol::Symbol;
1716
use syntax_pos::Span;
1817

19-
pub fn derive_attr_trait<'a>(cx: &mut ExtCtxt, attr: &'a ast::Attribute)
20-
-> Option<&'a NestedMetaItem> {
21-
if attr.name() != "derive" {
22-
return None;
23-
}
24-
if attr.value_str().is_some() {
25-
cx.span_err(attr.span, "unexpected value in `derive`");
26-
return None;
27-
}
28-
29-
let traits = attr.meta_item_list().unwrap_or(&[]);
30-
31-
if traits.is_empty() {
32-
cx.span_warn(attr.span, "empty trait list in `derive`");
33-
return None;
34-
}
35-
36-
return traits.get(0);
37-
}
38-
39-
pub fn verify_derive_attrs(cx: &mut ExtCtxt, attrs: &[ast::Attribute]) {
40-
for attr in attrs {
18+
pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<(Symbol, Span)> {
19+
let mut result = Vec::new();
20+
attrs.retain(|attr| {
4121
if attr.name() != "derive" {
42-
continue;
22+
return true;
4323
}
4424

4525
if attr.value_str().is_some() {
4626
cx.span_err(attr.span, "unexpected value in `derive`");
27+
return false;
4728
}
4829

4930
let traits = attr.meta_item_list().unwrap_or(&[]).to_owned();
50-
5131
if traits.is_empty() {
5232
cx.span_warn(attr.span, "empty trait list in `derive`");
53-
attr::mark_used(&attr);
54-
continue;
33+
return false;
5534
}
35+
5636
for titem in traits {
5737
if titem.word().is_none() {
5838
cx.span_err(titem.span, "malformed `derive` entry");
39+
return false;
5940
}
60-
}
61-
}
62-
}
63-
64-
#[derive(PartialEq, Debug, Clone, Copy)]
65-
pub enum DeriveType {
66-
ProcMacro,
67-
Builtin
68-
}
69-
70-
impl DeriveType {
71-
// Classify a derive trait name by resolving the macro.
72-
pub fn classify(cx: &mut ExtCtxt, tname: Name) -> DeriveType {
73-
match cx.resolver.resolve_builtin_macro(tname) {
74-
Ok(ext) => match *ext {
75-
SyntaxExtension::BuiltinDerive(..) => DeriveType::Builtin,
76-
_ => DeriveType::ProcMacro,
77-
},
78-
Err(_) => DeriveType::ProcMacro,
79-
}
80-
}
81-
}
82-
83-
pub fn get_derive_attr(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>,
84-
derive_type: DeriveType) -> Option<ast::Attribute> {
85-
for i in 0..attrs.len() {
86-
if attrs[i].name() != "derive" {
87-
continue;
88-
}
89-
90-
if attrs[i].value_str().is_some() {
91-
continue;
92-
}
93-
94-
let mut traits = attrs[i].meta_item_list().unwrap_or(&[]).to_owned();
95-
96-
// First, weed out malformed #[derive]
97-
traits.retain(|titem| titem.word().is_some());
98-
99-
let mut titem = None;
100-
101-
// See if we can find a matching trait.
102-
for j in 0..traits.len() {
103-
let tname = match traits[j].name() {
104-
Some(tname) => tname,
105-
_ => continue,
106-
};
107-
108-
if DeriveType::classify(cx, tname) == derive_type {
109-
titem = Some(traits.remove(j));
110-
break;
111-
}
41+
result.push((titem.name().unwrap(), titem.span));
11242
}
11343

114-
// If we find a trait, remove the trait from the attribute.
115-
if let Some(titem) = titem {
116-
if traits.len() == 0 {
117-
attrs.remove(i);
118-
} else {
119-
let derive = Symbol::intern("derive");
120-
let mitem = cx.meta_list(titem.span, derive, traits);
121-
attrs[i] = cx.attribute(titem.span, mitem);
122-
}
123-
let derive = Symbol::intern("derive");
124-
let mitem = cx.meta_list(titem.span, derive, vec![titem]);
125-
return Some(cx.attribute(mitem.span, mitem));
126-
}
127-
}
128-
return None;
44+
true
45+
});
46+
result
12947
}
13048

13149
fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
@@ -142,43 +60,25 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
14260
}
14361
}
14462

145-
pub fn add_derived_markers(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) {
146-
if attrs.is_empty() {
147-
return;
148-
}
149-
150-
let titems = attrs.iter().filter(|a| {
151-
a.name() == "derive"
152-
}).flat_map(|a| {
153-
a.meta_item_list().unwrap_or(&[]).iter()
154-
}).filter_map(|titem| {
155-
titem.name()
156-
}).collect::<Vec<_>>();
157-
158-
let span = attrs[0].span;
159-
160-
if !attrs.iter().any(|a| a.name() == "structural_match") &&
161-
titems.iter().any(|t| *t == "PartialEq") && titems.iter().any(|t| *t == "Eq") {
162-
let structural_match = Symbol::intern("structural_match");
163-
let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
164-
let meta = cx.meta_word(span, structural_match);
165-
attrs.push(cx.attribute(span, meta));
166-
}
167-
168-
if !attrs.iter().any(|a| a.name() == "rustc_copy_clone_marker") &&
169-
titems.iter().any(|t| *t == "Copy") && titems.iter().any(|t| *t == "Clone") {
170-
let structural_match = Symbol::intern("rustc_copy_clone_marker");
171-
let span = allow_unstable(cx, span, "derive(Copy, Clone)");
172-
let meta = cx.meta_word(span, structural_match);
173-
attrs.push(cx.attribute(span, meta));
174-
}
175-
}
176-
177-
pub fn find_derive_attr(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>)
178-
-> Option<ast::Attribute> {
179-
verify_derive_attrs(cx, attrs);
180-
get_derive_attr(cx, attrs, DeriveType::ProcMacro).or_else(|| {
181-
add_derived_markers(cx, attrs);
182-
get_derive_attr(cx, attrs, DeriveType::Builtin)
63+
pub fn add_derived_markers<T: HasAttrs>(cx: &mut ExtCtxt, traits: &[(Symbol, Span)], item: T) -> T {
64+
let span = match traits.get(0) {
65+
Some(&(_, span)) => span,
66+
None => return item,
67+
};
68+
69+
item.map_attrs(|mut attrs| {
70+
if traits.iter().any(|&(name, _)| name == "PartialEq") &&
71+
traits.iter().any(|&(name, _)| name == "Eq") {
72+
let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
73+
let meta = cx.meta_word(span, Symbol::intern("structural_match"));
74+
attrs.push(cx.attribute(span, meta));
75+
}
76+
if traits.iter().any(|&(name, _)| name == "Copy") &&
77+
traits.iter().any(|&(name, _)| name == "Clone") {
78+
let span = allow_unstable(cx, span, "derive(Copy, Clone)");
79+
let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
80+
attrs.push(cx.attribute(span, meta));
81+
}
82+
attrs
18383
})
18484
}

0 commit comments

Comments
 (0)