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