PR c++/79316 - default argument in deduction guide
authorJason Merrill <jason@redhat.com>
Thu, 9 Feb 2017 20:55:54 +0000 (15:55 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 9 Feb 2017 20:55:54 +0000 (15:55 -0500)
PR c++/79350 - explicit deduction guide
* parser.c (cp_parser_constructor_declarator_p)
(cp_parser_direct_declarator): Parse deduction guides more like
constructors.
* cp-tree.h (enum special_function_kind): Add sfk_deduction_guide.
* tree.c (special_function_p): Return it.
* decl.c (check_special_function_return_type): Handle it.
(grokdeclarator, grokfndecl): Adjust.
(cp_finish_decl): Pass flags to do_auto_deduction.
* error.c (dump_decl_name): Use TFF_UNQUALIFIED_NAME.
* pt.c (dguide_name_p): Take a const_tree.
(do_class_deduction): Handle explicit.
(do_auto_deduction): Pass flags through.
(build_deduction_guide): Copy explicit flag.

From-SVN: r245314

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/tree.c
gcc/testsuite/g++.dg/cpp1z/class-deduction27.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction28.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction9.C

index 6639fbd..caa1df9 100644 (file)
@@ -1,3 +1,21 @@
+2017-02-09  Jason Merrill  <jason@redhat.com>
+
+       PR c++/79316 - default argument in deduction guide
+       PR c++/79350 - explicit deduction guide
+       * parser.c (cp_parser_constructor_declarator_p)
+       (cp_parser_direct_declarator): Parse deduction guides more like
+       constructors.
+       * cp-tree.h (enum special_function_kind): Add sfk_deduction_guide.
+       * tree.c (special_function_p): Return it.
+       * decl.c (check_special_function_return_type): Handle it.
+       (grokdeclarator, grokfndecl): Adjust.
+       (cp_finish_decl): Pass flags to do_auto_deduction.
+       * error.c (dump_decl_name): Use TFF_UNQUALIFIED_NAME.
+       * pt.c (dguide_name_p): Take a const_tree.
+       (do_class_deduction): Handle explicit.
+       (do_auto_deduction): Pass flags through.
+       (build_deduction_guide): Copy explicit flag.
+
 2017-02-09  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/79429
index 77bf614..a410926 100644 (file)
@@ -4733,6 +4733,7 @@ enum special_function_kind {
                              deletes the object after it has been
                              destroyed.  */
   sfk_conversion,         /* A conversion operator.  */
+  sfk_deduction_guide,    /* A class template deduction guide.  */
   sfk_inheriting_constructor /* An inheriting constructor */
 };
 
@@ -6150,7 +6151,8 @@ extern tree do_auto_deduction                   (tree, tree, tree);
 extern tree do_auto_deduction                   (tree, tree, tree,
                                                  tsubst_flags_t,
                                                  auto_deduction_context,
-                                                tree = NULL_TREE);
+                                                tree = NULL_TREE,
+                                                int = LOOKUP_NORMAL);
 extern tree type_uses_auto                     (tree);
 extern tree type_uses_auto_or_concept          (tree);
 extern void append_type_to_template_for_access_check (tree, tree, tree,
@@ -6280,7 +6282,7 @@ 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);
+extern bool deduction_guide_p                  (const_tree);
 
 /* in repo.c */
 extern void init_repo                          (void);
index d1d485a..734a6c7 100644 (file)
@@ -6821,7 +6821,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
       if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
        adc = adc_decomp_type;
       type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
-                                                  tf_warning_or_error, adc);
+                                                  tf_warning_or_error, adc,
+                                                  NULL_TREE, flags);
       if (type == error_mark_node)
        return;
       if (TREE_CODE (type) == FUNCTION_TYPE)
@@ -8730,14 +8731,6 @@ grokfndecl (tree ctype,
                    "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);
@@ -9758,6 +9751,20 @@ check_special_function_return_type (special_function_kind sfk,
       type = optype;
       break;
 
+    case sfk_deduction_guide:
+      if (type)
+       error ("return type specified for deduction guide");
+      else if (type_quals != TYPE_UNQUALIFIED)
+       error_at (smallest_type_quals_location (type_quals, locations),
+                 "qualifiers are not allowed on declaration of "
+                 "deduction guide");
+      type = make_template_placeholder (CLASSTYPE_TI_TEMPLATE (optype));
+      for (int i = 0; i < ds_last; ++i)
+       if (i != ds_explicit && locations[i])
+         error_at (locations[i],
+                   "decl-specifier in declaration of deduction guide");
+      break;
+
     default:
       gcc_unreachable ();
     }
@@ -10105,7 +10112,6 @@ grokdeclarator (const cp_declarator *declarator,
                  {
                    gcc_assert (flags == NO_SPECIAL);
                    flags = TYPENAME_FLAG;
-                   ctor_return_type = TREE_TYPE (dname);
                    sfk = sfk_conversion;
                    if (is_typename_at_global_scope (dname))
                      name = identifier_to_locale (IDENTIFIER_POINTER (dname));
@@ -10285,8 +10291,9 @@ grokdeclarator (const cp_declarator *declarator,
 #endif
   typedef_type = type;
 
-
-  if (sfk != sfk_conversion)
+  if (sfk == sfk_conversion || sfk == sfk_deduction_guide)
+    ctor_return_type = TREE_TYPE (dname);
+  else
     ctor_return_type = ctype;
 
   if (sfk != sfk_none)
@@ -10906,12 +10913,13 @@ grokdeclarator (const cp_declarator *declarator,
                        if (!late_return_type)
                          {
                            if (dguide_name_p (unqualified_id))
-                             error_at (typespec_loc, "deduction guide for "
-                                       "%qT must have trailing return type",
-                                       TREE_TYPE (tmpl));
+                             error_at (declarator->id_loc, "deduction guide "
+                                       "for %qT must have trailing return "
+                                       "type", TREE_TYPE (tmpl));
                            else
-                             error_at (typespec_loc, "deduced class type %qT "
-                                       "in function return type", type);
+                             error_at (declarator->id_loc, "deduced class "
+                                       "type %qT in function return type",
+                                       type);
                            inform (DECL_SOURCE_LOCATION (tmpl),
                                    "%qD declared here", tmpl);
                          }
@@ -11039,6 +11047,11 @@ grokdeclarator (const cp_declarator *declarator,
                if (late_return_type_p)
                  error ("a conversion function cannot have a trailing return type");
              }
+           else if (sfk == sfk_deduction_guide)
+             {
+               if (explicitp == 1)
+                 explicitp = 2;
+             }
 
            arg_types = grokparms (declarator->u.function.parameters,
                                   &parms);
@@ -12207,6 +12220,8 @@ grokdeclarator (const cp_declarator *declarator,
        if (decl == NULL_TREE)
          return error_mark_node;
 
+       if (explicitp == 2)
+         DECL_NONCONVERTING_P (decl) = 1;
        if (staticp == 1)
          {
            int invalid_static = 0;
index 92137f7..d8c5d5e 100644 (file)
@@ -1015,7 +1015,7 @@ dump_decl_name (cxx_pretty_printer *pp, tree t, int flags)
   if (dguide_name_p (t))
     {
       dump_decl (pp, CLASSTYPE_TI_TEMPLATE (TREE_TYPE (t)),
-                TFF_PLAIN_IDENTIFIER);
+                TFF_UNQUALIFIED_NAME);
       return;
     }
 
index aadf44d..8812f8c 100644 (file)
@@ -19050,26 +19050,9 @@ cp_parser_init_declarator (cp_parser* parser,
 
   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, cdk,
+    = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
                            &ctor_dtor_or_conv_p,
                            /*parenthesized_p=*/NULL,
                            member_p, friend_p);
@@ -19083,17 +19066,6 @@ 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))
@@ -19136,6 +19108,25 @@ cp_parser_init_declarator (cp_parser* parser,
 
   if (function_declarator_p (declarator))
     {
+      /* Handle C++17 deduction guides.  */
+      if (!decl_specifiers->type
+         && ctor_dtor_or_conv_p <= 0
+         && cxx_dialect >= cxx1z)
+       {
+         cp_declarator *id = get_id_declarator (declarator);
+         tree name = id->u.id.unqualified_name;
+         parser->scope = id->u.id.qualifying_scope;
+         tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc);
+         if (tmpl
+             && (DECL_CLASS_TEMPLATE_P (tmpl)
+                 || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
+           {
+             id->u.id.unqualified_name = dguide_name (tmpl);
+             id->u.id.sfk = sfk_deduction_guide;
+             ctor_dtor_or_conv_p = 1;
+           }
+       }
+
       /* Check to see if the token indicates the start of a
         function-definition.  */
       if (cp_parser_token_starts_function_definition_p (token))
@@ -19202,8 +19193,8 @@ cp_parser_init_declarator (cp_parser* parser,
 
   /* [dcl.dcl]
 
-     Only in function declarations for constructors, destructors, and
-     type conversions can the decl-specifier-seq be omitted.
+     Only in function declarations for constructors, destructors, type
+     conversions, and deduction guides can the decl-specifier-seq be omitted.
 
      We explicitly postpone this check past the point where we handle
      function-definitions because we tolerate function-definitions
@@ -19453,8 +19444,8 @@ cp_parser_init_declarator (cp_parser* parser,
      attributes [opt] direct-abstract-declarator
 
    If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to
-   detect constructor, destructor or conversion operators. It is set
-   to -1 if the declarator is a name, and +1 if it is a
+   detect constructors, destructors, deduction guides, or conversion operators.
+   It is set to -1 if the declarator is a name, and +1 if it is a
    function. Otherwise it is set to zero. Usually you just want to
    test for >0, but internally the negative value is used.
 
@@ -25929,8 +25920,8 @@ cp_parser_global_scope_opt (cp_parser* parser, bool current_scope_valid_p)
 }
 
 /* Returns TRUE if the upcoming token sequence is the start of a
-   constructor declarator.  If FRIEND_P is true, the declarator is
-   preceded by the `friend' specifier.  */
+   constructor declarator or C++17 deduction guide.  If FRIEND_P is true, the
+   declarator is preceded by the `friend' specifier.  */
 
 static bool
 cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
@@ -25975,8 +25966,10 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
                               || friend_p);
 
   /* Outside of a class-specifier, there must be a
-     nested-name-specifier.  */
-  if (!nested_name_specifier && outside_class_specifier_p)
+     nested-name-specifier.  Except in C++17 mode, where we
+     might be declaring a guiding declaration.  */
+  if (!nested_name_specifier && outside_class_specifier_p
+      && cxx_dialect < cxx1z)
     constructor_p = false;
   else if (nested_name_specifier == error_mark_node)
     constructor_p = false;
@@ -26007,6 +26000,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
           };
 
         we must recognize that the nested `S' names a class.  */
+      if (cxx_dialect >= cxx1z)
+       cp_parser_parse_tentatively (parser);
+
       tree type_decl;
       type_decl = cp_parser_class_name (parser,
                                        /*typename_keyword_p=*/false,
@@ -26015,6 +26011,24 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
                                        /*check_dependency_p=*/false,
                                        /*class_head_p=*/false,
                                        /*is_declaration=*/false);
+
+      if (cxx_dialect >= cxx1z
+         && !cp_parser_parse_definitely (parser))
+       {
+         type_decl = NULL_TREE;
+         tree tmpl = cp_parser_template_name (parser,
+                                              /*template_keyword*/false,
+                                              /*check_dependency_p*/false,
+                                              /*is_declaration*/false,
+                                              none_type,
+                                              /*is_identifier*/NULL);
+         if (DECL_CLASS_TEMPLATE_P (tmpl)
+             || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
+           /* It's a deduction guide, return true.  */;
+         else
+           cp_parser_simulate_error (parser);
+       }
+
       /* If there was no class-name, then this is not a constructor.
         Otherwise, if we are in a class-specifier and we aren't
         handling a friend declaration, check that its type matches
@@ -26022,6 +26036,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
         is left alone for error recovery purposes.  */
       constructor_p = (!cp_parser_error_occurred (parser)
                       && (outside_class_specifier_p
+                          || type_decl == NULL_TREE
                           || type_decl == error_mark_node
                           || same_type_p (current_class_type,
                                           TREE_TYPE (type_decl))));
@@ -26056,7 +26071,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
             in the scope of the class.  */
          if (current_class_type)
            type = NULL_TREE;
-         else
+         else if (type_decl)
            {
              type = TREE_TYPE (type_decl);
              if (TREE_CODE (type) == TYPENAME_TYPE)
index 8863c28..58d6016 100644 (file)
@@ -24786,7 +24786,7 @@ dguide_name_p (tree name)
 /* True if FN is a deduction guide.  */
 
 bool
-deduction_guide_p (tree fn)
+deduction_guide_p (const_tree fn)
 {
   if (DECL_P (fn))
     if (tree name = DECL_NAME (fn))
@@ -24999,6 +24999,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
                                     dguide_name (type), fntype);
   DECL_ARGUMENTS (ded_fn) = fargs;
   DECL_ARTIFICIAL (ded_fn) = true;
+  DECL_NONCONVERTING_P (ded_fn) = DECL_NONCONVERTING_P (ctor);
   tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false);
   DECL_ARTIFICIAL (ded_tmpl) = true;
   DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn;
@@ -25015,8 +25016,9 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
    template TMPL based on the initializer INIT, and return the resulting
    type.  */
 
-tree
-do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain)
+static tree
+do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
+                   tsubst_flags_t complain)
 {
   if (!DECL_CLASS_TEMPLATE_P (tmpl))
     {
@@ -25083,9 +25085,48 @@ do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain)
       return error_mark_node;
     }
 
+  /* Prune explicit deduction guides in copy-initialization context.  */
+  tree old_cands = cands;
+  if (flags & LOOKUP_ONLYCONVERTING)
+    {
+      tree t = cands;
+      for (; t; t = OVL_NEXT (t))
+       if (DECL_NONCONVERTING_P (DECL_TEMPLATE_RESULT (OVL_CURRENT (t))))
+         break;
+      if (t)
+       {
+         tree pruned = NULL_TREE;
+         for (t = cands; t; t = OVL_NEXT (t))
+           {
+             tree f = OVL_CURRENT (t);
+             if (!DECL_NONCONVERTING_P (DECL_TEMPLATE_RESULT (f)))
+               pruned = build_overload (f, pruned);
+           }
+         cands = pruned;
+         if (cands == NULL_TREE)
+           {
+             error ("cannot deduce template arguments for copy-initialization"
+                    " of %qT, as it has no non-explicit deduction guides or "
+                    "user-declared constructors", type);
+             return error_mark_node;
+           }
+       }
+    }
+
   ++cp_unevaluated_operand;
   tree t = build_new_function_call (cands, &args, /*koenig*/false,
-                                   complain|tf_decltype);
+                                   tf_decltype);
+
+  if (t == error_mark_node && (complain & tf_warning_or_error))
+    {
+      error ("class template argument deduction failed:");
+      t = build_new_function_call (cands, &args, /*koenig*/false,
+                                  complain | tf_decltype);
+      if (old_cands != cands)
+       inform (input_location, "explicit deduction guides not considered "
+               "for copy-initialization");
+    }
+
   --cp_unevaluated_operand;
   release_tree_vector (args);
 
@@ -25106,7 +25147,10 @@ do_auto_deduction (tree type, tree init, tree auto_node)
 /* 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.
    The CONTEXT determines the context in which auto deduction is performed
-   and is used to control error diagnostics.
+   and is used to control error diagnostics.  FLAGS are the LOOKUP_* flags.
+   OUTER_TARGS are used during template argument deduction
+   (context == adc_unify) to properly substitute the result, and is ignored
+   in other contexts.
 
    For partial-concept-ids, extra args may be appended to the list of deduced
    template arguments prior to determining constraint satisfaction.  */
@@ -25114,7 +25158,7 @@ do_auto_deduction (tree type, tree init, tree auto_node)
 tree
 do_auto_deduction (tree type, tree init, tree auto_node,
                    tsubst_flags_t complain, auto_deduction_context context,
-                  tree outer_targs)
+                  tree outer_targs, int flags)
 {
   tree targs;
 
@@ -25129,7 +25173,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 
   if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
     /* C++17 class template argument deduction.  */
-    return do_class_deduction (type, tmpl, init, complain);
+    return do_class_deduction (type, tmpl, init, flags, complain);
 
   /* [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
index afd442f..785dfaf 100644 (file)
@@ -4374,6 +4374,8 @@ special_function_p (const_tree decl)
     return sfk_deleting_destructor;
   if (DECL_CONV_FN_P (decl))
     return sfk_conversion;
+  if (deduction_guide_p (decl))
+    return sfk_deduction_guide;
 
   return sfk_none;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction27.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction27.C
new file mode 100644 (file)
index 0000000..ce5c5d7
--- /dev/null
@@ -0,0 +1,5 @@
+// PR c++/79316
+// { dg-options -std=c++1z }
+
+  template<typename T> struct S { S(T t) {} };
+  template<typename T> S(T, int = 7) -> S<T>;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction28.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction28.C
new file mode 100644 (file)
index 0000000..c91ec0d
--- /dev/null
@@ -0,0 +1,24 @@
+// PR c++/79350
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  explicit A(T);
+};
+
+
+A a (42);
+A a2 = 42;                     // { dg-error "" }
+
+template <class T>
+struct B
+{
+  B(T*);
+};
+
+template <class T>
+explicit B(T) -> B<T*>;
+
+B b1 (0);
+B b2 = 0;                      // { dg-error "" }
index 5a2b4f6..149ef43 100644 (file)
@@ -10,7 +10,7 @@ namespace N {
 }
 
 template <class T>
-N::A(T) -> N::A<T>;            // { dg-error "scope" }
+N::A(T) -> N::A<T>;      // { dg-error "should have been declared inside .N" }
 
 namespace N {
   template <class T>