summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2012-03-24 16:56:08 -0400
committerJason Merrill <jason@gcc.gnu.org>2012-03-24 16:56:08 -0400
commit852497a31e9bc5d98c1ada24d38d7ec7ab93f8a9 (patch)
treef4083b8417d9f0e518dd8e9e301138cb94c4b2a5
parent8c5f2327427996b4b25ad6a4e0ce69832d025ea2 (diff)
downloadgcc-852497a31e9bc5d98c1ada24d38d7ec7ab93f8a9.tar.gz
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
-rw-r--r--gcc/cp/ChangeLog47
-rw-r--r--gcc/cp/cp-tree.h26
-rw-r--r--gcc/cp/decl.c64
-rw-r--r--gcc/cp/decl2.c19
-rw-r--r--gcc/cp/parser.c21
-rw-r--r--gcc/cp/pt.c78
-rw-r--r--gcc/cp/search.c5
-rw-r--r--gcc/cp/semantics.c40
-rw-r--r--gcc/cp/typeck.c95
-rw-r--r--gcc/cp/typeck2.c3
-rw-r--r--gcc/testsuite/ChangeLog17
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto18.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto3.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/trailing2.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn1.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn10.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn11.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn12.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn13.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn2.C3
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn3.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn4.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn5.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn6.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn7.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn8.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn9.C11
-rw-r--r--gcc/testsuite/g++.dg/gomp/pr38639.C2
-rw-r--r--gcc/testsuite/g++.dg/warn/pr23075.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/spec22.C2
30 files changed, 405 insertions, 148 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0fc0bd8a7f6..9cd2711e0a9 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index fc60d860108..7d986a8cf73 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e664d43285b..f021edf36e5 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 7eccf672546..b048ac7b3cd 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 75b7bdb046a..eac60f13572 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b36e49d4a07..f128947ead8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index bd1bc576429..14d272e10e8 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -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))
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 5646fa74717..6294e19af60 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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;
}
}
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index d2d6c4ef049..b68de52a13e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 974f92ff89c..80a1d0462ce 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a6b64242bae..94120525c34 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto18.C b/gcc/testsuite/g++.dg/cpp0x/auto18.C
index 17f7f995955..0a59242ab29 100644
--- a/gcc/testsuite/g++.dg/cpp0x/auto18.C
+++ b/gcc/testsuite/g++.dg/cpp0x/auto18.C
@@ -2,5 +2,5 @@
void f()
{
- auto val = val; // { dg-error "auto. type used in its own initializer" }
+ auto val = val; // { dg-error "auto" }
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto3.C b/gcc/testsuite/g++.dg/cpp0x/auto3.C
index 860790d7d3c..2b51d3191d1 100644
--- a/gcc/testsuite/g++.dg/cpp0x/auto3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/auto3.C
@@ -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 { };
diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing2.C b/gcc/testsuite/g++.dg/cpp0x/trailing2.C
index 5f5af22947f..91e55578d9b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/trailing2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/trailing2.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn1.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn1.C
new file mode 100644
index 00000000000..eb541490bb3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn1.C
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn10.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn10.C
new file mode 100644
index 00000000000..e3ed3a93352
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn10.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn11.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn11.C
new file mode 100644
index 00000000000..a9984aa54a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn11.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C
new file mode 100644
index 00000000000..e4e58e8999a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn12.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn13.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn13.C
new file mode 100644
index 00000000000..34a61ae20e3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn13.C
@@ -0,0 +1,6 @@
+// { dg-options -std=c++1y }
+
+struct A {
+ template <class T>
+ operator auto() { return T(); } // { dg-warning "auto.*template" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn2.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn2.C
new file mode 100644
index 00000000000..4c2cee7d285
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn2.C
@@ -0,0 +1,3 @@
+// { dg-options -std=c++1y }
+
+auto f() { return f(); } // { dg-error "auto" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn3.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn3.C
new file mode 100644
index 00000000000..107c37f915d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn3.C
@@ -0,0 +1,10 @@
+// { dg-options -std=c++1y }
+
+bool b;
+auto f()
+{
+ if (b)
+ return 42;
+ else
+ return f();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn4.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn4.C
new file mode 100644
index 00000000000..0b76bfce03a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn4.C
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn5.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn5.C
new file mode 100644
index 00000000000..f9af6c2fee0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn5.C
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn6.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn6.C
new file mode 100644
index 00000000000..03ff537b239
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn6.C
@@ -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&&>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn7.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn7.C
new file mode 100644
index 00000000000..b915352a41c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn7.C
@@ -0,0 +1,5 @@
+// { dg-options "-std=c++1y -pedantic-errors" }
+
+auto f();
+
+template <class T> auto f(T);
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn8.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn8.C
new file mode 100644
index 00000000000..dcec899379b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn8.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn9.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn9.C
new file mode 100644
index 00000000000..1fa747942cd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn9.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/gomp/pr38639.C b/gcc/testsuite/g++.dg/gomp/pr38639.C
index e7145ffbeb9..481583e80e3 100644
--- a/gcc/testsuite/g++.dg/gomp/pr38639.C
+++ b/gcc/testsuite/g++.dg/gomp/pr38639.C
@@ -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" }
;
}
diff --git a/gcc/testsuite/g++.dg/warn/pr23075.C b/gcc/testsuite/g++.dg/warn/pr23075.C
index e5b1b483d76..59e93be48f8 100644
--- a/gcc/testsuite/g++.dg/warn/pr23075.C
+++ b/gcc/testsuite/g++.dg/warn/pr23075.C
@@ -6,4 +6,4 @@ int
foo (void)
{
return; // { dg-error "with no value" }
-} // { dg-warning "no return statement" }
+} // { dg-bogus "no return statement" }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec22.C b/gcc/testsuite/g++.old-deja/g++.pt/spec22.C
index 41aab394d3e..94bffdbecaa 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/spec22.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/spec22.C
@@ -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> ()
{
}