Skip to content

Commit

Permalink
Use the macro namespace for custom derives.
Browse files Browse the repository at this point in the history
  • Loading branch information
jseyfried committed Oct 15, 2016
1 parent d902963 commit 33e3da8
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 47 deletions.
3 changes: 1 addition & 2 deletions src/librustc/middle/cstore.rs
Expand Up @@ -35,7 +35,6 @@ use session::Session;
use session::search_paths::PathKind;
use util::nodemap::{NodeSet, DefIdMap};
use std::path::PathBuf;
use std::rc::Rc;
use syntax::ast;
use syntax::attr;
use syntax::ext::base::MultiItemModifier;
Expand Down Expand Up @@ -425,7 +424,7 @@ pub struct LoadedMacro {

pub enum LoadedMacroKind {
Def(ast::MacroDef),
CustomDerive(String, Rc<MultiItemModifier>),
CustomDerive(String, Box<MultiItemModifier>),
}

pub trait CrateLoader {
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_metadata/macro_import.rs
Expand Up @@ -11,7 +11,6 @@
//! Used by `rustc` when loading a crate with exported macros.

use std::collections::HashSet;
use std::rc::Rc;
use std::env;
use std::mem;

Expand Down Expand Up @@ -212,7 +211,7 @@ impl<'a> CrateLoader<'a> {
fn register_custom_derive(&mut self,
trait_name: &str,
expand: fn(TokenStream) -> TokenStream) {
let derive = Rc::new(CustomDerive::new(expand));
let derive = Box::new(CustomDerive::new(expand));
self.0.push(LoadedMacro {
kind: LoadedMacroKind::CustomDerive(trait_name.to_string(), derive),
import_site: self.1,
Expand Down
51 changes: 26 additions & 25 deletions src/librustc_resolve/build_reduced_graph.rs
Expand Up @@ -36,7 +36,7 @@ use syntax::parse::token;
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind};
use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind};
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::ext::base::{MultiItemModifier, Resolver as SyntaxResolver};
use syntax::ext::base::{SyntaxExtension, Resolver as SyntaxResolver};
use syntax::ext::hygiene::Mark;
use syntax::feature_gate::{self, emit_feature_err};
use syntax::ext::tt::macro_rules;
Expand Down Expand Up @@ -195,33 +195,45 @@ impl<'b> Resolver<'b> {
// We need to error on `#[macro_use] extern crate` when it isn't at the
// crate root, because `$crate` won't work properly.
let is_crate_root = self.current_module.parent.is_none();
let import_macro = |this: &mut Self, name, ext, span| {
let shadowing = this.builtin_macros.insert(name, Rc::new(ext)).is_some();
if shadowing && expansion != Mark::root() {
let msg = format!("`{}` is already in scope", name);
this.session.struct_span_err(span, &msg)
.note("macro-expanded `#[macro_use]`s may not shadow \
existing macros (see RFC 1560)")
.emit();
}
};

let mut custom_derive_crate = false;
for loaded_macro in self.crate_loader.load_macros(item, is_crate_root) {
match loaded_macro.kind {
LoadedMacroKind::Def(mut def) => {
let name = def.ident.name;
if def.use_locally {
let ext =
Rc::new(macro_rules::compile(&self.session.parse_sess, &def));
if self.builtin_macros.insert(name, ext).is_some() &&
expansion != Mark::root() {
let msg = format!("`{}` is already in scope", name);
self.session.struct_span_err(loaded_macro.import_site, &msg)
.note("macro-expanded `#[macro_use]`s may not shadow \
existing macros (see RFC 1560)")
.emit();
}
self.macro_names.insert(name);
self.macro_names.insert(def.ident.name);
let ext = macro_rules::compile(&self.session.parse_sess, &def);
import_macro(self, def.ident.name, ext, loaded_macro.import_site);
}
if def.export {
def.id = self.next_node_id();
self.exported_macros.push(def);
}
}
LoadedMacroKind::CustomDerive(name, ext) => {
self.insert_custom_derive(&name, ext, item.span);
custom_derive_crate = true;
let ext = SyntaxExtension::CustomDerive(ext);
import_macro(self, token::intern(&name), ext, loaded_macro.import_site);
}
}
}

if custom_derive_crate && !self.session.features.borrow().proc_macro {
let issue = feature_gate::GateIssue::Language;
let msg = "loading custom derive macro crates is experimentally supported";
emit_feature_err(&self.session.parse_sess, "proc_macro", item.span, issue, msg);
}

self.crate_loader.process_item(item, &self.definitions);

// n.b. we don't need to look at the path option here, because cstore already did
Expand Down Expand Up @@ -504,17 +516,6 @@ impl<'b> Resolver<'b> {

false
}

fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
if !self.session.features.borrow().proc_macro {
let sess = &self.session.parse_sess;
let msg = "loading custom derive macro crates is experimentally supported";
emit_feature_err(sess, "proc_macro", sp, feature_gate::GateIssue::Language, msg);
}
if self.derive_modes.insert(token::intern(name), ext).is_some() {
self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
}
}
}

pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
Expand Down
3 changes: 0 additions & 3 deletions src/librustc_resolve/lib.rs
Expand Up @@ -53,7 +53,6 @@ use rustc::ty;
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};

use syntax::ext::base::MultiItemModifier;
use syntax::ext::hygiene::Mark;
use syntax::ast::{self, FloatTy};
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy};
Expand Down Expand Up @@ -1080,7 +1079,6 @@ pub struct Resolver<'a> {
new_import_semantics: bool, // true if `#![feature(item_like_imports)]`

pub exported_macros: Vec<ast::MacroDef>,
pub derive_modes: FnvHashMap<Name, Rc<MultiItemModifier>>,
crate_loader: &'a mut CrateLoader,
macro_names: FnvHashSet<Name>,
builtin_macros: FnvHashMap<Name, Rc<SyntaxExtension>>,
Expand Down Expand Up @@ -1271,7 +1269,6 @@ impl<'a> Resolver<'a> {
new_import_semantics: session.features.borrow().item_like_imports,

exported_macros: Vec::new(),
derive_modes: FnvHashMap(),
crate_loader: crate_loader,
macro_names: FnvHashSet(),
builtin_macros: FnvHashMap(),
Expand Down
6 changes: 1 addition & 5 deletions src/librustc_resolve/macros.rs
Expand Up @@ -17,7 +17,7 @@ use std::cell::Cell;
use std::rc::Rc;
use syntax::ast;
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier};
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
use syntax::ext::base::{NormalTT, SyntaxExtension};
use syntax::ext::expand::Expansion;
use syntax::ext::hygiene::Mark;
Expand Down Expand Up @@ -186,10 +186,6 @@ impl<'a> base::Resolver for Resolver<'a> {
}
})
}

fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>> {
self.derive_modes.get(&ident.name).cloned()
}
}

impl<'a> Resolver<'a> {
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/ext/base.rs
Expand Up @@ -508,6 +508,8 @@ pub enum SyntaxExtension {
/// the block.
///
IdentTT(Box<IdentMacroExpander>, Option<Span>, bool),

CustomDerive(Box<MultiItemModifier>),
}

pub type NamedSyntaxExtension = (Name, SyntaxExtension);
Expand All @@ -524,7 +526,6 @@ pub trait Resolver {
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy>;
fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>>;
}

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

fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option<Rc<MultiItemModifier>> { None }
fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy> {
Err(Determinacy::Determined)
Expand Down
15 changes: 14 additions & 1 deletion src/libsyntax/ext/expand.rs
Expand Up @@ -364,7 +364,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
self.parse_expansion(tok_result, kind, name, attr.span)
}
_ => unreachable!(),
SyntaxExtension::CustomDerive(_) => {
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name));
kind.dummy(attr.span)
}
_ => {
let msg = &format!("macro `{}` may not be used in attributes", name);
self.cx.span_err(attr.span, &msg);
kind.dummy(attr.span)
}
}
}

Expand Down Expand Up @@ -439,6 +447,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
return kind.dummy(span);
}

SyntaxExtension::CustomDerive(..) => {
self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname));
return kind.dummy(span);
}

SyntaxExtension::ProcMacro(ref expandfun) => {
if ident.name != keywords::Invalid.name() {
let msg =
Expand Down
24 changes: 17 additions & 7 deletions src/libsyntax_ext/deriving/mod.rs
Expand Up @@ -12,7 +12,7 @@

use syntax::ast::{self, MetaItem};
use syntax::attr::HasAttrs;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap;
Expand Down Expand Up @@ -158,10 +158,14 @@ pub fn expand_derive(cx: &mut ExtCtxt,
let tword = titem.word().unwrap();
let tname = tword.name();

let derive_mode = ast::Ident::with_empty_ctxt(intern(&tname));
let derive_mode = cx.resolver.resolve_derive_mode(derive_mode);
if is_builtin_trait(&tname) || derive_mode.is_some() {
return true
if is_builtin_trait(&tname) || {
let derive_mode =
ast::Path::from_ident(titem.span, ast::Ident::with_empty_ctxt(intern(&tname)));
cx.resolver.resolve_macro(cx.current_expansion.mark, &derive_mode, false).map(|ext| {
if let SyntaxExtension::CustomDerive(_) = *ext { true } else { false }
}).unwrap_or(false)
} {
return true;
}

if !cx.ecfg.enable_custom_derive() {
Expand Down Expand Up @@ -216,7 +220,9 @@ pub fn expand_derive(cx: &mut ExtCtxt,
.next();
if let Some((i, titem)) = macros_11_derive {
let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap()));
let ext = cx.resolver.resolve_derive_mode(tname).unwrap();
let path = ast::Path::from_ident(titem.span, tname);
let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();

traits.remove(i);
if traits.len() > 0 {
item = item.map(|mut i| {
Expand All @@ -232,7 +238,11 @@ pub fn expand_derive(cx: &mut ExtCtxt,
intern_and_get_ident("derive"),
vec![titem]);
let item = Annotatable::Item(item);
return ext.expand(cx, mitem.span, &mitem, item)
if let SyntaxExtension::CustomDerive(ref ext) = *ext {
return ext.expand(cx, mitem.span, &mitem, item);
} else {
unreachable!()
}
}

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

0 comments on commit 33e3da8

Please sign in to comment.