@@ -16,6 +16,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
1616use rustc_hir:: itemlikevisit:: { ItemLikeVisitor , ParItemLikeVisitor } ;
1717use rustc_hir:: lang_items;
1818use rustc_hir:: { AnonConst , GenericParamKind } ;
19+ use rustc_index:: bit_set:: GrowableBitSet ;
1920use rustc_index:: vec:: Idx ;
2021use rustc_middle:: hir:: map:: Map ;
2122use rustc_middle:: middle:: cstore:: { EncodedMetadata , ForeignModule , LinkagePreference , NativeLib } ;
@@ -51,7 +52,20 @@ struct EncodeContext<'tcx> {
5152 interpret_allocs_inverse : Vec < interpret:: AllocId > ,
5253
5354 // 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 ,
5569}
5670
5771macro_rules! encoder_methods {
@@ -154,18 +168,23 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
154168 // The Span infrastructure should make sure that this invariant holds:
155169 debug_assert ! ( span. lo <= span. hi) ;
156170
157- if !self . source_file_cache . contains ( span. lo ) {
171+ if !self . source_file_cache . 0 . contains ( span. lo ) {
158172 let source_map = self . tcx . sess . source_map ( ) ;
159173 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) ;
161176 }
162177
163- if !self . source_file_cache . contains ( span. hi ) {
178+ if !self . source_file_cache . 0 . contains ( span. hi ) {
164179 // Unfortunately, macro expansion still sometimes generates Spans
165180 // that malformed in this way.
166181 return TAG_INVALID_SPAN . encode ( self ) ;
167182 }
168183
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+
169188 // There are two possible cases here:
170189 // 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the
171190 // crate we are writing metadata for. When the metadata for *this* crate gets
@@ -176,7 +195,13 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
176195 // 2. This span comes from our own crate. No special hamdling is needed - we just
177196 // write `TAG_VALID_SPAN_LOCAL` to let the deserializer know that it should use
178197 // 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 {
180205 // To simplify deserialization, we 'rebase' this span onto the crate it originally came from
181206 // (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values
182207 // are relative to the source map information for the 'foreign' crate whose CrateNum
@@ -188,13 +213,13 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
188213 // Span that can be used without any additional trouble.
189214 let external_start_pos = {
190215 // 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 ( ) {
192217 ExternalSource :: Foreign { original_start_pos, .. } => * original_start_pos,
193218 src => panic ! ( "Unexpected external source {:?}" , src) ,
194219 }
195220 } ;
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;
198223
199224 ( TAG_VALID_SPAN_FOREIGN , lo, hi)
200225 } else {
@@ -212,7 +237,7 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
212237 if tag == TAG_VALID_SPAN_FOREIGN {
213238 // This needs to be two lines to avoid holding the `self.source_file_cache`
214239 // while calling `cnum.encode(self)`
215- let cnum = self . source_file_cache . cnum ;
240+ let cnum = self . source_file_cache . 0 . cnum ;
216241 cnum. encode ( self ) ?;
217242 }
218243 Ok ( ( ) )
@@ -386,17 +411,24 @@ impl<'tcx> EncodeContext<'tcx> {
386411 let all_source_files = source_map. files ( ) ;
387412
388413 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 ( ) ;
389418
390419 let adapted = all_source_files
391420 . 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 )
397429 } )
398- . map ( |source_file| {
399- match source_file. name {
430+ . map ( |( _ , source_file) | {
431+ let mut adapted = match source_file. name {
400432 // This path of this SourceFile has been modified by
401433 // path-remapping, so we use it verbatim (and avoid
402434 // cloning the whole map in the process).
@@ -419,15 +451,30 @@ impl<'tcx> EncodeContext<'tcx> {
419451
420452 // expanded code, not from a file
421453 _ => 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 ;
422464 }
465+ adapted
423466 } )
424467 . collect :: < Vec < _ > > ( ) ;
425468
426469 self . lazy ( adapted. iter ( ) . map ( |rc| & * * rc) )
427470 }
428471
472+ fn is_proc_macro ( & self ) -> bool {
473+ self . tcx . sess . crate_types ( ) . contains ( & CrateType :: ProcMacro )
474+ }
475+
429476 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 ( ) ;
431478
432479 let mut i = self . position ( ) ;
433480
@@ -458,11 +505,6 @@ impl<'tcx> EncodeContext<'tcx> {
458505
459506 let foreign_modules = self . encode_foreign_modules ( ) ;
460507
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-
466508 // Encode DefPathTable
467509 i = self . position ( ) ;
468510 let def_path_table = self . encode_def_path_table ( ) ;
@@ -514,12 +556,19 @@ impl<'tcx> EncodeContext<'tcx> {
514556 let proc_macro_data_bytes = self . position ( ) - i;
515557
516558 // 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.
518560 i = self . position ( ) ;
519561 let exported_symbols = self . tcx . exported_symbols ( LOCAL_CRATE ) ;
520562 let exported_symbols = self . encode_exported_symbols ( & exported_symbols) ;
521563 let exported_symbols_bytes = self . position ( ) - i;
522564
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+
523572 let attrs = tcx. hir ( ) . krate_attrs ( ) ;
524573 let has_default_lib_allocator = attr:: contains_name ( & attrs, sym:: default_lib_allocator) ;
525574
@@ -1860,17 +1909,22 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
18601909 // Will be filled with the root position after encoding everything.
18611910 encoder. emit_raw_bytes ( & [ 0 , 0 , 0 , 0 ] ) ;
18621911
1912+ let source_map_files = tcx. sess . source_map ( ) . files ( ) ;
1913+
18631914 let mut ecx = EncodeContext {
18641915 opaque : encoder,
18651916 tcx,
18661917 tables : Default :: default ( ) ,
18671918 lazy_state : LazyState :: NoNode ,
18681919 type_shorthands : Default :: default ( ) ,
18691920 predicate_shorthands : Default :: default ( ) ,
1870- source_file_cache : tcx . sess . source_map ( ) . files ( ) [ 0 ] . clone ( ) ,
1921+ source_file_cache : ( source_map_files [ 0 ] . clone ( ) , 0 ) ,
18711922 interpret_allocs : Default :: default ( ) ,
18721923 interpret_allocs_inverse : Default :: default ( ) ,
1924+ required_source_files : Some ( GrowableBitSet :: with_capacity ( source_map_files. len ( ) ) ) ,
1925+ is_proc_macro : tcx. sess . crate_types ( ) . contains ( & CrateType :: ProcMacro ) ,
18731926 } ;
1927+ drop ( source_map_files) ;
18741928
18751929 // Encode the rustc version string in a predictable location.
18761930 rustc_version ( ) . encode ( & mut ecx) . unwrap ( ) ;
0 commit comments