@@ -93,6 +93,10 @@ impl SyntaxContextData {
9393 fn is_decode_placeholder ( & self ) -> bool {
9494 self . dollar_crate_name == kw:: Empty
9595 }
96+
97+ fn key ( & self ) -> SyntaxContextKey {
98+ ( self . parent , self . outer_expn , self . outer_transparency )
99+ }
96100}
97101
98102rustc_index:: newtype_index! {
@@ -395,7 +399,7 @@ impl HygieneData {
395399 expn_hash_to_expn_id : iter:: once ( ( ExpnHash ( Fingerprint :: ZERO ) , ExpnId :: root ( ) ) )
396400 . collect ( ) ,
397401 syntax_context_data : vec ! [ root_ctxt_data] ,
398- syntax_context_map : FxHashMap :: default ( ) ,
402+ syntax_context_map : iter :: once ( ( root_ctxt_data . key ( ) , SyntaxContext ( 0 ) ) ) . collect ( ) ,
399403 expn_data_disambiguators : UnhashMap :: default ( ) ,
400404 }
401405 }
@@ -1454,34 +1458,38 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
14541458 // Don't try to decode data while holding the lock, since we need to
14551459 // be able to recursively decode a SyntaxContext
14561460 let ctxt_data = decode_data ( d, raw_id) ;
1461+ let ctxt_key = ctxt_data. key ( ) ;
14571462
14581463 let ctxt = HygieneData :: with ( |hygiene_data| {
1459- let old = if let Some ( old) = hygiene_data. syntax_context_data . get ( raw_id as usize )
1460- && old. outer_expn == ctxt_data. outer_expn
1461- && old. outer_transparency == ctxt_data. outer_transparency
1462- && old. parent == ctxt_data. parent
1463- {
1464- Some ( old. clone ( ) )
1465- } else {
1466- None
1467- } ;
1468- // Overwrite its placeholder data with our decoded data.
1469- let ctxt_data_ref = & mut hygiene_data. syntax_context_data [ pending_ctxt. as_u32 ( ) as usize ] ;
1470- let prev_ctxt_data = mem:: replace ( ctxt_data_ref, ctxt_data) ;
1471- // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`.
1472- // We don't care what the encoding crate set this to - we want to resolve it
1473- // from the perspective of the current compilation session
1474- ctxt_data_ref. dollar_crate_name = kw:: DollarCrate ;
1475- if let Some ( old) = old {
1476- * ctxt_data_ref = old;
1477- }
1478- // Make sure nothing weird happened while `decode_data` was running.
1479- if !prev_ctxt_data. is_decode_placeholder ( ) {
1480- // Another thread may have already inserted the decoded data,
1481- // but the decoded data should match.
1482- assert_eq ! ( prev_ctxt_data, * ctxt_data_ref) ;
1464+ match hygiene_data. syntax_context_map . get ( & ctxt_key) {
1465+ // Ensure that syntax contexts are unique.
1466+ // If syntax contexts with the given key already exists, reuse it instead of
1467+ // using `pending_ctxt`.
1468+ // `pending_ctxt` will leave an unused hole in the vector of syntax contexts.
1469+ // Hopefully its value isn't stored anywhere during decoding and its dummy data
1470+ // is never accessed later. The `is_decode_placeholder` asserts on all
1471+ // accesses to syntax context data attempt to ensure it.
1472+ Some ( & ctxt) => ctxt,
1473+ // This is a completely new context.
1474+ // Overwrite its placeholder data with our decoded data.
1475+ None => {
1476+ let ctxt_data_ref =
1477+ & mut hygiene_data. syntax_context_data [ pending_ctxt. as_u32 ( ) as usize ] ;
1478+ let prev_ctxt_data = mem:: replace ( ctxt_data_ref, ctxt_data) ;
1479+ // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`.
1480+ // We don't care what the encoding crate set this to - we want to resolve it
1481+ // from the perspective of the current compilation session.
1482+ ctxt_data_ref. dollar_crate_name = kw:: DollarCrate ;
1483+ // Make sure nothing weird happened while `decode_data` was running.
1484+ if !prev_ctxt_data. is_decode_placeholder ( ) {
1485+ // Another thread may have already inserted the decoded data,
1486+ // but the decoded data should match.
1487+ assert_eq ! ( prev_ctxt_data, * ctxt_data_ref) ;
1488+ }
1489+ hygiene_data. syntax_context_map . insert ( ctxt_key, pending_ctxt) ;
1490+ pending_ctxt
1491+ }
14831492 }
1484- pending_ctxt
14851493 } ) ;
14861494
14871495 // Mark the context as completed
0 commit comments