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!

llvm-svn: 247432
This commit is contained in:
Adrian Prantl 2015-09-11 17:23:08 +00:00
parent ca8441810f
commit 5c8bd88a4c
4 changed files with 157 additions and 12 deletions

View File

@ -148,7 +148,9 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
}
llvm::DIScope *CGDebugInfo::getDeclContextDescriptor(const Decl *D) {
return getContextDescriptor(cast<Decl>(D->getDeclContext()), TheCU);
llvm::DIScope *Mod = getParentModuleOrNull(D);
return getContextDescriptor(cast<Decl>(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<ClassTemplateSpecializationDecl>(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<llvm::DIType>(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<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNameSpace(NSDecl);
else if (const RecordDecl *RDecl =
dyn_cast_or_null<RecordDecl>(FD->getDeclContext()))
FDContext = getContextDescriptor(RDecl, TheCU);
dyn_cast_or_null<RecordDecl>(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<Decl>(DC), TheCU);
llvm::DIScope *Mod = getParentModuleOrNull(VD);
VDContext = getContextDescriptor(cast<Decl>(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) {

View File

@ -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,

View File

@ -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<long> implicitTemplate;
DebugCXX::Template<int> 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<int, DebugCXX::traits<int> >",
// CHECK-SAME: scope: ![[NS]],
// CHECK-SAME: flags: DIFlagFwdDecl,
// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIiNS_6traitsIiEEEE")
// CHECK: !DICompositeType(tag: DW_TAG_class_type,
// CHECK-SAME: name: "Template<float, DebugCXX::traits<float> >",
// 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)

View File

@ -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