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