Skip to content

Commit

Permalink
Allow linking to a proc macro on the target in metadata and still use…
Browse files Browse the repository at this point in the history
… a host proc macro to execute them
  • Loading branch information
Zoxc committed Jan 28, 2019
1 parent a21bd75 commit f722699
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 59 deletions.
2 changes: 2 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
Use with RUST_REGION_GRAPH=help for more info"),
parse_only: bool = (false, parse_bool, [UNTRACKED],
"parse only; do not compile, assemble, or link"),
dual_proc_macros: bool = (false, parse_bool, [TRACKED],
"load proc macros for both target and host, but only link to the target"),
no_codegen: bool = (false, parse_bool, [TRACKED],
"run all passes except codegen; no output"),
treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
Expand Down
1 change: 1 addition & 0 deletions src/librustc/session/filesearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub enum FileMatch {

// A module for searching for libraries

#[derive(Clone)]
pub struct FileSearch<'a> {
sysroot: &'a Path,
triple: &'a str,
Expand Down
169 changes: 113 additions & 56 deletions src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,15 @@ impl<'a> CrateLoader<'a> {
});
}

fn register_crate(&mut self,
root: &Option<CratePaths>,
ident: Symbol,
span: Span,
lib: Library,
dep_kind: DepKind)
-> (CrateNum, Lrc<cstore::CrateMetadata>) {
fn register_crate(
&mut self,
host_lib: Option<Library>,
root: &Option<CratePaths>,
ident: Symbol,
span: Span,
lib: Library,
dep_kind: DepKind
) -> (CrateNum, Lrc<cstore::CrateMetadata>) {
let crate_root = lib.metadata.get_root();
info!("register crate `extern crate {} as {}`", crate_root.name, ident);
self.verify_no_symbol_conflicts(span, &crate_root);
Expand Down Expand Up @@ -221,7 +223,16 @@ impl<'a> CrateLoader<'a> {
let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();

let proc_macros = crate_root.proc_macro_decls_static.map(|_| {
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
if self.sess.opts.debugging_opts.dual_proc_macros {
let host_lib = host_lib.unwrap();
self.load_derive_macros(
&host_lib.metadata.get_root(),
host_lib.dylib.clone().map(|p| p.0),
span
)
} else {
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
}
});

let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
Expand Down Expand Up @@ -268,6 +279,61 @@ impl<'a> CrateLoader<'a> {
(cnum, cmeta)
}

fn load_proc_macro<'b> (
&mut self,
locate_ctxt: &mut locator::Context<'b>,
path_kind: PathKind,
) -> Option<(LoadResult, Option<Library>)>
where
'a: 'b
{
// Use a new locator Context so trying to load a proc macro doesn't affect the error
// message we emit
let mut proc_macro_locator = locate_ctxt.clone();

// Try to load a proc macro
proc_macro_locator.is_proc_macro = Some(true);

// Load the proc macro crate for the target
let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros {
proc_macro_locator.reset();
let result = match self.load(&mut proc_macro_locator)? {
LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)),
LoadResult::Loaded(library) => Some(LoadResult::Loaded(library))
};
// Don't look for a matching hash when looking for the host crate.
// It won't be the same as the target crate hash
locate_ctxt.hash = None;
// Use the locate_ctxt when looking for the host proc macro crate, as that is required
// so we want it to affect the error message
(locate_ctxt, result)
} else {
(&mut proc_macro_locator, None)
};

// Load the proc macro crate for the host

locator.reset();
locator.is_proc_macro = Some(true);
locator.target = &self.sess.host;
locator.triple = TargetTriple::from_triple(config::host_triple());
locator.filesearch = self.sess.host_filesearch(path_kind);

let host_result = self.load(locator)?;

Some(if self.sess.opts.debugging_opts.dual_proc_macros {
let host_result = match host_result {
LoadResult::Previous(..) => {
panic!("host and target proc macros must be loaded in lock-step")
}
LoadResult::Loaded(library) => library
};
(target_result.unwrap(), Some(host_result))
} else {
(host_result, None)
})
}

fn resolve_crate<'b>(
&'b mut self,
root: &'b Option<CratePaths>,
Expand All @@ -280,53 +346,39 @@ impl<'a> CrateLoader<'a> {
mut dep_kind: DepKind,
) -> Result<(CrateNum, Lrc<cstore::CrateMetadata>), LoadError<'b>> {
info!("resolving crate `extern crate {} as {}`", name, ident);
let mut locate_ctxt = locator::Context {
sess: self.sess,
span,
ident,
crate_name: name,
hash: hash.map(|a| &*a),
extra_filename: extra_filename,
filesearch: self.sess.target_filesearch(path_kind),
target: &self.sess.target.target,
triple: self.sess.opts.target_triple.clone(),
root,
rejected_via_hash: vec![],
rejected_via_triple: vec![],
rejected_via_kind: vec![],
rejected_via_version: vec![],
rejected_via_filename: vec![],
should_match_name: true,
is_proc_macro: Some(false),
metadata_loader: &*self.cstore.metadata_loader,
};

let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
LoadResult::Previous(cnum)
(LoadResult::Previous(cnum), None)
} else {
info!("falling back to a load");
let mut locate_ctxt = locator::Context {
sess: self.sess,
span,
ident,
crate_name: name,
hash: hash.map(|a| &*a),
extra_filename: extra_filename,
filesearch: self.sess.target_filesearch(path_kind),
target: &self.sess.target.target,
triple: &self.sess.opts.target_triple,
root,
rejected_via_hash: vec![],
rejected_via_triple: vec![],
rejected_via_kind: vec![],
rejected_via_version: vec![],
rejected_via_filename: vec![],
should_match_name: true,
is_proc_macro: Some(false),
metadata_loader: &*self.cstore.metadata_loader,
};

self.load(&mut locate_ctxt).or_else(|| {
self.load(&mut locate_ctxt).map(|r| (r, None)).or_else(|| {
dep_kind = DepKind::UnexportedMacrosOnly;

let mut proc_macro_locator = locator::Context {
target: &self.sess.host,
triple: &TargetTriple::from_triple(config::host_triple()),
filesearch: self.sess.host_filesearch(path_kind),
rejected_via_hash: vec![],
rejected_via_triple: vec![],
rejected_via_kind: vec![],
rejected_via_version: vec![],
rejected_via_filename: vec![],
is_proc_macro: Some(true),
..locate_ctxt
};

self.load(&mut proc_macro_locator)
self.load_proc_macro(&mut locate_ctxt, path_kind)
}).ok_or_else(move || LoadError::LocatorError(locate_ctxt))?
};

match result {
LoadResult::Previous(cnum) => {
(LoadResult::Previous(cnum), None) => {
let data = self.cstore.get_crate_data(cnum);
if data.root.proc_macro_decls_static.is_some() {
dep_kind = DepKind::UnexportedMacrosOnly;
Expand All @@ -336,9 +388,10 @@ impl<'a> CrateLoader<'a> {
});
Ok((cnum, data))
}
LoadResult::Loaded(library) => {
Ok(self.register_crate(root, ident, span, library, dep_kind))
(LoadResult::Loaded(library), host_library) => {
Ok(self.register_crate(host_library, root, ident, span, library, dep_kind))
}
_ => panic!()
}
}

Expand All @@ -354,7 +407,7 @@ impl<'a> CrateLoader<'a> {
// don't want to match a host crate against an equivalent target one
// already loaded.
let root = library.metadata.get_root();
if locate_ctxt.triple == &self.sess.opts.target_triple {
if locate_ctxt.triple == self.sess.opts.target_triple {
let mut result = LoadResult::Loaded(library);
self.cstore.iter_crate_data(|cnum, data| {
if data.root.name == root.name && root.hash == data.root.hash {
Expand Down Expand Up @@ -450,9 +503,9 @@ impl<'a> CrateLoader<'a> {
fn read_extension_crate(&mut self, span: Span, orig_name: Symbol, rename: Symbol)
-> ExtensionCrate {
info!("read extension crate `extern crate {} as {}`", orig_name, rename);
let target_triple = &self.sess.opts.target_triple;
let target_triple = self.sess.opts.target_triple.clone();
let host_triple = TargetTriple::from_triple(config::host_triple());
let is_cross = target_triple != &host_triple;
let is_cross = target_triple != host_triple;
let mut target_only = false;
let mut locate_ctxt = locator::Context {
sess: self.sess,
Expand All @@ -463,7 +516,7 @@ impl<'a> CrateLoader<'a> {
extra_filename: None,
filesearch: self.sess.host_filesearch(PathKind::Crate),
target: &self.sess.host,
triple: &host_triple,
triple: host_triple,
root: &None,
rejected_via_hash: vec![],
rejected_via_triple: vec![],
Expand Down Expand Up @@ -547,7 +600,7 @@ impl<'a> CrateLoader<'a> {
*(sym as *const &[ProcMacro])
};

let extensions = decls.iter().map(|&decl| {
let mut extensions: Vec<_> = decls.iter().map(|&decl| {
match decl {
ProcMacro::CustomDerive { trait_name, attributes, client } => {
let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
Expand All @@ -574,13 +627,17 @@ impl<'a> CrateLoader<'a> {
})
}
}
}).map(|(name, ext)| (Symbol::intern(name), Lrc::new(ext))).collect();
}).map(|(name, ext)| (name, Lrc::new(ext))).collect();

// Intentionally leak the dynamic library. We can't ever unload it
// since the library can make things that will live arbitrarily long.
mem::forget(lib);

extensions
// Sort by macro name to ensure this is ordered the same way on
// both host and target proc macro crates
extensions.sort_by_key(|ext| ext.0);

extensions.into_iter().map(|(name, ext)| (Symbol::intern(name), ext)).collect()
}

/// Look for a plugin registrar. Returns library path, crate
Expand Down
16 changes: 13 additions & 3 deletions src/librustc_metadata/locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,13 @@ use flate2::read::DeflateDecoder;

use rustc_data_structures::owning_ref::OwningRef;

#[derive(Clone)]
pub struct CrateMismatch {
path: PathBuf,
got: String,
}

#[derive(Clone)]
pub struct Context<'a> {
pub sess: &'a Session,
pub span: Span,
Expand All @@ -255,7 +257,7 @@ pub struct Context<'a> {
pub extra_filename: Option<&'a str>,
// points to either self.sess.target.target or self.sess.host, must match triple
pub target: &'a Target,
pub triple: &'a TargetTriple,
pub triple: TargetTriple,
pub filesearch: FileSearch<'a>,
pub root: &'a Option<CratePaths>,
pub rejected_via_hash: Vec<CrateMismatch>,
Expand Down Expand Up @@ -299,6 +301,14 @@ impl CratePaths {
}

impl<'a> Context<'a> {
pub fn reset(&mut self) {
self.rejected_via_hash.clear();
self.rejected_via_triple.clear();
self.rejected_via_kind.clear();
self.rejected_via_version.clear();
self.rejected_via_filename.clear();
}

pub fn maybe_load_library_crate(&mut self) -> Option<Library> {
let mut seen_paths = FxHashSet::default();
match self.extra_filename {
Expand Down Expand Up @@ -396,7 +406,7 @@ impl<'a> Context<'a> {
add);

if (self.ident == "std" || self.ident == "core")
&& self.triple != &TargetTriple::from_triple(config::host_triple()) {
&& self.triple != TargetTriple::from_triple(config::host_triple()) {
err.note(&format!("the `{}` target may not be installed", self.triple));
}
err.span_label(self.span, "can't find crate");
Expand Down Expand Up @@ -715,7 +725,7 @@ impl<'a> Context<'a> {
}
}

if &root.triple != self.triple {
if root.triple != self.triple {
info!("Rejecting via crate triple: expected {} got {}",
self.triple,
root.triple);
Expand Down

0 comments on commit f722699

Please sign in to comment.