@@ -36,20 +36,21 @@ use rustc_middle::ty::subst::GenericArgKind;
3636use rustc_middle:: ty:: { self , AdtKind , Instance , ParamEnv , Ty , TyCtxt , COMMON_VTABLE_ENTRIES } ;
3737use rustc_session:: config:: { self , DebugInfo } ;
3838use rustc_span:: symbol:: Symbol ;
39+ use rustc_span:: FileName ;
3940use rustc_span:: FileNameDisplayPreference ;
40- use rustc_span:: { self , SourceFile , SourceFileHash } ;
41+ use rustc_span:: { self , SourceFile } ;
4142use rustc_target:: abi:: { Align , Size } ;
4243use smallvec:: smallvec;
4344use tracing:: debug;
4445
4546use libc:: { c_longlong, c_uint} ;
4647use std:: borrow:: Cow ;
47- use std:: collections:: hash_map:: Entry ;
4848use std:: fmt:: { self , Write } ;
4949use std:: hash:: { Hash , Hasher } ;
5050use std:: iter;
5151use std:: path:: { Path , PathBuf } ;
5252use std:: ptr;
53+ use tracing:: instrument;
5354
5455impl PartialEq for llvm:: Metadata {
5556 fn eq ( & self , other : & Self ) -> bool {
@@ -527,78 +528,105 @@ fn hex_encode(data: &[u8]) -> String {
527528}
528529
529530pub 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 ( ) )
579584 }
580- None => ( llvm:: ChecksumKind :: None , String :: new ( ) ) ,
581- } ;
585+ }
586+ other => ( "" . into ( ) , other. prefer_remapped ( ) . to_string_lossy ( ) . into_owned ( ) ) ,
587+ } ;
582588
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 ( ) ) ;
595595
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+ )
598607 }
599608 }
600609}
601610
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+
602630trait MsvcBasicName {
603631 fn msvc_basic_name ( self ) -> & ' static str ;
604632}
0 commit comments