diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index e06d1d245b23f..2802f44cda75d 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -676,6 +676,7 @@ fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dy metadata_loader, &mut v, &sess.opts.unstable_opts.ls, + sess.cfg_version, ) .unwrap(); safe_println!("{}", String::from_utf8(v).unwrap()); diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index dcccace12b00a..10bbebb3871e3 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -569,31 +569,47 @@ impl<'a> CrateLocator<'a> { debug!("skipping empty file"); continue; } - let (hash, metadata) = - match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) { - Ok(blob) => { - if let Some(h) = self.crate_matches(&blob, &lib) { - (h, blob) - } else { - info!("metadata mismatch"); - continue; - } - } - Err(MetadataError::LoadFailure(err)) => { - info!("no metadata found: {}", err); - // The file was present and created by the same compiler version, but we - // couldn't load it for some reason. Give a hard error instead of silently - // ignoring it, but only if we would have given an error anyway. - self.crate_rejections - .via_invalid - .push(CrateMismatch { path: lib, got: err }); - continue; - } - Err(err @ MetadataError::NotPresent(_)) => { - info!("no metadata found: {}", err); + let (hash, metadata) = match get_metadata_section( + self.target, + flavor, + &lib, + self.metadata_loader, + self.cfg_version, + ) { + Ok(blob) => { + if let Some(h) = self.crate_matches(&blob, &lib) { + (h, blob) + } else { + info!("metadata mismatch"); continue; } - }; + } + Err(MetadataError::VersionMismatch { expected_version, found_version }) => { + // The file was present and created by the same compiler version, but we + // couldn't load it for some reason. Give a hard error instead of silently + // ignoring it, but only if we would have given an error anyway. + info!( + "Rejecting via version: expected {} got {}", + expected_version, found_version + ); + self.crate_rejections + .via_version + .push(CrateMismatch { path: lib, got: found_version }); + continue; + } + Err(MetadataError::LoadFailure(err)) => { + info!("no metadata found: {}", err); + // The file was present and created by the same compiler version, but we + // couldn't load it for some reason. Give a hard error instead of silently + // ignoring it, but only if we would have given an error anyway. + self.crate_rejections.via_invalid.push(CrateMismatch { path: lib, got: err }); + continue; + } + Err(err @ MetadataError::NotPresent(_)) => { + info!("no metadata found: {}", err); + continue; + } + }; // If we see multiple hashes, emit an error about duplicate candidates. if slot.as_ref().is_some_and(|s| s.0 != hash) { if let Some(candidates) = err_data { @@ -648,16 +664,6 @@ impl<'a> CrateLocator<'a> { } fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option { - let rustc_version = rustc_version(self.cfg_version); - let found_version = metadata.get_rustc_version(); - if found_version != rustc_version { - info!("Rejecting via version: expected {} got {}", rustc_version, found_version); - self.crate_rejections - .via_version - .push(CrateMismatch { path: libpath.to_path_buf(), got: found_version }); - return None; - } - let header = metadata.get_header(); if header.is_proc_macro_crate != self.is_proc_macro { info!( @@ -770,6 +776,7 @@ fn get_metadata_section<'p>( flavor: CrateFlavor, filename: &'p Path, loader: &dyn MetadataLoader, + cfg_version: &'static str, ) -> Result> { if !filename.exists() { return Err(MetadataError::NotPresent(filename)); @@ -847,13 +854,18 @@ fn get_metadata_section<'p>( } }; let blob = MetadataBlob(raw_bytes); - if blob.is_compatible() { - Ok(blob) - } else { - Err(MetadataError::LoadFailure(format!( + match blob.check_compatibility(cfg_version) { + Ok(()) => Ok(blob), + Err(None) => Err(MetadataError::LoadFailure(format!( "invalid metadata version found: {}", filename.display() - ))) + ))), + Err(Some(found_version)) => { + return Err(MetadataError::VersionMismatch { + expected_version: rustc_version(cfg_version), + found_version, + }); + } } } @@ -864,9 +876,10 @@ pub fn list_file_metadata( metadata_loader: &dyn MetadataLoader, out: &mut dyn Write, ls_kinds: &[String], + cfg_version: &'static str, ) -> IoResult<()> { let flavor = get_flavor_from_path(path); - match get_metadata_section(target, flavor, path, metadata_loader) { + match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) { Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds), Err(msg) => write!(out, "{msg}\n"), } @@ -932,6 +945,8 @@ enum MetadataError<'a> { NotPresent(&'a Path), /// The file was present and invalid. LoadFailure(String), + /// The file was present, but compiled with a different rustc version. + VersionMismatch { expected_version: String, found_version: String }, } impl fmt::Display for MetadataError<'_> { @@ -941,6 +956,12 @@ impl fmt::Display for MetadataError<'_> { f.write_str(&format!("no such file: '{}'", filename.display())) } MetadataError::LoadFailure(msg) => f.write_str(msg), + MetadataError::VersionMismatch { expected_version, found_version } => { + f.write_str(&format!( + "rustc version mismatch. expected {}, found {}", + expected_version, found_version, + )) + } } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index da384007c22c2..0467cf2969fc5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -684,13 +684,25 @@ impl<'a, 'tcx, I: Idx, T> Decodable> for LazyTable implement_ty_decoder!(DecodeContext<'a, 'tcx>); impl MetadataBlob { - pub(crate) fn is_compatible(&self) -> bool { - self.blob().starts_with(METADATA_HEADER) - } + pub(crate) fn check_compatibility( + &self, + cfg_version: &'static str, + ) -> Result<(), Option> { + if !self.blob().starts_with(METADATA_HEADER) { + if self.blob().starts_with(b"rust") { + return Err(Some("".to_owned())); + } + return Err(None); + } - pub(crate) fn get_rustc_version(&self) -> String { - LazyValue::::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap()) - .decode(self) + let found_version = + LazyValue::::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap()) + .decode(self); + if rustc_version(cfg_version) != found_version { + return Err(Some(found_version)); + } + + Ok(()) } fn root_pos(&self) -> NonZero {