@@ -18,6 +18,7 @@ use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded};
18
18
use rustc_data_structures:: sync:: { Lock , LockGuard } ;
19
19
use rustc_data_structures:: thin_vec:: ThinVec ;
20
20
use rustc_errors:: { DiagnosticBuilder , FatalError } ;
21
+ use rustc_session:: Session ;
21
22
use rustc_span:: { Span , DUMMY_SP } ;
22
23
use std:: cell:: Cell ;
23
24
use std:: collections:: hash_map:: Entry ;
@@ -595,38 +596,86 @@ fn incremental_verify_ich<CTX, K, V: Debug>(
595
596
debug ! ( "END verify_ich({:?})" , dep_node) ;
596
597
597
598
if Some ( new_hash) != old_hash {
598
- let run_cmd = if let Some ( crate_name) = & tcx. sess ( ) . opts . crate_name {
599
- format ! ( "`cargo clean -p {}` or `cargo clean`" , crate_name)
600
- } else {
601
- "`cargo clean`" . to_string ( )
602
- } ;
599
+ incremental_verify_ich_cold ( tcx. sess ( ) , DebugArg :: from ( & dep_node) , DebugArg :: from ( & result) ) ;
600
+ }
601
+ }
603
602
604
- // When we emit an error message and panic, we try to debug-print the `DepNode`
605
- // and query result. Unforunately, this can cause us to run additional queries,
606
- // which may result in another fingerprint mismatch while we're in the middle
607
- // of processing this one. To avoid a double-panic (which kills the process
608
- // before we can print out the query static), we print out a terse
609
- // but 'safe' message if we detect a re-entrant call to this method.
610
- thread_local ! {
611
- static INSIDE_VERIFY_PANIC : Cell <bool > = const { Cell :: new( false ) } ;
612
- } ;
603
+ // This DebugArg business is largely a mirror of std::fmt::ArgumentV1, which is
604
+ // currently not exposed publicly.
605
+ //
606
+ // The PR which added this attempted to use `&dyn Debug` instead, but that
607
+ // showed statistically significant worse compiler performance. It's not
608
+ // actually clear what the cause there was -- the code should be cold. If this
609
+ // can be replaced with `&dyn Debug` with on perf impact, then it probably
610
+ // should be.
611
+ extern "C" {
612
+ type Opaque ;
613
+ }
613
614
614
- let old_in_panic = INSIDE_VERIFY_PANIC . with ( |in_panic| in_panic. replace ( true ) ) ;
615
+ struct DebugArg < ' a > {
616
+ value : & ' a Opaque ,
617
+ fmt : fn ( & Opaque , & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result ,
618
+ }
615
619
616
- if old_in_panic {
617
- tcx. sess ( ) . struct_err ( "internal compiler error: re-entrant incremental verify failure, suppressing message" )
618
- . emit ( ) ;
619
- } else {
620
- tcx. sess ( ) . struct_err ( & format ! ( "internal compiler error: encountered incremental compilation error with {:?}" , dep_node) )
620
+ impl < ' a , T > From < & ' a T > for DebugArg < ' a >
621
+ where
622
+ T : std:: fmt:: Debug ,
623
+ {
624
+ fn from ( value : & ' a T ) -> DebugArg < ' a > {
625
+ DebugArg {
626
+ value : unsafe { std:: mem:: transmute ( value) } ,
627
+ fmt : unsafe {
628
+ std:: mem:: transmute ( <T as std:: fmt:: Debug >:: fmt as fn ( _, _) -> std:: fmt:: Result )
629
+ } ,
630
+ }
631
+ }
632
+ }
633
+
634
+ impl std:: fmt:: Debug for DebugArg < ' _ > {
635
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
636
+ ( self . fmt ) ( self . value , f)
637
+ }
638
+ }
639
+
640
+ // Note that this is marked #[cold] and intentionally takes the equivalent of
641
+ // `dyn Debug` for its arguments, as we want to avoid generating a bunch of
642
+ // different implementations for LLVM to chew on (and filling up the final
643
+ // binary, too).
644
+ #[ cold]
645
+ fn incremental_verify_ich_cold ( sess : & Session , dep_node : DebugArg < ' _ > , result : DebugArg < ' _ > ) {
646
+ let run_cmd = if let Some ( crate_name) = & sess. opts . crate_name {
647
+ format ! ( "`cargo clean -p {}` or `cargo clean`" , crate_name)
648
+ } else {
649
+ "`cargo clean`" . to_string ( )
650
+ } ;
651
+
652
+ // When we emit an error message and panic, we try to debug-print the `DepNode`
653
+ // and query result. Unfortunately, this can cause us to run additional queries,
654
+ // which may result in another fingerprint mismatch while we're in the middle
655
+ // of processing this one. To avoid a double-panic (which kills the process
656
+ // before we can print out the query static), we print out a terse
657
+ // but 'safe' message if we detect a re-entrant call to this method.
658
+ thread_local ! {
659
+ static INSIDE_VERIFY_PANIC : Cell <bool > = const { Cell :: new( false ) } ;
660
+ } ;
661
+
662
+ let old_in_panic = INSIDE_VERIFY_PANIC . with ( |in_panic| in_panic. replace ( true ) ) ;
663
+
664
+ if old_in_panic {
665
+ sess. struct_err (
666
+ "internal compiler error: re-entrant incremental verify failure, suppressing message" ,
667
+ )
668
+ . emit ( ) ;
669
+ } else {
670
+ sess. struct_err ( & format ! ( "internal compiler error: encountered incremental compilation error with {:?}" , dep_node) )
621
671
. help ( & format ! ( "This is a known issue with the compiler. Run {} to allow your project to compile" , run_cmd) )
622
672
. note ( & "Please follow the instructions below to create a bug report with the provided information" )
623
673
. note ( & "See <https://github.com/rust-lang/rust/issues/84970> for more information" )
624
674
. emit ( ) ;
625
- panic ! ( "Found unstable fingerprints for {:?}: {:?}" , dep_node, result) ;
626
- }
627
-
628
- INSIDE_VERIFY_PANIC . with ( |in_panic| in_panic. set ( old_in_panic) ) ;
675
+ panic ! ( "Found unstable fingerprints for {:?}: {:?}" , dep_node, result) ;
629
676
}
677
+
678
+ INSIDE_VERIFY_PANIC . with ( |in_panic| in_panic. set ( old_in_panic) ) ;
630
679
}
631
680
632
681
/// Ensure that either this query has all green inputs or been executed.
0 commit comments