Debug info: better handling of static aggregate members with DIFlagStaticMember

Once again closer to GDC and Clang's output, and attaching static variables to the module scope prevents an assert from triggering in IR/DIBuilder.cpp:

  checkGlobalVariableScope(): Assertion `CT->getIdentifier().empty() && "Context of a global variable should not be a type with identifier"'
This commit is contained in:
Elie Morisse 2018-08-19 22:31:02 -03:00 committed by Martin Kinkelin
parent 2cdae62b0e
commit 9facf5ad28
2 changed files with 77 additions and 6 deletions

View file

@ -29,6 +29,9 @@
#include "module.h"
#include "mtype.h"
#include "nspace.h"
#include "template.h"
#include <functional>
////////////////////////////////////////////////////////////////////////////////
@ -108,6 +111,17 @@ ldc::DIScope ldc::DIBuilder::GetSymbolScope(Dsymbol* s) {
auto parent = s->toParent();
auto vd = s->isVarDeclaration();
if (vd && vd->isDataseg()) {
// static variables get attached to the module scope, but their
// parent composite types have to get declared
while (!parent->isModule()) {
if (parent->isAggregateDeclaration())
CreateCompositeTypeDescription(parent->getType());
parent = parent->toParent();
}
}
if (auto tempinst = parent->isTemplateInstance()) {
return GetSymbolScope(tempinst->tempdecl);
} else if (auto m = parent->isModule()) {
@ -391,7 +405,8 @@ ldc::DIType ldc::DIBuilder::CreateComplexType(Type *type) {
ldc::DIType ldc::DIBuilder::CreateMemberType(unsigned linnum, Type *type,
ldc::DIFile file,
const char *c_name,
unsigned offset, Prot::Kind prot) {
unsigned offset, Prot::Kind prot,
bool isStatic, DIScope scope) {
Type *t = type->toBasetype();
// translate functions to function pointers
@ -418,7 +433,10 @@ ldc::DIType ldc::DIBuilder::CreateMemberType(unsigned linnum, Type *type,
break;
}
return DBuilder.createMemberType(GetCU(),
if (isStatic)
Flags |= DIFlags::FlagStaticMember;
return DBuilder.createMemberType(scope,
c_name, // name
file, // file
linnum, // line number
@ -441,6 +459,34 @@ void ldc::DIBuilder::AddFields(AggregateDeclaration *ad, ldc::DIFile file,
}
}
void ldc::DIBuilder::AddStaticMembers(AggregateDeclaration *ad, ldc::DIFile file,
llvm::SmallVector<LLMetadata *, 16> &elems) {
auto scope = CreateCompositeTypeDescription(ad->getType());
std::function<void(Dsymbols*)> visitMembers = [&] (Dsymbols* members) {
for (auto s : *members) {
if (auto attrib = s->isAttribDeclaration()) {
if (Dsymbols *d = attrib->include(nullptr))
visitMembers(d);
} else if (auto tmixin = s->isTemplateMixin()) {
visitMembers(tmixin->members); // FIXME: static variables inside a template mixin need to be put inside a child DICompositeType for their value to become accessible (mangling issue).
// Also DWARF supports imported declarations, but LLVM currently does nothing with DIImportedEntity except at CU-level.
} else if (auto vd = s->isVarDeclaration())
if (vd->isDataseg() && !vd->aliassym /* TODO: tuples*/) {
llvm::MDNode* elem = CreateMemberType(vd->loc.linnum, vd->type, file,
vd->toChars(), 0,
vd->prot().kind,
/*isStatic = */true, scope);
elems.push_back(elem);
StaticDataMemberCache[vd].reset(elem);
}
} /*else if (auto fd = s->isFuncDeclaration())*/ // Clang also adds static functions as declarations,
// but they already work without adding them.
};
visitMembers(ad->members);
}
ldc::DIType ldc::DIBuilder::CreateCompositeType(Type *type) {
Type *t = type->toBasetype();
assert((t->ty == Tstruct || t->ty == Tclass) &&
@ -522,6 +568,7 @@ ldc::DIType ldc::DIBuilder::CreateCompositeType(Type *type) {
}
AddFields(ad, file, elems);
}
AddStaticMembers(ad, file, elems);
auto elemsArray = DBuilder.getOrCreateArray(elems);
@ -739,6 +786,12 @@ ldc::DIType ldc::DIBuilder::CreateTypeDescription(Type *type) {
llvm_unreachable("Unsupported type in debug info");
}
ldc::DICompositeType ldc::DIBuilder::CreateCompositeTypeDescription(Type *type) {
DIType ret = type->toBasetype()->ty == Tclass
? CreateCompositeType(type) : CreateTypeDescription(type);
return llvm::cast<llvm::DICompositeType>(ret);
}
////////////////////////////////////////////////////////////////////////////////
llvm::DICompileUnit::DebugEmissionKind getDebugEmissionKind()
@ -1171,6 +1224,15 @@ void ldc::DIBuilder::EmitGlobalVariable(llvm::GlobalVariable *llVar,
assert(vd->isDataseg() ||
(vd->storage_class & (STCconst | STCimmutable) && vd->_init));
DIScope scope = GetSymbolScope(vd);
llvm::MDNode* Decl = nullptr;
if (vd->isDataseg() && vd->toParent()->isAggregateDeclaration()) {
// static aggregate member
Decl = StaticDataMemberCache[vd];
assert(Decl && "static aggregate member not declared");
}
OutBuffer mangleBuf;
mangleToBuffer(vd, &mangleBuf);
@ -1179,7 +1241,7 @@ void ldc::DIBuilder::EmitGlobalVariable(llvm::GlobalVariable *llVar,
#else
DBuilder.createGlobalVariable(
#endif
GetSymbolScope(vd), // context
scope, // context
vd->toChars(), // name
mangleBuf.peekString(), // linkage name
CreateFile(vd), // file
@ -1187,10 +1249,11 @@ void ldc::DIBuilder::EmitGlobalVariable(llvm::GlobalVariable *llVar,
CreateTypeDescription(vd->type), // type
vd->protection.kind == Prot::private_, // is local to unit
#if LDC_LLVM_VER >= 400
nullptr // relative location of field
nullptr, // relative location of field
#else
llVar // value
llVar, // value
#endif
Decl // declaration
);
#if LDC_LLVM_VER >= 400