[DebugInfo] Support Fortran 'use <external module>' statement.
authorChih-Ping Chen <chih-ping.chen@intel.com>
Thu, 17 Dec 2020 16:08:46 +0000 (11:08 -0500)
committerChih-Ping Chen <chih-ping.chen@intel.com>
Fri, 18 Dec 2020 18:10:57 +0000 (13:10 -0500)
The main change is to add a 'IsDecl' field to DIModule so
that when IsDecl is set to true, the debug info entry generated
for the module would be marked as a declaration. That way, the debugger
would look up the definition of the module in the gloabl scope.

Please see the comments in llvm/test/DebugInfo/X86/dimodule.ll
for what the debug info entries would look like.

Differential Revision: https://reviews.llvm.org/D93462

14 files changed:
llvm/include/llvm/IR/DIBuilder.h
llvm/include/llvm/IR/DebugInfoMetadata.h
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/Bitcode/Reader/MetadataLoader.cpp
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
llvm/lib/IR/AsmWriter.cpp
llvm/lib/IR/DIBuilder.cpp
llvm/lib/IR/DebugInfoMetadata.cpp
llvm/lib/IR/LLVMContextImpl.h
llvm/test/Assembler/dimodule.ll
llvm/test/Bitcode/DIModule-fortran-external-module.ll [new file with mode: 0644]
llvm/test/DebugInfo/X86/dimodule.ll [new file with mode: 0644]
llvm/unittests/IR/MetadataTest.cpp

index 11c6e97..e023856 100644 (file)
@@ -772,14 +772,18 @@ namespace llvm {
     ///                    definitions as they would appear on a command line.
     /// \param IncludePath The path to the module map file.
     /// \param APINotesFile The path to an API notes file for this module.
-    /// \param File        Source file of the module declaration. Used for
-    ///                    Fortran modules.
-    /// \param LineNo      Source line number of the  module declaration.
+    /// \param File        Source file of the module.
     ///                    Used for Fortran modules.
+    /// \param LineNo      Source line number of the module.
+    ///                    Used for Fortran modules.
+    /// \param IsDecl      This is a module declaration; default to false;
+    ///                    when set to true, only Scope and Name are required
+    ///                    as this entry is just a hint for the debugger to find
+    ///                    the corresponding definition in the global scope.
     DIModule *createModule(DIScope *Scope, StringRef Name,
                            StringRef ConfigurationMacros, StringRef IncludePath,
                            StringRef APINotesFile = {}, DIFile *File = nullptr,
-                           unsigned LineNo = 0);
+                           unsigned LineNo = 0, bool IsDecl = false);
 
     /// This creates a descriptor for a lexical block with a new file
     /// attached. This merely extends the existing
index 0ba4c09..94b3beb 100644 (file)
@@ -2297,49 +2297,52 @@ class DIModule : public DIScope {
   friend class LLVMContextImpl;
   friend class MDNode;
   unsigned LineNo;
+  bool IsDecl;
 
   DIModule(LLVMContext &Context, StorageType Storage, unsigned LineNo,
-           ArrayRef<Metadata *> Ops)
+           bool IsDecl, ArrayRef<Metadata *> Ops)
       : DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops),
-        LineNo(LineNo) {}
+        LineNo(LineNo), IsDecl(IsDecl) {}
   ~DIModule() = default;
 
   static DIModule *getImpl(LLVMContext &Context, DIFile *File, DIScope *Scope,
                            StringRef Name, StringRef ConfigurationMacros,
                            StringRef IncludePath, StringRef APINotesFile,
-                           unsigned LineNo, StorageType Storage,
+                           unsigned LineNo, bool IsDecl, StorageType Storage,
                            bool ShouldCreate = true) {
     return getImpl(Context, File, Scope, getCanonicalMDString(Context, Name),
                    getCanonicalMDString(Context, ConfigurationMacros),
                    getCanonicalMDString(Context, IncludePath),
-                   getCanonicalMDString(Context, APINotesFile), LineNo, Storage,
-                   ShouldCreate);
+                   getCanonicalMDString(Context, APINotesFile), LineNo, IsDecl,
+                   Storage, ShouldCreate);
   }
   static DIModule *getImpl(LLVMContext &Context, Metadata *File,
                            Metadata *Scope, MDString *Name,
                            MDString *ConfigurationMacros, MDString *IncludePath,
-                           MDString *APINotesFile, unsigned LineNo,
+                           MDString *APINotesFile, unsigned LineNo, bool IsDecl,
                            StorageType Storage, bool ShouldCreate = true);
 
   TempDIModule cloneImpl() const {
     return getTemporary(getContext(), getFile(), getScope(), getName(),
                         getConfigurationMacros(), getIncludePath(),
-                        getAPINotesFile(), getLineNo());
+                        getAPINotesFile(), getLineNo(), getIsDecl());
   }
 
 public:
   DEFINE_MDNODE_GET(DIModule,
                     (DIFile * File, DIScope *Scope, StringRef Name,
                      StringRef ConfigurationMacros, StringRef IncludePath,
-                     StringRef APINotesFile, unsigned LineNo),
+                     StringRef APINotesFile, unsigned LineNo,
+                     bool IsDecl = false),
                     (File, Scope, Name, ConfigurationMacros, IncludePath,
-                     APINotesFile, LineNo))
+                     APINotesFile, LineNo, IsDecl))
   DEFINE_MDNODE_GET(DIModule,
                     (Metadata * File, Metadata *Scope, MDString *Name,
                      MDString *ConfigurationMacros, MDString *IncludePath,
-                     MDString *APINotesFile, unsigned LineNo),
+                     MDString *APINotesFile, unsigned LineNo,
+                     bool IsDecl = false),
                     (File, Scope, Name, ConfigurationMacros, IncludePath,
-                     APINotesFile, LineNo))
+                     APINotesFile, LineNo, IsDecl))
 
   TempDIModule clone() const { return cloneImpl(); }
 
@@ -2349,6 +2352,7 @@ public:
   StringRef getIncludePath() const { return getStringOperand(4); }
   StringRef getAPINotesFile() const { return getStringOperand(5); }
   unsigned getLineNo() const { return LineNo; }
+  bool getIsDecl() const { return IsDecl; }
 
   Metadata *getRawScope() const { return getOperand(1); }
   MDString *getRawName() const { return getOperandAs<MDString>(2); }
index 8146930..eff81e3 100644 (file)
@@ -5119,7 +5119,7 @@ bool LLParser::parseDIMacroFile(MDNode *&Result, bool IsDistinct) {
 /// parseDIModule:
 ///   ::= !DIModule(scope: !0, name: "SomeModule", configMacros:
 ///   "-DNDEBUG", includePath: "/usr/include", apinotes: "module.apinotes",
-///   file: !1, line: 4)
+///   file: !1, line: 4, isDecl: false)
 bool LLParser::parseDIModule(MDNode *&Result, bool IsDistinct) {
 #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED)                                    \
   REQUIRED(scope, MDField, );                                                  \
@@ -5128,13 +5128,14 @@ bool LLParser::parseDIModule(MDNode *&Result, bool IsDistinct) {
   OPTIONAL(includePath, MDStringField, );                                      \
   OPTIONAL(apinotes, MDStringField, );                                         \
   OPTIONAL(file, MDField, );                                                   \
-  OPTIONAL(line, LineField, );
+  OPTIONAL(line, LineField, );                                                 \
+  OPTIONAL(isDecl, MDBoolField, );
   PARSE_MD_FIELDS();
 #undef VISIT_MD_FIELDS
 
   Result = GET_OR_DISTINCT(DIModule, (Context, file.Val, scope.Val, name.Val,
                                       configMacros.Val, includePath.Val,
-                                      apinotes.Val, line.Val));
+                                      apinotes.Val, line.Val, isDecl.Val));
   return false;
 }
 
index 3fc85b1..8cdda62 100644 (file)
@@ -1565,19 +1565,20 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
   }
 
   case bitc::METADATA_MODULE: {
-    if (Record.size() < 5 || Record.size() > 8)
+    if (Record.size() < 5 || Record.size() > 9)
       return error("Invalid record");
 
-    unsigned Offset = Record.size() >= 7 ? 2 : 1;
+    unsigned Offset = Record.size() >= 8 ? 2 : 1;
     IsDistinct = Record[0];
     MetadataList.assignValue(
         GET_OR_DISTINCT(
             DIModule,
-            (Context, Record.size() >= 7 ? getMDOrNull(Record[1]) : nullptr,
+            (Context, Record.size() >= 8 ? getMDOrNull(Record[1]) : nullptr,
              getMDOrNull(Record[0 + Offset]), getMDString(Record[1 + Offset]),
              getMDString(Record[2 + Offset]), getMDString(Record[3 + Offset]),
              getMDString(Record[4 + Offset]),
-             Record.size() <= 7 ? 0 : Record[7])),
+             Record.size() <= 7 ? 0 : Record[7],
+             Record.size() <= 8 ? false : Record[8])),
         NextMetadataNo);
     NextMetadataNo++;
     break;
index b6a2e0b..dee7025 100644 (file)
@@ -1868,6 +1868,7 @@ void ModuleBitcodeWriter::writeDIModule(const DIModule *N,
   for (auto &I : N->operands())
     Record.push_back(VE.getMetadataOrNullID(I));
   Record.push_back(N->getLineNo());
+  Record.push_back(N->getIsDecl());
 
   Stream.EmitRecord(bitc::METADATA_MODULE, Record, Abbrev);
   Record.clear();
index b552a07..118b5fc 100644 (file)
@@ -1067,6 +1067,8 @@ DIE *DwarfUnit::getOrCreateModule(const DIModule *M) {
             getOrCreateSourceID(M->getFile()));
   if (M->getLineNo())
     addUInt(MDie, dwarf::DW_AT_decl_line, None, M->getLineNo());
+  if (M->getIsDecl())
+    addFlag(MDie, dwarf::DW_AT_declaration);
 
   return &MDie;
 }
index 88331bf..393f036 100644 (file)
@@ -2245,6 +2245,7 @@ static void writeDIModule(raw_ostream &Out, const DIModule *N,
   Printer.printString("apinotes", N->getAPINotesFile());
   Printer.printMetadata("file", N->getRawFile());
   Printer.printInt("line", N->getLineNo());
+  Printer.printBool("isDecl", N->getIsDecl(), /* Default */ false);
   Out << ")";
 }
 
index ac2777d..5104dc3 100644 (file)
@@ -874,9 +874,10 @@ DINamespace *DIBuilder::createNameSpace(DIScope *Scope, StringRef Name,
 DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name,
                                   StringRef ConfigurationMacros,
                                   StringRef IncludePath, StringRef APINotesFile,
-                                  DIFile *File, unsigned LineNo) {
+                                  DIFile *File, unsigned LineNo, bool IsDecl) {
   return DIModule::get(VMContext, File, getNonCompileUnitScope(Scope), Name,
-                       ConfigurationMacros, IncludePath, APINotesFile, LineNo);
+                       ConfigurationMacros, IncludePath, APINotesFile, LineNo,
+                       IsDecl);
 }
 
 DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope,
index bee35fe..22eca57 100644 (file)
@@ -926,14 +926,14 @@ DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *File,
                             Metadata *Scope, MDString *Name,
                             MDString *ConfigurationMacros,
                             MDString *IncludePath, MDString *APINotesFile,
-                            unsigned LineNo, StorageType Storage,
+                            unsigned LineNo, bool IsDecl, StorageType Storage,
                             bool ShouldCreate) {
   assert(isCanonical(Name) && "Expected canonical MDString");
   DEFINE_GETIMPL_LOOKUP(DIModule, (File, Scope, Name, ConfigurationMacros,
-                                   IncludePath, APINotesFile, LineNo));
+                                   IncludePath, APINotesFile, LineNo, IsDecl));
   Metadata *Ops[] = {File,        Scope,       Name, ConfigurationMacros,
                      IncludePath, APINotesFile};
-  DEFINE_GETIMPL_STORE(DIModule, (LineNo), Ops);
+  DEFINE_GETIMPL_STORE(DIModule, (LineNo, IsDecl), Ops);
 }
 
 DITemplateTypeParameter *
index cae2760..ddbf1e5 100644 (file)
@@ -891,25 +891,28 @@ template <> struct MDNodeKeyImpl<DIModule> {
   MDString *IncludePath;
   MDString *APINotesFile;
   unsigned LineNo;
+  bool IsDecl;
 
   MDNodeKeyImpl(Metadata *File, Metadata *Scope, MDString *Name,
                 MDString *ConfigurationMacros, MDString *IncludePath,
-                MDString *APINotesFile, unsigned LineNo)
+                MDString *APINotesFile, unsigned LineNo, bool IsDecl)
       : File(File), Scope(Scope), Name(Name),
         ConfigurationMacros(ConfigurationMacros), IncludePath(IncludePath),
-        APINotesFile(APINotesFile), LineNo(LineNo) {}
+        APINotesFile(APINotesFile), LineNo(LineNo), IsDecl(IsDecl) {}
   MDNodeKeyImpl(const DIModule *N)
       : File(N->getRawFile()), Scope(N->getRawScope()), Name(N->getRawName()),
         ConfigurationMacros(N->getRawConfigurationMacros()),
         IncludePath(N->getRawIncludePath()),
-        APINotesFile(N->getRawAPINotesFile()), LineNo(N->getLineNo()) {}
+        APINotesFile(N->getRawAPINotesFile()), LineNo(N->getLineNo()),
+        IsDecl(N->getIsDecl()) {}
 
   bool isKeyOf(const DIModule *RHS) const {
     return Scope == RHS->getRawScope() && Name == RHS->getRawName() &&
            ConfigurationMacros == RHS->getRawConfigurationMacros() &&
            IncludePath == RHS->getRawIncludePath() &&
            APINotesFile == RHS->getRawAPINotesFile() &&
-           File == RHS->getRawFile() && LineNo == RHS->getLineNo();
+           File == RHS->getRawFile() && LineNo == RHS->getLineNo() &&
+           IsDecl == RHS->getIsDecl();
   }
 
   unsigned getHashValue() const {
index 39d1d32..f5932e5 100644 (file)
@@ -1,8 +1,8 @@
 ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
 ; RUN: verify-uselistorder %s
 
-; CHECK: !named = !{!0, !1, !2, !1, !3}
-!named = !{!0, !1, !2, !3, !4}
+; CHECK: !named = !{!0, !1, !2, !1, !3, !4}
+!named = !{!0, !1, !2, !3, !4, !5}
 
 !0 = distinct !{}
 
@@ -16,3 +16,6 @@
 
 ; CHECK: !3 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", apinotes: "/tmp/m.apinotes", file: !0, line: 1)
 !4 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", apinotes: "/tmp/m.apinotes", file: !0, line: 1)
+
+; CHECK: !4 = !DIModule(scope: !0, name: "Module", isDecl: true)
+!5 = !DIModule(scope: !0, name: "Module", isDecl: true)
diff --git a/llvm/test/Bitcode/DIModule-fortran-external-module.ll b/llvm/test/Bitcode/DIModule-fortran-external-module.ll
new file mode 100644 (file)
index 0000000..a10804b
--- /dev/null
@@ -0,0 +1,59 @@
+; RUN: llvm-as -o - %s | llvm-dis -o - | FileCheck %s
+; CHECK: DIImportedEntity(tag: DW_TAG_imported_module, scope: !2, entity: !11, file: !3, line: 2)
+; CHECK: DIModule(scope: !2, name: "external_module", isDecl: true)
+
+; ModuleID = 'em.f90'
+source_filename = "em.f90"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@external_module_mp_dummy_ = available_externally global float 0.000000e+00, align 8, !dbg !0
+@0 = internal unnamed_addr constant i32 2
+
+; Function Attrs: noinline nounwind uwtable
+define void @MAIN__() #0 !dbg !2 {
+alloca_0:
+  %"var$1" = alloca [8 x i64], align 8
+  %"use_external_module_$X" = alloca float, align 8
+  call void @llvm.dbg.declare(metadata float* %"use_external_module_$X", metadata !13, metadata !DIExpression()), !dbg !17
+  %func_result = call i32 @for_set_reentrancy(i32* @0), !dbg !18
+  %external_module_mp_dummy__fetch = load float, float* @external_module_mp_dummy_, align 1, !dbg !19
+  %add = fadd reassoc ninf nsz arcp contract afn float 2.000000e+00, %external_module_mp_dummy__fetch, !dbg !20
+  store float %add, float* %"use_external_module_$X", align 1, !dbg !19
+  ret void, !dbg !21
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare i32 @for_set_reentrancy(i32*)
+
+attributes #0 = { noinline nounwind uwtable "intel-lang"="fortran" "min-legal-vector-width"="0" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.module.flags = !{!15, !16}
+!llvm.dbg.cu = !{!6}
+!omp_offload.info = !{}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "dummy", linkageName: "external_module_mp_dummy_", scope: !2, file: !3, line: 1, type: !14, isLocal: false, isDefinition: true)
+!2 = distinct !DISubprogram(name: "use_external_module", linkageName: "MAIN__", scope: !3, file: !3, line: 1, type: !4, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !12)
+!3 = !DIFile(filename: "em.f90", directory: "tests")
+!4 = !DISubroutineType(types: !5)
+!5 = !{null}
+!6 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3, producer: "Intel(R) Fortran 21.0-2165", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !7, globals: !8, imports: !9, splitDebugInlining: false, nameTableKind: None)
+!7 = !{}
+!8 = !{!0}
+!9 = !{!10}
+!10 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !2, entity: !11, file: !3, line: 2)
+!11 = !DIModule(scope: !2, name: "external_module", isDecl: true)
+!12 = !{!13}
+!13 = !DILocalVariable(name: "x", scope: !2, file: !3, line: 5, type: !14)
+!14 = !DIBasicType(name: "REAL*4", size: 32, encoding: DW_ATE_float)
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 2, !"Dwarf Version", i32 4}
+!17 = !DILocation(line: 5, column: 12, scope: !2)
+!18 = !DILocation(line: 1, column: 9, scope: !2)
+!19 = !DILocation(line: 6, column: 4, scope: !2)
+!20 = !DILocation(line: 6, column: 12, scope: !2)
+!21 = !DILocation(line: 8, column: 1, scope: !2)
diff --git a/llvm/test/DebugInfo/X86/dimodule.ll b/llvm/test/DebugInfo/X86/dimodule.ll
new file mode 100644 (file)
index 0000000..a2892c5
--- /dev/null
@@ -0,0 +1,91 @@
+; This test verifies that the debug info for an external Fortran module
+; is correctly generated.
+;
+; To generate the test source, compile the following two files in order in
+; the same directory (as the second compilation uses the .mod from the first):
+; external_module.f90 (to compile: <fortran compiler> -g -c external_module.f90)
+;   module external_module
+;     real :: dummy
+;   end module external_module
+;
+; em.f90 (to compile: <fortran compierl> -g -llvm-emit -c -S em.f90)
+;   program use_external_module
+;   use external_module
+;   implicit none
+;
+;     real :: x
+;     x = 2.0 + dummy
+;
+;   end program use_external_module
+;
+; The test would be in em.ll.
+
+; RUN: llc -filetype=obj  %s -o - | llvm-dwarfdump - | FileCheck %s
+
+; CHECK: [[DIE_ID:0x[0-9a-f]+]]: DW_TAG_module
+; CHECK-NEXT:                      DW_AT_name    ("external_module")
+; CHECK-NEXT:                      DW_AT_declaration     (true)
+
+; CHECK:      DW_TAG_imported_module
+; CHECK-NEXT:   DW_AT_decl_file
+; CHECK-NEXT:   DW_AT_decl_line
+; CHECK-NEXT:   DW_AT_import  ([[DIE_ID]])
+
+; When the debugger sees the module being imported is a declaration,
+; it should go to the global scope to find the module's definition.
+
+; ModuleID = 'em.f90'
+source_filename = "em.f90"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@external_module_mp_dummy_ = available_externally global float 0.000000e+00, align 8, !dbg !0
+@0 = internal unnamed_addr constant i32 2
+
+; Function Attrs: noinline nounwind uwtable
+define void @MAIN__() #0 !dbg !2 {
+alloca_0:
+  %"var$1" = alloca [8 x i64], align 8
+  %"use_external_module_$X" = alloca float, align 8
+  call void @llvm.dbg.declare(metadata float* %"use_external_module_$X", metadata !13, metadata !DIExpression()), !dbg !17
+  %func_result = call i32 @for_set_reentrancy(i32* @0), !dbg !18
+  %external_module_mp_dummy__fetch = load float, float* @external_module_mp_dummy_, align 1, !dbg !19
+  %add = fadd reassoc ninf nsz arcp contract afn float 2.000000e+00, %external_module_mp_dummy__fetch, !dbg !20
+  store float %add, float* %"use_external_module_$X", align 1, !dbg !19
+  ret void, !dbg !21
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare i32 @for_set_reentrancy(i32*)
+
+attributes #0 = { noinline nounwind uwtable "intel-lang"="fortran" "min-legal-vector-width"="0" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.module.flags = !{!15, !16}
+!llvm.dbg.cu = !{!6}
+!omp_offload.info = !{}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "dummy", linkageName: "external_module_mp_dummy_", scope: !2, file: !3, line: 1, type: !14, isLocal: false, isDefinition: true)
+!2 = distinct !DISubprogram(name: "use_external_module", linkageName: "MAIN__", scope: !3, file: !3, line: 1, type: !4, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !12)
+!3 = !DIFile(filename: "em.f90", directory: "tests")
+!4 = !DISubroutineType(types: !5)
+!5 = !{null}
+!6 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3, producer: "Intel(R) Fortran 21.0-2165", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !7, globals: !8, imports: !9, splitDebugInlining: false, nameTableKind: None)
+!7 = !{}
+!8 = !{!0}
+!9 = !{!10}
+!10 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !2, entity: !11, file: !3, line: 2)
+!11 = !DIModule(scope: !2, name: "external_module", isDecl: true)
+!12 = !{!13}
+!13 = !DILocalVariable(name: "x", scope: !2, file: !3, line: 5, type: !14)
+!14 = !DIBasicType(name: "REAL*4", size: 32, encoding: DW_ATE_float)
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 2, !"Dwarf Version", i32 4}
+!17 = !DILocation(line: 5, column: 12, scope: !2)
+!18 = !DILocation(line: 1, column: 9, scope: !2)
+!19 = !DILocation(line: 6, column: 4, scope: !2)
+!20 = !DILocation(line: 6, column: 12, scope: !2)
+!21 = !DILocation(line: 8, column: 1, scope: !2)
index 899bf68..5c05076 100644 (file)
@@ -2459,9 +2459,10 @@ TEST_F(DIModuleTest, get) {
   StringRef Includes = "-I.";
   StringRef APINotes = "/tmp/m.apinotes";
   unsigned LineNo = 4;
+  bool IsDecl = true;
 
   auto *N = DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
-                          APINotes, LineNo);
+                          APINotes, LineNo, IsDecl);
 
   EXPECT_EQ(dwarf::DW_TAG_module, N->getTag());
   EXPECT_EQ(File, N->getFile());
@@ -2471,22 +2472,25 @@ TEST_F(DIModuleTest, get) {
   EXPECT_EQ(Includes, N->getIncludePath());
   EXPECT_EQ(APINotes, N->getAPINotesFile());
   EXPECT_EQ(LineNo, N->getLineNo());
+  EXPECT_EQ(IsDecl, N->getIsDecl());
   EXPECT_EQ(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
-                             APINotes, LineNo));
+                             APINotes, LineNo, IsDecl));
   EXPECT_NE(N, DIModule::get(Context, getFile(), getFile(), Name, ConfigMacro,
-                             Includes, APINotes, LineNo));
+                             Includes, APINotes, LineNo, IsDecl));
   EXPECT_NE(N, DIModule::get(Context, File, Scope, "other", ConfigMacro,
-                             Includes, APINotes, LineNo));
+                             Includes, APINotes, LineNo, IsDecl));
   EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, "other", Includes,
-                             APINotes, LineNo));
+                             APINotes, LineNo, IsDecl));
   EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, "other",
-                             APINotes, LineNo));
+                             APINotes, LineNo, IsDecl));
   EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
-                             "other", LineNo));
+                             "other", LineNo, IsDecl));
   EXPECT_NE(N, DIModule::get(Context, getFile(), Scope, Name, ConfigMacro,
-                             Includes, APINotes, LineNo));
+                             Includes, APINotes, LineNo, IsDecl));
   EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
-                             APINotes, 5));
+                             APINotes, 5, IsDecl));
+  EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
+                             APINotes, LineNo, false));
 
   TempDIModule Temp = N->clone();
   EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));