diff options
author | Eric Christopher <echristo@gmail.com> | 2014-04-10 05:20:00 +0000 |
---|---|---|
committer | Eric Christopher <echristo@gmail.com> | 2014-04-10 05:20:00 +0000 |
commit | cab9fae40308173868967c870c0247239e07a9a3 (patch) | |
tree | 317e32fe66cc8b42999e2180e4393909793f8b61 | |
parent | 951716bf37dc43764322925350ba801c6d6dc04f (diff) | |
download | bcm5719-llvm-cab9fae40308173868967c870c0247239e07a9a3.tar.gz bcm5719-llvm-cab9fae40308173868967c870c0247239e07a9a3.zip |
Add global static variables for anonymous union fields. This makes
sure that a debugger can find them when stepping through code,
for example from the included testcase:
12 int test_it() {
13 c = 1;
14 d = 2;
-> 15 a = 4;
16 return (c == 1);
17 }
18
(lldb) p a
(int) $0 = 2
(lldb) p c
(int) $1 = 2
(lldb) p d
(int) $2 = 2
and a, c, d are all part of the file static anonymous union:
static union {
int c;
int d;
union {
int a;
};
struct {
int b;
};
};
Fixes PR19221.
llvm-svn: 205952
-rw-r--r-- | clang/lib/CodeGen/CGDebugInfo.cpp | 59 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGDebugInfo.h | 7 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp | 28 |
3 files changed, 88 insertions, 6 deletions
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 33fbb8d5437..45c78064aac 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3180,6 +3180,37 @@ CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) { return T; } +/// Recursively collect all of the member fields of a global anonymous decl and +/// create static variables for them. The first time this is called it needs +/// to be on a union and then from there we can have additional unnamed fields. +llvm::DIGlobalVariable +CGDebugInfo::CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile Unit, + unsigned LineNo, StringRef LinkageName, + llvm::GlobalVariable *Var, + llvm::DIDescriptor DContext) { + llvm::DIGlobalVariable GV; + + for (const auto *Field : RD->fields()) { + llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); + StringRef FieldName = Field->getName(); + + // Ignore unnamed fields, but recurse into anonymous records. + if (FieldName.empty()) { + const RecordType *RT = dyn_cast<RecordType>(Field->getType()); + if (RT) + GV = CollectAnonRecordDecls(RT->getDecl(), Unit, LineNo, LinkageName, + Var, DContext); + continue; + } + // Use VarDecl's Tag, Scope and Line number. + GV = DBuilder.createStaticVariable(DContext, FieldName, LinkageName, Unit, + LineNo, FieldTy, + Var->hasInternalLinkage(), Var, + llvm::DIDerivedType()); + } + return GV; +} + /// EmitGlobalVariable - Emit information about a global variable. void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, const VarDecl *D) { @@ -3200,19 +3231,35 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } + StringRef DeclName = D->getName(); StringRef LinkageName; - if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext()) - && !isa<ObjCMethodDecl>(D->getDeclContext())) + if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext()) && + !isa<ObjCMethodDecl>(D->getDeclContext())) LinkageName = Var->getName(); if (LinkageName == DeclName) LinkageName = StringRef(); + llvm::DIDescriptor DContext = getContextDescriptor(dyn_cast<Decl>(D->getDeclContext())); - llvm::DIGlobalVariable GV = DBuilder.createStaticVariable( - DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), - Var->hasInternalLinkage(), Var, - getOrCreateStaticDataMemberDeclarationOrNull(D)); + + // Attempt to store one global variable for the declaration - even if we + // emit a lot of fields. + llvm::DIGlobalVariable GV; + + // If this is an anonymous union then we'll want to emit a global + // variable for each member of the anonymous union so that it's possible + // to find the name of any field in the union. + if (T->isUnionType() && DeclName.empty()) { + const RecordDecl *RD = cast<RecordType>(T)->getDecl(); + assert(RD->isAnonymousStructOrUnion() && "unnamed non-anonymous struct or union?"); + GV = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext); + } else { + GV = DBuilder.createStaticVariable( + DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), + Var->hasInternalLinkage(), Var, + getOrCreateStaticDataMemberDeclarationOrNull(D)); + } DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(GV))); } diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index ea2998b1cb7..7f2ddd06367 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -358,6 +358,13 @@ private: llvm::DIDerivedType getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D); + /// Return a global variable that represents one of the collection of + /// global variables created for an anonmyous union. + llvm::DIGlobalVariable + CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile Unit, unsigned LineNo, + StringRef LinkageName, llvm::GlobalVariable *Var, + llvm::DIDescriptor DContext); + /// getFunctionName - Get function name for the given FunctionDecl. If the /// name is constructed on demand (e.g. C++ destructor) then the name /// is stored on the side. diff --git a/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp b/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp new file mode 100644 index 00000000000..396b7e94a8e --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -emit-llvm -gdwarf-4 -triple x86_64-linux-gnu %s -o - | FileCheck %s + +// Make sure that we emit a global variable for each of the members of the +// anonymous union. + +static union { + int c; + int d; + union { + int a; + }; + struct { + int b; + }; +}; + +int test_it() { + c = 1; + d = 2; + a = 4; + return (c == 1); +} + +// CHECK: [[FILE:.*]] = {{.*}}[ DW_TAG_file_type ] [{{.*}}debug-info-anon-union-vars.cpp] +// CHECK: [[FILE]]{{.*}}[ DW_TAG_variable ] [c] [line 6] [local] [def] +// CHECK: [[FILE]]{{.*}}[ DW_TAG_variable ] [d] [line 6] [local] [def] +// CHECK: [[FILE]]{{.*}}[ DW_TAG_variable ] [a] [line 6] [local] [def] +// CHECK: [[FILE]]{{.*}}[ DW_TAG_variable ] [b] [line 6] [local] [def] |