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