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.

From-SVN: r185768
This commit is contained in:
Jason Merrill 2012-03-24 16:56:08 -04:00 committed by Jason Merrill
parent 8c5f232742
commit 852497a31e
30 changed files with 405 additions and 148 deletions

View File

@ -1,3 +1,50 @@
2012-03-21 Jason Merrill <jason@redhat.com>
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 <paolo.carlini@oracle.com>
PR c++/52487

View File

@ -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);

View File

@ -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 %<auto%> 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 "
"%<auto%> 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 %<auto%>");
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 %<auto%> return type can be "
"deduced to %<void%>");
}
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);

View File

@ -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 %<auto%>", 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 %<auto%>", decl);
/* If we don't need a value, then we don't need to synthesize DECL. */
if (cp_unevaluated_operand != 0)
return true;

View File

@ -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 %<auto%> in conversion operator");
return error_mark_node;
if (cxx_dialect < cxx1y)
{
error ("invalid use of %<auto%> in conversion operator");
return error_mark_node;
}
else if (template_parm_scope_p ())
warning (0, "use of %<auto%> in member template "
"conversion operator can never be deduced");
}
return type_specified;

View File

@ -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 %<auto%> 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 '<type error>'
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);

View File

@ -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))

View File

@ -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;
}
}

View File

@ -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 %<auto%> return type can be "
"deduced to %<void%>");
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

View File

@ -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;

View File

@ -1,3 +1,20 @@
2012-03-21 Jason Merrill <jason@redhat.com>
* 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 <rguenther@suse.de>
PR tree-optimization/52678

View File

@ -2,5 +2,5 @@
void f()
{
auto val = val; // { dg-error "auto. type used in its own initializer" }
auto val = val; // { dg-error "auto" }
}

View File

@ -1,5 +1,5 @@
// Negative test for auto
// { dg-options "-std=c++0x" }
// { dg-do compile { target c++11 } }
#include <initializer_list>
@ -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<class T>
struct A { };

View File

@ -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" }

View File

@ -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);

View File

@ -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 <class T>
auto f(T t) { return t; }
template<> auto f<int>(int);
template auto f<float>(float);
template<> auto f(int*);
template auto f(float*);
template<> short f<short>(short); // { dg-error "does not match" }
template char f<char>(char); // { dg-error "does not match" }
template<> short f(short*); // { dg-error "does not match" }
template char f(char*); // { dg-error "does not match" }

View File

@ -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" }

View File

@ -0,0 +1,14 @@
// { dg-options -std=c++1y }
// { dg-final { scan-assembler "_ZN1AIiEcviEv" } }
template <class T>
struct A {
T t;
operator auto() { return t+1; }
};
int main()
{
int i = A<int>{42};
return (i != 43);
}

View File

@ -0,0 +1,6 @@
// { dg-options -std=c++1y }
struct A {
template <class T>
operator auto() { return T(); } // { dg-warning "auto.*template" }
};

View File

@ -0,0 +1,3 @@
// { dg-options -std=c++1y }
auto f() { return f(); } // { dg-error "auto" }

View File

@ -0,0 +1,10 @@
// { dg-options -std=c++1y }
bool b;
auto f()
{
if (b)
return 42;
else
return f();
}

View File

@ -0,0 +1,7 @@
// { dg-options -std=c++1y }
template <class T>
constexpr auto f(T t) { return t+1; }
#define SA(X) static_assert((X),#X)
SA(f(1)==2);

View File

@ -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;
}

View File

@ -0,0 +1,18 @@
// { dg-options -std=c++1y }
template <class T, class U> struct ST;
template <class T> struct ST<T,T> {};
int g(int);
char& g(char);
double&& g(double);
template <class T> auto&& f(T t)
{ return g(t); } // { dg-warning "reference to temporary" }
int main()
{
ST<decltype(f(1)),int&&>();
ST<decltype(f('\0')),char&>();
ST<decltype(f(1.0)),double&&>();
}

View File

@ -0,0 +1,5 @@
// { dg-options "-std=c++1y -pedantic-errors" }
auto f();
template <class T> auto f(T);

View File

@ -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 <class T> auto f(T t) { return t; }
template <class T> T f(T t);
int main()
{
f(42); // { dg-error "ambiguous" }
}

View File

@ -0,0 +1,11 @@
// { dg-options -std=c++1y }
// { dg-final { scan-assembler "_Z1fIiERDaRKT_S1_" } }
template <class T>
auto& f(const T& t, T u) { return t; }
int main()
{
int i;
f(i,i);
}

View File

@ -6,7 +6,7 @@ template<int> 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" }
;
}

View File

@ -6,4 +6,4 @@ int
foo (void)
{
return; // { dg-error "with no value" }
} // { dg-warning "no return statement" }
} // { dg-bogus "no return statement" }

View File

@ -10,6 +10,6 @@ struct S
template <class T>
template <> // { dg-error "enclosing class templates|invalid explicit specialization" }
void S<T>::f<int> () // { dg-error "does not match|invalid function declaration" }
void S<T>::f<int> ()
{
}