diff mbox series

c++: Properly mangle CONST_DECL without a INTEGER_CST value [PR116511]

Message ID 01020191c70b82f6-b6eab845-f923-4389-bef2-f189b8c4ca43-000000@eu-west-1.amazonses.com
State New
Headers show
Series c++: Properly mangle CONST_DECL without a INTEGER_CST value [PR116511] | expand

Commit Message

Simon Martin Sept. 6, 2024, 11:15 a.m. UTC
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 mbox series

Patch

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;