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:
parent
8c5f232742
commit
852497a31e
|
@ -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>
|
2012-03-22 Paolo Carlini <paolo.carlini@oracle.com>
|
||||||
|
|
||||||
PR c++/52487
|
PR c++/52487
|
||||||
|
|
|
@ -96,8 +96,8 @@ c-common.h, not after.
|
||||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
|
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
|
||||||
STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
|
STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
|
||||||
TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
|
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)
|
TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
|
||||||
|
FNDECL_USED_AUTO (in FUNCTION_DECL)
|
||||||
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
|
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
|
||||||
ICS_BAD_FLAG (in _CONV)
|
ICS_BAD_FLAG (in _CONV)
|
||||||
FN_TRY_BLOCK_P (in TRY_BLOCK)
|
FN_TRY_BLOCK_P (in TRY_BLOCK)
|
||||||
|
@ -660,11 +660,6 @@ enum cp_lambda_default_capture_mode_type {
|
||||||
#define LAMBDA_EXPR_MUTABLE_P(NODE) \
|
#define LAMBDA_EXPR_MUTABLE_P(NODE) \
|
||||||
TREE_LANG_FLAG_1 (LAMBDA_EXPR_CHECK (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.
|
/* The return type in the expression.
|
||||||
* NULL_TREE indicates that none was specified. */
|
* NULL_TREE indicates that none was specified. */
|
||||||
#define LAMBDA_EXPR_RETURN_TYPE(NODE) \
|
#define LAMBDA_EXPR_RETURN_TYPE(NODE) \
|
||||||
|
@ -804,7 +799,6 @@ enum cp_tree_index
|
||||||
CPTI_CLASS_TYPE,
|
CPTI_CLASS_TYPE,
|
||||||
CPTI_UNKNOWN_TYPE,
|
CPTI_UNKNOWN_TYPE,
|
||||||
CPTI_INIT_LIST_TYPE,
|
CPTI_INIT_LIST_TYPE,
|
||||||
CPTI_DEPENDENT_LAMBDA_RETURN_TYPE,
|
|
||||||
CPTI_VTBL_TYPE,
|
CPTI_VTBL_TYPE,
|
||||||
CPTI_VTBL_PTR_TYPE,
|
CPTI_VTBL_PTR_TYPE,
|
||||||
CPTI_STD,
|
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 class_type_node cp_global_trees[CPTI_CLASS_TYPE]
|
||||||
#define unknown_type_node cp_global_trees[CPTI_UNKNOWN_TYPE]
|
#define unknown_type_node cp_global_trees[CPTI_UNKNOWN_TYPE]
|
||||||
#define init_list_type_node cp_global_trees[CPTI_INIT_LIST_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_type_node cp_global_trees[CPTI_VTBL_TYPE]
|
||||||
#define vtbl_ptr_type_node cp_global_trees[CPTI_VTBL_PTR_TYPE]
|
#define vtbl_ptr_type_node cp_global_trees[CPTI_VTBL_PTR_TYPE]
|
||||||
#define std_node cp_global_trees[CPTI_STD]
|
#define std_node cp_global_trees[CPTI_STD]
|
||||||
|
@ -1076,6 +1069,7 @@ struct GTY(()) language_function {
|
||||||
tree x_in_charge_parm;
|
tree x_in_charge_parm;
|
||||||
tree x_vtt_parm;
|
tree x_vtt_parm;
|
||||||
tree x_return_value;
|
tree x_return_value;
|
||||||
|
tree x_auto_return_pattern;
|
||||||
|
|
||||||
BOOL_BITFIELD returns_value : 1;
|
BOOL_BITFIELD returns_value : 1;
|
||||||
BOOL_BITFIELD returns_null : 1;
|
BOOL_BITFIELD returns_null : 1;
|
||||||
|
@ -1158,6 +1152,11 @@ struct GTY(()) language_function {
|
||||||
#define current_function_return_value \
|
#define current_function_return_value \
|
||||||
(cp_function_chain->x_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
|
/* True if NAME is the IDENTIFIER_NODE for an overloaded "operator
|
||||||
new" or "operator delete". */
|
new" or "operator delete". */
|
||||||
#define NEW_DELETE_OPNAME_P(NAME) \
|
#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) \
|
#define DECL_LOCAL_FUNCTION_P(NODE) \
|
||||||
DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (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
|
/* 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
|
been explicitly declared, such as a built-in function or a friend
|
||||||
declared inside a class. In the latter case DECL_HIDDEN_FRIEND_P
|
declared inside a class. In the latter case DECL_HIDDEN_FRIEND_P
|
||||||
|
@ -4144,6 +4150,8 @@ enum tsubst_flags {
|
||||||
conversion. */
|
conversion. */
|
||||||
tf_no_access_control = 1 << 7, /* Do not perform access checks, even
|
tf_no_access_control = 1 << 7, /* Do not perform access checks, even
|
||||||
when issuing other errors. */
|
when issuing other errors. */
|
||||||
|
tf_partial = 1 << 8, /* Doing initial explicit argument
|
||||||
|
substitution in fn_type_unification. */
|
||||||
/* Convenient substitution flags combinations. */
|
/* Convenient substitution flags combinations. */
|
||||||
tf_warning_or_error = tf_warning | tf_error
|
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_return_type (tree);
|
||||||
extern tree lambda_proxy_type (tree);
|
extern tree lambda_proxy_type (tree);
|
||||||
extern tree lambda_function (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_capture (tree, tree, tree, bool, bool);
|
||||||
extern tree add_default_capture (tree, tree, tree);
|
extern tree add_default_capture (tree, tree, tree);
|
||||||
extern tree build_capture_proxy (tree);
|
extern tree build_capture_proxy (tree);
|
||||||
|
|
|
@ -960,6 +960,7 @@ decls_match (tree newdecl, tree olddecl)
|
||||||
tree f2 = TREE_TYPE (olddecl);
|
tree f2 = TREE_TYPE (olddecl);
|
||||||
tree p1 = TYPE_ARG_TYPES (f1);
|
tree p1 = TYPE_ARG_TYPES (f1);
|
||||||
tree p2 = TYPE_ARG_TYPES (f2);
|
tree p2 = TYPE_ARG_TYPES (f2);
|
||||||
|
tree r2;
|
||||||
|
|
||||||
/* Specializations of different templates are different functions
|
/* Specializations of different templates are different functions
|
||||||
even if they have the same type. */
|
even if they have the same type. */
|
||||||
|
@ -988,7 +989,14 @@ decls_match (tree newdecl, tree olddecl)
|
||||||
if (TREE_CODE (f1) != TREE_CODE (f2))
|
if (TREE_CODE (f1) != TREE_CODE (f2))
|
||||||
return 0;
|
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)
|
if (!prototype_p (f2) && DECL_EXTERN_C_P (olddecl)
|
||||||
&& (DECL_BUILT_IN (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))))
|
TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
|
||||||
{
|
{
|
||||||
error ("new declaration %q#D", newdecl);
|
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;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -3644,10 +3656,6 @@ cxx_init_decl_processing (void)
|
||||||
init_list_type_node = make_node (LANG_TYPE);
|
init_list_type_node = make_node (LANG_TYPE);
|
||||||
record_unknown_type (init_list_type_node, "init list");
|
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
|
/* Make sure we get a unique function type, so we can give
|
||||||
its pointer type a name. (This wins for gdb.) */
|
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_INITIAL (decl) || init))
|
||||||
DECL_INITIALIZED_IN_CLASS_P (decl) = 1;
|
DECL_INITIALIZED_IN_CLASS_P (decl) = 1;
|
||||||
|
|
||||||
auto_node = type_uses_auto (type);
|
if (TREE_CODE (decl) != FUNCTION_DECL
|
||||||
if (auto_node)
|
&& (auto_node = type_uses_auto (type)))
|
||||||
{
|
{
|
||||||
tree d_init;
|
tree d_init;
|
||||||
if (init == NULL_TREE)
|
if (init == NULL_TREE)
|
||||||
|
@ -9188,9 +9196,13 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
{
|
{
|
||||||
if (!declarator->u.function.late_return_type)
|
if (!declarator->u.function.late_return_type)
|
||||||
{
|
{
|
||||||
error ("%qs function uses %<auto%> type specifier without"
|
if (current_class_type
|
||||||
" trailing return type", name);
|
&& LAMBDA_TYPE_P (current_class_type))
|
||||||
return error_mark_node;
|
/* 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))
|
else if (!is_auto (type))
|
||||||
{
|
{
|
||||||
|
@ -10029,7 +10041,8 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
}
|
}
|
||||||
else if (decl_context == FIELD)
|
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%>");
|
error ("non-static data member declared %<auto%>");
|
||||||
type = error_mark_node;
|
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. */
|
/* In a function definition, arg types must be complete. */
|
||||||
require_complete_types_for_parms (current_function_parms);
|
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;
|
return;
|
||||||
if (!COMPLETE_OR_VOID_TYPE_P (return_type)
|
if (!COMPLETE_OR_VOID_TYPE_P (return_type)
|
||||||
|| (TYPE_FOR_JAVA (return_type) && MAYBE_CLASS_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. */
|
/* Build the return declaration for the function. */
|
||||||
restype = TREE_TYPE (fntype);
|
restype = TREE_TYPE (fntype);
|
||||||
|
|
||||||
if (DECL_RESULT (decl1) == NULL_TREE)
|
if (DECL_RESULT (decl1) == NULL_TREE)
|
||||||
{
|
{
|
||||||
tree resdecl;
|
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_stmt_tree ()->stmts_are_full_exprs_p = 1;
|
||||||
current_binding_level = bl;
|
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. */
|
/* Start the statement-tree, start the tree now. */
|
||||||
DECL_SAVED_TREE (decl1) = push_stmt_list ();
|
DECL_SAVED_TREE (decl1) = push_stmt_list ();
|
||||||
|
|
||||||
|
@ -13463,6 +13484,23 @@ finish_function (int flags)
|
||||||
of curly braces for a function. */
|
of curly braces for a function. */
|
||||||
gcc_assert (stmts_are_full_exprs_p ());
|
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
|
/* Save constexpr function body before it gets munged by
|
||||||
the NRV transformation. */
|
the NRV transformation. */
|
||||||
maybe_save_function_definition (fndecl);
|
maybe_save_function_definition (fndecl);
|
||||||
|
|
|
@ -151,6 +151,9 @@ change_return_type (tree new_ret, tree fntype)
|
||||||
tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
|
tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
|
||||||
tree attrs = TYPE_ATTRIBUTES (fntype);
|
tree attrs = TYPE_ATTRIBUTES (fntype);
|
||||||
|
|
||||||
|
if (new_ret == error_mark_node)
|
||||||
|
return fntype;
|
||||||
|
|
||||||
if (same_type_p (new_ret, TREE_TYPE (fntype)))
|
if (same_type_p (new_ret, TREE_TYPE (fntype)))
|
||||||
return fntype;
|
return fntype;
|
||||||
|
|
||||||
|
@ -4281,7 +4284,11 @@ mark_used (tree decl)
|
||||||
if ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
|
if ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
|
||||||
|| DECL_LANG_SPECIFIC (decl) == NULL
|
|| DECL_LANG_SPECIFIC (decl) == NULL
|
||||||
|| DECL_THUNK_P (decl))
|
|| 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
|
/* 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
|
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.
|
/* Normally, we can wait until instantiation-time to synthesize DECL.
|
||||||
However, if DECL is a static data member initialized with a constant
|
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
|
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)
|
if ((decl_maybe_constant_var_p (decl)
|
||||||
|| (TREE_CODE (decl) == FUNCTION_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_LANG_SPECIFIC (decl)
|
||||||
&& DECL_TEMPLATE_INFO (decl)
|
&& DECL_TEMPLATE_INFO (decl)
|
||||||
&& !uses_template_parms (DECL_TI_ARGS (decl)))
|
&& !uses_template_parms (DECL_TI_ARGS (decl)))
|
||||||
|
@ -4321,6 +4331,9 @@ mark_used (tree decl)
|
||||||
--function_depth;
|
--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 we don't need a value, then we don't need to synthesize DECL. */
|
||||||
if (cp_unevaluated_operand != 0)
|
if (cp_unevaluated_operand != 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -8416,9 +8416,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
|
||||||
if (LAMBDA_EXPR_RETURN_TYPE (lambda_expr))
|
if (LAMBDA_EXPR_RETURN_TYPE (lambda_expr))
|
||||||
return_type_specs.type = LAMBDA_EXPR_RETURN_TYPE (lambda_expr);
|
return_type_specs.type = LAMBDA_EXPR_RETURN_TYPE (lambda_expr);
|
||||||
else
|
else
|
||||||
/* Maybe we will deduce the return type later, but we can use void
|
/* Maybe we will deduce the return type later. */
|
||||||
as a placeholder return type anyways. */
|
return_type_specs.type = make_auto ();
|
||||||
return_type_specs.type = void_type_node;
|
|
||||||
|
|
||||||
p = obstack_alloc (&declarator_obstack, 0);
|
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))
|
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. */
|
/* Will get error here if type not deduced yet. */
|
||||||
finish_return_stmt (expr);
|
finish_return_stmt (expr);
|
||||||
|
@ -8550,13 +8550,10 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
|
||||||
|
|
||||||
if (!done)
|
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))
|
while (cp_lexer_next_token_is_keyword (parser->lexer, RID_LABEL))
|
||||||
cp_parser_label_declaration (parser);
|
cp_parser_label_declaration (parser);
|
||||||
cp_parser_statement_seq_opt (parser, NULL_TREE);
|
cp_parser_statement_seq_opt (parser, NULL_TREE);
|
||||||
cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
|
cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
|
||||||
LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda_expr) = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finish_compound_stmt (compound_stmt);
|
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)
|
if (! cp_parser_uncommitted_to_tentative_parse_p (parser)
|
||||||
&& type_uses_auto (type_specified))
|
&& type_uses_auto (type_specified))
|
||||||
{
|
{
|
||||||
error ("invalid use of %<auto%> in conversion operator");
|
if (cxx_dialect < cxx1y)
|
||||||
return error_mark_node;
|
{
|
||||||
|
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;
|
return type_specified;
|
||||||
|
|
78
gcc/cp/pt.c
78
gcc/cp/pt.c
|
@ -9112,12 +9112,6 @@ instantiate_class_template_1 (tree type)
|
||||||
tree decl = lambda_function (type);
|
tree decl = lambda_function (type);
|
||||||
if (decl)
|
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);
|
instantiate_decl (decl, false, false);
|
||||||
maybe_add_lambda_conv_op (type);
|
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. */
|
about the template parameter in question. */
|
||||||
return t;
|
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
|
/* If we get here, we must have been looking at a parm for a
|
||||||
more deeply nested template. Make a new version of this
|
more deeply nested template. Make a new version of this
|
||||||
template parameter, but with a lower level. */
|
template parameter, but with a lower level. */
|
||||||
|
@ -14334,14 +14334,8 @@ tsubst_copy_and_build (tree t,
|
||||||
= (LAMBDA_EXPR_DISCRIMINATOR (t));
|
= (LAMBDA_EXPR_DISCRIMINATOR (t));
|
||||||
LAMBDA_EXPR_EXTRA_SCOPE (r)
|
LAMBDA_EXPR_EXTRA_SCOPE (r)
|
||||||
= RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t));
|
= RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t));
|
||||||
if (LAMBDA_EXPR_RETURN_TYPE (t) == dependent_lambda_return_type_node)
|
LAMBDA_EXPR_RETURN_TYPE (r)
|
||||||
{
|
= tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl);
|
||||||
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);
|
|
||||||
|
|
||||||
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
|
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
|
||||||
&& LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
|
&& LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
|
||||||
|
@ -14860,7 +14854,7 @@ fn_type_unification (tree fn,
|
||||||
fntype = deduction_tsubst_fntype (fn, converted_args,
|
fntype = deduction_tsubst_fntype (fn, converted_args,
|
||||||
(explain_p
|
(explain_p
|
||||||
? tf_warning_or_error
|
? tf_warning_or_error
|
||||||
: tf_none));
|
: tf_none) | tf_partial);
|
||||||
processing_template_decl -= incomplete;
|
processing_template_decl -= incomplete;
|
||||||
|
|
||||||
if (fntype == error_mark_node)
|
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. */
|
to see if it matches ARG. */
|
||||||
{
|
{
|
||||||
if (TREE_CODE (arg) == TREE_CODE (parm)
|
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);
|
return unify_success (explain_p);
|
||||||
else
|
else
|
||||||
return unify_type_mismatch (explain_p, parm, arg);
|
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
|
The call to fn_type_unification will handle substitution into the
|
||||||
FN. */
|
FN. */
|
||||||
decl_type = TREE_TYPE (decl);
|
decl_type = TREE_TYPE (decl);
|
||||||
if (explicit_args && uses_template_parms (decl_type))
|
if (explicit_args && decl == DECL_TEMPLATE_RESULT (fn))
|
||||||
{
|
{
|
||||||
tree tmpl;
|
tree tmpl;
|
||||||
tree converted_args;
|
tree converted_args;
|
||||||
|
@ -18315,7 +18310,8 @@ always_instantiate_p (tree decl)
|
||||||
that for "extern template" functions. Therefore, we check
|
that for "extern template" functions. Therefore, we check
|
||||||
DECL_DECLARED_INLINE_P, rather than possibly_inlined_p. */
|
DECL_DECLARED_INLINE_P, rather than possibly_inlined_p. */
|
||||||
return ((TREE_CODE (decl) == FUNCTION_DECL
|
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
|
/* And we need to instantiate static data members so that
|
||||||
their initializers are available in integral constant
|
their initializers are available in integral constant
|
||||||
expressions. */
|
expressions. */
|
||||||
|
@ -20269,20 +20265,6 @@ listify_autos (tree type, tree auto_node)
|
||||||
return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
|
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
|
/* 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. */
|
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 parms, tparms, targs;
|
||||||
tree args[1];
|
tree args[1];
|
||||||
tree decl;
|
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
|
if (init == error_mark_node)
|
||||||
|
return error_mark_node;
|
||||||
|
|
||||||
if (processing_template_decl
|
if (processing_template_decl
|
||||||
&& (TREE_TYPE (init) == NULL_TREE
|
&& (TREE_TYPE (init) == NULL_TREE
|
||||||
|| BRACE_ENCLOSED_INITIALIZER_P (init)))
|
|| BRACE_ENCLOSED_INITIALIZER_P (init)))
|
||||||
/* Not enough information to try this yet. */
|
/* Not enough information to try this yet. */
|
||||||
return type;
|
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
|
/* [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
|
with either a new invented type template parameter U or, if the
|
||||||
initializer is a braced-init-list (8.5.4), with
|
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
|
/* If type is error_mark_node a diagnostic must have been
|
||||||
emitted by now. Also, having a mention to '<type error>'
|
emitted by now. Also, having a mention to '<type error>'
|
||||||
in the diagnostic is not really useful to the user. */
|
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;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20348,8 +20328,14 @@ do_auto_deduction (tree type, tree init, tree auto_node)
|
||||||
if (TREE_TYPE (auto_node)
|
if (TREE_TYPE (auto_node)
|
||||||
&& !same_type_p (TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)))
|
&& !same_type_p (TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)))
|
||||||
{
|
{
|
||||||
error ("inconsistent deduction for %qT: %qT and then %qT",
|
if (cfun && auto_node == current_function_auto_return_pattern
|
||||||
auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0));
|
&& 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;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0);
|
TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0);
|
||||||
|
|
|
@ -2430,6 +2430,11 @@ lookup_conversions_r (tree binfo,
|
||||||
if (!IDENTIFIER_MARKED (name))
|
if (!IDENTIFIER_MARKED (name))
|
||||||
{
|
{
|
||||||
tree type = DECL_CONV_FN_TYPE (cur);
|
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,
|
if (check_hidden_convs (binfo, virtual_depth, virtualness,
|
||||||
type, parent_convs, other_convs))
|
type, parent_convs, other_convs))
|
||||||
|
|
|
@ -8691,18 +8691,16 @@ begin_lambda_type (tree lambda)
|
||||||
tree
|
tree
|
||||||
lambda_return_type (tree expr)
|
lambda_return_type (tree expr)
|
||||||
{
|
{
|
||||||
tree type;
|
if (expr == NULL_TREE)
|
||||||
|
return void_type_node;
|
||||||
if (type_unknown_p (expr)
|
if (type_unknown_p (expr)
|
||||||
|| BRACE_ENCLOSED_INITIALIZER_P (expr))
|
|| BRACE_ENCLOSED_INITIALIZER_P (expr))
|
||||||
{
|
{
|
||||||
cxx_incomplete_type_error (expr, TREE_TYPE (expr));
|
cxx_incomplete_type_error (expr, TREE_TYPE (expr));
|
||||||
return void_type_node;
|
return void_type_node;
|
||||||
}
|
}
|
||||||
if (type_dependent_expression_p (expr))
|
gcc_checking_assert (!type_dependent_expression_p (expr));
|
||||||
type = dependent_lambda_return_type_node;
|
return cv_unqualified (type_decays_to (unlowered_expr_type (expr)));
|
||||||
else
|
|
||||||
type = cv_unqualified (type_decays_to (unlowered_expr_type (expr)));
|
|
||||||
return type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given a LAMBDA_EXPR or closure type LAMBDA, return the op() of the
|
/* 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;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Recompute the return type for LAMBDA with body of the form:
|
/* Insert the deduced return type for an auto function. */
|
||||||
{ return EXPR ; } */
|
|
||||||
|
|
||||||
void
|
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;
|
tree result;
|
||||||
|
|
||||||
LAMBDA_EXPR_RETURN_TYPE (lambda) = return_type;
|
|
||||||
|
|
||||||
if (return_type == error_mark_node)
|
if (return_type == error_mark_node)
|
||||||
return;
|
return;
|
||||||
if (TREE_TYPE (TREE_TYPE (fco)) == return_type)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* TREE_TYPE (FUNCTION_DECL) == METHOD_TYPE
|
if (LAMBDA_FUNCTION_P (fco))
|
||||||
TREE_TYPE (METHOD_TYPE) == return-type */
|
{
|
||||||
|
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));
|
TREE_TYPE (fco) = change_return_type (return_type, TREE_TYPE (fco));
|
||||||
|
|
||||||
result = DECL_RESULT (fco);
|
result = DECL_RESULT (fco);
|
||||||
if (result == NULL_TREE)
|
if (result == NULL_TREE)
|
||||||
return;
|
return;
|
||||||
|
if (TREE_TYPE (result) == return_type)
|
||||||
|
return;
|
||||||
|
|
||||||
/* We already have a DECL_RESULT from start_preparsed_function.
|
/* We already have a DECL_RESULT from start_preparsed_function.
|
||||||
Now we need to redo the work it and allocate_struct_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;
|
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
|
#ifdef PCC_STATIC_STRUCT_RETURN
|
||||||
cfun->returns_pcc_struct = 1;
|
cfun->returns_pcc_struct = aggr;
|
||||||
#endif
|
#endif
|
||||||
cfun->returns_struct = 1;
|
cfun->returns_struct = aggr;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -733,6 +733,11 @@ merge_types (tree t1, tree t2)
|
||||||
if (t2 == error_mark_node)
|
if (t2 == error_mark_node)
|
||||||
return t1;
|
return t1;
|
||||||
|
|
||||||
|
/* Handle merging an auto redeclaration with a previous deduced
|
||||||
|
return type. */
|
||||||
|
if (is_auto (t1))
|
||||||
|
return t2;
|
||||||
|
|
||||||
/* Merge the attributes. */
|
/* Merge the attributes. */
|
||||||
attributes = (*targetm.merge_type_attributes) (t1, t2);
|
attributes = (*targetm.merge_type_attributes) (t1, t2);
|
||||||
|
|
||||||
|
@ -7779,9 +7784,11 @@ tree
|
||||||
check_return_expr (tree retval, bool *no_warning)
|
check_return_expr (tree retval, bool *no_warning)
|
||||||
{
|
{
|
||||||
tree result;
|
tree result;
|
||||||
/* The type actually returned by the function, after any
|
/* The type actually returned by the function. */
|
||||||
promotions. */
|
|
||||||
tree valtype;
|
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;
|
int fn_returns_value_p;
|
||||||
bool named_return_value_okay_p;
|
bool named_return_value_okay_p;
|
||||||
|
|
||||||
|
@ -7812,30 +7819,6 @@ check_return_expr (tree retval, bool *no_warning)
|
||||||
return NULL_TREE;
|
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)
|
if (processing_template_decl)
|
||||||
{
|
{
|
||||||
current_function_returns_value = 1;
|
current_function_returns_value = 1;
|
||||||
|
@ -7844,6 +7827,42 @@ check_return_expr (tree retval, bool *no_warning)
|
||||||
return retval;
|
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
|
/* When no explicit return-value is given in a function with a named
|
||||||
return value, the named return value is used. */
|
return value, the named return value is used. */
|
||||||
result = DECL_RESULT (current_function_decl);
|
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. */
|
that's supposed to return a value. */
|
||||||
if (!retval && fn_returns_value_p)
|
if (!retval && fn_returns_value_p)
|
||||||
{
|
{
|
||||||
permerror (input_location, "return-statement with no value, in function returning %qT",
|
if (functype != error_mark_node)
|
||||||
valtype);
|
permerror (input_location, "return-statement with no value, in "
|
||||||
/* Clear this, so finish_function won't say that we reach the
|
"function returning %qT", valtype);
|
||||||
end of a non-void function (which we don't, we gave a
|
/* Remember that this function did return. */
|
||||||
return!). */
|
current_function_returns_value = 1;
|
||||||
current_function_returns_null = 0;
|
|
||||||
/* And signal caller that TREE_NO_WARNING should be set on the
|
/* And signal caller that TREE_NO_WARNING should be set on the
|
||||||
RETURN_EXPR to avoid control reaches end of non-void function
|
RETURN_EXPR to avoid control reaches end of non-void function
|
||||||
warnings in tree-cfg.c. */
|
warnings in tree-cfg.c. */
|
||||||
|
@ -7963,14 +7981,12 @@ check_return_expr (tree retval, bool *no_warning)
|
||||||
&& DECL_CONTEXT (retval) == current_function_decl
|
&& DECL_CONTEXT (retval) == current_function_decl
|
||||||
&& ! TREE_STATIC (retval)
|
&& ! TREE_STATIC (retval)
|
||||||
&& ! DECL_ANON_UNION_VAR_P (retval)
|
&& ! DECL_ANON_UNION_VAR_P (retval)
|
||||||
&& (DECL_ALIGN (retval)
|
&& (DECL_ALIGN (retval) >= DECL_ALIGN (result))
|
||||||
>= DECL_ALIGN (DECL_RESULT (current_function_decl)))
|
|
||||||
/* The cv-unqualified type of the returned value must be the
|
/* The cv-unqualified type of the returned value must be the
|
||||||
same as the cv-unqualified return type of the
|
same as the cv-unqualified return type of the
|
||||||
function. */
|
function. */
|
||||||
&& same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
|
&& same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
|
||||||
(TYPE_MAIN_VARIANT
|
(TYPE_MAIN_VARIANT (functype)))
|
||||||
(TREE_TYPE (TREE_TYPE (current_function_decl)))))
|
|
||||||
/* And the returned value must be non-volatile. */
|
/* And the returned value must be non-volatile. */
|
||||||
&& ! TYPE_VOLATILE (TREE_TYPE (retval)));
|
&& ! TYPE_VOLATILE (TREE_TYPE (retval)));
|
||||||
|
|
||||||
|
@ -7995,8 +8011,6 @@ check_return_expr (tree retval, bool *no_warning)
|
||||||
;
|
;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The type the function is declared to return. */
|
|
||||||
tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
|
|
||||||
int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
|
int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
|
||||||
|
|
||||||
/* The functype's return type will have been set to void, if it
|
/* 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
|
&& DECL_CONTEXT (retval) == current_function_decl
|
||||||
&& !TREE_STATIC (retval)
|
&& !TREE_STATIC (retval)
|
||||||
&& same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
|
&& same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
|
||||||
(TYPE_MAIN_VARIANT
|
(TYPE_MAIN_VARIANT (functype)))
|
||||||
(TREE_TYPE (TREE_TYPE (current_function_decl)))))
|
|
||||||
/* This is only interesting for class type. */
|
/* 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;
|
flags = flags | LOOKUP_PREFER_RVALUE;
|
||||||
|
|
||||||
/* First convert the value to the function's return type, then
|
/* First convert the value to the function's return type, then
|
||||||
|
|
|
@ -1818,7 +1818,8 @@ add_exception_specifier (tree list, tree spec, int complain)
|
||||||
else
|
else
|
||||||
diag_type = DK_ERROR; /* error */
|
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);
|
cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
|
|
@ -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>
|
2012-03-23 Richard Guenther <rguenther@suse.de>
|
||||||
|
|
||||||
PR tree-optimization/52678
|
PR tree-optimization/52678
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
void f()
|
void f()
|
||||||
{
|
{
|
||||||
auto val = val; // { dg-error "auto. type used in its own initializer" }
|
auto val = val; // { dg-error "auto" }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Negative test for auto
|
// Negative test for auto
|
||||||
// { dg-options "-std=c++0x" }
|
// { dg-do compile { target c++11 } }
|
||||||
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ auto x; // { dg-error "auto" }
|
||||||
auto i = 42, j = 42.0; // { dg-error "auto" }
|
auto i = 42, j = 42.0; // { dg-error "auto" }
|
||||||
|
|
||||||
// New CWG issue
|
// 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>
|
template<class T>
|
||||||
struct A { };
|
struct A { };
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// PR c++/37967
|
// PR c++/37967
|
||||||
// Negative test for auto
|
// Negative test for auto
|
||||||
// { dg-options "-std=c++0x" }
|
// { dg-do compile { target c++11 } }
|
||||||
|
|
||||||
auto f1 () -> int;
|
auto f1 () -> int;
|
||||||
auto f2 (); // { dg-error "without trailing return type" }
|
auto f2 (); // { dg-error "without trailing return type" }
|
||||||
|
|
|
@ -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);
|
|
@ -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" }
|
|
@ -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" }
|
|
@ -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);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
// { dg-options -std=c++1y }
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
template <class T>
|
||||||
|
operator auto() { return T(); } // { dg-warning "auto.*template" }
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
// { dg-options -std=c++1y }
|
||||||
|
|
||||||
|
auto f() { return f(); } // { dg-error "auto" }
|
|
@ -0,0 +1,10 @@
|
||||||
|
// { dg-options -std=c++1y }
|
||||||
|
|
||||||
|
bool b;
|
||||||
|
auto f()
|
||||||
|
{
|
||||||
|
if (b)
|
||||||
|
return 42;
|
||||||
|
else
|
||||||
|
return f();
|
||||||
|
}
|
|
@ -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);
|
|
@ -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;
|
||||||
|
}
|
|
@ -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&&>();
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
// { dg-options "-std=c++1y -pedantic-errors" }
|
||||||
|
|
||||||
|
auto f();
|
||||||
|
|
||||||
|
template <class T> auto f(T);
|
|
@ -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" }
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ template<int> void
|
||||||
foo ()
|
foo ()
|
||||||
{
|
{
|
||||||
#pragma omp parallel for
|
#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" }
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,4 @@ int
|
||||||
foo (void)
|
foo (void)
|
||||||
{
|
{
|
||||||
return; // { dg-error "with no value" }
|
return; // { dg-error "with no value" }
|
||||||
} // { dg-warning "no return statement" }
|
} // { dg-bogus "no return statement" }
|
||||||
|
|
|
@ -10,6 +10,6 @@ struct S
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
template <> // { dg-error "enclosing class templates|invalid explicit specialization" }
|
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> ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue