Skip to content

Commit a979c01

Browse files
authored
Rollup merge of rust-lang#37198 - jseyfried:future_proof_macros_11, r=nrc
macros 1.1: future proofing and cleanup This PR - uses the macro namespace for custom derives (instead of a dedicated custom derive namespace), - relaxes the shadowing rules for `#[macro_use]`-imported custom derives to match the shadowing rules for ordinary `#[macro_use]`-imported macros, and - treats custom derive `extern crate`s like empty modules so that we can eventually allow, for example, `extern crate serde_derive; use serde_derive::Serialize;` backwards compatibly. r? @alexcrichton
2 parents 46de940 + aac6dca commit a979c01

File tree

10 files changed

+92
-95
lines changed

10 files changed

+92
-95
lines changed

src/librustc/middle/cstore.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ use session::Session;
3535
use session::search_paths::PathKind;
3636
use util::nodemap::{NodeSet, DefIdMap};
3737
use std::path::PathBuf;
38-
use std::rc::Rc;
3938
use syntax::ast;
4039
use syntax::attr;
4140
use syntax::ext::base::MultiItemModifier;
@@ -425,7 +424,7 @@ pub struct LoadedMacro {
425424

426425
pub enum LoadedMacroKind {
427426
Def(ast::MacroDef),
428-
CustomDerive(String, Rc<MultiItemModifier>),
427+
CustomDerive(String, Box<MultiItemModifier>),
429428
}
430429

431430
pub trait CrateLoader {

src/librustc_metadata/macro_import.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//! Used by `rustc` when loading a crate with exported macros.
1212
1313
use std::collections::HashSet;
14-
use std::rc::Rc;
1514
use std::env;
1615
use std::mem;
1716

@@ -212,7 +211,7 @@ impl<'a> CrateLoader<'a> {
212211
fn register_custom_derive(&mut self,
213212
trait_name: &str,
214213
expand: fn(TokenStream) -> TokenStream) {
215-
let derive = Rc::new(CustomDerive::new(expand));
214+
let derive = Box::new(CustomDerive::new(expand));
216215
self.0.push(LoadedMacro {
217216
kind: LoadedMacroKind::CustomDerive(trait_name.to_string(), derive),
218217
import_site: self.1,

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use syntax::parse::token;
3636
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind};
3737
use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind};
3838
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
39-
use syntax::ext::base::{MultiItemModifier, Resolver as SyntaxResolver};
39+
use syntax::ext::base::{SyntaxExtension, Resolver as SyntaxResolver};
4040
use syntax::ext::hygiene::Mark;
4141
use syntax::feature_gate::{self, emit_feature_err};
4242
use syntax::ext::tt::macro_rules;
@@ -195,33 +195,45 @@ impl<'b> Resolver<'b> {
195195
// We need to error on `#[macro_use] extern crate` when it isn't at the
196196
// crate root, because `$crate` won't work properly.
197197
let is_crate_root = self.current_module.parent.is_none();
198+
let import_macro = |this: &mut Self, name, ext, span| {
199+
let shadowing = this.builtin_macros.insert(name, Rc::new(ext)).is_some();
200+
if shadowing && expansion != Mark::root() {
201+
let msg = format!("`{}` is already in scope", name);
202+
this.session.struct_span_err(span, &msg)
203+
.note("macro-expanded `#[macro_use]`s may not shadow \
204+
existing macros (see RFC 1560)")
205+
.emit();
206+
}
207+
};
208+
209+
let mut custom_derive_crate = false;
198210
for loaded_macro in self.crate_loader.load_macros(item, is_crate_root) {
199211
match loaded_macro.kind {
200212
LoadedMacroKind::Def(mut def) => {
201-
let name = def.ident.name;
202213
if def.use_locally {
203-
let ext =
204-
Rc::new(macro_rules::compile(&self.session.parse_sess, &def));
205-
if self.builtin_macros.insert(name, ext).is_some() &&
206-
expansion != Mark::root() {
207-
let msg = format!("`{}` is already in scope", name);
208-
self.session.struct_span_err(loaded_macro.import_site, &msg)
209-
.note("macro-expanded `#[macro_use]`s may not shadow \
210-
existing macros (see RFC 1560)")
211-
.emit();
212-
}
213-
self.macro_names.insert(name);
214+
self.macro_names.insert(def.ident.name);
215+
let ext = macro_rules::compile(&self.session.parse_sess, &def);
216+
import_macro(self, def.ident.name, ext, loaded_macro.import_site);
214217
}
215218
if def.export {
216219
def.id = self.next_node_id();
217220
self.exported_macros.push(def);
218221
}
219222
}
220223
LoadedMacroKind::CustomDerive(name, ext) => {
221-
self.insert_custom_derive(&name, ext, item.span);
224+
custom_derive_crate = true;
225+
let ext = SyntaxExtension::CustomDerive(ext);
226+
import_macro(self, token::intern(&name), ext, loaded_macro.import_site);
222227
}
223228
}
224229
}
230+
231+
if custom_derive_crate && !self.session.features.borrow().proc_macro {
232+
let issue = feature_gate::GateIssue::Language;
233+
let msg = "loading custom derive macro crates is experimentally supported";
234+
emit_feature_err(&self.session.parse_sess, "proc_macro", item.span, issue, msg);
235+
}
236+
225237
self.crate_loader.process_item(item, &self.definitions);
226238

227239
// n.b. we don't need to look at the path option here, because cstore already did
@@ -238,6 +250,12 @@ impl<'b> Resolver<'b> {
238250
self.define(parent, name, TypeNS, (module, sp, vis));
239251

240252
self.populate_module_if_necessary(module);
253+
} else if custom_derive_crate {
254+
// Define an empty module
255+
let def = Def::Mod(self.definitions.local_def_id(item.id));
256+
let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name));
257+
let module = self.arenas.alloc_module(module);
258+
self.define(parent, name, TypeNS, (module, sp, vis));
241259
}
242260
}
243261

@@ -504,17 +522,6 @@ impl<'b> Resolver<'b> {
504522

505523
false
506524
}
507-
508-
fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
509-
if !self.session.features.borrow().proc_macro {
510-
let sess = &self.session.parse_sess;
511-
let msg = "loading custom derive macro crates is experimentally supported";
512-
emit_feature_err(sess, "proc_macro", sp, feature_gate::GateIssue::Language, msg);
513-
}
514-
if self.derive_modes.insert(token::intern(name), ext).is_some() {
515-
self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
516-
}
517-
}
518525
}
519526

520527
pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {

src/librustc_resolve/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ use rustc::ty;
5353
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
5454
use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
5555

56-
use syntax::ext::base::MultiItemModifier;
5756
use syntax::ext::hygiene::Mark;
5857
use syntax::ast::{self, FloatTy};
5958
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy};
@@ -1082,7 +1081,6 @@ pub struct Resolver<'a> {
10821081
new_import_semantics: bool, // true if `#![feature(item_like_imports)]`
10831082

10841083
pub exported_macros: Vec<ast::MacroDef>,
1085-
pub derive_modes: FnvHashMap<Name, Rc<MultiItemModifier>>,
10861084
crate_loader: &'a mut CrateLoader,
10871085
macro_names: FnvHashSet<Name>,
10881086
builtin_macros: FnvHashMap<Name, Rc<SyntaxExtension>>,
@@ -1273,7 +1271,6 @@ impl<'a> Resolver<'a> {
12731271
new_import_semantics: session.features.borrow().item_like_imports,
12741272

12751273
exported_macros: Vec::new(),
1276-
derive_modes: FnvHashMap(),
12771274
crate_loader: crate_loader,
12781275
macro_names: FnvHashSet(),
12791276
builtin_macros: FnvHashMap(),

src/librustc_resolve/macros.rs

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use std::cell::Cell;
1717
use std::rc::Rc;
1818
use syntax::ast;
1919
use syntax::errors::DiagnosticBuilder;
20-
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier};
20+
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
2121
use syntax::ext::base::{NormalTT, SyntaxExtension};
22-
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
22+
use syntax::ext::expand::Expansion;
2323
use syntax::ext::hygiene::Mark;
2424
use syntax::ext::tt::macro_rules;
2525
use syntax::parse::token::intern;
@@ -162,30 +162,22 @@ impl<'a> base::Resolver for Resolver<'a> {
162162
None
163163
}
164164

165-
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
165+
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
166166
-> Result<Rc<SyntaxExtension>, Determinacy> {
167-
let (name, span) = match invoc.kind {
168-
InvocationKind::Bang { ref mac, .. } => {
169-
let path = &mac.node.path;
170-
if path.segments.len() > 1 || path.global ||
171-
!path.segments[0].parameters.is_empty() {
172-
self.session.span_err(path.span,
173-
"expected macro name without module separators");
174-
return Err(Determinacy::Determined);
175-
}
176-
(path.segments[0].identifier.name, path.span)
177-
}
178-
InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
179-
};
167+
if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
168+
self.session.span_err(path.span, "expected macro name without module separators");
169+
return Err(Determinacy::Determined);
170+
}
171+
let name = path.segments[0].identifier.name;
180172

181173
let invocation = self.invocations[&scope];
182174
if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
183175
invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
184176
}
185177
self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| {
186178
if force {
187-
let mut err =
188-
self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
179+
let msg = format!("macro undefined: '{}!'", name);
180+
let mut err = self.session.struct_span_err(path.span, &msg);
189181
self.suggest_macro_name(&name.as_str(), &mut err);
190182
err.emit();
191183
Determinacy::Determined
@@ -194,10 +186,6 @@ impl<'a> base::Resolver for Resolver<'a> {
194186
}
195187
})
196188
}
197-
198-
fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>> {
199-
self.derive_modes.get(&ident.name).cloned()
200-
}
201189
}
202190

203191
impl<'a> Resolver<'a> {

src/libsyntax/ext/base.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use attr::HasAttrs;
1515
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
1616
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
1717
use errors::DiagnosticBuilder;
18-
use ext::expand::{self, Invocation, Expansion};
18+
use ext::expand::{self, Expansion};
1919
use ext::hygiene::Mark;
2020
use fold::{self, Folder};
2121
use parse::{self, parser};
@@ -508,6 +508,8 @@ pub enum SyntaxExtension {
508508
/// the block.
509509
///
510510
IdentTT(Box<IdentMacroExpander>, Option<Span>, bool),
511+
512+
CustomDerive(Box<MultiItemModifier>),
511513
}
512514

513515
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
@@ -522,9 +524,8 @@ pub trait Resolver {
522524
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
523525

524526
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
525-
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
527+
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
526528
-> Result<Rc<SyntaxExtension>, Determinacy>;
527-
fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>>;
528529
}
529530

530531
#[derive(Copy, Clone, Debug)]
@@ -545,8 +546,7 @@ impl Resolver for DummyResolver {
545546
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
546547

547548
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
548-
fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option<Rc<MultiItemModifier>> { None }
549-
fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool)
549+
fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
550550
-> Result<Rc<SyntaxExtension>, Determinacy> {
551551
Err(Determinacy::Determined)
552552
}

src/libsyntax/ext/expand.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
240240

241241
let scope =
242242
if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
243-
let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) {
243+
let resolution = match invoc.kind {
244+
InvocationKind::Bang { ref mac, .. } => {
245+
self.cx.resolver.resolve_macro(scope, &mac.node.path, force)
246+
}
247+
InvocationKind::Attr { ref attr, .. } => {
248+
let ident = ast::Ident::with_empty_ctxt(intern(&*attr.name()));
249+
let path = ast::Path::from_ident(attr.span, ident);
250+
self.cx.resolver.resolve_macro(scope, &path, force)
251+
}
252+
};
253+
let ext = match resolution {
244254
Ok(ext) => Some(ext),
245255
Err(Determinacy::Determined) => None,
246256
Err(Determinacy::Undetermined) => {
@@ -354,7 +364,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
354364
let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
355365
self.parse_expansion(tok_result, kind, name, attr.span)
356366
}
357-
_ => unreachable!(),
367+
SyntaxExtension::CustomDerive(_) => {
368+
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name));
369+
kind.dummy(attr.span)
370+
}
371+
_ => {
372+
let msg = &format!("macro `{}` may not be used in attributes", name);
373+
self.cx.span_err(attr.span, &msg);
374+
kind.dummy(attr.span)
375+
}
358376
}
359377
}
360378

@@ -429,6 +447,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
429447
return kind.dummy(span);
430448
}
431449

450+
SyntaxExtension::CustomDerive(..) => {
451+
self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname));
452+
return kind.dummy(span);
453+
}
454+
432455
SyntaxExtension::ProcMacro(ref expandfun) => {
433456
if ident.name != keywords::Invalid.name() {
434457
let msg =

src/libsyntax_ext/deriving/mod.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
1313
use syntax::ast::{self, MetaItem};
1414
use syntax::attr::HasAttrs;
15-
use syntax::ext::base::{Annotatable, ExtCtxt};
15+
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
1616
use syntax::ext::build::AstBuilder;
1717
use syntax::feature_gate;
1818
use syntax::codemap;
@@ -158,10 +158,14 @@ pub fn expand_derive(cx: &mut ExtCtxt,
158158
let tword = titem.word().unwrap();
159159
let tname = tword.name();
160160

161-
let derive_mode = ast::Ident::with_empty_ctxt(intern(&tname));
162-
let derive_mode = cx.resolver.resolve_derive_mode(derive_mode);
163-
if is_builtin_trait(&tname) || derive_mode.is_some() {
164-
return true
161+
if is_builtin_trait(&tname) || {
162+
let derive_mode =
163+
ast::Path::from_ident(titem.span, ast::Ident::with_empty_ctxt(intern(&tname)));
164+
cx.resolver.resolve_macro(cx.current_expansion.mark, &derive_mode, false).map(|ext| {
165+
if let SyntaxExtension::CustomDerive(_) = *ext { true } else { false }
166+
}).unwrap_or(false)
167+
} {
168+
return true;
165169
}
166170

167171
if !cx.ecfg.enable_custom_derive() {
@@ -216,7 +220,9 @@ pub fn expand_derive(cx: &mut ExtCtxt,
216220
.next();
217221
if let Some((i, titem)) = macros_11_derive {
218222
let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap()));
219-
let ext = cx.resolver.resolve_derive_mode(tname).unwrap();
223+
let path = ast::Path::from_ident(titem.span, tname);
224+
let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();
225+
220226
traits.remove(i);
221227
if traits.len() > 0 {
222228
item = item.map(|mut i| {
@@ -232,7 +238,11 @@ pub fn expand_derive(cx: &mut ExtCtxt,
232238
intern_and_get_ident("derive"),
233239
vec![titem]);
234240
let item = Annotatable::Item(item);
235-
return ext.expand(cx, mitem.span, &mitem, item)
241+
if let SyntaxExtension::CustomDerive(ref ext) = *ext {
242+
return ext.expand(cx, mitem.span, &mitem, item);
243+
} else {
244+
unreachable!()
245+
}
236246
}
237247

238248
// Ok, at this point we know that there are no old-style `#[derive_Foo]` nor

src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-2.rs

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/test/compile-fail-fulldeps/proc-macro/shadow.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@
99
// except according to those terms.
1010

1111
// aux-build:derive-a.rs
12-
// aux-build:derive-a-2.rs
1312

1413
#![feature(proc_macro)]
1514

1615
#[macro_use]
1716
extern crate derive_a;
1817
#[macro_use]
19-
extern crate derive_a_2; //~ ERROR: cannot shadow existing derive mode `A`
18+
extern crate derive_a; //~ ERROR `derive_a` has already been defined
2019

2120
fn main() {}

0 commit comments

Comments
 (0)