From patchwork Fri Jan 6 21:38:28 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 134704 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id AAE8EB6F70 for ; Sat, 7 Jan 2012 08:39:06 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1326490746; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=hesJ1p3 sLKfz/F80q0mKXEwiJ+k=; b=Sg45jagh1I0OGznebdf5H7nn4teFw3B/Y4WrBGo GguxIJci6NmPuq7aE38pBuFMlyOQZfBOJbfy0CHgu6mPVBPTyurMLrpmQf0602zh XRPPKJhk82EPyLILJ2PcstxhjWjrdz64gUP+ssmgzrz8jEM7hpMuuZcqWljyRTMg DAO4= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=sANw/H5VIIJ4rco+L7RaPCrmYF1FfD6+JQqYDdjLNM5WSNxxrGIEexwRUUt7Nx d4bArLJELiax0H09EO3t/Zy4IN8PUSDWtQgjurT/2AlBB8kVKLqy076UR0YIxwNT kz5XxPSLSSlD4SxZXPvqQN1JCSE3UywgFwgWcMwcvTE/4=; Received: (qmail 17049 invoked by alias); 6 Jan 2012 21:39:00 -0000 Received: (qmail 16648 invoked by uid 22791); 6 Jan 2012 21:38:51 -0000 X-SWARE-Spam-Status: No, hits=-6.6 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_FN, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 06 Jan 2012 21:38:31 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q06LcUCr020643 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 6 Jan 2012 16:38:30 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q06LcUrP022491 for ; Fri, 6 Jan 2012 16:38:30 -0500 Received: from [0.0.0.0] (ovpn-113-110.phx2.redhat.com [10.3.113.110]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id q06LcSoG031798 for ; Fri, 6 Jan 2012 16:38:29 -0500 Message-ID: <4F0769D4.2070802@redhat.com> Date: Fri, 06 Jan 2012 16:38:28 -0500 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:8.0) Gecko/20111112 Thunderbird/8.0 MIME-Version: 1.0 To: gcc-patches List Subject: C++/libiberty PATCH for many mangling fixes (6057, 48051, 50855, 51322 and more) Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch fixes several mangling issues that have been around for a while; several things didn't have a defined mangling until recently, and others have been adjusted subtly. The most notable of these is that the mangling for a C++11 template argument pack has changed, which affects any code that uses variadic templates. For the moment, only the additions are enabled by default; the changes require -fabi-version=6 or =0. Other changes since -fabi-version=2 have been fairly limited in scope, not affecting very much code. But this is a big change, that will require recompilation of pretty much any C++11 code when it happens. The question is, should it happen now, or wait until a later flag day when we make other changes as well? We have said that we make no guarantees about backward compatibility in C++0x mode, but we still need to decide whether to break it incrementally (so that future breakage will be less, and to improve compatibility with other compilers) or all at once later on? Tested x86_64-pc-linux-gnu, applying to trunk. commit c712790430099b450bbdcdbda237121893b7b3d2 Author: Jason Merrill Date: Fri Jan 6 09:35:14 2012 -0500 * error.c (dump_expr): Print type of CONSTRUCTOR. diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 21d6781..62b47ca 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -2194,6 +2194,8 @@ dump_expr (tree t, int flags) } else { + if (!BRACE_ENCLOSED_INITIALIZER_P (t)) + dump_type (TREE_TYPE (t), 0); pp_cxx_left_brace (cxx_pp); dump_expr_init_vec (CONSTRUCTOR_ELTS (t), flags); pp_cxx_right_brace (cxx_pp); diff --git a/gcc/testsuite/g++.dg/cpp0x/error7.C b/gcc/testsuite/g++.dg/cpp0x/error7.C new file mode 100644 index 0000000..0dfbf9f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/error7.C @@ -0,0 +1,10 @@ +// Test for printing the type of T{} in error messages. +// { dg-options -std=c++0x } + +template struct A { }; +template A f(T t); // { dg-message "T{}" } + +int main() +{ + f(); // { dg-error "no match" } +} commit 5bebdf16393c8f6ca7b9b2f2cd741919ac25d952 Author: Jason Merrill Date: Fri Jan 6 09:39:03 2012 -0500 * mangle.c (mangle_decl): Don't generate mangling aliases for maybe-in-charge [cd]tors. diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 548998a..e5c2895 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -3194,7 +3194,10 @@ mangle_decl (const tree decl) tree id = get_mangled_id (decl); SET_DECL_ASSEMBLER_NAME (decl, id); - if (G.need_abi_warning) + if (G.need_abi_warning + /* Don't do this for a fake symbol we aren't going to emit anyway. */ + && !DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl) + && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)) { #ifdef ASM_OUTPUT_DEF /* If the mangling will change in the future, emit an alias with the commit c427dcbe4bedd0f17df7054d17412960e0cba40c Author: Jason Merrill Date: Fri Jan 6 09:44:05 2012 -0500 * cp-demangle.c (cplus_demangle_type): decltype, pack expansion and vector are substitutable. (cplus_demangle_operators): Sort. diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 0f1166b..0ed8397 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -1554,7 +1554,8 @@ d_identifier (struct d_info *di, int len) /* operator_name ::= many different two character encodings. ::= cv ::= v -*/ + + This list is sorted for binary search. */ #define NL(s) s, (sizeof s) - 1 @@ -1566,6 +1567,8 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "aa", NL ("&&"), 2 }, { "ad", NL ("&"), 1 }, { "an", NL ("&"), 2 }, + { "at", NL ("alignof "), 1 }, + { "az", NL ("alignof "), 1 }, { "cl", NL ("()"), 2 }, { "cm", NL (","), 2 }, { "co", NL ("~"), 1 }, @@ -1611,8 +1614,6 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "rs", NL (">>"), 2 }, { "st", NL ("sizeof "), 1 }, { "sz", NL ("sizeof "), 1 }, - { "at", NL ("alignof "), 1 }, - { "az", NL ("alignof "), 1 }, { NULL, NULL, 0, 0 } }; @@ -2242,12 +2243,14 @@ cplus_demangle_type (struct d_info *di) d_expression (di), NULL); if (ret && d_next_char (di) != 'E') ret = NULL; + can_subst = 1; break; case 'p': /* Pack expansion. */ ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION, cplus_demangle_type (di), NULL); + can_subst = 1; break; case 'f': @@ -2298,6 +2301,7 @@ cplus_demangle_type (struct d_info *di) case 'v': ret = d_vector_type (di); + can_subst = 1; break; case 'n': diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index 70abf68..642fe14 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -4018,6 +4018,18 @@ K<1, &S::m>::f() --format=gnu-v3 _ZSt10_ConstructI10CellBorderIS0_EEvPT_DpOT0_ _ZSt10_ConstructI10CellBorderIS0_EEvPT_DpOT0_ +# A pack expansion is substitutable. +--format=gnu-v3 +_Z1fIJiEiEv1AIJDpT_EET0_S4_ +void f(A, int, int) +# So is decltype. +--format=gnu-v3 +_Z1fIiiEDTcvT__EET0_S2_ +decltype ((int)()) f(int, int) +# And vector. +--format=gnu-v3 +_Z1fDv4_iS_ +f(int __vector(4), int __vector(4)) # # Ada (GNAT) tests. # commit f4d29990c578120c19277e4a55e574ad5d384591 Author: Jason Merrill Date: Fri Jan 6 11:13:01 2012 -0500 PR c++/6057 PR c++/48051 PR c++/50855 PR c++/51322 gcc/cp/ * mangle.c (write_expression): Support NEW_EXPR, DELETE_EXPR, THROW_EXPR, CONSTRUCTOR, OVERLOAD. Fix PREINCREMENT_EXPR and PREDECREMENT_EXPR. (write_template_arg): Fix mangling of class-scope functions and argument packs. (mangle_decl): Update suggested -fabi-version argument. * operators.def: Add DOTSTAR_EXPR, REINTERPRET_CAST_EXPR, DYNAMIC_CAST_EXPR; correct CONST_CAST_EXPR, STATIC_CAST_EXPR. * tree.c (dependent_name): No longer static. * cp-tree.h: Declare it. * pt.c (unify): Defer handling of unconverted functions. include/ * demangle.h (enum demangle_component_type): Add DEMANGLE_COMPONENT_INITIALIZER_LIST, DEMANGLE_COMPONENT_NULLARY. libiberty/ * cp-demangle.c (d_dump): Handle DEMANGLE_COMPONENT_NULLARY and DEMANGLE_COMPONENT_INITIALIZER_LIST. (d_make_comp): Likewise. Allow null right arg for DEMANGLE_COMPONENT_TRINARY_ARG2. (cplus_demangle_operators): Adjust new/delete; add .*, :: and throw. (d_template_args, d_template_arg): Handle 'J' for argument packs. (d_exprlist): Add terminator parm. (d_expression, d_print_comp): Handle initializer lists, nullary expressions, prefix/suffix operators, and new. (d_print_subexpr): Avoid parens around DEMANGLE_COMPONENT_QUAL_NAME and DEMANGLE_COMPONENT_INITIALIZER_LIST. * testsuite/demangle-expected: Add tests. diff --git a/gcc/common.opt b/gcc/common.opt index 6cfe17a..0544478 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -782,7 +782,10 @@ Driver Undocumented ; function parameters used in other parameters and the return type. ; First selectable in G++ 4.6. ; -; 6: The version of the ABI that doesn't promote scoped enums to int. +; 6: The version of the ABI that doesn't promote scoped enums to int and +; changes the mangling of template argument packs, const/static_cast, +; prefix ++ and --, and a class scope function used as a template +; argument. ; First selectable in G++ 4.7. ; ; Additional positive integers will be assigned as new versions of diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6e62bd1..ccad644 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5674,6 +5674,7 @@ extern tree hash_tree_cons (tree, tree, tree); extern tree hash_tree_chain (tree, tree); extern tree build_qualified_name (tree, tree, tree, bool); extern int is_overloaded_fn (tree); +extern tree dependent_name (tree); extern tree get_fns (tree); extern tree get_first_fn (tree); extern tree ovl_cons (tree, tree); diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index e5c2895..f4efa67 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2646,6 +2646,102 @@ write_expression (tree expr) write_expression (TREE_OPERAND (expr, 0)); write_expression (TREE_OPERAND (expr, 2)); } + else if (code == NEW_EXPR || code == VEC_NEW_EXPR) + { + /* ::= [gs] nw * _ E + ::= [gs] nw * _ + ::= [gs] na * _ E + ::= [gs] na * _ + ::= pi * E */ + tree placement = TREE_OPERAND (expr, 0); + tree type = TREE_OPERAND (expr, 1); + tree nelts = TREE_OPERAND (expr, 2); + tree init = TREE_OPERAND (expr, 3); + tree t; + + gcc_assert (code == NEW_EXPR); + if (TREE_OPERAND (expr, 2)) + code = VEC_NEW_EXPR; + + if (NEW_EXPR_USE_GLOBAL (expr)) + write_string ("gs"); + + write_string (operator_name_info[(int) code].mangled_name); + + for (t = placement; t; t = TREE_CHAIN (t)) + write_expression (TREE_VALUE (t)); + + write_char ('_'); + + if (nelts) + { + tree domain; + ++processing_template_decl; + domain = compute_array_index_type (NULL_TREE, nelts, + tf_warning_or_error); + type = build_cplus_array_type (type, domain); + --processing_template_decl; + } + write_type (type); + + if (init && TREE_CODE (init) == TREE_LIST + && TREE_CODE (TREE_VALUE (init)) == CONSTRUCTOR + && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init))) + write_expression (TREE_VALUE (init)); + else + { + if (init) + write_string ("pi"); + if (init && init != void_zero_node) + for (t = init; t; t = TREE_CHAIN (t)) + write_expression (TREE_VALUE (t)); + write_char ('E'); + } + } + else if (code == DELETE_EXPR || code == VEC_DELETE_EXPR) + { + gcc_assert (code == DELETE_EXPR); + if (DELETE_EXPR_USE_VEC (expr)) + code = VEC_DELETE_EXPR; + + if (DELETE_EXPR_USE_GLOBAL (expr)) + write_string ("gs"); + + write_string (operator_name_info[(int) code].mangled_name); + + write_expression (TREE_OPERAND (expr, 0)); + } + else if (code == THROW_EXPR) + { + tree op = TREE_OPERAND (expr, 0); + if (op) + { + write_string ("tw"); + write_expression (op); + } + else + write_string ("tr"); + } + else if (code == CONSTRUCTOR) + { + VEC(constructor_elt,gc)* elts = CONSTRUCTOR_ELTS (expr); + unsigned i; tree val; + + if (BRACE_ENCLOSED_INITIALIZER_P (expr)) + write_string ("il"); + else + { + write_string ("tl"); + write_type (TREE_TYPE (expr)); + } + FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val) + write_expression (val); + write_char ('E'); + } + else if (dependent_name (expr)) + { + write_unqualified_id (dependent_name (expr)); + } else { int i, len; @@ -2688,6 +2784,16 @@ write_expression (tree expr) /* If it wasn't any of those, recursively expand the expression. */ name = operator_name_info[(int) code].mangled_name; + + /* We used to mangle const_cast and static_cast like a C cast. */ + if (!abi_version_at_least (6) + && (code == CONST_CAST_EXPR + || code == STATIC_CAST_EXPR)) + { + name = operator_name_info[CAST_EXPR].mangled_name; + G.need_abi_warning = 1; + } + if (name == NULL) { sorry ("mangling %C", code); @@ -2734,16 +2840,21 @@ write_expression (tree expr) } break; - /* FIXME these should have a distinct mangling. */ + case DYNAMIC_CAST_EXPR: + case REINTERPRET_CAST_EXPR: case STATIC_CAST_EXPR: case CONST_CAST_EXPR: write_type (TREE_TYPE (expr)); write_expression (TREE_OPERAND (expr, 0)); break; - case NEW_EXPR: - sorry ("mangling new-expression"); - break; + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + if (abi_version_at_least (6)) + write_char ('_'); + else + G.need_abi_warning = 1; + /* Fall through. */ default: /* In the middle-end, some expressions have more operands than @@ -2855,12 +2966,28 @@ write_template_arg (tree node) G.need_abi_warning = 1; } + if (TREE_CODE (node) == BASELINK + && !type_unknown_p (node)) + { + if (abi_version_at_least (6)) + node = BASELINK_FUNCTIONS (node); + else + /* We wrongly wrapped a class-scope function in X/E. */ + G.need_abi_warning = 1; + } + if (ARGUMENT_PACK_P (node)) { /* Expand the template argument pack. */ tree args = ARGUMENT_PACK_ARGS (node); int i, length = TREE_VEC_LENGTH (args); - write_char ('I'); + if (abi_version_at_least (6)) + write_char ('J'); + else + { + write_char ('I'); + G.need_abi_warning = 1; + } for (i = 0; i < length; ++i) write_template_arg (TREE_VEC_ELT (args, i)); write_char ('E'); @@ -3208,8 +3335,8 @@ mangle_decl (const tree decl) SET_IDENTIFIER_GLOBAL_VALUE (id, decl); if (IDENTIFIER_GLOBAL_VALUE (id) != decl) - inform (DECL_SOURCE_LOCATION (decl), "-fabi-version=4 (or =0) " - "avoids this error with a change in vector mangling"); + inform (DECL_SOURCE_LOCATION (decl), "-fabi-version=6 (or =0) " + "avoids this error with a change in mangling"); #ifdef ASM_OUTPUT_DEF save_ver = flag_abi_version; diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def index 20d811b..3dc7404 100644 --- a/gcc/cp/operators.def +++ b/gcc/cp/operators.def @@ -101,8 +101,10 @@ DEF_SIMPLE_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", 1) /* The cast operator. */ DEF_SIMPLE_OPERATOR ("", TYPE_EXPR, "cv", 1) DEF_SIMPLE_OPERATOR ("", CAST_EXPR, "cv", 1) -DEF_SIMPLE_OPERATOR ("", CONST_CAST_EXPR, "cv", 1) -DEF_SIMPLE_OPERATOR ("", STATIC_CAST_EXPR, "cv", 1) +DEF_SIMPLE_OPERATOR ("dynamic_cast", DYNAMIC_CAST_EXPR, "dc", 1) +DEF_SIMPLE_OPERATOR ("reinterpret_cast", REINTERPRET_CAST_EXPR, "rc", 1) +DEF_SIMPLE_OPERATOR ("const_cast", CONST_CAST_EXPR, "cc", 1) +DEF_SIMPLE_OPERATOR ("static_cast", STATIC_CAST_EXPR, "sc", 1) /* Binary operators. */ DEF_SIMPLE_OPERATOR ("+", PLUS_EXPR, "pl", 2) @@ -125,6 +127,7 @@ DEF_SIMPLE_OPERATOR ("&&", TRUTH_ANDIF_EXPR, "aa", 2) DEF_SIMPLE_OPERATOR ("||", TRUTH_ORIF_EXPR, "oo", 2) DEF_SIMPLE_OPERATOR (",", COMPOUND_EXPR, "cm", 2) DEF_SIMPLE_OPERATOR ("->*", MEMBER_REF, "pm", 2) +DEF_SIMPLE_OPERATOR (".*", DOTSTAR_EXPR, "ds", 2) DEF_SIMPLE_OPERATOR ("->", COMPONENT_REF, "pt", 2) DEF_SIMPLE_OPERATOR ("[]", ARRAY_REF, "ix", 2) DEF_SIMPLE_OPERATOR ("++", POSTINCREMENT_EXPR, "pp", 2) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 77e3388..bc3dd97 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -16885,7 +16885,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, default: /* An unresolved overload is a nondeduced context. */ - if (type_unknown_p (parm)) + if (is_overloaded_fn (parm) || type_unknown_p (parm)) return unify_success (explain_p); gcc_assert (EXPR_P (parm)); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index dea7632..8ef3e25 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1457,7 +1457,7 @@ is_overloaded_fn (tree x) (14.6.2), return the IDENTIFIER_NODE for that name. Otherwise, return NULL_TREE. */ -static tree +tree dependent_name (tree x) { if (TREE_CODE (x) == IDENTIFIER_NODE) diff --git a/gcc/testsuite/g++.dg/abi/mangle51.C b/gcc/testsuite/g++.dg/abi/mangle51.C new file mode 100644 index 0000000..4992f1a --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle51.C @@ -0,0 +1,27 @@ +// { dg-options "-std=c++0x -fabi-version=0" } + +void* operator new (__SIZE_TYPE__, void *p) { return p; } +int i; + +template struct helper {}; +// { dg-final { scan-assembler "_Z6check1IiEvP6helperIXsznw_T_EEE" } } +template void check1( helper * ) { } +// { dg-final { scan-assembler "_Z6check2IiEvP6helperIXszgsnw_T_piEEE" } } +template void check2( helper * ) { } +// { dg-final { scan-assembler "_Z6check3IiEvP6helperIXsznwadL_Z1iE_T_piLi1EEEE" } } +template void check3( helper * ) { } +// { dg-final { scan-assembler "_Z7check3aIiEvP6helperIXsznw_T_ilLi1EEEE" } } +template void check3a( helper * ) { } +// { dg-final { scan-assembler "_Z6check4IiEvP6helperIXszna_A1_T_EEE" } } +template void check4( helper * ) { } +// { dg-final { scan-assembler "_Z6check5IiEvP6helperIXszna_A1_T_piEEE" } } +template void check5( helper * ) { } +int main() +{ + check1(0); + check2(0); + check3(0); + check3a(0); + check4(0); + check5(0); +} diff --git a/gcc/testsuite/g++.dg/abi/mangle52.C b/gcc/testsuite/g++.dg/abi/mangle52.C new file mode 100644 index 0000000..2c46341 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle52.C @@ -0,0 +1,21 @@ +// { dg-options "-fabi-version=0" } + +template struct helper {}; +// { dg-final { scan-assembler "_Z6check1IiEvP6helperIXszscT_Li1EEE" } } +template void check1( helper(1))> * ) { } +// { dg-final { scan-assembler "_Z6check2IiXadL_Z1iEEEvP6helperIXszccPT_T0_EE" } } +template void check2( helper(p))> * ) { } +// { dg-final { scan-assembler "_Z6check3IiEvP6helperIXszrcPT_Li0EEE" } } +template void check3( helper(0))> * ) { } +// { dg-final { scan-assembler "_Z6check4I1AXadL_Z1aEEEvP6helperIXszdcPT_T0_EE" } } +template void check4( helper(p))> * ) { } + +struct A{} a; +int i; +int main() +{ + check1(0); + check2(0); + check3(0); + check4(0); +} diff --git a/gcc/testsuite/g++.dg/abi/mangle53.C b/gcc/testsuite/g++.dg/abi/mangle53.C new file mode 100644 index 0000000..b279182 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle53.C @@ -0,0 +1,13 @@ +// { dg-options "-std=c++0x" } + +bool b; +// { dg-final { scan-assembler "_Z1fIiEDTquL_Z1bEfp_twLi42EET_" } } +template auto f (T t) -> decltype(b?t:throw 42) { return 0; } +// { dg-final { scan-assembler "_Z2f2IiEDTquL_Z1bEfp_trET_" } } +template auto f2 (T t) -> decltype(b?t:throw) { return 0; } + +int main() +{ + f(0); + f2(0); +} diff --git a/gcc/testsuite/g++.dg/abi/mangle54.C b/gcc/testsuite/g++.dg/abi/mangle54.C new file mode 100644 index 0000000..ea98df1 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle54.C @@ -0,0 +1,19 @@ +// { dg-options "-std=c++0x -fabi-version=0" } + +int i; +// { dg-final { scan-assembler "_Z2f1IiEDTppfp_ET_" } } +template auto f1 (T t) -> decltype(t++) { return i; } +// { dg-final { scan-assembler "_Z2f2IiEDTpp_fp_ET_" } } +template auto f2 (T t) -> decltype(++t) { return i; } +// { dg-final { scan-assembler "_Z2f3IiEDTmmfp_ET_" } } +template auto f3 (T t) -> decltype(t--) { return i; } +// { dg-final { scan-assembler "_Z2f4IiEDTmm_fp_ET_" } } +template auto f4 (T t) -> decltype(--t) { return i; } + +int main() +{ + f1(0); + f2(0); + f3(0); + f4(0); +} diff --git a/gcc/testsuite/g++.dg/abi/mangle55.C b/gcc/testsuite/g++.dg/abi/mangle55.C new file mode 100644 index 0000000..72caadc --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle55.C @@ -0,0 +1,14 @@ +// { dg-options "-std=c++0x" } + +struct A { int i; }; +// { dg-final { scan-assembler "_Z2f1Ii1AEDTdsfp_fp0_ET0_MS2_T_" } } +template auto f1 (U u, T U::* p) -> decltype(u.*p) { return u.*p; } +// { dg-final { scan-assembler "_Z2f2Ii1AEDTpmfp_fp0_EPT0_MS2_T_" } } +template auto f2 (U* u, T U::* p) -> decltype(u->*p) { return u->*p; } + +int main() +{ + A a = {}; + f1(a, &A::i); + f2(&a, &A::i); +} diff --git a/gcc/testsuite/g++.dg/abi/mangle56.C b/gcc/testsuite/g++.dg/abi/mangle56.C new file mode 100644 index 0000000..0fd2701 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle56.C @@ -0,0 +1,13 @@ +// { dg-options "-std=c++0x" } + +template T g(T t1, T t2) { return t2; } +// { dg-final { scan-assembler "_Z2f1IiEDTcl1gfp_ilEEET_" } } +template auto f1 (T t) -> decltype(g(t,{})) { return g(t,{}); } +// { dg-final { scan-assembler "_Z2f2IiEDTcl1gfp_tlT_EEES0_" } } +template auto f2 (T t) -> decltype(g(t,T{})) { return g(t,T{}); } + +int main() +{ + f1(0); + f2(0); +} diff --git a/gcc/testsuite/g++.dg/abi/mangle57.C b/gcc/testsuite/g++.dg/abi/mangle57.C new file mode 100644 index 0000000..3d9d81e --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle57.C @@ -0,0 +1,16 @@ +// { dg-options "-std=c++0x -fabi-version=0" } + +template int cmp1(T a, T b); +int cmp2(char a, char b); +template struct A { }; +// { dg-final { scan-assembler "_Z1fIcEvR1AIT_X4cmp1EE" } } +template void f (A &); +// { dg-final { scan-assembler "_Z1fIcEvR1AIT_L_Z4cmp2ccEE" } } +template void f (A &); +void g() +{ + A a; + f(a); + A a2; + f(a2); +} diff --git a/gcc/testsuite/g++.dg/abi/mangle58.C b/gcc/testsuite/g++.dg/abi/mangle58.C new file mode 100644 index 0000000..14e5543 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle58.C @@ -0,0 +1,19 @@ +// { dg-options "-std=c++0x -fabi-version=0" } + +template struct A { }; +struct B { + template static int cmp1(T a, T b); + static int cmp2(char a, char b); + // { dg-final { scan-assembler "_ZN1B1fIcEEvR1AIT_X4cmp1EE" } } + template static void f (A &); + // { dg-final { scan-assembler "_ZN1B1fIcEEvR1AIT_L_ZNS_4cmp2EccEE" } } + template static void f (A &); +}; + +void g() +{ + A a; + B::f(a); + A a2; + B::f(a2); +} diff --git a/gcc/testsuite/g++.dg/abi/mangle59.C b/gcc/testsuite/g++.dg/abi/mangle59.C new file mode 100644 index 0000000..3c88ec8 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle59.C @@ -0,0 +1,19 @@ +// { dg-options "-std=c++0x -fabi-version=0" } + +// { dg-final { scan-assembler "_Z1fIiEDTcmdlfp_psfp_EPT_" } } +template auto f (T* p) -> decltype(delete p, +p) { return p; } +// { dg-final { scan-assembler "_Z1gIiEDTcmgsdlfp_psfp_EPT_" } } +template auto g (T* p) -> decltype(::delete p, +p) { return p; } +// { dg-final { scan-assembler "_Z1hIiEDTcmdafp_psfp_EPT_" } } +template auto h (T* p) -> decltype(delete[] p, +p) { return p; } +// { dg-final { scan-assembler "_Z1iIiEDTcmgsdafp_psfp_EPT_" } } +template auto i (T* p) -> decltype(::delete[] p, +p) { return p; } + +int main() +{ + int x; + f(&x); + g(&x); + h(&x); + i(&x); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing3.C b/gcc/testsuite/g++.dg/cpp0x/trailing3.C index 82d36f0..1c64f45 100644 --- a/gcc/testsuite/g++.dg/cpp0x/trailing3.C +++ b/gcc/testsuite/g++.dg/cpp0x/trailing3.C @@ -1,5 +1,5 @@ // More auto/decltype mangling tests. -// { dg-options "-std=c++0x" } +// { dg-options "-std=c++0x -fabi-version=0" } template struct B @@ -58,6 +58,6 @@ int main() A().h(1); // { dg-final { scan-assembler "_ZN1AIiE1jIiEEDTplfp_clL_Z1xvEEET_" } } A().j(1); - // { dg-final { scan-assembler "_Z1gIIidEEDTcl1fspplfp_Li1EEEDpT_" } } + // { dg-final { scan-assembler "_Z1gIJidEEDTcl1fspplfp_Li1EEEDpT_" } } g(42, 1.0); } diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic111.C b/gcc/testsuite/g++.dg/cpp0x/variadic111.C index 378162e..cb94ce6 100644 --- a/gcc/testsuite/g++.dg/cpp0x/variadic111.C +++ b/gcc/testsuite/g++.dg/cpp0x/variadic111.C @@ -1,5 +1,5 @@ // PR c++/48424 -// { dg-options -std=c++0x } +// { dg-options "-std=c++0x -fabi-version=0" } template struct S @@ -16,4 +16,4 @@ int main() s.f(1,2.0,false,'a'); } -// { dg-final { scan-assembler "_ZN1SIIidEE1fIIbcEEEvidDpOT_" } } +// { dg-final { scan-assembler "_ZN1SIJidEE1fIJbcEEEvidDpOT_" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic4.C b/gcc/testsuite/g++.dg/cpp0x/variadic4.C index 9257a92..1bdad32 100644 --- a/gcc/testsuite/g++.dg/cpp0x/variadic4.C +++ b/gcc/testsuite/g++.dg/cpp0x/variadic4.C @@ -1,4 +1,4 @@ -// { dg-options "-std=gnu++0x" } +// { dg-options "-std=gnu++0x -fabi-version=0" } // { dg-do compile } template class tuple {}; @@ -9,7 +9,7 @@ void f_two(tuple) {} void f_nested(tuple, float>) { } -// { dg-final { scan-assembler "_Z6f_none5tupleIIEE" } } -// { dg-final { scan-assembler "_Z5f_one5tupleIIiEE" } } -// { dg-final { scan-assembler "_Z5f_two5tupleIIifEE" } } -// { dg-final { scan-assembler "_Z8f_nested5tupleIIiS_IIdcEEfEE" } } +// { dg-final { scan-assembler "_Z6f_none5tupleIJEE" } } +// { dg-final { scan-assembler "_Z5f_one5tupleIJiEE" } } +// { dg-final { scan-assembler "_Z5f_two5tupleIJifEE" } } +// { dg-final { scan-assembler "_Z8f_nested5tupleIJiS_IJdcEEfEE" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic42.C b/gcc/testsuite/g++.dg/cpp0x/variadic42.C index 47d9b66..3ec68e8 100644 --- a/gcc/testsuite/g++.dg/cpp0x/variadic42.C +++ b/gcc/testsuite/g++.dg/cpp0x/variadic42.C @@ -1,4 +1,4 @@ -// { dg-options "-std=gnu++0x" } +// { dg-options "-std=gnu++0x -fabi-version=5" } // { dg-do compile } template void f(Args...) { } diff --git a/gcc/testsuite/g++.dg/template/nontype22.C b/gcc/testsuite/g++.dg/template/nontype22.C index f2c8c46..44d8479 100644 --- a/gcc/testsuite/g++.dg/template/nontype22.C +++ b/gcc/testsuite/g++.dg/template/nontype22.C @@ -3,7 +3,7 @@ template int cmp1(T a, T b); template struct A { }; -template void f (A &); // { dg-bogus "" "" { xfail *-*-* } } +template void f (A &); void g() { A a; diff --git a/gcc/testsuite/g++.dg/template/pr35240.C b/gcc/testsuite/g++.dg/template/pr35240.C index 88e2505..5b94551 100644 --- a/gcc/testsuite/g++.dg/template/pr35240.C +++ b/gcc/testsuite/g++.dg/template/pr35240.C @@ -1,12 +1,11 @@ // PR c++/35240 // { dg-do compile } - template struct A {}; -template A foo(); // { dg-message "unimplemented" } +template A foo(); void bar() { - foo<1>(); // { dg-message "required" } + foo<1>(); } diff --git a/include/demangle.h b/include/demangle.h index 98b11d7..34b3ed3 100644 --- a/include/demangle.h +++ b/include/demangle.h @@ -344,6 +344,9 @@ enum demangle_component_type template argument, and the right subtree is either NULL or another TEMPLATE_ARGLIST node. */ DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, + /* An initializer list. The left subtree is either an explicit type or + NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST. */ + DEMANGLE_COMPONENT_INITIALIZER_LIST, /* An operator. This holds information about a standard operator. */ DEMANGLE_COMPONENT_OPERATOR, @@ -353,6 +356,8 @@ enum demangle_component_type /* A typecast, represented as a unary operator. The one subtree is the type to which the argument should be cast. */ DEMANGLE_COMPONENT_CAST, + /* A nullary expression. The left subtree is the operator. */ + DEMANGLE_COMPONENT_NULLARY, /* A unary expression. The left subtree is the operator, and the right subtree is the single argument. */ DEMANGLE_COMPONENT_UNARY, diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 0ed8397..2dfd67c 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -648,9 +648,15 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: printf ("template argument list\n"); break; + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + printf ("initializer list\n"); + break; case DEMANGLE_COMPONENT_CAST: printf ("cast\n"); break; + case DEMANGLE_COMPONENT_NULLARY: + printf ("nullary operator\n"); + break; case DEMANGLE_COMPONENT_UNARY: printf ("unary operator\n"); break; @@ -806,7 +812,6 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_BINARY_ARGS: case DEMANGLE_COMPONENT_TRINARY: case DEMANGLE_COMPONENT_TRINARY_ARG1: - case DEMANGLE_COMPONENT_TRINARY_ARG2: case DEMANGLE_COMPONENT_LITERAL: case DEMANGLE_COMPONENT_LITERAL_NEG: case DEMANGLE_COMPONENT_COMPOUND_NAME: @@ -843,6 +848,8 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_PACK_EXPANSION: case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + case DEMANGLE_COMPONENT_NULLARY: + case DEMANGLE_COMPONENT_TRINARY_ARG2: if (left == NULL) return NULL; break; @@ -850,6 +857,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, /* This needs a right parameter, but the left parameter can be empty. */ case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_INITIALIZER_LIST: if (right == NULL) return NULL; break; @@ -1573,15 +1581,17 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "cm", NL (","), 2 }, { "co", NL ("~"), 1 }, { "dV", NL ("/="), 2 }, - { "da", NL ("delete[]"), 1 }, + { "da", NL ("delete[] "), 1 }, { "de", NL ("*"), 1 }, - { "dl", NL ("delete"), 1 }, + { "dl", NL ("delete "), 1 }, + { "ds", NL (".*"), 2 }, { "dt", NL ("."), 2 }, { "dv", NL ("/"), 2 }, { "eO", NL ("^="), 2 }, { "eo", NL ("^"), 2 }, { "eq", NL ("=="), 2 }, { "ge", NL (">="), 2 }, + { "gs", NL ("::"), 1 }, { "gt", NL (">"), 2 }, { "ix", NL ("[]"), 2 }, { "lS", NL ("<<="), 2 }, @@ -1593,11 +1603,11 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "mi", NL ("-"), 2 }, { "ml", NL ("*"), 2 }, { "mm", NL ("--"), 1 }, - { "na", NL ("new[]"), 1 }, + { "na", NL ("new[]"), 3 }, { "ne", NL ("!="), 2 }, { "ng", NL ("-"), 1 }, { "nt", NL ("!"), 1 }, - { "nw", NL ("new"), 1 }, + { "nw", NL ("new"), 3 }, { "oR", NL ("|="), 2 }, { "oo", NL ("||"), 2 }, { "or", NL ("|"), 2 }, @@ -1614,6 +1624,8 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "rs", NL (">>"), 2 }, { "st", NL ("sizeof "), 1 }, { "sz", NL ("sizeof "), 1 }, + { "tr", NL ("throw"), 0 }, + { "tw", NL ("throw "), 1 }, { NULL, NULL, 0, 0 } }; @@ -2679,8 +2691,10 @@ d_template_args (struct d_info *di) constructor or destructor. */ hold_last_name = di->last_name; - if (! d_check_char (di, 'I')) + if (d_peek_char (di) != 'I' + && d_peek_char (di) != 'J') return NULL; + d_advance (di, 1); if (d_peek_char (di) == 'E') { @@ -2739,6 +2753,7 @@ d_template_arg (struct d_info *di) return d_expr_primary (di); case 'I': + case 'J': /* An argument pack. */ return d_template_args (di); @@ -2747,15 +2762,16 @@ d_template_arg (struct d_info *di) } } -/* Subroutine of ::= cl + E */ +/* Parse a sequence of expressions until we hit the terminator + character. */ static struct demangle_component * -d_exprlist (struct d_info *di) +d_exprlist (struct d_info *di, char terminator) { struct demangle_component *list = NULL; struct demangle_component **p = &list; - if (d_peek_char (di) == 'E') + if (d_peek_char (di) == terminator) { d_advance (di, 1); return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL); @@ -2772,7 +2788,7 @@ d_exprlist (struct d_info *di) return NULL; p = &d_right (*p); - if (d_peek_char (di) == 'E') + if (d_peek_char (di) == terminator) { d_advance (di, 1); break; @@ -2863,9 +2879,21 @@ d_expression (struct d_info *di) else return name; } + else if ((peek == 'i' || peek == 't') + && d_peek_next_char (di) == 'l') + { + /* Brace-enclosed initializer list, untyped or typed. */ + struct demangle_component *type = NULL; + if (peek == 't') + type = cplus_demangle_type (di); + d_advance (di, 2); + return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST, + type, d_exprlist (di, 'E')); + } else { struct demangle_component *op; + const char *code = NULL; int args; op = d_operator_name (di); @@ -2873,12 +2901,13 @@ d_expression (struct d_info *di) return NULL; if (op->type == DEMANGLE_COMPONENT_OPERATOR) - di->expansion += op->u.s_operator.op->len - 2; - - if (op->type == DEMANGLE_COMPONENT_OPERATOR - && strcmp (op->u.s_operator.op->code, "st") == 0) - return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, - cplus_demangle_type (di)); + { + code = op->u.s_operator.op->code; + di->expansion += op->u.s_operator.op->len - 2; + if (strcmp (code, "st") == 0) + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + cplus_demangle_type (di)); + } switch (op->type) { @@ -2897,26 +2926,43 @@ d_expression (struct d_info *di) switch (args) { + case 0: + return d_make_comp (di, DEMANGLE_COMPONENT_NULLARY, op, NULL); + case 1: { struct demangle_component *operand; + int suffix = 0; + + if (code && (code[0] == 'p' || code[0] == 'm') + && code[1] == code[0]) + /* pp_ and mm_ are the prefix variants. */ + suffix = !d_check_char (di, '_'); + if (op->type == DEMANGLE_COMPONENT_CAST && d_check_char (di, '_')) - operand = d_exprlist (di); + operand = d_exprlist (di, 'E'); else operand = d_expression (di); - return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, - operand); + + if (suffix) + /* Indicate the suffix variant for d_print_comp. */ + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + d_make_comp (di, + DEMANGLE_COMPONENT_BINARY_ARGS, + operand, operand)); + else + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + operand); } case 2: { struct demangle_component *left; struct demangle_component *right; - const char *code = op->u.s_operator.op->code; left = d_expression (di); if (!strcmp (code, "cl")) - right = d_exprlist (di); + right = d_exprlist (di, 'E'); else if (!strcmp (code, "dt") || !strcmp (code, "pt")) { right = d_unqualified_name (di); @@ -2936,17 +2982,50 @@ d_expression (struct d_info *di) { struct demangle_component *first; struct demangle_component *second; + struct demangle_component *third; - first = d_expression (di); - second = d_expression (di); + if (!strcmp (code, "qu")) + { + /* ?: expression. */ + first = d_expression (di); + second = d_expression (di); + third = d_expression (di); + } + else if (code[0] == 'n') + { + /* new-expression. */ + if (code[1] != 'w' && code[1] != 'a') + return NULL; + first = d_exprlist (di, '_'); + second = cplus_demangle_type (di); + if (d_peek_char (di) == 'E') + { + d_advance (di, 1); + third = NULL; + } + else if (d_peek_char (di) == 'p' + && d_peek_next_char (di) == 'i') + { + /* Parenthesized initializer. */ + d_advance (di, 2); + third = d_exprlist (di, 'E'); + } + else if (d_peek_char (di) == 'i' + && d_peek_next_char (di) == 'l') + /* initializer-list. */ + third = d_expression (di); + else + return NULL; + } + else + return NULL; return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op, d_make_comp (di, DEMANGLE_COMPONENT_TRINARY_ARG1, first, d_make_comp (di, DEMANGLE_COMPONENT_TRINARY_ARG2, - second, - d_expression (di)))); + second, third))); } default: return NULL; @@ -3666,6 +3745,8 @@ d_print_subexpr (struct d_print_info *dpi, int options, { int simple = 0; if (dc->type == DEMANGLE_COMPONENT_NAME + || dc->type == DEMANGLE_COMPONENT_QUAL_NAME + || dc->type == DEMANGLE_COMPONENT_INITIALIZER_LIST || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM) simple = 1; if (!simple) @@ -4261,6 +4342,19 @@ d_print_comp (struct d_print_info *dpi, int options, } return; + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + { + struct demangle_component *type = d_left (dc); + struct demangle_component *list = d_right (dc); + + if (type) + d_print_comp (dpi, options, type); + d_append_char (dpi, '{'); + d_print_comp (dpi, options, list); + d_append_char (dpi, '}'); + } + return; + case DEMANGLE_COMPONENT_OPERATOR: { char c; @@ -4284,55 +4378,59 @@ d_print_comp (struct d_print_info *dpi, int options, d_print_cast (dpi, options, dc); return; + case DEMANGLE_COMPONENT_NULLARY: + d_print_expr_op (dpi, options, d_left (dc)); + return; + case DEMANGLE_COMPONENT_UNARY: - if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR - && d_left (dc)->u.s_operator.op->len == 1 - && d_left (dc)->u.s_operator.op->name[0] == '&' - && d_right (dc)->type == DEMANGLE_COMPONENT_TYPED_NAME - && d_left (d_right (dc))->type == DEMANGLE_COMPONENT_QUAL_NAME - && d_right (d_right (dc))->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) - { - /* Address of a function (therefore in an expression context) must - have its argument list suppressed. - - unary operator ... dc - operator & ... d_left (dc) - typed name ... d_right (dc) - qualified name ... d_left (d_right (dc)) - - function type ... d_right (d_right (dc)) - argument list - */ - - d_print_expr_op (dpi, options, d_left (dc)); - d_print_comp (dpi, options, d_left (d_right (dc))); - return; - } - else if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR - && d_left (dc)->u.s_operator.op->len == 1 - && d_left (dc)->u.s_operator.op->name[0] == '&' - && d_right (dc)->type == DEMANGLE_COMPONENT_QUAL_NAME) - { - /* Keep also already processed variant without the argument list. + { + struct demangle_component *op = d_left (dc); + struct demangle_component *operand = d_right (dc); + const char *code = NULL; - unary operator ... dc - operator & ... d_left (dc) - qualified name ... d_right (dc) - */ + if (op->type == DEMANGLE_COMPONENT_OPERATOR) + { + code = op->u.s_operator.op->code; + if (!strcmp (code, "ad")) + { + /* Don't print the argument list for the address of a + function. */ + if (operand->type == DEMANGLE_COMPONENT_TYPED_NAME + && d_left (operand)->type == DEMANGLE_COMPONENT_QUAL_NAME + && d_right (operand)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) + operand = d_left (operand); + } + if (operand->type == DEMANGLE_COMPONENT_BINARY_ARGS) + { + /* This indicates a suffix operator. */ + operand = d_left (operand); + d_print_subexpr (dpi, options, operand); + d_print_expr_op (dpi, options, op); + return; + } + } - d_print_expr_op (dpi, options, d_left (dc)); - d_print_comp (dpi, options, d_right (dc)); - return; - } - else if (d_left (dc)->type != DEMANGLE_COMPONENT_CAST) - d_print_expr_op (dpi, options, d_left (dc)); - else - { - d_append_char (dpi, '('); - d_print_cast (dpi, options, d_left (dc)); - d_append_char (dpi, ')'); - } - d_print_subexpr (dpi, options, d_right (dc)); + if (op->type != DEMANGLE_COMPONENT_CAST) + d_print_expr_op (dpi, options, op); + else + { + d_append_char (dpi, '('); + d_print_cast (dpi, options, op); + d_append_char (dpi, ')'); + } + if (code && !strcmp (code, "gs")) + /* Avoid parens after '::'. */ + d_print_comp (dpi, options, operand); + else if (code && !strcmp (code, "st")) + /* Always print parens for sizeof (type). */ + { + d_append_char (dpi, '('); + d_print_comp (dpi, options, operand); + d_append_char (dpi, ')'); + } + else + d_print_subexpr (dpi, options, operand); + } return; case DEMANGLE_COMPONENT_BINARY: @@ -4397,11 +4495,33 @@ d_print_comp (struct d_print_info *dpi, int options, d_print_error (dpi); return; } - d_print_subexpr (dpi, options, d_left (d_right (dc))); - d_print_expr_op (dpi, options, d_left (dc)); - d_print_subexpr (dpi, options, d_left (d_right (d_right (dc)))); - d_append_string (dpi, " : "); - d_print_subexpr (dpi, options, d_right (d_right (d_right (dc)))); + { + struct demangle_component *op = d_left (dc); + struct demangle_component *first = d_left (d_right (dc)); + struct demangle_component *second = d_left (d_right (d_right (dc))); + struct demangle_component *third = d_right (d_right (d_right (dc))); + + if (!strcmp (op->u.s_operator.op->code, "qu")) + { + d_print_subexpr (dpi, options, first); + d_print_expr_op (dpi, options, op); + d_print_subexpr (dpi, options, second); + d_append_string (dpi, " : "); + d_print_subexpr (dpi, options, third); + } + else + { + d_append_string (dpi, "new "); + if (d_left (first) != NULL) + { + d_print_subexpr (dpi, options, first); + d_append_char (dpi, ' '); + } + d_print_comp (dpi, options, second); + if (third) + d_print_subexpr (dpi, options, third); + } + } return; case DEMANGLE_COMPONENT_TRINARY_ARG1: diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index 642fe14..3f3960a 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -3935,7 +3935,7 @@ _Z1tIlEDTplcvT_Li5EclL_Z1qsELi6EEEv decltype (((long)(5))+(q(6))) t() # test for expansion of function parameter pack --format=gnu-v3 -_Z1gIIidEEDTclL_Z1fEspplfp_Li1EEEDpT_ +_Z1gIJidEEDTclL_Z1fEspplfp_Li1EEEDpT_ decltype (f(({parm#1}+(1))...)) g(int, double) # lambda tests --format=gnu-v3 @@ -4030,6 +4030,45 @@ decltype ((int)()) f(int, int) --format=gnu-v3 _Z1fDv4_iS_ f(int __vector(4), int __vector(4)) +--format=gnu-v3 +_Z2f1Ii1AEDTdsfp_fp0_ET0_MS2_T_ +decltype ({parm#1}.*{parm#2}) f1(A, int A::*) +--format=gnu-v3 +_Z2f2IiEDTquL_Z1bEfp_trET_ +decltype (b?{parm#1} : (throw)) f2(int) +--format=gnu-v3 +_Z6check1IiEvP6helperIXsznw_T_EEE +void check1(helper*) +--format=gnu-v3 +_Z6check2IiEvP6helperIXszgsnw_T_piEEE +void check2(helper*) +--format=gnu-v3 +_Z6check3IiEvP6helperIXsznwadL_Z1iE_T_piLi1EEEE +void check3(helper*) +--format=gnu-v3 +_Z6check4IiEvP6helperIXszna_A1_T_EEE +void check4(helper*) +--format=gnu-v3 +_Z6check5IiEvP6helperIXszna_A1_T_piEEE +void check5(helper*) +--format=gnu-v3 +_Z1fIiEDTcmgsdlfp_psfp_EPT_ +decltype ((::delete {parm#1}),(+{parm#1})) f(int*) +--format=gnu-v3 +_Z1fIiEDTcmdafp_psfp_EPT_ +decltype ((delete[] {parm#1}),(+{parm#1})) f(int*) +--format=gnu-v3 +_Z2f1IiEDTppfp_ET_ +decltype ({parm#1}++) f1(int) +--format=gnu-v3 +_Z2f1IiEDTpp_fp_ET_ +decltype (++{parm#1}) f1(int) +--format=gnu-v3 +_Z2f1IiEDTcl1gfp_ilEEET_ +decltype (g({parm#1}, {})) f1(int) +--format=gnu-v3 +_Z2f1IiEDTnw_T_ilEES0_ +decltype (new int{}) f1(int) # # Ada (GNAT) tests. # diff --git a/libstdc++-v3/testsuite/abi/demangle/regression/cw-16.cc b/libstdc++-v3/testsuite/abi/demangle/regression/cw-16.cc index 49d44bc..12fa6fe 100644 --- a/libstdc++-v3/testsuite/abi/demangle/regression/cw-16.cc +++ b/libstdc++-v3/testsuite/abi/demangle/regression/cw-16.cc @@ -39,7 +39,7 @@ verify_demangle("_Z1fPFYPFiiEiE", verify_demangle("_Z1fI1XENT_1tES2_", "X::t f(X::t)"); verify_demangle("_Z1fILi5E1AEvN1CIXstN1T1tEEXszsrS2_1tEE1qE", - "void f<5, A>(C::q)"); + "void f<5, A>(C::q)"); // 2003/12/03, libstdc++/13045 verify_demangle("_Z1fILi1ELc120EEv1AIXplT_cviLd4028ae147ae147aeEEE", "void f<1, (char)120>(A<(1)+((int)((double)[4028ae147ae147ae]))>)");