diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 577740963c9..8059562e581 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,23 @@ 2013-03-29 Jason Merrill + 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 d1777a0ce28..62d6e15ff7b 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 edf46d4c262..521da0054ab 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 45ad20cd9a9..4275b45c1e7 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 2af900ded8b..dd27e6cc2f3 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 08bfa22e0fa..e303ea245b1 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 d36c984d9d5..8ad877ef82b 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 4ef4ede1621..2fc282e9112 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 (AUTO_IS_DECLTYPE (auto_node)) { - 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. */ + 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 8bd76120fc7..63f18d022f9 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 00000000000..bab58a63b90 --- /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 00000000000..5caec52143a --- /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 00000000000..8bc961ebc86 --- /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 00000000000..b593a48cc55 --- /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()); +}