Implement return type deduction for normal functions with -std=c++1y.
authorJason Merrill <jason@redhat.com>
Sat, 24 Mar 2012 20:56:08 +0000 (16:56 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 24 Mar 2012 20:56:08 +0000 (16:56 -0400)
* 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

30 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/search.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/auto18.C
gcc/testsuite/g++.dg/cpp0x/auto3.C
gcc/testsuite/g++.dg/cpp0x/trailing2.C
gcc/testsuite/g++.dg/cpp1y/auto-fn1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/auto-fn9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/pr38639.C
gcc/testsuite/g++.dg/warn/pr23075.C
gcc/testsuite/g++.old-deja/g++.pt/spec22.C

index 0fc0bd8a7f64c21dc4d2f32fcb23eb55a0d19e20..9cd2711e0a979de8372082783a86efb8a32d4627 100644 (file)
@@ -1,3 +1,50 @@
+2012-03-21  Jason Merrill  <jason@redhat.com>
+
+       Implement return type deduction for normal functions with -std=c++1y.
+       * cp-tree.h (FNDECL_USED_AUTO): New macro.
+       (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P): Remove.
+       (dependent_lambda_return_type_node): Remove.
+       (CPTI_DEPENDENT_LAMBDA_RETURN_TYPE): Remove.
+       (struct language_function): Add x_auto_return_pattern field.
+       (current_function_auto_return_pattern): New.
+       (enum tsubst_flags): Add tf_partial.
+       * decl.c (decls_match): Handle auto return comparison.
+       (duplicate_decls): Adjust error message for auto return.
+       (cxx_init_decl_processing): Remove dependent_lambda_return_type_node.
+       (cp_finish_decl): Don't do auto deduction for functions.
+       (grokdeclarator): Allow auto return without trailing return type in
+       C++1y mode.
+       (check_function_type): Defer checking of deduced return type.
+       (start_preparsed_function): Set current_function_auto_return_pattern.
+       (finish_function): Set deduced return type to void if not previously
+       deduced.
+       * decl2.c (change_return_type): Handle error_mark_node.
+       (mark_used): Always instantiate functions with deduced return type.
+       Complain about use if deduction isn't done.
+       * parser.c (cp_parser_lambda_declarator_opt): Use 'auto' for
+       initial return type.
+       (cp_parser_lambda_body): Don't deduce return type in a template.
+       (cp_parser_conversion_type_id): Allow auto in C++1y.
+       * pt.c (instantiate_class_template_1): Don't mess with
+       LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P.
+       (tsubst_copy_and_build): Likewise.
+       (fn_type_unification, tsubst): Don't reduce the template parm level
+       of 'auto' during deduction.
+       (unify): Compare 'auto' specially.
+       (get_bindings): Change test.
+       (always_instantiate_p): Always instantiate functions with deduced
+       return type.
+       (do_auto_deduction): Handle error_mark_node and lambda context.
+       Don't check for use in initializer.
+       (contains_auto_r): Remove.
+       * search.c (lookup_conversions_r): Handle auto conversion function.
+       * semantics.c (lambda_return_type): Handle null return.  Don't mess
+       with dependent_lambda_return_type_node.
+       (apply_deduced_return_type): Rename from apply_lambda_return_type.
+       * typeck.c (merge_types): Handle auto.
+       (check_return_expr): Do auto deduction.
+       * typeck2.c (add_exception_specifier): Fix complain check.
+
 2012-03-22  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/52487
index fc60d860108ef23d6c158df65f8a3b9ec374fafc..7d986a8cf735131a5f8c3620ad37921008124580 100644 (file)
@@ -96,8 +96,8 @@ c-common.h, not after.
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
       STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
       TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
-      LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR)
       TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
+      FNDECL_USED_AUTO (in FUNCTION_DECL)
    3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
       ICS_BAD_FLAG (in _CONV)
       FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -660,11 +660,6 @@ enum cp_lambda_default_capture_mode_type {
 #define LAMBDA_EXPR_MUTABLE_P(NODE) \
   TREE_LANG_FLAG_1 (LAMBDA_EXPR_CHECK (NODE))
 
-/* True iff we should try to deduce the lambda return type from any return
-   statement.  */
-#define LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P(NODE) \
-  TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE))
-
 /* The return type in the expression.
  * NULL_TREE indicates that none was specified.  */
 #define LAMBDA_EXPR_RETURN_TYPE(NODE) \
@@ -804,7 +799,6 @@ enum cp_tree_index
     CPTI_CLASS_TYPE,
     CPTI_UNKNOWN_TYPE,
     CPTI_INIT_LIST_TYPE,
-    CPTI_DEPENDENT_LAMBDA_RETURN_TYPE,
     CPTI_VTBL_TYPE,
     CPTI_VTBL_PTR_TYPE,
     CPTI_STD,
@@ -876,7 +870,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define class_type_node                        cp_global_trees[CPTI_CLASS_TYPE]
 #define unknown_type_node              cp_global_trees[CPTI_UNKNOWN_TYPE]
 #define init_list_type_node            cp_global_trees[CPTI_INIT_LIST_TYPE]
-#define dependent_lambda_return_type_node cp_global_trees[CPTI_DEPENDENT_LAMBDA_RETURN_TYPE]
 #define vtbl_type_node                 cp_global_trees[CPTI_VTBL_TYPE]
 #define vtbl_ptr_type_node             cp_global_trees[CPTI_VTBL_PTR_TYPE]
 #define std_node                       cp_global_trees[CPTI_STD]
@@ -1076,6 +1069,7 @@ struct GTY(()) language_function {
   tree x_in_charge_parm;
   tree x_vtt_parm;
   tree x_return_value;
+  tree x_auto_return_pattern;
 
   BOOL_BITFIELD returns_value : 1;
   BOOL_BITFIELD returns_null : 1;
@@ -1158,6 +1152,11 @@ struct GTY(()) language_function {
 #define current_function_return_value \
   (cp_function_chain->x_return_value)
 
+/* A type involving 'auto' to be used for return type deduction.  */
+
+#define current_function_auto_return_pattern \
+  (cp_function_chain->x_auto_return_pattern)
+
 /* True if NAME is the IDENTIFIER_NODE for an overloaded "operator
    new" or "operator delete".  */
 #define NEW_DELETE_OPNAME_P(NAME)              \
@@ -3085,6 +3084,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define DECL_LOCAL_FUNCTION_P(NODE) \
   DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE))
 
+/* True if NODE was declared with auto in its return type, but it has
+   started compilation and so the return type might have been changed by
+   return type deduction; its declared return type should be found in
+   DECL_STRUCT_FUNCTION(NODE)->language->x_auto_return_pattern.  */
+#define FNDECL_USED_AUTO(NODE) \
+  TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (NODE))
+
 /* Nonzero if NODE is a DECL which we know about but which has not
    been explicitly declared, such as a built-in function or a friend
    declared inside a class.  In the latter case DECL_HIDDEN_FRIEND_P
@@ -4144,6 +4150,8 @@ enum tsubst_flags {
                                    conversion.  */
   tf_no_access_control = 1 << 7, /* Do not perform access checks, even
                                    when issuing other errors.   */
+  tf_partial = 1 << 8,          /* Doing initial explicit argument
+                                   substitution in fn_type_unification.  */
   /* Convenient substitution flags combinations.  */
   tf_warning_or_error = tf_warning | tf_error
 };
@@ -5619,7 +5627,7 @@ extern tree lambda_capture_field_type             (tree);
 extern tree lambda_return_type                 (tree);
 extern tree lambda_proxy_type                  (tree);
 extern tree lambda_function                    (tree);
-extern void apply_lambda_return_type            (tree, tree);
+extern void apply_deduced_return_type           (tree, tree);
 extern tree add_capture                         (tree, tree, tree, bool, bool);
 extern tree add_default_capture                 (tree, tree, tree);
 extern tree build_capture_proxy                        (tree);
index e664d43285b15823fc6fe4dd0bf9b859c8b44cc2..f021edf36e5829e5c8f8944a90df956ce578b097 100644 (file)
@@ -960,6 +960,7 @@ decls_match (tree newdecl, tree olddecl)
       tree f2 = TREE_TYPE (olddecl);
       tree p1 = TYPE_ARG_TYPES (f1);
       tree p2 = TYPE_ARG_TYPES (f2);
+      tree r2;
 
       /* Specializations of different templates are different functions
         even if they have the same type.  */
@@ -988,7 +989,14 @@ decls_match (tree newdecl, tree olddecl)
       if (TREE_CODE (f1) != TREE_CODE (f2))
        return 0;
 
-      if (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2)))
+      /* A declaration with deduced return type should use its pre-deduction
+        type for declaration matching.  */
+      if (FNDECL_USED_AUTO (olddecl))
+       r2 = DECL_STRUCT_FUNCTION (olddecl)->language->x_auto_return_pattern;
+      else
+       r2 = TREE_TYPE (f2);
+
+      if (same_type_p (TREE_TYPE (f1), r2))
        {
          if (!prototype_p (f2) && DECL_EXTERN_C_P (olddecl)
              && (DECL_BUILT_IN (olddecl)
@@ -1486,7 +1494,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
                              TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
            {
              error ("new declaration %q#D", newdecl);
-             error ("ambiguates old declaration %q+#D", olddecl);
+             if (FNDECL_USED_AUTO (olddecl))
+               error_at (DECL_SOURCE_LOCATION (olddecl), "ambiguates old "
+                         "declaration with deduced return type");
+             else
+               error ("ambiguates old declaration %q+#D", olddecl);
               return error_mark_node;
            }
          else
@@ -3644,10 +3656,6 @@ cxx_init_decl_processing (void)
   init_list_type_node = make_node (LANG_TYPE);
   record_unknown_type (init_list_type_node, "init list");
 
-  dependent_lambda_return_type_node = make_node (LANG_TYPE);
-  record_unknown_type (dependent_lambda_return_type_node,
-                      "undeduced lambda return type");
-
   {
     /* Make sure we get a unique function type, so we can give
        its pointer type a name.  (This wins for gdb.) */
@@ -6008,8 +6016,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
       && (DECL_INITIAL (decl) || init))
     DECL_INITIALIZED_IN_CLASS_P (decl) = 1;
 
-  auto_node = type_uses_auto (type);
-  if (auto_node)
+  if (TREE_CODE (decl) != FUNCTION_DECL
+      && (auto_node = type_uses_auto (type)))
     {
       tree d_init;
       if (init == NULL_TREE)
@@ -9188,9 +9196,13 @@ grokdeclarator (const cp_declarator *declarator,
                  {
                    if (!declarator->u.function.late_return_type)
                      {
-                       error ("%qs function uses %<auto%> type specifier without"
-                              " trailing return type", name);
-                       return error_mark_node;
+                       if (current_class_type
+                           && LAMBDA_TYPE_P (current_class_type))
+                         /* OK for C++11 lambdas.  */;
+                       else if (cxx_dialect < cxx1y)
+                         pedwarn (input_location, 0, "%qs function uses "
+                                  "%<auto%> type specifier without trailing "
+                                  "return type", name);
                      }
                    else if (!is_auto (type))
                      {
@@ -10029,7 +10041,8 @@ grokdeclarator (const cp_declarator *declarator,
       }
     else if (decl_context == FIELD)
       {
-       if (!staticp && type_uses_auto (type))
+       if (!staticp && TREE_CODE (type) != METHOD_TYPE
+           && type_uses_auto (type))
          {
            error ("non-static data member declared %<auto%>");
            type = error_mark_node;
@@ -12570,7 +12583,8 @@ check_function_type (tree decl, tree current_function_parms)
   /* In a function definition, arg types must be complete.  */
   require_complete_types_for_parms (current_function_parms);
 
-  if (dependent_type_p (return_type))
+  if (dependent_type_p (return_type)
+      || type_uses_auto (return_type))
     return;
   if (!COMPLETE_OR_VOID_TYPE_P (return_type)
       || (TYPE_FOR_JAVA (return_type) && MAYBE_CLASS_TYPE_P (return_type)))
@@ -12741,6 +12755,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
 
   /* Build the return declaration for the function.  */
   restype = TREE_TYPE (fntype);
+
   if (DECL_RESULT (decl1) == NULL_TREE)
     {
       tree resdecl;
@@ -12849,6 +12864,12 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
   current_stmt_tree ()->stmts_are_full_exprs_p = 1;
   current_binding_level = bl;
 
+  if (!processing_template_decl && type_uses_auto (restype))
+    {
+      FNDECL_USED_AUTO (decl1) = true;
+      current_function_auto_return_pattern = restype;
+    }
+
   /* Start the statement-tree, start the tree now.  */
   DECL_SAVED_TREE (decl1) = push_stmt_list ();
 
@@ -13463,6 +13484,23 @@ finish_function (int flags)
      of curly braces for a function.  */
   gcc_assert (stmts_are_full_exprs_p ());
 
+  /* If there are no return statements in a function with auto return type,
+     the return type is void.  But if the declared type is something like
+     auto*, this is an error.  */
+  if (!processing_template_decl && FNDECL_USED_AUTO (fndecl)
+      && TREE_TYPE (fntype) == current_function_auto_return_pattern)
+    {
+      if (!is_auto (current_function_auto_return_pattern)
+         && !current_function_returns_value && !current_function_returns_null)
+       {
+         error ("no return statements in function returning %qT",
+                current_function_auto_return_pattern);
+         inform (input_location, "only plain %<auto%> return type can be "
+                 "deduced to %<void%>");
+       }
+      apply_deduced_return_type (fndecl, void_type_node);
+    }
+
   /* Save constexpr function body before it gets munged by
      the NRV transformation.   */
   maybe_save_function_definition (fndecl);
index 7eccf6725469e854aa07246c49e25ad3e5559619..b048ac7b3cd569c1478526f7a565360e9bb4ce0d 100644 (file)
@@ -151,6 +151,9 @@ change_return_type (tree new_ret, tree fntype)
   tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
   tree attrs = TYPE_ATTRIBUTES (fntype);
 
+  if (new_ret == error_mark_node)
+    return fntype;
+
   if (same_type_p (new_ret, TREE_TYPE (fntype)))
     return fntype;
 
@@ -4281,7 +4284,11 @@ mark_used (tree decl)
   if ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
       || DECL_LANG_SPECIFIC (decl) == NULL
       || DECL_THUNK_P (decl))
-    return true;
+    {
+      if (!processing_template_decl && type_uses_auto (TREE_TYPE (decl)))
+       error ("use of %qD before deduction of %<auto%>", decl);
+      return true;
+    }
 
   /* We only want to do this processing once.  We don't need to keep trying
      to instantiate inline templates, because unit-at-a-time will make sure
@@ -4303,10 +4310,13 @@ mark_used (tree decl)
   /* Normally, we can wait until instantiation-time to synthesize DECL.
      However, if DECL is a static data member initialized with a constant
      or a constexpr function, we need it right now because a reference to
-     such a data member or a call to such function is not value-dependent.  */
+     such a data member or a call to such function is not value-dependent.
+     For a function that uses auto in the return type, we need to instantiate
+     it to find out its type.  */
   if ((decl_maybe_constant_var_p (decl)
        || (TREE_CODE (decl) == FUNCTION_DECL
-          && DECL_DECLARED_CONSTEXPR_P (decl)))
+          && (DECL_DECLARED_CONSTEXPR_P (decl)
+              || type_uses_auto (TREE_TYPE (TREE_TYPE (decl))))))
       && DECL_LANG_SPECIFIC (decl)
       && DECL_TEMPLATE_INFO (decl)
       && !uses_template_parms (DECL_TI_ARGS (decl)))
@@ -4321,6 +4331,9 @@ mark_used (tree decl)
       --function_depth;
     }
 
+  if (type_uses_auto (TREE_TYPE (decl)))
+    error ("use of %qD before deduction of %<auto%>", decl);
+
   /* If we don't need a value, then we don't need to synthesize DECL.  */
   if (cp_unevaluated_operand != 0)
     return true;
index 75b7bdb046a34bb487aa3fdb8db134df5e6a21a3..eac60f13572821e25d5d1b77b3a457fb3210da0c 100644 (file)
@@ -8416,9 +8416,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
     if (LAMBDA_EXPR_RETURN_TYPE (lambda_expr))
       return_type_specs.type = LAMBDA_EXPR_RETURN_TYPE (lambda_expr);
     else
-      /* Maybe we will deduce the return type later, but we can use void
-        as a placeholder return type anyways.  */
-      return_type_specs.type = void_type_node;
+      /* Maybe we will deduce the return type later.  */
+      return_type_specs.type = make_auto ();
 
     p = obstack_alloc (&declarator_obstack, 0);
 
@@ -8539,7 +8538,8 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
 
        if (cp_parser_parse_definitely (parser))
          {
-           apply_lambda_return_type (lambda_expr, lambda_return_type (expr));
+           if (!processing_template_decl)
+             apply_deduced_return_type (fco, lambda_return_type (expr));
 
            /* Will get error here if type not deduced yet.  */
            finish_return_stmt (expr);
@@ -8550,13 +8550,10 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
 
     if (!done)
       {
-       if (!LAMBDA_EXPR_RETURN_TYPE (lambda_expr))
-         LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda_expr) = true;
        while (cp_lexer_next_token_is_keyword (parser->lexer, RID_LABEL))
          cp_parser_label_declaration (parser);
        cp_parser_statement_seq_opt (parser, NULL_TREE);
        cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
-       LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda_expr) = false;
       }
 
     finish_compound_stmt (compound_stmt);
@@ -11275,8 +11272,14 @@ cp_parser_conversion_type_id (cp_parser* parser)
   if (! cp_parser_uncommitted_to_tentative_parse_p (parser)
       && type_uses_auto (type_specified))
     {
-      error ("invalid use of %<auto%> in conversion operator");
-      return error_mark_node;
+      if (cxx_dialect < cxx1y)
+       {
+         error ("invalid use of %<auto%> in conversion operator");
+         return error_mark_node;
+       }
+      else if (template_parm_scope_p ())
+       warning (0, "use of %<auto%> in member template "
+                "conversion operator can never be deduced");
     }
 
   return type_specified;
index b36e49d4a070b3e1207e5128ed10f6f222a9dc06..f128947ead867ef12d2c11f53874a4759b8fb2b0 100644 (file)
@@ -9112,12 +9112,6 @@ instantiate_class_template_1 (tree type)
       tree decl = lambda_function (type);
       if (decl)
        {
-         tree lambda = CLASSTYPE_LAMBDA_EXPR (type);
-         if (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda))
-           {
-             apply_lambda_return_type (lambda, void_type_node);
-             LAMBDA_EXPR_RETURN_TYPE (lambda) = NULL_TREE;
-           }
          instantiate_decl (decl, false, false);
          maybe_add_lambda_conv_op (type);
        }
@@ -11331,6 +11325,12 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
             about the template parameter in question.  */
          return t;
 
+       /* Early in template argument deduction substitution, we don't
+          want to reduce the level of 'auto', or it will be confused
+          with a normal template parm in subsequent deduction.  */
+       if (is_auto (t) && (complain & tf_partial))
+         return t;
+
        /* If we get here, we must have been looking at a parm for a
           more deeply nested template.  Make a new version of this
           template parameter, but with a lower level.  */
@@ -14334,14 +14334,8 @@ tsubst_copy_and_build (tree t,
          = (LAMBDA_EXPR_DISCRIMINATOR (t));
        LAMBDA_EXPR_EXTRA_SCOPE (r)
          = RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t));
-       if (LAMBDA_EXPR_RETURN_TYPE (t) == dependent_lambda_return_type_node)
-         {
-           LAMBDA_EXPR_RETURN_TYPE (r) = dependent_lambda_return_type_node;
-           LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (r) = true;
-         }
-       else
-         LAMBDA_EXPR_RETURN_TYPE (r)
-           = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl);
+       LAMBDA_EXPR_RETURN_TYPE (r)
+         = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl);
 
        gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
                    && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
@@ -14860,7 +14854,7 @@ fn_type_unification (tree fn,
       fntype = deduction_tsubst_fntype (fn, converted_args,
                                        (explain_p
                                         ? tf_warning_or_error
-                                        : tf_none));
+                                        : tf_none) | tf_partial);
       processing_template_decl -= incomplete;
 
       if (fntype == error_mark_node)
@@ -16275,7 +16269,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
           to see if it matches ARG.  */
        {
          if (TREE_CODE (arg) == TREE_CODE (parm)
-             && same_type_p (parm, arg))
+             && (is_auto (parm) ? is_auto (arg)
+                 : same_type_p (parm, arg)))
            return unify_success (explain_p);
          else
            return unify_type_mismatch (explain_p, parm, arg);
@@ -17408,7 +17403,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
      The call to fn_type_unification will handle substitution into the
      FN.  */
   decl_type = TREE_TYPE (decl);
-  if (explicit_args && uses_template_parms (decl_type))
+  if (explicit_args && decl == DECL_TEMPLATE_RESULT (fn))
     {
       tree tmpl;
       tree converted_args;
@@ -18315,7 +18310,8 @@ always_instantiate_p (tree decl)
      that for "extern template" functions.  Therefore, we check
      DECL_DECLARED_INLINE_P, rather than possibly_inlined_p.  */
   return ((TREE_CODE (decl) == FUNCTION_DECL
-          && DECL_DECLARED_INLINE_P (decl))
+          && (DECL_DECLARED_INLINE_P (decl)
+              || type_uses_auto (TREE_TYPE (TREE_TYPE (decl)))))
          /* And we need to instantiate static data members so that
             their initializers are available in integral constant
             expressions.  */
@@ -20269,20 +20265,6 @@ listify_autos (tree type, tree auto_node)
   return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
 }
 
-/* walk_tree helper for do_auto_deduction.  */
-
-static tree
-contains_auto_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
-                void *type)
-{
-  /* Is this a variable with the type we're looking for?  */
-  if (DECL_P (*tp)
-      && TREE_TYPE (*tp) == type)
-    return *tp;
-  else
-    return NULL_TREE;
-}
-
 /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
    from INIT.  AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE.  */
 
@@ -20291,25 +20273,17 @@ do_auto_deduction (tree type, tree init, tree auto_node)
 {
   tree parms, tparms, targs;
   tree args[1];
-  tree decl;
   int val;
 
+  if (init == error_mark_node)
+    return error_mark_node;
+
   if (processing_template_decl
       && (TREE_TYPE (init) == NULL_TREE
          || BRACE_ENCLOSED_INITIALIZER_P (init)))
     /* Not enough information to try this yet.  */
     return type;
 
-  /* The name of the object being declared shall not appear in the
-     initializer expression.  */
-  decl = cp_walk_tree_without_duplicates (&init, contains_auto_r, type);
-  if (decl)
-    {
-      error ("variable %q#D with %<auto%> type used in its own "
-            "initializer", decl);
-      return error_mark_node;
-    }
-
   /* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto
      with either a new invented type template parameter U or, if the
      initializer is a braced-init-list (8.5.4), with
@@ -20337,7 +20311,13 @@ do_auto_deduction (tree type, tree init, tree auto_node)
        /* If type is error_mark_node a diagnostic must have been
           emitted by now.  Also, having a mention to '<type error>'
           in the diagnostic is not really useful to the user.  */
-       error ("unable to deduce %qT from %qE", type, init);
+       {
+         if (cfun && auto_node == current_function_auto_return_pattern
+             && LAMBDA_FUNCTION_P (current_function_decl))
+           error ("unable to deduce lambda return type from %qE", init);
+         else
+           error ("unable to deduce %qT from %qE", type, init);
+       }
       return error_mark_node;
     }
 
@@ -20348,8 +20328,14 @@ do_auto_deduction (tree type, tree init, tree auto_node)
   if (TREE_TYPE (auto_node)
       && !same_type_p (TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)))
     {
-      error ("inconsistent deduction for %qT: %qT and then %qT",
-            auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0));
+      if (cfun && auto_node == current_function_auto_return_pattern
+         && LAMBDA_FUNCTION_P (current_function_decl))
+       error ("inconsistent types %qT and %qT deduced for "
+              "lambda return type", TREE_TYPE (auto_node),
+              TREE_VEC_ELT (targs, 0));
+      else
+       error ("inconsistent deduction for %qT: %qT and then %qT",
+              auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0));
       return error_mark_node;
     }
   TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0);
index bd1bc576429b5c476b92cbcdf38e768fd9b9ed34..14d272e10e86e12457e413894b4edf3dab68232a 100644 (file)
@@ -2430,6 +2430,11 @@ lookup_conversions_r (tree binfo,
          if (!IDENTIFIER_MARKED (name))
            {
              tree type = DECL_CONV_FN_TYPE (cur);
+             if (type_uses_auto (type))
+               {
+                 mark_used (cur);
+                 type = DECL_CONV_FN_TYPE (cur);
+               }
 
              if (check_hidden_convs (binfo, virtual_depth, virtualness,
                                      type, parent_convs, other_convs))
index 5646fa7471734638471dcf86b528133147339a0e..6294e19af607aa6e45597f950079f5a89b28207d 100644 (file)
@@ -8691,18 +8691,16 @@ begin_lambda_type (tree lambda)
 tree
 lambda_return_type (tree expr)
 {
-  tree type;
+  if (expr == NULL_TREE)
+    return void_type_node;
   if (type_unknown_p (expr)
       || BRACE_ENCLOSED_INITIALIZER_P (expr))
     {
       cxx_incomplete_type_error (expr, TREE_TYPE (expr));
       return void_type_node;
     }
-  if (type_dependent_expression_p (expr))
-    type = dependent_lambda_return_type_node;
-  else
-    type = cv_unqualified (type_decays_to (unlowered_expr_type (expr)));
-  return type;
+  gcc_checking_assert (!type_dependent_expression_p (expr));
+  return cv_unqualified (type_decays_to (unlowered_expr_type (expr)));
 }
 
 /* Given a LAMBDA_EXPR or closure type LAMBDA, return the op() of the
@@ -8749,29 +8747,32 @@ lambda_capture_field_type (tree expr)
   return type;
 }
 
-/* Recompute the return type for LAMBDA with body of the form:
-     { return EXPR ; }  */
+/* Insert the deduced return type for an auto function.  */
 
 void
-apply_lambda_return_type (tree lambda, tree return_type)
+apply_deduced_return_type (tree fco, tree return_type)
 {
-  tree fco = lambda_function (lambda);
   tree result;
 
-  LAMBDA_EXPR_RETURN_TYPE (lambda) = return_type;
-
   if (return_type == error_mark_node)
     return;
-  if (TREE_TYPE (TREE_TYPE (fco)) == return_type)
-    return;
 
-  /* TREE_TYPE (FUNCTION_DECL) == METHOD_TYPE
-     TREE_TYPE (METHOD_TYPE)   == return-type  */
+  if (LAMBDA_FUNCTION_P (fco))
+    {
+      tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type);
+      LAMBDA_EXPR_RETURN_TYPE (lambda) = return_type;
+    }
+
+  if (DECL_CONV_FN_P (fco))
+    DECL_NAME (fco) = mangle_conv_op_name_for_type (return_type);
+
   TREE_TYPE (fco) = change_return_type (return_type, TREE_TYPE (fco));
 
   result = DECL_RESULT (fco);
   if (result == NULL_TREE)
     return;
+  if (TREE_TYPE (result) == return_type)
+    return;
 
   /* We already have a DECL_RESULT from start_preparsed_function.
      Now we need to redo the work it and allocate_struct_function
@@ -8786,12 +8787,13 @@ apply_lambda_return_type (tree lambda, tree return_type)
 
   DECL_RESULT (fco) = result;
 
-  if (!processing_template_decl && aggregate_value_p (result, fco))
+  if (!processing_template_decl)
     {
+      bool aggr = aggregate_value_p (result, fco);
 #ifdef PCC_STATIC_STRUCT_RETURN
-      cfun->returns_pcc_struct = 1;
+      cfun->returns_pcc_struct = aggr;
 #endif
-      cfun->returns_struct = 1;
+      cfun->returns_struct = aggr;
     }
 
 }
index d2d6c4ef04944cb2b723e43a8427c0ff241a8e8b..b68de52a13e04f3f4123e1bfad0a195a59c1e6f3 100644 (file)
@@ -733,6 +733,11 @@ merge_types (tree t1, tree t2)
   if (t2 == error_mark_node)
     return t1;
 
+  /* Handle merging an auto redeclaration with a previous deduced
+     return type.  */
+  if (is_auto (t1))
+    return t2;
+
   /* Merge the attributes.  */
   attributes = (*targetm.merge_type_attributes) (t1, t2);
 
@@ -7779,9 +7784,11 @@ tree
 check_return_expr (tree retval, bool *no_warning)
 {
   tree result;
-  /* The type actually returned by the function, after any
-     promotions.  */
+  /* The type actually returned by the function.  */
   tree valtype;
+  /* The type the function is declared to return, or void if
+     the declared type is incomplete.  */
+  tree functype;
   int fn_returns_value_p;
   bool named_return_value_okay_p;
 
@@ -7812,30 +7819,6 @@ check_return_expr (tree retval, bool *no_warning)
       return NULL_TREE;
     }
 
-  /* As an extension, deduce lambda return type from a return statement
-     anywhere in the body.  */
-  if (retval && LAMBDA_FUNCTION_P (current_function_decl))
-    {
-      tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type);
-      if (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda))
-       {
-         tree type = lambda_return_type (retval);
-         tree oldtype = LAMBDA_EXPR_RETURN_TYPE (lambda);
-
-         if (oldtype == NULL_TREE)
-           apply_lambda_return_type (lambda, type);
-         /* If one of the answers is type-dependent, we can't do any
-            better until instantiation time.  */
-         else if (oldtype == dependent_lambda_return_type_node)
-           /* Leave it.  */;
-         else if (type == dependent_lambda_return_type_node)
-           apply_lambda_return_type (lambda, type);
-         else if (!same_type_p (type, oldtype))
-           error ("inconsistent types %qT and %qT deduced for "
-                  "lambda return type", type, oldtype);
-       }
-    }
-
   if (processing_template_decl)
     {
       current_function_returns_value = 1;
@@ -7844,6 +7827,42 @@ check_return_expr (tree retval, bool *no_warning)
       return retval;
     }
 
+  functype = TREE_TYPE (TREE_TYPE (current_function_decl));
+
+  /* Deduce auto return type from a return statement.  */
+  if (current_function_auto_return_pattern)
+    {
+      tree auto_node;
+      tree type;
+
+      if (!retval && !is_auto (current_function_auto_return_pattern))
+       {
+         /* Give a helpful error message.  */
+         error ("return-statement with no value, in function returning %qT",
+                current_function_auto_return_pattern);
+         inform (input_location, "only plain %<auto%> return type can be "
+                 "deduced to %<void%>");
+         type = error_mark_node;
+       }
+      else
+       {
+         if (!retval)
+           retval = void_zero_node;
+         auto_node = type_uses_auto (current_function_auto_return_pattern);
+         type = do_auto_deduction (current_function_auto_return_pattern,
+                                   retval, auto_node);
+       }
+
+      if (type == error_mark_node)
+       /* Leave it.  */;
+      else if (functype == current_function_auto_return_pattern)
+       apply_deduced_return_type (current_function_decl, type);
+      else
+       /* A mismatch should have been diagnosed in do_auto_deduction.  */
+       gcc_assert (same_type_p (type, functype));
+      functype = type;
+    }
+
   /* When no explicit return-value is given in a function with a named
      return value, the named return value is used.  */
   result = DECL_RESULT (current_function_decl);
@@ -7857,12 +7876,11 @@ check_return_expr (tree retval, bool *no_warning)
      that's supposed to return a value.  */
   if (!retval && fn_returns_value_p)
     {
-      permerror (input_location, "return-statement with no value, in function returning %qT",
-                valtype);
-      /* Clear this, so finish_function won't say that we reach the
-        end of a non-void function (which we don't, we gave a
-        return!).  */
-      current_function_returns_null = 0;
+      if (functype != error_mark_node)
+       permerror (input_location, "return-statement with no value, in "
+                  "function returning %qT", valtype);
+      /* Remember that this function did return.  */
+      current_function_returns_value = 1;
       /* And signal caller that TREE_NO_WARNING should be set on the
         RETURN_EXPR to avoid control reaches end of non-void function
         warnings in tree-cfg.c.  */
@@ -7963,14 +7981,12 @@ check_return_expr (tree retval, bool *no_warning)
      && DECL_CONTEXT (retval) == current_function_decl
      && ! TREE_STATIC (retval)
      && ! DECL_ANON_UNION_VAR_P (retval)
-     && (DECL_ALIGN (retval)
-         >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
+     && (DECL_ALIGN (retval) >= DECL_ALIGN (result))
      /* The cv-unqualified type of the returned value must be the
         same as the cv-unqualified return type of the
         function.  */
      && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
-                     (TYPE_MAIN_VARIANT
-                      (TREE_TYPE (TREE_TYPE (current_function_decl)))))
+                     (TYPE_MAIN_VARIANT (functype)))
      /* And the returned value must be non-volatile.  */
      && ! TYPE_VOLATILE (TREE_TYPE (retval)));
      
@@ -7995,8 +8011,6 @@ check_return_expr (tree retval, bool *no_warning)
     ;
   else
     {
-      /* The type the function is declared to return.  */
-      tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
       int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
 
       /* The functype's return type will have been set to void, if it
@@ -8016,10 +8030,9 @@ check_return_expr (tree retval, bool *no_warning)
          && DECL_CONTEXT (retval) == current_function_decl
          && !TREE_STATIC (retval)
          && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
-                         (TYPE_MAIN_VARIANT
-                          (TREE_TYPE (TREE_TYPE (current_function_decl)))))
+                         (TYPE_MAIN_VARIANT (functype)))
          /* This is only interesting for class type.  */
-         && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
+         && CLASS_TYPE_P (functype))
        flags = flags | LOOKUP_PREFER_RVALUE;
 
       /* First convert the value to the function's return type, then
index 974f92ff89cf71e89082b69d6a866aa18acc2025..80a1d0462ceb5bb8fe9457f29e538663f3f02690 100644 (file)
@@ -1818,7 +1818,8 @@ add_exception_specifier (tree list, tree spec, int complain)
   else
     diag_type = DK_ERROR; /* error */
 
-  if (diag_type != DK_UNSPECIFIED && complain)
+  if (diag_type != DK_UNSPECIFIED
+      && (complain & tf_warning_or_error))
     cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type);
 
   return list;
index a6b64242baef8c0e5b3229d3dfe132f2262b0afb..94120525c342bc34fd9b39deca322a79fac74a00 100644 (file)
@@ -1,3 +1,20 @@
+2012-03-21  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/auto3.C: Compile with -pedantic-errors.
+       * g++.dg/cpp0x/trailing2.C: Likewise.
+       * g++.dg/warn/pr23075.C: Change dg-warning to dg-bogus.
+       * g++.dg/cpp1y/auto-fn1.C: New.
+       * g++.dg/cpp1y/auto-fn2.C: New.
+       * g++.dg/cpp1y/auto-fn3.C: New.
+       * g++.dg/cpp1y/auto-fn4.C: New.
+       * g++.dg/cpp1y/auto-fn5.C: New.
+       * g++.dg/cpp1y/auto-fn6.C: New.
+       * g++.dg/cpp1y/auto-fn7.C: New.
+       * g++.dg/cpp1y/auto-fn8.C: New.
+       * g++.dg/cpp1y/auto-fn9.C: New.
+       * g++.dg/cpp1y/auto-fn10.C: New.
+       * g++.dg/cpp1y/auto-fn11.C: New.
+
 2012-03-23  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/52678
index 17f7f99595573796d8a407dc5b575c696af1e852..0a59242ab29c44f39c233a3ab131c14b73e2a1ab 100644 (file)
@@ -2,5 +2,5 @@
 
 void f()
 {
-  auto val = val;  // { dg-error "auto. type used in its own initializer" }
+  auto val = val;  // { dg-error "auto" }
 }
index 860790d7d3c90f4b1502d6d56410124aede5ca0f..2b51d3191d1f6cb111261c833bc148de4b026d4b 100644 (file)
@@ -1,5 +1,5 @@
 // Negative test for auto
-// { dg-options "-std=c++0x" }
+// { dg-do compile { target c++11 } }
 
 #include <initializer_list>
 
@@ -10,7 +10,7 @@ auto x;                               // { dg-error "auto" }
 auto i = 42, j = 42.0;         // { dg-error "auto" }
 
 // New CWG issue
-auto a[2] = { 1, 2 };          // { dg-error "initializer_list" }
+auto a[2] = { 1, 2 };          // { dg-error "auto|initializer_list" }
 
 template<class T>
 struct A { };
index 5f5af22947ffd7f956ee4162509b8f96b4dd1063..91e55578d9bad17adc9a96485911da3bf7d77be6 100644 (file)
@@ -1,6 +1,6 @@
 // PR c++/37967
 // Negative test for auto
-// { dg-options "-std=c++0x" }
+// { dg-do compile { target c++11 } }
 
 auto f1 () -> int;
 auto f2 ();            // { dg-error "without trailing return type" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn1.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn1.C
new file mode 100644 (file)
index 0000000..eb54149
--- /dev/null
@@ -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 (file)
index 0000000..e3ed3a9
--- /dev/null
@@ -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 (file)
index 0000000..a9984aa
--- /dev/null
@@ -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 (file)
index 0000000..e4e58e8
--- /dev/null
@@ -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 (file)
index 0000000..34a61ae
--- /dev/null
@@ -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 (file)
index 0000000..4c2cee7
--- /dev/null
@@ -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 (file)
index 0000000..107c37f
--- /dev/null
@@ -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 (file)
index 0000000..0b76bfc
--- /dev/null
@@ -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 (file)
index 0000000..f9af6c2
--- /dev/null
@@ -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 (file)
index 0000000..03ff537
--- /dev/null
@@ -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 (file)
index 0000000..b915352
--- /dev/null
@@ -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 (file)
index 0000000..dcec899
--- /dev/null
@@ -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 (file)
index 0000000..1fa7479
--- /dev/null
@@ -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);
+}
index e7145ffbeb9fd5bc886ae960be0b2396d3df28d1..481583e80e3daa2f5d3239cdb3a99ae2bf202860 100644 (file)
@@ -6,7 +6,7 @@ template<int> void
 foo ()
 {
 #pragma omp parallel for
-  for (auto i = i = 0; i<4; ++i)       // { dg-error "incomplete|unable|invalid" }
+  for (auto i = i = 0; i<4; ++i)       // { dg-error "incomplete|unable|invalid|auto" }
     ;
 }
 
index e5b1b483d767142d838aafbf9bc348532ff54459..59e93be48f84fc0d3a240685979e035658d2bb3b 100644 (file)
@@ -6,4 +6,4 @@ int
 foo (void)
 {
   return;      // { dg-error "with no value" }
-}              // { dg-warning "no return statement" }
+}              // { dg-bogus "no return statement" }
index 41aab394d3eecd05ae05777589b1bf34bf6e2d69..94bffdbecaa6fa86438bf9fd1a2670f6545b9aa6 100644 (file)
@@ -10,6 +10,6 @@ struct S
 
 template <class T> 
 template <> // { dg-error "enclosing class templates|invalid explicit specialization" }
-void S<T>::f<int> ()  // { dg-error "does not match|invalid function declaration" }
+void S<T>::f<int> ()
 {
 }