From: Adrian Prantl Date: Thu, 11 May 2017 22:59:19 +0000 (+0000) Subject: Module Debug Info: Emit namespaced C++ forward decls in the correct module. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7c80de2a7fd93882e335d7c0fa4165d3b5e2923a;p=clang Module Debug Info: Emit namespaced C++ forward decls in the correct module. The AST merges NamespaceDecls, but for module debug info it is important to put a namespace decl (or rather its children) into the correct (sub-)module, so we need to use the parent module of the decl that triggered this namespace to be serialized as a second key when looking up DINamespace nodes. rdar://problem/29339538 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@302840 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 3e54346605..d15ae06b45 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -208,8 +208,10 @@ llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context, } // Check namespace. - if (const auto *NSDecl = dyn_cast(Context)) - return getOrCreateNameSpace(NSDecl); + if (const auto *NSDecl = dyn_cast(Context)) { + auto *ParentModule = dyn_cast(Default); + return getOrCreateNamespace(NSDecl, ParentModule); + } if (const auto *RDecl = dyn_cast(Context)) if (!RDecl->isDependentType()) @@ -2861,7 +2863,7 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit, if (DebugKind >= codegenoptions::LimitedDebugInfo) { if (const NamespaceDecl *NSDecl = dyn_cast_or_null(FD->getDeclContext())) - FDContext = getOrCreateNameSpace(NSDecl); + FDContext = getOrCreateNamespace(NSDecl, getParentModuleOrNull(FD)); else if (const RecordDecl *RDecl = dyn_cast_or_null(FD->getDeclContext())) { llvm::DIScope *Mod = getParentModuleOrNull(RDecl); @@ -3961,7 +3963,7 @@ void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) { CGM.getCodeGenOpts().DebugExplicitImport) { DBuilder.createImportedModule( getCurrentContextDescriptor(cast(UD.getDeclContext())), - getOrCreateNameSpace(NSDecl), + getOrCreateNamespace(NSDecl, getParentModuleOrNull(&UD)), getLineNumber(UD.getLocation())); } } @@ -4021,23 +4023,32 @@ CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) { else R = DBuilder.createImportedDeclaration( getCurrentContextDescriptor(cast(NA.getDeclContext())), - getOrCreateNameSpace(cast(NA.getAliasedNamespace())), + getOrCreateNamespace(cast(NA.getAliasedNamespace()), + getParentModuleOrNull(&NA)), getLineNumber(NA.getLocation()), NA.getName()); VH.reset(R); return R; } llvm::DINamespace * -CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) { +CGDebugInfo::getOrCreateNamespace(const NamespaceDecl *NSDecl, + llvm::DIModule *ParentModule) { NSDecl = NSDecl->getCanonicalDecl(); - auto I = NameSpaceCache.find(NSDecl); - if (I != NameSpaceCache.end()) + // The AST merges NamespaceDecls, but for module debug info it is important to + // put a namespace decl (or rather its children) into the correct + // (sub-)module, so use the parent module of the decl that triggered this + // namespace to be serialized as a second key. + NamespaceKey Key = {NSDecl, ParentModule}; + auto I = NamespaceCache.find(Key); + if (I != NamespaceCache.end()) return cast(I->second); llvm::DIScope *Context = getDeclContextDescriptor(NSDecl); - llvm::DINamespace *NS = - DBuilder.createNameSpace(Context, NSDecl->getName(), NSDecl->isInline()); - NameSpaceCache[NSDecl].reset(NS); + // Don't trust the context if it is a DIModule (see comment above). + llvm::DINamespace *NS = DBuilder.createNameSpace( + isa(Context) ? ParentModule : Context, NSDecl->getName(), + NSDecl->isInline()); + NamespaceCache[Key].reset(NS); return NS; } diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 5050ca0ad3..beafd25f9b 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -125,7 +125,8 @@ class CGDebugInfo { /// Cache declarations relevant to DW_TAG_imported_declarations (C++ /// using declarations) that aren't covered by other more specific caches. llvm::DenseMap DeclCache; - llvm::DenseMap NameSpaceCache; + typedef std::pair NamespaceKey; + llvm::DenseMap NamespaceCache; llvm::DenseMap NamespaceAliasCache; llvm::DenseMap> @@ -194,8 +195,15 @@ class CGDebugInfo { getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F); /// \return debug info descriptor for vtable. llvm::DIType *getOrCreateVTablePtrType(llvm::DIFile *F); + + /// \return namespace descriptor for the given namespace decl. + /// /// \return namespace descriptor for the given namespace decl. - llvm::DINamespace *getOrCreateNameSpace(const NamespaceDecl *N); + /// \param ParentModule The parent module (or nullptr) of this particular + /// namespace decl. This needs to be passed in because + /// the AST merges namespace decls. + llvm::DINamespace *getOrCreateNamespace(const NamespaceDecl *N, + llvm::DIModule *ParentModule); llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, QualType PointeeTy, llvm::DIFile *F); llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache); diff --git a/test/Modules/DebugInfoNamespace.cpp b/test/Modules/DebugInfoNamespace.cpp new file mode 100644 index 0000000000..33add085d8 --- /dev/null +++ b/test/Modules/DebugInfoNamespace.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -x objective-c++ -std=c++11 -debug-info-kind=standalone \ +// RUN: -dwarf-ext-refs -fmodules \ +// RUN: -fmodule-format=obj -fimplicit-module-maps \ +// RUN: -triple %itanium_abi_triple -fmodules-cache-path=%t \ +// RUN: %s -I %S/Inputs/DebugInfoNamespace -I %t -emit-llvm -o - \ +// RUN: | FileCheck %s + +#include "A.h" +#include "B.h" +using namespace N; +B b; + +// Verify that the forward decl of B is in module B. +// +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "B", +// CHECK-SAME: scope: ![[N:[0-9]+]] +// CHECK: ![[N]] = !DINamespace(name: "N", scope: ![[B:[0-9]+]]) +// CHECK: ![[B]] = !DIModule(scope: null, name: "B", diff --git a/test/Modules/Inputs/DebugInfoNamespace/A.h b/test/Modules/Inputs/DebugInfoNamespace/A.h new file mode 100644 index 0000000000..dc5a1cd26a --- /dev/null +++ b/test/Modules/Inputs/DebugInfoNamespace/A.h @@ -0,0 +1,3 @@ +namespace N { + struct A {}; +} diff --git a/test/Modules/Inputs/DebugInfoNamespace/B.h b/test/Modules/Inputs/DebugInfoNamespace/B.h new file mode 100644 index 0000000000..c9033a54d4 --- /dev/null +++ b/test/Modules/Inputs/DebugInfoNamespace/B.h @@ -0,0 +1,3 @@ +namespace N { + struct B {}; +} diff --git a/test/Modules/Inputs/DebugInfoNamespace/module.modulemap b/test/Modules/Inputs/DebugInfoNamespace/module.modulemap new file mode 100644 index 0000000000..9300fcf98c --- /dev/null +++ b/test/Modules/Inputs/DebugInfoNamespace/module.modulemap @@ -0,0 +1,8 @@ +module A { + header "A.h" + export * +} +module B { + header "B.h" + export * +}