Skip to content

Commit f722699

Browse files
committed
Allow linking to a proc macro on the target in metadata and still use a host proc macro to execute them
1 parent a21bd75 commit f722699

File tree

4 files changed

+129
-59
lines changed

4 files changed

+129
-59
lines changed

src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
12161216
Use with RUST_REGION_GRAPH=help for more info"),
12171217
parse_only: bool = (false, parse_bool, [UNTRACKED],
12181218
"parse only; do not compile, assemble, or link"),
1219+
dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1220+
"load proc macros for both target and host, but only link to the target"),
12191221
no_codegen: bool = (false, parse_bool, [TRACKED],
12201222
"run all passes except codegen; no output"),
12211223
treat_err_as_bug: bool = (false, parse_bool, [TRACKED],

src/librustc/session/filesearch.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub enum FileMatch {
1818

1919
// A module for searching for libraries
2020

21+
#[derive(Clone)]
2122
pub struct FileSearch<'a> {
2223
sysroot: &'a Path,
2324
triple: &'a str,

src/librustc_metadata/creader.rs

+113-56
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,15 @@ impl<'a> CrateLoader<'a> {
187187
});
188188
}
189189

190-
fn register_crate(&mut self,
191-
root: &Option<CratePaths>,
192-
ident: Symbol,
193-
span: Span,
194-
lib: Library,
195-
dep_kind: DepKind)
196-
-> (CrateNum, Lrc<cstore::CrateMetadata>) {
190+
fn register_crate(
191+
&mut self,
192+
host_lib: Option<Library>,
193+
root: &Option<CratePaths>,
194+
ident: Symbol,
195+
span: Span,
196+
lib: Library,
197+
dep_kind: DepKind
198+
) -> (CrateNum, Lrc<cstore::CrateMetadata>) {
197199
let crate_root = lib.metadata.get_root();
198200
info!("register crate `extern crate {} as {}`", crate_root.name, ident);
199201
self.verify_no_symbol_conflicts(span, &crate_root);
@@ -221,7 +223,16 @@ impl<'a> CrateLoader<'a> {
221223
let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
222224

223225
let proc_macros = crate_root.proc_macro_decls_static.map(|_| {
224-
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
226+
if self.sess.opts.debugging_opts.dual_proc_macros {
227+
let host_lib = host_lib.unwrap();
228+
self.load_derive_macros(
229+
&host_lib.metadata.get_root(),
230+
host_lib.dylib.clone().map(|p| p.0),
231+
span
232+
)
233+
} else {
234+
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
235+
}
225236
});
226237

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

282+
fn load_proc_macro<'b> (
283+
&mut self,
284+
locate_ctxt: &mut locator::Context<'b>,
285+
path_kind: PathKind,
286+
) -> Option<(LoadResult, Option<Library>)>
287+
where
288+
'a: 'b
289+
{
290+
// Use a new locator Context so trying to load a proc macro doesn't affect the error
291+
// message we emit
292+
let mut proc_macro_locator = locate_ctxt.clone();
293+
294+
// Try to load a proc macro
295+
proc_macro_locator.is_proc_macro = Some(true);
296+
297+
// Load the proc macro crate for the target
298+
let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros {
299+
proc_macro_locator.reset();
300+
let result = match self.load(&mut proc_macro_locator)? {
301+
LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)),
302+
LoadResult::Loaded(library) => Some(LoadResult::Loaded(library))
303+
};
304+
// Don't look for a matching hash when looking for the host crate.
305+
// It won't be the same as the target crate hash
306+
locate_ctxt.hash = None;
307+
// Use the locate_ctxt when looking for the host proc macro crate, as that is required
308+
// so we want it to affect the error message
309+
(locate_ctxt, result)
310+
} else {
311+
(&mut proc_macro_locator, None)
312+
};
313+
314+
// Load the proc macro crate for the host
315+
316+
locator.reset();
317+
locator.is_proc_macro = Some(true);
318+
locator.target = &self.sess.host;
319+
locator.triple = TargetTriple::from_triple(config::host_triple());
320+
locator.filesearch = self.sess.host_filesearch(path_kind);
321+
322+
let host_result = self.load(locator)?;
323+
324+
Some(if self.sess.opts.debugging_opts.dual_proc_macros {
325+
let host_result = match host_result {
326+
LoadResult::Previous(..) => {
327+
panic!("host and target proc macros must be loaded in lock-step")
328+
}
329+
LoadResult::Loaded(library) => library
330+
};
331+
(target_result.unwrap(), Some(host_result))
332+
} else {
333+
(host_result, None)
334+
})
335+
}
336+
271337
fn resolve_crate<'b>(
272338
&'b mut self,
273339
root: &'b Option<CratePaths>,
@@ -280,53 +346,39 @@ impl<'a> CrateLoader<'a> {
280346
mut dep_kind: DepKind,
281347
) -> Result<(CrateNum, Lrc<cstore::CrateMetadata>), LoadError<'b>> {
282348
info!("resolving crate `extern crate {} as {}`", name, ident);
349+
let mut locate_ctxt = locator::Context {
350+
sess: self.sess,
351+
span,
352+
ident,
353+
crate_name: name,
354+
hash: hash.map(|a| &*a),
355+
extra_filename: extra_filename,
356+
filesearch: self.sess.target_filesearch(path_kind),
357+
target: &self.sess.target.target,
358+
triple: self.sess.opts.target_triple.clone(),
359+
root,
360+
rejected_via_hash: vec![],
361+
rejected_via_triple: vec![],
362+
rejected_via_kind: vec![],
363+
rejected_via_version: vec![],
364+
rejected_via_filename: vec![],
365+
should_match_name: true,
366+
is_proc_macro: Some(false),
367+
metadata_loader: &*self.cstore.metadata_loader,
368+
};
369+
283370
let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
284-
LoadResult::Previous(cnum)
371+
(LoadResult::Previous(cnum), None)
285372
} else {
286373
info!("falling back to a load");
287-
let mut locate_ctxt = locator::Context {
288-
sess: self.sess,
289-
span,
290-
ident,
291-
crate_name: name,
292-
hash: hash.map(|a| &*a),
293-
extra_filename: extra_filename,
294-
filesearch: self.sess.target_filesearch(path_kind),
295-
target: &self.sess.target.target,
296-
triple: &self.sess.opts.target_triple,
297-
root,
298-
rejected_via_hash: vec![],
299-
rejected_via_triple: vec![],
300-
rejected_via_kind: vec![],
301-
rejected_via_version: vec![],
302-
rejected_via_filename: vec![],
303-
should_match_name: true,
304-
is_proc_macro: Some(false),
305-
metadata_loader: &*self.cstore.metadata_loader,
306-
};
307-
308-
self.load(&mut locate_ctxt).or_else(|| {
374+
self.load(&mut locate_ctxt).map(|r| (r, None)).or_else(|| {
309375
dep_kind = DepKind::UnexportedMacrosOnly;
310-
311-
let mut proc_macro_locator = locator::Context {
312-
target: &self.sess.host,
313-
triple: &TargetTriple::from_triple(config::host_triple()),
314-
filesearch: self.sess.host_filesearch(path_kind),
315-
rejected_via_hash: vec![],
316-
rejected_via_triple: vec![],
317-
rejected_via_kind: vec![],
318-
rejected_via_version: vec![],
319-
rejected_via_filename: vec![],
320-
is_proc_macro: Some(true),
321-
..locate_ctxt
322-
};
323-
324-
self.load(&mut proc_macro_locator)
376+
self.load_proc_macro(&mut locate_ctxt, path_kind)
325377
}).ok_or_else(move || LoadError::LocatorError(locate_ctxt))?
326378
};
327379

328380
match result {
329-
LoadResult::Previous(cnum) => {
381+
(LoadResult::Previous(cnum), None) => {
330382
let data = self.cstore.get_crate_data(cnum);
331383
if data.root.proc_macro_decls_static.is_some() {
332384
dep_kind = DepKind::UnexportedMacrosOnly;
@@ -336,9 +388,10 @@ impl<'a> CrateLoader<'a> {
336388
});
337389
Ok((cnum, data))
338390
}
339-
LoadResult::Loaded(library) => {
340-
Ok(self.register_crate(root, ident, span, library, dep_kind))
391+
(LoadResult::Loaded(library), host_library) => {
392+
Ok(self.register_crate(host_library, root, ident, span, library, dep_kind))
341393
}
394+
_ => panic!()
342395
}
343396
}
344397

@@ -354,7 +407,7 @@ impl<'a> CrateLoader<'a> {
354407
// don't want to match a host crate against an equivalent target one
355408
// already loaded.
356409
let root = library.metadata.get_root();
357-
if locate_ctxt.triple == &self.sess.opts.target_triple {
410+
if locate_ctxt.triple == self.sess.opts.target_triple {
358411
let mut result = LoadResult::Loaded(library);
359412
self.cstore.iter_crate_data(|cnum, data| {
360413
if data.root.name == root.name && root.hash == data.root.hash {
@@ -450,9 +503,9 @@ impl<'a> CrateLoader<'a> {
450503
fn read_extension_crate(&mut self, span: Span, orig_name: Symbol, rename: Symbol)
451504
-> ExtensionCrate {
452505
info!("read extension crate `extern crate {} as {}`", orig_name, rename);
453-
let target_triple = &self.sess.opts.target_triple;
506+
let target_triple = self.sess.opts.target_triple.clone();
454507
let host_triple = TargetTriple::from_triple(config::host_triple());
455-
let is_cross = target_triple != &host_triple;
508+
let is_cross = target_triple != host_triple;
456509
let mut target_only = false;
457510
let mut locate_ctxt = locator::Context {
458511
sess: self.sess,
@@ -463,7 +516,7 @@ impl<'a> CrateLoader<'a> {
463516
extra_filename: None,
464517
filesearch: self.sess.host_filesearch(PathKind::Crate),
465518
target: &self.sess.host,
466-
triple: &host_triple,
519+
triple: host_triple,
467520
root: &None,
468521
rejected_via_hash: vec![],
469522
rejected_via_triple: vec![],
@@ -547,7 +600,7 @@ impl<'a> CrateLoader<'a> {
547600
*(sym as *const &[ProcMacro])
548601
};
549602

550-
let extensions = decls.iter().map(|&decl| {
603+
let mut extensions: Vec<_> = decls.iter().map(|&decl| {
551604
match decl {
552605
ProcMacro::CustomDerive { trait_name, attributes, client } => {
553606
let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
@@ -574,13 +627,17 @@ impl<'a> CrateLoader<'a> {
574627
})
575628
}
576629
}
577-
}).map(|(name, ext)| (Symbol::intern(name), Lrc::new(ext))).collect();
630+
}).map(|(name, ext)| (name, Lrc::new(ext))).collect();
578631

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

583-
extensions
636+
// Sort by macro name to ensure this is ordered the same way on
637+
// both host and target proc macro crates
638+
extensions.sort_by_key(|ext| ext.0);
639+
640+
extensions.into_iter().map(|(name, ext)| (Symbol::intern(name), ext)).collect()
584641
}
585642

586643
/// Look for a plugin registrar. Returns library path, crate

src/librustc_metadata/locator.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,13 @@ use flate2::read::DeflateDecoder;
241241

242242
use rustc_data_structures::owning_ref::OwningRef;
243243

244+
#[derive(Clone)]
244245
pub struct CrateMismatch {
245246
path: PathBuf,
246247
got: String,
247248
}
248249

250+
#[derive(Clone)]
249251
pub struct Context<'a> {
250252
pub sess: &'a Session,
251253
pub span: Span,
@@ -255,7 +257,7 @@ pub struct Context<'a> {
255257
pub extra_filename: Option<&'a str>,
256258
// points to either self.sess.target.target or self.sess.host, must match triple
257259
pub target: &'a Target,
258-
pub triple: &'a TargetTriple,
260+
pub triple: TargetTriple,
259261
pub filesearch: FileSearch<'a>,
260262
pub root: &'a Option<CratePaths>,
261263
pub rejected_via_hash: Vec<CrateMismatch>,
@@ -299,6 +301,14 @@ impl CratePaths {
299301
}
300302

301303
impl<'a> Context<'a> {
304+
pub fn reset(&mut self) {
305+
self.rejected_via_hash.clear();
306+
self.rejected_via_triple.clear();
307+
self.rejected_via_kind.clear();
308+
self.rejected_via_version.clear();
309+
self.rejected_via_filename.clear();
310+
}
311+
302312
pub fn maybe_load_library_crate(&mut self) -> Option<Library> {
303313
let mut seen_paths = FxHashSet::default();
304314
match self.extra_filename {
@@ -396,7 +406,7 @@ impl<'a> Context<'a> {
396406
add);
397407

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

718-
if &root.triple != self.triple {
728+
if root.triple != self.triple {
719729
info!("Rejecting via crate triple: expected {} got {}",
720730
self.triple,
721731
root.triple);

0 commit comments

Comments
 (0)