@@ -387,7 +387,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
387
387
return Ok ( DUMMY_SP ) ;
388
388
}
389
389
390
- debug_assert_eq ! ( tag, TAG_VALID_SPAN ) ;
390
+ debug_assert ! ( tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN ) ;
391
391
392
392
let lo = BytePos :: decode ( self ) ?;
393
393
let len = BytePos :: decode ( self ) ?;
@@ -399,7 +399,68 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
399
399
bug ! ( "Cannot decode Span without Session." )
400
400
} ;
401
401
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
+
403
464
let source_file = {
404
465
// Optimize for the case that most spans within a translated item
405
466
// originate from the same source_file.
@@ -413,16 +474,32 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
413
474
. binary_search_by_key ( & lo, |source_file| source_file. original_start_pos )
414
475
. unwrap_or_else ( |index| index - 1 ) ;
415
476
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
+ }
417
482
& imported_source_files[ index]
418
483
}
419
484
} ;
420
485
421
486
// 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
+ ) ;
423
494
424
495
// 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
+ ) ;
426
503
427
504
let lo =
428
505
( lo + source_file. translated_source_file . start_pos ) - source_file. original_start_pos ;
@@ -1424,14 +1501,16 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
1424
1501
let local_version = local_source_map. new_imported_source_file (
1425
1502
name,
1426
1503
name_was_remapped,
1427
- self . cnum . as_u32 ( ) ,
1428
1504
src_hash,
1429
1505
name_hash,
1430
1506
source_length,
1507
+ self . cnum ,
1431
1508
lines,
1432
1509
multibyte_chars,
1433
1510
non_narrow_chars,
1434
1511
normalized_pos,
1512
+ start_pos,
1513
+ end_pos,
1435
1514
) ;
1436
1515
debug ! (
1437
1516
"CrateMetaData::imported_source_files alloc \
0 commit comments