Allow deduction guides to look into primary template.
authorJason Merrill <jason@redhat.com>
Fri, 3 Mar 2017 01:26:47 +0000 (20:26 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 3 Mar 2017 01:26:47 +0000 (20:26 -0500)
* cp-tree.h (struct saved_scope): Add deduction_guide_type.
(struct cp_decl_specifier_seq): Add constructor_p.
* parser.c (cp_parser_decl_specifier_seq): Set constructor_p.
(cp_parser_init_declarator): Check it.  Set ctor_dtor_or_conv_p.
Clear deduction_guide_type.  Don't handle deduction guide names.
(cp_parser_declarator): Don't clear ctor_dtor_or_conv_p.
(cp_parser_direct_declarator): Likewise.  Handle deduction guides.
(cp_parser_member_declaration, cp_parser_cache_defarg)
(cp_parser_objc_class_ivars): Set ctor_dtor_or_conv_p.
* pt.c (tsubst_copy, tsubst_copy_and_build): Revert last change.
(build_deduction_guide): Set deduction_guide_type.
(dependent_scope_p): Check deduction_guide_type.
* search.c (lookup_member): Likewise.

From-SVN: r245858

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/search.c
gcc/testsuite/g++.dg/cpp1z/class-deduction37.C [new file with mode: 0644]

index 04ae0de3260420ea3b036e2d759fa49aeab570f8..7b68b1395991e490fdb04dc2a9a0c499942e2255 100644 (file)
@@ -1,3 +1,20 @@
+2017-03-02  Jason Merrill  <jason@redhat.com>
+
+       Allow deduction guides to look into primary template.
+       * cp-tree.h (struct saved_scope): Add deduction_guide_type.
+       (struct cp_decl_specifier_seq): Add constructor_p.
+       * parser.c (cp_parser_decl_specifier_seq): Set constructor_p.
+       (cp_parser_init_declarator): Check it.  Set ctor_dtor_or_conv_p.
+       Clear deduction_guide_type.  Don't handle deduction guide names.
+       (cp_parser_declarator): Don't clear ctor_dtor_or_conv_p.
+       (cp_parser_direct_declarator): Likewise.  Handle deduction guides.
+       (cp_parser_member_declaration, cp_parser_cache_defarg)
+       (cp_parser_objc_class_ivars): Set ctor_dtor_or_conv_p.
+       * pt.c (tsubst_copy, tsubst_copy_and_build): Revert last change.
+       (build_deduction_guide): Set deduction_guide_type.
+       (dependent_scope_p): Check deduction_guide_type.
+       * search.c (lookup_member): Likewise.
+
 2017-03-02  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/79782
index f53f7442bc9fee734e8af1ca81aeb6cc77c1b17f..31edc5f175b9a8ea625c022d0fb2dfc144eaa08f 100644 (file)
@@ -1272,6 +1272,7 @@ struct GTY(()) saved_scope {
   vec<tree, va_gc> *lang_base;
   tree lang_name;
   tree template_parms;
+  tree deduction_guide_type;
   cp_binding_level *x_previous_class_level;
   tree x_saved_tree;
 
@@ -5422,6 +5423,9 @@ struct cp_decl_specifier_seq {
   BOOL_BITFIELD gnu_thread_keyword_p : 1;
   /* True iff the type is a decltype.  */
   BOOL_BITFIELD decltype_p : 1;
+  /* True iff the declaration declares a constructor or C++17 deduction
+     guide.  */
+  BOOL_BITFIELD constructor_p : 1;
 };
 
 /* The various kinds of declarators.  */
index e6848701150020f02cd683b271a8d32ba01540ea..fbe864f685adc99217d15daa686f158c70a128cb 100644 (file)
@@ -13313,6 +13313,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
           && constructor_possible_p
           && (cp_parser_constructor_declarator_p
               (parser, decl_spec_seq_has_spec_p (decl_specs, ds_friend))));
+      if (constructor_p)
+       decl_specs->constructor_p = true;
 
       /* If we don't have a DECL_SPEC yet, then we must be looking at
         a type-specifier.  */
@@ -19010,7 +19012,7 @@ cp_parser_init_declarator (cp_parser* parser,
   enum cpp_ttype initialization_kind;
   bool is_direct_init = false;
   bool is_non_constant_init;
-  int ctor_dtor_or_conv_p;
+  int ctor_dtor_or_conv_p = decl_specifiers->constructor_p ? -1 : 0;
   bool friend_p = cp_parser_friend_p (decl_specifiers);
   tree pushed_scope = NULL_TREE;
   bool range_for_decl_p = false;
@@ -19048,6 +19050,9 @@ cp_parser_init_declarator (cp_parser* parser,
 
   parser->default_arg_ok_p = saved_default_arg_ok_p;
 
+  if (cxx_dialect >= cxx1z)
+    scope_chain->deduction_guide_type = NULL_TREE;
+
   /* If the DECLARATOR was erroneous, there's no need to go
      further.  */
   if (declarator == cp_error_declarator)
@@ -19095,25 +19100,6 @@ 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))
@@ -19432,8 +19418,10 @@ cp_parser_init_declarator (cp_parser* parser,
 
    If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to
    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
+   The caller should set it before the call, to -1 if parsing the
+   decl-specifier-seq determined that we're declaring a constructor or
+   deduction guide, or 0 otherwise.  This function sets it to -1 if the
+   declarator is a name, and +1 if it is a function. Usually you just want to
    test for >0, but internally the negative value is used.
 
    (The reason for CTOR_DTOR_OR_CONV_P is that a declaration must have
@@ -19464,11 +19452,6 @@ cp_parser_declarator (cp_parser* parser,
   tree class_type;
   tree gnu_attributes = NULL_TREE, std_attributes = NULL_TREE;
 
-  /* Assume this is not a constructor, destructor, or type-conversion
-     operator.  */
-  if (ctor_dtor_or_conv_p)
-    *ctor_dtor_or_conv_p = 0;
-
   if (cp_parser_allow_gnu_extensions_p (parser))
     gnu_attributes = cp_parser_gnu_attributes_opt (parser);
 
@@ -19766,9 +19749,6 @@ cp_parser_direct_declarator (cp_parser* parser,
          /* Parse an array-declarator.  */
          tree bounds, attrs;
 
-         if (ctor_dtor_or_conv_p)
-           *ctor_dtor_or_conv_p = 0;
-
          first = false;
          parser->default_arg_ok_p = false;
          parser->in_declarator_p = true;
@@ -20023,6 +20003,34 @@ cp_parser_direct_declarator (cp_parser* parser,
                      *ctor_dtor_or_conv_p = -1;
                  }
              }
+
+           if (cxx_dialect >= cxx1z
+               && sfk == sfk_none
+               && ctor_dtor_or_conv_p
+               && *ctor_dtor_or_conv_p == -1)
+             {
+               /* If *ctor_dtor_or_conv_p is set and we aren't declaring a
+                  constructor, we must be declaring a deduction guide.  */
+               tree tmpl;
+               if (qualifying_scope)
+                 tmpl = (lookup_qualified_name
+                         (qualifying_scope, unqualified_name,
+                          /*prefer_type*/false, /*complain*/true));
+               else
+                 tmpl = lookup_name (unqualified_name);
+               if (tmpl
+                   && (DECL_CLASS_TEMPLATE_P (tmpl)
+                       || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
+                 {
+                   unqualified_name = dguide_name (tmpl);
+                   scope_chain->deduction_guide_type
+                     = TREE_TYPE (unqualified_name);
+                   sfk = sfk_deduction_guide;
+                 }
+               else
+                 gcc_checking_assert (false);
+             }
+
            declarator = make_id_declarator (qualifying_scope,
                                             unqualified_name,
                                             sfk);
@@ -23251,7 +23259,7 @@ cp_parser_member_declaration (cp_parser* parser)
              cp_declarator *declarator;
              tree initializer;
              tree asm_specification;
-             int ctor_dtor_or_conv_p;
+             int ctor_dtor_or_conv_p = decl_specifiers.constructor_p ? -1 : 0;
 
              /* Parse the declarator.  */
              declarator
@@ -28334,7 +28342,7 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
                     declarator.  */
                  do
                    {
-                     int ctor_dtor_or_conv_p;
+                     int ctor_dtor_or_conv_p = 0;
                      cp_lexer_consume_token (parser->lexer);
                      cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
                                            &ctor_dtor_or_conv_p,
@@ -29655,7 +29663,7 @@ cp_parser_objc_class_ivars (cp_parser* parser)
        {
          tree width = NULL_TREE, attributes, first_attribute, decl;
          cp_declarator *declarator = NULL;
-         int ctor_dtor_or_conv_p;
+         int ctor_dtor_or_conv_p = 0;
 
          /* Check for a (possibly unnamed) bitfield declaration.  */
          token = cp_lexer_peek_token (parser->lexer);
index 8144ca66a0152b80ab191a478d7197dfd0ceb3ce..3b320fc2b48e4df7f31c2c961a988f74798c31d1 100644 (file)
@@ -14641,15 +14641,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
             have to substitute this with one having context `D<int>'.  */
 
          tree context = tsubst (DECL_CONTEXT (t), args, complain, in_decl);
-         if (dependent_scope_p (context))
-           {
-             /* When rewriting a constructor into a deduction guide, a
-                non-dependent name can become dependent, so memtmpl<args>
-                becomes context::template memtmpl<args>.  */
-             tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-             return build_qualified_name (type, context, DECL_NAME (t),
-                                          /*template*/true);
-           }
          return lookup_field (context, DECL_NAME(t), 0, false);
        }
       else
@@ -16633,14 +16624,6 @@ tsubst_copy_and_build (tree t,
        if (targs == error_mark_node)
          return error_mark_node;
 
-       if (TREE_CODE (templ) == SCOPE_REF)
-         {
-           tree name = TREE_OPERAND (templ, 1);
-           tree tid = lookup_template_function (name, targs);
-           TREE_OPERAND (templ, 1) = tid;
-           return templ;
-         }
-
        if (variable_template_p (templ))
          RETURN (lookup_and_finish_template_variable (templ, targs, complain));
 
@@ -23476,6 +23459,9 @@ bool
 dependent_scope_p (tree scope)
 {
   return (scope && TYPE_P (scope) && dependent_type_p (scope)
+         && !(cxx_dialect >= cxx1z
+              && scope_chain->deduction_guide_type
+              && same_type_p (scope, scope_chain->deduction_guide_type))
          && !currently_open_class (scope));
 }
 
@@ -24997,6 +24983,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
       if (outer_args)
        ctor = tsubst (ctor, outer_args, complain, ctor);
       type = DECL_CONTEXT (ctor);
+      scope_chain->deduction_guide_type = type;
       tree fn_tmpl;
       if (TREE_CODE (ctor) == TEMPLATE_DECL)
        {
@@ -25089,6 +25076,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
          current_template_parms = save_parms;
          --processing_template_decl;
        }
+      scope_chain->deduction_guide_type = NULL_TREE;
     }
 
   if (!memtmpl)
index 09c1b4e6456d24682eb3246de361a4e8354f6ba4..6eb41243814537fc5af9ef368b50b1e4cae3fecc 100644 (file)
@@ -1279,6 +1279,13 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type,
     if (tree t = currently_open_class (type))
       type = t;
 
+  /* Declaration of a deduction guide can look inside the primary class
+     template; replace a compatible type with the real one.  */
+  if (cxx_dialect >= cxx1z
+      && scope_chain->deduction_guide_type
+      && same_type_p (type, scope_chain->deduction_guide_type))
+    type = scope_chain->deduction_guide_type;
+
   if (!basetype_path)
     basetype_path = TYPE_BINFO (type);
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C
new file mode 100644 (file)
index 0000000..ee21d14
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-options -std=c++1z }
+
+template <class T> struct A
+{
+  using value_t = T;
+  A(value_t);
+};
+
+template <class T>
+A(typename A<T>::value_t) -> A<double>;
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+A a(42);
+same<decltype(a),A<double>> s1;