DwarfDebug craziness

From DwarfDebug.cpp:

/// GetOrCreateSourceID - Look up the source id with the given directory and
/// source file names. If none currently exists, create a new id and insert it
/// in the SourceIds map. This can update DirectoryNames and SourceFileNames
/// maps as well.
unsigned DwarfDebug::GetOrCreateSourceID(StringRef FileName,
                                        StringRef DirName) {
// If FE did not provide a file name, then assume stdin.
if (FileName.empty())
   return GetOrCreateSourceID("<stdin>", StringRef());

// TODO: this might not belong here. See if we can factor this better.
if (DirName == CompilationDir)
   DirName = "";

The last snippet weirds me out and breaks Rust debug information
generation. Specifically, when creating a new compile unit, we see
this:

CompileUnit *DwarfDebug::constructCompileUnit(const MDNode *N) {
DICompileUnit DIUnit(N);
StringRef FN = DIUnit.getFilename();
CompilationDir = DIUnit.getDirectory();
unsigned ID = GetOrCreateSourceID(FN, CompilationDir);

Note how CompilationDir is passed to GetOrCreateSourceID as DirName?
That means that the map of compilation units is created entirely based
on file names excluding the path, so two compilation units that happen
to share a name generate identical source IDs and then attempt to
generate duplicate symbols for labels. For a temporary workaround
locally I've deleted the check in GetOrCreateSourceID, but I have no
idea if that has other negative consequences. Can someone who
understands what's going on here comment?

Cheers,
Josh

Josh Matthews wrote:

From DwarfDebug.cpp:

/// GetOrCreateSourceID - Look up the source id with the given directory and
/// source file names. If none currently exists, create a new id and insert it
/// in the SourceIds map. This can update DirectoryNames and SourceFileNames
/// maps as well.
unsigned DwarfDebug::GetOrCreateSourceID(StringRef FileName,
                                         StringRef DirName) {
  // If FE did not provide a file name, then assume stdin.
  if (FileName.empty())
    return GetOrCreateSourceID("<stdin>", StringRef());

  // TODO: this might not belong here. See if we can factor this better.
  if (DirName == CompilationDir)
    DirName = "";

The last snippet weirds me out and breaks Rust debug information
generation. Specifically, when creating a new compile unit, we see
this:

In DWARF, if the directory index is zero then it's assumed to be the contents of AT_compilation_dir. This implements that optimization.

CompileUnit *DwarfDebug::constructCompileUnit(const MDNode *N) {
  DICompileUnit DIUnit(N);
  StringRef FN = DIUnit.getFilename();
  CompilationDir = DIUnit.getDirectory();
  unsigned ID = GetOrCreateSourceID(FN, CompilationDir);

Note how CompilationDir is passed to GetOrCreateSourceID as DirName?
That means that the map of compilation units is created entirely based
on file names excluding the path, so two compilation units that happen
to share a name generate identical source IDs and then attempt to
generate duplicate symbols for labels.

The file name does not exclude the path:

$ cat a/a.c
int a(void) { return 0; }
$ clang a/a.c -g -S -o - -flto | grep DW_TAG_compile_unit
!0 = metadata !{i32 720913, i32 0, i32 12, metadata !"a/a.c", metadata !"/home/nicholas", metadata !"clang version 3.1 (trunk 146849)", i1 true, i1 false, metadata !"", i32 0, metadata !1, metadata !1, metadata !3, metadata !1} ; [ DW_TAG_compile_unit ]

Note that the filename is "a/a.c", not "a.c". The directory is also correct, as the file is indeed in /home/nicholas/a/a.c .

  For a temporary workaround

locally I've deleted the check in GetOrCreateSourceID, but I have no
idea if that has other negative consequences. Can someone who
understands what's going on here comment?

How is this breaking rust?

Nick

Oh, I see. I was operating under the assumption that the descriptions
from the docs

metadata, ;; Source file name
metadata, ;; Source file directory (includes trailing slash)

were equivalent to basename(file) and dirname(file) respectively.
Thanks for clearing this up.

Cheers,
Josh