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

Reply via email to