krisb created this revision. krisb added reviewers: dblaikie, probinson. Herald added a subscriber: hiraditya. krisb requested review of this revision. Herald added projects: clang, LLVM. Herald added subscribers: llvm-commits, cfe-commits.
This fixes https://bugs.llvm.org/show_bug.cgi?id=44695 (and likely https://bugs.llvm.org/show_bug.cgi?id=30637). On clang side we need to place static locals defined within a bracketed block into a correct scope. Since getContextDescriptor() does no access lexical blocks, just pick the innermost lexical scope early. On llvm side the patch proposes to delay emission of static locals until their parent scopes are created (just like normal local variables). In case of inlined function, static locals are created only for abstract entities (as per suggestions from https://bugs.llvm.org/show_bug.cgi?id=30637). Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D109703 Files: clang/lib/CodeGen/CGDebugInfo.cpp clang/test/CodeGen/debug-info-static.c llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp llvm/test/DebugInfo/Generic/static-locals.ll llvm/test/DebugInfo/X86/gnu-public-names.ll
Index: llvm/test/DebugInfo/X86/gnu-public-names.ll =================================================================== --- llvm/test/DebugInfo/X86/gnu-public-names.ll +++ llvm/test/DebugInfo/X86/gnu-public-names.ll @@ -137,19 +137,6 @@ ; CHECK-NOT: {{DW_TAG|NULL}} ; CHECK: DW_AT_name {{.*}} "global_namespace_function" -; CHECK: DW_TAG_subprogram -; CHECK-NOT: {{DW_TAG|NULL}} -; CHECK: DW_AT_name {{.*}} "f3" -; CHECK-NOT: {{DW_TAG|NULL}} -; CHECK: [[F3_Z:.*]]: DW_TAG_variable -; CHECK-NOT: DW_TAG -; CHECK: DW_AT_name {{.*}} "z" -; CHECK-NOT: {{DW_TAG|NULL}} -; CHECK: DW_AT_location -; CHECK-NOT: {{DW_TAG|NULL}} -; CHECK: NULL -; CHECK-NOT: {{DW_TAG|NULL}} - ; CHECK: [[ANON:.*]]: DW_TAG_namespace ; CHECK-NOT: DW_AT_name ; CHECK: [[ANON_I:.*]]: DW_TAG_variable @@ -237,6 +224,19 @@ ; CHECK: DW_AT_linkage_name ; CHECK-NOT: {{DW_TAG|NULL}} ; CHECK: DW_AT_name {{.*}} "global_function" +; CHECK-NOT: {{DW_TAG|NULL}} + +; CHECK: DW_TAG_subprogram +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_name {{.*}} "f3" +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: [[F3_Z:.*]]: DW_TAG_variable +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name {{.*}} "z" +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_location +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: NULL ; CHECK-LABEL: .debug_gnu_pubnames contents: ; CHECK-NEXT: length = {{.*}}, version = 0x0002, unit_offset = 0x00000000, unit_size = {{.*}} @@ -250,8 +250,8 @@ ; comes out naturally from LLVM's implementation, so I'm OK with it for now. If ; it's demonstrated that this is a major size concern or degrades debug info ; consumer behavior, feel free to change it. -; CHECK-NEXT: [[F3_Z]] STATIC VARIABLE "f3::z" ; CHECK-NEXT: [[ANON]] EXTERNAL TYPE "(anonymous namespace)" +; CHECK-NEXT: [[F3_Z]] STATIC VARIABLE "f3::z" ; CHECK-NEXT: [[OUTER_ANON]] EXTERNAL TYPE "outer::(anonymous namespace)" ; CHECK-NEXT: [[ANON_INNER_B]] STATIC VARIABLE "(anonymous namespace)::inner::b" ; CHECK-NEXT: [[OUTER]] EXTERNAL TYPE "outer" Index: llvm/test/DebugInfo/Generic/static-locals.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/Generic/static-locals.ll @@ -0,0 +1,204 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s \ +; RUN: | llvm-dwarfdump -debug-info - \ +; RUN: | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s + +; Generated from: + +; static int global = 42; +; +; inline __attribute__((always_inline)) +; int inlined() { +; static int inlined_a = 1; +; if (global > 100) { +; static int inlined_b = 2; +; return inlined_b; +; } +; { +; static int inlined_c = 3; +; inlined_a = inlined_c; +; } +; return inlined_a; +; } +; +; int foo() { +; static int a = 1; +; if (global < 100) { +; static int b = 2; +; return b; +; } +; { +; static int c = 3; +; a = c; +; } +; return a; +; } +; +; int far() { +; return inlined(); +; } + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("global") +; CHECK: DW_TAG_base_type + +; foo(). +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("a") +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("b") +; CHECK: NULL +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("c") +; CHECK: NULL +; CHECK: NULL + +; inlined(). +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("inlined") +; CHECK: DW_AT_inline (DW_INL_inlined) +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("inlined_a") +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("inlined_b") +; CHECK: NULL +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("inlined_c") +; CHECK: NULL +; CHECK: NULL + +; far(). +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("far") +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin (0x000000c3 "_Z7inlinedv") +; CHECK: NULL +; CHECK: NULL + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@_ZZ3foovE1a = internal global i32 1, align 4, !dbg !0 +@_ZL6global = internal global i32 42, align 4, !dbg !17 +@_ZZ3foovE1b = internal global i32 2, align 4, !dbg !10 +@_ZZ3foovE1c = internal global i32 3, align 4, !dbg !14 +@_ZZ7inlinedvE9inlined_a = linkonce_odr dso_local global i32 1, align 4, !dbg !19 +@_ZZ7inlinedvE9inlined_b = linkonce_odr dso_local global i32 2, align 4, !dbg !22 +@_ZZ7inlinedvE9inlined_c = linkonce_odr dso_local global i32 3, align 4, !dbg !26 + +define dso_local i32 @_Z3foov() !dbg !2 { +entry: + %retval = alloca i32, align 4 + %0 = load i32, i32* @_ZL6global, align 4, !dbg !35 + %cmp = icmp slt i32 %0, 100, !dbg !36 + br i1 %cmp, label %if.then, label %if.end, !dbg !37 + +if.then: ; preds = %entry + %1 = load i32, i32* @_ZZ3foovE1b, align 4, !dbg !38 + store i32 %1, i32* %retval, align 4, !dbg !39 + br label %return, !dbg !39 + +if.end: ; preds = %entry + %2 = load i32, i32* @_ZZ3foovE1c, align 4, !dbg !40 + store i32 %2, i32* @_ZZ3foovE1a, align 4, !dbg !41 + %3 = load i32, i32* @_ZZ3foovE1a, align 4, !dbg !42 + store i32 %3, i32* %retval, align 4, !dbg !43 + br label %return, !dbg !43 + +return: ; preds = %if.end, %if.then + %4 = load i32, i32* %retval, align 4, !dbg !44 + ret i32 %4, !dbg !44 +} + +define dso_local i32 @_Z3farv() !dbg !45 { +entry: + %retval.i = alloca i32, align 4 + %0 = load i32, i32* @_ZL6global, align 4, !dbg !46 + %cmp.i = icmp sgt i32 %0, 100, !dbg !48 + br i1 %cmp.i, label %if.then.i, label %if.end.i, !dbg !49 + +if.then.i: ; preds = %entry + %1 = load i32, i32* @_ZZ7inlinedvE9inlined_b, align 4, !dbg !50 + store i32 %1, i32* %retval.i, align 4, !dbg !51 + br label %_Z7inlinedv.exit, !dbg !51 + +if.end.i: ; preds = %entry + %2 = load i32, i32* @_ZZ7inlinedvE9inlined_c, align 4, !dbg !52 + store i32 %2, i32* @_ZZ7inlinedvE9inlined_a, align 4, !dbg !53 + %3 = load i32, i32* @_ZZ7inlinedvE9inlined_a, align 4, !dbg !54 + store i32 %3, i32* %retval.i, align 4, !dbg !55 + br label %_Z7inlinedv.exit, !dbg !55 + +_Z7inlinedv.exit: ; preds = %if.then.i, %if.end.i + %4 = load i32, i32* %retval.i, align 4, !dbg !56 + ret i32 %4, !dbg !57 +} + +!llvm.dbg.cu = !{!7} +!llvm.module.flags = !{!29, !30, !31, !32, !33} +!llvm.ident = !{!34} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 18, type: !6, isLocal: true, isDefinition: true) +!2 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 17, type: !4, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !8) +!3 = !DIFile(filename: "test.cpp", directory: "..") +!4 = !DISubroutineType(types: !5) +!5 = !{!6} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !8, globals: !9, splitDebugInlining: false, nameTableKind: None) +!8 = !{} +!9 = !{!0, !10, !14, !17, !19, !22, !26} +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "b", scope: !12, file: !3, line: 20, type: !6, isLocal: true, isDefinition: true) +!12 = distinct !DILexicalBlock(scope: !13, file: !3, line: 19, column: 21) +!13 = distinct !DILexicalBlock(scope: !2, file: !3, line: 19, column: 7) +!14 = !DIGlobalVariableExpression(var: !15, expr: !DIExpression()) +!15 = distinct !DIGlobalVariable(name: "c", scope: !16, file: !3, line: 24, type: !6, isLocal: true, isDefinition: true) +!16 = distinct !DILexicalBlock(scope: !2, file: !3, line: 23, column: 3) +!17 = !DIGlobalVariableExpression(var: !18, expr: !DIExpression()) +!18 = distinct !DIGlobalVariable(name: "global", linkageName: "_ZL6global", scope: !7, file: !3, line: 1, type: !6, isLocal: true, isDefinition: true) +!19 = !DIGlobalVariableExpression(var: !20, expr: !DIExpression()) +!20 = distinct !DIGlobalVariable(name: "inlined_a", scope: !21, file: !3, line: 5, type: !6, isLocal: false, isDefinition: true) +!21 = distinct !DISubprogram(name: "inlined", linkageName: "_Z7inlinedv", scope: !3, file: !3, line: 4, type: !4, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !8) +!22 = !DIGlobalVariableExpression(var: !23, expr: !DIExpression()) +!23 = distinct !DIGlobalVariable(name: "inlined_b", scope: !24, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true) +!24 = distinct !DILexicalBlock(scope: !25, file: !3, line: 6, column: 21) +!25 = distinct !DILexicalBlock(scope: !21, file: !3, line: 6, column: 7) +!26 = !DIGlobalVariableExpression(var: !27, expr: !DIExpression()) +!27 = distinct !DIGlobalVariable(name: "inlined_c", scope: !28, file: !3, line: 11, type: !6, isLocal: false, isDefinition: true) +!28 = distinct !DILexicalBlock(scope: !21, file: !3, line: 10, column: 3) +!29 = !{i32 7, !"Dwarf Version", i32 4} +!30 = !{i32 2, !"Debug Info Version", i32 3} +!31 = !{i32 1, !"wchar_size", i32 4} +!32 = !{i32 7, !"uwtable", i32 1} +!33 = !{i32 7, !"frame-pointer", i32 2} +!34 = !{!"clang version 14.0.0"} +!35 = !DILocation(line: 19, column: 7, scope: !13) +!36 = !DILocation(line: 19, column: 14, scope: !13) +!37 = !DILocation(line: 19, column: 7, scope: !2) +!38 = !DILocation(line: 21, column: 12, scope: !12) +!39 = !DILocation(line: 21, column: 5, scope: !12) +!40 = !DILocation(line: 25, column: 9, scope: !16) +!41 = !DILocation(line: 25, column: 7, scope: !16) +!42 = !DILocation(line: 27, column: 10, scope: !2) +!43 = !DILocation(line: 27, column: 3, scope: !2) +!44 = !DILocation(line: 28, column: 1, scope: !2) +!45 = distinct !DISubprogram(name: "far", linkageName: "_Z3farv", scope: !3, file: !3, line: 30, type: !4, scopeLine: 30, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !8) +!46 = !DILocation(line: 6, column: 7, scope: !25, inlinedAt: !47) +!47 = distinct !DILocation(line: 31, column: 10, scope: !45) +!48 = !DILocation(line: 6, column: 14, scope: !25, inlinedAt: !47) +!49 = !DILocation(line: 6, column: 7, scope: !21, inlinedAt: !47) +!50 = !DILocation(line: 8, column: 12, scope: !24, inlinedAt: !47) +!51 = !DILocation(line: 8, column: 5, scope: !24, inlinedAt: !47) +!52 = !DILocation(line: 12, column: 17, scope: !28, inlinedAt: !47) +!53 = !DILocation(line: 12, column: 15, scope: !28, inlinedAt: !47) +!54 = !DILocation(line: 14, column: 10, scope: !21, inlinedAt: !47) +!55 = !DILocation(line: 14, column: 3, scope: !21, inlinedAt: !47) +!56 = !DILocation(line: 15, column: 1, scope: !21, inlinedAt: !47) +!57 = !DILocation(line: 31, column: 3, scope: !45) Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1120,8 +1120,8 @@ } /// Sort and unique GVEs by comparing their fragment offset. -static SmallVectorImpl<DwarfCompileUnit::GlobalExpr> & -sortGlobalExprs(SmallVectorImpl<DwarfCompileUnit::GlobalExpr> &GVEs) { +static SmallVector<DwarfCompileUnit::GlobalExpr, 1> & +sortGlobalExprs(SmallVector<DwarfCompileUnit::GlobalExpr, 1> &GVEs) { llvm::sort( GVEs, [](DwarfCompileUnit::GlobalExpr A, DwarfCompileUnit::GlobalExpr B) { // Sort order: first null exprs, then exprs without fragment @@ -1225,8 +1225,13 @@ DenseSet<DIGlobalVariable *> Processed; for (auto *GVE : CUNode->getGlobalVariables()) { DIGlobalVariable *GV = GVE->getVariable(); - if (Processed.insert(GV).second) + if (Processed.insert(GV).second) { + if (GV->getScope() && isa<DILocalScope>(GV->getScope())) { + CU.deferStaticLocal(GV, sortGlobalExprs(GVMap[GV])); + continue; + } CU.getOrCreateGlobalVariableDIE(GV, sortGlobalExprs(GVMap[GV])); + } } for (auto *Ty : CUNode->getEnumTypes()) { Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -45,6 +45,14 @@ enum class UnitKind { Skeleton, Full }; class DwarfCompileUnit final : public DwarfUnit { +public: + /// A pair of GlobalVariable and DIExpression. + struct GlobalExpr { + const GlobalVariable *Var; + const DIExpression *Expr; + }; + +private: /// A numeric ID unique among all CUs in the module unsigned UniqueID; bool HasRangeLists = false; @@ -106,12 +114,21 @@ void finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) override; + /// Static local variables defined within the CU. + DenseMap<const DIGlobalVariable *, SmallVector<GlobalExpr, 1>> + StaticLocalVars; + + /// Static local variables contained in a particular scope. + DenseMap<const DILocalScope *, SmallVector<const DIGlobalVariable *, 4>> + StaticLocalsInScope; + public: DwarfCompileUnit(unsigned UID, const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU, UnitKind Kind = UnitKind::Full); bool hasRangeLists() const { return HasRangeLists; } + unsigned getUniqueID() const { return UniqueID; } DwarfCompileUnit *getSkeleton() const { @@ -128,12 +145,6 @@ /// Get line table start symbol for this unit. MCSymbol *getLineTableStartSym() const { return LineTableStartSym; } - /// A pair of GlobalVariable and DIExpression. - struct GlobalExpr { - const GlobalVariable *Var; - const DIExpression *Expr; - }; - struct BaseTypeRef { BaseTypeRef(unsigned BitSize, dwarf::TypeKind Encoding) : BitSize(BitSize), Encoding(Encoding) {} @@ -149,9 +160,31 @@ getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV, ArrayRef<GlobalExpr> GlobalExprs); + /// Get or create static local variable DIE. + DIE * + getOrCreateStaticLocalVariableDIE(const DIGlobalVariable *GV, + ArrayRef<GlobalExpr> GlobalExprs); + + /// deferStaticLocal - Remember a static local to delay DIE construction + /// until its scope DIE is created. + void deferStaticLocal(const DIGlobalVariable *GV, + SmallVector<GlobalExpr, 1> &GlobalExprs) { + const auto *Scope = cast<DILocalScope>(GV->getScope()); + StaticLocalsInScope[Scope].push_back(GV); + StaticLocalVars.insert({GV, GlobalExprs}); + } + + /// getDeferredStaticLocalsInScope - Return a list of static local variables + /// for the given debug scope. + SmallVectorImpl<const DIGlobalVariable *> & + getDeferredStaticLocalsInScope(const DILocalScope *Scope) { + return StaticLocalsInScope[Scope]; + } + DIE *getOrCreateCommonBlock(const DICommonBlock *CB, ArrayRef<GlobalExpr> GlobalExprs); + void addLocationAttribute(DIE *ToDIE, const DIGlobalVariable *GV, ArrayRef<GlobalExpr> GlobalExprs); Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -996,12 +996,59 @@ return Result; } +DIE *DwarfCompileUnit::getOrCreateStaticLocalVariableDIE( + const DIGlobalVariable *GV, ArrayRef<GlobalExpr> GlobalExprs) { + + // Check for pre-existence. + if (DIE *Die = getDIE(GV)) + return Die; + + // Define variable debug information entry. + auto VariableDIE = DIE::get(DIEValueAllocator, GV->getTag()); + insertDIE(GV, VariableDIE); + + // Add name and type. + addString(*VariableDIE, dwarf::DW_AT_name, GV->getDisplayName()); + + const DIType *GTy = GV->getType(); + if (GTy) + addType(*VariableDIE, GTy); + + // Add line number info. + addSourceLine(*VariableDIE, GV); + + if (!GV->isDefinition()) + addFlag(*VariableDIE, dwarf::DW_AT_declaration); + else + addGlobalName(GV->getName(), *VariableDIE, GV->getScope()); + + if (uint32_t AlignInBytes = GV->getAlignInBytes()) + addUInt(*VariableDIE, dwarf::DW_AT_alignment, dwarf::DW_FORM_udata, + AlignInBytes); + + if (MDTuple *TP = GV->getTemplateParams()) + addTemplateParams(*VariableDIE, DINodeArray(TP)); + + // Add location. + addLocationAttribute(VariableDIE, GV, GlobalExprs); + + return VariableDIE; +} + DIE *DwarfCompileUnit::createScopeChildrenDIE(LexicalScope *Scope, SmallVectorImpl<DIE *> &Children, bool *HasNonScopeChildren) { assert(Children.empty()); DIE *ObjectPointer = nullptr; + // Emit static local variables. + auto *IA = Scope->getInlinedAt(); + if (!IA) { + for (auto &GV : getDeferredStaticLocalsInScope(Scope->getScopeNode())) + Children.push_back( + getOrCreateStaticLocalVariableDIE(GV, StaticLocalVars[GV])); + } + // Emit function arguments (order is significant). auto Vars = DU->getScopeVariables().lookup(Scope); for (auto &DV : Vars.Args) Index: clang/test/CodeGen/debug-info-static.c =================================================================== --- clang/test/CodeGen/debug-info-static.c +++ clang/test/CodeGen/debug-info-static.c @@ -1,11 +1,23 @@ // RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s // CHECK: @f.xyzzy = internal global i32 0, align 4, !dbg [[XYZZY:![0-9]+]] +// CHECK: @f.xyzzz = internal global i32 42, align 4, !dbg [[XYZZZ:![0-9]+]] + +// CHECK-DAG: [[XYZZY]] = !DIGlobalVariableExpression(var: [[VAR1:.*]], expr: !DIExpression()) +// CHECK-DAG: [[VAR1]] = distinct !DIGlobalVariable(name: "xyzzy", scope: [[SCOPE1:.*]], file +// CHECK-DAG: [[SCOPE1]] = distinct !DISubprogram + +// Ensure that static local declared within a bracketed block has a DILexicalBlock scope. +// CHECK-DAG: [[XYZZZ]] = !DIGlobalVariableExpression(var: [[VAR2:.*]], expr: !DIExpression()) +// CHECK-DAG: [[VAR2]] = distinct !DIGlobalVariable(name: "xyzzz", scope: [[SCOPE2:.*]], file +// CHECK-DAG: [[SCOPE2]] = distinct !DILexicalBlock -// CHECK: [[XYZZY]] = !DIGlobalVariableExpression(var: [[VAR:.*]], expr: !DIExpression()) -// CHECK: [[VAR]] = distinct !DIGlobalVariable void f(void) { static int xyzzy; xyzzy += 3; + if (xyzzy > 10) { + static int xyzzz = 42; + xyzzy += xyzzz; + } } Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -3624,6 +3624,15 @@ TemplateParameters = nullptr; } + // For static locals just pick the lexical scope we are in (either a + // subprogram or a bracketed (lexical) block). + if (VD->isStaticLocal()) { + assert(!LexicalBlockStack.empty() && + "Static local should have a local scope!"); + VDContext = LexicalBlockStack.back(); + return; + } + // Since we emit declarations (DW_AT_members) for static members, place the // definition of those static members in the namespace they were declared in // in the source code (the lexical decl context).
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits