From: Adrian Prantl Date: Wed, 29 Apr 2015 16:52:31 +0000 (+0000) Subject: Debug Info: Represent local anonymous unions as anonymous unions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3d58a85fdd0894bc04b1167c7fef037fda1ac4fc;p=clang Debug Info: Represent local anonymous unions as anonymous unions and as artificial local variables in the debug info. This is a follow-up to r236059. We can't get rid of the local variables entirely because the gdb buildbot depends on them, but we can mark them as artificial while still emitting the correct debug info. As I learned from review comments other compilers also follow this model. A paired commit in LLVM temporarily relaxes the debug info verifier to not check the integrity of DW_OP_bit_pieces of artificial variables. rdar://problem/20730771 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@236125 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index cbb4f85c84..3a9b4c7ace 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -2839,6 +2839,13 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::Tag Tag, // all union fields. const RecordDecl *RD = cast(RT->getDecl()); if (RD->isUnion() && RD->isAnonymousStructOrUnion()) { + // GDB has trouble finding local variables in anonymous unions, so we emit + // artifical local variables for each of the members. + // + // FIXME: Remove this code as soon as GDB supports this. + // The debug info verifier in LLVM operates based on the assumption that a + // variable has the same size as its storage and we had to disable the check + // for artificial variables. for (const auto *Field : RD->fields()) { llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit); StringRef FieldName = Field->getName(); @@ -2850,14 +2857,14 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::Tag Tag, // Use VarDecl's Tag, Scope and Line number. auto *D = DBuilder.createLocalVariable( Tag, Scope, FieldName, Unit, Line, FieldTy, - CGM.getLangOpts().Optimize, Flags, ArgNo); + CGM.getLangOpts().Optimize, Flags | llvm::DINode::FlagArtificial, + ArgNo); // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr), llvm::DebugLoc::get(Line, Column, Scope), Builder.GetInsertBlock()); } - return; } } diff --git a/test/CodeGenCXX/debug-info-anon-union-vars.cpp b/test/CodeGenCXX/debug-info-anon-union-vars.cpp index cfc7bc8fbf..ad3b6d4c62 100644 --- a/test/CodeGenCXX/debug-info-anon-union-vars.cpp +++ b/test/CodeGenCXX/debug-info-anon-union-vars.cpp @@ -21,8 +21,26 @@ int test_it() { return (c == 1); } +void foo() { + union { + int i; + char c; + }; + i = 8; +} + // CHECK: [[FILE:.*]] = !DIFile(filename: "{{.*}}debug-info-anon-union-vars.cpp", // CHECK: !DIGlobalVariable(name: "c",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true // CHECK: !DIGlobalVariable(name: "d",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true // CHECK: !DIGlobalVariable(name: "a",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true // CHECK: !DIGlobalVariable(name: "b",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true +// CHECK: !DILocalVariable(tag: DW_TAG_auto_variable, name: "i", {{.*}}, flags: DIFlagArtificial +// CHECK: !DILocalVariable(tag: DW_TAG_auto_variable, name: "c", {{.*}}, flags: DIFlagArtificial +// CHECK: !DILocalVariable( +// CHECK-NOT: name: +// CHECK: type: ![[UNION:[0-9]+]] +// CHECK: ![[UNION]] = !DICompositeType(tag: DW_TAG_union_type, +// CHECK-NOT: name: +// CHECK: elements +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "i", scope: ![[UNION]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "c", scope: ![[UNION]],