diff --git a/Cargo.lock b/Cargo.lock index 19dadaa14005a..ad4af76f4b382 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2365,6 +2365,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_fs_util 0.0.0", + "rustc_macros 0.1.0", "rustc_target 0.0.0", "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", @@ -2817,6 +2818,16 @@ dependencies = [ "core 0.0.0", ] +[[package]] +name = "rustc_macros" +version = "0.1.0" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_metadata" version = "0.0.0" diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 70e4a69a07d44..ca86aeb8100a9 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -109,6 +109,12 @@ fn main() { cmd.arg("-Zexternal-macro-backtrace"); + // Link crates to the proc macro crate for the target, but use a host proc macro crate + // to actually run the macros + if env::var_os("RUST_DUAL_PROC_MACROS").is_some() { + cmd.arg("-Zdual-proc-macros"); + } + // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of // linking all deps statically into the dylib. @@ -258,13 +264,6 @@ fn main() { } } - // Force all crates compiled by this compiler to (a) be unstable and (b) - // allow the `rustc_private` feature to link to other unstable crates - // also in the sysroot. - if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { - cmd.arg("-Z").arg("force-unstable-if-unmarked"); - } - if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { cmd.arg("--remap-path-prefix").arg(&map); } @@ -284,6 +283,14 @@ fn main() { } } + // Force all crates compiled by this compiler to (a) be unstable and (b) + // allow the `rustc_private` feature to link to other unstable crates + // also in the sysroot. We also do this for host crates, since those + // may be proc macros, in which case we might ship them. + if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) { + cmd.arg("-Z").arg("force-unstable-if-unmarked"); + } + if env::var_os("RUSTC_PARALLEL_COMPILER").is_some() { cmd.arg("--cfg").arg("parallel_compiler"); } diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 7e6c0a9f52aa2..eb1a2a59fa3c5 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -812,6 +812,17 @@ impl<'a> Builder<'a> { cargo.env("RUST_CHECK", "1"); } + match mode { + Mode::Std | Mode::Test | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTest=> {}, + Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { + // Build proc macros both for the host and the target + if target != compiler.host && cmd != "check" { + cargo.arg("-Zdual-proc-macros"); + cargo.env("RUST_DUAL_PROC_MACROS", "1"); + } + }, + } + cargo.arg("-j").arg(self.jobs().to_string()); // Remove make-related flags to ensure Cargo can correctly set things up cargo.env_remove("MAKEFLAGS"); diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 20370372082b9..a30b465698e2a 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -42,7 +42,8 @@ impl Step for Std { true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&builder, &libdir, &libstd_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); } } @@ -88,7 +89,8 @@ impl Step for Rustc { true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&builder, &libdir, &librustc_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target)); } } @@ -175,7 +177,8 @@ impl Step for Test { true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(builder, &libdir, &libtest_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(builder, &libdir, &hostdir, &libtest_stamp(builder, compiler, target)); } } @@ -222,7 +225,8 @@ impl Step for Rustdoc { true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&builder, &libdir, &rustdoc_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &rustdoc_stamp(builder, compiler, target)); builder.cargo(compiler, Mode::ToolRustc, target, "clean"); } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 249a183189048..9498dbb595232 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -224,7 +224,8 @@ impl Step for StdLink { target_compiler.host, target)); let libdir = builder.sysroot_libdir(target_compiler, target); - add_to_sysroot(builder, &libdir, &libstd_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(target_compiler, compiler.host); + add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); if builder.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" { // The sanitizers are only built in stage1 or above, so the dylibs will @@ -431,8 +432,12 @@ impl Step for TestLink { &compiler.host, target_compiler.host, target)); - add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target), - &libtest_stamp(builder, compiler, target)); + add_to_sysroot( + builder, + &builder.sysroot_libdir(target_compiler, target), + &builder.sysroot_libdir(target_compiler, compiler.host), + &libtest_stamp(builder, compiler, target) + ); builder.cargo(target_compiler, Mode::ToolTest, target, "clean"); } @@ -496,8 +501,8 @@ impl Step for Rustc { return; } - // Ensure that build scripts have a std to link against. - builder.ensure(Std { + // Ensure that build scripts and proc macros have a std / libproc_macro to link against. + builder.ensure(Test { compiler: builder.compiler(self.compiler.stage, builder.config.build), target: builder.config.build, }); @@ -592,8 +597,12 @@ impl Step for RustcLink { &compiler.host, target_compiler.host, target)); - add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target), - &librustc_stamp(builder, compiler, target)); + add_to_sysroot( + builder, + &builder.sysroot_libdir(target_compiler, target), + &builder.sysroot_libdir(target_compiler, compiler.host), + &librustc_stamp(builder, compiler, target) + ); builder.cargo(target_compiler, Mode::ToolRustc, target, "clean"); } } @@ -1015,10 +1024,20 @@ impl Step for Assemble { /// /// For a particular stage this will link the file listed in `stamp` into the /// `sysroot_dst` provided. -pub fn add_to_sysroot(builder: &Builder<'_>, sysroot_dst: &Path, stamp: &Path) { +pub fn add_to_sysroot( + builder: &Builder<'_>, + sysroot_dst: &Path, + sysroot_host_dst: &Path, + stamp: &Path +) { t!(fs::create_dir_all(&sysroot_dst)); - for path in builder.read_stamp_file(stamp) { - builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); + t!(fs::create_dir_all(&sysroot_host_dst)); + for (path, host) in builder.read_stamp_file(stamp) { + if host { + builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap())); + } else { + builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); + } } } @@ -1047,8 +1066,14 @@ pub fn run_cargo(builder: &Builder<'_>, let mut deps = Vec::new(); let mut toplevel = Vec::new(); let ok = stream_cargo(builder, cargo, &mut |msg| { - let filenames = match msg { - CargoMessage::CompilerArtifact { filenames, .. } => filenames, + let (filenames, crate_types) = match msg { + CargoMessage::CompilerArtifact { + filenames, + target: CargoTarget { + crate_types, + }, + .. + } => (filenames, crate_types), _ => return, }; for filename in filenames { @@ -1063,15 +1088,19 @@ pub fn run_cargo(builder: &Builder<'_>, let filename = Path::new(&*filename); // If this was an output file in the "host dir" we don't actually - // worry about it, it's not relevant for us. + // worry about it, it's not relevant for us if filename.starts_with(&host_root_dir) { + // Unless it's a proc macro used in the compiler + if crate_types.iter().any(|t| t == "proc-macro") { + deps.push((filename.to_path_buf(), true)); + } continue; } // If this was output in the `deps` dir then this is a precise file // name (hash included) so we start tracking it. if filename.starts_with(&target_deps_dir) { - deps.push(filename.to_path_buf()); + deps.push((filename.to_path_buf(), false)); continue; } @@ -1124,10 +1153,10 @@ pub fn run_cargo(builder: &Builder<'_>, let candidate = format!("{}.lib", path_to_add); let candidate = PathBuf::from(candidate); if candidate.exists() { - deps.push(candidate); + deps.push((candidate, false)); } } - deps.push(path_to_add.into()); + deps.push((path_to_add.into(), false)); } // Now we want to update the contents of the stamp file, if necessary. First @@ -1140,12 +1169,13 @@ pub fn run_cargo(builder: &Builder<'_>, let mut new_contents = Vec::new(); let mut max = None; let mut max_path = None; - for dep in deps.iter() { + for (dep, proc_macro) in deps.iter() { let mtime = mtime(dep); if Some(mtime) > max { max = Some(mtime); max_path = Some(dep.clone()); } + new_contents.extend(if *proc_macro { b"h" } else { b"t" }); new_contents.extend(dep.to_str().unwrap().as_bytes()); new_contents.extend(b"\0"); } @@ -1157,7 +1187,7 @@ pub fn run_cargo(builder: &Builder<'_>, if contents_equal && max <= stamp_mtime { builder.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}", stamp, max, stamp_mtime)); - return deps + return deps.into_iter().map(|(d, _)| d).collect() } if max > stamp_mtime { builder.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path)); @@ -1165,7 +1195,7 @@ pub fn run_cargo(builder: &Builder<'_>, builder.verbose(&format!("updating {:?} as deps changed", stamp)); } t!(fs::write(&stamp, &new_contents)); - deps + deps.into_iter().map(|(d, _)| d).collect() } pub fn stream_cargo( @@ -1211,6 +1241,11 @@ pub fn stream_cargo( status.success() } +#[derive(Deserialize)] +pub struct CargoTarget<'a> { + crate_types: Vec>, +} + #[derive(Deserialize)] #[serde(tag = "reason", rename_all = "kebab-case")] pub enum CargoMessage<'a> { @@ -1218,6 +1253,7 @@ pub enum CargoMessage<'a> { package_id: Cow<'a, str>, features: Vec>, filenames: Vec>, + target: CargoTarget<'a>, }, BuildScriptExecuted { package_id: Cow<'a, str>, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 84e2c5aab54a3..9317a40545eac 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1129,7 +1129,7 @@ impl Build { ret } - fn read_stamp_file(&self, stamp: &Path) -> Vec { + fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, bool)> { if self.config.dry_run { return Vec::new(); } @@ -1142,8 +1142,9 @@ impl Build { if part.is_empty() { continue } - let path = PathBuf::from(t!(str::from_utf8(part))); - paths.push(path); + let host = part[0] as char == 'h'; + let path = PathBuf::from(t!(str::from_utf8(&part[1..]))); + paths.push((path, host)); } paths } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index fc1a17d546675..9dbcacf70262c 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -91,7 +91,8 @@ impl Step for ToolBuild { compile::CargoMessage::CompilerArtifact { package_id, features, - filenames + filenames, + target: _, } => { (package_id, features, filenames) } diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 26a27ea88e27a..31e10c19c7a60 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -24,6 +24,7 @@ rustc-rayon = "0.1.2" rustc-rayon-core = "0.1.2" rustc_apfloat = { path = "../librustc_apfloat" } rustc_target = { path = "../librustc_target" } +rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } errors = { path = "../librustc_errors", package = "rustc_errors" } serialize = { path = "../libserialize" } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 2d0296aa38c70..4b5670af13858 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -32,6 +32,7 @@ use crate::ty::query::Providers; use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync}; use rustc_data_structures::thin_vec::ThinVec; +use rustc_macros::HashStable; use serialize::{self, Encoder, Encodable, Decoder, Decodable}; use std::collections::{BTreeSet, BTreeMap}; @@ -149,7 +150,7 @@ pub const DUMMY_HIR_ID: HirId = HirId { pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX; -#[derive(Clone, RustcEncodable, RustcDecodable, Copy)] +#[derive(Clone, RustcEncodable, RustcDecodable, Copy, HashStable)] pub struct Lifetime { pub hir_id: HirId, pub span: Span, diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 0803816fb03f4..d8d4157e20ec9 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -157,12 +157,6 @@ impl_stable_hash_for!(struct ast::Label { ident }); -impl_stable_hash_for!(struct hir::Lifetime { - hir_id, - span, - name -}); - impl_stable_hash_for!(struct hir::Path { span, def, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 205ea6126fc59..6adfaa53946ac 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -141,14 +141,8 @@ pub mod util { pub mod bug; } -// A private module so that macro-expanded idents like -// `::rustc::lint::Lint` will also work in `rustc` itself. -// -// `libstd` uses the same trick. -#[doc(hidden)] -mod rustc { - pub use crate::lint; -} +// Allows macros to refer to this crate as `::rustc` +extern crate self as rustc; // FIXME(#27438): right now the unit tests of librustc don't refer to any actual // functions generated in librustc_data_structures (all diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 774ab0333db54..a4c587b5ca761 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1232,6 +1232,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], diff --git a/src/librustc/session/filesearch.rs b/src/librustc/session/filesearch.rs index 77f190e281229..cf09d45ca38fc 100644 --- a/src/librustc/session/filesearch.rs +++ b/src/librustc/session/filesearch.rs @@ -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, diff --git a/src/librustc_macros/Cargo.toml b/src/librustc_macros/Cargo.toml new file mode 100644 index 0000000000000..2fe51a22fb484 --- /dev/null +++ b/src/librustc_macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rustc_macros" +version = "0.1.0" +authors = ["The Rust Project Developers"] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +synstructure = "0.10.1" +syn = { version = "0.15.22", features = ["full"] } +proc-macro2 = "0.4.24" +quote = "0.6.10" diff --git a/src/librustc_macros/src/hash_stable.rs b/src/librustc_macros/src/hash_stable.rs new file mode 100644 index 0000000000000..6d7590c7d1cd3 --- /dev/null +++ b/src/librustc_macros/src/hash_stable.rs @@ -0,0 +1,87 @@ +use synstructure; +use syn::{self, Meta, NestedMeta, parse_quote}; +use proc_macro2::{self, Ident}; +use quote::quote; + +struct Attributes { + ignore: bool, + project: Option, +} + +fn parse_attributes(field: &syn::Field) -> Attributes { + let mut attrs = Attributes { + ignore: false, + project: None, + }; + for attr in &field.attrs { + if let Ok(meta) = attr.parse_meta() { + if &meta.name().to_string() != "stable_hasher" { + continue; + } + let mut any_attr = false; + if let Meta::List(list) = meta { + for nested in list.nested.iter() { + if let NestedMeta::Meta(meta) = nested { + if &meta.name().to_string() == "ignore" { + attrs.ignore = true; + any_attr = true; + } + if &meta.name().to_string() == "project" { + if let Meta::List(list) = meta { + if let Some(nested) = list.nested.iter().next() { + if let NestedMeta::Meta(meta) = nested { + attrs.project = Some(meta.name()); + any_attr = true; + } + } + } + } + } + } + } + if !any_attr { + panic!("error parsing stable_hasher"); + } + } + } + attrs +} + +pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + let generic: syn::GenericParam = parse_quote!('__ctx); + s.add_bounds(synstructure::AddBounds::Generics); + s.add_impl_generic(generic); + let body = s.each(|bi| { + let attrs = parse_attributes(bi.ast()); + if attrs.ignore { + quote!{} + } else if let Some(project) = attrs.project { + quote!{ + &#bi.#project.hash_stable(__hcx, __hasher); + } + } else { + quote!{ + #bi.hash_stable(__hcx, __hasher); + } + } + }); + + let discriminant = match s.ast().data { + syn::Data::Enum(_) => quote! { + ::std::mem::discriminant(self).hash_stable(__hcx, __hasher); + }, + syn::Data::Struct(_) => quote! {}, + syn::Data::Union(_) => panic!("cannot derive on union"), + }; + + s.bound_impl(quote!(::rustc_data_structures::stable_hasher::HashStable + <::rustc::ich::StableHashingContext<'__ctx>>), quote!{ + fn hash_stable<__W: ::rustc_data_structures::stable_hasher::StableHasherResult>( + &self, + __hcx: &mut ::rustc::ich::StableHashingContext<'__ctx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<__W>) { + #discriminant + match *self { #body } + } + }) +} diff --git a/src/librustc_macros/src/lib.rs b/src/librustc_macros/src/lib.rs new file mode 100644 index 0000000000000..cad31264b05a4 --- /dev/null +++ b/src/librustc_macros/src/lib.rs @@ -0,0 +1,8 @@ +#![feature(proc_macro_hygiene)] +#![deny(rust_2018_idioms)] + +use synstructure::decl_derive; + +mod hash_stable; + +decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 6f2718381c2ec..36d9bf9f50dd5 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -188,13 +188,15 @@ impl<'a> CrateLoader<'a> { }); } - fn register_crate(&mut self, - root: &Option, - ident: Symbol, - span: Span, - lib: Library, - dep_kind: DepKind) - -> (CrateNum, Lrc) { + fn register_crate( + &mut self, + host_lib: Option, + root: &Option, + ident: Symbol, + span: Span, + lib: Library, + dep_kind: DepKind + ) -> (CrateNum, Lrc) { 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); @@ -222,7 +224,16 @@ impl<'a> CrateLoader<'a> { let dependencies: Vec = 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, || { @@ -269,6 +280,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)> + 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, @@ -282,7 +348,7 @@ impl<'a> CrateLoader<'a> { ) -> Result<(CrateNum, Lrc), LoadError<'b>> { info!("resolving crate `extern crate {} as {}`", name, ident); 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 { @@ -294,7 +360,7 @@ impl<'a> CrateLoader<'a> { extra_filename: extra_filename, filesearch: self.sess.target_filesearch(path_kind), target: &self.sess.target.target, - triple: &self.sess.opts.target_triple, + triple: self.sess.opts.target_triple.clone(), root, rejected_via_hash: vec![], rejected_via_triple: vec![], @@ -306,28 +372,14 @@ impl<'a> CrateLoader<'a> { 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; @@ -337,9 +389,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!() } } @@ -355,7 +408,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 { @@ -451,9 +504,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, @@ -464,7 +517,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![], diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 1c4e3bc6a50e7..6fe00a4ad2ff2 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -648,7 +648,7 @@ impl<'a, 'tcx> CrateMetadata { pub fn get_stability(&self, id: DefIndex) -> Option { match self.is_proc_macro(id) { - true => None, + true => self.root.proc_macro_stability.clone(), false => self.entry(id).stability.map(|stab| stab.decode(self)), } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f79cfa3b773eb..683056c9b33a0 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -490,7 +490,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { None }, - + proc_macro_stability: if is_proc_macro { + tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| stab.clone()) + } else { + None + }, compiler_builtins: attr::contains_name(&attrs, "compiler_builtins"), needs_allocator: attr::contains_name(&attrs, "needs_allocator"), needs_panic_runtime: attr::contains_name(&attrs, "needs_panic_runtime"), diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 6a1aada5ac706..81878c4f687b6 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -244,11 +244,13 @@ use rustc_data_structures::owning_ref::OwningRef; use log::{debug, info, warn}; +#[derive(Clone)] pub struct CrateMismatch { path: PathBuf, got: String, } +#[derive(Clone)] pub struct Context<'a> { pub sess: &'a Session, pub span: Span, @@ -258,7 +260,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, pub rejected_via_hash: Vec, @@ -302,6 +304,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 { let mut seen_paths = FxHashSet::default(); match self.extra_filename { @@ -399,7 +409,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"); @@ -718,7 +728,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); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index af79ea37dff55..afeea9947b5e3 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -187,6 +187,7 @@ pub struct CrateRoot { pub has_default_lib_allocator: bool, pub plugin_registrar_fn: Option, pub proc_macro_decls_static: Option, + pub proc_macro_stability: Option, pub crate_deps: LazySeq, pub dylib_dependency_formats: LazySeq>, diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.rs b/src/test/ui-fulldeps/hash-stable-is-unstable.rs new file mode 100644 index 0000000000000..9f67f642df1ce --- /dev/null +++ b/src/test/ui-fulldeps/hash-stable-is-unstable.rs @@ -0,0 +1,15 @@ +// ignore-stage1 + +extern crate rustc_data_structures; +//~^ use of unstable library feature 'rustc_private' +extern crate rustc; +//~^ use of unstable library feature 'rustc_private' +extern crate rustc_macros; +//~^ use of unstable library feature 'rustc_private' + +use rustc_macros::HashStable; +//~^ use of unstable library feature 'rustc_private' + +#[derive(HashStable)] +//~^ use of unstable library feature 'rustc_private' +struct Test; diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr new file mode 100644 index 0000000000000..e7007204d3895 --- /dev/null +++ b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr @@ -0,0 +1,48 @@ +error[E0601]: `main` function not found in crate `hash_stable_is_unstable` + | + = note: consider adding a `main` function to `$DIR/hash-stable-is-unstable.rs` + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) + --> $DIR/hash-stable-is-unstable.rs:3:1 + | +LL | extern crate rustc_data_structures; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) + --> $DIR/hash-stable-is-unstable.rs:5:1 + | +LL | extern crate rustc; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) + --> $DIR/hash-stable-is-unstable.rs:7:1 + | +LL | extern crate rustc_macros; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) + --> $DIR/hash-stable-is-unstable.rs:10:5 + | +LL | use rustc_macros::HashStable; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) + --> $DIR/hash-stable-is-unstable.rs:13:10 + | +LL | #[derive(HashStable)] + | ^^^^^^^^^^ + | + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error: aborting due to 6 previous errors + +Some errors occurred: E0601, E0658. +For more information about an error, try `rustc --explain E0601`. diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index f581ce1f5a379..d7683aae841cd 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -137,6 +137,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("smallvec"), Crate("stable_deref_trait"), Crate("syn"), + Crate("synstructure"), Crate("tempfile"), Crate("termcolor"), Crate("terminon"),