forked from OSchip/llvm-project
Module Debugging: Emit forward declarations for types that are defined in
clang modules, if -dwarf-ext-refs (DebugTypesExtRefs) is specified. llvm-svn: 247369
This commit is contained in:
parent
d0929a1c87
commit
49553dd269
|
@ -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())
|
||||
|
@ -1669,9 +1674,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;
|
||||
|
@ -2081,9 +2086,16 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
|
|||
if (auto *T = getTypeOrNull(Ty))
|
||||
return T;
|
||||
|
||||
llvm::DIType *Res = nullptr;
|
||||
if (DebugTypeExtRefs)
|
||||
// Make a forward declaration of an external type.
|
||||
Res = getTypeExtRefOrNull(Ty, Unit);
|
||||
|
||||
// Otherwise create the type.
|
||||
llvm::DIType *Res = CreateTypeNode(Ty, Unit);
|
||||
void *TyPtr = Ty.getAsOpaquePtr();
|
||||
if (!Res)
|
||||
Res = CreateTypeNode(Ty, Unit);
|
||||
|
||||
void* TyPtr = Ty.getAsOpaquePtr();
|
||||
|
||||
// And update the type cache.
|
||||
TypeCache[TyPtr].reset(Res);
|
||||
|
@ -2115,6 +2127,123 @@ 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::getTypeExtRefOrNull(QualType Ty, llvm::DIFile *F,
|
||||
bool Anchored) {
|
||||
assert(DebugTypeExtRefs && "module debugging only");
|
||||
Decl *TyDecl = nullptr;
|
||||
StringRef Name;
|
||||
SmallString<256> UID;
|
||||
unsigned Tag = 0;
|
||||
|
||||
// Handle all types that have a declaration.
|
||||
switch (Ty->getTypeClass()) {
|
||||
case Type::Typedef: {
|
||||
TyDecl = cast<TypedefType>(Ty)->getDecl();
|
||||
if (!TyDecl->isFromASTFile())
|
||||
return nullptr;
|
||||
|
||||
// A typedef will anchor a type in the module.
|
||||
if (auto *TD = dyn_cast<TypedefDecl>(TyDecl)) {
|
||||
// This is a working around the fact that LLVM does not allow
|
||||
// typedefs to be forward declarations.
|
||||
QualType Ty = TD->getUnderlyingType();
|
||||
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
|
||||
if (auto *AnchoredTy = getTypeExtRefOrNull(Ty, F, /*Anchored=*/true)) {
|
||||
TypeCache[Ty.getAsOpaquePtr()].reset(AnchoredTy);
|
||||
SourceLocation Loc = TD->getLocation();
|
||||
return DBuilder.createTypedef(AnchoredTy, TD->getName(),
|
||||
getOrCreateFile(Loc), getLineNumber(Loc),
|
||||
getDeclContextDescriptor(TD));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Record: {
|
||||
TyDecl = cast<RecordType>(Ty)->getDecl();
|
||||
if (!TyDecl->isFromASTFile())
|
||||
return nullptr;
|
||||
|
||||
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TyDecl))
|
||||
if (!CTSD->isExplicitInstantiationOrSpecialization() && !Anchored)
|
||||
// We may not assume that this type made it into the module.
|
||||
return nullptr;
|
||||
// C++ classes and template instantiations.
|
||||
if (auto *RD = dyn_cast<CXXRecordDecl>(TyDecl)) {
|
||||
if (!RD->getDefinition())
|
||||
return nullptr;
|
||||
Tag = getTagForRecord(RD);
|
||||
UID =
|
||||
getUniqueTagTypeName(cast<TagType>(RD->getTypeForDecl()), CGM, TheCU);
|
||||
Name = getClassName(RD);
|
||||
} else if (auto *RD = dyn_cast<RecordDecl>(TyDecl)) {
|
||||
// C-style structs.
|
||||
if (!RD->getDefinition())
|
||||
return nullptr;
|
||||
Tag = getTagForRecord(RD);
|
||||
Name = getClassName(RD);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Enum: {
|
||||
TyDecl = cast<EnumType>(Ty)->getDecl();
|
||||
if (!TyDecl->isFromASTFile())
|
||||
return nullptr;
|
||||
|
||||
if (auto *ED = dyn_cast<EnumDecl>(TyDecl)) {
|
||||
if (!ED->getDefinition())
|
||||
return nullptr;
|
||||
Tag = llvm::dwarf::DW_TAG_enumeration_type;
|
||||
if ((TheCU->getSourceLanguage() == llvm::dwarf::DW_LANG_C_plus_plus) ||
|
||||
(TheCU->getSourceLanguage() == llvm::dwarf::DW_LANG_ObjC_plus_plus)) {
|
||||
UID = getUniqueTagTypeName(cast<TagType>(ED->getTypeForDecl()), CGM,
|
||||
TheCU);
|
||||
Name = ED->getName();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::ObjCInterface: {
|
||||
TyDecl = cast<ObjCInterfaceType>(Ty)->getDecl();
|
||||
if (!TyDecl->isFromASTFile())
|
||||
return nullptr;
|
||||
|
||||
if (auto *ID = dyn_cast<ObjCInterfaceDecl>(TyDecl)) {
|
||||
if (!ID->getDefinition())
|
||||
return nullptr;
|
||||
Tag = llvm::dwarf::DW_TAG_structure_type;
|
||||
Name = ID->getName();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (Tag && !Name.empty()) {
|
||||
assert(TyDecl);
|
||||
auto *Ctx = getDeclContextDescriptor(TyDecl);
|
||||
return DBuilder.createForwardDecl(Tag, Name, Ctx, F, 0, 0, 0, 0, UID);
|
||||
} else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
|
||||
// Handle qualifiers, which recursively handles what they refer to.
|
||||
if (Ty.hasLocalQualifiers())
|
||||
|
@ -2325,8 +2454,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 +2505,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 +3432,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) {
|
||||
|
|
|
@ -397,6 +397,15 @@ private:
|
|||
llvm::DIModule *
|
||||
getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod);
|
||||
|
||||
/// DebugTypeExtRefs: If \p D originated in a clang module, return it.
|
||||
llvm::DIModule *getParentModuleOrNull(const Decl *D);
|
||||
|
||||
/// Return a forward declaration of an external type, if this type
|
||||
/// came from a clang module. If \p Anchored is true, template
|
||||
/// types will be assumed to have been instantiated in the module.
|
||||
llvm::DIType *getTypeExtRefOrNull(QualType Ty, llvm::DIFile *F,
|
||||
bool Anchored = false);
|
||||
|
||||
/// Get the type from the cache or create a new partial type if
|
||||
/// necessary.
|
||||
llvm::DICompositeType *getOrCreateLimitedType(const RecordType *Ty,
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// 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: ![[ANON_ENUM:[0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type
|
||||
// CHECK-SAME: scope: ![[MOD:[0-9]+]],
|
||||
// CHECK-SAME: {{.*}}line: 16, {{.*}}, elements: ![[EE:[0-9]+]])
|
||||
|
||||
// CHECK: ![[NS:.*]] = !DINamespace(name: "DebugCXX", scope: ![[MOD:[0-9]+]],
|
||||
// CHECK: ![[MOD]] = !DIModule(scope: null, name: {{.*}}DebugCXX
|
||||
|
||||
// CHECK: ![[EE]] = !{![[E2:[0-9]+]]}
|
||||
// CHECK: ![[E2]] = !DIEnumerator(name: "e2", value: 50)
|
||||
|
||||
// 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]]
|
||||
|
||||
// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !"_ZTSN8DebugCXX6StructE", line: 21)
|
|
@ -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
|
Loading…
Reference in New Issue