26
26
27
27
use std:: cell:: RefCell ;
28
28
use std:: collections:: hash_map:: Entry ;
29
- use std:: fmt;
30
29
use std:: hash:: Hash ;
30
+ use std:: { fmt, iter, mem} ;
31
31
32
32
use rustc_data_structures:: fingerprint:: Fingerprint ;
33
33
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
@@ -54,7 +54,11 @@ pub struct SyntaxContext(u32);
54
54
impl !Ord for SyntaxContext { }
55
55
impl !PartialOrd for SyntaxContext { }
56
56
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 ) ]
58
62
pub struct SyntaxContextData {
59
63
outer_expn : ExpnId ,
60
64
outer_transparency : Transparency ,
@@ -67,6 +71,27 @@ pub struct SyntaxContextData {
67
71
dollar_crate_name : Symbol ,
68
72
}
69
73
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
+
70
95
rustc_index:: newtype_index! {
71
96
/// A unique ID associated with a macro invocation and expansion.
72
97
#[ orderable]
@@ -333,7 +358,7 @@ pub(crate) struct HygieneData {
333
358
foreign_expn_hashes : FxHashMap < ExpnId , ExpnHash > ,
334
359
expn_hash_to_expn_id : UnhashMap < ExpnHash , ExpnId > ,
335
360
syntax_context_data : Vec < SyntaxContextData > ,
336
- syntax_context_map : FxHashMap < ( SyntaxContext , ExpnId , Transparency ) , SyntaxContext > ,
361
+ syntax_context_map : FxHashMap < SyntaxContextKey , SyntaxContext > ,
337
362
/// Maps the `local_hash` of an `ExpnData` to the next disambiguator value.
338
363
/// This is used by `update_disambiguator` to keep track of which `ExpnData`s
339
364
/// would have collisions without a disambiguator.
@@ -352,21 +377,15 @@ impl HygieneData {
352
377
None ,
353
378
) ;
354
379
380
+ let root_ctxt_data = SyntaxContextData :: root ( ) ;
355
381
HygieneData {
356
382
local_expn_data : IndexVec :: from_elem_n ( Some ( root_data) , 1 ) ,
357
383
local_expn_hashes : IndexVec :: from_elem_n ( ExpnHash ( Fingerprint :: ZERO ) , 1 ) ,
358
384
foreign_expn_data : FxHashMap :: default ( ) ,
359
385
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 ( ) ) )
361
387
. 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] ,
370
389
syntax_context_map : FxHashMap :: default ( ) ,
371
390
expn_data_disambiguators : UnhashMap :: default ( ) ,
372
391
}
@@ -416,23 +435,28 @@ impl HygieneData {
416
435
}
417
436
418
437
fn normalize_to_macros_2_0 ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
438
+ assert ! ( !self . syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
419
439
self . syntax_context_data [ ctxt. 0 as usize ] . opaque
420
440
}
421
441
422
442
fn normalize_to_macro_rules ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
443
+ assert ! ( !self . syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
423
444
self . syntax_context_data [ ctxt. 0 as usize ] . opaque_and_semitransparent
424
445
}
425
446
426
447
fn outer_expn ( & self , ctxt : SyntaxContext ) -> ExpnId {
448
+ assert ! ( !self . syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
427
449
self . syntax_context_data [ ctxt. 0 as usize ] . outer_expn
428
450
}
429
451
430
452
fn outer_mark ( & self , ctxt : SyntaxContext ) -> ( ExpnId , Transparency ) {
453
+ assert ! ( !self . syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
431
454
let data = & self . syntax_context_data [ ctxt. 0 as usize ] ;
432
455
( data. outer_expn , data. outer_transparency )
433
456
}
434
457
435
458
fn parent_ctxt ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
459
+ assert ! ( !self . syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
436
460
self . syntax_context_data [ ctxt. 0 as usize ] . parent
437
461
}
438
462
@@ -542,6 +566,7 @@ impl HygieneData {
542
566
transparency : Transparency ,
543
567
) -> SyntaxContext {
544
568
let syntax_context_data = & mut self . syntax_context_data ;
569
+ assert ! ( !syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
545
570
let mut opaque = syntax_context_data[ ctxt. 0 as usize ] . opaque ;
546
571
let mut opaque_and_semitransparent =
547
572
syntax_context_data[ ctxt. 0 as usize ] . opaque_and_semitransparent ;
@@ -552,7 +577,7 @@ impl HygieneData {
552
577
. syntax_context_map
553
578
. entry ( ( parent, expn_id, transparency) )
554
579
. 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 ( ) ) ;
556
581
syntax_context_data. push ( SyntaxContextData {
557
582
outer_expn : expn_id,
558
583
outer_transparency : transparency,
@@ -572,7 +597,7 @@ impl HygieneData {
572
597
. entry ( ( parent, expn_id, transparency) )
573
598
. or_insert_with ( || {
574
599
let new_opaque_and_semitransparent =
575
- SyntaxContext ( syntax_context_data. len ( ) as u32 ) ;
600
+ SyntaxContext :: from_usize ( syntax_context_data. len ( ) ) ;
576
601
syntax_context_data. push ( SyntaxContextData {
577
602
outer_expn : expn_id,
578
603
outer_transparency : transparency,
@@ -587,8 +612,6 @@ impl HygieneData {
587
612
588
613
let parent = ctxt;
589
614
* 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 ) ;
592
615
syntax_context_data. push ( SyntaxContextData {
593
616
outer_expn : expn_id,
594
617
outer_transparency : transparency,
@@ -597,7 +620,7 @@ impl HygieneData {
597
620
opaque_and_semitransparent,
598
621
dollar_crate_name : kw:: DollarCrate ,
599
622
} ) ;
600
- new_opaque_and_semitransparent_and_transparent
623
+ SyntaxContext :: from_usize ( syntax_context_data . len ( ) - 1 )
601
624
} )
602
625
}
603
626
}
@@ -704,6 +727,10 @@ impl SyntaxContext {
704
727
SyntaxContext ( raw as u32 )
705
728
}
706
729
730
+ fn from_usize ( raw : usize ) -> SyntaxContext {
731
+ SyntaxContext ( u32:: try_from ( raw) . unwrap ( ) )
732
+ }
733
+
707
734
/// Extend a syntax context with a given expansion and transparency.
708
735
pub fn apply_mark ( self , expn_id : ExpnId , transparency : Transparency ) -> SyntaxContext {
709
736
HygieneData :: with ( |data| data. apply_mark ( self , expn_id, transparency) )
@@ -884,7 +911,10 @@ impl SyntaxContext {
884
911
}
885
912
886
913
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
+ } )
888
918
}
889
919
890
920
pub fn edition ( self ) -> Edition {
@@ -1224,7 +1254,7 @@ impl HygieneEncodeContext {
1224
1254
1225
1255
// Consume the current round of SyntaxContexts.
1226
1256
// 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 ( ) ) } ;
1228
1258
1229
1259
// It's fine to iterate over a HashMap, because the serialization
1230
1260
// of the table that we insert data into doesn't depend on insertion
@@ -1236,7 +1266,7 @@ impl HygieneEncodeContext {
1236
1266
}
1237
1267
} ) ;
1238
1268
1239
- let latest_expns = { std :: mem:: take ( & mut * self . latest_expns . lock ( ) ) } ;
1269
+ let latest_expns = { mem:: take ( & mut * self . latest_expns . lock ( ) ) } ;
1240
1270
1241
1271
// Same as above, this is fine as we are inserting into a order-independent hashset
1242
1272
#[ allow( rustc:: potential_query_instability) ]
@@ -1270,6 +1300,7 @@ pub struct HygieneDecodeContext {
1270
1300
inner : Lock < HygieneDecodeContextInner > ,
1271
1301
1272
1302
/// 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.
1273
1304
local_in_progress : WorkerLocal < RefCell < FxHashMap < u32 , ( ) > > > ,
1274
1305
}
1275
1306
@@ -1354,28 +1385,33 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
1354
1385
return SyntaxContext :: root ( ) ;
1355
1386
}
1356
1387
1357
- let ctxt = {
1388
+ let pending_ctxt = {
1358
1389
let mut inner = context. inner . lock ( ) ;
1359
1390
1391
+ // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between
1392
+ // raw ids from different crate metadatas.
1360
1393
if let Some ( ctxt) = inner. remapped_ctxts . get ( raw_id as usize ) . copied ( ) . flatten ( ) {
1361
1394
// This has already been decoded.
1362
1395
return ctxt;
1363
1396
}
1364
1397
1365
1398
match inner. decoding . entry ( raw_id) {
1366
1399
Entry :: Occupied ( ctxt_entry) => {
1400
+ let pending_ctxt = * ctxt_entry. get ( ) ;
1367
1401
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.
1374
1412
Entry :: Vacant ( entry) => {
1375
1413
entry. insert ( ( ) ) ;
1376
-
1377
- // Some other thread is current decoding this. Race with it.
1378
- * ctxt_entry. get ( )
1414
+ pending_ctxt
1379
1415
}
1380
1416
}
1381
1417
}
@@ -1386,18 +1422,10 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
1386
1422
// Allocate and store SyntaxContext id *before* calling the decoder function,
1387
1423
// as the SyntaxContextData may reference itself.
1388
1424
let new_ctxt = HygieneData :: with ( |hygiene_data| {
1389
- let new_ctxt = SyntaxContext ( hygiene_data. syntax_context_data . len ( ) as u32 ) ;
1390
1425
// 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 )
1401
1429
} ) ;
1402
1430
entry. insert ( new_ctxt) ;
1403
1431
new_ctxt
@@ -1407,38 +1435,39 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
1407
1435
1408
1436
// Don't try to decode data while holding the lock, since we need to
1409
1437
// 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) ;
1415
1439
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 )
1419
1442
&& old. outer_expn == ctxt_data. outer_expn
1420
1443
&& old. outer_transparency == ctxt_data. outer_transparency
1421
1444
&& old. parent == ctxt_data. parent
1422
1445
{
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;
1424
1459
}
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) ;
1437
1466
}
1467
+ pending_ctxt
1438
1468
} ) ;
1439
1469
1440
1470
// Mark the context as completed
1441
-
1442
1471
context. local_in_progress . borrow_mut ( ) . remove ( & raw_id) ;
1443
1472
1444
1473
let mut inner = context. inner . lock ( ) ;
0 commit comments