Auto merge of #58013 - Zoxc:stable-hash-macro-simple, r=oli-obk
Create a derive macro for HashStable and allow proc macros in rustc A combination of https://github.com/rust-lang/rust/pull/56864 and https://github.com/rust-lang/rust/pull/56795. There were complications with using `serde_derive` as rustc doesn't know which crate to use for the host when there is a serde_derive in the sysroot and cargo passes another on the command line built from crates.io. r? @eddyb (for proc macro changes) @alexcrichton (for rustbuild changes) @michaelwoerister (for the macro itself)
This commit is contained in:
commit
0547ceb200
24 changed files with 392 additions and 87 deletions
11
Cargo.lock
11
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"
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Cow<'a, str>>,
|
||||
}
|
||||
|
||||
#[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<Cow<'a, str>>,
|
||||
filenames: Vec<Cow<'a, str>>,
|
||||
target: CargoTarget<'a>,
|
||||
},
|
||||
BuildScriptExecuted {
|
||||
package_id: Cow<'a, str>,
|
||||
|
|
|
@ -1129,7 +1129,7 @@ impl Build {
|
|||
ret
|
||||
}
|
||||
|
||||
fn read_stamp_file(&self, stamp: &Path) -> Vec<PathBuf> {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -91,7 +91,8 @@ impl Step for ToolBuild {
|
|||
compile::CargoMessage::CompilerArtifact {
|
||||
package_id,
|
||||
features,
|
||||
filenames
|
||||
filenames,
|
||||
target: _,
|
||||
} => {
|
||||
(package_id, features, filenames)
|
||||
}
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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,
|
||||
|
|
14
src/librustc_macros/Cargo.toml
Normal file
14
src/librustc_macros/Cargo.toml
Normal file
|
@ -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"
|
87
src/librustc_macros/src/hash_stable.rs
Normal file
87
src/librustc_macros/src/hash_stable.rs
Normal file
|
@ -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<Ident>,
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
})
|
||||
}
|
8
src/librustc_macros/src/lib.rs
Normal file
8
src/librustc_macros/src/lib.rs
Normal file
|
@ -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);
|
|
@ -188,13 +188,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);
|
||||
|
@ -222,7 +224,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, || {
|
||||
|
@ -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<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>,
|
||||
|
@ -282,7 +348,7 @@ impl<'a> CrateLoader<'a> {
|
|||
) -> Result<(CrateNum, Lrc<cstore::CrateMetadata>), 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![],
|
||||
|
|
|
@ -648,7 +648,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
|
||||
pub fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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<CratePaths>,
|
||||
pub rejected_via_hash: Vec<CrateMismatch>,
|
||||
|
@ -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<Library> {
|
||||
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);
|
||||
|
|
|
@ -187,6 +187,7 @@ pub struct CrateRoot {
|
|||
pub has_default_lib_allocator: bool,
|
||||
pub plugin_registrar_fn: Option<DefIndex>,
|
||||
pub proc_macro_decls_static: Option<DefIndex>,
|
||||
pub proc_macro_stability: Option<attr::Stability>,
|
||||
|
||||
pub crate_deps: LazySeq<CrateDep>,
|
||||
pub dylib_dependency_formats: LazySeq<Option<LinkagePreference>>,
|
||||
|
|
15
src/test/ui-fulldeps/hash-stable-is-unstable.rs
Normal file
15
src/test/ui-fulldeps/hash-stable-is-unstable.rs
Normal file
|
@ -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;
|
48
src/test/ui-fulldeps/hash-stable-is-unstable.stderr
Normal file
48
src/test/ui-fulldeps/hash-stable-is-unstable.stderr
Normal file
|
@ -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`.
|
|
@ -137,6 +137,7 @@ const WHITELIST: &[Crate<'_>] = &[
|
|||
Crate("smallvec"),
|
||||
Crate("stable_deref_trait"),
|
||||
Crate("syn"),
|
||||
Crate("synstructure"),
|
||||
Crate("tempfile"),
|
||||
Crate("termcolor"),
|
||||
Crate("terminon"),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue