From: Eric Christopher Date: Thu, 10 Apr 2014 05:20:00 +0000 (+0000) Subject: Add global static variables for anonymous union fields. This makes X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=993b99c22e182b24e042cc8281d899987e11d337;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205952 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 33fbb8d543..45c78064aa 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/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(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(D->getDeclContext()) - && !isa(D->getDeclContext())) + if (D->getDeclContext() && !isa(D->getDeclContext()) && + !isa(D->getDeclContext())) LinkageName = Var->getName(); if (LinkageName == DeclName) LinkageName = StringRef(); + llvm::DIDescriptor DContext = getContextDescriptor(dyn_cast(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(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/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index ea2998b1cb..7f2ddd0636 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/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/test/CodeGenCXX/debug-info-anon-union-vars.cpp b/test/CodeGenCXX/debug-info-anon-union-vars.cpp new file mode 100644 index 0000000000..396b7e94a8 --- /dev/null +++ b/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]