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 are accumulated in the DECL_ATTRIBUTES, but the existing tag may
not be the same as the one being added.  This was not handled correctly
and led to the ICE reported in the PR.

The more accurate requirement for consistency is that if there is an
existing chain of annotations, then it is a sub-chain of the one we are
adding in the current pass.  This patch fixes gen_btf_tag_dies to use
the more accurate check and properly handle the case in the PR.

Bootstrapped and tested on x86_64-linux-gnu.

OK for trunk?
Thanks

        PR debug/122248

gcc/

        * dwarf2out.cc (gen_btf_tag_dies): Handle repeated declarations
        of the same object with different decl_tags and improve accuracy
        of the consistency check under flag_checking.

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                              | 27 +++++++++++---
 .../debug/dwarf2/dwarf-btf-decl-tag-4.c       | 28 +++++++++++++++
 .../debug/dwarf2/dwarf-btf-decl-tag-5.c       | 35 +++++++++++++++++++
 .../debug/dwarf2/dwarf-btf-decl-tag-6.c       | 24 +++++++++++++
 4 files changed, 109 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c

diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index a817c69c95a..8fe6e3321e1 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -13843,13 +13843,30 @@ 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.  */
+        There may be an existing annotation chain, as in the case of global
+        decls which may can processed (and declared) multiple times.
+        Each time a global decl is processed it may have additional
+        decl_tags, but the set should never shrink.  */
       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);
+       {
+         if (flag_checking)
+           {
+             /* If there is an existing annotation chain, then it must be a
+                sub-chain of this one, i.e. its head must be somewhere in the
+                chain from tag_die.  Otherwise we may have a bug.  */
+             dw_die_ref d = tag_die;
+             while (d && d != existing)
+               d = get_AT_ref (die, DW_AT_GNU_annotation);
+
+             gcc_assert (d);
+           }
+
+         /* Remove the existing annotation and replace it with the new.  */
+         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
index 00000000000..6fdcdc6e864
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c
@@ -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
index 00000000000..c7cb60ca986
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c
@@ -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
index 00000000000..dd89d1142b9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c
@@ -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 } } */
-- 
2.51.0

Reply via email to