From 86359a653cbb9f4042735a8e42a1fbdbb7bf59f4 Mon Sep 17 00:00:00 2001 From: jason Date: Sat, 24 Mar 2012 20:56:08 +0000 Subject: [PATCH] Implement return type deduction for normal functions with -std=c++1y. * cp-tree.h (FNDECL_USED_AUTO): New macro. (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P): Remove. (dependent_lambda_return_type_node): Remove. (CPTI_DEPENDENT_LAMBDA_RETURN_TYPE): Remove. (struct language_function): Add x_auto_return_pattern field. (current_function_auto_return_pattern): New. (enum tsubst_flags): Add tf_partial. * decl.c (decls_match): Handle auto return comparison. (duplicate_decls): Adjust error message for auto return. (cxx_init_decl_processing): Remove dependent_lambda_return_type_node. (cp_finish_decl): Don't do auto deduction for functions. (grokdeclarator): Allow auto return without trailing return type in C++1y mode. (check_function_type): Defer checking of deduced return type. (start_preparsed_function): Set current_function_auto_return_pattern. (finish_function): Set deduced return type to void if not previously deduced. * decl2.c (change_return_type): Handle error_mark_node. (mark_used): Always instantiate functions with deduced return type. Complain about use if deduction isn't done. * parser.c (cp_parser_lambda_declarator_opt): Use 'auto' for initial return type. (cp_parser_lambda_body): Don't deduce return type in a template. (cp_parser_conversion_type_id): Allow auto in C++1y. * pt.c (instantiate_class_template_1): Don't mess with LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P. (tsubst_copy_and_build): Likewise. (fn_type_unification, tsubst): Don't reduce the template parm level of 'auto' during deduction. (unify): Compare 'auto' specially. (get_bindings): Change test. (always_instantiate_p): Always instantiate functions with deduced return type. (do_auto_deduction): Handle error_mark_node and lambda context. Don't check for use in initializer. (contains_auto_r): Remove. * search.c (lookup_conversions_r): Handle auto conversion function. * semantics.c (lambda_return_type): Handle null return. Don't mess with dependent_lambda_return_type_node. (apply_deduced_return_type): Rename from apply_lambda_return_type. * typeck.c (merge_types): Handle auto. (check_return_expr): Do auto deduction. * typeck2.c (add_exception_specifier): Fix complain check. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@185768 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 47 +++++++++++++++ gcc/cp/cp-tree.h | 26 +++++--- gcc/cp/decl.c | 64 ++++++++++++++++---- gcc/cp/decl2.c | 19 +++++- gcc/cp/parser.c | 21 ++++--- gcc/cp/pt.c | 78 ++++++++++-------------- gcc/cp/search.c | 5 ++ gcc/cp/semantics.c | 40 +++++++------ gcc/cp/typeck.c | 95 +++++++++++++++++------------- gcc/cp/typeck2.c | 3 +- gcc/testsuite/ChangeLog | 17 ++++++ gcc/testsuite/g++.dg/cpp0x/auto18.C | 2 +- gcc/testsuite/g++.dg/cpp0x/auto3.C | 4 +- gcc/testsuite/g++.dg/cpp0x/trailing2.C | 2 +- gcc/testsuite/g++.dg/cpp1y/auto-fn1.C | 5 ++ gcc/testsuite/g++.dg/cpp1y/auto-fn10.C | 16 +++++ gcc/testsuite/g++.dg/cpp1y/auto-fn11.C | 5 ++ gcc/testsuite/g++.dg/cpp1y/auto-fn12.C | 14 +++++ gcc/testsuite/g++.dg/cpp1y/auto-fn13.C | 6 ++ gcc/testsuite/g++.dg/cpp1y/auto-fn2.C | 3 + gcc/testsuite/g++.dg/cpp1y/auto-fn3.C | 10 ++++ gcc/testsuite/g++.dg/cpp1y/auto-fn4.C | 7 +++ gcc/testsuite/g++.dg/cpp1y/auto-fn5.C | 11 ++++ gcc/testsuite/g++.dg/cpp1y/auto-fn6.C | 18 ++++++ gcc/testsuite/g++.dg/cpp1y/auto-fn7.C | 5 ++ gcc/testsuite/g++.dg/cpp1y/auto-fn8.C | 13 ++++ gcc/testsuite/g++.dg/cpp1y/auto-fn9.C | 11 ++++ gcc/testsuite/g++.dg/gomp/pr38639.C | 2 +- gcc/testsuite/g++.dg/warn/pr23075.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/spec22.C | 2 +- 30 files changed, 405 insertions(+), 148 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn1.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn10.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn11.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn12.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn13.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn2.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn3.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn4.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn5.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn6.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn7.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn8.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn9.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0fc0bd8..9cd2711 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,50 @@ +2012-03-21 Jason Merrill + + Implement return type deduction for normal functions with -std=c++1y. + * cp-tree.h (FNDECL_USED_AUTO): New macro. + (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P): Remove. + (dependent_lambda_return_type_node): Remove. + (CPTI_DEPENDENT_LAMBDA_RETURN_TYPE): Remove. + (struct language_function): Add x_auto_return_pattern field. + (current_function_auto_return_pattern): New. + (enum tsubst_flags): Add tf_partial. + * decl.c (decls_match): Handle auto return comparison. + (duplicate_decls): Adjust error message for auto return. + (cxx_init_decl_processing): Remove dependent_lambda_return_type_node. + (cp_finish_decl): Don't do auto deduction for functions. + (grokdeclarator): Allow auto return without trailing return type in + C++1y mode. + (check_function_type): Defer checking of deduced return type. + (start_preparsed_function): Set current_function_auto_return_pattern. + (finish_function): Set deduced return type to void if not previously + deduced. + * decl2.c (change_return_type): Handle error_mark_node. + (mark_used): Always instantiate functions with deduced return type. + Complain about use if deduction isn't done. + * parser.c (cp_parser_lambda_declarator_opt): Use 'auto' for + initial return type. + (cp_parser_lambda_body): Don't deduce return type in a template. + (cp_parser_conversion_type_id): Allow auto in C++1y. + * pt.c (instantiate_class_template_1): Don't mess with + LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P. + (tsubst_copy_and_build): Likewise. + (fn_type_unification, tsubst): Don't reduce the template parm level + of 'auto' during deduction. + (unify): Compare 'auto' specially. + (get_bindings): Change test. + (always_instantiate_p): Always instantiate functions with deduced + return type. + (do_auto_deduction): Handle error_mark_node and lambda context. + Don't check for use in initializer. + (contains_auto_r): Remove. + * search.c (lookup_conversions_r): Handle auto conversion function. + * semantics.c (lambda_return_type): Handle null return. Don't mess + with dependent_lambda_return_type_node. + (apply_deduced_return_type): Rename from apply_lambda_return_type. + * typeck.c (merge_types): Handle auto. + (check_return_expr): Do auto deduction. + * typeck2.c (add_exception_specifier): Fix complain check. + 2012-03-22 Paolo Carlini PR c++/52487 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fc60d86..7d986a8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -96,8 +96,8 @@ c-common.h, not after. DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST) TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE) - LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR) TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR) + FNDECL_USED_AUTO (in FUNCTION_DECL) 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -660,11 +660,6 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_MUTABLE_P(NODE) \ TREE_LANG_FLAG_1 (LAMBDA_EXPR_CHECK (NODE)) -/* True iff we should try to deduce the lambda return type from any return - statement. */ -#define LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P(NODE) \ - TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE)) - /* The return type in the expression. * NULL_TREE indicates that none was specified. */ #define LAMBDA_EXPR_RETURN_TYPE(NODE) \ @@ -804,7 +799,6 @@ enum cp_tree_index CPTI_CLASS_TYPE, CPTI_UNKNOWN_TYPE, CPTI_INIT_LIST_TYPE, - CPTI_DEPENDENT_LAMBDA_RETURN_TYPE, CPTI_VTBL_TYPE, CPTI_VTBL_PTR_TYPE, CPTI_STD, @@ -876,7 +870,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define class_type_node cp_global_trees[CPTI_CLASS_TYPE] #define unknown_type_node cp_global_trees[CPTI_UNKNOWN_TYPE] #define init_list_type_node cp_global_trees[CPTI_INIT_LIST_TYPE] -#define dependent_lambda_return_type_node cp_global_trees[CPTI_DEPENDENT_LAMBDA_RETURN_TYPE] #define vtbl_type_node cp_global_trees[CPTI_VTBL_TYPE] #define vtbl_ptr_type_node cp_global_trees[CPTI_VTBL_PTR_TYPE] #define std_node cp_global_trees[CPTI_STD] @@ -1076,6 +1069,7 @@ struct GTY(()) language_function { tree x_in_charge_parm; tree x_vtt_parm; tree x_return_value; + tree x_auto_return_pattern; BOOL_BITFIELD returns_value : 1; BOOL_BITFIELD returns_null : 1; @@ -1158,6 +1152,11 @@ struct GTY(()) language_function { #define current_function_return_value \ (cp_function_chain->x_return_value) +/* A type involving 'auto' to be used for return type deduction. */ + +#define current_function_auto_return_pattern \ + (cp_function_chain->x_auto_return_pattern) + /* True if NAME is the IDENTIFIER_NODE for an overloaded "operator new" or "operator delete". */ #define NEW_DELETE_OPNAME_P(NAME) \ @@ -3085,6 +3084,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECL_LOCAL_FUNCTION_P(NODE) \ DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE)) +/* True if NODE was declared with auto in its return type, but it has + started compilation and so the return type might have been changed by + return type deduction; its declared return type should be found in + DECL_STRUCT_FUNCTION(NODE)->language->x_auto_return_pattern. */ +#define FNDECL_USED_AUTO(NODE) \ + TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (NODE)) + /* Nonzero if NODE is a DECL which we know about but which has not been explicitly declared, such as a built-in function or a friend declared inside a class. In the latter case DECL_HIDDEN_FRIEND_P @@ -4144,6 +4150,8 @@ enum tsubst_flags { conversion. */ tf_no_access_control = 1 << 7, /* Do not perform access checks, even when issuing other errors. */ + tf_partial = 1 << 8, /* Doing initial explicit argument + substitution in fn_type_unification. */ /* Convenient substitution flags combinations. */ tf_warning_or_error = tf_warning | tf_error }; @@ -5619,7 +5627,7 @@ extern tree lambda_capture_field_type (tree); extern tree lambda_return_type (tree); extern tree lambda_proxy_type (tree); extern tree lambda_function (tree); -extern void apply_lambda_return_type (tree, tree); +extern void apply_deduced_return_type (tree, tree); extern tree add_capture (tree, tree, tree, bool, bool); extern tree add_default_capture (tree, tree, tree); extern tree build_capture_proxy (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e664d43..f021edf 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -960,6 +960,7 @@ decls_match (tree newdecl, tree olddecl) tree f2 = TREE_TYPE (olddecl); tree p1 = TYPE_ARG_TYPES (f1); tree p2 = TYPE_ARG_TYPES (f2); + tree r2; /* Specializations of different templates are different functions even if they have the same type. */ @@ -988,7 +989,14 @@ decls_match (tree newdecl, tree olddecl) if (TREE_CODE (f1) != TREE_CODE (f2)) return 0; - if (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2))) + /* A declaration with deduced return type should use its pre-deduction + type for declaration matching. */ + if (FNDECL_USED_AUTO (olddecl)) + r2 = DECL_STRUCT_FUNCTION (olddecl)->language->x_auto_return_pattern; + else + r2 = TREE_TYPE (f2); + + if (same_type_p (TREE_TYPE (f1), r2)) { if (!prototype_p (f2) && DECL_EXTERN_C_P (olddecl) && (DECL_BUILT_IN (olddecl) @@ -1486,7 +1494,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) TYPE_ARG_TYPES (TREE_TYPE (olddecl)))) { error ("new declaration %q#D", newdecl); - error ("ambiguates old declaration %q+#D", olddecl); + if (FNDECL_USED_AUTO (olddecl)) + error_at (DECL_SOURCE_LOCATION (olddecl), "ambiguates old " + "declaration with deduced return type"); + else + error ("ambiguates old declaration %q+#D", olddecl); return error_mark_node; } else @@ -3644,10 +3656,6 @@ cxx_init_decl_processing (void) init_list_type_node = make_node (LANG_TYPE); record_unknown_type (init_list_type_node, "init list"); - dependent_lambda_return_type_node = make_node (LANG_TYPE); - record_unknown_type (dependent_lambda_return_type_node, - "undeduced lambda return type"); - { /* Make sure we get a unique function type, so we can give its pointer type a name. (This wins for gdb.) */ @@ -6008,8 +6016,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, && (DECL_INITIAL (decl) || init)) DECL_INITIALIZED_IN_CLASS_P (decl) = 1; - auto_node = type_uses_auto (type); - if (auto_node) + if (TREE_CODE (decl) != FUNCTION_DECL + && (auto_node = type_uses_auto (type))) { tree d_init; if (init == NULL_TREE) @@ -9188,9 +9196,13 @@ grokdeclarator (const cp_declarator *declarator, { if (!declarator->u.function.late_return_type) { - error ("%qs function uses % type specifier without" - " trailing return type", name); - return error_mark_node; + if (current_class_type + && LAMBDA_TYPE_P (current_class_type)) + /* OK for C++11 lambdas. */; + else if (cxx_dialect < cxx1y) + pedwarn (input_location, 0, "%qs function uses " + "% type specifier without trailing " + "return type", name); } else if (!is_auto (type)) { @@ -10029,7 +10041,8 @@ grokdeclarator (const cp_declarator *declarator, } else if (decl_context == FIELD) { - if (!staticp && type_uses_auto (type)) + if (!staticp && TREE_CODE (type) != METHOD_TYPE + && type_uses_auto (type)) { error ("non-static data member declared %"); type = error_mark_node; @@ -12570,7 +12583,8 @@ check_function_type (tree decl, tree current_function_parms) /* In a function definition, arg types must be complete. */ require_complete_types_for_parms (current_function_parms); - if (dependent_type_p (return_type)) + if (dependent_type_p (return_type) + || type_uses_auto (return_type)) return; if (!COMPLETE_OR_VOID_TYPE_P (return_type) || (TYPE_FOR_JAVA (return_type) && MAYBE_CLASS_TYPE_P (return_type))) @@ -12741,6 +12755,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) /* Build the return declaration for the function. */ restype = TREE_TYPE (fntype); + if (DECL_RESULT (decl1) == NULL_TREE) { tree resdecl; @@ -12849,6 +12864,12 @@ start_preparsed_function (tree decl1, tree attrs, int flags) current_stmt_tree ()->stmts_are_full_exprs_p = 1; current_binding_level = bl; + if (!processing_template_decl && type_uses_auto (restype)) + { + FNDECL_USED_AUTO (decl1) = true; + current_function_auto_return_pattern = restype; + } + /* Start the statement-tree, start the tree now. */ DECL_SAVED_TREE (decl1) = push_stmt_list (); @@ -13463,6 +13484,23 @@ finish_function (int flags) of curly braces for a function. */ gcc_assert (stmts_are_full_exprs_p ()); + /* If there are no return statements in a function with auto return type, + the return type is void. But if the declared type is something like + auto*, this is an error. */ + if (!processing_template_decl && FNDECL_USED_AUTO (fndecl) + && TREE_TYPE (fntype) == current_function_auto_return_pattern) + { + if (!is_auto (current_function_auto_return_pattern) + && !current_function_returns_value && !current_function_returns_null) + { + error ("no return statements in function returning %qT", + current_function_auto_return_pattern); + inform (input_location, "only plain % return type can be " + "deduced to %"); + } + apply_deduced_return_type (fndecl, void_type_node); + } + /* Save constexpr function body before it gets munged by the NRV transformation. */ maybe_save_function_definition (fndecl); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 7eccf67..b048ac7 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -151,6 +151,9 @@ change_return_type (tree new_ret, tree fntype) tree raises = TYPE_RAISES_EXCEPTIONS (fntype); tree attrs = TYPE_ATTRIBUTES (fntype); + if (new_ret == error_mark_node) + return fntype; + if (same_type_p (new_ret, TREE_TYPE (fntype))) return fntype; @@ -4281,7 +4284,11 @@ mark_used (tree decl) if ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) || DECL_LANG_SPECIFIC (decl) == NULL || DECL_THUNK_P (decl)) - return true; + { + if (!processing_template_decl && type_uses_auto (TREE_TYPE (decl))) + error ("use of %qD before deduction of %", decl); + return true; + } /* We only want to do this processing once. We don't need to keep trying to instantiate inline templates, because unit-at-a-time will make sure @@ -4303,10 +4310,13 @@ mark_used (tree decl) /* Normally, we can wait until instantiation-time to synthesize DECL. However, if DECL is a static data member initialized with a constant or a constexpr function, we need it right now because a reference to - such a data member or a call to such function is not value-dependent. */ + such a data member or a call to such function is not value-dependent. + For a function that uses auto in the return type, we need to instantiate + it to find out its type. */ if ((decl_maybe_constant_var_p (decl) || (TREE_CODE (decl) == FUNCTION_DECL - && DECL_DECLARED_CONSTEXPR_P (decl))) + && (DECL_DECLARED_CONSTEXPR_P (decl) + || type_uses_auto (TREE_TYPE (TREE_TYPE (decl)))))) && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) && !uses_template_parms (DECL_TI_ARGS (decl))) @@ -4321,6 +4331,9 @@ mark_used (tree decl) --function_depth; } + if (type_uses_auto (TREE_TYPE (decl))) + error ("use of %qD before deduction of %", decl); + /* If we don't need a value, then we don't need to synthesize DECL. */ if (cp_unevaluated_operand != 0) return true; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 75b7bdb..eac60f1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8416,9 +8416,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (LAMBDA_EXPR_RETURN_TYPE (lambda_expr)) return_type_specs.type = LAMBDA_EXPR_RETURN_TYPE (lambda_expr); else - /* Maybe we will deduce the return type later, but we can use void - as a placeholder return type anyways. */ - return_type_specs.type = void_type_node; + /* Maybe we will deduce the return type later. */ + return_type_specs.type = make_auto (); p = obstack_alloc (&declarator_obstack, 0); @@ -8539,7 +8538,8 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) if (cp_parser_parse_definitely (parser)) { - apply_lambda_return_type (lambda_expr, lambda_return_type (expr)); + if (!processing_template_decl) + apply_deduced_return_type (fco, lambda_return_type (expr)); /* Will get error here if type not deduced yet. */ finish_return_stmt (expr); @@ -8550,13 +8550,10 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) if (!done) { - if (!LAMBDA_EXPR_RETURN_TYPE (lambda_expr)) - LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda_expr) = true; while (cp_lexer_next_token_is_keyword (parser->lexer, RID_LABEL)) cp_parser_label_declaration (parser); cp_parser_statement_seq_opt (parser, NULL_TREE); cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); - LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda_expr) = false; } finish_compound_stmt (compound_stmt); @@ -11275,8 +11272,14 @@ cp_parser_conversion_type_id (cp_parser* parser) if (! cp_parser_uncommitted_to_tentative_parse_p (parser) && type_uses_auto (type_specified)) { - error ("invalid use of % in conversion operator"); - return error_mark_node; + if (cxx_dialect < cxx1y) + { + error ("invalid use of % in conversion operator"); + return error_mark_node; + } + else if (template_parm_scope_p ()) + warning (0, "use of % in member template " + "conversion operator can never be deduced"); } return type_specified; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b36e49d..f128947 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9112,12 +9112,6 @@ instantiate_class_template_1 (tree type) tree decl = lambda_function (type); if (decl) { - tree lambda = CLASSTYPE_LAMBDA_EXPR (type); - if (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda)) - { - apply_lambda_return_type (lambda, void_type_node); - LAMBDA_EXPR_RETURN_TYPE (lambda) = NULL_TREE; - } instantiate_decl (decl, false, false); maybe_add_lambda_conv_op (type); } @@ -11331,6 +11325,12 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) about the template parameter in question. */ return t; + /* Early in template argument deduction substitution, we don't + want to reduce the level of 'auto', or it will be confused + with a normal template parm in subsequent deduction. */ + if (is_auto (t) && (complain & tf_partial)) + return t; + /* If we get here, we must have been looking at a parm for a more deeply nested template. Make a new version of this template parameter, but with a lower level. */ @@ -14334,14 +14334,8 @@ tsubst_copy_and_build (tree t, = (LAMBDA_EXPR_DISCRIMINATOR (t)); LAMBDA_EXPR_EXTRA_SCOPE (r) = RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t)); - if (LAMBDA_EXPR_RETURN_TYPE (t) == dependent_lambda_return_type_node) - { - LAMBDA_EXPR_RETURN_TYPE (r) = dependent_lambda_return_type_node; - LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (r) = true; - } - else - LAMBDA_EXPR_RETURN_TYPE (r) - = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl); + LAMBDA_EXPR_RETURN_TYPE (r) + = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl); gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL); @@ -14860,7 +14854,7 @@ fn_type_unification (tree fn, fntype = deduction_tsubst_fntype (fn, converted_args, (explain_p ? tf_warning_or_error - : tf_none)); + : tf_none) | tf_partial); processing_template_decl -= incomplete; if (fntype == error_mark_node) @@ -16275,7 +16269,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, to see if it matches ARG. */ { if (TREE_CODE (arg) == TREE_CODE (parm) - && same_type_p (parm, arg)) + && (is_auto (parm) ? is_auto (arg) + : same_type_p (parm, arg))) return unify_success (explain_p); else return unify_type_mismatch (explain_p, parm, arg); @@ -17408,7 +17403,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype) The call to fn_type_unification will handle substitution into the FN. */ decl_type = TREE_TYPE (decl); - if (explicit_args && uses_template_parms (decl_type)) + if (explicit_args && decl == DECL_TEMPLATE_RESULT (fn)) { tree tmpl; tree converted_args; @@ -18315,7 +18310,8 @@ always_instantiate_p (tree decl) that for "extern template" functions. Therefore, we check DECL_DECLARED_INLINE_P, rather than possibly_inlined_p. */ return ((TREE_CODE (decl) == FUNCTION_DECL - && DECL_DECLARED_INLINE_P (decl)) + && (DECL_DECLARED_INLINE_P (decl) + || type_uses_auto (TREE_TYPE (TREE_TYPE (decl))))) /* And we need to instantiate static data members so that their initializers are available in integral constant expressions. */ @@ -20269,20 +20265,6 @@ listify_autos (tree type, tree auto_node) return tsubst (type, argvec, tf_warning_or_error, NULL_TREE); } -/* walk_tree helper for do_auto_deduction. */ - -static tree -contains_auto_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, - void *type) -{ - /* Is this a variable with the type we're looking for? */ - if (DECL_P (*tp) - && TREE_TYPE (*tp) == type) - return *tp; - else - return NULL_TREE; -} - /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. */ @@ -20291,25 +20273,17 @@ do_auto_deduction (tree type, tree init, tree auto_node) { tree parms, tparms, targs; tree args[1]; - tree decl; int val; + if (init == error_mark_node) + return error_mark_node; + if (processing_template_decl && (TREE_TYPE (init) == NULL_TREE || BRACE_ENCLOSED_INITIALIZER_P (init))) /* Not enough information to try this yet. */ return type; - /* The name of the object being declared shall not appear in the - initializer expression. */ - decl = cp_walk_tree_without_duplicates (&init, contains_auto_r, type); - if (decl) - { - error ("variable %q#D with % type used in its own " - "initializer", decl); - return error_mark_node; - } - /* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initializer is a braced-init-list (8.5.4), with @@ -20337,7 +20311,13 @@ do_auto_deduction (tree type, tree init, tree auto_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. */ - error ("unable to deduce %qT from %qE", type, init); + { + 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; } @@ -20348,8 +20328,14 @@ do_auto_deduction (tree type, tree init, tree auto_node) if (TREE_TYPE (auto_node) && !same_type_p (TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0))) { - error ("inconsistent deduction for %qT: %qT and then %qT", - auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)); + if (cfun && auto_node == current_function_auto_return_pattern + && LAMBDA_FUNCTION_P (current_function_decl)) + error ("inconsistent types %qT and %qT deduced for " + "lambda return type", TREE_TYPE (auto_node), + TREE_VEC_ELT (targs, 0)); + else + error ("inconsistent deduction for %qT: %qT and then %qT", + auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)); return error_mark_node; } TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index bd1bc57..14d272e 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -2430,6 +2430,11 @@ lookup_conversions_r (tree binfo, if (!IDENTIFIER_MARKED (name)) { tree type = DECL_CONV_FN_TYPE (cur); + if (type_uses_auto (type)) + { + mark_used (cur); + type = DECL_CONV_FN_TYPE (cur); + } if (check_hidden_convs (binfo, virtual_depth, virtualness, type, parent_convs, other_convs)) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 5646fa7..6294e19 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8691,18 +8691,16 @@ begin_lambda_type (tree lambda) tree lambda_return_type (tree expr) { - tree type; + if (expr == NULL_TREE) + return void_type_node; if (type_unknown_p (expr) || BRACE_ENCLOSED_INITIALIZER_P (expr)) { cxx_incomplete_type_error (expr, TREE_TYPE (expr)); return void_type_node; } - if (type_dependent_expression_p (expr)) - type = dependent_lambda_return_type_node; - else - type = cv_unqualified (type_decays_to (unlowered_expr_type (expr))); - return type; + gcc_checking_assert (!type_dependent_expression_p (expr)); + return cv_unqualified (type_decays_to (unlowered_expr_type (expr))); } /* Given a LAMBDA_EXPR or closure type LAMBDA, return the op() of the @@ -8749,29 +8747,32 @@ lambda_capture_field_type (tree expr) return type; } -/* Recompute the return type for LAMBDA with body of the form: - { return EXPR ; } */ +/* Insert the deduced return type for an auto function. */ void -apply_lambda_return_type (tree lambda, tree return_type) +apply_deduced_return_type (tree fco, tree return_type) { - tree fco = lambda_function (lambda); tree result; - LAMBDA_EXPR_RETURN_TYPE (lambda) = return_type; - if (return_type == error_mark_node) return; - if (TREE_TYPE (TREE_TYPE (fco)) == return_type) - return; - /* TREE_TYPE (FUNCTION_DECL) == METHOD_TYPE - TREE_TYPE (METHOD_TYPE) == return-type */ + if (LAMBDA_FUNCTION_P (fco)) + { + tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); + LAMBDA_EXPR_RETURN_TYPE (lambda) = return_type; + } + + if (DECL_CONV_FN_P (fco)) + DECL_NAME (fco) = mangle_conv_op_name_for_type (return_type); + TREE_TYPE (fco) = change_return_type (return_type, TREE_TYPE (fco)); result = DECL_RESULT (fco); if (result == NULL_TREE) return; + if (TREE_TYPE (result) == return_type) + return; /* We already have a DECL_RESULT from start_preparsed_function. Now we need to redo the work it and allocate_struct_function @@ -8786,12 +8787,13 @@ apply_lambda_return_type (tree lambda, tree return_type) DECL_RESULT (fco) = result; - if (!processing_template_decl && aggregate_value_p (result, fco)) + if (!processing_template_decl) { + bool aggr = aggregate_value_p (result, fco); #ifdef PCC_STATIC_STRUCT_RETURN - cfun->returns_pcc_struct = 1; + cfun->returns_pcc_struct = aggr; #endif - cfun->returns_struct = 1; + cfun->returns_struct = aggr; } } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index d2d6c4e..b68de52 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -733,6 +733,11 @@ merge_types (tree t1, tree t2) if (t2 == error_mark_node) return t1; + /* Handle merging an auto redeclaration with a previous deduced + return type. */ + if (is_auto (t1)) + return t2; + /* Merge the attributes. */ attributes = (*targetm.merge_type_attributes) (t1, t2); @@ -7779,9 +7784,11 @@ tree check_return_expr (tree retval, bool *no_warning) { tree result; - /* The type actually returned by the function, after any - promotions. */ + /* The type actually returned by the function. */ tree valtype; + /* The type the function is declared to return, or void if + the declared type is incomplete. */ + tree functype; int fn_returns_value_p; bool named_return_value_okay_p; @@ -7812,30 +7819,6 @@ check_return_expr (tree retval, bool *no_warning) return NULL_TREE; } - /* As an extension, deduce lambda return type from a return statement - anywhere in the body. */ - if (retval && LAMBDA_FUNCTION_P (current_function_decl)) - { - tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); - if (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda)) - { - tree type = lambda_return_type (retval); - tree oldtype = LAMBDA_EXPR_RETURN_TYPE (lambda); - - if (oldtype == NULL_TREE) - apply_lambda_return_type (lambda, type); - /* If one of the answers is type-dependent, we can't do any - better until instantiation time. */ - else if (oldtype == dependent_lambda_return_type_node) - /* Leave it. */; - else if (type == dependent_lambda_return_type_node) - apply_lambda_return_type (lambda, type); - else if (!same_type_p (type, oldtype)) - error ("inconsistent types %qT and %qT deduced for " - "lambda return type", type, oldtype); - } - } - if (processing_template_decl) { current_function_returns_value = 1; @@ -7844,6 +7827,42 @@ check_return_expr (tree retval, bool *no_warning) return retval; } + functype = TREE_TYPE (TREE_TYPE (current_function_decl)); + + /* Deduce auto return type from a return statement. */ + if (current_function_auto_return_pattern) + { + tree auto_node; + tree type; + + if (!retval && !is_auto (current_function_auto_return_pattern)) + { + /* Give a helpful error message. */ + error ("return-statement with no value, in function returning %qT", + current_function_auto_return_pattern); + inform (input_location, "only plain % return type can be " + "deduced to %"); + type = error_mark_node; + } + else + { + if (!retval) + retval = void_zero_node; + auto_node = type_uses_auto (current_function_auto_return_pattern); + type = do_auto_deduction (current_function_auto_return_pattern, + retval, auto_node); + } + + if (type == error_mark_node) + /* Leave it. */; + else if (functype == current_function_auto_return_pattern) + apply_deduced_return_type (current_function_decl, type); + else + /* A mismatch should have been diagnosed in do_auto_deduction. */ + gcc_assert (same_type_p (type, functype)); + functype = type; + } + /* When no explicit return-value is given in a function with a named return value, the named return value is used. */ result = DECL_RESULT (current_function_decl); @@ -7857,12 +7876,11 @@ check_return_expr (tree retval, bool *no_warning) that's supposed to return a value. */ if (!retval && fn_returns_value_p) { - permerror (input_location, "return-statement with no value, in function returning %qT", - valtype); - /* Clear this, so finish_function won't say that we reach the - end of a non-void function (which we don't, we gave a - return!). */ - current_function_returns_null = 0; + if (functype != error_mark_node) + permerror (input_location, "return-statement with no value, in " + "function returning %qT", valtype); + /* Remember that this function did return. */ + current_function_returns_value = 1; /* And signal caller that TREE_NO_WARNING should be set on the RETURN_EXPR to avoid control reaches end of non-void function warnings in tree-cfg.c. */ @@ -7963,14 +7981,12 @@ check_return_expr (tree retval, bool *no_warning) && DECL_CONTEXT (retval) == current_function_decl && ! TREE_STATIC (retval) && ! DECL_ANON_UNION_VAR_P (retval) - && (DECL_ALIGN (retval) - >= DECL_ALIGN (DECL_RESULT (current_function_decl))) + && (DECL_ALIGN (retval) >= DECL_ALIGN (result)) /* The cv-unqualified type of the returned value must be the same as the cv-unqualified return type of the function. */ && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))), - (TYPE_MAIN_VARIANT - (TREE_TYPE (TREE_TYPE (current_function_decl))))) + (TYPE_MAIN_VARIANT (functype))) /* And the returned value must be non-volatile. */ && ! TYPE_VOLATILE (TREE_TYPE (retval))); @@ -7995,8 +8011,6 @@ check_return_expr (tree retval, bool *no_warning) ; else { - /* The type the function is declared to return. */ - tree functype = TREE_TYPE (TREE_TYPE (current_function_decl)); int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING; /* The functype's return type will have been set to void, if it @@ -8016,10 +8030,9 @@ check_return_expr (tree retval, bool *no_warning) && DECL_CONTEXT (retval) == current_function_decl && !TREE_STATIC (retval) && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))), - (TYPE_MAIN_VARIANT - (TREE_TYPE (TREE_TYPE (current_function_decl))))) + (TYPE_MAIN_VARIANT (functype))) /* This is only interesting for class type. */ - && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))) + && CLASS_TYPE_P (functype)) flags = flags | LOOKUP_PREFER_RVALUE; /* First convert the value to the function's return type, then diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 974f92f..80a1d04 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1818,7 +1818,8 @@ add_exception_specifier (tree list, tree spec, int complain) else diag_type = DK_ERROR; /* error */ - if (diag_type != DK_UNSPECIFIED && complain) + if (diag_type != DK_UNSPECIFIED + && (complain & tf_warning_or_error)) cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type); return list; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a6b6424..9412052 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,20 @@ +2012-03-21 Jason Merrill + + * g++.dg/cpp0x/auto3.C: Compile with -pedantic-errors. + * g++.dg/cpp0x/trailing2.C: Likewise. + * g++.dg/warn/pr23075.C: Change dg-warning to dg-bogus. + * g++.dg/cpp1y/auto-fn1.C: New. + * g++.dg/cpp1y/auto-fn2.C: New. + * g++.dg/cpp1y/auto-fn3.C: New. + * g++.dg/cpp1y/auto-fn4.C: New. + * g++.dg/cpp1y/auto-fn5.C: New. + * g++.dg/cpp1y/auto-fn6.C: New. + * g++.dg/cpp1y/auto-fn7.C: New. + * g++.dg/cpp1y/auto-fn8.C: New. + * g++.dg/cpp1y/auto-fn9.C: New. + * g++.dg/cpp1y/auto-fn10.C: New. + * g++.dg/cpp1y/auto-fn11.C: New. + 2012-03-23 Richard Guenther PR tree-optimization/52678 diff --git a/gcc/testsuite/g++.dg/cpp0x/auto18.C b/gcc/testsuite/g++.dg/cpp0x/auto18.C index 17f7f99..0a59242 100644 --- a/gcc/testsuite/g++.dg/cpp0x/auto18.C +++ b/gcc/testsuite/g++.dg/cpp0x/auto18.C @@ -2,5 +2,5 @@ void f() { - auto val = val; // { dg-error "auto. type used in its own initializer" } + auto val = val; // { dg-error "auto" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/auto3.C b/gcc/testsuite/g++.dg/cpp0x/auto3.C index 860790d..2b51d31 100644 --- a/gcc/testsuite/g++.dg/cpp0x/auto3.C +++ b/gcc/testsuite/g++.dg/cpp0x/auto3.C @@ -1,5 +1,5 @@ // Negative test for auto -// { dg-options "-std=c++0x" } +// { dg-do compile { target c++11 } } #include @@ -10,7 +10,7 @@ auto x; // { dg-error "auto" } auto i = 42, j = 42.0; // { dg-error "auto" } // New CWG issue -auto a[2] = { 1, 2 }; // { dg-error "initializer_list" } +auto a[2] = { 1, 2 }; // { dg-error "auto|initializer_list" } template struct A { }; diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing2.C b/gcc/testsuite/g++.dg/cpp0x/trailing2.C index 5f5af22..91e5557 100644 --- a/gcc/testsuite/g++.dg/cpp0x/trailing2.C +++ b/gcc/testsuite/g++.dg/cpp0x/trailing2.C @@ -1,6 +1,6 @@ // PR c++/37967 // Negative test for auto -// { dg-options "-std=c++0x" } +// { dg-do compile { target c++11 } } auto f1 () -> int; auto f2 (); // { dg-error "without trailing return type" } diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn1.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn1.C new file mode 100644 index 0000000..eb54149 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn1.C @@ -0,0 +1,5 @@ +// { dg-options -std=c++1y } + +constexpr auto f() { return (char)42; } +#define SA(X) static_assert ((X),#X) +SA (f() == 42); diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn10.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn10.C new file mode 100644 index 0000000..e3ed3a9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn10.C @@ -0,0 +1,16 @@ +// A template declared with auto should be declared with auto in an +// explicit instantiation or explicit specialization, too. +// { dg-options -std=c++1y } + +template +auto f(T t) { return t; } + +template<> auto f(int); +template auto f(float); +template<> auto f(int*); +template auto f(float*); + +template<> short f(short); // { dg-error "does not match" } +template char f(char); // { dg-error "does not match" } +template<> short f(short*); // { dg-error "does not match" } +template char f(char*); // { dg-error "does not match" } diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn11.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn11.C new file mode 100644 index 0000000..a9984aa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn11.C @@ -0,0 +1,5 @@ +// { dg-options -std=c++1y } + +auto f() { return; } // OK, return type is void +auto* g() { return; } // { dg-error "no value" } +auto* h() { } // { dg-error "no return statements" } diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C new file mode 100644 index 0000000..e4e58e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C @@ -0,0 +1,14 @@ +// { dg-options -std=c++1y } +// { dg-final { scan-assembler "_ZN1AIiEcviEv" } } + +template +struct A { + T t; + operator auto() { return t+1; } +}; + +int main() +{ + int i = A{42}; + return (i != 43); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn13.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn13.C new file mode 100644 index 0000000..34a61ae --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn13.C @@ -0,0 +1,6 @@ +// { dg-options -std=c++1y } + +struct A { + template + operator auto() { return T(); } // { dg-warning "auto.*template" } +}; diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn2.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn2.C new file mode 100644 index 0000000..4c2cee7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn2.C @@ -0,0 +1,3 @@ +// { dg-options -std=c++1y } + +auto f() { return f(); } // { dg-error "auto" } diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn3.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn3.C new file mode 100644 index 0000000..107c37f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn3.C @@ -0,0 +1,10 @@ +// { dg-options -std=c++1y } + +bool b; +auto f() +{ + if (b) + return 42; + else + return f(); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn4.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn4.C new file mode 100644 index 0000000..0b76bfc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn4.C @@ -0,0 +1,7 @@ +// { dg-options -std=c++1y } + +template +constexpr auto f(T t) { return t+1; } + +#define SA(X) static_assert((X),#X) +SA(f(1)==2); diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn5.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn5.C new file mode 100644 index 0000000..f9af6c2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn5.C @@ -0,0 +1,11 @@ +// { dg-options -std=c++1y } +// { dg-do run } + +int i; +auto& f() { return i; } + +int main() +{ + f() = 42; + return i != 42; +} diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn6.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn6.C new file mode 100644 index 0000000..03ff537 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn6.C @@ -0,0 +1,18 @@ +// { dg-options -std=c++1y } + +template struct ST; +template struct ST {}; + +int g(int); +char& g(char); +double&& g(double); + +template auto&& f(T t) +{ return g(t); } // { dg-warning "reference to temporary" } + +int main() +{ + ST(); + ST(); + ST(); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn7.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn7.C new file mode 100644 index 0000000..b915352 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn7.C @@ -0,0 +1,5 @@ +// { dg-options "-std=c++1y -pedantic-errors" } + +auto f(); + +template auto f(T); diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn8.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn8.C new file mode 100644 index 0000000..dcec899 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn8.C @@ -0,0 +1,13 @@ +// { dg-options "-std=c++1y -pedantic-errors" } + +auto f() { return 42; } // { dg-error "deduced return type" } +auto f(); // OK +int f(); // { dg-error "new declaration" } + +template auto f(T t) { return t; } +template T f(T t); + +int main() +{ + f(42); // { dg-error "ambiguous" } +} diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn9.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn9.C new file mode 100644 index 0000000..1fa7479 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn9.C @@ -0,0 +1,11 @@ +// { dg-options -std=c++1y } +// { dg-final { scan-assembler "_Z1fIiERDaRKT_S1_" } } + +template +auto& f(const T& t, T u) { return t; } + +int main() +{ + int i; + f(i,i); +} diff --git a/gcc/testsuite/g++.dg/gomp/pr38639.C b/gcc/testsuite/g++.dg/gomp/pr38639.C index e7145ff..481583e 100644 --- a/gcc/testsuite/g++.dg/gomp/pr38639.C +++ b/gcc/testsuite/g++.dg/gomp/pr38639.C @@ -6,7 +6,7 @@ template void foo () { #pragma omp parallel for - for (auto i = i = 0; i<4; ++i) // { dg-error "incomplete|unable|invalid" } + for (auto i = i = 0; i<4; ++i) // { dg-error "incomplete|unable|invalid|auto" } ; } diff --git a/gcc/testsuite/g++.dg/warn/pr23075.C b/gcc/testsuite/g++.dg/warn/pr23075.C index e5b1b48..59e93be 100644 --- a/gcc/testsuite/g++.dg/warn/pr23075.C +++ b/gcc/testsuite/g++.dg/warn/pr23075.C @@ -6,4 +6,4 @@ int foo (void) { return; // { dg-error "with no value" } -} // { dg-warning "no return statement" } +} // { dg-bogus "no return statement" } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec22.C b/gcc/testsuite/g++.old-deja/g++.pt/spec22.C index 41aab39..94bffdb 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/spec22.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec22.C @@ -10,6 +10,6 @@ struct S template template <> // { dg-error "enclosing class templates|invalid explicit specialization" } -void S::f () // { dg-error "does not match|invalid function declaration" } +void S::f () { } -- 2.7.4