213213//! metadata::loader or metadata::creader for all the juicy details!
214214
215215use cstore:: { MetadataBlob , MetadataVec , MetadataArchive } ;
216+ use common:: { metadata_encoding_version, rustc_version} ;
216217use decoder;
217- use encoder;
218218
219219use rustc:: hir:: svh:: Svh ;
220220use rustc:: session:: Session ;
@@ -260,6 +260,7 @@ pub struct Context<'a> {
260260 pub rejected_via_hash : Vec < CrateMismatch > ,
261261 pub rejected_via_triple : Vec < CrateMismatch > ,
262262 pub rejected_via_kind : Vec < CrateMismatch > ,
263+ pub rejected_via_version : Vec < CrateMismatch > ,
263264 pub should_match_name : bool ,
264265}
265266
@@ -336,6 +337,10 @@ impl<'a> Context<'a> {
336337 struct_span_err ! ( self . sess, self . span, E0462 ,
337338 "found staticlib `{}` instead of rlib or dylib{}" ,
338339 self . ident, add)
340+ } else if !self . rejected_via_version . is_empty ( ) {
341+ struct_span_err ! ( self . sess, self . span, E0514 ,
342+ "found crate `{}` compiled by an incompatible version of rustc{}" ,
343+ self . ident, add)
339344 } else {
340345 struct_span_err ! ( self . sess, self . span, E0463 ,
341346 "can't find crate for `{}`{}" ,
@@ -350,7 +355,7 @@ impl<'a> Context<'a> {
350355 }
351356 }
352357 if !self . rejected_via_hash . is_empty ( ) {
353- err. note ( "perhaps this crate needs to be recompiled?" ) ;
358+ err. note ( "perhaps that crate needs to be recompiled?" ) ;
354359 let mismatches = self . rejected_via_hash . iter ( ) ;
355360 for ( i, & CrateMismatch { ref path, .. } ) in mismatches. enumerate ( ) {
356361 err. note ( & format ! ( "crate `{}` path #{}: {}" ,
@@ -367,13 +372,22 @@ impl<'a> Context<'a> {
367372 }
368373 }
369374 if !self . rejected_via_kind . is_empty ( ) {
370- err. help ( "please recompile this crate using --crate-type lib" ) ;
375+ err. help ( "please recompile that crate using --crate-type lib" ) ;
371376 let mismatches = self . rejected_via_kind . iter ( ) ;
372377 for ( i, & CrateMismatch { ref path, .. } ) in mismatches. enumerate ( ) {
373378 err. note ( & format ! ( "crate `{}` path #{}: {}" ,
374379 self . ident, i+1 , path. display( ) ) ) ;
375380 }
376381 }
382+ if !self . rejected_via_version . is_empty ( ) {
383+ err. help ( & format ! ( "please recompile that crate using this compiler ({})" ,
384+ rustc_version( ) ) ) ;
385+ let mismatches = self . rejected_via_version . iter ( ) ;
386+ for ( i, & CrateMismatch { ref path, ref got } ) in mismatches. enumerate ( ) {
387+ err. note ( & format ! ( "crate `{}` path #{}: {} compiled by {:?}" ,
388+ self . ident, i+1 , path. display( ) , got) ) ;
389+ }
390+ }
377391
378392 err. emit ( ) ;
379393 self . sess . abort_if_errors ( ) ;
@@ -591,6 +605,17 @@ impl<'a> Context<'a> {
591605 }
592606
593607 fn crate_matches ( & mut self , crate_data : & [ u8 ] , libpath : & Path ) -> Option < Svh > {
608+ let crate_rustc_version = decoder:: crate_rustc_version ( crate_data) ;
609+ if crate_rustc_version != Some ( rustc_version ( ) ) {
610+ let message = crate_rustc_version. unwrap_or ( format ! ( "an unknown compiler" ) ) ;
611+ info ! ( "Rejecting via version: expected {} got {}" , rustc_version( ) , message) ;
612+ self . rejected_via_version . push ( CrateMismatch {
613+ path : libpath. to_path_buf ( ) ,
614+ got : message
615+ } ) ;
616+ return None ;
617+ }
618+
594619 if self . should_match_name {
595620 match decoder:: maybe_get_crate_name ( crate_data) {
596621 Some ( ref name) if self . crate_name == * name => { }
@@ -742,6 +767,21 @@ impl ArchiveMetadata {
742767 pub fn as_slice < ' a > ( & ' a self ) -> & ' a [ u8 ] { unsafe { & * self . data } }
743768}
744769
770+ fn verify_decompressed_encoding_version ( blob : & MetadataBlob , filename : & Path )
771+ -> Result < ( ) , String >
772+ {
773+ let data = blob. as_slice_raw ( ) ;
774+ if data. len ( ) < 4 +metadata_encoding_version. len ( ) ||
775+ !<[ u8 ] >:: eq ( & data[ ..4 ] , & [ 0 , 0 , 0 , 0 ] ) ||
776+ & data[ 4 ..4 +metadata_encoding_version. len ( ) ] != metadata_encoding_version
777+ {
778+ Err ( ( format ! ( "incompatible metadata version found: '{}'" ,
779+ filename. display( ) ) ) )
780+ } else {
781+ Ok ( ( ) )
782+ }
783+ }
784+
745785// Just a small wrapper to time how long reading metadata takes.
746786fn get_metadata_section ( target : & Target , flavor : CrateFlavor , filename : & Path )
747787 -> Result < MetadataBlob , String > {
@@ -772,7 +812,10 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
772812 return match ArchiveMetadata :: new ( archive) . map ( |ar| MetadataArchive ( ar) ) {
773813 None => Err ( format ! ( "failed to read rlib metadata: '{}'" ,
774814 filename. display( ) ) ) ,
775- Some ( blob) => Ok ( blob)
815+ Some ( blob) => {
816+ try!( verify_decompressed_encoding_version ( & blob, filename) ) ;
817+ Ok ( blob)
818+ }
776819 } ;
777820 }
778821 unsafe {
@@ -801,12 +844,12 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
801844 let cbuf = llvm:: LLVMGetSectionContents ( si. llsi ) ;
802845 let csz = llvm:: LLVMGetSectionSize ( si. llsi ) as usize ;
803846 let cvbuf: * const u8 = cbuf as * const u8 ;
804- let vlen = encoder :: metadata_encoding_version. len ( ) ;
847+ let vlen = metadata_encoding_version. len ( ) ;
805848 debug ! ( "checking {} bytes of metadata-version stamp" ,
806849 vlen) ;
807850 let minsz = cmp:: min ( vlen, csz) ;
808851 let buf0 = slice:: from_raw_parts ( cvbuf, minsz) ;
809- let version_ok = buf0 == encoder :: metadata_encoding_version;
852+ let version_ok = buf0 == metadata_encoding_version;
810853 if !version_ok {
811854 return Err ( ( format ! ( "incompatible metadata version found: '{}'" ,
812855 filename. display( ) ) ) ) ;
@@ -817,7 +860,11 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
817860 csz - vlen) ;
818861 let bytes = slice:: from_raw_parts ( cvbuf1, csz - vlen) ;
819862 match flate:: inflate_bytes ( bytes) {
820- Ok ( inflated) => return Ok ( MetadataVec ( inflated) ) ,
863+ Ok ( inflated) => {
864+ let blob = MetadataVec ( inflated) ;
865+ try!( verify_decompressed_encoding_version ( & blob, filename) ) ;
866+ return Ok ( blob) ;
867+ }
821868 Err ( _) => { }
822869 }
823870 }
0 commit comments