Skip to content

Commit 978d4f7

Browse files
committed
hygiene: Asserts, comments, code cleanup
1 parent 0307e40 commit 978d4f7

File tree

1 file changed

+92
-63
lines changed

1 file changed

+92
-63
lines changed

compiler/rustc_span/src/hygiene.rs

Lines changed: 92 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626

2727
use std::cell::RefCell;
2828
use std::collections::hash_map::Entry;
29-
use std::fmt;
3029
use std::hash::Hash;
30+
use std::{fmt, iter, mem};
3131

3232
use rustc_data_structures::fingerprint::Fingerprint;
3333
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -54,7 +54,11 @@ pub struct SyntaxContext(u32);
5454
impl !Ord for SyntaxContext {}
5555
impl !PartialOrd for SyntaxContext {}
5656

57-
#[derive(Debug, Encodable, Decodable, Clone)]
57+
/// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal.
58+
/// The other fields are only for caching.
59+
type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);
60+
61+
#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable)]
5862
pub struct SyntaxContextData {
5963
outer_expn: ExpnId,
6064
outer_transparency: Transparency,
@@ -67,6 +71,27 @@ pub struct SyntaxContextData {
6771
dollar_crate_name: Symbol,
6872
}
6973

74+
impl SyntaxContextData {
75+
fn root() -> SyntaxContextData {
76+
SyntaxContextData {
77+
outer_expn: ExpnId::root(),
78+
outer_transparency: Transparency::Opaque,
79+
parent: SyntaxContext::root(),
80+
opaque: SyntaxContext::root(),
81+
opaque_and_semitransparent: SyntaxContext::root(),
82+
dollar_crate_name: kw::DollarCrate,
83+
}
84+
}
85+
86+
fn decode_placeholder() -> SyntaxContextData {
87+
SyntaxContextData { dollar_crate_name: kw::Empty, ..SyntaxContextData::root() }
88+
}
89+
90+
fn is_decode_placeholder(&self) -> bool {
91+
self.dollar_crate_name == kw::Empty
92+
}
93+
}
94+
7095
rustc_index::newtype_index! {
7196
/// A unique ID associated with a macro invocation and expansion.
7297
#[orderable]
@@ -333,7 +358,7 @@ pub(crate) struct HygieneData {
333358
foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
334359
expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>,
335360
syntax_context_data: Vec<SyntaxContextData>,
336-
syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
361+
syntax_context_map: FxHashMap<SyntaxContextKey, SyntaxContext>,
337362
/// Maps the `local_hash` of an `ExpnData` to the next disambiguator value.
338363
/// This is used by `update_disambiguator` to keep track of which `ExpnData`s
339364
/// would have collisions without a disambiguator.
@@ -352,21 +377,15 @@ impl HygieneData {
352377
None,
353378
);
354379

380+
let root_ctxt_data = SyntaxContextData::root();
355381
HygieneData {
356382
local_expn_data: IndexVec::from_elem_n(Some(root_data), 1),
357383
local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1),
358384
foreign_expn_data: FxHashMap::default(),
359385
foreign_expn_hashes: FxHashMap::default(),
360-
expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
386+
expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
361387
.collect(),
362-
syntax_context_data: vec![SyntaxContextData {
363-
outer_expn: ExpnId::root(),
364-
outer_transparency: Transparency::Opaque,
365-
parent: SyntaxContext(0),
366-
opaque: SyntaxContext(0),
367-
opaque_and_semitransparent: SyntaxContext(0),
368-
dollar_crate_name: kw::DollarCrate,
369-
}],
388+
syntax_context_data: vec![root_ctxt_data],
370389
syntax_context_map: FxHashMap::default(),
371390
expn_data_disambiguators: UnhashMap::default(),
372391
}
@@ -416,23 +435,28 @@ impl HygieneData {
416435
}
417436

418437
fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
438+
assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
419439
self.syntax_context_data[ctxt.0 as usize].opaque
420440
}
421441

422442
fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
443+
assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
423444
self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent
424445
}
425446

426447
fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
448+
assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
427449
self.syntax_context_data[ctxt.0 as usize].outer_expn
428450
}
429451

430452
fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
453+
assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
431454
let data = &self.syntax_context_data[ctxt.0 as usize];
432455
(data.outer_expn, data.outer_transparency)
433456
}
434457

435458
fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
459+
assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
436460
self.syntax_context_data[ctxt.0 as usize].parent
437461
}
438462

@@ -542,6 +566,7 @@ impl HygieneData {
542566
transparency: Transparency,
543567
) -> SyntaxContext {
544568
let syntax_context_data = &mut self.syntax_context_data;
569+
assert!(!syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
545570
let mut opaque = syntax_context_data[ctxt.0 as usize].opaque;
546571
let mut opaque_and_semitransparent =
547572
syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent;
@@ -552,7 +577,7 @@ impl HygieneData {
552577
.syntax_context_map
553578
.entry((parent, expn_id, transparency))
554579
.or_insert_with(|| {
555-
let new_opaque = SyntaxContext(syntax_context_data.len() as u32);
580+
let new_opaque = SyntaxContext::from_usize(syntax_context_data.len());
556581
syntax_context_data.push(SyntaxContextData {
557582
outer_expn: expn_id,
558583
outer_transparency: transparency,
@@ -572,7 +597,7 @@ impl HygieneData {
572597
.entry((parent, expn_id, transparency))
573598
.or_insert_with(|| {
574599
let new_opaque_and_semitransparent =
575-
SyntaxContext(syntax_context_data.len() as u32);
600+
SyntaxContext::from_usize(syntax_context_data.len());
576601
syntax_context_data.push(SyntaxContextData {
577602
outer_expn: expn_id,
578603
outer_transparency: transparency,
@@ -587,8 +612,6 @@ impl HygieneData {
587612

588613
let parent = ctxt;
589614
*self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| {
590-
let new_opaque_and_semitransparent_and_transparent =
591-
SyntaxContext(syntax_context_data.len() as u32);
592615
syntax_context_data.push(SyntaxContextData {
593616
outer_expn: expn_id,
594617
outer_transparency: transparency,
@@ -597,7 +620,7 @@ impl HygieneData {
597620
opaque_and_semitransparent,
598621
dollar_crate_name: kw::DollarCrate,
599622
});
600-
new_opaque_and_semitransparent_and_transparent
623+
SyntaxContext::from_usize(syntax_context_data.len() - 1)
601624
})
602625
}
603626
}
@@ -704,6 +727,10 @@ impl SyntaxContext {
704727
SyntaxContext(raw as u32)
705728
}
706729

730+
fn from_usize(raw: usize) -> SyntaxContext {
731+
SyntaxContext(u32::try_from(raw).unwrap())
732+
}
733+
707734
/// Extend a syntax context with a given expansion and transparency.
708735
pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
709736
HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
@@ -884,7 +911,10 @@ impl SyntaxContext {
884911
}
885912

886913
pub(crate) fn dollar_crate_name(self) -> Symbol {
887-
HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
914+
HygieneData::with(|data| {
915+
assert!(!data.syntax_context_data[self.0 as usize].is_decode_placeholder());
916+
data.syntax_context_data[self.0 as usize].dollar_crate_name
917+
})
888918
}
889919

890920
pub fn edition(self) -> Edition {
@@ -1224,7 +1254,7 @@ impl HygieneEncodeContext {
12241254

12251255
// Consume the current round of SyntaxContexts.
12261256
// Drop the lock() temporary early
1227-
let latest_ctxts = { std::mem::take(&mut *self.latest_ctxts.lock()) };
1257+
let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) };
12281258

12291259
// It's fine to iterate over a HashMap, because the serialization
12301260
// of the table that we insert data into doesn't depend on insertion
@@ -1236,7 +1266,7 @@ impl HygieneEncodeContext {
12361266
}
12371267
});
12381268

1239-
let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) };
1269+
let latest_expns = { mem::take(&mut *self.latest_expns.lock()) };
12401270

12411271
// Same as above, this is fine as we are inserting into a order-independent hashset
12421272
#[allow(rustc::potential_query_instability)]
@@ -1270,6 +1300,7 @@ pub struct HygieneDecodeContext {
12701300
inner: Lock<HygieneDecodeContextInner>,
12711301

12721302
/// A set of serialized `SyntaxContext` ids that are currently being decoded on each thread.
1303+
/// Uses a hash map instead of hash set to use entry APIs.
12731304
local_in_progress: WorkerLocal<RefCell<FxHashMap<u32, ()>>>,
12741305
}
12751306

@@ -1354,28 +1385,33 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
13541385
return SyntaxContext::root();
13551386
}
13561387

1357-
let ctxt = {
1388+
let pending_ctxt = {
13581389
let mut inner = context.inner.lock();
13591390

1391+
// Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between
1392+
// raw ids from different crate metadatas.
13601393
if let Some(ctxt) = inner.remapped_ctxts.get(raw_id as usize).copied().flatten() {
13611394
// This has already been decoded.
13621395
return ctxt;
13631396
}
13641397

13651398
match inner.decoding.entry(raw_id) {
13661399
Entry::Occupied(ctxt_entry) => {
1400+
let pending_ctxt = *ctxt_entry.get();
13671401
match context.local_in_progress.borrow_mut().entry(raw_id) {
1368-
Entry::Occupied(..) => {
1369-
// We're decoding this already on the current thread. Return here
1370-
// and let the function higher up the stack finish decoding to handle
1371-
// recursive cases.
1372-
return *ctxt_entry.get();
1373-
}
1402+
// We're decoding this already on the current thread. Return here and let the
1403+
// function higher up the stack finish decoding to handle recursive cases.
1404+
// Hopefully having a `SyntaxContext` that refers to an incorrect data is ok
1405+
// during reminder of the decoding process, it's certainly not ok after the
1406+
// top level decoding function returns.
1407+
Entry::Occupied(..) => return pending_ctxt,
1408+
// Some other thread is current decoding this.
1409+
// Race with it (alternatively we could wait here).
1410+
// We cannot return this value, unlike in the recursive case above, because it
1411+
// may expose a `SyntaxContext` pointing to incorrect data to arbitrary code.
13741412
Entry::Vacant(entry) => {
13751413
entry.insert(());
1376-
1377-
// Some other thread is current decoding this. Race with it.
1378-
*ctxt_entry.get()
1414+
pending_ctxt
13791415
}
13801416
}
13811417
}
@@ -1386,18 +1422,10 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
13861422
// Allocate and store SyntaxContext id *before* calling the decoder function,
13871423
// as the SyntaxContextData may reference itself.
13881424
let new_ctxt = HygieneData::with(|hygiene_data| {
1389-
let new_ctxt = SyntaxContext(hygiene_data.syntax_context_data.len() as u32);
13901425
// Push a dummy SyntaxContextData to ensure that nobody else can get the
1391-
// same ID as us. This will be overwritten after call `decode_Data`
1392-
hygiene_data.syntax_context_data.push(SyntaxContextData {
1393-
outer_expn: ExpnId::root(),
1394-
outer_transparency: Transparency::Transparent,
1395-
parent: SyntaxContext::root(),
1396-
opaque: SyntaxContext::root(),
1397-
opaque_and_semitransparent: SyntaxContext::root(),
1398-
dollar_crate_name: kw::Empty,
1399-
});
1400-
new_ctxt
1426+
// same ID as us. This will be overwritten after call `decode_data`.
1427+
hygiene_data.syntax_context_data.push(SyntaxContextData::decode_placeholder());
1428+
SyntaxContext::from_usize(hygiene_data.syntax_context_data.len() - 1)
14011429
});
14021430
entry.insert(new_ctxt);
14031431
new_ctxt
@@ -1407,38 +1435,39 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
14071435

14081436
// Don't try to decode data while holding the lock, since we need to
14091437
// be able to recursively decode a SyntaxContext
1410-
let mut ctxt_data = decode_data(d, raw_id);
1411-
// Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`
1412-
// We don't care what the encoding crate set this to - we want to resolve it
1413-
// from the perspective of the current compilation session
1414-
ctxt_data.dollar_crate_name = kw::DollarCrate;
1438+
let ctxt_data = decode_data(d, raw_id);
14151439

1416-
// Overwrite the dummy data with our decoded SyntaxContextData
1417-
HygieneData::with(|hygiene_data| {
1418-
if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize)
1440+
let ctxt = HygieneData::with(|hygiene_data| {
1441+
let old = if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize)
14191442
&& old.outer_expn == ctxt_data.outer_expn
14201443
&& old.outer_transparency == ctxt_data.outer_transparency
14211444
&& old.parent == ctxt_data.parent
14221445
{
1423-
ctxt_data = old.clone();
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;
14241459
}
1425-
1426-
let dummy = std::mem::replace(
1427-
&mut hygiene_data.syntax_context_data[ctxt.as_u32() as usize],
1428-
ctxt_data,
1429-
);
1430-
if cfg!(not(parallel_compiler)) {
1431-
// Make sure nothing weird happened while `decode_data` was running.
1432-
// We used `kw::Empty` for the dummy value and we expect nothing to be
1433-
// modifying the dummy entry.
1434-
// This does not hold for the parallel compiler as another thread may
1435-
// have inserted the fully decoded data.
1436-
assert_eq!(dummy.dollar_crate_name, kw::Empty);
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);
14371466
}
1467+
pending_ctxt
14381468
});
14391469

14401470
// Mark the context as completed
1441-
14421471
context.local_in_progress.borrow_mut().remove(&raw_id);
14431472

14441473
let mut inner = context.inner.lock();

0 commit comments

Comments
 (0)