Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macros 1.1: future proofing and cleanup #37198

Merged
merged 3 commits into from
Oct 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/librustc/middle/cstore.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
57 changes: 32 additions & 25 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
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 All @@ -238,6 +250,12 @@ impl<'b> Resolver<'b> {
self.define(parent, name, TypeNS, (module, sp, vis));

self.populate_module_if_necessary(module);
} else if custom_derive_crate {
// Define an empty module
let def = Def::Mod(self.definitions.local_def_id(item.id));
let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name));
let module = self.arenas.alloc_module(module);
self.define(parent, name, TypeNS, (module, sp, vis));
}
}

Expand Down Expand Up @@ -504,17 +522,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
Original file line number Diff line number Diff line change
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
32 changes: 10 additions & 22 deletions src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ 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, Invocation, InvocationKind};
use syntax::ext::expand::Expansion;
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::parse::token::intern;
Expand Down Expand Up @@ -162,30 +162,22 @@ impl<'a> base::Resolver for Resolver<'a> {
None
}

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

let invocation = self.invocations[&scope];
if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
}
self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| {
if force {
let mut err =
self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
let msg = format!("macro undefined: '{}!'", name);
let mut err = self.session.struct_span_err(path.span, &msg);
self.suggest_macro_name(&name.as_str(), &mut err);
err.emit();
Determinacy::Determined
Expand All @@ -194,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
10 changes: 5 additions & 5 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use attr::HasAttrs;
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
use errors::DiagnosticBuilder;
use ext::expand::{self, Invocation, Expansion};
use ext::expand::{self, Expansion};
use ext::hygiene::Mark;
use fold::{self, Folder};
use parse::{self, parser};
Expand Down 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 @@ -522,9 +524,8 @@ pub trait Resolver {
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>;
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
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,8 +546,7 @@ 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_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool)
fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy> {
Err(Determinacy::Determined)
}
Expand Down
27 changes: 25 additions & 2 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {

let scope =
if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) {
let resolution = match invoc.kind {
InvocationKind::Bang { ref mac, .. } => {
self.cx.resolver.resolve_macro(scope, &mac.node.path, force)
}
InvocationKind::Attr { ref attr, .. } => {
let ident = ast::Ident::with_empty_ctxt(intern(&*attr.name()));
let path = ast::Path::from_ident(attr.span, ident);
self.cx.resolver.resolve_macro(scope, &path, force)
}
};
let ext = match resolution {
Ok(ext) => Some(ext),
Err(Determinacy::Determined) => None,
Err(Determinacy::Undetermined) => {
Expand Down Expand Up @@ -354,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 @@ -429,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
Original file line number Diff line number Diff line change
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
25 changes: 0 additions & 25 deletions src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-2.rs

This file was deleted.

3 changes: 1 addition & 2 deletions src/test/compile-fail-fulldeps/proc-macro/shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@
// except according to those terms.

// aux-build:derive-a.rs
// aux-build:derive-a-2.rs

#![feature(proc_macro)]

#[macro_use]
extern crate derive_a;
#[macro_use]
extern crate derive_a_2; //~ ERROR: cannot shadow existing derive mode `A`
extern crate derive_a; //~ ERROR `derive_a` has already been defined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm isn't this testing something else than before? Before it was preventing two #[proc_macro_derive(A)] was an error, but here it's erroring out on the extern crate annotations?

Copy link
Contributor Author

@jseyfried jseyfried Oct 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it used to test that a #[macro_use]-imported custom derive cannot shadow an existing #[macro_use]-imported custom derive.

This PR changes #[macro_use]-imported custom derives to have the same scope and shadowing restrictions as other #[macro_use]-imported macros, so it is no longer an error for an unexpanded #[macro_use] to import a shadowing custom derive (just as it is not an error today for ordinary unexpanded #[macro_use]s to shadow).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(c.f. the second bullet point in the initial comment)


fn main() {}