From patchwork Fri Mar 29 19:51:13 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 232488 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]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 243952C00BC for ; Sat, 30 Mar 2013 06:52:08 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; q= dns; s=default; b=NdeWeW5rW1NbwQ+XD7XXzH9NtMzoXyyDi2Xb6deHZzP4KN hBnj8z3IV2i1PXIcU0xZ6fN/5qt3U90D2Q/Ns+OerGkAIIutitpw6k2afzlmbz9K 3hmmThGzUZvADS7M1uF54eC1EohanqzXtKXHA0HMqEseiIQv/K2yR/E5DDiT4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; s= default; bh=SU1q51oQ9czLKssXkUtePzfuNII=; b=k2h3yjK0TLIkTZUAcRD9 1z36XtM1+ML8y5DMqkxVhIVs/0HQoElHVvhdUZWxZXypeu9ukxWntI34L/iuzlXx Y0Nwn5uCmA1h74BdIOuKAEM98LQXIPgvF/JSJUkuR+LgW1ipg5sG0I6z3lze/bsH y+PPJExq9yASesqrk9oE5qc= Received: (qmail 22792 invoked by alias); 29 Mar 2013 19:51:54 -0000 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 Received: (qmail 22759 invoked by uid 89); 29 Mar 2013 19:51:46 -0000 X-Spam-SWARE-Status: No, score=-7.0 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, RP_MATCHES_RCVD, SPF_HELO_PASS, TW_CX, TW_TM autolearn=ham version=3.3.1 Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Fri, 29 Mar 2013 19:51:16 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r2TJpENh008684 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 29 Mar 2013 15:51:15 -0400 Received: from [10.3.113.94] (ovpn-113-94.phx2.redhat.com [10.3.113.94]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r2TJpDeQ023241 for ; Fri, 29 Mar 2013 15:51:14 -0400 Message-ID: <5155F0B1.7050003@redhat.com> Date: Fri, 29 Mar 2013 15:51:13 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:21.0) Gecko/20100101 Thunderbird/21.0a2 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH to implement N3582 changes to proposed C++14 return type deduction X-Virus-Found: No I've updated my proposal for return type deduction for normal functions in C++14 for the upcoming Bristol meeting: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3582.html and this patch implements the changes in the new proposal relative to the previous revision. I started trying to change the parsing of initializers and return expressions in order to implement decltype(auto), but that got rather hairy, particularly for initializers, so I ended up going a different way: determining whether an expression is an identifier or member reference based on the trees rather than directly in the parser. To make that work, I needed to make sure that a parenthesized expression, or a folded ?: expression, could be distinguished from a simpler expression; to that end, I've adopted PAREN_EXPR from the middle end. Tested x86_64-pc-linux-gnu, applying to trunk. commit 81070bed26366c95a3115b902c333bd32a1c9df8 Author: Jason Merrill Date: Fri Mar 22 21:31:38 2013 -0400 N3582 * cp-tree.h (AUTO_IS_DECLTYPE): New. * parser.c (cp_parser_decltype): Handle decltype(auto). (cp_parser_type_id_1): Allow auto without a late-specified return in C++1y. (cp_parser_primary_expression): Use the return value of finish_parenthesized_expr. (cp_parser_transaction_expression): Likewise. * semantics.c (force_paren_expr): New. (finish_parenthesized_expr): Use it. * call.c (build_conditional_expr_1): Likewise. * pt.c (do_auto_deduction): Handle decltype(auto). (tsubst_copy): Handle PAREN_EXPR. (tsubst_copy_and_build): Likewise. * error.c (dump_expr): Handle PAREN_EXPR. * cxx-pretty-print.c (pp_cxx_expression): Likewise. * mangle.c (write_expression): Ignore PAREN_EXPR. * parser.c (cp_parser_decltype_expr): Split out... (cp_parser_decltype): ...from here. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index d1777a0..62d6e15 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4845,6 +4845,8 @@ build_conditional_expr_1 (tree arg1, tree arg2, tree arg3, lvalue, we must add a NON_LVALUE_EXPR. */ result = rvalue (result); } + else + result = force_paren_expr (result); return result; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index edf46d4..521da00 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -121,6 +121,7 @@ c-common.h, not after. 4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR 5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE) ENUM_FIXED_UNDERLYING_TYPE_P (in ENUMERAL_TYPE) + AUTO_IS_DECLTYPE (in TEMPLATE_TYPE_PARM) 6: TYPE_DEPENDENT_P_VALID Usage of DECL_LANG_FLAG_?: @@ -4604,6 +4605,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; #define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \ (TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE))) +/* True iff this TEMPLATE_TYPE_PARM represents decltype(auto). */ +#define AUTO_IS_DECLTYPE(NODE) \ + (TYPE_LANG_FLAG_5 (TEMPLATE_TYPE_PARM_CHECK (NODE))) + /* These constants can used as bit flags in the process of tree formatting. TFF_PLAIN_IDENTIFIER: unqualified part of a name. @@ -5659,6 +5664,7 @@ extern tree finish_asm_stmt (int, tree, tree, tree, tree, extern tree finish_label_stmt (tree); extern void finish_label_decl (tree); extern tree finish_parenthesized_expr (tree); +extern tree force_paren_expr (tree); extern tree finish_non_static_data_member (tree, tree, tree); extern tree begin_stmt_expr (void); extern tree finish_stmt_expr_expr (tree, tree); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 45ad20c..4275b45 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -1167,6 +1167,12 @@ pp_cxx_expression (cxx_pretty_printer *pp, tree t) pp_cxx_ws_string (pp, ""); break; + case PAREN_EXPR: + pp_cxx_left_paren (pp); + pp_cxx_expression (pp, TREE_OPERAND (t, 0)); + pp_cxx_right_paren (pp); + break; + default: pp_c_expression (pp_c_base (pp), t); break; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 2af900d..dd27e6c 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -2506,6 +2506,12 @@ dump_expr (tree t, int flags) pp_string (cxx_pp, M_("")); break; + case PAREN_EXPR: + pp_cxx_left_paren (cxx_pp); + dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS); + pp_cxx_right_paren (cxx_pp); + break; + /* This list is incomplete, but should suffice for now. It is very important that `sorry' does not call `report_error_function'. That could cause an infinite loop. */ diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 08bfa22..e303ea2 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2555,6 +2555,8 @@ write_expression (tree expr) is converted (via qualification conversions) to another type. */ while (TREE_CODE (expr) == NOP_EXPR + /* Parentheses aren't mangled. */ + || code == PAREN_EXPR || TREE_CODE (expr) == NON_LVALUE_EXPR) { expr = TREE_OPERAND (expr, 0); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d36c984..8ad877e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4106,7 +4106,7 @@ cp_parser_primary_expression (cp_parser *parser, example, the expression is of the form `A::B', since `&A::B' might be a pointer-to-member, but `&(A::B)' is not. */ - finish_parenthesized_expr (expr); + expr = finish_parenthesized_expr (expr); /* DR 705: Wrapping an unqualified name in parentheses suppresses arg-dependent lookup. We want to pass back CP_ID_KIND_QUALIFIED for suppressing vtable lookup @@ -11399,7 +11399,9 @@ cp_parser_decltype_expr (cp_parser *parser, /* Parse a `decltype' type. Returns the type. simple-type-specifier: - decltype ( expression ) */ + decltype ( expression ) + C++14 proposal: + decltype ( auto ) */ static tree cp_parser_decltype (cp_parser *parser) @@ -11427,6 +11429,18 @@ cp_parser_decltype (cp_parser *parser) if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return error_mark_node; + /* decltype (auto) */ + if (cxx_dialect >= cxx1y + && cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO)) + { + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + return error_mark_node; + expr = make_auto (); + AUTO_IS_DECLTYPE (expr) = true; + goto rewrite; + } + /* Types cannot be defined in a `decltype' expression. Save away the old message. */ saved_message = parser->type_definition_forbidden_message; @@ -11485,6 +11499,7 @@ cp_parser_decltype (cp_parser *parser) expr = finish_decltype_type (expr, id_expression_or_member_access_p, tf_warning_or_error); + rewrite: /* Replace the decltype with a CPP_DECLTYPE so we don't need to parse it again. */ start_token->type = CPP_DECLTYPE; @@ -17207,6 +17222,7 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg, abstract_declarator = NULL; if (type_specifier_seq.type + && cxx_dialect < cxx1y && type_uses_auto (type_specifier_seq.type)) { /* A type-id with type 'auto' is only ok if the abstract declarator @@ -28003,7 +28019,7 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword) cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); - finish_parenthesized_expr (expr); + expr = finish_parenthesized_expr (expr); cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4ef4ede..2fc282e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12303,6 +12303,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) case TYPEID_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: + case PAREN_EXPR: return build1 (code, tsubst (TREE_TYPE (t), args, complain, in_decl), tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl)); @@ -14549,6 +14550,9 @@ tsubst_copy_and_build (tree t, RETURN (tsubst_expr(t, args, complain, in_decl, integral_constant_expression_p)); + case PAREN_EXPR: + RETURN (finish_parenthesized_expr (RECUR (TREE_OPERAND (t, 0)))); + default: /* Handle Objective-C++ constructs, if appropriate. */ { @@ -20593,9 +20597,7 @@ listify_autos (tree type, tree auto_node) tree do_auto_deduction (tree type, tree init, tree auto_node) { - tree parms, tparms, targs; - tree args[1]; - int val; + tree targs; if (init == error_mark_node) return error_mark_node; @@ -20614,32 +20616,42 @@ do_auto_deduction (tree type, tree init, tree auto_node) init = resolve_nondeduced_context (init); - parms = build_tree_list (NULL_TREE, type); - args[0] = init; - tparms = make_tree_vec (1); targs = make_tree_vec (1); - TREE_VEC_ELT (tparms, 0) - = build_tree_list (NULL_TREE, TYPE_NAME (auto_node)); - val = type_unification_real (tparms, targs, parms, args, 1, 0, - DEDUCE_CALL, LOOKUP_NORMAL, - /*explain_p=*/false); - if (val > 0) - { - if (processing_template_decl) - /* Try again at instantiation time. */ - return type; - if (type && type != error_mark_node) - /* If type is error_mark_node a diagnostic must have been - emitted by now. Also, having a mention to '' - in the diagnostic is not really useful to the user. */ + if (AUTO_IS_DECLTYPE (auto_node)) + { + bool id = (DECL_P (init) || TREE_CODE (init) == COMPONENT_REF); + TREE_VEC_ELT (targs, 0) + = finish_decltype_type (init, id, tf_warning_or_error); + } + else + { + tree parms = build_tree_list (NULL_TREE, type); + tree tparms = make_tree_vec (1); + int val; + + TREE_VEC_ELT (tparms, 0) + = build_tree_list (NULL_TREE, TYPE_NAME (auto_node)); + val = type_unification_real (tparms, targs, parms, &init, 1, 0, + DEDUCE_CALL, LOOKUP_NORMAL, + /*explain_p=*/false); + if (val > 0) { - if (cfun && auto_node == current_function_auto_return_pattern - && LAMBDA_FUNCTION_P (current_function_decl)) - error ("unable to deduce lambda return type from %qE", init); - else - error ("unable to deduce %qT from %qE", type, init); + if (processing_template_decl) + /* Try again at instantiation time. */ + return type; + if (type && type != error_mark_node) + /* If type is error_mark_node a diagnostic must have been + emitted by now. Also, having a mention to '' + in the diagnostic is not really useful to the user. */ + { + if (cfun && auto_node == current_function_auto_return_pattern + && LAMBDA_FUNCTION_P (current_function_decl)) + error ("unable to deduce lambda return type from %qE", init); + else + error ("unable to deduce %qT from %qE", type, init); + } + return error_mark_node; } - return error_mark_node; } /* If the list of declarators contains more than one declarator, the type diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8bd7612..63f18d0 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1507,6 +1507,38 @@ finish_mem_initializers (tree mem_inits) emit_mem_initializers (mem_inits); } +/* Obfuscate EXPR if it looks like an id-expression or member access so + that the call to finish_decltype in do_auto_deduction will give the + right result. */ + +tree +force_paren_expr (tree expr) +{ + /* This is only needed for decltype(auto) in C++14. */ + if (cxx_dialect < cxx1y) + return expr; + + if (!DECL_P (expr) && TREE_CODE (expr) != COMPONENT_REF + && TREE_CODE (expr) != SCOPE_REF) + return expr; + + if (processing_template_decl) + expr = build1 (PAREN_EXPR, TREE_TYPE (expr), expr); + else + { + cp_lvalue_kind kind = lvalue_kind (expr); + if ((kind & ~clk_class) != clk_none) + { + tree type = unlowered_expr_type (expr); + bool rval = !!(kind & clk_rvalueref); + type = cp_build_reference_type (type, rval); + expr = build_static_cast (type, expr, tf_warning_or_error); + } + } + + return expr; +} + /* Finish a parenthesized expression EXPR. */ tree @@ -1525,6 +1557,8 @@ finish_parenthesized_expr (tree expr) if (TREE_CODE (expr) == STRING_CST) PAREN_STRING_LITERAL_P (expr) = 1; + expr = force_paren_expr (expr); + return expr; } diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn15.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn15.C new file mode 100644 index 0000000..bab58a6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn15.C @@ -0,0 +1,50 @@ +// { dg-options "-std=c++1y -Wno-return-local-addr" } + +template struct same_type; +template struct same_type {}; + +int& f(); +int i; + +decltype(auto) g() { return f(); } +decltype(auto) h1() { return i; } +decltype(auto) h2() { return (i); } +decltype(auto) h2a() { return 0,i; } + +struct A { int i; }; +A a; + +decltype(auto) h3() { return a.i; } +decltype(auto) h4() { return (a.i); } + +template +decltype(auto) h5(T t) { return t.i; } +template +decltype(auto) h6(T t) { return (t.i); } + +int main() +{ + decltype(auto) i = f(); + same_type(); + decltype(auto) i2 = i; + same_type(); + decltype(auto) i3 = ::i; + same_type(); + decltype(auto) i4 = (::i); + same_type(); + decltype(auto) i5 = a.i; + same_type(); + decltype(auto) i6 = (a.i); + same_type(); + decltype(auto) i7 = true ? ::i : ::i; + same_type(); + + same_type(); + same_type(); + same_type(); + same_type(); + same_type(); + same_type(); + same_type(); + same_type(); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn16.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn16.C new file mode 100644 index 0000000..5caec52 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn16.C @@ -0,0 +1,12 @@ +// { dg-options -std=c++1y } + +template struct ST; +template struct ST {}; + +int j; +auto x3 = []()->auto&& { return j; }; // OK: return type is int& + +int main() +{ + ST(); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn17.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn17.C new file mode 100644 index 0000000..8bc961e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn17.C @@ -0,0 +1,22 @@ +// { dg-options -std=c++1y } +// { dg-do run } + +int c; +int d; + +struct A +{ + A() { ++c; } + A(const A&) { ++c; } + ~A() { ++d; } +}; + +A g() { return A(); } +decltype(auto) f() { return g(); } + +int main() +{ + f(); + if (c < 1 || c != d) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/mangle1.C b/gcc/testsuite/g++.dg/cpp1y/mangle1.C new file mode 100644 index 0000000..b593a48 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/mangle1.C @@ -0,0 +1,13 @@ +// Test that the parens don't show up in the mangling +// { dg-options "-std=c++1y -Wno-return-local-addr" } +// { dg-final { scan-assembler "_Z1gI1AEDTdtfp_1iET_" } } + +struct A { int i; }; + +template +auto g(T t)->decltype((t.i)) { return t.i; } + +int main() +{ + g(A()); +} commit 280f9803ad351e07d3edddabb83c20c1e7d17b23 Author: Jason Merrill Date: Fri Mar 22 21:17:59 2013 -0400 * parser.c (cp_parser_decltype_expr): Split out... (cp_parser_decltype): ...from here. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 09c5dff..d36c984 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11286,59 +11286,15 @@ cp_parser_static_assert(cp_parser *parser, bool member_p) finish_static_assert (condition, message, saved_loc, member_p); } -/* Parse a `decltype' type. Returns the type. - - simple-type-specifier: - decltype ( expression ) */ +/* Parse the expression in decltype ( expression ). */ static tree -cp_parser_decltype (cp_parser *parser) +cp_parser_decltype_expr (cp_parser *parser, + bool &id_expression_or_member_access_p) { - tree expr; - bool id_expression_or_member_access_p = false; - const char *saved_message; - bool saved_integral_constant_expression_p; - bool saved_non_integral_constant_expression_p; cp_token *id_expr_start_token; - cp_token *start_token = cp_lexer_peek_token (parser->lexer); - - if (start_token->type == CPP_DECLTYPE) - { - /* Already parsed. */ - cp_lexer_consume_token (parser->lexer); - return start_token->u.value; - } - - /* Look for the `decltype' token. */ - if (!cp_parser_require_keyword (parser, RID_DECLTYPE, RT_DECLTYPE)) - return error_mark_node; - - /* Types cannot be defined in a `decltype' expression. Save away the - old message. */ - saved_message = parser->type_definition_forbidden_message; - - /* And create the new one. */ - parser->type_definition_forbidden_message - = G_("types may not be defined in % expressions"); - - /* The restrictions on constant-expressions do not apply inside - decltype expressions. */ - saved_integral_constant_expression_p - = parser->integral_constant_expression_p; - saved_non_integral_constant_expression_p - = parser->non_integral_constant_expression_p; - parser->integral_constant_expression_p = false; - - /* Do not actually evaluate the expression. */ - ++cp_unevaluated_operand; - - /* Do not warn about problems with the expression. */ - ++c_inhibit_evaluation_warnings; + tree expr; - /* Parse the opening `('. */ - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) - return error_mark_node; - /* First, try parsing an id-expression. */ id_expr_start_token = cp_lexer_peek_token (parser->lexer); cp_parser_parse_tentatively (parser); @@ -11428,32 +11384,88 @@ cp_parser_decltype (cp_parser *parser) cp_parser_parse_definitely (parser); else { - bool saved_greater_than_is_operator_p; - /* Abort our attempt to parse an id-expression or member access expression. */ cp_parser_abort_tentative_parse (parser); - /* Within a parenthesized expression, a `>' token is always - the greater-than operator. */ - saved_greater_than_is_operator_p - = parser->greater_than_is_operator_p; - parser->greater_than_is_operator_p = true; - /* Parse a full expression. */ expr = cp_parser_expression (parser, /*cast_p=*/false, /*decltype*/true, NULL); + } + + return expr; +} + +/* Parse a `decltype' type. Returns the type. + + simple-type-specifier: + decltype ( expression ) */ - /* The `>' token might be the end of a template-id or - template-parameter-list now. */ - parser->greater_than_is_operator_p - = saved_greater_than_is_operator_p; +static tree +cp_parser_decltype (cp_parser *parser) +{ + tree expr; + bool id_expression_or_member_access_p = false; + const char *saved_message; + bool saved_integral_constant_expression_p; + bool saved_non_integral_constant_expression_p; + bool saved_greater_than_is_operator_p; + cp_token *start_token = cp_lexer_peek_token (parser->lexer); + + if (start_token->type == CPP_DECLTYPE) + { + /* Already parsed. */ + cp_lexer_consume_token (parser->lexer); + return start_token->u.value; } + /* Look for the `decltype' token. */ + if (!cp_parser_require_keyword (parser, RID_DECLTYPE, RT_DECLTYPE)) + return error_mark_node; + + /* Parse the opening `('. */ + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return error_mark_node; + + /* Types cannot be defined in a `decltype' expression. Save away the + old message. */ + saved_message = parser->type_definition_forbidden_message; + + /* And create the new one. */ + parser->type_definition_forbidden_message + = G_("types may not be defined in % expressions"); + + /* The restrictions on constant-expressions do not apply inside + decltype expressions. */ + saved_integral_constant_expression_p + = parser->integral_constant_expression_p; + saved_non_integral_constant_expression_p + = parser->non_integral_constant_expression_p; + parser->integral_constant_expression_p = false; + + /* Within a parenthesized expression, a `>' token is always + the greater-than operator. */ + saved_greater_than_is_operator_p + = parser->greater_than_is_operator_p; + parser->greater_than_is_operator_p = true; + + /* Do not actually evaluate the expression. */ + ++cp_unevaluated_operand; + + /* Do not warn about problems with the expression. */ + ++c_inhibit_evaluation_warnings; + + expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p); + /* Go back to evaluating expressions. */ --cp_unevaluated_operand; --c_inhibit_evaluation_warnings; + /* The `>' token might be the end of a template-id or + template-parameter-list now. */ + parser->greater_than_is_operator_p + = saved_greater_than_is_operator_p; + /* Restore the old message and the integral constant expression flags. */ parser->type_definition_forbidden_message = saved_message;