@@ -387,7 +387,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
387387 return Ok ( DUMMY_SP ) ;
388388 }
389389
390- debug_assert_eq ! ( tag, TAG_VALID_SPAN ) ;
390+ debug_assert ! ( tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN ) ;
391391
392392 let lo = BytePos :: decode ( self ) ?;
393393 let len = BytePos :: decode ( self ) ?;
@@ -399,7 +399,68 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
399399 bug ! ( "Cannot decode Span without Session." )
400400 } ;
401401
402- let imported_source_files = self . cdata ( ) . imported_source_files ( & sess. source_map ( ) ) ;
402+ // There are two possibilities here:
403+ // 1. This is a 'local span', which is located inside a `SourceFile`
404+ // that came from this crate. In this case, we use the source map data
405+ // encoded in this crate. This branch should be taken nearly all of the time.
406+ // 2. This is a 'foreign span', which is located inside a `SourceFile`
407+ // that came from a *different* crate (some crate upstream of the one
408+ // whose metadata we're looking at). For example, consider this dependency graph:
409+ //
410+ // A -> B -> C
411+ //
412+ // Suppose that we're currently compiling crate A, and start deserializing
413+ // metadata from crate B. When we deserialize a Span from crate B's metadata,
414+ // there are two posibilites:
415+ //
416+ // 1. The span references a file from crate B. This makes it a 'local' span,
417+ // which means that we can use crate B's serialized source map information.
418+ // 2. The span references a file from crate C. This makes it a 'foreign' span,
419+ // which means we need to use Crate *C* (not crate B) to determine the source
420+ // map information. We only record source map information for a file in the
421+ // crate that 'owns' it, so deserializing a Span may require us to look at
422+ // a transitive dependency.
423+ //
424+ // When we encode a foreign span, we adjust its 'lo' and 'high' values
425+ // to be based on the *foreign* crate (e.g. crate C), not the crate
426+ // we are writing metadata for (e.g. crate B). This allows us to
427+ // treat the 'local' and 'foreign' cases almost identically during deserialization:
428+ // we can call `imported_source_files` for the proper crate, and binary search
429+ // through the returned slice using our span.
430+ let imported_source_files = if tag == TAG_VALID_SPAN_LOCAL {
431+ self . cdata ( ) . imported_source_files ( sess. source_map ( ) )
432+ } else {
433+ // FIXME: We don't decode dependencies of proc-macros.
434+ // Remove this once #69976 is merged
435+ if self . cdata ( ) . root . is_proc_macro_crate ( ) {
436+ debug ! (
437+ "SpecializedDecoder<Span>::specialized_decode: skipping span for proc-macro crate {:?}" ,
438+ self . cdata( ) . cnum
439+ ) ;
440+ // Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE
441+ // since we don't have `cnum_map` populated.
442+ // This advances the decoder position so that we can continue
443+ // to read metadata.
444+ let _ = u32:: decode ( self ) ?;
445+ return Ok ( DUMMY_SP ) ;
446+ }
447+ // tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above
448+ let cnum = CrateNum :: decode ( self ) ?;
449+ debug ! (
450+ "SpecializedDecoder<Span>::specialized_decode: loading source files from cnum {:?}" ,
451+ cnum
452+ ) ;
453+
454+ // Decoding 'foreign' spans should be rare enough that it's
455+ // not worth it to maintain a per-CrateNum cache for `last_source_file_index`.
456+ // We just set it to 0, to ensure that we don't try to access something out
457+ // of bounds for our initial 'guess'
458+ self . last_source_file_index = 0 ;
459+
460+ let foreign_data = self . cdata ( ) . cstore . get_crate_data ( cnum) ;
461+ foreign_data. imported_source_files ( sess. source_map ( ) )
462+ } ;
463+
403464 let source_file = {
404465 // Optimize for the case that most spans within a translated item
405466 // originate from the same source_file.
@@ -413,16 +474,32 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
413474 . binary_search_by_key ( & lo, |source_file| source_file. original_start_pos )
414475 . unwrap_or_else ( |index| index - 1 ) ;
415476
416- self . last_source_file_index = index;
477+ // Don't try to cache the index for foreign spans,
478+ // as this would require a map from CrateNums to indices
479+ if tag == TAG_VALID_SPAN_LOCAL {
480+ self . last_source_file_index = index;
481+ }
417482 & imported_source_files[ index]
418483 }
419484 } ;
420485
421486 // Make sure our binary search above is correct.
422- debug_assert ! ( lo >= source_file. original_start_pos && lo <= source_file. original_end_pos) ;
487+ debug_assert ! (
488+ lo >= source_file. original_start_pos && lo <= source_file. original_end_pos,
489+ "Bad binary search: lo={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}" ,
490+ lo,
491+ source_file. original_start_pos,
492+ source_file. original_end_pos
493+ ) ;
423494
424495 // Make sure we correctly filtered out invalid spans during encoding
425- debug_assert ! ( hi >= source_file. original_start_pos && hi <= source_file. original_end_pos) ;
496+ debug_assert ! (
497+ hi >= source_file. original_start_pos && hi <= source_file. original_end_pos,
498+ "Bad binary search: hi={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}" ,
499+ hi,
500+ source_file. original_start_pos,
501+ source_file. original_end_pos
502+ ) ;
426503
427504 let lo =
428505 ( lo + source_file. translated_source_file . start_pos ) - source_file. original_start_pos ;
@@ -1424,14 +1501,16 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
14241501 let local_version = local_source_map. new_imported_source_file (
14251502 name,
14261503 name_was_remapped,
1427- self . cnum . as_u32 ( ) ,
14281504 src_hash,
14291505 name_hash,
14301506 source_length,
1507+ self . cnum ,
14311508 lines,
14321509 multibyte_chars,
14331510 non_narrow_chars,
14341511 normalized_pos,
1512+ start_pos,
1513+ end_pos,
14351514 ) ;
14361515 debug ! (
14371516 "CrateMetaData::imported_source_files alloc \
0 commit comments