]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++/modules: false positive abi_tag mismatch [PR124957]
authorPatrick Palka <ppalka@redhat.com>
Tue, 5 May 2026 15:26:16 +0000 (11:26 -0400)
committerPatrick Palka <ppalka@redhat.com>
Tue, 5 May 2026 15:26:16 +0000 (11:26 -0400)
Here x in _a.C is defined in terms of A, which has an abi_tag, so it
should inherit A's abi_tag.  It turns out this abi_tag propagation
happens only during mangling via class.cc:check_abi_tags, and we happen
to never mangle x in this TU, so we stream out x with no abi_tag.

In _b.C we import and re-export x, and we also happen to mangle x (for
arbitrary reasons that I didn't question), which means when we stream it
out this time it has an abi_tag.

In _c.C we import both versions of x, merge them, during which we compare
their abi_tag, notice a mismatch, and diagnose.  But the mismatch is
solely due to one version ('existing') being mangled, and therefore went
through class.cc:check_abi_tags, and the other ('decl') not.

Idiosyncracies of this testcase aside (like why x gets mangled in _b.C,
why we stream in two apparent x's in _c.C), it does seem like this
diagnostic routine should be robust to this situation.  To that end this
patch makes the routine ignore such inherited tags during the comparison
if there's a mangled-ness mismatch, via a new flag ABI_TAG_INHERITED
that's set on all inherited tags.  In passing, rename the existing flag
ABI_TAG_IMPLICIT to ABI_TAG_NOT_MANGLED to better describe and
differentiate it from the new flag.

PR c++/124957

gcc/cp/ChangeLog:

* class.cc (check_tag): Set ABI_TAG_INHERITED on the TREE_LIST
of an inherited tag.  Adjust after ABI_TAG_IMPLICIT renaming.
* cp-tree.h (ABI_TAG_IMPLICIT): Rename to ...
(ABI_TAG_NOT_MANGLED): ... this.
(equal_abi_tags): Adjust forward declaration.
* mangle.cc (write_unqualified_name): Adjust equal_abi_tags call.
(sorted_abi_tags): New ignore_inherited_p parameter, for ignoring
ABI_TAG_INHERITED tags.  Adjust after ABI_TAG_INHERITED renaming.
(write_abi_tags): Adjust sorted_abi_tags call.
(equal_abi_tags): New ignore_inherited_p parameter.  Pass it to
sorted_abi_tags.
* module.cc (trees_in::check_abi_tags): Pass
ignore_inherited_p=true to equal_abi_tags iff there's a
mangled-ness mismatch.

gcc/testsuite/ChangeLog:

* g++.dg/modules/attrib-6_a.C: New test.
* g++.dg/modules/attrib-6_b.C: New test.
* g++.dg/modules/attrib-6_c.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/class.cc
gcc/cp/cp-tree.h
gcc/cp/mangle.cc
gcc/cp/module.cc
gcc/testsuite/g++.dg/modules/attrib-6_a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/attrib-6_b.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/attrib-6_c.C [new file with mode: 0644]

index 9f77ec68220b6ca056f775e99e17fb68212e02f7..c9a7eb5c76ecf6274f7bd5a90346a2a10d8162ad 100644 (file)
@@ -1711,11 +1711,12 @@ check_tag (tree tag, tree id, tree *tp, abi_tag_data *p)
          /* Don't inherit this tag multiple times.  */
          IDENTIFIER_MARKED (id) = true;
 
+         ABI_TAG_INHERITED (p->tags) = true;
          if (TYPE_P (p->t))
            {
              /* Tags inherited from type template arguments are only used
                 to avoid warnings.  */
-             ABI_TAG_IMPLICIT (p->tags) = true;
+             ABI_TAG_NOT_MANGLED (p->tags) = true;
              return;
            }
          /* For functions and variables we want to warn, too.  */
index 70132b586d8bfa264e6757049879fc0736d3c944..b94c7a8ca9990ccf774ca602d3a494e94ac42a9a 100644 (file)
@@ -429,7 +429,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR)
       TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX)
       ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute)
-      ABI_TAG_IMPLICIT (in the TREE_LIST for the argument of abi_tag)
+      ABI_TAG_NOT_MANGLED (in the TREE_LIST for the argument of abi_tag)
       LAMBDA_CAPTURE_EXPLICIT_P (in a TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST)
       PARENTHESIZED_LIST_P (in the TREE_LIST for a parameter-declaration-list)
       CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR)
@@ -480,6 +480,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK)
       BIND_EXPR_VEC_DTOR (in BIND_EXPR)
       ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR)
+      ABI_TAG_INHERITED (in the TREE_LIST for the argument of abi_tag)
       STATIC_INIT_DECOMP_BASE_P (in the TREE_LIST for {static,tls}_aggregates)
       MUST_NOT_THROW_THROW_P (in MUST_NOT_THROW_EXPR)
       LAMBDA_EXPR_CONST_QUAL_P (in LAMBDA_EXPR)
@@ -3962,8 +3963,14 @@ struct GTY(()) lang_decl {
 #define ATTR_IS_DEPENDENT(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
 
 /* In a TREE_LIST in the argument of attribute abi_tag, indicates that the tag
-   was inherited from a template parameter, not explicitly indicated.  */
-#define ABI_TAG_IMPLICIT(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
+   was inherited from a template parameter, not explicitly indicated.
+   These are not mangled because they're already represented in the mangling
+   of the template argument.  */
+#define ABI_TAG_NOT_MANGLED(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
+
+/* In a TREE_LIST in the argument of attribute abi_tag, indicates that the tag
+ * was added by check_abi_tags, not explicitly specified.  */
+#define ABI_TAG_INHERITED(NODE) TREE_LANG_FLAG_1 (TREE_LIST_CHECK (NODE))
 
 /* In a TREE_LIST for a parameter-declaration-list, indicates that all the
    parameters in the list have declarators enclosed in ().  */
@@ -9123,7 +9130,7 @@ extern void mangle_module_substitution            (int);
 extern int mangle_module_component             (tree id, bool partition);
 extern tree mangle_module_global_init          (int);
 extern unsigned HOST_WIDE_INT range_expr_nelts (tree);
-extern bool equal_abi_tags                     (tree, tree);
+extern bool equal_abi_tags                     (tree, tree, bool);
 
 /* in dump.cc */
 extern bool cp_dump_tree                       (void *, tree);
index 6e6b16d389d0b2826e0e1f130bc618d101879d85..2605f8505cdcab637e0f3937aea8600a4030518f 100644 (file)
@@ -1645,7 +1645,7 @@ write_unqualified_name (tree decl)
 
          if (!G.need_abi_warning
              && abi_warn_or_compat_version_crosses (11)
-             && !equal_abi_tags (dtags, mtags))
+             && !equal_abi_tags (dtags, mtags, /*ignore_inherited_p=*/false))
            G.need_abi_warning = 1;
 
          if (!abi_version_at_least (10))
@@ -1709,13 +1709,14 @@ tree_string_cmp (const void *p1, const void *p2)
 /* Return the TREE_LIST of TAGS as a sorted VEC.  */
 
 static vec<tree, va_gc> *
-sorted_abi_tags (tree tags)
+sorted_abi_tags (tree tags, bool ignore_inherited_p)
 {
   vec<tree, va_gc> * vec = make_tree_vector();
 
   for (tree t = tags; t; t = TREE_CHAIN (t))
     {
-      if (ABI_TAG_IMPLICIT (t))
+      if (ABI_TAG_NOT_MANGLED (t)
+         || (ignore_inherited_p && ABI_TAG_INHERITED (t)))
        continue;
       tree str = TREE_VALUE (t);
       vec_safe_push (vec, str);
@@ -1735,7 +1736,7 @@ write_abi_tags (tree tags)
   if (tags == NULL_TREE)
     return;
 
-  vec<tree, va_gc> * vec = sorted_abi_tags (tags);
+  vec<tree, va_gc> * vec = sorted_abi_tags (tags, /*ignore_inherited_p=*/false);
 
   unsigned i; tree str;
   FOR_EACH_VEC_ELT (*vec, i, str)
@@ -1751,10 +1752,10 @@ write_abi_tags (tree tags)
 /* True iff the TREE_LISTS T1 and T2 of ABI tags are equivalent.  */
 
 bool
-equal_abi_tags (tree t1, tree t2)
+equal_abi_tags (tree t1, tree t2, bool ignore_inherited_p)
 {
-  releasing_vec v1 = sorted_abi_tags (t1);
-  releasing_vec v2 = sorted_abi_tags (t2);
+  releasing_vec v1 = sorted_abi_tags (t1, ignore_inherited_p);
+  releasing_vec v2 = sorted_abi_tags (t2, ignore_inherited_p);
 
   unsigned len1 = v1->length();
   if (len1 != v2->length())
index 5bf16ecbe3ba24a3b02c9e63c4d79a91fc86ad71..6616c8753641df6bf4c553dfeae216cf090884bb 100644 (file)
@@ -12542,8 +12542,13 @@ trees_in::check_abi_tags (tree existing, tree decl, tree &eattr, tree &dattr)
       if (dtags)
        dtags = TREE_VALUE (dtags);
 
-      /* We only error if mangling wouldn't consider the tags equivalent.  */
-      if (!equal_abi_tags (etags, dtags))
+      /* We only error if mangling wouldn't consider the tags equivalent.
+        Since tags might have been inherited during mangling, ignore
+        inherited tags if there's a mangled-ness mismatch.  */
+      bool ignore_inherited_p
+       = (DECL_ASSEMBLER_NAME_SET_P (STRIP_TEMPLATE (existing))
+          != DECL_ASSEMBLER_NAME_SET_P (STRIP_TEMPLATE (decl)));
+      if (!equal_abi_tags (etags, dtags, ignore_inherited_p))
        {
          auto_diagnostic_group d;
          if (dtags)
diff --git a/gcc/testsuite/g++.dg/modules/attrib-6_a.C b/gcc/testsuite/g++.dg/modules/attrib-6_a.C
new file mode 100644 (file)
index 0000000..ea8508c
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/124957
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-fmodules" }
+
+export module mod:partition;
+
+int dummy;
+struct [[gnu::abi_tag("cxx11")]] A { int m; };
+export inline int A::*x = &A::m;
+// x does not get mangled in this TU => cxx11 abi_tag not propagated to x
diff --git a/gcc/testsuite/g++.dg/modules/attrib-6_b.C b/gcc/testsuite/g++.dg/modules/attrib-6_b.C
new file mode 100644 (file)
index 0000000..3015aa6
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/124957
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-fmodules" }
+
+export module mod; // { dg-module-cmi "mod" }
+export import :partition;
+
+// x gets mangled in this TU => cxx11 abi_tag propagated to x
diff --git a/gcc/testsuite/g++.dg/modules/attrib-6_c.C b/gcc/testsuite/g++.dg/modules/attrib-6_c.C
new file mode 100644 (file)
index 0000000..c0c55a2
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/124957
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-fmodules -fno-module-lazy" }
+
+module mod;
+import :partition;
+
+// OK, no bogus abi_tag mismatch error for the imported x's