diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index daf9fa6158f1c..a5e7028b0f689 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -5,7 +5,7 @@ use std::fs::File; use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; -use rustc_codegen_ssa::METADATA_FILENAME; +use rustc_codegen_ssa::{METADATA_FILE_EXTENSION, METADATA_FILE_PREFIX}; use rustc_session::Session; use object::{Object, SymbolKind}; @@ -116,7 +116,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { self.add_archive(rlib.to_owned(), move |fname: &str| { // Ignore metadata files, no matter the name. - if fname == METADATA_FILENAME { + if fname.starts_with(METADATA_FILE_PREFIX) && fname.ends_with(METADATA_FILE_EXTENSION) { return true; } diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index c0245aa1e0213..67ddf9da94bb1 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -299,6 +299,7 @@ pub(super) fn run_aot( Box::new(( CodegenResults { crate_name: tcx.crate_name(LOCAL_CRATE), + crate_hash: tcx.crate_hash(LOCAL_CRATE), modules, allocator_module, metadata_module, diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs index 2e3b9fb8364e4..7c51f7ccb8c31 100644 --- a/compiler/rustc_codegen_cranelift/src/metadata.rs +++ b/compiler/rustc_codegen_cranelift/src/metadata.rs @@ -4,7 +4,7 @@ use std::convert::TryFrom; use std::fs::File; use std::path::Path; -use rustc_codegen_ssa::METADATA_FILENAME; +use rustc_codegen_ssa::{METADATA_FILE_EXTENSION, METADATA_FILE_PREFIX}; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::rustc_erase_owner; use rustc_data_structures::sync::MetadataRef; @@ -23,7 +23,10 @@ impl MetadataLoader for CraneliftMetadataLoader { // Iterate over all entries in the archive: while let Some(entry_result) = archive.next_entry() { let mut entry = entry_result.map_err(|e| format!("{:?}", e))?; - if entry.header().identifier() == METADATA_FILENAME.as_bytes() { + let filename = String::from_utf8_lossy(entry.header().identifier()); + if filename.starts_with(METADATA_FILE_PREFIX) + && filename.ends_with(METADATA_FILE_EXTENSION) + { let mut buf = Vec::with_capacity( usize::try_from(entry.header().size()) .expect("Rlib metadata file too big to load into memory."), @@ -94,9 +97,7 @@ pub(crate) fn write_metadata( assert!(kind == MetadataKind::Compressed); let mut compressed = tcx.metadata_encoding_version(); - FrameEncoder::new(&mut compressed) - .write_all(&metadata.raw_data) - .unwrap(); + FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); product.add_rustc_section( rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx), diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 4e7213853b015..08d2dbeb440c1 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -10,7 +10,9 @@ use std::str; use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind}; use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; -use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME}; +use rustc_codegen_ssa::{ + looks_like_rust_object_file, METADATA_FILE_EXTENSION, METADATA_FILE_PREFIX, +}; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -130,7 +132,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { self.add_archive(rlib, move |fname: &str| { // Ignore metadata files, no matter the name. - if fname == METADATA_FILENAME { + if fname.starts_with(METADATA_FILE_PREFIX) && fname.ends_with(METADATA_FILE_EXTENSION) { return true; } diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 1090d4a25c7cf..62cadb94b1bd2 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -28,6 +28,8 @@ use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_data_structures::small_c_str::SmallCStr; +use rustc_data_structures::svh::Svh; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::dep_graph; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::cstore::EncodedMetadata; @@ -70,6 +72,9 @@ pub fn write_compressed_metadata<'tcx>( let directive = format!(".section {}", section_name); llvm::LLVMSetModuleInlineAsm2(metadata_llmod, directive.as_ptr().cast(), directive.len()) } + + let svh = tcx.crate_hash(LOCAL_CRATE); + add_svh_symbol(tcx, &llvm_module, &svh); } pub struct ValueIter<'ll> { @@ -93,6 +98,42 @@ pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> { unsafe { ValueIter { cur: llvm::LLVMGetFirstGlobal(llmod), step: llvm::LLVMGetNextGlobal } } } +pub fn svh_symbol_name( + tcx: TyCtxt<'_>, + svh: &Svh, //, cgu_name: Symbol +) -> String { + format!("rust_svh_{}_{}", tcx.original_crate_name(LOCAL_CRATE), svh) +} + +fn add_svh_symbol(tcx: TyCtxt<'tcx>, llvm_module: &'ll ModuleLlvm, svh: &Svh) { + let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod()); + + let svh_bytes: Vec = format!("{}", svh).as_bytes().to_vec(); + let llconst = common::bytes_in_context(metadata_llcx, &svh_bytes); + let name = svh_symbol_name(tcx, &svh); //cgu_name + let buf = CString::new(name).unwrap(); + let llglobal = + unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) }; + unsafe { + llvm::LLVMSetInitializer(llglobal, llconst); + let section_name = + if tcx.sess.target.options.is_like_osx { "__DATA,.rust_svh" } else { ".rust_svh" }; + + let name = SmallCStr::new(§ion_name); + llvm::LLVMSetSection(llglobal, name.as_ptr()); + + // Also generate a .section directive to force no + // flags, at least for ELF outputs, so that the + // metadata doesn't get loaded into memory. + let directive = format!(".section {}", section_name); + llvm::LLVMRustAppendModuleInlineAsm( + metadata_llmod, + directive.as_ptr().cast(), + directive.len(), + ) + } +} + pub fn compile_codegen_unit( tcx: TyCtxt<'tcx>, cgu_name: Symbol, @@ -116,6 +157,7 @@ pub fn compile_codegen_unit( let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); { let cx = CodegenCx::new(tcx, cgu, &llvm_module); + let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx); for &(mono_item, (linkage, visibility)) in &mono_items { mono_item.predefine::>(&cx, linkage, visibility); diff --git a/compiler/rustc_codegen_llvm/src/metadata.rs b/compiler/rustc_codegen_llvm/src/metadata.rs index 3912d6a3a48b6..93875c075b052 100644 --- a/compiler/rustc_codegen_llvm/src/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/metadata.rs @@ -1,12 +1,11 @@ use crate::llvm; use crate::llvm::archive_ro::ArchiveRO; use crate::llvm::{mk_section_iter, False, ObjectFile}; -use rustc_middle::middle::cstore::MetadataLoader; -use rustc_target::spec::Target; - -use rustc_codegen_ssa::METADATA_FILENAME; +use rustc_codegen_ssa::{METADATA_FILE_EXTENSION, METADATA_FILE_PREFIX}; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::rustc_erase_owner; +use rustc_middle::middle::cstore::MetadataLoader; +use rustc_target::spec::Target; use tracing::debug; use rustc_fs_util::path_to_c_string; @@ -30,10 +29,19 @@ impl MetadataLoader for LlvmMetadataLoader { let buf: OwningRef<_, [u8]> = archive.try_map(|ar| { ar.iter() .filter_map(|s| s.ok()) - .find(|sect| sect.name() == Some(METADATA_FILENAME)) + .find(|sect| { + if let Some(n) = sect.name() { + n.starts_with(METADATA_FILE_PREFIX) && n.ends_with(METADATA_FILE_EXTENSION) + } else { + false + } + }) .map(|s| s.data()) .ok_or_else(|| { - debug!("didn't find '{}' in the archive", METADATA_FILENAME); + debug!( + "didn't find '{}*{}' in the archive", + METADATA_FILE_PREFIX, METADATA_FILE_EXTENSION + ); format!("failed to read rlib metadata: '{}'", filename.display()) }) })?; diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 5a627a0efa364..5ad3ae638c389 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,4 +1,5 @@ use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::svh::Svh; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; @@ -21,7 +22,10 @@ use super::archive::ArchiveBuilder; use super::command::Command; use super::linker::{self, Linker}; use super::rpath::{self, RPathConfig}; -use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME}; +use crate::{ + looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILE_EXTENSION, + METADATA_FILE_PREFIX, +}; use cc::windows_registry; use tempfile::Builder as TempFileBuilder; @@ -268,8 +272,16 @@ pub fn each_linked_rlib( /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a /// directory being searched for `extern crate` (observing an incomplete file). /// The returned path is the temporary file containing the complete metadata. -pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeTempDir) -> PathBuf { - let out_filename = tmpdir.as_ref().join(METADATA_FILENAME); +pub fn emit_metadata( + sess: &Session, + metadata: &EncodedMetadata, + tmpdir: &MaybeTempDir, + crate_name: &str, + svh: &Svh, +) -> PathBuf { + let out_filename = tmpdir + .as_ref() + .join(format!("{}{}-{}{}", METADATA_FILE_PREFIX, crate_name, svh, METADATA_FILE_EXTENSION)); let result = fs::write(&out_filename, &metadata.raw_data); if let Err(e) = result { @@ -358,7 +370,13 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( RlibFlavor::Normal => { // Instead of putting the metadata in an object file section, rlibs // contain the metadata in a separate file. - ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir)); + ab.add_file(&emit_metadata( + sess, + &codegen_results.metadata, + tmpdir, + &codegen_results.crate_name.as_str(), + &codegen_results.crate_hash, + )); // After adding all files to the archive, we need to update the // symbol table of the archive. This currently dies on macOS (see @@ -1912,7 +1930,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( let mut any_objects = false; for f in archive.src_files() { - if f == METADATA_FILENAME { + if f.starts_with(METADATA_FILE_PREFIX) && f.ends_with(METADATA_FILE_EXTENSION) { archive.remove_file(&f); continue; } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 9a6f8cde1b25d..3ea13f91701ef 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -9,7 +9,7 @@ use rustc_hir::Node; use rustc_index::vec::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{ - metadata_symbol_name, ExportedSymbol, SymbolExportLevel, + metadata_symbol_name, svh_symbol_name, ExportedSymbol, SymbolExportLevel, }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; @@ -218,6 +218,11 @@ fn exported_symbols_provider_local( let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); symbols.push((exported_symbol, SymbolExportLevel::Rust)); + + let symbol_name = svh_symbol_name(tcx); + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); + + symbols.push((exported_symbol, SymbolExportLevel::C)); } if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7f2bb7b5bcdaf..fe0b2fea57e82 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -13,6 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::profiling::TimingGuard; use rustc_data_structures::profiling::VerboseTimingGuard; +use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; use rustc_errors::{DiagnosticId, FatalError, Handler, Level}; @@ -414,6 +415,7 @@ pub fn start_async_codegen( let sess = tcx.sess; let crate_name = tcx.crate_name(LOCAL_CRATE); + let crate_hash = tcx.crate_hash(LOCAL_CRATE); let no_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins); let is_compiler_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::compiler_builtins); @@ -466,6 +468,7 @@ pub fn start_async_codegen( windows_subsystem, linker_info, crate_info, + crate_hash, coordinator_send, codegen_worker_receive, @@ -1712,6 +1715,7 @@ pub struct OngoingCodegen { pub windows_subsystem: Option, pub linker_info: LinkerInfo, pub crate_info: CrateInfo, + pub crate_hash: Svh, pub coordinator_send: Sender>, pub codegen_worker_receive: Receiver>, pub shared_emitter_main: SharedEmitterMain, @@ -1753,6 +1757,7 @@ impl OngoingCodegen { ( CodegenResults { crate_name: self.crate_name, + crate_hash: self.crate_hash, metadata: self.metadata, windows_subsystem: self.windows_subsystem, linker_info: self.linker_info, diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 70b92b234e94c..d34487bc319ab 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -21,6 +21,7 @@ extern crate tracing; extern crate rustc_middle; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; @@ -56,8 +57,8 @@ pub struct ModuleCodegen { pub kind: ModuleKind, } -// FIXME(eddyb) maybe include the crate name in this? -pub const METADATA_FILENAME: &str = "lib.rmeta"; +pub const METADATA_FILE_PREFIX: &str = "lib"; +pub const METADATA_FILE_EXTENSION: &str = ".rmeta"; impl ModuleCodegen { pub fn into_compiled_module( @@ -130,6 +131,7 @@ pub struct CrateInfo { #[derive(Encodable, Decodable)] pub struct CodegenResults { pub crate_name: Symbol, + pub crate_hash: Svh, pub modules: Vec, pub allocator_module: Option, pub metadata_module: Option, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 82cf4ab7f5c08..f2045a6469d46 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -7,6 +7,7 @@ use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::steal::Steal; +use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; @@ -33,7 +34,7 @@ use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; use rustc_session::Session; use rustc_span::symbol::Symbol; -use rustc_span::{FileName, RealFileName}; +use rustc_span::{FileName, RealFileName, SourceFile}; use rustc_trait_selection::traits; use rustc_typeck as typeck; use tracing::{info, warn}; @@ -526,6 +527,11 @@ fn escape_dep_env(symbol: Symbol) -> String { escaped } +enum FileHash { + SourceFile(Lrc), + BinaryHash(u64, String), +} + fn write_out_deps( sess: &Session, boxed_resolver: &Steal>>, @@ -541,34 +547,42 @@ fn write_out_deps( let result = (|| -> io::Result<()> { // Build a list of files used to compile the output and // write Makefile-compatible dependency rules - let mut files: Vec = sess - .source_map() - .files() + let source_files = sess.source_map().files(); + let mut files: Vec<(String, Option)> = source_files .iter() .filter(|fmap| fmap.is_real_file()) .filter(|fmap| !fmap.is_imported()) - .map(|fmap| escape_dep_filename(&fmap.unmapped_path.as_ref().unwrap_or(&fmap.name))) + .map(|fmap| { + ( + escape_dep_filename(&fmap.unmapped_path.as_ref().unwrap_or(&fmap.name)), + Some(FileHash::SourceFile(fmap.clone())), + ) + }) .collect(); if let Some(ref backend) = sess.opts.debugging_opts.codegen_backend { - files.push(backend.to_string()); + files.push((backend.to_string(), None)); // TO DO: is this something we need to hash? } if sess.binary_dep_depinfo() { boxed_resolver.borrow().borrow_mut().access(|resolver| { for cnum in resolver.cstore().crates_untracked() { let source = resolver.cstore().crate_source_untracked(cnum); + let svh = resolver.cstore().crate_hash_untracked(cnum); if let Some((path, _)) = source.dylib { + let hash = hash_bin(&path, &svh).ok(); let file_name = FileName::Real(RealFileName::Named(path)); - files.push(escape_dep_filename(&file_name)); + files.push((escape_dep_filename(&file_name), hash)); } if let Some((path, _)) = source.rlib { + let hash = hash_bin(&path, &svh).ok(); let file_name = FileName::Real(RealFileName::Named(path)); - files.push(escape_dep_filename(&file_name)); + files.push((escape_dep_filename(&file_name), hash)); } if let Some((path, _)) = source.rmeta { + let hash = hash_bin(&path, &svh).ok(); let file_name = FileName::Real(RealFileName::Named(path)); - files.push(escape_dep_filename(&file_name)); + files.push((escape_dep_filename(&file_name), hash)); } } }); @@ -576,14 +590,36 @@ fn write_out_deps( let mut file = BufWriter::new(fs::File::create(&deps_filename)?); for path in out_filenames { - writeln!(file, "{}: {}\n", path.display(), files.join(" "))?; + let line: Vec<&str> = files.iter().map(|(f, _)| f.as_ref()).collect(); + writeln!(file, "{}: {}\n", path.display(), line.join(" "))?; } // Emit a fake target for each input file to the compilation. This // prevents `make` from spitting out an error if a file is later // deleted. For more info see #28735 - for path in files { + for (path, file_hash) in files { writeln!(file, "{}:", path)?; + + match file_hash { + Some(FileHash::SourceFile(src_file)) => { + let bytes = src_file.src_hash.hash_bytes(); + let mut hash_as_hex = String::with_capacity(bytes.len() * 2); + for byte in bytes { + hash_as_hex.push_str(&format!("{:x}", byte)); + } + writeln!( + file, + "# size:{} {}:{}", + src_file.byte_length(), + src_file.src_hash.kind.to_string(), + hash_as_hex + )?; + } + Some(FileHash::BinaryHash(size, svh)) => { + writeln!(file, "# size:{} svh:{}", size, svh)?; + } + None => {} + } } // Emit special comments with information about accessed environment variables. @@ -623,6 +659,12 @@ fn write_out_deps( } } +fn hash_bin(path: &PathBuf, svh: &Svh) -> io::Result { + let size = fs::metadata(path)?.len(); + let svh_str = format!("{}", svh); + Ok(FileHash::BinaryHash(size, svh_str)) +} + pub fn prepare_outputs( sess: &Session, compiler: &Compiler, @@ -963,7 +1005,16 @@ fn encode_and_write_metadata( .tempdir_in(out_filename.parent().unwrap()) .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))); let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); - let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir); + + let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str(); + + let metadata_filename = emit_metadata( + tcx.sess, + &metadata, + &metadata_tmpdir, + &crate_name, + &tcx.crate_hash(LOCAL_CRATE), + ); if let Err(e) = fs::rename(&metadata_filename, &out_filename) { tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); } diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index c4c025de8b3c4..8a70d8c7ec725 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -644,6 +644,9 @@ impl<'a> CrateLocator<'a> { } let hash = root.hash(); + assert_eq!(Some(hash), metadata.get_svh()); + // FIXME: we could move this earlier and check against the + // metadata hash as we could reject without decompressing the metadata blob. if let Some(expected_hash) = self.hash { if hash != expected_hash { info!("Rejecting via hash: expected {} got {}", expected_hash, hash); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index a1df1a63fc58d..993eee6c12978 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -594,15 +594,39 @@ impl MetadataBlob { } crate fn get_rustc_version(&self) -> String { - Lazy::::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap()) + if self.is_compatible() { + Lazy::::from_position( + NonZeroUsize::new(METADATA_HEADER.len() + 4 + 1 + mem::size_of::<[u8; 64]>()) + .unwrap(), + ) .decode(self) + } else { + // Assume older... + Lazy::::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap()) + .decode(self) + } + } + + //used only by an assert? + crate fn get_svh(&self) -> Option { + if !self.is_compatible() { + return None; + } + let hash = + Lazy::<[u8; 64]>::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap()) + .decode(self); + + // Currently only the first 8 bytes are in use of the svh + let mut smol_hash = [0_u8; 8]; + smol_hash.copy_from_slice(&hash[..8]); + Some(Svh::new(u64::from_le_bytes(smol_hash))) } crate fn get_root(&self) -> CrateRoot<'tcx> { let slice = self.raw_bytes(); let offset = METADATA_HEADER.len(); let pos = (((slice[offset + 0] as u32) << 24) - | ((slice[offset + 1] as u32) << 16) + | ((slice[offset + 1] as u32) << 16)//TO DO replace with just one function call? | ((slice[offset + 2] as u32) << 8) | ((slice[offset + 3] as u32) << 0)) as usize; Lazy::>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a7cf1079b8fe4..83f9f3f7d8332 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -19,7 +19,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ - metadata_symbol_name, ExportedSymbol, SymbolExportLevel, + metadata_symbol_name, svh_symbol_name, ExportedSymbol, SymbolExportLevel, }; use rustc_middle::mir::interpret; use rustc_middle::traits::specialization_graph; @@ -1669,12 +1669,15 @@ impl EncodeContext<'a, 'tcx> { // The metadata symbol name is special. It should not show up in // downstream crates. let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx)); + let svh_symbol_name = SymbolName::new(self.tcx, &svh_symbol_name(self.tcx)); self.lazy( exported_symbols .iter() .filter(|&&(ref exported_symbol, _)| match *exported_symbol { - ExportedSymbol::NoDefId(symbol_name) => symbol_name != metadata_symbol_name, + ExportedSymbol::NoDefId(symbol_name) => { + symbol_name != metadata_symbol_name && symbol_name != svh_symbol_name + } _ => true, }) .cloned(), @@ -2063,6 +2066,9 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { hygiene_ctxt: &hygiene_ctxt, }; + // Encode the crate's svh hash in a predictable location for cargo. + crate_svh(tcx).encode(&mut ecx).unwrap(); + // Encode the rustc version string in a predictable location. rustc_version().encode(&mut ecx).unwrap(); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 2bd2019d3cdb5..3d94fccede6f5 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -7,7 +7,7 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; use rustc_hir as hir; use rustc_hir::def::CtorKind; -use rustc_hir::def_id::{DefId, DefIndex, DefPathHash}; +use rustc_hir::def_id::{DefId, DefIndex, DefPathHash, LOCAL_CRATE}; use rustc_hir::definitions::DefKey; use rustc_hir::lang_items; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; @@ -15,7 +15,7 @@ use rustc_middle::hir::exports::Export; use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; -use rustc_middle::ty::{self, ReprOptions, Ty}; +use rustc_middle::ty::{self, ReprOptions, Ty, TyCtxt}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; use rustc_session::CrateDisambiguator; @@ -41,16 +41,23 @@ crate fn rustc_version() -> String { format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version")) } +crate fn crate_svh(tcx: TyCtxt<'_>) -> [u8; 64] { + let mut svh = [0; 64]; // 512bits for future expansion of svh size. + let svh_front = &mut svh[0..8]; + svh_front.copy_from_slice(&tcx.crate_hash(LOCAL_CRATE).as_u64().to_le_bytes()); + svh +} + /// Metadata encoding version. /// N.B., increment this if you change the format of metadata such that /// the rustc version can't be found to compare with `rustc_version()`. -const METADATA_VERSION: u8 = 5; +const METADATA_VERSION: u8 = 6; /// Metadata header which includes `METADATA_VERSION`. /// /// This header is followed by the position of the `CrateRoot`, /// which is encoded as a 32-bit big-endian unsigned integer, -/// and further followed by the rustc version string. +/// and further followed by the rustc version string and the svh. crate const METADATA_HEADER: &[u8; 8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION]; /// Additional metadata for a `Lazy` where `T` may not be `Sized`, diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 276e45ce99b29..ed8e4faac821d 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -53,3 +53,8 @@ pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String { tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex() ) } + +/// Embed the hash that represents the crate for use as a fingerprint. +pub fn svh_symbol_name(tcx: TyCtxt<'_>) -> String { + format!("rust_svh_{}_{}", tcx.original_crate_name(LOCAL_CRATE), tcx.crate_hash(LOCAL_CRATE)) +} diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 0926561f4c513..3fb9a06286118 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -50,7 +50,7 @@ use rustc_data_structures::sync::{Lock, Lrc}; use std::borrow::Cow; use std::cell::RefCell; use std::cmp::{self, Ordering}; -use std::fmt; +use std::fmt::{self, Display}; use std::hash::Hash; use std::ops::{Add, Range, Sub}; use std::path::{Path, PathBuf}; @@ -1038,6 +1038,16 @@ pub enum SourceFileHashAlgorithm { Sha256, } +impl Display for SourceFileHashAlgorithm { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SourceFileHashAlgorithm::Md5 => write!(f, "md5"), + SourceFileHashAlgorithm::Sha1 => write!(f, "sha1"), + SourceFileHashAlgorithm::Sha256 => write!(f, "sha256"), + } + } +} + impl FromStr for SourceFileHashAlgorithm { type Err = (); diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index 0e1bef6f68d53..860d2c9991b3d 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -60,6 +60,7 @@ impl CodegenBackend for TheBackend { Box::new(CodegenResults { crate_name: tcx.crate_name(LOCAL_CRATE), + crate_hash: tcx.crate_hash(LOCAL_CRATE), modules: vec![], allocator_module: None, metadata_module: None,