Implement P0091R2, Template argument deduction for class templates.
authorJason Merrill <jason@redhat.com>
Tue, 4 Oct 2016 20:42:58 +0000 (16:42 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 4 Oct 2016 20:42:58 +0000 (16:42 -0400)
* parser.c (cp_parser_simple_type_specifier): Parse class placeholder.
Use the location of the beginning of the type-specifier.
(cp_parser_init_declarator): Parse deduction guide.
(cp_parser_diagnose_invalid_type_name): Mention class deduction.
(cp_parser_type_id_1): Don't accept class placeholder as template arg.
* cp-tree.h (CLASS_PLACEHOLDER_TEMPLATE): New.
* decl.c (grokdeclarator): Check for uninitialized auto here.
(start_decl_1): Not here.
(cp_finish_decl): Or here.  Don't collapse a list when doing
class deduction.
(grokfndecl): Check deduction guide scope and body.
* error.c (dump_decl, dump_function_decl, dump_function_name):
Handle deduction guides.
* pt.c (make_template_placeholder, do_class_deduction): New.
(build_deduction_guide, rewrite_template_parm): New.
(dguide_name, dguide_name_p, deduction_guide_p): New.
(do_auto_deduction): Call do_class_deduction.
(splice_late_return_type, is_auto): Handle class placeholders.
(template_parms_level_to_args): Split from template_parms_to_args.
(tsubst_template_parms_level): Split from tsubst_template_parms.
* typeck2.c (build_functional_cast): Handle class placeholder.

From-SVN: r240756

27 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/error.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/concepts/class-deduction1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/concepts/var-concept5.C
gcc/testsuite/g++.dg/cpp1z/class-deduction1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/access10.C
gcc/testsuite/g++.dg/parse/decl-specifier-1.C
gcc/testsuite/g++.dg/parse/template2.C
gcc/testsuite/g++.old-deja/g++.robertl/eb129.C
gcc/testsuite/g++.old-deja/g++.robertl/eb129a.C

index 1aa8e73234c1c3f0f5f0463944389cd2bfb52861..3fc378ae4637cf956b7a104d74e56385ab6403fb 100644 (file)
@@ -1,3 +1,28 @@
+2016-10-04  Jason Merrill  <jason@redhat.com>
+
+       Implement P0091R2, Template argument deduction for class templates.
+       * parser.c (cp_parser_simple_type_specifier): Parse class placeholder.
+       Use the location of the beginning of the type-specifier.
+       (cp_parser_init_declarator): Parse deduction guide.
+       (cp_parser_diagnose_invalid_type_name): Mention class deduction.
+       (cp_parser_type_id_1): Don't accept class placeholder as template arg.
+       * cp-tree.h (CLASS_PLACEHOLDER_TEMPLATE): New.
+       * decl.c (grokdeclarator): Check for uninitialized auto here.
+       (start_decl_1): Not here.
+       (cp_finish_decl): Or here.  Don't collapse a list when doing
+       class deduction.
+       (grokfndecl): Check deduction guide scope and body.
+       * error.c (dump_decl, dump_function_decl, dump_function_name):
+       Handle deduction guides.
+       * pt.c (make_template_placeholder, do_class_deduction): New.
+       (build_deduction_guide, rewrite_template_parm): New.
+       (dguide_name, dguide_name_p, deduction_guide_p): New.
+       (do_auto_deduction): Call do_class_deduction.
+       (splice_late_return_type, is_auto): Handle class placeholders.
+       (template_parms_level_to_args): Split from template_parms_to_args.
+       (tsubst_template_parms_level): Split from tsubst_template_parms.
+       * typeck2.c (build_functional_cast): Handle class placeholder.
+
 2016-10-04  Martin Sebor  <msebor@redhat.com>
 
        PR c++/77804
index 85702c53a412d6e91badf17af07c3d433a32db29..3fbe1d96c66059c849e25c835fc57dc6fb5e0cc4 100644 (file)
@@ -1199,6 +1199,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define vptr_identifier                        cp_global_trees[CPTI_VPTR_IDENTIFIER]
 /* The name of the std namespace.  */
 #define std_identifier                 cp_global_trees[CPTI_STD_IDENTIFIER]
+/* The name of a C++17 deduction guide.  */
 #define lang_name_c                    cp_global_trees[CPTI_LANG_NAME_C]
 #define lang_name_cplusplus            cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
 
@@ -5104,6 +5105,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 #define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \
   (TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE)))
 
+/* For a C++17 class deduction placeholder, the template it represents.  */
+#define CLASS_PLACEHOLDER_TEMPLATE(NODE) \
+  (DECL_INITIAL (TYPE_NAME (TEMPLATE_TYPE_PARM_CHECK (NODE))))
+
 /* Contexts in which auto deduction occurs. These flags are
    used to control diagnostics in do_auto_deduction.  */
 
@@ -6027,6 +6032,7 @@ extern int num_template_headers_for_class (tree);
 extern void check_template_variable            (tree);
 extern tree make_auto                          (void);
 extern tree make_decltype_auto                 (void);
+extern tree make_template_placeholder          (tree);
 extern tree do_auto_deduction                   (tree, tree, tree);
 extern tree do_auto_deduction                   (tree, tree, tree,
                                                  tsubst_flags_t,
@@ -6158,6 +6164,9 @@ extern void register_local_specialization       (tree, tree);
 extern tree retrieve_local_specialization       (tree);
 extern tree extract_fnparm_pack                 (tree, tree *);
 extern tree template_parm_to_arg                (tree);
+extern tree dguide_name                                (tree);
+extern bool dguide_name_p                      (tree);
+extern bool deduction_guide_p                  (tree);
 
 /* in repo.c */
 extern void init_repo                          (void);
index c8f766618d137e4c7e4c5b16c9dfb0ba2fbf8ef1..6646062e6723eeef84cfd8c45c77926d2e65686c 100644 (file)
@@ -5140,7 +5140,7 @@ start_decl_1 (tree decl, bool initialized)
   else if (aggregate_definition_p && !complete_p)
     {
       if (type_uses_auto (type))
-       error ("declaration of %q#D has no initializer", decl);
+       gcc_unreachable ();
       else
        error ("aggregate %q#D has incomplete type and cannot be defined",
               decl);
@@ -6695,12 +6695,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
              return;
            }
 
-         error ("declaration of %q#D has no initializer", decl);
-         TREE_TYPE (decl) = error_mark_node;
-         return;
+         gcc_unreachable ();
        }
       d_init = init;
-      if (TREE_CODE (d_init) == TREE_LIST)
+      if (TREE_CODE (d_init) == TREE_LIST
+         && !CLASS_PLACEHOLDER_TEMPLATE (auto_node))
        d_init = build_x_compound_expr_from_list (d_init, ELK_INIT,
                                                  tf_warning_or_error);
       d_init = resolve_nondeduced_context (d_init, tf_warning_or_error);
@@ -8182,7 +8181,27 @@ grokfndecl (tree ctype,
        }
     }
 
-  if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))
+  if (deduction_guide_p (decl))
+    {
+      if (!DECL_NAMESPACE_SCOPE_P (decl))
+       {
+         error_at (location, "deduction guide %qD must be declared at "
+                   "namespace scope", decl);
+         return NULL_TREE;
+       }
+      tree type = TREE_TYPE (DECL_NAME (decl));
+      if (CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type))
+       {
+         error_at (location, "deduction guide %qD must be declared in the "
+                   "same scope as %qT", decl, type);
+         inform (location_of (type), "  declared here");
+         return NULL_TREE;
+       }
+      if (funcdef_flag)
+       error_at (location,
+                 "deduction guide %qD must not have a function body", decl);
+    }
+  else if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))
       && !grok_op_properties (decl, /*complain=*/true))
     return NULL_TREE;
   else if (UDLIT_OPER_P (DECL_NAME (decl)))
@@ -11063,12 +11082,19 @@ grokdeclarator (const cp_declarator *declarator,
       }
     else if (decl_context == FIELD)
       {
-       if (!staticp && !friendp && TREE_CODE (type) != METHOD_TYPE
-           && type_uses_auto (type))
-         {
-           error ("non-static data member declared %<auto%>");
-           type = error_mark_node;
-         }
+       if (!staticp && !friendp && TREE_CODE (type) != METHOD_TYPE)
+         if (tree auto_node = type_uses_auto (type))
+           {
+             location_t loc = declspecs->locations[ds_type_spec];
+             if (CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+               error_at (loc, "invalid use of template-name %qE without an "
+                         "argument list",
+                         CLASS_PLACEHOLDER_TEMPLATE (auto_node));
+             else
+               error_at (loc, "non-static data member declared with "
+                         "placeholder %qT", auto_node);
+             type = error_mark_node;
+           }
 
        /* The C99 flexible array extension.  */
        if (!staticp && TREE_CODE (type) == ARRAY_TYPE
@@ -11543,6 +11569,22 @@ grokdeclarator (const cp_declarator *declarator,
          }
       }
 
+    if (VAR_P (decl) && !initialized)
+      if (tree auto_node = type_uses_auto (type))
+       {
+         location_t loc = declspecs->locations[ds_type_spec];
+         if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+           {
+             error_at (loc, "invalid use of template-name %qE without an "
+                       "argument list", tmpl);
+             inform (loc, "class template argument deduction "
+                     "requires an initializer");
+           }
+         else
+           error_at (loc, "declaration of %q#D has no initializer", decl);
+         TREE_TYPE (decl) = error_mark_node;
+       }
+
     if (storage_class == sc_extern && initialized && !funcdef_flag)
       {
        if (toplevel_bindings_p ())
index 745d7ba86722b8b1f10f9a78fd0d4075a41e4216..20b20b48e9689fc7e929cc4fca51537887bbfc9f 100644 (file)
@@ -1159,6 +1159,9 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
          dump_type (pp, TREE_TYPE (t), flags);
          break;
        }
+      else if (dguide_name_p (t))
+       dump_decl (pp, CLASSTYPE_TI_TEMPLATE (TREE_TYPE (t)),
+                  TFF_PLAIN_IDENTIFIER);
       else
        pp_cxx_tree_identifier (pp, t);
       break;
@@ -1552,8 +1555,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
 
   /* Print the return type?  */
   if (show_return)
-    show_return = !DECL_CONV_FN_P (t)  && !DECL_CONSTRUCTOR_P (t)
-                 && !DECL_DESTRUCTOR_P (t);
+    show_return = (!DECL_CONV_FN_P (t)  && !DECL_CONSTRUCTOR_P (t)
+                  && !DECL_DESTRUCTOR_P (t) && !deduction_guide_p (t));
   if (show_return)
     {
       tree ret = fndecl_declared_return_type (t);
@@ -1598,6 +1601,11 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
 
       if (show_return)
        dump_type_suffix (pp, TREE_TYPE (fntype), flags);
+      else if (deduction_guide_p (t))
+       {
+         pp_cxx_ws_string (pp, "->");
+         dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags);
+       }
 
       if (flag_concepts)
         if (tree ci = get_constraints (t))
@@ -1767,10 +1775,6 @@ dump_function_name (cxx_pretty_printer *pp, tree t, int flags)
       pp_cxx_ws_string (pp, "operator");
       dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags);
     }
-  else if (name && IDENTIFIER_OPNAME_P (name))
-    pp_cxx_tree_identifier (pp, name);
-  else if (name && UDLIT_OPER_P (name))
-    pp_cxx_tree_identifier (pp, name);
   else
     dump_decl (pp, name, flags);
 
index 8581375655c9b587a76c7659b407ce336d106b13..683a6dda924d386427ffcc27601fe724fa3596bc 100644 (file)
@@ -3155,6 +3155,9 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
       error_at (location,
                "invalid use of template-name %qE without an argument list",
                decl);
+      if (DECL_CLASS_TEMPLATE_P (decl) && cxx_dialect < cxx1z)
+       inform (location, "class template argument deduction is only available "
+               "with -std=c++1z or -std=gnu++1z");
       inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
     }
   else if (TREE_CODE (id) == BIT_NOT_EXPR)
@@ -12224,6 +12227,9 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
      linkage-specification
      namespace-definition
 
+   C++17:
+     deduction-guide
+
    GNU extension:
 
    declaration:
@@ -16150,7 +16156,7 @@ cp_parser_type_specifier (cp_parser* parser,
      double
      void
 
-   C++0x Extension:
+   C++11 Extension:
 
    simple-type-specifier:
      auto
@@ -16159,6 +16165,10 @@ cp_parser_type_specifier (cp_parser* parser,
      char32_t
      __underlying_type ( type-id )
 
+   C++17 extension:
+
+     nested-name-specifier(opt) template-name
+
    GNU Extension:
 
    simple-type-specifier:
@@ -16429,9 +16439,11 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       /* Don't gobble tokens or issue error messages if this is an
         optional type-specifier.  */
-      if (flags & CP_PARSER_FLAGS_OPTIONAL)
+      if ((flags & CP_PARSER_FLAGS_OPTIONAL) || cxx_dialect >= cxx1z)
        cp_parser_parse_tentatively (parser);
 
+      token = cp_lexer_peek_token (parser->lexer);
+
       /* Look for the optional `::' operator.  */
       global_p
        = (cp_parser_global_scope_opt (parser,
@@ -16445,7 +16457,6 @@ cp_parser_simple_type_specifier (cp_parser* parser,
                                                /*type_p=*/false,
                                                /*is_declaration=*/false)
           != NULL_TREE);
-      token = cp_lexer_peek_token (parser->lexer);
       /* If we have seen a nested-name-specifier, and the next token
         is `template', then we are using the template-id production.  */
       if (parser->scope
@@ -16476,9 +16487,50 @@ cp_parser_simple_type_specifier (cp_parser* parser,
          && identifier_p (DECL_NAME (type)))
        maybe_note_name_used_in_class (DECL_NAME (type), type);
       /* If it didn't work out, we don't have a TYPE.  */
-      if ((flags & CP_PARSER_FLAGS_OPTIONAL)
+      if (((flags & CP_PARSER_FLAGS_OPTIONAL) || cxx_dialect >= cxx1z)
          && !cp_parser_parse_definitely (parser))
        type = NULL_TREE;
+      if (!type && cxx_dialect >= cxx1z)
+       {
+         if (flags & CP_PARSER_FLAGS_OPTIONAL)
+           cp_parser_parse_tentatively (parser);
+
+         cp_parser_global_scope_opt (parser,
+                                     /*current_scope_valid_p=*/false);
+         cp_parser_nested_name_specifier_opt (parser,
+                                              /*typename_keyword_p=*/false,
+                                              /*check_dependency_p=*/true,
+                                              /*type_p=*/false,
+                                              /*is_declaration=*/false);
+         tree name = cp_parser_identifier (parser);
+         if (name && TREE_CODE (name) == IDENTIFIER_NODE
+             && parser->scope != error_mark_node)
+           {
+             tree tmpl = cp_parser_lookup_name (parser, name,
+                                                none_type,
+                                                /*is_template=*/false,
+                                                /*is_namespace=*/false,
+                                                /*check_dependency=*/true,
+                                                /*ambiguous_decls=*/NULL,
+                                                token->location);
+             if (tmpl && tmpl != error_mark_node
+                 && DECL_CLASS_TEMPLATE_P (tmpl))
+               type = make_template_placeholder (tmpl);
+             else
+               {
+                 type = error_mark_node;
+                 if (!cp_parser_simulate_error (parser))
+                   cp_parser_name_lookup_error (parser, name, tmpl,
+                                                NLE_TYPE, token->location);
+               }
+           }
+         else
+           type = error_mark_node;
+
+         if ((flags & CP_PARSER_FLAGS_OPTIONAL)
+             && !cp_parser_parse_definitely (parser))
+           type = NULL_TREE;
+       }
       if (type && decl_specs)
        cp_parser_set_decl_spec_type (decl_specs, type,
                                      token,
@@ -18577,10 +18629,28 @@ cp_parser_init_declarator (cp_parser* parser,
      declared.  */
   resume_deferring_access_checks ();
 
-  /* Parse the declarator.  */
   token = cp_lexer_peek_token (parser->lexer);
+
+  cp_parser_declarator_kind cdk = CP_PARSER_DECLARATOR_NAMED;
+  if (token->type == CPP_OPEN_PAREN
+      && decl_specifiers->type
+      && is_auto (decl_specifiers->type)
+      && CLASS_PLACEHOLDER_TEMPLATE (decl_specifiers->type))
+    {
+      // C++17 deduction guide.
+      cdk = CP_PARSER_DECLARATOR_ABSTRACT;
+
+      for (int i = 0; i < ds_last; ++i)
+       if (i != ds_type_spec
+           && decl_specifiers->locations[i]
+           && !cp_parser_simulate_error (parser))
+         error_at (decl_specifiers->locations[i],
+                   "decl-specifier in declaration of deduction guide");
+    }
+
+  /* Parse the declarator.  */
   declarator
-    = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+    = cp_parser_declarator (parser, cdk,
                            &ctor_dtor_or_conv_p,
                            /*parenthesized_p=*/NULL,
                            member_p, friend_p);
@@ -18594,6 +18664,17 @@ cp_parser_init_declarator (cp_parser* parser,
   if (declarator == cp_error_declarator)
     return error_mark_node;
 
+  if (cdk == CP_PARSER_DECLARATOR_ABSTRACT)
+    {
+      gcc_assert (declarator->kind == cdk_function
+                 && !declarator->declarator);
+      tree t = CLASS_PLACEHOLDER_TEMPLATE (decl_specifiers->type);
+      declarator->declarator = make_id_declarator (NULL_TREE, dguide_name (t),
+                                                  sfk_none);
+      declarator->declarator->id_loc
+       = decl_specifiers->locations[ds_type_spec];
+    }
+
   /* Check that the number of template-parameter-lists is OK.  */
   if (!cp_parser_check_declarator_template_parameters (parser, declarator,
                                                       token->location))
@@ -20118,6 +20199,16 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg,
   cp_parser_type_specifier_seq (parser, /*is_declaration=*/false,
                                is_trailing_return,
                                &type_specifier_seq);
+  if (is_template_arg && type_specifier_seq.type
+      && TREE_CODE (type_specifier_seq.type) == TEMPLATE_TYPE_PARM
+      && CLASS_PLACEHOLDER_TEMPLATE (type_specifier_seq.type))
+    /* A bare template name as a template argument is a template template
+       argument, not a placeholder, so fail parsing it as a type argument.  */
+    {
+      gcc_assert (cp_parser_uncommitted_to_tentative_parse_p (parser));
+      cp_parser_simulate_error (parser);
+      return error_mark_node;
+    }
   if (type_specifier_seq.type == error_mark_node)
     return error_mark_node;
 
index 2fd1aac5d5d0a32bb7c2b287114c2208bd6001cc..f92366658c9eaa2b7b9aabd880bf648f2dab4bff 100644 (file)
@@ -4272,6 +4272,23 @@ template_parm_to_arg (tree t)
   return t;
 }
 
+/* Given a single level of template parameters (a TREE_VEC), return it
+   as a set of template arguments.  */
+
+static tree
+template_parms_level_to_args (tree parms)
+{
+  tree a = copy_node (parms);
+  TREE_TYPE (a) = NULL_TREE;
+  for (int i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
+    TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
+
+  if (CHECKING_P)
+    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
+
+  return a;
+}
+
 /* Given a set of template parameters, return them as a set of template
    arguments.  The template parameters are represented as a TREE_VEC, in
    the form documented in cp-tree.h for template arguments.  */
@@ -4292,15 +4309,7 @@ template_parms_to_args (tree parms)
 
   for (header = parms; header; header = TREE_CHAIN (header))
     {
-      tree a = copy_node (TREE_VALUE (header));
-      int i;
-
-      TREE_TYPE (a) = NULL_TREE;
-      for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
-       TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
-
-      if (CHECKING_P)
-       SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
+      tree a = template_parms_level_to_args (TREE_VALUE (header));
 
       if (length > 1)
        TREE_VEC_ELT (args, --l) = a;
@@ -11357,6 +11366,30 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   return t;
 }
 
+/* Substitute ARGS into one level PARMS of template parameters.  */
+
+static tree
+tsubst_template_parms_level (tree parms, tree args, tsubst_flags_t complain)
+{
+  if (parms == error_mark_node)
+    return error_mark_node;
+
+  tree new_vec = make_tree_vec (TREE_VEC_LENGTH (parms));
+
+  for (int i = 0; i < TREE_VEC_LENGTH (new_vec); ++i)
+    {
+      tree tuple = TREE_VEC_ELT (parms, i);
+
+      if (tuple == error_mark_node)
+       continue;
+
+      TREE_VEC_ELT (new_vec, i) =
+       tsubst_template_parm (tuple, args, complain);
+    }
+
+  return new_vec;
+}
+
 /* Return the result of substituting ARGS into the template parameters
    given by PARMS.  If there are m levels of ARGS and m + n levels of
    PARMS, then the result will contain n levels of PARMS.  For
@@ -11381,26 +11414,8 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
        new_parms = &(TREE_CHAIN (*new_parms)),
         parms = TREE_CHAIN (parms))
     {
-      tree new_vec =
-       make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms)));
-      int i;
-
-      for (i = 0; i < TREE_VEC_LENGTH (new_vec); ++i)
-       {
-          tree tuple;
-
-          if (parms == error_mark_node)
-            continue;
-
-          tuple = TREE_VEC_ELT (TREE_VALUE (parms), i);
-
-          if (tuple == error_mark_node)
-            continue;
-
-         TREE_VEC_ELT (new_vec, i) =
-           tsubst_template_parm (tuple, args, complain);
-       }
-
+      tree new_vec = tsubst_template_parms_level (TREE_VALUE (parms),
+                                                 args, complain);
       *new_parms =
        tree_cons (size_int (TMPL_PARMS_DEPTH (parms)
                             - TMPL_ARGS_DEPTH (args)),
@@ -23940,6 +23955,16 @@ make_auto (void)
   return make_auto_1 (get_identifier ("auto"), true);
 }
 
+/* Return a C++17 deduction placeholder for class template TMPL.  */
+
+tree
+make_template_placeholder (tree tmpl)
+{
+  tree t = make_auto_1 (DECL_NAME (tmpl), true);
+  CLASS_PLACEHOLDER_TEMPLATE (t) = tmpl;
+  return t;
+}
+
 /* Make a "constrained auto" type-specifier. This is an
    auto type with constraints that must be associated after
    deduction.  The constraint is formed from the given
@@ -24097,6 +24122,316 @@ extract_autos (tree type)
   return tree_vec;
 }
 
+/* The stem for deduction guide names.  */
+const char *const dguide_base = "__dguide_";
+
+/* Return the name for a deduction guide for class template TMPL.  */
+
+tree
+dguide_name (tree tmpl)
+{
+  tree type = (TYPE_P (tmpl) ? tmpl : TREE_TYPE (tmpl));
+  tree tname = TYPE_IDENTIFIER (type);
+  char *buf = (char *) alloca (1 + strlen (dguide_base)
+                              + IDENTIFIER_LENGTH (tname));
+  memcpy (buf, dguide_base, strlen (dguide_base));
+  memcpy (buf + strlen (dguide_base), IDENTIFIER_POINTER (tname),
+         IDENTIFIER_LENGTH (tname) + 1);
+  tree dname = get_identifier (buf);
+  TREE_TYPE (dname) = type;
+  return dname;
+}
+
+/* True if NAME is the name of a deduction guide.  */
+
+bool
+dguide_name_p (tree name)
+{
+  return (TREE_TYPE (name)
+         && !strncmp (IDENTIFIER_POINTER (name), dguide_base,
+                      strlen (dguide_base)));
+}
+
+/* True if FN is a deduction guide.  */
+
+bool
+deduction_guide_p (tree fn)
+{
+  if (tree name = DECL_NAME (fn))
+    return dguide_name_p (name);
+  return false;
+}
+
+/* OLDDECL is a _DECL for a template parameter.  Return a similar parameter at
+   LEVEL:INDEX, using tsubst_args and complain for substitution into non-type
+   template parameter types.  Note that the handling of template template
+   parameters relies on current_template_parms being set appropriately for the
+   new template.  */
+
+static tree
+rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
+                      tree tsubst_args, tsubst_flags_t complain)
+{
+  tree oldidx = get_template_parm_index (olddecl);
+
+  tree newtype;
+  if (TREE_CODE (olddecl) == TYPE_DECL
+      || TREE_CODE (olddecl) == TEMPLATE_DECL)
+    {
+      newtype = copy_type (TREE_TYPE (olddecl));
+      TYPE_MAIN_VARIANT (newtype) = newtype;
+    }
+  else
+    newtype = tsubst (TREE_TYPE (olddecl), tsubst_args,
+                     complain, NULL_TREE);
+
+  tree newdecl
+    = build_decl (DECL_SOURCE_LOCATION (olddecl), TREE_CODE (olddecl),
+                 DECL_NAME (olddecl), newtype);
+  SET_DECL_TEMPLATE_PARM_P (newdecl);
+
+  tree newidx;
+  if (TREE_CODE (olddecl) == TYPE_DECL
+      || TREE_CODE (olddecl) == TEMPLATE_DECL)
+    {
+      newidx = TEMPLATE_TYPE_PARM_INDEX (newtype)
+       = build_template_parm_index (index, level, level,
+                                    newdecl, newtype);
+      TYPE_STUB_DECL (newtype) = TYPE_NAME (newtype) = newdecl;
+      TYPE_CANONICAL (newtype) = canonical_type_parameter (newtype);
+
+      if (TREE_CODE (olddecl) == TEMPLATE_DECL)
+       {
+         DECL_TEMPLATE_RESULT (newdecl)
+           = build_decl (DECL_SOURCE_LOCATION (olddecl), TYPE_DECL,
+                         DECL_NAME (olddecl), newtype);
+         DECL_ARTIFICIAL (DECL_TEMPLATE_RESULT (newdecl)) = true;
+         // First create a copy (ttargs) of tsubst_args with an
+         // additional level for the template template parameter's own
+         // template parameters (ttparms).
+         tree ttparms = (INNERMOST_TEMPLATE_PARMS
+                         (DECL_TEMPLATE_PARMS (olddecl)));
+         const int depth = TMPL_ARGS_DEPTH (tsubst_args);
+         tree ttargs = make_tree_vec (depth + 1);
+         for (int i = 0; i < depth; ++i)
+           TREE_VEC_ELT (ttargs, i) = TREE_VEC_ELT (tsubst_args, i);
+         TREE_VEC_ELT (ttargs, depth)
+           = template_parms_level_to_args (ttparms);
+         // Substitute ttargs into ttparms to fix references to
+         // other template parameters.
+         ttparms = tsubst_template_parms_level (ttparms, ttargs,
+                                                complain);
+         // Now substitute again with args based on tparms, to reduce
+         // the level of the ttparms.
+         ttargs = current_template_args ();
+         ttparms = tsubst_template_parms_level (ttparms, ttargs,
+                                                complain);
+         // Finally, tack the adjusted parms onto tparms.
+         ttparms = tree_cons (size_int (depth), ttparms,
+                              current_template_parms);
+         DECL_TEMPLATE_PARMS (newdecl) = ttparms;
+       }
+    }
+  else
+    {
+      tree oldconst = TEMPLATE_PARM_DECL (oldidx);
+      tree newconst
+       = build_decl (DECL_SOURCE_LOCATION (oldconst),
+                     TREE_CODE (oldconst),
+                     DECL_NAME (oldconst), newtype);
+      TREE_CONSTANT (newconst) = TREE_CONSTANT (newdecl)
+       = TREE_READONLY (newconst) = TREE_READONLY (newdecl) = true;
+      SET_DECL_TEMPLATE_PARM_P (newconst);
+      newidx = build_template_parm_index (index, level, level,
+                                         newconst, newtype);
+      DECL_INITIAL (newdecl) = DECL_INITIAL (newconst) = newidx;
+    }
+
+  TEMPLATE_PARM_PARAMETER_PACK (newidx)
+    = TEMPLATE_PARM_PARAMETER_PACK (oldidx);
+  return newdecl;
+}
+
+/* Returns a C++17 class deduction guide template based on the constructor
+   CTOR.  */
+
+static tree
+build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
+{
+  if (outer_args)
+    ctor = tsubst (ctor, outer_args, complain, ctor);
+  tree type = DECL_CONTEXT (ctor);
+  tree fn_tmpl;
+  if (TREE_CODE (ctor) == TEMPLATE_DECL)
+    {
+      fn_tmpl = ctor;
+      ctor = DECL_TEMPLATE_RESULT (fn_tmpl);
+    }
+  else
+    fn_tmpl = DECL_TI_TEMPLATE (ctor);
+
+  tree tparms = DECL_TEMPLATE_PARMS (fn_tmpl);
+  /* If type is a member class template, DECL_TI_ARGS (ctor) will have fully
+     specialized args for the enclosing class.  Strip those off, as the
+     deduction guide won't have those template parameters.  */
+  tree targs = get_innermost_template_args (DECL_TI_ARGS (ctor),
+                                           TMPL_PARMS_DEPTH (tparms));
+  /* Discard the 'this' parameter.  */
+  tree fparms = FUNCTION_ARG_CHAIN (ctor);
+  tree fargs = TREE_CHAIN (DECL_ARGUMENTS (ctor));
+  tree ci = get_constraints (ctor);
+
+  if (PRIMARY_TEMPLATE_P (fn_tmpl))
+    {
+      /* For a member template constructor, we need to flatten the two template
+        parameter lists into one, and then adjust the function signature
+        accordingly.  This gets...complicated.  */
+      ++processing_template_decl;
+      tree save_parms = current_template_parms;
+
+      /* For a member template we should have two levels of parms/args, one for
+        the class and one for the constructor.  We stripped specialized args
+        for further enclosing classes above.  */
+      const int depth = 2;
+      gcc_assert (TMPL_ARGS_DEPTH (targs) == depth);
+
+      /* Template args for translating references to the two-level template
+        parameters into references to the one-level template parameters we are
+        creating.  */
+      tree tsubst_args = copy_node (targs);
+      TMPL_ARGS_LEVEL (tsubst_args, depth)
+       = copy_node (TMPL_ARGS_LEVEL (tsubst_args, depth));
+
+      /* Template parms for the constructor template.  */
+      tree ftparms = TREE_VALUE (tparms);
+      unsigned flen = TREE_VEC_LENGTH (ftparms);
+      /* Template parms for the class template.  */
+      tparms = TREE_CHAIN (tparms);
+      tree ctparms = TREE_VALUE (tparms);
+      unsigned clen = TREE_VEC_LENGTH (ctparms);
+      /* Template parms for the deduction guide start as a copy of the template
+        parms for the class.  We set current_template_parms for
+        lookup_template_class_1.  */
+      current_template_parms = tparms = copy_node (tparms);
+      tree new_vec = TREE_VALUE (tparms) = make_tree_vec (flen + clen);
+      for (unsigned i = 0; i < clen; ++i)
+       TREE_VEC_ELT (new_vec, i) = TREE_VEC_ELT (ctparms, i);
+
+      /* Now we need to rewrite the constructor parms to append them to the
+        class parms.  */
+      for (unsigned i = 0; i < flen; ++i)
+       {
+         unsigned index = i + clen;
+         unsigned level = 1;
+         tree oldelt = TREE_VEC_ELT (ftparms, i);
+         tree olddecl = TREE_VALUE (oldelt);
+         tree newdecl = rewrite_template_parm (olddecl, index, level,
+                                               tsubst_args, complain);
+         tree newdef = tsubst_template_arg (TREE_PURPOSE (oldelt),
+                                            tsubst_args, complain, ctor);
+         tree list = build_tree_list (newdef, newdecl);
+         TEMPLATE_PARM_CONSTRAINTS (list)
+           = tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt),
+                                     tsubst_args, complain, ctor);
+         TREE_VEC_ELT (new_vec, index) = list;
+         TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list);
+       }
+
+      /* Now we have a final set of template parms to substitute into the
+        function signature.  */
+      targs = template_parms_to_args (tparms);
+      fparms = tsubst (fparms, tsubst_args, complain, ctor);
+      fargs = tsubst (fargs, tsubst_args, complain, ctor);
+      if (ci)
+       ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor);
+
+      current_template_parms = save_parms;
+      --processing_template_decl;
+    }
+
+  tree fntype = build_function_type (type, fparms);
+  tree ded_fn = build_lang_decl_loc (DECL_SOURCE_LOCATION (ctor),
+                                    FUNCTION_DECL,
+                                    dguide_name (type), fntype);
+  DECL_ARGUMENTS (ded_fn) = fargs;
+  tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false);
+  DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn;
+  TREE_TYPE (ded_tmpl) = TREE_TYPE (ded_fn);
+  DECL_TEMPLATE_INFO (ded_fn) = build_template_info (ded_tmpl, targs);
+  if (ci)
+    set_constraints (ded_tmpl, ci);
+
+  return ded_tmpl;
+}
+
+/* Deduce template arguments for the class template TMPL based on the
+   initializer INIT, and return the resulting type.  */
+
+tree
+do_class_deduction (tree tmpl, tree init, tsubst_flags_t complain)
+{
+  gcc_assert (DECL_CLASS_TEMPLATE_P (tmpl));
+  tree type = TREE_TYPE (tmpl);
+
+  vec<tree,va_gc> *args;
+  if (TREE_CODE (init) == TREE_LIST)
+    args = make_tree_vector_from_list (init);
+  else
+    args = make_tree_vector_single (init);
+
+  if (args->length() == 1)
+    {
+      /* First try to deduce directly, since we don't have implicitly-declared
+        constructors yet.  */
+      tree parms = build_tree_list (NULL_TREE, type);
+      tree tparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
+      tree targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
+      int err = type_unification_real (tparms, targs, parms, &(*args)[0],
+                                      1, /*subr*/false, DEDUCE_CALL,
+                                      LOOKUP_NORMAL, NULL, /*explain*/false);
+      if (err == 0)
+       return tsubst (type, targs, complain, tmpl);
+    }
+
+  tree dname = dguide_name (tmpl);
+  tree cands = lookup_qualified_name (CP_DECL_CONTEXT (tmpl), dname,
+                                     /*type*/false, /*complain*/false,
+                                     /*hidden*/false);
+  if (cands == error_mark_node)
+    cands = NULL_TREE;
+
+  tree outer_args = NULL_TREE;
+  if (DECL_CLASS_SCOPE_P (tmpl)
+      && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (tmpl)))
+    {
+      outer_args = CLASSTYPE_TI_ARGS (DECL_CONTEXT (tmpl));
+      type = TREE_TYPE (most_general_template (tmpl));
+    }
+
+  if (CLASSTYPE_METHOD_VEC (type))
+    // FIXME cache artificial deduction guides
+    for (tree fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns))
+      {
+       tree fn = OVL_CURRENT (fns);
+       tree guide = build_deduction_guide (fn, outer_args, complain);
+       cands = ovl_cons (guide, cands);
+      }
+
+  if (cands == NULL_TREE)
+    {
+      error ("cannot deduce template arguments for %qT, as it has "
+            "no deduction guides or user-declared constructors", type);
+      return error_mark_node;
+    }
+
+  tree t = build_new_function_call (cands, &args, /*koenig*/false,
+                                   complain|tf_decltype);
+
+  release_tree_vector (args);
+
+  return TREE_TYPE (t);
+}
+
 /* 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.  */
 
@@ -24175,6 +24510,9 @@ do_auto_deduction (tree type, tree init, tree auto_node,
          return error_mark_node;
        }
     }
+  else if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+    /* C++17 class template argument deduction.  */
+    return do_class_deduction (tmpl, init, complain);
   else
     {
       tree parms = build_tree_list (NULL_TREE, type);
@@ -24274,6 +24612,20 @@ splice_late_return_type (tree type, tree late_return_type)
 {
   if (is_auto (type))
     {
+      if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type))
+       {
+         if (!late_return_type)
+           error ("deduction guide must have trailing return type");
+         else if (CLASS_TYPE_P (late_return_type)
+                  && CLASSTYPE_TEMPLATE_INFO (late_return_type)
+                  && CLASSTYPE_TI_TEMPLATE (late_return_type) == tmpl)
+           /* OK */;
+         else
+           error ("trailing return type %qT of deduction guide is not "
+                  "a specialization of %qT",
+                  late_return_type, TREE_TYPE (tmpl));
+       }
+
       if (late_return_type)
        return late_return_type;
 
@@ -24288,14 +24640,15 @@ splice_late_return_type (tree type, tree late_return_type)
 }
 
 /* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto' or
-   'decltype(auto)'.  */
+   'decltype(auto)' or a deduced class template.  */
 
 bool
 is_auto (const_tree type)
 {
   if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
       && (TYPE_IDENTIFIER (type) == get_identifier ("auto")
-         || TYPE_IDENTIFIER (type) == get_identifier ("decltype(auto)")))
+         || TYPE_IDENTIFIER (type) == get_identifier ("decltype(auto)")
+         || CLASS_PLACEHOLDER_TEMPLATE (type)))
     return true;
   else
     return false;
index 6e226856edcbc4021ab370a7d14bdd93343dadef..a063ea3439234bf5ad3c2a2c4605f5cdc9315875 100644 (file)
@@ -1952,11 +1952,23 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
       return error_mark_node;
     }
 
-  if (type_uses_auto (type))
+  if (tree anode = type_uses_auto (type))
     {
-      if (complain & tf_error)
-       error ("invalid use of %<auto%>");
-      return error_mark_node;
+      if (!CLASS_PLACEHOLDER_TEMPLATE (anode))
+       {
+         if (complain & tf_error)
+           error ("invalid use of %qT", anode);
+         return error_mark_node;
+       }
+      else if (!parms)
+       {
+         if (complain & tf_error)
+           error ("cannot deduce template arguments for %qT from ()", anode);
+         return error_mark_node;
+       }
+      else
+       type = do_auto_deduction (type, parms, anode, complain,
+                                 adc_variable_type);
     }
 
   if (processing_template_decl)
diff --git a/gcc/testsuite/g++.dg/concepts/class-deduction1.C b/gcc/testsuite/g++.dg/concepts/class-deduction1.C
new file mode 100644 (file)
index 0000000..ad48cf8
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-options "-std=c++1z -fconcepts" }
+
+template <class T>
+concept bool Isint = __is_same_as(T,int);
+
+template <class T>
+struct A
+{
+  int i;
+  A(...);
+};
+
+template <Isint I>
+A(I) -> A<I>;
+
+A a(1);
+A a2(1.0);                     // { dg-error "" }
index ca163321e7620e15962eb70b5155bac872ccf87f..b91eb945eb1f709224a0c2af1bc7c57266e83c09 100644 (file)
@@ -10,5 +10,5 @@ concept bool C2 = true;
 template<C1 T> // { dg-error "not a type" }
 constexpr bool f1( )  { return true; }
 
-template<C2<int> T> // { dg-error "expected" }
+template<C2<int> T> // { dg-error "expected|not a type" }
 constexpr bool f2( )  { return true; }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction1.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction1.C
new file mode 100644 (file)
index 0000000..87fced9
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  A(T);
+};
+
+A a (42);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction10.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction10.C
new file mode 100644 (file)
index 0000000..8bc4288
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  int i;
+  A(...);
+};
+
+template <class T>
+A(T) -> A<T> { }               // { dg-error "1:function body" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction11.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction11.C
new file mode 100644 (file)
index 0000000..4e90292
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  int i;
+  A(...);
+};
+
+template <class T>
+static A(T) -> A<T>;           // { dg-error "1:decl-specifier" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction12.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction12.C
new file mode 100644 (file)
index 0000000..9eb541d
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  template<class U, template<U u> class P>
+  A(T,U,P<42>);
+};
+
+template <int I> struct B { };
+
+int i;
+A a(&i,2,B<42>());
+
+template <class,class> class same;
+template <class T> class same<T,T> {};
+same<decltype(a), A<int*>> s;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction13.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction13.C
new file mode 100644 (file)
index 0000000..0e2d235
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  template <class U>
+  struct B
+  {
+    template <class V>
+    B(T,U,V);
+  };
+};
+
+A<int>::B b(1,2.0,'\3');
+
+template <class,class> class same;
+template <class T> class same<T,T> {};
+same<decltype(b), A<int>::B<double>> s;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction2.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction2.C
new file mode 100644 (file)
index 0000000..736b263
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  template <class U>
+  A(T, U);
+};
+
+A a (42, 1.0);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction3.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction3.C
new file mode 100644 (file)
index 0000000..ed86965
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-options -std=c++1z }
+
+template <int I>
+struct A { };
+
+template <int I>
+struct B
+{
+  template<template<int>class T>
+  B(T<I>);
+};
+
+A<42> a;
+B b (a);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction4.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction4.C
new file mode 100644 (file)
index 0000000..16c41f4
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-options -std=c++1z }
+
+template <int I, int J>
+struct A { };
+
+template <int I>
+struct B
+{
+  template<int J>
+  B(A<I,J>);
+};
+
+A<42,24> a;
+B b (a);
+
+int main()
+{
+  (B(a));
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction5.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction5.C
new file mode 100644 (file)
index 0000000..b94a300
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  int i;
+};
+
+A<int> a1;
+A a(a1);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction6.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction6.C
new file mode 100644 (file)
index 0000000..569217d
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  int i;
+};
+
+struct B : A<int> {} b;
+
+A a(b);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction7.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction7.C
new file mode 100644 (file)
index 0000000..8e982b9
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  int i;
+};
+
+template <class T>
+A(T);                         // { dg-error "must have trailing return type" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction8.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction8.C
new file mode 100644 (file)
index 0000000..3658315
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  int i;
+  A(...);                      // { dg-message "candidate" }
+};
+
+A a(42);                       // { dg-error "" }
+
+template <class T>
+A(T) -> A<T>;
+
+A a2(42);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction9.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction9.C
new file mode 100644 (file)
index 0000000..5a2b4f6
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-options -std=c++1z }
+
+namespace N {
+  template <class T>
+  struct A
+  {
+    int i;
+    A(...);
+  };
+}
+
+template <class T>
+N::A(T) -> N::A<T>;            // { dg-error "scope" }
+
+namespace N {
+  template <class T>
+  A(T) -> A<T>;
+}
index 62adc1b16f99f1ab809b030370ad9d733b148b6f..d53d3177e6c98eda6ce41473a03591065c8f0927 100644 (file)
@@ -8,4 +8,4 @@ template<int> struct A
 };
 
 // Instead of the bogus error we get a different error.
-// { dg-error "template-name" "" { target *-*-* } 7 }
+// { dg-error "template-name|expected" "" { target *-*-* } 7 }
index baf0fe77816e40a2f098a6d00410f3ec01c6c999..5c39b602de58cc3ef4e2f6fdd8d90f908cfa30a1 100644 (file)
@@ -5,13 +5,12 @@
 namespace N
 {
     template<typename> 
-    struct X { };              // { dg-message "N::X" }
+    struct X { };
 }
 
 N::X X;                           // { dg-error "" "" }
 
 int main()
 {
-    return sizeof(X);             // { dg-error "" "" }
-    // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } 15 }
+    return sizeof(X);      // { dg-prune-output "not declared in this scope" }
 }
index 6689c8bfa1dde1c595bb0e0adaaa5fb95d239a72..93c7defb165b19b7cab766b9d7ac13593b53f50a 100644 (file)
@@ -3,5 +3,5 @@ namespace N {
 }
 
 int main() {
-  N::C(); // { dg-error "template" }
+  N::C(); // { dg-error "template|deduction" }
 }
index 83fb86bb948e9b3e1dba5ee8c2a1983139c5bbda..a8dae01afe2df5673746b08121fa6e584cd38ce5 100644 (file)
@@ -17,7 +17,7 @@ int main()
               find_if( l.begin(), l.end(),
                        // This is a typo, it should be bind2nd, but an
                        // ICE is not a very helpful diagnostic!
-                       binder2nd( equal_to<int>(), 2 ) ); // { dg-error "" 
+                       binder2nd( equal_to<int>(), 2 ) ); // { dg-error "" "" { target c++14_down } }
       assert( *(it) == 2 );
 }
 
index bba5ff0671fc75eee2bb8872be9d91c30f0e4a8a..3150422e3c5042a5d6016fe4142035f2207ac6fd 100644 (file)
@@ -16,7 +16,7 @@ int main()
               std::find_if( l.begin(), l.end(),
                        // This is a typo, it should be bind2nd, but an
                        // ICE is not a very helpful diagnostic!
-                       std::binder2nd( std::equal_to<int>(), 2 ) ); // { dg-error "" 
+                       std::binder2nd( std::equal_to<int>(), 2 ) ); // { dg-error "" "" { target c++14_down } }
       assert( *(it) == 2 );
 }