* 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
2013-04-19 Jason Merrill <jason@redhat.com>
+ 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.
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. */
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<tree, va_gc> *deferred_mark_used_calls;
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,
/* 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))
{
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
pedwarn (input_location, 0, "%qs function uses "
"%<auto%> 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))
{
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 %<auto%>", decl);
+}
+
#include "gt-cp-decl.h"
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)))
&& uses_template_parms (DECL_TI_ARGS (decl)))
return true;
- if (type_uses_auto (TREE_TYPE (decl)))
- {
- error ("use of %qD before deduction of %<auto%>", 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)
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)
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;
}
}
}
-/* 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,
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<ARG>. */
static tree
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 %<decltype(auto)%>", type);
+ return error_mark_node;
+ }
}
else
{
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;
{
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;
{
/* 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
{
--- /dev/null
+// { dg-options "-std=c++1y" }
+
+struct A
+{
+ virtual int f() { return 1; } // { dg-message "overriding" }
+ virtual auto g() { return 1; } // { dg-error "virtual" }
+};
+
+struct B: A
+{
+ auto f() { return 1; } // { dg-error "return type" }
+};
--- /dev/null
+// { dg-options "-std=c++1y" }
+
+template <class T>
+auto f() { return T::i; }
+
+extern template auto f<int>(); // does not force instantiation
--- /dev/null
+// { dg-options "-std=c++1y" }
+
+template <class T>
+auto f(T) { return 42; }
+template <class T>
+auto g(T) { return 0.0; }
+
+int main()
+{
+ int (*p)(int) = &f; // OK
+ p = &g; // { dg-error "no match" }
+}
--- /dev/null
+// N3638: decltype(auto) must stand alone
+// { dg-options "-std=c++1y" }
+
+void f();
+decltype(auto) g1() { return &f; }
+decltype(auto)* g2() { return f; } // { dg-error "decltype.auto" }
// { dg-options "-std=c++1y -pedantic-errors" }
-auto f() { return 42; } // { dg-error "deduced return type" }
+auto f() { return 42; } // { dg-error "old declaration .auto" }
auto f(); // OK
int f(); // { dg-error "new declaration" }