From: Adrian Prantl Date: Tue, 30 Jun 2015 17:39:51 +0000 (+0000) Subject: Debug Info: Emit debug info for @import declarations. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e9ad7b24fe294af689cd6c15171b3ced4bec36b4;p=clang Debug Info: Emit debug info for @import declarations. This allows a module-aware debugger such as LLDB to import the currently visible modules before dropping into the expression evaluator. rdar://problem/20965932 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241084 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index a139ce0e07..8daf8af4e1 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -27,6 +27,8 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Frontend/CodeGenOptions.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/PreprocessorOptions.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Constants.h" @@ -1661,6 +1663,49 @@ llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, return CreateTypeDefinition(Ty, Unit); } +llvm::DIModule * +CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod) { + llvm::DIModule *ModuleRef = nullptr; + auto it = ModuleRefCache.find(Mod.Signature); + if (it != ModuleRefCache.end()) + ModuleRef = it->second; + else { + // Macro definitions that were defined with "-D" on the command line. + SmallString<128> ConfigMacros; + { + llvm::raw_svector_ostream OS(ConfigMacros); + const auto &PPOpts = CGM.getPreprocessorOpts(); + unsigned I = 0; + // Translate the macro definitions back into a commmand line. + for (auto &M : PPOpts.Macros) { + if (++I > 1) + OS << " "; + const std::string &Macro = M.first; + bool Undef = M.second; + OS << "\"-" << (Undef ? 'U' : 'D'); + for (char c : Macro) + switch (c) { + case '\\' : OS << "\\\\"; break; + case '"' : OS << "\\\""; break; + default: OS << c; + } + OS << '\"'; + } + } + llvm::DIBuilder DIB(CGM.getModule()); + auto *CU = DIB.createCompileUnit( + TheCU->getSourceLanguage(), internString(Mod.ModuleName), + internString(Mod.Path), TheCU->getProducer(), true, StringRef(), 0, + internString(Mod.ASTFile), llvm::DIBuilder::FullDebug, Mod.Signature); + ModuleRef = DIB.createModule( + CU, Mod.ModuleName, ConfigMacros, internString(Mod.Path), + internString(CGM.getHeaderSearchOpts().Sysroot)); + DIB.finalize(); + ModuleRefCache.insert(std::make_pair(Mod.Signature, ModuleRef)); + } + return ModuleRef; +} + llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile *Unit) { ObjCInterfaceDecl *ID = Ty->getDecl(); @@ -3304,6 +3349,15 @@ void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) { getLineNumber(USD.getLocation())); } +void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) { + auto *Reader = CGM.getContext().getExternalSource(); + auto Info = Reader->getSourceDescriptor(*ID.getImportedModule()); + DBuilder.createImportedDeclaration( + getCurrentContextDescriptor(cast(ID.getDeclContext())), + getOrCreateModuleRef(Info), + getLineNumber(ID.getLocation())); +} + llvm::DIImportedEntity * CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) { if (CGM.getCodeGenOpts().getDebugInfo() < CodeGenOptions::LimitedDebugInfo) diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 8509e0770d..10d3b0d9ab 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -83,6 +83,9 @@ class CGDebugInfo { /// which may change. llvm::SmallVector ObjCInterfaceCache; + /// \brief Cache of references to AST files such as PCHs or modules. + llvm::DenseMap ModuleRefCache; + /// \brief list of interfaces we want to keep even if orphaned. std::vector RetainedTypes; @@ -289,6 +292,9 @@ public: /// \brief Emit C++ using declaration. void EmitUsingDecl(const UsingDecl &UD); + /// \brief Emit an @import declaration. + void EmitImportDecl(const ImportDecl &ID); + /// \brief Emit C++ namespace alias. llvm::DIImportedEntity *EmitNamespaceAlias(const NamespaceAliasDecl &NA); @@ -344,6 +350,10 @@ private: /// necessary. llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg); + /// \brief Get a reference to a clang module. + llvm::DIModule * + getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod); + /// \brief Get the type from the cache or create a new /// partial type if necessary. llvm::DIType *getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile *F); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index ea09ba8d4f..b905bd2b36 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -3362,6 +3362,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { Owner->getTopLevelModule()->Name == getLangOpts().CurrentModule) break; } + if (CGDebugInfo *DI = getModuleDebugInfo()) + DI->EmitImportDecl(*Import); ImportedModules.insert(Import->getImportedModule()); break; diff --git a/test/Modules/Inputs/DebugModule.h b/test/Modules/Inputs/DebugModule.h new file mode 100644 index 0000000000..5612b73a8c --- /dev/null +++ b/test/Modules/Inputs/DebugModule.h @@ -0,0 +1 @@ +@class F; diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index fe762f54a1..b9c8e72cfa 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -327,3 +327,8 @@ module recursive2 { module crash { header "crash.h" } + +module DebugModule { + header "DebugModule.h" +} + diff --git a/test/Modules/debug-info-moduleimport.m b/test/Modules/debug-info-moduleimport.m new file mode 100644 index 0000000000..9580af0849 --- /dev/null +++ b/test/Modules/debug-info-moduleimport.m @@ -0,0 +1,7 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -g -fmodules -DGREETING="Hello World" -UNDEBUG -fimplicit-module-maps -fmodules-cache-path=%t %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - | FileCheck %s + +// CHECK: ![[CU:.*]] = !DICompileUnit +@import DebugModule; +// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: ![[CU]], entity: ![[MODULE:.*]], line: 5) +// CHECK: ![[MODULE]] = !DIModule(scope: null, name: "DebugModule", configMacros: "\22-DGREETING=Hello World\22 \22-UNDEBUG\22", includePath: "{{.*}}/test/Modules/Inputs", isysroot: "/tmp/..")