https://gcc.gnu.org/g:986938a310e726162bfda79adbb070c36aadfc80

commit r16-6269-g986938a310e726162bfda79adbb070c36aadfc80
Author: Jakub Jelinek <[email protected]>
Date:   Fri Dec 19 11:12:21 2025 +0100

    c++, dwarf2out: Debug info for namespace scope structured bindings 
[PR122968]
    
    As the following testcase shows, we weren't emitting any debug info for
    namespace scope structured bindings (except for tuple based ones, those
    worked fine).
    
    There are multiple problems:
    1) for tuple based structured bindings there is cp_finish_decl and the
       VAR_DECLs are registered in varpool, but the other ones are just
       VAR_DECLs with DECL_VALUE_EXPR for elements of the underlying VAR_DECL,
       so they don't really appear in the IL; and we weren't calling
       early_global_decl debug hook on those
    2) fixing that makes those appear only with -fno-eliminate-unused-symbols,
       because whether something is used is determined by the presence of
       varpool node for it; I think varpool is unprepared to handle
       DECL_VALUE_EXPR VAR_DECLs, those would appear always unused;
       so, the patch instead adds mapping from the underlying VAR_DECL
       to the structured bindings needed for debug info in an artificial
       attribute and when marking the underlying VAR_DECL of a structured
       binding as used, it marks all the structured bindings attached to it
       as well
    3) with this, the DW_TAG_variable DIEs for structured bindings appear even
       without -fno-eliminate-unused-symbols, but they still don't have
       locations; for that we need to arrange when we add DW_AT_location to the
       underlying variable to also add DW_AT_location to the structured bindings
       afterwards
    
    Note, this patch doesn't improve the structured bindings bound to bitfields
    case the PR was filed for originally, neither at namespace scope nor at
    block scope.  That will need to be handled incrementally.
    
    2025-12-19  Jakub Jelinek  <[email protected]>
    
            PR debug/122968
    gcc/
            * dwarf2out.cc (premark_used_variables): Handle "structured 
bindings"
            attribute.
            (dwarf2out_late_global_decl): Likewise.
    gcc/cp/
            * decl.cc (cp_finish_decomp): For structured bindings at namespace
            scope which have DECL_HAS_VALUE_EXPR_P set, call early_global_decl
            debug hook and put all such structured bindings into
            "structured bindings" attribute arguments on the underlying decl.
    gcc/testsuite/
            * g++.dg/guality/decomp1.C: New test.

Diff:
---
 gcc/cp/decl.cc                         | 17 +++++++++++++++
 gcc/dwarf2out.cc                       | 30 +++++++++++++++++++++++++--
 gcc/testsuite/g++.dg/guality/decomp1.C | 38 ++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index f094f1ea5e97..8468b778da8d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -11083,6 +11083,23 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool 
test_p)
            DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
          }
     }
+  else if (DECL_NAMESPACE_SCOPE_P (decl) && !seen_error ())
+    {
+      tree attr = NULL_TREE, *pa = &attr;
+      for (unsigned int i = 0; i < count; i++)
+       if ((unsigned) pack != i
+           && DECL_HAS_VALUE_EXPR_P (v[i])
+           && !DECL_IGNORED_P (v[i]))
+         {
+           (*debug_hooks->early_global_decl) (v[i]);
+           *pa = build_tree_list (NULL_TREE, v[i]);
+           pa = &TREE_CHAIN (*pa);
+         }
+      if (attr)
+       DECL_ATTRIBUTES (decl)
+         = tree_cons (get_identifier ("structured bindings"),
+                      attr, DECL_ATTRIBUTES (decl));
+    }
   return false;
 }
 
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index c637f9d93f05..443c3f00523c 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -23877,7 +23877,17 @@ premark_used_variables (void)
     {
       dw_die_ref die = lookup_decl_die (var->decl);
       if (die)
-       die->die_perennial_p = 1;
+       {
+         die->die_perennial_p = 1;
+         if (tree attr = lookup_attribute ("structured bindings",
+                                           DECL_ATTRIBUTES (var->decl)))
+           for (tree d = TREE_VALUE (attr); d; d = TREE_CHAIN (d))
+             {
+               die = lookup_decl_die (TREE_VALUE (d));
+               if (die)
+                 die->die_perennial_p = 1;
+             }
+       }
     }
 }
 
@@ -27896,7 +27906,23 @@ dwarf2out_late_global_decl (tree decl)
                    && is_trivial_indirect_ref (DECL_VALUE_EXPR (decl))))
            tree_add_const_value_attribute_for_decl (die, decl);
          else
-           add_location_or_const_value_attribute (die, decl, false);
+           {
+             add_location_or_const_value_attribute (die, decl, false);
+             /* For C++ structured bindings at namespace scope when processing
+                the underlying variable also add locations on the structured
+                bindings which refer to it (unless they are tuple-based, then
+                they are separate VAR_DECLs registered in varpool).  */
+             if (tree attr = lookup_attribute ("structured bindings",
+                                               DECL_ATTRIBUTES (decl)))
+               for (tree d = TREE_VALUE (attr); d; d = TREE_CHAIN (d))
+                 {
+                   die = lookup_decl_die (TREE_VALUE (d));
+                   if (die)
+                     add_location_or_const_value_attribute (die,
+                                                            TREE_VALUE (d),
+                                                            false);
+                 }
+           }
        }
     }
 }
diff --git a/gcc/testsuite/g++.dg/guality/decomp1.C 
b/gcc/testsuite/g++.dg/guality/decomp1.C
new file mode 100644
index 000000000000..912f94647391
--- /dev/null
+++ b/gcc/testsuite/g++.dg/guality/decomp1.C
@@ -0,0 +1,38 @@
+// PR debug/122968
+// { dg-do run { target int32plus } }
+// { dg-options "-g" }
+
+struct S { unsigned a; unsigned long long b; short c; } s = { 10, 53967718, 
-42 };
+auto [ a, b, c ] = s;
+static auto [ d, e, f ] = S { 5, 1245234412, -231 };
+auto *p = &d;
+volatile int v;
+namespace N {
+  auto [ a, b, c ] = S { 8, 7135498, 256 };
+  int arr[4] = { 1, 2, 3, 4 };
+  auto [ d, e, f, g ] = arr;
+}
+
+int
+main ()
+{
+  asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c) : "memory");
+  asm volatile ("" : : "g" (&d), "g" (&e), "g" (&f) : "memory");
+  asm volatile ("" : : "g" (&N::a), "g" (&N::b), "g" (&N::c) : "memory");
+  asm volatile ("" : : "g" (&N::d), "g" (&N::e), "g" (&N::f) : "memory");
+  asm volatile ("" : : "g" (&N::g) : "memory");
+  v = 1;
+// { dg-final { gdb-test 24 "a" "10" } }
+// { dg-final { gdb-test 24 "b" "53967718" } }
+// { dg-final { gdb-test 24 "c" "-42" } }
+// { dg-final { gdb-test 24 "d" "5" } }
+// { dg-final { gdb-test 24 "e" "1245234412" } }
+// { dg-final { gdb-test 24 "f" "-231" } }
+// { dg-final { gdb-test 24 "N::a" "8" } }
+// { dg-final { gdb-test 24 "N::b" "7135498" } }
+// { dg-final { gdb-test 24 "N::c" "256" } }
+// { dg-final { gdb-test 24 "N::d" "1" } }
+// { dg-final { gdb-test 24 "N::e" "2" } }
+// { dg-final { gdb-test 24 "N::f" "3" } }
+// { dg-final { gdb-test 24 "N::g" "4" } }
+}

Reply via email to