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
This commit is contained in:
parent
86c0810c72
commit
79d8a27242
@ -1,5 +1,22 @@
|
||||
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.
|
||||
|
@ -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. */
|
||||
|
@ -5225,6 +5225,9 @@ extern void initialize_artificial_var (tree, vec<constructor_elt, va_gc> *);
|
||||
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;
|
||||
@ -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,
|
||||
|
@ -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 "
|
||||
"%<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))
|
||||
{
|
||||
@ -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 %<auto%>", decl);
|
||||
}
|
||||
|
||||
#include "gt-cp-decl.h"
|
||||
|
@ -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 %<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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
34
gcc/cp/pt.c
34
gcc/cp/pt.c
@ -20672,15 +20672,16 @@ make_args_non_dependent (vec<tree, va_gc> *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<ARG>. */
|
||||
|
||||
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 %<decltype(auto)%>", 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;
|
||||
|
@ -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
|
||||
{
|
||||
|
12
gcc/testsuite/g++.dg/cpp1y/auto-fn18.C
Normal file
12
gcc/testsuite/g++.dg/cpp1y/auto-fn18.C
Normal file
@ -0,0 +1,12 @@
|
||||
// { 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" }
|
||||
};
|
6
gcc/testsuite/g++.dg/cpp1y/auto-fn19.C
Normal file
6
gcc/testsuite/g++.dg/cpp1y/auto-fn19.C
Normal file
@ -0,0 +1,6 @@
|
||||
// { dg-options "-std=c++1y" }
|
||||
|
||||
template <class T>
|
||||
auto f() { return T::i; }
|
||||
|
||||
extern template auto f<int>(); // does not force instantiation
|
12
gcc/testsuite/g++.dg/cpp1y/auto-fn20.C
Normal file
12
gcc/testsuite/g++.dg/cpp1y/auto-fn20.C
Normal file
@ -0,0 +1,12 @@
|
||||
// { 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" }
|
||||
}
|
6
gcc/testsuite/g++.dg/cpp1y/auto-fn21.C
Normal file
6
gcc/testsuite/g++.dg/cpp1y/auto-fn21.C
Normal file
@ -0,0 +1,6 @@
|
||||
// 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" }
|
@ -1,6 +1,6 @@
|
||||
// { 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" }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user