@@ -36,20 +36,21 @@ use rustc_middle::ty::subst::GenericArgKind;
36
36
use rustc_middle:: ty:: { self , AdtKind , Instance , ParamEnv , Ty , TyCtxt , COMMON_VTABLE_ENTRIES } ;
37
37
use rustc_session:: config:: { self , DebugInfo } ;
38
38
use rustc_span:: symbol:: Symbol ;
39
+ use rustc_span:: FileName ;
39
40
use rustc_span:: FileNameDisplayPreference ;
40
- use rustc_span:: { self , SourceFile , SourceFileHash } ;
41
+ use rustc_span:: { self , SourceFile } ;
41
42
use rustc_target:: abi:: { Align , Size } ;
42
43
use smallvec:: smallvec;
43
44
use tracing:: debug;
44
45
45
46
use libc:: { c_longlong, c_uint} ;
46
47
use std:: borrow:: Cow ;
47
- use std:: collections:: hash_map:: Entry ;
48
48
use std:: fmt:: { self , Write } ;
49
49
use std:: hash:: { Hash , Hasher } ;
50
50
use std:: iter;
51
51
use std:: path:: { Path , PathBuf } ;
52
52
use std:: ptr;
53
+ use tracing:: instrument;
53
54
54
55
impl PartialEq for llvm:: Metadata {
55
56
fn eq ( & self , other : & Self ) -> bool {
@@ -527,78 +528,105 @@ fn hex_encode(data: &[u8]) -> String {
527
528
}
528
529
529
530
pub fn file_metadata < ' ll > ( cx : & CodegenCx < ' ll , ' _ > , source_file : & SourceFile ) -> & ' ll DIFile {
530
- debug ! ( "file_metadata: file_name: {:?}" , source_file. name) ;
531
-
532
- let hash = Some ( & source_file. src_hash ) ;
533
- let file_name = Some ( source_file. name . prefer_remapped ( ) . to_string ( ) ) ;
534
- let directory = if source_file. is_real_file ( ) && !source_file. is_imported ( ) {
535
- Some (
536
- cx. sess ( )
537
- . opts
538
- . working_dir
539
- . to_string_lossy ( FileNameDisplayPreference :: Remapped )
540
- . to_string ( ) ,
541
- )
542
- } else {
543
- // If the path comes from an upstream crate we assume it has been made
544
- // independent of the compiler's working directory one way or another.
545
- None
546
- } ;
547
- file_metadata_raw ( cx, file_name, directory, hash)
548
- }
549
-
550
- pub fn unknown_file_metadata < ' ll > ( cx : & CodegenCx < ' ll , ' _ > ) -> & ' ll DIFile {
551
- file_metadata_raw ( cx, None , None , None )
552
- }
553
-
554
- fn file_metadata_raw < ' ll > (
555
- cx : & CodegenCx < ' ll , ' _ > ,
556
- file_name : Option < String > ,
557
- directory : Option < String > ,
558
- hash : Option < & SourceFileHash > ,
559
- ) -> & ' ll DIFile {
560
- let key = ( file_name, directory) ;
561
-
562
- match debug_context ( cx) . created_files . borrow_mut ( ) . entry ( key) {
563
- Entry :: Occupied ( o) => o. get ( ) ,
564
- Entry :: Vacant ( v) => {
565
- let ( file_name, directory) = v. key ( ) ;
566
- debug ! ( "file_metadata: file_name: {:?}, directory: {:?}" , file_name, directory) ;
567
-
568
- let file_name = file_name. as_deref ( ) . unwrap_or ( "<unknown>" ) ;
569
- let directory = directory. as_deref ( ) . unwrap_or ( "" ) ;
570
-
571
- let ( hash_kind, hash_value) = match hash {
572
- Some ( hash) => {
573
- let kind = match hash. kind {
574
- rustc_span:: SourceFileHashAlgorithm :: Md5 => llvm:: ChecksumKind :: MD5 ,
575
- rustc_span:: SourceFileHashAlgorithm :: Sha1 => llvm:: ChecksumKind :: SHA1 ,
576
- rustc_span:: SourceFileHashAlgorithm :: Sha256 => llvm:: ChecksumKind :: SHA256 ,
577
- } ;
578
- ( kind, hex_encode ( hash. hash_bytes ( ) ) )
531
+ let cache_key = Some ( ( source_file. name_hash , source_file. src_hash ) ) ;
532
+ return debug_context ( cx)
533
+ . created_files
534
+ . borrow_mut ( )
535
+ . entry ( cache_key)
536
+ . or_insert_with ( || alloc_new_file_metadata ( cx, source_file) ) ;
537
+
538
+ #[ instrument( skip( cx, source_file) , level = "debug" ) ]
539
+ fn alloc_new_file_metadata < ' ll > (
540
+ cx : & CodegenCx < ' ll , ' _ > ,
541
+ source_file : & SourceFile ,
542
+ ) -> & ' ll DIFile {
543
+ debug ! ( ?source_file. name) ;
544
+
545
+ let ( directory, file_name) = match & source_file. name {
546
+ FileName :: Real ( filename) => {
547
+ let working_directory = & cx. sess ( ) . opts . working_dir ;
548
+ debug ! ( ?working_directory) ;
549
+
550
+ let filename = cx
551
+ . sess ( )
552
+ . source_map ( )
553
+ . path_mapping ( )
554
+ . to_embeddable_absolute_path ( filename. clone ( ) , working_directory) ;
555
+
556
+ // Construct the absolute path of the file
557
+ let abs_path = filename. remapped_path_if_available ( ) ;
558
+ debug ! ( ?abs_path) ;
559
+
560
+ if let Ok ( rel_path) =
561
+ abs_path. strip_prefix ( working_directory. remapped_path_if_available ( ) )
562
+ {
563
+ // If the compiler's working directory (which also is the DW_AT_comp_dir of
564
+ // the compilation unit) is a prefix of the path we are about to emit, then
565
+ // only emit the part relative to the working directory.
566
+ // Because of path remapping we sometimes see strange things here: `abs_path`
567
+ // might actually look like a relative path
568
+ // (e.g. `<crate-name-and-version>/src/lib.rs`), so if we emit it without
569
+ // taking the working directory into account, downstream tooling will
570
+ // interpret it as `<working-directory>/<crate-name-and-version>/src/lib.rs`,
571
+ // which makes no sense. Usually in such cases the working directory will also
572
+ // be remapped to `<crate-name-and-version>` or some other prefix of the path
573
+ // we are remapping, so we end up with
574
+ // `<crate-name-and-version>/<crate-name-and-version>/src/lib.rs`.
575
+ // By moving the working directory portion into the `directory` part of the
576
+ // DIFile, we allow LLVM to emit just the relative path for DWARF, while
577
+ // still emitting the correct absolute path for CodeView.
578
+ (
579
+ working_directory. to_string_lossy ( FileNameDisplayPreference :: Remapped ) ,
580
+ rel_path. to_string_lossy ( ) . into_owned ( ) ,
581
+ )
582
+ } else {
583
+ ( "" . into ( ) , abs_path. to_string_lossy ( ) . into_owned ( ) )
579
584
}
580
- None => ( llvm:: ChecksumKind :: None , String :: new ( ) ) ,
581
- } ;
585
+ }
586
+ other => ( "" . into ( ) , other. prefer_remapped ( ) . to_string_lossy ( ) . into_owned ( ) ) ,
587
+ } ;
582
588
583
- let file_metadata = unsafe {
584
- llvm:: LLVMRustDIBuilderCreateFile (
585
- DIB ( cx) ,
586
- file_name. as_ptr ( ) . cast ( ) ,
587
- file_name. len ( ) ,
588
- directory. as_ptr ( ) . cast ( ) ,
589
- directory. len ( ) ,
590
- hash_kind,
591
- hash_value. as_ptr ( ) . cast ( ) ,
592
- hash_value. len ( ) ,
593
- )
594
- } ;
589
+ let hash_kind = match source_file. src_hash . kind {
590
+ rustc_span:: SourceFileHashAlgorithm :: Md5 => llvm:: ChecksumKind :: MD5 ,
591
+ rustc_span:: SourceFileHashAlgorithm :: Sha1 => llvm:: ChecksumKind :: SHA1 ,
592
+ rustc_span:: SourceFileHashAlgorithm :: Sha256 => llvm:: ChecksumKind :: SHA256 ,
593
+ } ;
594
+ let hash_value = hex_encode ( source_file. src_hash . hash_bytes ( ) ) ;
595
595
596
- v. insert ( file_metadata) ;
597
- file_metadata
596
+ unsafe {
597
+ llvm:: LLVMRustDIBuilderCreateFile (
598
+ DIB ( cx) ,
599
+ file_name. as_ptr ( ) . cast ( ) ,
600
+ file_name. len ( ) ,
601
+ directory. as_ptr ( ) . cast ( ) ,
602
+ directory. len ( ) ,
603
+ hash_kind,
604
+ hash_value. as_ptr ( ) . cast ( ) ,
605
+ hash_value. len ( ) ,
606
+ )
598
607
}
599
608
}
600
609
}
601
610
611
+ pub fn unknown_file_metadata < ' ll > ( cx : & CodegenCx < ' ll , ' _ > ) -> & ' ll DIFile {
612
+ debug_context ( cx) . created_files . borrow_mut ( ) . entry ( None ) . or_insert_with ( || unsafe {
613
+ let file_name = "<unknown>" ;
614
+ let directory = "" ;
615
+ let hash_value = "" ;
616
+
617
+ llvm:: LLVMRustDIBuilderCreateFile (
618
+ DIB ( cx) ,
619
+ file_name. as_ptr ( ) . cast ( ) ,
620
+ file_name. len ( ) ,
621
+ directory. as_ptr ( ) . cast ( ) ,
622
+ directory. len ( ) ,
623
+ llvm:: ChecksumKind :: None ,
624
+ hash_value. as_ptr ( ) . cast ( ) ,
625
+ hash_value. len ( ) ,
626
+ )
627
+ } )
628
+ }
629
+
602
630
trait MsvcBasicName {
603
631
fn msvc_basic_name ( self ) -> & ' static str ;
604
632
}
0 commit comments