From 2532f2149e5f58a48be1e0d3121fdb3b6734def2 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 11 Sep 2015 17:23:08 +0000 Subject: [PATCH] Module Debugging: Emit forward declarations for types that are defined in clang modules, if -dwarf-ext-refs (DebugTypesExtRefs) is specified. This reimplements r247369 in about a third of the amount of code. Thanks to David Blaikie pointing this out in post-commit review! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247432 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGDebugInfo.cpp | 68 ++++++++++++++++++++++++++++------ lib/CodeGen/CGDebugInfo.h | 3 ++ test/Modules/ExtDebugInfo.cpp | 69 +++++++++++++++++++++++++++++++++++ test/Modules/ExtDebugInfo.m | 29 +++++++++++++++ 4 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 test/Modules/ExtDebugInfo.cpp create mode 100644 test/Modules/ExtDebugInfo.m diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 693d0f6fdf..38be54ea75 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -148,7 +148,9 @@ void CGDebugInfo::setLocation(SourceLocation Loc) { } llvm::DIScope *CGDebugInfo::getDeclContextDescriptor(const Decl *D) { - return getContextDescriptor(cast(D->getDeclContext()), TheCU); + llvm::DIScope *Mod = getParentModuleOrNull(D); + return getContextDescriptor(cast(D->getDeclContext()), + Mod ? Mod : TheCU); } llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context, @@ -1448,6 +1450,9 @@ void CGDebugInfo::completeRequiredType(const RecordDecl *RD) { if (CXXDecl->isDynamicClass()) return; + if (DebugTypeExtRefs && RD->isFromASTFile()) + return; + QualType Ty = CGM.getContext().getRecordType(RD); llvm::DIType *T = getTypeOrNull(Ty); if (T && T->isForwardDecl()) @@ -1478,8 +1483,19 @@ static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I, } static bool shouldOmitDefinition(CodeGenOptions::DebugInfoKind DebugKind, + bool DebugTypeExtRefs, const RecordDecl *RD, const LangOptions &LangOpts) { + // Does the type exist in an imported clang module? + if (DebugTypeExtRefs && RD->isFromASTFile()) { + if (auto *CTSD = dyn_cast(RD)) + if (CTSD->isExplicitInstantiationOrSpecialization()) + // We may not assume that this type made it into the module. + return true; + if (RD->getDefinition()) + return true; + } + if (DebugKind > CodeGenOptions::LimitedDebugInfo) return false; @@ -1513,7 +1529,8 @@ static bool shouldOmitDefinition(CodeGenOptions::DebugInfoKind DebugKind, llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) { RecordDecl *RD = Ty->getDecl(); llvm::DIType *T = cast_or_null(getTypeOrNull(QualType(Ty, 0))); - if (T || shouldOmitDefinition(DebugKind, RD, CGM.getLangOpts())) { + if (T || shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD, + CGM.getLangOpts())) { if (!T) T = getOrCreateRecordFwdDecl(Ty, getDeclContextDescriptor(RD)); return T; @@ -1616,6 +1633,12 @@ llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (!ID) return nullptr; + // Return a forward declaration if this type was imported from a clang module. + if (DebugTypeExtRefs && ID->isFromASTFile() && ID->getDefinition()) + return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, + ID->getName(), + getDeclContextDescriptor(ID), Unit, 0); + // Get overall information about the record type for the debug info. llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation()); unsigned Line = getLineNumber(ID->getLocation()); @@ -1669,9 +1692,9 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod) { TheCU->getSourceLanguage(), internString(Mod.ModuleName), internString(Mod.Path), TheCU->getProducer(), true, StringRef(), 0, internString(Mod.ASTFile), llvm::DIBuilder::FullDebug, Mod.Signature); - llvm::DIModule *M = - DIB.createModule(CU, Mod.ModuleName, ConfigMacros, internString(Mod.Path), - internString(CGM.getHeaderSearchOpts().Sysroot)); + llvm::DIModule *M = DIB.createModule( + CU, Mod.ModuleName, ConfigMacros, internString(Mod.Path), + internString(CGM.getHeaderSearchOpts().Sysroot)); DIB.finalize(); ModRef.reset(M); return M; @@ -1930,6 +1953,7 @@ llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) { llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); + uint64_t Size = 0; uint64_t Align = 0; if (!ED->getTypeForDecl()->isIncompleteType()) { @@ -1939,9 +1963,12 @@ llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) { SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU); + bool isImportedFromModule = + DebugTypeExtRefs && ED->isFromASTFile() && ED->getDefinition(); + // If this is just a forward declaration, construct an appropriately // marked node and just return it. - if (!ED->getDefinition()) { + if (isImportedFromModule || !ED->getDefinition()) { llvm::DIScope *EDContext = getDeclContextDescriptor(ED); llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation()); unsigned Line = getLineNumber(ED->getLocation()); @@ -2081,9 +2108,8 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { if (auto *T = getTypeOrNull(Ty)) return T; - // Otherwise create the type. llvm::DIType *Res = CreateTypeNode(Ty, Unit); - void *TyPtr = Ty.getAsOpaquePtr(); + void* TyPtr = Ty.getAsOpaquePtr(); // And update the type cache. TypeCache[TyPtr].reset(Res); @@ -2115,6 +2141,19 @@ ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) { } } +llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) { + if (!DebugTypeExtRefs || !D || !D->isFromASTFile()) + return nullptr; + + llvm::DIModule *ModuleRef = nullptr; + auto *Reader = CGM.getContext().getExternalSource(); + auto Idx = D->getOwningModuleID(); + auto Info = Reader->getSourceDescriptor(Idx); + if (Info) + ModuleRef = getOrCreateModuleRef(*Info); + return ModuleRef; +} + llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { // Handle qualifiers, which recursively handles what they refer to. if (Ty.hasLocalQualifiers()) @@ -2325,8 +2364,10 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit, dyn_cast_or_null(FD->getDeclContext())) FDContext = getOrCreateNameSpace(NSDecl); else if (const RecordDecl *RDecl = - dyn_cast_or_null(FD->getDeclContext())) - FDContext = getContextDescriptor(RDecl, TheCU); + dyn_cast_or_null(FD->getDeclContext())) { + llvm::DIScope *Mod = getParentModuleOrNull(RDecl); + FDContext = getContextDescriptor(RDecl, Mod ? Mod : TheCU); + } // Collect template parameters. TParamsArray = CollectFunctionTemplateParams(FD, Unit); } @@ -2374,7 +2415,9 @@ void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit, // outside the class by putting it in the global scope. if (DC->isRecord()) DC = CGM.getContext().getTranslationUnitDecl(); - VDContext = getContextDescriptor(cast(DC), TheCU); + + llvm::DIScope *Mod = getParentModuleOrNull(VD); + VDContext = getContextDescriptor(cast(DC), Mod ? Mod : TheCU); } llvm::DISubprogram * @@ -3299,7 +3342,8 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) { if (!LexicalBlockStack.empty()) return LexicalBlockStack.back(); - return getContextDescriptor(D, TheCU); + llvm::DIScope *Mod = getParentModuleOrNull(D); + return getContextDescriptor(D, Mod ? Mod : TheCU); } void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) { diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 507496ba3a..3ff377ec18 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -397,6 +397,9 @@ private: llvm::DIModule * getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod); + /// DebugTypeExtRefs: If \p D originated in a clang module, return it. + llvm::DIModule *getParentModuleOrNull(const Decl *D); + /// Get the type from the cache or create a new partial type if /// necessary. llvm::DICompositeType *getOrCreateLimitedType(const RecordType *Ty, diff --git a/test/Modules/ExtDebugInfo.cpp b/test/Modules/ExtDebugInfo.cpp new file mode 100644 index 0000000000..91b9a770e6 --- /dev/null +++ b/test/Modules/ExtDebugInfo.cpp @@ -0,0 +1,69 @@ +// RUN: rm -rf %t +// Test that only forward declarations are emitted for types dfined in modules. + +// Modules: +// RUN: %clang_cc1 -x objective-c++ -std=c++11 -g -dwarf-ext-refs -fmodules \ +// RUN: -fmodule-format=obj -fimplicit-module-maps -DMODULES \ +// RUN: -fmodules-cache-path=%t %s -I %S/Inputs -I %t -emit-llvm -o %t-mod.ll +// RUN: cat %t-mod.ll | FileCheck %s + +// PCH: +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodule-format=obj -emit-pch -I%S/Inputs \ +// RUN: -o %t.pch %S/Inputs/DebugCXX.h +// RUN: %clang_cc1 -std=c++11 -g -dwarf-ext-refs -fmodule-format=obj \ +// RUN: -include-pch %t.pch %s -emit-llvm -o %t-pch.ll %s +// RUN: cat %t-pch.ll | FileCheck %s + +#ifdef MODULES +@import DebugCXX; +#endif + +using DebugCXX::Struct; + +Struct s; +DebugCXX::Enum e; +DebugCXX::Template implicitTemplate; +DebugCXX::Template explicitTemplate; +DebugCXX::FloatInstatiation typedefTemplate; +int Struct::static_member = -1; +enum { + e3 = -1 +} conflicting_uid = e3; +auto anon_enum = DebugCXX::e2; +char _anchor = anon_enum + conflicting_uid; + +// CHECK: ![[NS:.*]] = !DINamespace(name: "DebugCXX", scope: ![[MOD:[0-9]+]], +// CHECK: ![[MOD]] = !DIModule(scope: null, name: {{.*}}DebugCXX + +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Struct", +// CHECK-SAME: scope: ![[NS]], +// CHECK-SAME: flags: DIFlagFwdDecl, +// CHECK-SAME: identifier: "_ZTSN8DebugCXX6StructE") + +// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum", +// CHECK-SAME: scope: ![[NS]], +// CHECK-SAME: flags: DIFlagFwdDecl, +// CHECK-SAME: identifier: "_ZTSN8DebugCXX4EnumE") + +// CHECK: !DICompositeType(tag: DW_TAG_class_type, + +// CHECK: !DICompositeType(tag: DW_TAG_class_type, +// CHECK-SAME: name: "Template >", +// CHECK-SAME: scope: ![[NS]], +// CHECK-SAME: flags: DIFlagFwdDecl, +// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIiNS_6traitsIiEEEE") + +// CHECK: !DICompositeType(tag: DW_TAG_class_type, +// CHECK-SAME: name: "Template >", +// CHECK-SAME: scope: ![[NS]], +// CHECK-SAME: flags: DIFlagFwdDecl, +// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE") + +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "static_member", +// CHECK-SAME: scope: !"_ZTSN8DebugCXX6StructE" + +// CHECK: !DIGlobalVariable(name: "anon_enum", {{.*}}, type: ![[ANON_ENUM:[0-9]+]] +// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, scope: ![[NS]], +// CHECK-SAME: line: 16 + +// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !"_ZTSN8DebugCXX6StructE", line: 21) diff --git a/test/Modules/ExtDebugInfo.m b/test/Modules/ExtDebugInfo.m new file mode 100644 index 0000000000..6431a88677 --- /dev/null +++ b/test/Modules/ExtDebugInfo.m @@ -0,0 +1,29 @@ +// RUN: rm -rf %t +// Test that only forward declarations are emitted for types dfined in modules. + +// Modules: +// RUN: %clang_cc1 -x objective-c -g -dwarf-ext-refs -fmodules \ +// RUN: -fmodule-format=obj -fimplicit-module-maps -DMODULES \ +// RUN: -fmodules-cache-path=%t %s -I %S/Inputs -I %t -emit-llvm -o %t-mod.ll +// RUN: cat %t-mod.ll | FileCheck %s + +// PCH: +// RUN: %clang_cc1 -x objective-c -fmodule-format=obj -emit-pch -I%S/Inputs \ +// RUN: -o %t.pch %S/Inputs/DebugObjC.h +// RUN: %clang_cc1 -x objective-c -g -dwarf-ext-refs -fmodule-format=obj \ +// RUN: -include-pch %t.pch %s -emit-llvm -o %t-pch.ll %s +// RUN: cat %t-pch.ll | FileCheck %s + +#ifdef MODULES +@import DebugObjC; +#endif + +int foo(ObjCClass *c) { + [c instanceMethodWithInt: 0]; + return [c property]; +} + +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, +// CHECK-SAME: scope: ![[MOD:[0-9]+]], +// CHECK-SAME: flags: DIFlagFwdDecl) +// CHECK: ![[MOD]] = !DIModule(scope: null, name: {{.*}}DebugObjC -- 2.40.0