]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
dwarf: handle repeated decl with different btf_decl_tags [PR122248]
authorDavid Faust <david.faust@oracle.com>
Tue, 28 Oct 2025 18:13:25 +0000 (11:13 -0700)
committerDavid Faust <david.faust@oracle.com>
Thu, 30 Oct 2025 16:26:23 +0000 (09:26 -0700)
The check in gen_btf_tag_dies which asserted that if the target DIE
already had an annotation then it must be the same as the one we are
attempting to add was too strict.  It is valid for multiple declarations
of the same object to appear with different decl_tags, in which case the
tags from each are accumulated in DECL_ATTRIBUTES.  The existing
annotation may not be the same as the one being added, since new tags
will be added to the head of the chain.

The proper behavior is to always replace any existing AT_GNU_annotation
to refer to the chain of annotations we have just constructed, whether
the head of that chain is the same or not.

PR debug/122248

gcc/

* dwarf2out.cc (gen_btf_tag_dies): Always replace an existing
AT_GNU_annotation on the target die.

gcc/testsuite/

* gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c: New.
* gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c: New.
* gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c: New.

gcc/dwarf2out.cc
gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c [new file with mode: 0644]

index a817c69c95af4960c8990dc7d91ce97d8e49efc7..ac39cf51f7470a3d856250ed0f8b0c46f3fff8d5 100644 (file)
@@ -13842,14 +13842,14 @@ gen_btf_tag_dies (tree attr, dw_die_ref die)
 
   if (die)
     {
-      /* Add AT_GNU_annotation referring to the annotation DIE.
-        It may have already been added, some global declarations are processed
-        twice, but if so it must be the same or we have a bug.  */
-      dw_die_ref existing = get_AT_ref (die, DW_AT_GNU_annotation);
-      if (existing)
-       gcc_checking_assert (existing == tag_die);
-      else
-       add_AT_die_ref (die, DW_AT_GNU_annotation, tag_die);
+      /* Add (or replace) AT_GNU_annotation referring to the annotation DIE.
+        Replacement may happen for example when 'die' is a global variable
+        which has been re-declared multiple times.  In any case, the set of
+        input attributes is the one that ought to be reflected.  For global
+        variable re-declarations which add additional decl tags, they will
+        have been accumulated in the variable's DECL_ATTRIBUTES for us.  */
+      remove_AT (die, DW_AT_GNU_annotation);
+      add_AT_die_ref (die, DW_AT_GNU_annotation, tag_die);
     }
 
   return tag_die;
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c
new file mode 100644 (file)
index 0000000..6fdcdc6
--- /dev/null
@@ -0,0 +1,28 @@
+/* Test DWARF generation for decl_tags on global decls appearing multiple
+   times with different decl_tags.  PR122248.  */
+/* { dg-do compile } */
+/* { dg-options "-gdwarf -dA" } */
+
+#define __tag1 __attribute__((btf_decl_tag ("tag1")))
+#define __tag2 __attribute__((btf_decl_tag ("tag2")))
+#define __tag3 __attribute__((btf_decl_tag ("tag3")))
+#define __tag4 __attribute__((btf_decl_tag ("tag4")))
+
+int foo __tag1;
+int foo __tag2;
+
+/* Result: foo has __tag1 and __tag2.  */
+
+int bar __tag3;
+int bar;
+
+/* Result: bar has __tag3.  */
+
+int baz;
+int baz __tag4;
+
+/* Result: baz has __tag4.  */
+
+/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_GNU_annotation" 4 } } */
+/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 4 } } */
+
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c
new file mode 100644 (file)
index 0000000..c7cb60c
--- /dev/null
@@ -0,0 +1,35 @@
+/* Test DWARF generation for decl_tags on global decls appearing multiple
+   times with different decl_tags.  PR122248.  */
+/* { dg-do compile } */
+/* { dg-options "-gdwarf -dA" } */
+
+#define __tag1 __attribute__((btf_decl_tag ("tag1")))
+#define __tag2 __attribute__((btf_decl_tag ("tag2")))
+#define __tag3 __attribute__((btf_decl_tag ("tag3")))
+
+struct S
+{
+  int x;
+  char c;
+};
+
+extern struct S foo __tag1;
+struct S foo __tag2;
+
+/* Result: non-completing variable DIE for 'foo' has tag1, and the
+   completing DIE (with AT_specification) for 'foo' has tag2 -> tag1.  */
+
+extern int a __tag3;
+int a;
+
+/* Result: non-completing variable DIE for a has tag3, and the
+   completing DIE (with AT_specification) for 'a' also refers to tag3.  */
+
+/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_GNU_annotation" 3 } } */
+
+/* 5 AT_GNU annotations:
+   - foo -> tag1
+   - foo -> tag2 -> tag1
+   - a -> tag3
+   - a -> tag3 */
+/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 5 } } */
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c
new file mode 100644 (file)
index 0000000..dd89d11
--- /dev/null
@@ -0,0 +1,24 @@
+/* Test DWARF generation for decl_tags on global decls appearing multiple
+   times with different decl_tags.  PR122248.  */
+/* { dg-do compile } */
+/* { dg-options "-gdwarf -dA" } */
+
+#define __tag1 __attribute__((btf_decl_tag ("tag1")))
+#define __tag2 __attribute__((btf_decl_tag ("tag2")))
+#define __tag3 __attribute__((btf_decl_tag ("tag3")))
+
+__tag1
+extern int
+do_thing (int);
+
+__tag2
+__tag3
+int
+do_thing (int x)
+{
+  return x * x;
+}
+
+/* Result: do_thing has all 3 tags.  */
+/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_GNU_annotation" 3 } } */
+/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 3 } } */