Skip to content

Commit 187d989

Browse files
authored
Auto merge of #37542 - jseyfried:custom_derive_reexports, r=nrc
Support `#[macro_reexport]`ing custom derives This is gated behind `#![feature(macro_reexport)]` and `#![feature(proc_macro)]`. r? @nrc
2 parents ab03f85 + f35eff2 commit 187d989

File tree

16 files changed

+210
-172
lines changed

16 files changed

+210
-172
lines changed

src/librustc/middle/cstore.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use session::Session;
3434
use session::search_paths::PathKind;
3535
use util::nodemap::{NodeSet, DefIdMap};
3636
use std::path::PathBuf;
37+
use std::rc::Rc;
3738
use syntax::ast;
3839
use syntax::attr;
3940
use syntax::ext::base::SyntaxExtension;
@@ -106,6 +107,11 @@ pub enum InlinedItemRef<'a> {
106107
ImplItem(DefId, &'a hir::ImplItem)
107108
}
108109

110+
pub enum LoadedMacro {
111+
MacroRules(ast::MacroDef),
112+
ProcMacro(Rc<SyntaxExtension>),
113+
}
114+
109115
#[derive(Copy, Clone, Debug)]
110116
pub struct ExternCrate {
111117
/// def_id of an `extern crate` in the current crate that caused
@@ -211,7 +217,7 @@ pub trait CrateStore<'tcx> {
211217
fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath>;
212218
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
213219
fn item_children(&self, did: DefId) -> Vec<def::Export>;
214-
fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef;
220+
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
215221

216222
// misc. metadata
217223
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -383,7 +389,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
383389
}
384390
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { bug!("struct_field_names") }
385391
fn item_children(&self, did: DefId) -> Vec<def::Export> { bug!("item_children") }
386-
fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef { bug!("load_macro") }
392+
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
387393

388394
// misc. metadata
389395
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -424,7 +430,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
424430
}
425431

426432
pub trait CrateLoader {
427-
fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool)
428-
-> Vec<(ast::Name, SyntaxExtension)>;
433+
fn process_item(&mut self, item: &ast::Item, defs: &Definitions);
429434
fn postprocess(&mut self, krate: &ast::Crate);
430435
}

src/librustc_metadata/creader.rs

+57-79
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ use syntax::ast;
3535
use syntax::abi::Abi;
3636
use syntax::attr;
3737
use syntax::ext::base::SyntaxExtension;
38-
use syntax::feature_gate::{self, emit_feature_err};
3938
use syntax::parse::token::{InternedString, intern};
4039
use syntax_pos::{Span, DUMMY_SP};
4140
use log;
@@ -285,15 +284,13 @@ impl<'a> CrateLoader<'a> {
285284

286285
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
287286

288-
if crate_root.macro_derive_registrar.is_some() {
289-
self.sess.span_err(span, "crates of the `proc-macro` crate type \
290-
cannot be linked at runtime");
291-
}
292-
293287
let cmeta = Rc::new(cstore::CrateMetadata {
294288
name: name.to_string(),
295289
extern_crate: Cell::new(None),
296290
key_map: metadata.load_key_map(crate_root.index),
291+
proc_macros: crate_root.macro_derive_registrar.map(|_| {
292+
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
293+
}),
297294
root: crate_root,
298295
blob: metadata,
299296
cnum_map: RefCell::new(cnum_map),
@@ -317,34 +314,48 @@ impl<'a> CrateLoader<'a> {
317314
hash: Option<&Svh>,
318315
span: Span,
319316
kind: PathKind,
320-
dep_kind: DepKind)
317+
mut dep_kind: DepKind)
321318
-> (CrateNum, Rc<cstore::CrateMetadata>) {
322319
info!("resolving crate `extern crate {} as {}`", name, ident);
323-
let result = match self.existing_match(name, hash, kind) {
324-
Some(cnum) => LoadResult::Previous(cnum),
325-
None => {
326-
info!("falling back to a load");
327-
let mut locate_ctxt = locator::Context {
328-
sess: self.sess,
329-
span: span,
330-
ident: ident,
331-
crate_name: name,
332-
hash: hash.map(|a| &*a),
333-
filesearch: self.sess.target_filesearch(kind),
334-
target: &self.sess.target.target,
335-
triple: &self.sess.opts.target_triple,
336-
root: root,
320+
let result = if let Some(cnum) = self.existing_match(name, hash, kind) {
321+
LoadResult::Previous(cnum)
322+
} else {
323+
info!("falling back to a load");
324+
let mut locate_ctxt = locator::Context {
325+
sess: self.sess,
326+
span: span,
327+
ident: ident,
328+
crate_name: name,
329+
hash: hash.map(|a| &*a),
330+
filesearch: self.sess.target_filesearch(kind),
331+
target: &self.sess.target.target,
332+
triple: &self.sess.opts.target_triple,
333+
root: root,
334+
rejected_via_hash: vec![],
335+
rejected_via_triple: vec![],
336+
rejected_via_kind: vec![],
337+
rejected_via_version: vec![],
338+
should_match_name: true,
339+
is_proc_macro: Some(false),
340+
};
341+
342+
self.load(&mut locate_ctxt).or_else(|| {
343+
dep_kind = DepKind::MacrosOnly;
344+
345+
let mut proc_macro_locator = locator::Context {
346+
target: &self.sess.host,
347+
triple: config::host_triple(),
348+
filesearch: self.sess.host_filesearch(PathKind::Crate),
337349
rejected_via_hash: vec![],
338350
rejected_via_triple: vec![],
339351
rejected_via_kind: vec![],
340352
rejected_via_version: vec![],
341-
should_match_name: true,
353+
is_proc_macro: Some(true),
354+
..locate_ctxt
342355
};
343-
match self.load(&mut locate_ctxt) {
344-
Some(result) => result,
345-
None => locate_ctxt.report_errs(),
346-
}
347-
}
356+
357+
self.load(&mut proc_macro_locator)
358+
}).unwrap_or_else(|| locate_ctxt.report_errs())
348359
};
349360

350361
match result {
@@ -431,6 +442,10 @@ impl<'a> CrateLoader<'a> {
431442
dep_kind: DepKind)
432443
-> cstore::CrateNumMap {
433444
debug!("resolving deps of external crate");
445+
if crate_root.macro_derive_registrar.is_some() {
446+
return cstore::CrateNumMap::new();
447+
}
448+
434449
// The map from crate numbers in the crate we're resolving to local crate
435450
// numbers
436451
let deps = crate_root.crate_deps.decode(metadata);
@@ -479,6 +494,7 @@ impl<'a> CrateLoader<'a> {
479494
rejected_via_kind: vec![],
480495
rejected_via_version: vec![],
481496
should_match_name: true,
497+
is_proc_macro: None,
482498
};
483499
let library = self.load(&mut locate_ctxt).or_else(|| {
484500
if !is_cross {
@@ -525,51 +541,36 @@ impl<'a> CrateLoader<'a> {
525541
/// implemented as dynamic libraries, but we have a possible future where
526542
/// custom derive (and other macro-1.1 style features) are implemented via
527543
/// executables and custom IPC.
528-
fn load_derive_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate)
529-
-> Option<Vec<(ast::Name, SyntaxExtension)>> {
544+
fn load_derive_macros(&mut self, root: &CrateRoot, dylib: Option<PathBuf>, span: Span)
545+
-> Vec<(ast::Name, Rc<SyntaxExtension>)> {
530546
use std::{env, mem};
531547
use proc_macro::TokenStream;
532548
use proc_macro::__internal::Registry;
533549
use rustc_back::dynamic_lib::DynamicLibrary;
534550
use syntax_ext::deriving::custom::CustomDerive;
535551

536-
let root = ekrate.metadata.get_root();
537-
let index = match root.macro_derive_registrar {
538-
Some(index) => index,
539-
None => return None,
540-
};
541-
if !self.sess.features.borrow().proc_macro {
542-
let issue = feature_gate::GateIssue::Language;
543-
let msg = "loading custom derive macro crates is experimentally supported";
544-
emit_feature_err(&self.sess.parse_sess, "proc_macro", item.span, issue, msg);
545-
}
546-
547-
if ekrate.target_only {
548-
let msg = format!("proc-macro crate is not available for triple `{}` (only found {})",
549-
config::host_triple(), self.sess.opts.target_triple);
550-
self.sess.span_fatal(item.span, &msg);
551-
}
552-
let path = match ekrate.dylib.clone() {
552+
let path = match dylib {
553553
Some(dylib) => dylib,
554-
None => span_bug!(item.span, "proc-macro crate not dylib"),
554+
None => span_bug!(span, "proc-macro crate not dylib"),
555555
};
556556
// Make sure the path contains a / or the linker will search for it.
557557
let path = env::current_dir().unwrap().join(path);
558558
let lib = match DynamicLibrary::open(Some(&path)) {
559559
Ok(lib) => lib,
560-
Err(err) => self.sess.span_fatal(item.span, &err),
560+
Err(err) => self.sess.span_fatal(span, &err),
561561
};
562562

563-
let sym = self.sess.generate_derive_registrar_symbol(&root.hash, index);
563+
let sym = self.sess.generate_derive_registrar_symbol(&root.hash,
564+
root.macro_derive_registrar.unwrap());
564565
let registrar = unsafe {
565566
let sym = match lib.symbol(&sym) {
566567
Ok(f) => f,
567-
Err(err) => self.sess.span_fatal(item.span, &err),
568+
Err(err) => self.sess.span_fatal(span, &err),
568569
};
569570
mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
570571
};
571572

572-
struct MyRegistrar(Vec<(ast::Name, SyntaxExtension)>);
573+
struct MyRegistrar(Vec<(ast::Name, Rc<SyntaxExtension>)>);
573574

574575
impl Registry for MyRegistrar {
575576
fn register_custom_derive(&mut self,
@@ -580,7 +581,7 @@ impl<'a> CrateLoader<'a> {
580581
let derive = SyntaxExtension::CustomDerive(
581582
Box::new(CustomDerive::new(expand, attrs))
582583
);
583-
self.0.push((intern(trait_name), derive));
584+
self.0.push((intern(trait_name), Rc::new(derive)));
584585
}
585586
}
586587

@@ -590,7 +591,7 @@ impl<'a> CrateLoader<'a> {
590591
// Intentionally leak the dynamic library. We can't ever unload it
591592
// since the library can make things that will live arbitrarily long.
592593
mem::forget(lib);
593-
Some(my_registrar.0)
594+
my_registrar.0
594595
}
595596

596597
/// Look for a plugin registrar. Returns library path, crate
@@ -928,35 +929,14 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
928929
self.register_statically_included_foreign_items();
929930
}
930931

931-
fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool)
932-
-> Vec<(ast::Name, SyntaxExtension)> {
932+
fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) {
933933
match item.node {
934934
ast::ItemKind::ExternCrate(_) => {}
935-
ast::ItemKind::ForeignMod(ref fm) => {
936-
self.process_foreign_mod(item, fm);
937-
return Vec::new();
938-
}
939-
_ => return Vec::new(),
935+
ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm),
936+
_ => return,
940937
}
941938

942939
let info = self.extract_crate_info(item).unwrap();
943-
if load_macros {
944-
let ekrate = self.read_extension_crate(item.span, &info);
945-
946-
// If this is a proc-macro crate, return here to avoid registering.
947-
if let Some(custom_derives) = self.load_derive_macros(item, &ekrate) {
948-
return custom_derives;
949-
}
950-
951-
// Register crate now to avoid double-reading metadata
952-
if let PMDSource::Owned(lib) = ekrate.metadata {
953-
if ekrate.target_only || config::host_triple() == self.sess.opts.target_triple {
954-
let ExternCrateInfo { ref ident, ref name, dep_kind, .. } = info;
955-
self.register_crate(&None, ident, name, item.span, lib, dep_kind);
956-
}
957-
}
958-
}
959-
960940
let (cnum, ..) = self.resolve_crate(
961941
&None, &info.ident, &info.name, None, item.span, PathKind::Crate, info.dep_kind,
962942
);
@@ -968,7 +948,5 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
968948
ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
969949
self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
970950
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
971-
972-
Vec::new()
973951
}
974952
}

src/librustc_metadata/cstore.rs

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use std::rc::Rc;
2828
use std::path::PathBuf;
2929
use flate::Bytes;
3030
use syntax::{ast, attr};
31+
use syntax::ext::base::SyntaxExtension;
3132
use syntax_pos;
3233

3334
pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
@@ -80,6 +81,8 @@ pub struct CrateMetadata {
8081

8182
pub dep_kind: Cell<DepKind>,
8283
pub source: CrateSource,
84+
85+
pub proc_macros: Option<Vec<(ast::Name, Rc<SyntaxExtension>)>>,
8386
}
8487

8588
pub struct CachedInlinedItem {

src/librustc_metadata/cstore_impl.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use locator;
1414
use schema;
1515

1616
use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate};
17-
use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
17+
use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference, LoadedMacro};
1818
use rustc::hir::def::{self, Def};
1919
use rustc::middle::lang_items;
2020
use rustc::session::Session;
@@ -353,8 +353,13 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
353353
result
354354
}
355355

356-
fn load_macro(&self, id: DefId, sess: &Session) -> ast::MacroDef {
357-
let (name, def) = self.get_crate_data(id.krate).get_macro(id.index);
356+
fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro {
357+
let data = self.get_crate_data(id.krate);
358+
if let Some(ref proc_macros) = data.proc_macros {
359+
return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize()].1.clone());
360+
}
361+
362+
let (name, def) = data.get_macro(id.index);
358363
let source_name = format!("<{} macros>", name);
359364

360365
// NB: Don't use parse_tts_from_source_str because it parses with quote_depth > 0.
@@ -379,15 +384,15 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
379384
sess.imported_macro_spans.borrow_mut()
380385
.insert(local_span, (def.name.as_str().to_string(), def.span));
381386

382-
ast::MacroDef {
387+
LoadedMacro::MacroRules(ast::MacroDef {
383388
ident: ast::Ident::with_empty_ctxt(def.name),
384389
id: ast::DUMMY_NODE_ID,
385390
span: local_span,
386391
imported_from: None, // FIXME
387392
allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"),
388393
attrs: def.attrs,
389394
body: body,
390-
}
395+
})
391396
}
392397

393398
fn maybe_get_item_ast<'a>(&'tcx self,

src/librustc_metadata/decoder.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,15 @@ impl<'a, 'tcx> CrateMetadata {
691691
pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
692692
where F: FnMut(def::Export)
693693
{
694-
let macros_only = self.dep_kind.get() == DepKind::MacrosOnly;
694+
if let Some(ref proc_macros) = self.proc_macros {
695+
for (id, &(name, _)) in proc_macros.iter().enumerate() {
696+
callback(def::Export {
697+
name: name,
698+
def: Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id), }),
699+
})
700+
}
701+
return
702+
}
695703

696704
// Find the item.
697705
let item = match self.maybe_entry(id) {
@@ -700,6 +708,7 @@ impl<'a, 'tcx> CrateMetadata {
700708
};
701709

702710
// Iterate over all children.
711+
let macros_only = self.dep_kind.get() == DepKind::MacrosOnly;
703712
for child_index in item.children.decode(self) {
704713
if macros_only {
705714
continue

src/librustc_metadata/locator.rs

+7
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ pub struct Context<'a> {
262262
pub rejected_via_kind: Vec<CrateMismatch>,
263263
pub rejected_via_version: Vec<CrateMismatch>,
264264
pub should_match_name: bool,
265+
pub is_proc_macro: Option<bool>,
265266
}
266267

267268
pub struct ArchiveMetadata {
@@ -623,6 +624,12 @@ impl<'a> Context<'a> {
623624

624625
fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
625626
let root = metadata.get_root();
627+
if let Some(is_proc_macro) = self.is_proc_macro {
628+
if root.macro_derive_registrar.is_some() != is_proc_macro {
629+
return None;
630+
}
631+
}
632+
626633
let rustc_version = rustc_version();
627634
if root.rustc_version != rustc_version {
628635
info!("Rejecting via version: expected {} got {}",

0 commit comments

Comments
 (0)