Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e577b7a

Browse files
committedSep 13, 2024
hygiene: Ensure uniqueness of SyntaxContextDatas
1 parent 978d4f7 commit e577b7a

File tree

1 file changed

+35
-27
lines changed

1 file changed

+35
-27
lines changed
 

‎compiler/rustc_span/src/hygiene.rs

+35-27
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ impl SyntaxContextData {
9090
fn is_decode_placeholder(&self) -> bool {
9191
self.dollar_crate_name == kw::Empty
9292
}
93+
94+
fn key(&self) -> SyntaxContextKey {
95+
(self.parent, self.outer_expn, self.outer_transparency)
96+
}
9397
}
9498

9599
rustc_index::newtype_index! {
@@ -386,7 +390,7 @@ impl HygieneData {
386390
expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
387391
.collect(),
388392
syntax_context_data: vec![root_ctxt_data],
389-
syntax_context_map: FxHashMap::default(),
393+
syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext(0))).collect(),
390394
expn_data_disambiguators: UnhashMap::default(),
391395
}
392396
}
@@ -1436,35 +1440,39 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
14361440
// Don't try to decode data while holding the lock, since we need to
14371441
// be able to recursively decode a SyntaxContext
14381442
let ctxt_data = decode_data(d, raw_id);
1443+
let ctxt_key = ctxt_data.key();
14391444

14401445
let ctxt = HygieneData::with(|hygiene_data| {
1441-
let old = if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize)
1442-
&& old.outer_expn == ctxt_data.outer_expn
1443-
&& old.outer_transparency == ctxt_data.outer_transparency
1444-
&& old.parent == ctxt_data.parent
1445-
{
1446-
Some(old.clone())
1447-
} else {
1448-
None
1449-
};
1450-
// Overwrite its placeholder data with our decoded data.
1451-
let ctxt_data_ref = &mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize];
1452-
let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data);
1453-
// Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`.
1454-
// We don't care what the encoding crate set this to - we want to resolve it
1455-
// from the perspective of the current compilation session
1456-
ctxt_data_ref.dollar_crate_name = kw::DollarCrate;
1457-
if let Some(old) = old {
1458-
*ctxt_data_ref = old;
1459-
}
1460-
// Make sure nothing weird happened while `decode_data` was running.
1461-
if !prev_ctxt_data.is_decode_placeholder() {
1462-
// With parallel compiler another thread may have already inserted the decoded
1463-
// data, but the decoded data should match.
1464-
assert!(cfg!(parallel_compiler));
1465-
assert_eq!(prev_ctxt_data, *ctxt_data_ref);
1446+
match hygiene_data.syntax_context_map.get(&ctxt_key) {
1447+
// Ensure that syntax contexts are unique.
1448+
// If syntax contexts with the given key already exists, reuse it instead of
1449+
// using `pending_ctxt`.
1450+
// `pending_ctxt` will leave an unused hole in the vector of syntax contexts.
1451+
// Hopefully its value isn't stored anywhere during decoding and its dummy data
1452+
// is never accessed later. The `is_decode_placeholder` asserts on all
1453+
// accesses to syntax context data attempt to ensure it.
1454+
Some(&ctxt) => ctxt,
1455+
// This is a completely new context.
1456+
// Overwrite its placeholder data with our decoded data.
1457+
None => {
1458+
let ctxt_data_ref =
1459+
&mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize];
1460+
let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data);
1461+
// Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`.
1462+
// We don't care what the encoding crate set this to - we want to resolve it
1463+
// from the perspective of the current compilation session
1464+
ctxt_data_ref.dollar_crate_name = kw::DollarCrate;
1465+
// Make sure nothing weird happened while `decode_data` was running.
1466+
if !prev_ctxt_data.is_decode_placeholder() {
1467+
// With parallel compiler another thread may have already inserted the decoded
1468+
// data, but the decoded data should match.
1469+
assert!(cfg!(parallel_compiler));
1470+
assert_eq!(prev_ctxt_data, *ctxt_data_ref);
1471+
}
1472+
hygiene_data.syntax_context_map.insert(ctxt_key, pending_ctxt);
1473+
pending_ctxt
1474+
}
14661475
}
1467-
pending_ctxt
14681476
});
14691477

14701478
// Mark the context as completed

0 commit comments

Comments
 (0)
Failed to load comments.