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/4] [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/4] 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 +... +*/ >From a77c0c8da6a00f0627d607da43fecc8d304ab15b Mon Sep 17 00:00:00 2001 From: Vladislav Dzhidzhoev <[email protected]> Date: Fri, 31 Jul 2026 17:27:12 +0200 Subject: [PATCH 3/4] Test expression evaluation --- .../debuginfo-tests/dexter-tests/static-locals-in-lb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 index d93d61707b61e..11c75236cec7f 100644 --- 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 @@ -24,18 +24,20 @@ int main(int argc, const char **argv) { return 0; } -// CHECK-DAG: seen_values: 2 -// CHECK-DAG: correct_steps: 2 +// CHECK-DAG: seen_values: 4 +// CHECK-DAG: correct_steps: 4 // CHECK-DAG: unexpected_value_steps: 0 // CHECK-DAG: missing_var_steps: 2 -// CHECK-DAG: correct_step_coverage: 50.0% +// CHECK-DAG: correct_step_coverage: 66.7% /* --- !where {lines: !label pos}: !value y: 1 + !value "x + y": 6 !where {lines: !label neg}: !value y: 2 + !value "x - y": -5 # The value of y's should not be available out of declaration scopes. !where {lines: !label ret}: !value y: null >From 3ef8fbfc5b7822e5c449f41ca34557cfcd32a920 Mon Sep 17 00:00:00 2001 From: Vladislav Dzhidzhoev <[email protected]> Date: Fri, 31 Jul 2026 17:31:16 +0200 Subject: [PATCH 4/4] Fix formatting --- .../debuginfo-tests/dexter-tests/static-locals-in-lb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 11c75236cec7f..1649e5be71f09 100644 --- 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 @@ -1,5 +1,5 @@ -// This test case verifies that function-local static variables with the same name -// declared in different lexical blocks are read correctly in the debugger. +// 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 // _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
