Investigating the ICE in 71814, I found that we never implemented the specified mangling for sizeof...; sZ for a simple sizeof...(pack) and sP for a more complicated form involving an alias template. So the first patch implements mangling and demangling those forms.
Similarly, 71711 shows that we never implemented mangling of C++17 fold-expressions, or partial instantiation of them. The last patch bumps -fabi-version to 11 to deal with the change in sizeof... mangling. Tested x86_64-pc-linux-gnu, applying to trunk.
commit 81272a102f30521982d4e6442d1ef7b868f2d1fa Author: Jason Merrill <ja...@redhat.com> Date: Mon Jul 11 16:02:42 2016 -0400 PR c++/71814 - mangling sizeof... (sP and sZ) gcc/cp/ * mangle.c (write_expression): Handle sizeof... an argument pack. libiberty/ * cp-demangle.c (cplus_demangle_operators): Add sP and sZ. (d_print_comp_inner): Handle them. (d_template_args_1): Split out from d_template_args. (d_args_length): New. diff --git a/gcc/common.opt b/gcc/common.opt index 2b68fa7..b56ba47 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -882,6 +882,9 @@ Driver Undocumented ; identity, such as ia32 calling convention attributes (stdcall, etc.) ; Default in G++ 6 (set in c_common_post_options). ; +; 11: The version of the ABI that corrects mangling of sizeof... expressions. +; Default in G++ 7. +; ; Additional positive integers will be assigned as new versions of ; the ABI become the default version of the ABI. fabi-version= diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 0e44409..8205da9 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2767,17 +2767,67 @@ write_expression (tree expr) write_mangled_name (expr, false); write_char ('E'); } - else if (TREE_CODE (expr) == SIZEOF_EXPR - && SIZEOF_EXPR_TYPE_P (expr)) + else if (TREE_CODE (expr) == SIZEOF_EXPR) { - write_string ("st"); - write_type (TREE_TYPE (TREE_OPERAND (expr, 0))); - } - else if (TREE_CODE (expr) == SIZEOF_EXPR - && TYPE_P (TREE_OPERAND (expr, 0))) - { - write_string ("st"); - write_type (TREE_OPERAND (expr, 0)); + tree op = TREE_OPERAND (expr, 0); + + if (PACK_EXPANSION_P (op)) + { + if (abi_warn_or_compat_version_crosses (11)) + G.need_abi_warning = true; + if (abi_version_at_least (11)) + { + /* sZ rather than szDp. */ + write_string ("sZ"); + write_expression (PACK_EXPANSION_PATTERN (op)); + return; + } + } + + if (SIZEOF_EXPR_TYPE_P (expr)) + { + write_string ("st"); + write_type (TREE_TYPE (op)); + } + else if (ARGUMENT_PACK_P (op)) + { + tree args = ARGUMENT_PACK_ARGS (op); + int length = TREE_VEC_LENGTH (args); + if (abi_warn_or_compat_version_crosses (10)) + G.need_abi_warning = true; + if (abi_version_at_least (10)) + { + /* sP <template-arg>* E # sizeof...(T), size of a captured + template parameter pack from an alias template */ + write_string ("sP"); + for (int i = 0; i < length; ++i) + write_template_arg (TREE_VEC_ELT (args, i)); + write_char ('E'); + } + else + { + /* In GCC 5 we represented this sizeof wrong, with the effect + that we mangled it as the last element of the pack. */ + tree arg = TREE_VEC_ELT (args, length-1); + if (TYPE_P (op)) + { + write_string ("st"); + write_type (arg); + } + else + { + write_string ("sz"); + write_expression (arg); + } + } + } + else if (TYPE_P (TREE_OPERAND (expr, 0))) + { + write_string ("st"); + write_type (TREE_OPERAND (expr, 0)); + } + else + goto normal_expr; } else if (TREE_CODE (expr) == ALIGNOF_EXPR && TYPE_P (TREE_OPERAND (expr, 0))) @@ -2947,6 +2997,7 @@ write_expression (tree expr) } else { + normal_expr: int i, len; const char *name; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-mangle1.C b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle1.C new file mode 100644 index 0000000..51f9581 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle1.C @@ -0,0 +1,11 @@ +// Test for sZ mangling. +// { dg-do compile { target c++11 } } +// { dg-final { scan-assembler "_Z1fIJidEEv1AIXsZT_EE" } } + +template <int I> struct A { }; +template <typename... Ts> void f(A<sizeof...(Ts)>); + +int main() +{ + f<int,double>(A<2>()); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-mangle1a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle1a.C new file mode 100644 index 0000000..b230ffa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle1a.C @@ -0,0 +1,12 @@ +// Test for sZ mangling. +// { dg-do compile { target c++11 } } +// { dg-final { scan-assembler "_Z1fIJidEEv1AIXstDpT_EE" } } +// { dg-options -fabi-version=9 } + +template <int I> struct A { }; +template <typename... Ts> void f(A<sizeof...(Ts)>); + +int main() +{ + f<int,double>(A<2>()); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-mangle2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle2.C new file mode 100644 index 0000000..ea96ef8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle2.C @@ -0,0 +1,18 @@ +// Testcase from cxx-abi-dev. +// { dg-do compile { target c++11 } } + +struct A { + template<int...T> using N = int[sizeof...(T)]; + template<int...A> void f(N<A...> &); + + template<typename...T> using M = int[sizeof...(T)]; + template<typename...A> void g(M<A...> &); +}; +void g(A a) +{ + int arr[3]; + // { dg-final { scan-assembler "_ZN1A1fIJLi1ELi2ELi3EEEEvRAsZT__i" } } + a.f<1,2,3>(arr); + // { dg-final { scan-assembler "_ZN1A1gIJiiiEEEvRAsZT__i" } } + a.g<int,int,int>(arr); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-mangle2a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle2a.C new file mode 100644 index 0000000..3ac1517 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle2a.C @@ -0,0 +1,19 @@ +// Testcase from cxx-abi-dev. +// { dg-do compile { target c++11 } } +// { dg-options "-fabi-version=9" } + +struct A { + template<int...T> using N = int[sizeof...(T)]; + template<int...A> void f(N<A...> &); + + template<typename...T> using M = int[sizeof...(T)]; + template<typename...A> void g(M<A...> &); +}; +void g(A a) +{ + int arr[3]; + // { dg-final { scan-assembler "_ZN1A1fIJLi1ELi2ELi3EEEEvRAszspT__i" } } + a.f<1,2,3>(arr); + // { dg-final { scan-assembler "_ZN1A1gIJiiiEEEvRAstDpT__i" } } + a.g<int,int,int>(arr); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-mangle3.C b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle3.C new file mode 100644 index 0000000..f239ef7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle3.C @@ -0,0 +1,10 @@ +// Testcase from cxx-abi-dev. +// { dg-do compile { target c++11 } } +// { dg-final { scan-assembler "_ZN1A1fIJiiEiJiiiEEEvRAsPDpT_T0_DpT1_E_iS3_S5_" } } + +struct A { + template<typename...T> using N = int[sizeof...(T)]; + template<typename...A, typename B, typename...C> + void f(N<A..., B, C...> &, B, C...); +}; +void g(A a) { int arr[6]; a.f<int, int>(arr, 1, 2, 3, 4); } diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-mangle3a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle3a.C new file mode 100644 index 0000000..eba8f59 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-mangle3a.C @@ -0,0 +1,11 @@ +// Testcase from cxx-abi-dev. +// { dg-do compile { target c++11 } } +// { dg-options -fabi-version=9 } +// { dg-final { scan-assembler "_ZN1A1fIJiiEiJiiiEEEvRAstDpT1__iT0_S2_" } } + +struct A { + template<typename...T> using N = int[sizeof...(T)]; + template<typename...A, typename B, typename...C> + void f(N<A..., B, C...> &, B, C...); +}; +void g(A a) { int arr[6]; a.f<int, int>(arr, 1, 2, 3, 4); } diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 7f664b9..56d3bcb 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -466,6 +466,7 @@ static struct demangle_component * d_template_param (struct d_info *); static struct demangle_component *d_template_args (struct d_info *); +static struct demangle_component *d_template_args_1 (struct d_info *); static struct demangle_component * d_template_arg (struct d_info *); @@ -1795,6 +1796,8 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "rc", NL ("reinterpret_cast"), 2 }, { "rm", NL ("%"), 2 }, { "rs", NL (">>"), 2 }, + { "sP", NL ("sizeof..."), 1 }, + { "sZ", NL ("sizeof..."), 1 }, { "sc", NL ("static_cast"), 2 }, { "st", NL ("sizeof "), 1 }, { "sz", NL ("sizeof "), 1 }, @@ -2995,6 +2998,19 @@ d_template_param (struct d_info *di) static struct demangle_component * d_template_args (struct d_info *di) { + if (d_peek_char (di) != 'I' + && d_peek_char (di) != 'J') + return NULL; + d_advance (di, 1); + + return d_template_args_1 (di); +} + +/* <template-arg>* E */ + +static struct demangle_component * +d_template_args_1 (struct d_info *di) +{ struct demangle_component *hold_last_name; struct demangle_component *al; struct demangle_component **pal; @@ -3004,11 +3020,6 @@ d_template_args (struct d_info *di) constructor or destructor. */ hold_last_name = di->last_name; - if (d_peek_char (di) != 'I' - && d_peek_char (di) != 'J') - return NULL; - d_advance (di, 1); - if (d_peek_char (di) == 'E') { /* An argument pack can be empty. */ @@ -3270,6 +3281,8 @@ d_expression_1 (struct d_info *di) if (op->type == DEMANGLE_COMPONENT_CAST && d_check_char (di, '_')) operand = d_exprlist (di, 'E'); + else if (code && !strcmp (code, "sP")) + operand = d_template_args_1 (di); else operand = d_expression_1 (di); @@ -4289,6 +4302,30 @@ d_pack_length (const struct demangle_component *dc) return count; } +/* Returns the number of template args in DC, expanding any pack expansions + found there. */ + +static int +d_args_length (struct d_print_info *dpi, const struct demangle_component *dc) +{ + int count = 0; + for (; dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST; + dc = d_right (dc)) + { + struct demangle_component *elt = d_left (dc); + if (elt == NULL) + break; + if (elt->type == DEMANGLE_COMPONENT_PACK_EXPANSION) + { + struct demangle_component *a = d_find_pack (dpi, d_left (elt)); + count += d_pack_length (a); + } + else + ++count; + } + return count; +} + /* DC is a component of a mangled expression. Print it, wrapped in parens if needed. */ @@ -5125,6 +5162,21 @@ d_print_comp_inner (struct d_print_info *dpi, int options, } } + /* For sizeof..., just print the pack length. */ + if (code && !strcmp (code, "sZ")) + { + struct demangle_component *a = d_find_pack (dpi, operand); + int len = d_pack_length (a); + d_append_num (dpi, len); + return; + } + else if (code && !strcmp (code, "sP")) + { + int len = d_args_length (dpi, operand); + d_append_num (dpi, len); + return; + } + if (op->type != DEMANGLE_COMPONENT_CAST) d_print_expr_op (dpi, options, op); else diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index 1d95952..92ad01f 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -4536,6 +4536,12 @@ void baz<int>(A<sizeof (foo((int)(), (floatcomplex )00000000_00000000))>*) --format=gnu-v3 _Z3fooI1FEN1XIXszdtcl1PclcvT__EEE5arrayEE4TypeEv X<sizeof ((P(((F)())())).array)>::Type foo<F>() + +_Z1fIJidEEv1AIXsZT_EE +void f<int, double>(A<2>) + +_ZN1A1fIJiiEiJiiiEEEvRAsPDpT_T0_DpT1_E_iS3_S5_ +void A::f<int, int, int, int, int, int>(int (&) [6], int, int, int, int) # # Tests a use-after-free problem PR70481
commit 4a8f978dceb66e3c87b5a73e0daa29422d3bed92 Author: Jason Merrill <ja...@redhat.com> Date: Wed Jul 13 18:00:48 2016 -0400 PR c++/71711 - mangle C++1z fold-expressions. * operators.def: Add *_FOLD_EXPR. * cp-tree.h (FOLD_EXPR_P): Parenthesize. * mangle.c (write_expression): Handle fold-expressions. * pt.c (tsubst_unary_left_fold, tsubst_binary_left_fold) (tsubst_unary_right_fold, tsubst_binary_right_fold): Handle partial instantiation. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 74b8c7c..7e84036 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3334,11 +3334,11 @@ extern void decl_shadowed_for_var_insert (tree, tree); TREE_CHECK2 (NODE, BINARY_LEFT_FOLD_EXPR, BINARY_RIGHT_FOLD_EXPR) /* True if NODE is UNARY_FOLD_EXPR or a BINARY_FOLD_EXPR */ -#define FOLD_EXPR_P(NODE) \ - TREE_CODE (NODE) == UNARY_LEFT_FOLD_EXPR \ - || TREE_CODE (NODE) == UNARY_RIGHT_FOLD_EXPR \ - || TREE_CODE (NODE) == BINARY_LEFT_FOLD_EXPR \ - || TREE_CODE (NODE) == BINARY_RIGHT_FOLD_EXPR +#define FOLD_EXPR_P(NODE) \ + (TREE_CODE (NODE) == UNARY_LEFT_FOLD_EXPR \ + || TREE_CODE (NODE) == UNARY_RIGHT_FOLD_EXPR \ + || TREE_CODE (NODE) == BINARY_LEFT_FOLD_EXPR \ + || TREE_CODE (NODE) == BINARY_RIGHT_FOLD_EXPR) /* True when NODE is a fold over a compound assignment operator. */ #define FOLD_EXPR_MODIFY_P(NODE) \ diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 8205da9..d5b26d6 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -3145,6 +3145,29 @@ write_expression (tree expr) "cannot be mangled"); continue; } + else if (FOLD_EXPR_P (expr)) + { + /* The first 'operand' of a fold-expression is the operator + that it folds over. */ + if (i == 0) + { + int fcode = TREE_INT_CST_LOW (operand); + write_string (operator_name_info[fcode].mangled_name); + continue; + } + else if (code == BINARY_LEFT_FOLD_EXPR) + { + /* The order of operands of the binary left and right + folds is the same, but we want to mangle them in + lexical order, i.e. non-pack first. */ + if (i == 1) + operand = FOLD_EXPR_INIT (expr); + else + operand = FOLD_EXPR_PACK (expr); + } + if (PACK_EXPANSION_P (operand)) + operand = PACK_EXPANSION_PATTERN (operand); + } write_expression (operand); } } diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def index aa657fa..5b4f1b0 100644 --- a/gcc/cp/operators.def +++ b/gcc/cp/operators.def @@ -155,3 +155,7 @@ DEF_SIMPLE_OPERATOR ("()", CALL_EXPR, "cl", -1) /* Variadic templates extension. */ DEF_SIMPLE_OPERATOR ("...", EXPR_PACK_EXPANSION, "sp", 1) +DEF_SIMPLE_OPERATOR ("... +", UNARY_LEFT_FOLD_EXPR, "fl", 2) +DEF_SIMPLE_OPERATOR ("+ ...", UNARY_RIGHT_FOLD_EXPR, "fr", 2) +DEF_SIMPLE_OPERATOR ("+ ... +", BINARY_LEFT_FOLD_EXPR, "fL", 3) +DEF_SIMPLE_OPERATOR ("+ ... +", BINARY_RIGHT_FOLD_EXPR, "fR", 3) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 73b53e2..de70fb2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10791,6 +10791,12 @@ tsubst_unary_left_fold (tree t, tree args, tsubst_flags_t complain, tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl); if (pack == error_mark_node) return error_mark_node; + if (PACK_EXPANSION_P (pack)) + { + tree r = copy_node (t); + FOLD_EXPR_PACK (r) = pack; + return r; + } if (TREE_VEC_LENGTH (pack) == 0) return expand_empty_fold (t, complain); else @@ -10813,6 +10819,14 @@ tsubst_binary_left_fold (tree t, tree args, tsubst_flags_t complain, if (init == error_mark_node) return error_mark_node; + if (PACK_EXPANSION_P (pack)) + { + tree r = copy_node (t); + FOLD_EXPR_PACK (r) = pack; + FOLD_EXPR_INIT (r) = init; + return r; + } + tree vec = make_tree_vec (TREE_VEC_LENGTH (pack) + 1); TREE_VEC_ELT (vec, 0) = init; for (int i = 0; i < TREE_VEC_LENGTH (pack); ++i) @@ -10854,6 +10868,12 @@ tsubst_unary_right_fold (tree t, tree args, tsubst_flags_t complain, tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl); if (pack == error_mark_node) return error_mark_node; + if (PACK_EXPANSION_P (pack)) + { + tree r = copy_node (t); + FOLD_EXPR_PACK (r) = pack; + return r; + } if (TREE_VEC_LENGTH (pack) == 0) return expand_empty_fold (t, complain); else @@ -10876,6 +10896,14 @@ tsubst_binary_right_fold (tree t, tree args, tsubst_flags_t complain, if (init == error_mark_node) return error_mark_node; + if (PACK_EXPANSION_P (pack)) + { + tree r = copy_node (t); + FOLD_EXPR_PACK (r) = pack; + FOLD_EXPR_INIT (r) = init; + return r; + } + int n = TREE_VEC_LENGTH (pack); tree vec = make_tree_vec (n + 1); for (int i = 0; i < n; ++i) diff --git a/gcc/testsuite/g++.dg/cpp1z/fold-mangle.C b/gcc/testsuite/g++.dg/cpp1z/fold-mangle.C new file mode 100644 index 0000000..1a8f16c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/fold-mangle.C @@ -0,0 +1,20 @@ +// PR c++/71711 +// { dg-options -std=c++1z } + +template < int > struct A {}; +template < int ... N > void unary_left (A < (... + N) >); +template < int ... N > void unary_right (A < (N + ...) >); +template < int ... N > void binary_left (A < (42 + ... + N) >); +template < int ... N > void binary_right (A < (N + ... + 42) >); + +void bar () +{ + // { dg-final { scan-assembler "_Z10unary_leftIJLi1ELi2ELi3EEEv1AIXflplT_EE" } } + unary_left < 1, 2, 3 > ({}); + // { dg-final { scan-assembler "_Z11unary_rightIJLi1ELi2ELi3EEEv1AIXfrplT_EE" } } + unary_right < 1, 2, 3 > ({}); + // { dg-final { scan-assembler "_Z11binary_leftIJLi1ELi2ELi3EEEv1AIXfLplLi42ET_EE" } } + binary_left < 1, 2, 3 > ({}); + // { dg-final { scan-assembler "_Z12binary_rightIJLi1ELi2ELi3EEEv1AIXfRplT_Li42EEE" } } + binary_right < 1, 2, 3 > ({}); +}
commit bb9c173eedbc3bce2ba4101114a1d36d7fd09ce6 Author: Jason Merrill <ja...@redhat.com> Date: Wed Jul 13 13:08:47 2016 -0400 Update -fabi-version default to 11. * c-opts.c (c_common_post_options): Update -fabi-version default to 11. diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index d945825..c11e7e7 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -887,15 +887,15 @@ c_common_post_options (const char **pfilename) } else if (flag_abi_compat_version == -1) { - /* Generate compatibility aliases for ABI v8 (5.1) by default. */ + /* Generate compatibility aliases for ABI v10 (6.1) by default. */ flag_abi_compat_version - = (flag_abi_version == 0 ? 8 : 0); + = (flag_abi_version == 0 ? 10 : 0); } /* Change flag_abi_version to be the actual current ABI level for the benefit of c_cpp_builtins. */ if (flag_abi_version == 0) - flag_abi_version = 10; + flag_abi_version = 11; if (cxx_dialect >= cxx11) { diff --git a/gcc/testsuite/g++.dg/abi/macro0.C b/gcc/testsuite/g++.dg/abi/macro0.C index 6a695b9..5bc2277 100644 --- a/gcc/testsuite/g++.dg/abi/macro0.C +++ b/gcc/testsuite/g++.dg/abi/macro0.C @@ -1,6 +1,6 @@ // This testcase will need to be kept in sync with c_common_post_options. // { dg-options "-fabi-version=0" } -#if __GXX_ABI_VERSION != 1010 +#if __GXX_ABI_VERSION != 1011 #error "Incorrect value of __GXX_ABI_VERSION" #endif