diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2024-09-13 23:08:37 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2025-03-15 20:45:56 +0300 |
| commit | 6e1effe948525538427b2a6932f1619d74776cef (patch) | |
| tree | 734d9b52a7f78e59de0b0dfd9a5685aa2f38804c /compiler/rustc_span/src/hygiene.rs | |
| parent | 360a87d51df99df2c2d2cbec0e5b30dbd9c03e59 (diff) | |
| download | rust-6e1effe948525538427b2a6932f1619d74776cef.tar.gz rust-6e1effe948525538427b2a6932f1619d74776cef.zip | |
hygiene: Ensure uniqueness of `SyntaxContextData`s
Diffstat (limited to 'compiler/rustc_span/src/hygiene.rs')
| -rw-r--r-- | compiler/rustc_span/src/hygiene.rs | 60 |
1 files changed, 34 insertions, 26 deletions
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index b872f5e9d38..36ecbe1cb78 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -93,6 +93,10 @@ impl SyntaxContextData { fn is_decode_placeholder(&self) -> bool { self.dollar_crate_name == kw::Empty } + + fn key(&self) -> SyntaxContextKey { + (self.parent, self.outer_expn, self.outer_transparency) + } } rustc_index::newtype_index! { @@ -395,7 +399,7 @@ impl HygieneData { expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) .collect(), syntax_context_data: vec![root_ctxt_data], - syntax_context_map: FxHashMap::default(), + syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext(0))).collect(), expn_data_disambiguators: UnhashMap::default(), } } @@ -1454,34 +1458,38 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext let ctxt_data = decode_data(d, raw_id); + let ctxt_key = ctxt_data.key(); let ctxt = HygieneData::with(|hygiene_data| { - let old = if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize) - && old.outer_expn == ctxt_data.outer_expn - && old.outer_transparency == ctxt_data.outer_transparency - && old.parent == ctxt_data.parent - { - Some(old.clone()) - } else { - None - }; - // Overwrite its placeholder data with our decoded data. - let ctxt_data_ref = &mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize]; - let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data); - // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`. - // We don't care what the encoding crate set this to - we want to resolve it - // from the perspective of the current compilation session - ctxt_data_ref.dollar_crate_name = kw::DollarCrate; - if let Some(old) = old { - *ctxt_data_ref = old; - } - // Make sure nothing weird happened while `decode_data` was running. - if !prev_ctxt_data.is_decode_placeholder() { - // Another thread may have already inserted the decoded data, - // but the decoded data should match. - assert_eq!(prev_ctxt_data, *ctxt_data_ref); + match hygiene_data.syntax_context_map.get(&ctxt_key) { + // Ensure that syntax contexts are unique. + // If syntax contexts with the given key already exists, reuse it instead of + // using `pending_ctxt`. + // `pending_ctxt` will leave an unused hole in the vector of syntax contexts. + // Hopefully its value isn't stored anywhere during decoding and its dummy data + // is never accessed later. The `is_decode_placeholder` asserts on all + // accesses to syntax context data attempt to ensure it. + Some(&ctxt) => ctxt, + // This is a completely new context. + // Overwrite its placeholder data with our decoded data. + None => { + let ctxt_data_ref = + &mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize]; + let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data); + // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`. + // We don't care what the encoding crate set this to - we want to resolve it + // from the perspective of the current compilation session. + ctxt_data_ref.dollar_crate_name = kw::DollarCrate; + // Make sure nothing weird happened while `decode_data` was running. + if !prev_ctxt_data.is_decode_placeholder() { + // Another thread may have already inserted the decoded data, + // but the decoded data should match. + assert_eq!(prev_ctxt_data, *ctxt_data_ref); + } + hygiene_data.syntax_context_map.insert(ctxt_key, pending_ctxt); + pending_ctxt + } } - pending_ctxt }); // Mark the context as completed |
