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

[WIP] Allow linking to a proc macro on the target in metadata and still use a host proc macro to execute them #57626

Closed
wants to merge 1 commit into from
Closed
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
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
166 changes: 110 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,58 @@ 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))
};
// 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 +343,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 +385,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 +404,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 +500,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 +513,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 +597,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 +624,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