@@ -26,6 +26,7 @@ use tokenstream::{TokenStream, TokenTree};
26
26
use tokenstream;
27
27
28
28
use std:: { cmp, fmt} ;
29
+ use std:: mem;
29
30
use rustc_data_structures:: sync:: { Lrc , Lock } ;
30
31
31
32
#[ derive( Clone , RustcEncodable , RustcDecodable , PartialEq , Eq , Hash , Debug , Copy ) ]
@@ -88,6 +89,12 @@ impl Lit {
88
89
ByteStr ( _) | ByteStrRaw ( ..) => "byte string"
89
90
}
90
91
}
92
+
93
+ // See comments in `interpolated_to_tokenstream` for why we care about
94
+ // *probably* equal here rather than actual equality
95
+ fn probably_equal_for_proc_macro ( & self , other : & Lit ) -> bool {
96
+ mem:: discriminant ( self ) == mem:: discriminant ( other)
97
+ }
91
98
}
92
99
93
100
pub ( crate ) fn ident_can_begin_expr ( ident : ast:: Ident , is_raw : bool ) -> bool {
@@ -530,14 +537,6 @@ impl Token {
530
537
// stream they came from. Here we attempt to extract these
531
538
// lossless token streams before we fall back to the
532
539
// stringification.
533
- //
534
- // During early phases of the compiler, though, the AST could
535
- // get modified directly (e.g. attributes added or removed) and
536
- // the internal cache of tokens my not be invalidated or
537
- // updated. Consequently if the "lossless" token stream
538
- // disagrees with our actuall stringification (which has
539
- // historically been much more battle-tested) then we go with
540
- // the lossy stream anyway (losing span information).
541
540
let mut tokens = None ;
542
541
543
542
match nt. 0 {
@@ -569,13 +568,96 @@ impl Token {
569
568
let source = pprust:: token_to_string ( self ) ;
570
569
parse_stream_from_source_str ( FileName :: MacroExpansion , source, sess, Some ( span) )
571
570
} ) ;
571
+
572
+ // During early phases of the compiler the AST could get modified
573
+ // directly (e.g. attributes added or removed) and the internal cache
574
+ // of tokens my not be invalidated or updated. Consequently if the
575
+ // "lossless" token stream disagrees with our actual stringification
576
+ // (which has historically been much more battle-tested) then we go
577
+ // with the lossy stream anyway (losing span information).
578
+ //
579
+ // Note that the comparison isn't `==` here to avoid comparing spans,
580
+ // but it *also* is a "probable" equality which is a pretty weird
581
+ // definition. We mostly want to catch actual changes to the AST
582
+ // like a `#[cfg]` being processed or some weird `macro_rules!`
583
+ // expansion.
584
+ //
585
+ // What we *don't* want to catch is the fact that a user-defined
586
+ // literal like `0xf` is stringified as `15`, causing the cached token
587
+ // stream to not be literal `==` token-wise (ignoring spans) to the
588
+ // token stream we got from stringification.
589
+ //
590
+ // Instead the "probably equal" check here is "does each token
591
+ // recursively have the same discriminant?" We basically don't look at
592
+ // the token values here and assume that such fine grained modifications
593
+ // of token streams doesn't happen.
572
594
if let Some ( tokens) = tokens {
573
- if tokens. eq_unspanned ( & tokens_for_real) {
595
+ if tokens. probably_equal_for_proc_macro ( & tokens_for_real) {
574
596
return tokens
575
597
}
576
598
}
577
599
return tokens_for_real
578
600
}
601
+
602
+ // See comments in `interpolated_to_tokenstream` for why we care about
603
+ // *probably* equal here rather than actual equality
604
+ pub fn probably_equal_for_proc_macro ( & self , other : & Token ) -> bool {
605
+ if mem:: discriminant ( self ) != mem:: discriminant ( other) {
606
+ return false
607
+ }
608
+ match ( self , other) {
609
+ ( & Eq , & Eq ) |
610
+ ( & Lt , & Lt ) |
611
+ ( & Le , & Le ) |
612
+ ( & EqEq , & EqEq ) |
613
+ ( & Ne , & Ne ) |
614
+ ( & Ge , & Ge ) |
615
+ ( & Gt , & Gt ) |
616
+ ( & AndAnd , & AndAnd ) |
617
+ ( & OrOr , & OrOr ) |
618
+ ( & Not , & Not ) |
619
+ ( & Tilde , & Tilde ) |
620
+ ( & At , & At ) |
621
+ ( & Dot , & Dot ) |
622
+ ( & DotDot , & DotDot ) |
623
+ ( & DotDotDot , & DotDotDot ) |
624
+ ( & DotDotEq , & DotDotEq ) |
625
+ ( & DotEq , & DotEq ) |
626
+ ( & Comma , & Comma ) |
627
+ ( & Semi , & Semi ) |
628
+ ( & Colon , & Colon ) |
629
+ ( & ModSep , & ModSep ) |
630
+ ( & RArrow , & RArrow ) |
631
+ ( & LArrow , & LArrow ) |
632
+ ( & FatArrow , & FatArrow ) |
633
+ ( & Pound , & Pound ) |
634
+ ( & Dollar , & Dollar ) |
635
+ ( & Question , & Question ) |
636
+ ( & Whitespace , & Whitespace ) |
637
+ ( & Comment , & Comment ) |
638
+ ( & Eof , & Eof ) => true ,
639
+
640
+ ( & BinOp ( a) , & BinOp ( b) ) |
641
+ ( & BinOpEq ( a) , & BinOpEq ( b) ) => a == b,
642
+
643
+ ( & OpenDelim ( a) , & OpenDelim ( b) ) |
644
+ ( & CloseDelim ( a) , & CloseDelim ( b) ) => a == b,
645
+
646
+ ( & DocComment ( a) , & DocComment ( b) ) |
647
+ ( & Shebang ( a) , & Shebang ( b) ) => a == b,
648
+
649
+ ( & Lifetime ( a) , & Lifetime ( b) ) => a. name == b. name ,
650
+ ( & Ident ( a, b) , & Ident ( c, d) ) => a. name == c. name && b == d,
651
+
652
+ ( & Literal ( ref a, b) , & Literal ( ref c, d) ) => {
653
+ b == d && a. probably_equal_for_proc_macro ( c)
654
+ }
655
+
656
+ ( & Interpolated ( _) , & Interpolated ( _) ) => false ,
657
+
658
+ _ => panic ! ( "forgot to add a token?" ) ,
659
+ }
660
+ }
579
661
}
580
662
581
663
#[ derive( Clone , RustcEncodable , RustcDecodable , Eq , Hash ) ]
0 commit comments