https://github.com/dzhidzhoev updated https://github.com/llvm/llvm-project/pull/213153
>From 747a9f607f019f1316a60e2426712b7d5f002367 Mon Sep 17 00:00:00 2001 From: Vladislav Dzhidzhoev <[email protected]> Date: Wed, 29 Jul 2026 22:35:09 +0200 Subject: [PATCH 1/2] [clang][DebugInfo] Allow function-local statics to be scoped within a lexical block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up for https://github.com/llvm/llvm-project/pull/187927. Currently, static local variables are created in DISubprogram scopes. With this change, DIGlobalVariables for static locals are created in the corresponding DILexicalBlocks. It helps debug info consumers to distinguish betweeen static locals with the same name declared in different lexical blocks. Fixes https://github.com/llvm/llvm-project/issues/19612. This change has already been reviewed in https://reviews.llvm.org/D125694, but it was quite a while ago, so I’m opening a new PR for visibility. Authored-by: Kristina Bessonova <[email protected]> --- clang/lib/CodeGen/CGDebugInfo.cpp | 8 +++ .../X86/debug-info-static-locals.cpp | 56 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 clang/test/DebugInfo/X86/debug-info-static-locals.cpp diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index f155761a1d998..4cf448041e246 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -4627,6 +4627,14 @@ void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit, TemplateParameters = nullptr; } + // Get context for static locals (that are technically globals) the same way + // we do for "local" locals -- by using current lexical block. + if (VD->isStaticLocal()) { + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); + 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). diff --git a/clang/test/DebugInfo/X86/debug-info-static-locals.cpp b/clang/test/DebugInfo/X86/debug-info-static-locals.cpp new file mode 100644 index 0000000000000..2671564d25816 --- /dev/null +++ b/clang/test/DebugInfo/X86/debug-info-static-locals.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -emit-llvm -debug-info-kind=limited %s -o - -O0 | FileCheck %s + +// Test that static local variables are emitted in correct scopes. + +void test() { + static int bar = 2; + { + static int bar = 1; + { + static int bar = 0; + } + } +} + +// Automatic local variables in braceless arms of +// if statement are placed in the same DILexicalBlock. +// Test that the behavior for static locals is the same as +// for automatic variables in that case. +void test_braceless(int x) { + if (x) + static int foo = 30; + else + static int foo = 40; + if (x) +#line 100 + int foobar = 50; + else +#line 200 + int foobar = 60; +} + +// CHECK: ![[FS_GVE:[0-9]+]] = !DIGlobalVariableExpression(var: ![[FS_GV:[0-9]+]] +// CHECK: ![[FS_GV]] = distinct !DIGlobalVariable(name: "bar", scope: ![[FSCOPE:[0-9]+]] +// CHECK: ![[FSCOPE]] = distinct !DISubprogram(name: "test" +// CHECK-SAME: retainedNodes: ![[FS_DECLS:[0-9]+]] +// CHECK: ![[FS_DECLS]] = !{![[FS_GVE]], ![[LB1_GVE:[0-9]+]], ![[LB2_GVE:[0-9]+]]} +// CHECK: ![[LB1_GVE]] = !DIGlobalVariableExpression(var: ![[LB1_GV:[0-9]+]] +// CHECK: ![[LB1_GV]] = distinct !DIGlobalVariable(name: "bar", scope: ![[LB1SCOPE:[0-9]+]] +// CHECK: ![[LB1SCOPE]] = distinct !DILexicalBlock(scope: ![[FSCOPE]] +// CHECK: ![[LB2_GVE]] = !DIGlobalVariableExpression(var: ![[LB2_GV:[0-9]+]] +// CHECK: ![[LB2_GV]] = distinct !DIGlobalVariable(name: "bar", scope: ![[LB2SCOPE:[0-9]+]] +// CHECK: ![[LB2SCOPE]] = distinct !DILexicalBlock(scope: ![[LB1SCOPE]] + +// CHECK: ![[B_LB1_GVE:[0-9]+]] = !DIGlobalVariableExpression(var: ![[B_LB1_GV:[0-9]+]] +// CHECK: ![[B_LB1_GV]] = distinct !DIGlobalVariable(name: "foo", scope: ![[B_LBSCOPE:[0-9]+]] +// CHECK: ![[B_LBSCOPE]] = distinct !DILexicalBlock(scope: ![[BSCOPE:[0-9]+]] +// CHECK: ![[BSCOPE]] = distinct !DISubprogram(name: "test_braceless" +// CHECK-SAME: retainedNodes: ![[B_DECLS:[0-9]+]] +// CHECK: ![[B_DECLS]] = !{![[B_LB1_GVE]], ![[B_LB2_GVE:[0-9]+]]} +// CHECK: ![[B_LB2_GVE]] = !DIGlobalVariableExpression(var: ![[B_LB2_GV:[0-9]+]] + +// CHECK: ![[LOCAL_VAR_SCOPE:[0-9]+]] = distinct !DILexicalBlock(scope: ![[BSCOPE]] +// CHECK: ![[LOCAL_VAR1:[0-9]+]] = !DILocalVariable(name: "foobar", scope: ![[LOCAL_VAR_SCOPE]] +// CHECK-SAME: line: 100 +// CHECK: ![[LOCAL_VAR2:[0-9]+]] = !DILocalVariable(name: "foobar", scope: ![[LOCAL_VAR_SCOPE]] +// CHECK-SAME: line: 200 >From 5e5aa43d0d8078e8a8d263ef1c90de2790e5873b Mon Sep 17 00:00:00 2001 From: Vladislav Dzhidzhoev <[email protected]> Date: Fri, 31 Jul 2026 16:35:04 +0200 Subject: [PATCH 2/2] Add tests --- .../X86/debug-info-thread-locals.cpp | 25 +++++++++++ .../dexter-tests/static-locals-in-lb.c | 43 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 clang/test/DebugInfo/X86/debug-info-thread-locals.cpp create mode 100644 cross-project-tests/debuginfo-tests/dexter-tests/static-locals-in-lb.c diff --git a/clang/test/DebugInfo/X86/debug-info-thread-locals.cpp b/clang/test/DebugInfo/X86/debug-info-thread-locals.cpp new file mode 100644 index 0000000000000..507b8d9762a01 --- /dev/null +++ b/clang/test/DebugInfo/X86/debug-info-thread-locals.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -emit-llvm -debug-info-kind=limited %s -o - -O0 | FileCheck %s + +// Test that thread-local variables are emitted in correct scopes. + +void test() { + thread_local int bar = 2; + { + thread_local int bar = 1; + { + thread_local int bar = 0; + } + } +} + +// CHECK: ![[FS_GVE:[0-9]+]] = !DIGlobalVariableExpression(var: ![[FS_GV:[0-9]+]] +// CHECK: ![[FS_GV]] = distinct !DIGlobalVariable(name: "bar", scope: ![[FSCOPE:[0-9]+]] +// CHECK: ![[FSCOPE]] = distinct !DISubprogram(name: "test" +// CHECK-SAME: retainedNodes: ![[FS_DECLS:[0-9]+]] +// CHECK: ![[FS_DECLS]] = !{![[FS_GVE]], ![[LB1_GVE:[0-9]+]], ![[LB2_GVE:[0-9]+]]} +// CHECK: ![[LB1_GVE]] = !DIGlobalVariableExpression(var: ![[LB1_GV:[0-9]+]] +// CHECK: ![[LB1_GV]] = distinct !DIGlobalVariable(name: "bar", scope: ![[LB1SCOPE:[0-9]+]] +// CHECK: ![[LB1SCOPE]] = distinct !DILexicalBlock(scope: ![[FSCOPE]] +// CHECK: ![[LB2_GVE]] = !DIGlobalVariableExpression(var: ![[LB2_GV:[0-9]+]] +// CHECK: ![[LB2_GV]] = distinct !DIGlobalVariable(name: "bar", scope: ![[LB2SCOPE:[0-9]+]] +// CHECK: ![[LB2SCOPE]] = distinct !DILexicalBlock(scope: ![[LB1SCOPE]] diff --git a/cross-project-tests/debuginfo-tests/dexter-tests/static-locals-in-lb.c b/cross-project-tests/debuginfo-tests/dexter-tests/static-locals-in-lb.c new file mode 100644 index 0000000000000..d93d61707b61e --- /dev/null +++ b/cross-project-tests/debuginfo-tests/dexter-tests/static-locals-in-lb.c @@ -0,0 +1,43 @@ +// This test case verifies that function-local static variables with the same name +// declared in different lexical blocks are read correctly in the debugger. +// REQUIRES: lldb +// UNSUPPORTED: system-windows +// +// RUN: %clang -O0 -glldb %s -o %t +// RUN: %dexter -w --binary %t %dexter_lldb_args -- %s | FileCheck %s + +int test(int x) { + int result; + if (x > 0) { + static int y = 1; + result = x + y; // !dex_label pos + } else { + static int y = 2; + result = x - y; // !dex_label neg + } + return result; // !dex_label ret +} + +int main(int argc, const char **argv) { + test(5); + test(-3); + return 0; +} + +// CHECK-DAG: seen_values: 2 +// CHECK-DAG: correct_steps: 2 +// CHECK-DAG: unexpected_value_steps: 0 +// CHECK-DAG: missing_var_steps: 2 +// CHECK-DAG: correct_step_coverage: 50.0% + +/* +--- +!where {lines: !label pos}: + !value y: 1 +!where {lines: !label neg}: + !value y: 2 +# The value of y's should not be available out of declaration scopes. +!where {lines: !label ret}: + !value y: null +... +*/ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
