We ICE upon the following *valid* code when mangling the requires
clause
=== cut here ===
template <int> struct s1 {
enum { e1 = 1 };
};
template <int t2> struct s2 {
enum { e1 = s1<t2>::e1 };
s2() requires(0 != e1) {}
};
s2<8> a;
=== cut here ===
The problem is that the mangler wrongly assumes that the DECL_INITIAL of
a CONST_DECL is always an INTEGER_CST, and blindly passes it to
write_integer_cst.
I assume we should be able to actually compute the value of e1 and use
it when mangling, however from my investigation, it seems to be a pretty
involved change.
What's clear however is that we should not try to write a non-literal as
a literal. This patch adds a utility function to determine whether a
tree is a literal as per the definition in the ABI, and uses it to only
call write_template_arg_literal when we actually have a literal in hand.
Note that I had to change the expectation of an existing test, that was
expecting "[...]void (AF::*)(){}[...]" and now gets an equivalent
"[...](void (AF::*)())0[...]" (and FWIW is what clang and icx give; see
https://godbolt.org/z/hnjdeKEhW).
Successfully tested on x86_64-pc-linux-gnu.
PR c++/116511
gcc/cp/ChangeLog:
* mangle.cc (literal_p): New.
(write_expression): Only call write_template_arg_literal for
expressions with literal_p.
(write_template_arg): Likewise.
(write_template_arg_literal): Assert literal_p.
gcc/testsuite/ChangeLog:
* g++.dg/abi/mangle72.C: Adjust test expectation.
* g++.dg/abi/mangle80.C: New test.
---
gcc/cp/mangle.cc | 33 ++++++++++++++++++++++++-----
gcc/testsuite/g++.dg/abi/mangle72.C | 2 +-
gcc/testsuite/g++.dg/abi/mangle80.C | 13 ++++++++++++
3 files changed, 42 insertions(+), 6 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/abi/mangle80.C
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 46dc6923add..8279c3fe177 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -223,6 +223,7 @@ static void write_method_parms (tree, const int, const
tree);
static void write_class_enum_type (const tree);
static void write_template_args (tree, tree = NULL_TREE);
static void write_expression (tree);
+static bool literal_p (const tree);
static void write_template_arg_literal (const tree);
static void write_template_arg (tree);
static void write_template_template_arg (const tree);
@@ -3397,8 +3398,7 @@ write_expression (tree expr)
|| code == TEMPLATE_PARM_INDEX)
write_template_param (expr);
/* Handle literals. */
- else if (TREE_CODE_CLASS (code) == tcc_constant
- || code == CONST_DECL)
+ else if (literal_p (expr))
write_template_arg_literal (expr);
else if (code == EXCESS_PRECISION_EXPR
&& TREE_CODE (TREE_OPERAND (expr, 0)) == REAL_CST)
@@ -3946,6 +3946,29 @@ write_expression (tree expr)
}
}
+/* Determine whether T is a literal per section 5.1.6.1 of the CXX ABI. */
+
+static bool
+literal_p (const tree t)
+{
+ if ((TREE_TYPE (t) && NULLPTR_TYPE_P (TREE_TYPE (t)))
+ || null_member_pointer_value_p (t))
+ return true;
+ else
+ switch (TREE_CODE (t))
+ {
+ case CONST_DECL:
+ return literal_p (DECL_INITIAL (t));
+ case INTEGER_CST:
+ case REAL_CST:
+ case STRING_CST:
+ case COMPLEX_CST:
+ return true;
+ default:
+ return false;
+ }
+}
+
/* Literal subcase of non-terminal <template-arg>.
"Literal arguments, e.g. "A<42L>", are encoded with their type
@@ -3956,6 +3979,8 @@ write_expression (tree expr)
static void
write_template_arg_literal (const tree value)
{
+ gcc_assert (literal_p (value));
+
if (TREE_CODE (value) == STRING_CST)
/* Temporarily mangle strings as braced initializer lists. */
write_string ("tl");
@@ -4113,9 +4138,7 @@ write_template_arg (tree node)
else if (code == TEMPLATE_DECL)
/* A template appearing as a template arg is a template template arg. */
write_template_template_arg (node);
- else if ((TREE_CODE_CLASS (code) == tcc_constant && code != PTRMEM_CST)
- || code == CONST_DECL
- || null_member_pointer_value_p (node))
+ else if (literal_p (node))
write_template_arg_literal (node);
else if (code == EXCESS_PRECISION_EXPR
&& TREE_CODE (TREE_OPERAND (node, 0)) == REAL_CST)
diff --git a/gcc/testsuite/g++.dg/abi/mangle72.C
b/gcc/testsuite/g++.dg/abi/mangle72.C
index 9581451c25d..fd7d6cb51ad 100644
--- a/gcc/testsuite/g++.dg/abi/mangle72.C
+++ b/gcc/testsuite/g++.dg/abi/mangle72.C
@@ -89,7 +89,7 @@ void k00 (F<D{{ 0, 0 }}>) { }
// { dg-final { scan-assembler "_Z3k001FIXtl1DEEE" } }
void k0x (F<D{{ 0, &AF::f }}>) { }
-// { dg-final { scan-assembler
"_Z3k0x1FIXtl1DtlA2_M2AFFvvEtlS3_EtlS3_adL_ZNS1_1fEvEEEEEE" } }
+// { dg-final { scan-assembler
"_Z3k0x1FIXtl1DtlA2_M2AFFvvELS3_0EtlS3_adL_ZNS1_1fEvEEEEEE" } }
void kx_ (F<D{{ &AF::f }}>) { }
// { dg-final { scan-assembler
"_Z3kx_1FIXtl1DtlA2_M2AFFvvEtlS3_adL_ZNS1_1fEvEEEEEE" } }
diff --git a/gcc/testsuite/g++.dg/abi/mangle80.C
b/gcc/testsuite/g++.dg/abi/mangle80.C
new file mode 100644
index 00000000000..983f35cc440
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle80.C
@@ -0,0 +1,13 @@
+// PR c++/116511
+// { dg-do compile { target c++20 } }
+// { dg-additional-options -fabi-compat-version=0 }
+template <int> struct s1 {
+ enum { e1 = 1 };
+};
+template <int t2> struct s2 {
+ enum { e1 = s1<t2>::e1 };
+ s2() requires(0 != e1) {}
+};
+
+// { dg-final { scan-assembler "_ZN2s2ILi8EEC1EvQneLi0EL_ZNS_IXT_EEUt_2e1EE" }
}
+s2<8> a;
--
2.44.0