@@ -16,6 +16,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
16
16
use rustc_hir:: itemlikevisit:: { ItemLikeVisitor , ParItemLikeVisitor } ;
17
17
use rustc_hir:: lang_items;
18
18
use rustc_hir:: { AnonConst , GenericParamKind } ;
19
+ use rustc_index:: bit_set:: GrowableBitSet ;
19
20
use rustc_index:: vec:: Idx ;
20
21
use rustc_middle:: hir:: map:: Map ;
21
22
use rustc_middle:: middle:: cstore:: { EncodedMetadata , ForeignModule , LinkagePreference , NativeLib } ;
@@ -51,7 +52,20 @@ struct EncodeContext<'tcx> {
51
52
interpret_allocs_inverse : Vec < interpret:: AllocId > ,
52
53
53
54
// This is used to speed up Span encoding.
54
- source_file_cache : Lrc < SourceFile > ,
55
+ // The `usize` is an index into the `MonotonicVec`
56
+ // that stores the `SourceFile`
57
+ source_file_cache : ( Lrc < SourceFile > , usize ) ,
58
+ // The indices (into the `SourceMap`'s `MonotonicVec`)
59
+ // of all of the `SourceFiles` that we need to serialize.
60
+ // When we serialize a `Span`, we insert the index of its
61
+ // `SourceFile` into the `GrowableBitSet`.
62
+ //
63
+ // This needs to be a `GrowableBitSet` and not a
64
+ // regular `BitSet` because we may actually import new `SourceFiles`
65
+ // during metadata encoding, due to executing a query
66
+ // with a result containing a foreign `Span`.
67
+ required_source_files : Option < GrowableBitSet < usize > > ,
68
+ is_proc_macro : bool ,
55
69
}
56
70
57
71
macro_rules! encoder_methods {
@@ -154,18 +168,23 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
154
168
// The Span infrastructure should make sure that this invariant holds:
155
169
debug_assert ! ( span. lo <= span. hi) ;
156
170
157
- if !self . source_file_cache . contains ( span. lo ) {
171
+ if !self . source_file_cache . 0 . contains ( span. lo ) {
158
172
let source_map = self . tcx . sess . source_map ( ) ;
159
173
let source_file_index = source_map. lookup_source_file_idx ( span. lo ) ;
160
- self . source_file_cache = source_map. files ( ) [ source_file_index] . clone ( ) ;
174
+ self . source_file_cache =
175
+ ( source_map. files ( ) [ source_file_index] . clone ( ) , source_file_index) ;
161
176
}
162
177
163
- if !self . source_file_cache . contains ( span. hi ) {
178
+ if !self . source_file_cache . 0 . contains ( span. hi ) {
164
179
// Unfortunately, macro expansion still sometimes generates Spans
165
180
// that malformed in this way.
166
181
return TAG_INVALID_SPAN . encode ( self ) ;
167
182
}
168
183
184
+ let source_files = self . required_source_files . as_mut ( ) . expect ( "Already encoded SourceMap!" ) ;
185
+ // Record the fact that we need to encode the data for this `SourceFile`
186
+ source_files. insert ( self . source_file_cache . 1 ) ;
187
+
169
188
// There are two possible cases here:
170
189
// 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the
171
190
// crate we are writing metadata for. When the metadata for *this* crate gets
@@ -176,7 +195,13 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
176
195
// 2. This span comes from our own crate. No special hamdling is needed - we just
177
196
// write `TAG_VALID_SPAN_LOCAL` to let the deserializer know that it should use
178
197
// our own source map information.
179
- let ( tag, lo, hi) = if self . source_file_cache . is_imported ( ) {
198
+ //
199
+ // If we're a proc-macro crate, we always treat this as a local `Span`.
200
+ // In `encode_source_map`, we serialize foreign `SourceFile`s into our metadata
201
+ // if we're a proc-macro crate.
202
+ // This allows us to avoid loading the dependencies of proc-macro crates: all of
203
+ // the information we need to decode `Span`s is stored in the proc-macro crate.
204
+ let ( tag, lo, hi) = if self . source_file_cache . 0 . is_imported ( ) && !self . is_proc_macro {
180
205
// To simplify deserialization, we 'rebase' this span onto the crate it originally came from
181
206
// (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values
182
207
// are relative to the source map information for the 'foreign' crate whose CrateNum
@@ -188,13 +213,13 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
188
213
// Span that can be used without any additional trouble.
189
214
let external_start_pos = {
190
215
// Introduce a new scope so that we drop the 'lock()' temporary
191
- match & * self . source_file_cache . external_src . lock ( ) {
216
+ match & * self . source_file_cache . 0 . external_src . lock ( ) {
192
217
ExternalSource :: Foreign { original_start_pos, .. } => * original_start_pos,
193
218
src => panic ! ( "Unexpected external source {:?}" , src) ,
194
219
}
195
220
} ;
196
- let lo = ( span. lo - self . source_file_cache . start_pos ) + external_start_pos;
197
- let hi = ( span. hi - self . source_file_cache . start_pos ) + external_start_pos;
221
+ let lo = ( span. lo - self . source_file_cache . 0 . start_pos ) + external_start_pos;
222
+ let hi = ( span. hi - self . source_file_cache . 0 . start_pos ) + external_start_pos;
198
223
199
224
( TAG_VALID_SPAN_FOREIGN , lo, hi)
200
225
} else {
@@ -212,7 +237,7 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
212
237
if tag == TAG_VALID_SPAN_FOREIGN {
213
238
// This needs to be two lines to avoid holding the `self.source_file_cache`
214
239
// while calling `cnum.encode(self)`
215
- let cnum = self . source_file_cache . cnum ;
240
+ let cnum = self . source_file_cache . 0 . cnum ;
216
241
cnum. encode ( self ) ?;
217
242
}
218
243
Ok ( ( ) )
@@ -386,17 +411,24 @@ impl<'tcx> EncodeContext<'tcx> {
386
411
let all_source_files = source_map. files ( ) ;
387
412
388
413
let ( working_dir, _cwd_remapped) = self . tcx . sess . working_dir . clone ( ) ;
414
+ // By replacing the `Option` with `None`, we ensure that we can't
415
+ // accidentally serialize any more `Span`s after the source map encoding
416
+ // is done.
417
+ let required_source_files = self . required_source_files . take ( ) . unwrap ( ) ;
389
418
390
419
let adapted = all_source_files
391
420
. iter ( )
392
- . filter ( |source_file| {
393
- // No need to re-export imported source_files, as any downstream
394
- // crate will import them from their original source.
395
- // FIXME(eddyb) the `Span` encoding should take that into account.
396
- !source_file. is_imported ( )
421
+ . enumerate ( )
422
+ . filter ( |( idx, source_file) | {
423
+ // Only serialize `SourceFile`s that were used
424
+ // during the encoding of a `Span`
425
+ required_source_files. contains ( * idx) &&
426
+ // Don't serialize imported `SourceFile`s, unless
427
+ // we're in a proc-macro crate.
428
+ ( !source_file. is_imported ( ) || self . is_proc_macro )
397
429
} )
398
- . map ( |source_file| {
399
- match source_file. name {
430
+ . map ( |( _ , source_file) | {
431
+ let mut adapted = match source_file. name {
400
432
// This path of this SourceFile has been modified by
401
433
// path-remapping, so we use it verbatim (and avoid
402
434
// cloning the whole map in the process).
@@ -419,15 +451,30 @@ impl<'tcx> EncodeContext<'tcx> {
419
451
420
452
// expanded code, not from a file
421
453
_ => source_file. clone ( ) ,
454
+ } ;
455
+
456
+ // We're serializing this `SourceFile` into our crate metadata,
457
+ // so mark it as coming from this crate.
458
+ // This also ensures that we don't try to deserialize the
459
+ // `CrateNum` for a proc-macro dependency - since proc macro
460
+ // dependencies aren't loaded when we deserialize a proc-macro,
461
+ // trying to remap the `CrateNum` would fail.
462
+ if self . is_proc_macro {
463
+ Lrc :: make_mut ( & mut adapted) . cnum = LOCAL_CRATE ;
422
464
}
465
+ adapted
423
466
} )
424
467
. collect :: < Vec < _ > > ( ) ;
425
468
426
469
self . lazy ( adapted. iter ( ) . map ( |rc| & * * rc) )
427
470
}
428
471
472
+ fn is_proc_macro ( & self ) -> bool {
473
+ self . tcx . sess . crate_types ( ) . contains ( & CrateType :: ProcMacro )
474
+ }
475
+
429
476
fn encode_crate_root ( & mut self ) -> Lazy < CrateRoot < ' tcx > > {
430
- let is_proc_macro = self . tcx . sess . crate_types ( ) . contains ( & CrateType :: ProcMacro ) ;
477
+ let is_proc_macro = self . is_proc_macro ( ) ;
431
478
432
479
let mut i = self . position ( ) ;
433
480
@@ -458,11 +505,6 @@ impl<'tcx> EncodeContext<'tcx> {
458
505
459
506
let foreign_modules = self . encode_foreign_modules ( ) ;
460
507
461
- // Encode source_map
462
- i = self . position ( ) ;
463
- let source_map = self . encode_source_map ( ) ;
464
- let source_map_bytes = self . position ( ) - i;
465
-
466
508
// Encode DefPathTable
467
509
i = self . position ( ) ;
468
510
let def_path_table = self . encode_def_path_table ( ) ;
@@ -514,12 +556,19 @@ impl<'tcx> EncodeContext<'tcx> {
514
556
let proc_macro_data_bytes = self . position ( ) - i;
515
557
516
558
// Encode exported symbols info. This is prefetched in `encode_metadata` so we encode
517
- // this last to give the prefetching as much time as possible to complete.
559
+ // this late to give the prefetching as much time as possible to complete.
518
560
i = self . position ( ) ;
519
561
let exported_symbols = self . tcx . exported_symbols ( LOCAL_CRATE ) ;
520
562
let exported_symbols = self . encode_exported_symbols ( & exported_symbols) ;
521
563
let exported_symbols_bytes = self . position ( ) - i;
522
564
565
+ // Encode source_map. This needs to be done last,
566
+ // since encoding `Span`s tells us which `SourceFiles` we actually
567
+ // need to encode.
568
+ i = self . position ( ) ;
569
+ let source_map = self . encode_source_map ( ) ;
570
+ let source_map_bytes = self . position ( ) - i;
571
+
523
572
let attrs = tcx. hir ( ) . krate_attrs ( ) ;
524
573
let has_default_lib_allocator = attr:: contains_name ( & attrs, sym:: default_lib_allocator) ;
525
574
@@ -1854,17 +1903,22 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
1854
1903
// Will be filled with the root position after encoding everything.
1855
1904
encoder. emit_raw_bytes ( & [ 0 , 0 , 0 , 0 ] ) ;
1856
1905
1906
+ let source_map_files = tcx. sess . source_map ( ) . files ( ) ;
1907
+
1857
1908
let mut ecx = EncodeContext {
1858
1909
opaque : encoder,
1859
1910
tcx,
1860
1911
tables : Default :: default ( ) ,
1861
1912
lazy_state : LazyState :: NoNode ,
1862
1913
type_shorthands : Default :: default ( ) ,
1863
1914
predicate_shorthands : Default :: default ( ) ,
1864
- source_file_cache : tcx . sess . source_map ( ) . files ( ) [ 0 ] . clone ( ) ,
1915
+ source_file_cache : ( source_map_files [ 0 ] . clone ( ) , 0 ) ,
1865
1916
interpret_allocs : Default :: default ( ) ,
1866
1917
interpret_allocs_inverse : Default :: default ( ) ,
1918
+ required_source_files : Some ( GrowableBitSet :: with_capacity ( source_map_files. len ( ) ) ) ,
1919
+ is_proc_macro : tcx. sess . crate_types ( ) . contains ( & CrateType :: ProcMacro ) ,
1867
1920
} ;
1921
+ drop ( source_map_files) ;
1868
1922
1869
1923
// Encode the rustc version string in a predictable location.
1870
1924
rustc_version ( ) . encode ( & mut ecx) . unwrap ( ) ;
0 commit comments