From 79d8a2724290d3c6e14f9935b62993b90776aa4e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 19 Apr 2013 12:28:24 -0400 Subject: N3638 changes to return type deduction * decl.c (undeduced_auto_decl): New. (require_deduced_type): New. (fndecl_declared_return_type): New. (decls_match): Use it. (duplicate_decls): Don't check for auto return. (grokdeclarator): Reject virtual auto. * class.c (resolve_address_of_overloaded_function): Handle auto function templates. * decl2.c (mark_used): Use undeduced_auto_decl, require_deduced_type. * cp-tree.h: Declare new fns. * error.c (dump_function_decl): Use fndecl_declared_return_type. * search.c (check_final_overrider): Likewise. * pt.c (make_decltype_auto): New. (do_auto_deduction): Require plain decltype(auto). (is_auto): Adjust. From-SVN: r198099 --- gcc/cp/ChangeLog | 17 +++++++++++++++++ gcc/cp/class.c | 21 ++++++++++++++++++++- gcc/cp/cp-tree.h | 4 ++++ gcc/cp/decl.c | 48 +++++++++++++++++++++++++++++++++++++++--------- gcc/cp/decl2.c | 8 ++------ gcc/cp/error.c | 5 ++++- gcc/cp/parser.c | 2 +- gcc/cp/pt.c | 34 +++++++++++++++++++++++++++------- gcc/cp/search.c | 7 +++---- 9 files changed, 117 insertions(+), 29 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9d6ad14..7e224ae 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,22 @@ 2013-04-19 Jason Merrill + N3638 changes to return type deduction + * decl.c (undeduced_auto_decl): New. + (require_deduced_type): New. + (fndecl_declared_return_type): New. + (decls_match): Use it. + (duplicate_decls): Don't check for auto return. + (grokdeclarator): Reject virtual auto. + * class.c (resolve_address_of_overloaded_function): Handle + auto function templates. + * decl2.c (mark_used): Use undeduced_auto_decl, require_deduced_type. + * cp-tree.h: Declare new fns. + * error.c (dump_function_decl): Use fndecl_declared_return_type. + * search.c (check_final_overrider): Likewise. + * pt.c (make_decltype_auto): New. + (do_auto_deduction): Require plain decltype(auto). + (is_auto): Adjust. + DR 941 * decl.c (duplicate_decls): Don't propagate DECL_DELETED_FN to template specializations. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 58248bf..b936ac8 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -7256,19 +7256,38 @@ resolve_address_of_overloaded_function (tree target_type, one, or vice versa. */ continue; + tree ret = target_ret_type; + + /* If the template has a deduced return type, don't expose it to + template argument deduction. */ + if (undeduced_auto_decl (fn)) + ret = NULL_TREE; + /* Try to do argument deduction. */ targs = make_tree_vec (DECL_NTPARMS (fn)); instantiation = fn_type_unification (fn, explicit_targs, targs, args, - nargs, target_ret_type, + nargs, ret, DEDUCE_EXACT, LOOKUP_NORMAL, false, false); if (instantiation == error_mark_node) /* Instantiation failed. */ continue; + /* And now force instantiation to do return type deduction. */ + if (undeduced_auto_decl (instantiation)) + { + ++function_depth; + instantiate_decl (instantiation, /*defer*/false, /*class*/false); + --function_depth; + + require_deduced_type (instantiation); + } + /* See if there's a match. */ if (same_type_p (target_fn_type, static_fn_type (instantiation))) matches = tree_cons (instantiation, fn, matches); + + ggc_free (targs); } /* Now, remove all but the most specialized of the matches. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f7c65b6..a5c7548 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5225,6 +5225,9 @@ extern void initialize_artificial_var (tree, vec *); extern tree check_var_type (tree, tree); extern tree reshape_init (tree, tree, tsubst_flags_t); extern tree next_initializable_field (tree); +extern tree fndecl_declared_return_type (tree); +extern bool undeduced_auto_decl (tree); +extern void require_deduced_type (tree); extern bool defer_mark_used_calls; extern GTY(()) vec *deferred_mark_used_calls; @@ -5425,6 +5428,7 @@ extern tree check_explicit_specialization (tree, tree, int, int); extern int num_template_headers_for_class (tree); extern void check_template_variable (tree); extern tree make_auto (void); +extern tree make_decltype_auto (void); extern tree do_auto_deduction (tree, tree, tree); extern tree type_uses_auto (tree); extern void append_type_to_template_for_access_check (tree, tree, tree, diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 3328812..b2f1c6e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -992,10 +992,7 @@ decls_match (tree newdecl, tree olddecl) /* 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); + r2 = fndecl_declared_return_type (olddecl); if (same_type_p (TREE_TYPE (f1), r2)) { @@ -1538,11 +1535,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) TYPE_ARG_TYPES (TREE_TYPE (olddecl)))) { error ("new declaration %q#D", newdecl); - 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); + error ("ambiguates old declaration %q+#D", olddecl); return error_mark_node; } else @@ -9503,6 +9496,9 @@ grokdeclarator (const cp_declarator *declarator, pedwarn (input_location, 0, "%qs function uses " "% type specifier without trailing " "return type", name); + else if (virtualp) + permerror (input_location, "virtual function cannot " + "have deduced return type"); } else if (!is_auto (type)) { @@ -14380,4 +14376,38 @@ cxx_comdat_group (tree decl) return name; } +/* Returns the return type for FN as written by the user, which may include + a placeholder for a deduced return type. */ + +tree +fndecl_declared_return_type (tree fn) +{ + fn = STRIP_TEMPLATE (fn); + if (FNDECL_USED_AUTO (fn)) + return (DECL_STRUCT_FUNCTION (fn)->language + ->x_auto_return_pattern); + else + return TREE_TYPE (TREE_TYPE (fn)); +} + +/* Returns true iff DECL was declared with an auto return type and it has + not yet been deduced to a real type. */ + +bool +undeduced_auto_decl (tree decl) +{ + if (cxx_dialect < cxx1y) + return false; + return type_uses_auto (TREE_TYPE (decl)); +} + +/* Complain if DECL has an undeduced return type. */ + +void +require_deduced_type (tree decl) +{ + if (undeduced_auto_decl (decl)) + error ("use of %qD before deduction of %", decl); +} + #include "gt-cp-decl.h" diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index a5b2655..74e51a8 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -4578,7 +4578,7 @@ mark_used (tree decl) if ((decl_maybe_constant_var_p (decl) || (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_CONSTEXPR_P (decl)) - || type_uses_auto (TREE_TYPE (decl))) + || undeduced_auto_decl (decl)) && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) && !uses_template_parms (DECL_TI_ARGS (decl))) @@ -4601,11 +4601,7 @@ mark_used (tree decl) && uses_template_parms (DECL_TI_ARGS (decl))) return true; - if (type_uses_auto (TREE_TYPE (decl))) - { - error ("use of %qD before deduction of %", decl); - return false; - } + require_deduced_type (decl); /* If we don't need a value, then we don't need to synthesize DECL. */ if (cp_unevaluated_operand != 0) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 300fe0c..6bac7ec 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1403,7 +1403,10 @@ dump_function_decl (tree t, int flags) show_return = !DECL_CONV_FN_P (t) && !DECL_CONSTRUCTOR_P (t) && !DECL_DESTRUCTOR_P (t); if (show_return) - dump_type_prefix (TREE_TYPE (fntype), flags); + { + tree ret = fndecl_declared_return_type (t); + dump_type_prefix (ret, flags); + } /* Print the function name. */ if (!do_outer_scope) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6560852..1893482 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11510,7 +11510,7 @@ cp_parser_decltype (cp_parser *parser) cp_lexer_consume_token (parser->lexer); if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) return error_mark_node; - expr = make_auto (); + expr = make_decltype_auto (); AUTO_IS_DECLTYPE (expr) = true; goto rewrite; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3856813..77329a4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20672,15 +20672,16 @@ make_args_non_dependent (vec *args) } } -/* Returns a type which represents 'auto'. We use a TEMPLATE_TYPE_PARM - with a level one deeper than the actual template parms. */ +/* Returns a type which represents 'auto' or 'decltype(auto)'. We use a + TEMPLATE_TYPE_PARM with a level one deeper than the actual template + parms. */ -tree -make_auto (void) +static tree +make_auto_1 (tree name) { tree au = cxx_make_type (TEMPLATE_TYPE_PARM); TYPE_NAME (au) = build_decl (BUILTINS_LOCATION, - TYPE_DECL, get_identifier ("auto"), au); + TYPE_DECL, name, au); TYPE_STUB_DECL (au) = TYPE_NAME (au); TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index (0, processing_template_decl + 1, processing_template_decl + 1, @@ -20692,6 +20693,18 @@ make_auto (void) return au; } +tree +make_decltype_auto (void) +{ + return make_auto_1 (get_identifier ("decltype(auto)")); +} + +tree +make_auto (void) +{ + return make_auto_1 (get_identifier ("auto")); +} + /* Given type ARG, return std::initializer_list. */ static tree @@ -20756,6 +20769,11 @@ do_auto_deduction (tree type, tree init, tree 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); + if (type != auto_node) + { + error ("%qT as type rather than plain %", type); + return error_mark_node; + } } else { @@ -20834,13 +20852,15 @@ splice_late_return_type (tree type, tree late_return_type) return tsubst (type, argvec, tf_warning_or_error, NULL_TREE); } -/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto'. */ +/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto' or + 'decltype(auto)'. */ bool is_auto (const_tree type) { if (TREE_CODE (type) == TEMPLATE_TYPE_PARM - && TYPE_IDENTIFIER (type) == get_identifier ("auto")) + && (TYPE_IDENTIFIER (type) == get_identifier ("auto") + || TYPE_IDENTIFIER (type) == get_identifier ("decltype(auto)"))) return true; else return false; diff --git a/gcc/cp/search.c b/gcc/cp/search.c index b64398f..b113477 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1842,8 +1842,8 @@ check_final_overrider (tree overrider, tree basefn) { tree over_type = TREE_TYPE (overrider); tree base_type = TREE_TYPE (basefn); - tree over_return = TREE_TYPE (over_type); - tree base_return = TREE_TYPE (base_type); + tree over_return = fndecl_declared_return_type (overrider); + tree base_return = fndecl_declared_return_type (basefn); tree over_throw, base_throw; int fail = 0; @@ -1897,8 +1897,7 @@ check_final_overrider (tree overrider, tree basefn) { /* can_convert will permit user defined conversion from a (reference to) class type. We must reject them. */ - over_return = non_reference (TREE_TYPE (over_type)); - if (CLASS_TYPE_P (over_return)) + if (CLASS_TYPE_P (non_reference (over_return))) fail = 2; else { -- cgit v1.1