Collect both normal and static data members of a class in source
order. Describe static data members to metadata using new interfaces. Part of PR14471. Patch by Paul Robinson! llvm-svn: 172591
This commit is contained in:
parent
4d23a4ae1f
commit
91a3190a28
|
@ -747,33 +747,6 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
|
|||
}
|
||||
|
||||
|
||||
void CGDebugInfo::
|
||||
CollectRecordStaticVars(const RecordDecl *RD, llvm::DIType FwdDecl) {
|
||||
|
||||
for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end();
|
||||
I != E; ++I)
|
||||
if (const VarDecl *V = dyn_cast<VarDecl>(*I)) {
|
||||
if (V->getInit()) {
|
||||
const APValue *Value = V->evaluateValue();
|
||||
if (Value && Value->isInt()) {
|
||||
llvm::ConstantInt *CI
|
||||
= llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
|
||||
|
||||
// Create the descriptor for static variable.
|
||||
llvm::DIFile VUnit = getOrCreateFile(V->getLocation());
|
||||
StringRef VName = V->getName();
|
||||
llvm::DIType VTy = getOrCreateType(V->getType(), VUnit);
|
||||
// Do not use DIGlobalVariable for enums.
|
||||
if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) {
|
||||
DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit,
|
||||
getLineNumber(V->getLocation()),
|
||||
VTy, true, CI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llvm::DIType CGDebugInfo::createFieldType(StringRef name,
|
||||
QualType type,
|
||||
uint64_t sizeInBitsOverride,
|
||||
|
@ -807,94 +780,155 @@ llvm::DIType CGDebugInfo::createFieldType(StringRef name,
|
|||
alignInBits, offsetInBits, flags, debugType);
|
||||
}
|
||||
|
||||
/// CollectRecordLambdaFields - Helper for CollectRecordFields.
|
||||
void CGDebugInfo::
|
||||
CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
|
||||
SmallVectorImpl<llvm::Value *> &elements,
|
||||
llvm::DIType RecordTy) {
|
||||
// For C++11 Lambdas a Field will be the same as a Capture, but the Capture
|
||||
// has the name and the location of the variable so we should iterate over
|
||||
// both concurrently.
|
||||
const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(CXXDecl);
|
||||
RecordDecl::field_iterator Field = CXXDecl->field_begin();
|
||||
unsigned fieldno = 0;
|
||||
for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
|
||||
E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
|
||||
const LambdaExpr::Capture C = *I;
|
||||
if (C.capturesVariable()) {
|
||||
VarDecl *V = C.getCapturedVar();
|
||||
llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
|
||||
StringRef VName = V->getName();
|
||||
uint64_t SizeInBitsOverride = 0;
|
||||
if (Field->isBitField()) {
|
||||
SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
|
||||
assert(SizeInBitsOverride && "found named 0-width bitfield");
|
||||
}
|
||||
llvm::DIType fieldType
|
||||
= createFieldType(VName, Field->getType(), SizeInBitsOverride,
|
||||
C.getLocation(), Field->getAccess(),
|
||||
layout.getFieldOffset(fieldno), VUnit, RecordTy);
|
||||
elements.push_back(fieldType);
|
||||
} else {
|
||||
// TODO: Need to handle 'this' in some way by probably renaming the
|
||||
// this of the lambda class and having a field member of 'this' or
|
||||
// by using AT_object_pointer for the function and having that be
|
||||
// used as 'this' for semantic references.
|
||||
assert(C.capturesThis() && "Field that isn't captured and isn't this?");
|
||||
FieldDecl *f = *Field;
|
||||
llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
|
||||
QualType type = f->getType();
|
||||
llvm::DIType fieldType
|
||||
= createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
|
||||
layout.getFieldOffset(fieldno), VUnit, RecordTy);
|
||||
|
||||
elements.push_back(fieldType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// CollectRecordStaticField - Helper for CollectRecordFields.
|
||||
void CGDebugInfo::
|
||||
CollectRecordStaticField(const VarDecl *Var,
|
||||
SmallVectorImpl<llvm::Value *> &elements,
|
||||
llvm::DIType RecordTy) {
|
||||
// Create the descriptor for the static variable, with or without
|
||||
// constant initializers.
|
||||
llvm::DIFile VUnit = getOrCreateFile(Var->getLocation());
|
||||
llvm::DIType VTy = getOrCreateType(Var->getType(), VUnit);
|
||||
|
||||
// Do not describe enums as static members.
|
||||
if (VTy.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
|
||||
return;
|
||||
|
||||
unsigned LineNumber = getLineNumber(Var->getLocation());
|
||||
StringRef VName = Var->getName();
|
||||
llvm::ConstantInt *CI = NULL;
|
||||
if (Var->getInit()) {
|
||||
const APValue *Value = Var->evaluateValue();
|
||||
if (Value && Value->isInt())
|
||||
CI = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
|
||||
}
|
||||
|
||||
unsigned Flags = 0;
|
||||
AccessSpecifier Access = Var->getAccess();
|
||||
if (Access == clang::AS_private)
|
||||
Flags |= llvm::DIDescriptor::FlagPrivate;
|
||||
else if (Access == clang::AS_protected)
|
||||
Flags |= llvm::DIDescriptor::FlagProtected;
|
||||
|
||||
llvm::DIType GV = DBuilder.createStaticMemberType(RecordTy, VName, VUnit,
|
||||
LineNumber, VTy, Flags, CI);
|
||||
elements.push_back(GV);
|
||||
StaticDataMemberCache[Var->getCanonicalDecl()] = llvm::WeakVH(GV);
|
||||
}
|
||||
|
||||
/// CollectRecordNormalField - Helper for CollectRecordFields.
|
||||
void CGDebugInfo::
|
||||
CollectRecordNormalField(const FieldDecl *field, uint64_t OffsetInBits,
|
||||
llvm::DIFile tunit,
|
||||
SmallVectorImpl<llvm::Value *> &elements,
|
||||
llvm::DIType RecordTy) {
|
||||
StringRef name = field->getName();
|
||||
QualType type = field->getType();
|
||||
|
||||
// Ignore unnamed fields unless they're anonymous structs/unions.
|
||||
if (name.empty() && !type->isRecordType())
|
||||
return;
|
||||
|
||||
uint64_t SizeInBitsOverride = 0;
|
||||
if (field->isBitField()) {
|
||||
SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
|
||||
assert(SizeInBitsOverride && "found named 0-width bitfield");
|
||||
}
|
||||
|
||||
llvm::DIType fieldType
|
||||
= createFieldType(name, type, SizeInBitsOverride,
|
||||
field->getLocation(), field->getAccess(),
|
||||
OffsetInBits, tunit, RecordTy);
|
||||
|
||||
elements.push_back(fieldType);
|
||||
}
|
||||
|
||||
/// CollectRecordFields - A helper function to collect debug info for
|
||||
/// record fields. This is used while creating debug info entry for a Record.
|
||||
void CGDebugInfo::
|
||||
CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
|
||||
SmallVectorImpl<llvm::Value *> &elements,
|
||||
llvm::DIType RecordTy) {
|
||||
const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
|
||||
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record);
|
||||
|
||||
// For C++11 Lambdas a Field will be the same as a Capture, but the Capture
|
||||
// has the name and the location of the variable so we should iterate over
|
||||
// both concurrently.
|
||||
if (CXXDecl && CXXDecl->isLambda()) {
|
||||
RecordDecl::field_iterator Field = CXXDecl->field_begin();
|
||||
unsigned fieldno = 0;
|
||||
for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
|
||||
E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
|
||||
const LambdaExpr::Capture C = *I;
|
||||
if (C.capturesVariable()) {
|
||||
VarDecl *V = C.getCapturedVar();
|
||||
llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
|
||||
StringRef VName = V->getName();
|
||||
uint64_t SizeInBitsOverride = 0;
|
||||
if (Field->isBitField()) {
|
||||
SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
|
||||
assert(SizeInBitsOverride && "found named 0-width bitfield");
|
||||
}
|
||||
llvm::DIType fieldType
|
||||
= createFieldType(VName, Field->getType(), SizeInBitsOverride, C.getLocation(),
|
||||
Field->getAccess(), layout.getFieldOffset(fieldno),
|
||||
VUnit, RecordTy);
|
||||
elements.push_back(fieldType);
|
||||
} else {
|
||||
// TODO: Need to handle 'this' in some way by probably renaming the
|
||||
// this of the lambda class and having a field member of 'this' or
|
||||
// by using AT_object_pointer for the function and having that be
|
||||
// used as 'this' for semantic references.
|
||||
assert(C.capturesThis() && "Field that isn't captured and isn't this?");
|
||||
FieldDecl *f = *Field;
|
||||
llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
|
||||
QualType type = f->getType();
|
||||
llvm::DIType fieldType
|
||||
= createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
|
||||
layout.getFieldOffset(fieldno), VUnit, RecordTy);
|
||||
if (CXXDecl && CXXDecl->isLambda())
|
||||
CollectRecordLambdaFields(CXXDecl, elements, RecordTy);
|
||||
else {
|
||||
const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
|
||||
|
||||
elements.push_back(fieldType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Field number for non-static fields.
|
||||
unsigned fieldNo = 0;
|
||||
|
||||
// Bookkeeping for an ms struct, which ignores certain fields.
|
||||
bool IsMsStruct = record->isMsStruct(CGM.getContext());
|
||||
const FieldDecl *LastFD = 0;
|
||||
for (RecordDecl::field_iterator I = record->field_begin(),
|
||||
E = record->field_end();
|
||||
I != E; ++I, ++fieldNo) {
|
||||
FieldDecl *field = *I;
|
||||
|
||||
if (IsMsStruct) {
|
||||
// Zero-length bitfields following non-bitfield members are ignored
|
||||
if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) {
|
||||
--fieldNo;
|
||||
continue;
|
||||
// Static and non-static members should appear in the same order as
|
||||
// the corresponding declarations in the source program.
|
||||
for (RecordDecl::decl_iterator I = record->decls_begin(),
|
||||
E = record->decls_end(); I != E; ++I)
|
||||
if (const VarDecl *V = dyn_cast<VarDecl>(*I))
|
||||
CollectRecordStaticField(V, elements, RecordTy);
|
||||
else if (FieldDecl *field = dyn_cast<FieldDecl>(*I)) {
|
||||
if (IsMsStruct) {
|
||||
// Zero-length bitfields following non-bitfield members are
|
||||
// completely ignored; we don't even count them.
|
||||
if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD))
|
||||
continue;
|
||||
LastFD = field;
|
||||
}
|
||||
LastFD = field;
|
||||
CollectRecordNormalField(field, layout.getFieldOffset(fieldNo),
|
||||
tunit, elements, RecordTy);
|
||||
|
||||
// Bump field number for next field.
|
||||
++fieldNo;
|
||||
}
|
||||
|
||||
StringRef name = field->getName();
|
||||
QualType type = field->getType();
|
||||
|
||||
// Ignore unnamed fields unless they're anonymous structs/unions.
|
||||
if (name.empty() && !type->isRecordType()) {
|
||||
LastFD = field;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t SizeInBitsOverride = 0;
|
||||
if (field->isBitField()) {
|
||||
SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
|
||||
assert(SizeInBitsOverride && "found named 0-width bitfield");
|
||||
}
|
||||
|
||||
llvm::DIType fieldType
|
||||
= createFieldType(name, type, SizeInBitsOverride,
|
||||
field->getLocation(), field->getAccess(),
|
||||
layout.getFieldOffset(fieldNo), tunit, RecordTy);
|
||||
|
||||
elements.push_back(fieldType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1296,8 +1330,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
|
|||
CollectVTableInfo(CXXDecl, DefUnit, EltTys);
|
||||
}
|
||||
|
||||
// Collect static variables with initializers and other fields.
|
||||
CollectRecordStaticVars(RD, FwdDecl);
|
||||
// Collect data fields (including static variables and any initializers).
|
||||
CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
|
||||
llvm::DIArray TParamsArray;
|
||||
if (CXXDecl) {
|
||||
|
@ -2679,6 +2712,21 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
|
|||
declare->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
|
||||
}
|
||||
|
||||
/// getStaticDataMemberDeclaration - If D is an out-of-class definition of
|
||||
/// a static data member of a class, find its corresponding in-class
|
||||
/// declaration.
|
||||
llvm::DIDerivedType CGDebugInfo::getStaticDataMemberDeclaration(const Decl *D) {
|
||||
if (cast<VarDecl>(D)->isStaticDataMember()) {
|
||||
llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
|
||||
MI = StaticDataMemberCache.find(D->getCanonicalDecl());
|
||||
if (MI != StaticDataMemberCache.end())
|
||||
// Verify the info still exists.
|
||||
if (llvm::Value *V = MI->second)
|
||||
return llvm::DIDerivedType(cast<llvm::MDNode>(V));
|
||||
}
|
||||
return llvm::DIDerivedType();
|
||||
}
|
||||
|
||||
/// EmitGlobalVariable - Emit information about a global variable.
|
||||
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
|
||||
const VarDecl *D) {
|
||||
|
@ -2710,7 +2758,8 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
|
|||
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
|
||||
DBuilder.createStaticVariable(DContext, DeclName, LinkageName,
|
||||
Unit, LineNo, getOrCreateType(T, Unit),
|
||||
Var->hasInternalLinkage(), Var);
|
||||
Var->hasInternalLinkage(), Var,
|
||||
getStaticDataMemberDeclaration(D));
|
||||
}
|
||||
|
||||
/// EmitGlobalVariable - Emit information about an objective-c interface.
|
||||
|
@ -2757,7 +2806,8 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
|
|||
return;
|
||||
DBuilder.createStaticVariable(Unit, Name, Name, Unit,
|
||||
getLineNumber(VD->getLocation()),
|
||||
Ty, true, Init);
|
||||
Ty, true, Init,
|
||||
getStaticDataMemberDeclaration(VD));
|
||||
}
|
||||
|
||||
/// getOrCreateNamesSpace - Return namespace descriptor for the given
|
||||
|
|
|
@ -85,6 +85,7 @@ class CGDebugInfo {
|
|||
llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
|
||||
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
|
||||
llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
|
||||
llvm::DenseMap<const Decl *, llvm::WeakVH> StaticDataMemberCache;
|
||||
|
||||
/// Helper functions for getOrCreateType.
|
||||
llvm::DIType CreateType(const BuiltinType *Ty);
|
||||
|
@ -158,7 +159,18 @@ class CGDebugInfo {
|
|||
AccessSpecifier AS, uint64_t offsetInBits,
|
||||
llvm::DIFile tunit,
|
||||
llvm::DIDescriptor scope);
|
||||
void CollectRecordStaticVars(const RecordDecl *, llvm::DIType);
|
||||
|
||||
// Helpers for collecting fields of a record.
|
||||
void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
|
||||
SmallVectorImpl<llvm::Value *> &E,
|
||||
llvm::DIType RecordTy);
|
||||
void CollectRecordStaticField(const VarDecl *Var,
|
||||
SmallVectorImpl<llvm::Value *> &E,
|
||||
llvm::DIType RecordTy);
|
||||
void CollectRecordNormalField(const FieldDecl *Field, uint64_t OffsetInBits,
|
||||
llvm::DIFile F,
|
||||
SmallVectorImpl<llvm::Value *> &E,
|
||||
llvm::DIType RecordTy);
|
||||
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
|
||||
SmallVectorImpl<llvm::Value *> &E,
|
||||
llvm::DIType RecordTy);
|
||||
|
@ -298,6 +310,11 @@ private:
|
|||
/// declaration for the given method definition.
|
||||
llvm::DISubprogram getFunctionDeclaration(const Decl *D);
|
||||
|
||||
/// getStaticDataMemberDeclaration - Return debug info descriptor to
|
||||
/// describe in-class static data member declaration for the given
|
||||
/// out-of-class definition.
|
||||
llvm::DIDerivedType getStaticDataMemberDeclaration(const Decl *D);
|
||||
|
||||
/// getFunctionName - Get function name for the given FunctionDecl. If the
|
||||
/// name is constructred on demand (e.g. C++ destructor) then the name
|
||||
/// is stored on the side.
|
||||
|
|
|
@ -6,5 +6,5 @@ int main() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !5, metadata !"localstatic", metadata !"localstatic", metadata !"", metadata !6, i32 5, metadata !9, i32 1, i32 1, i32* @main.localstatic} ; [ DW_TAG_variable ]
|
||||
// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"global", metadata !"global", metadata !"", metadata !6, i32 3, metadata !9, i32 0, i32 1, i32* @global} ; [ DW_TAG_variable ]
|
||||
// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !5, metadata !"localstatic", metadata !"localstatic", metadata !"", metadata !6, i32 5, metadata !9, i32 1, i32 1, i32* @main.localstatic, null} ; [ DW_TAG_variable ]
|
||||
// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"global", metadata !"global", metadata !"", metadata !6, i32 3, metadata !9, i32 0, i32 1, i32* @global, null} ; [ DW_TAG_variable ]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// RUN: %clang_cc1 -g -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
// CHECK: xyzzy} ; [ DW_TAG_variable ]
|
||||
// CHECK: xyzzy, null} ; [ DW_TAG_variable ]
|
||||
void f(void)
|
||||
{
|
||||
static int xyzzy;
|
||||
|
|
|
@ -61,11 +61,11 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
|
|||
// CHECK: [[DES_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ]
|
||||
|
||||
// CVAR:
|
||||
// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"cvar", metadata !"cvar", metadata !"", metadata [[FILE]], i32 [[CVAR_LINE:.*]], metadata ![[CVAR_T:.*]], i32 0, i32 1, %class.anon.0* @cvar} ; [ DW_TAG_variable ]
|
||||
// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"cvar", metadata !"cvar", metadata !"", metadata [[FILE]], i32 [[CVAR_LINE:.*]], metadata ![[CVAR_T:.*]], i32 0, i32 1, %class.anon.0* @cvar, null} ; [ DW_TAG_variable ]
|
||||
// CHECK: [[CVAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[CVAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[CVAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
|
||||
// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
|
||||
|
||||
// VAR:
|
||||
// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"var", metadata !"var", metadata !"", metadata [[FILE]], i32 [[VAR_LINE:.*]], metadata ![[VAR_T:.*]], i32 1, i32 1, %class.anon* @var} ; [ DW_TAG_variable ]
|
||||
// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"var", metadata !"var", metadata !"", metadata [[FILE]], i32 [[VAR_LINE:.*]], metadata ![[VAR_T:.*]], i32 1, i32 1, %class.anon* @var, null} ; [ DW_TAG_variable ]
|
||||
// CHECK: [[VAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[VAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[VAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
|
||||
// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
|
||||
|
|
Loading…
Reference in New Issue