[PR C++/59930] template friend classes & default args
authorNathan Sidwell <nathan@acm.org>
Fri, 15 Dec 2017 15:04:59 +0000 (15:04 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Fri, 15 Dec 2017 15:04:59 +0000 (15:04 +0000)
https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01055.html
PR c++/59930
* decl.c (xref_tag_1): Correct comments about template friends and
default args.
* friend.c (make_friend_class): Move comments concerning
self-friendliness to code dealing with such.
* pt.c (check_default_tmpl_args): Deal with template friend
classes too.
(push_template_decl_real): Check default args for non-function
template friends.

PR c++/59930
* g++.dg/cpp0x/temp_default4.C: Adjust diagnostic.
* g++.old-deja/g++.pt/friend23.C: Likewise.
* g++.old-deja/g++.pt/friend24.C: Delete.

From-SVN: r255698

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/friend.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/temp_default4.C
gcc/testsuite/g++.old-deja/g++.pt/friend23.C
gcc/testsuite/g++.old-deja/g++.pt/friend24.C [deleted file]

index d7a1dde686f0a0ff050cb1e87a44c6c1ce4946f0..37c129d174f7d2dd058a407d8ee618f3ff317c0f 100644 (file)
@@ -1,3 +1,15 @@
+2017-12-15  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/59930
+       * decl.c (xref_tag_1): Correct comments about template friends and
+       default args.
+       * friend.c (make_friend_class): Move comments concerning
+       self-friendliness to code dealing with such.
+       * pt.c (check_default_tmpl_args): Deal with template friend
+       classes too.
+       (push_template_decl_real): Check default args for non-function
+       template friends.
+
 2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>
 
        * decl2.c (start_static_storage_duration_function): Avoid warning.
index 445c23c5dacf75387582028d10a08c353d675695..63a7b92b3bc871f534f125fcde4b10929ccce1d7 100644 (file)
@@ -13538,37 +13538,28 @@ xref_tag_1 (enum tag_types tag_code, tree name,
         processing a (member) template declaration of a template
         class, we must be very careful; consider:
 
-          template <class X>
-          struct S1
+          template <class X> struct S1
 
-          template <class U>
-          struct S2
-          { template <class V>
-          friend struct S1; };
+          template <class U> struct S2
+          {
+            template <class V> friend struct S1;
+          };
 
         Here, the S2::S1 declaration should not be confused with the
         outer declaration.  In particular, the inner version should
-        have a template parameter of level 2, not level 1.  This
-        would be particularly important if the member declaration
-        were instead:
-
-          template <class V = U> friend struct S1;
+        have a template parameter of level 2, not level 1.
 
-        say, when we should tsubst into `U' when instantiating
-        S2.  On the other hand, when presented with:
+        On the other hand, when presented with:
 
-          template <class T>
-          struct S1 {
-            template <class U>
-            struct S2 {};
-            template <class U>
-            friend struct S2;
+          template <class T> struct S1
+          {
+            template <class U> struct S2 {};
+            template <class U> friend struct S2;
           };
 
-        we must find the inner binding eventually.  We
-        accomplish this by making sure that the new type we
-        create to represent this declaration has the right
-        TYPE_CONTEXT.  */
+        the friend must find S1::S2 eventually.  We accomplish this
+        by making sure that the new type we create to represent this
+        declaration has the right TYPE_CONTEXT.  */
       context = TYPE_CONTEXT (t);
       t = NULL_TREE;
     }
@@ -13622,9 +13613,10 @@ xref_tag_1 (enum tag_types tag_code, tree name,
          return error_mark_node;
        }
 
-      /* Make injected friend class visible.  */
       if (scope != ts_within_enclosing_non_class && TYPE_HIDDEN_P (t))
        {
+         /* This is no longer an invisible friend.  Make it
+            visible.  */
          tree decl = TYPE_NAME (t);
 
          DECL_ANTICIPATED (decl) = false;
index ef93bfe39ec452c1cc6530a632d3c5514c04ef06..e99ae681f1e39158cfa1184ab6933c30f4d40e8e 100644 (file)
@@ -283,21 +283,18 @@ make_friend_class (tree type, tree friend_type, bool complain)
     return;
 
   if (friend_depth)
-    /* If the TYPE is a template then it makes sense for it to be
-       friends with itself; this means that each instantiation is
-       friends with all other instantiations.  */
     {
+      /* [temp.friend] Friend declarations shall not declare partial
+        specializations.  */
       if (CLASS_TYPE_P (friend_type)
          && CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type)
          && uses_template_parms (friend_type))
        {
-         /* [temp.friend]
-            Friend declarations shall not declare partial
-            specializations.  */
          error ("partial specialization %qT declared %<friend%>",
                 friend_type);
          return;
        }
+
       if (TYPE_TEMPLATE_INFO (friend_type)
          && !PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (friend_type)))
        {
@@ -311,7 +308,11 @@ make_friend_class (tree type, tree friend_type, bool complain)
          return;
        }
     }
-  else if (same_type_p (type, friend_type))
+
+  /* It makes sense for a template class to be friends with itself,
+     that means the instantiations can be friendly.  Other cases are
+     not so meaningful.  */
+  if (!friend_depth && same_type_p (type, friend_type))
     {
       if (complain)
        warning (0, "class %qT is implicitly friends with itself",
index 69b95351d8b6c9aa6be5c9c74ae66afe253dc2ae..5a6a7cff939496a29caa2b315bdd24be9addb208 100644 (file)
@@ -4980,9 +4980,10 @@ fixed_parameter_pack_p (tree parm)
    a primary template.  IS_PARTIAL is true if DECL is a partial
    specialization.
 
-   IS_FRIEND_DECL is nonzero if DECL is a friend function template
-   declaration (but not a definition); 1 indicates a declaration, 2
-   indicates a redeclaration. When IS_FRIEND_DECL=2, no errors are
+   IS_FRIEND_DECL is nonzero if DECL is either a non-defining friend
+   function template declaration or a friend class template
+   declaration.  In the function case, 1 indicates a declaration, 2
+   indicates a redeclaration.  When IS_FRIEND_DECL=2, no errors are
    emitted for extraneous default arguments.
 
    Returns TRUE if there were no errors found, FALSE otherwise. */
@@ -5130,7 +5131,7 @@ check_default_tmpl_args (tree decl, tree parms, bool is_primary,
     msg = G_("default template arguments may not be used in function template "
             "friend re-declaration");
   else if (is_friend_decl)
-    msg = G_("default template arguments may not be used in function template "
+    msg = G_("default template arguments may not be used in template "
             "friend declarations");
   else if (TREE_CODE (decl) == FUNCTION_DECL && (cxx_dialect == cxx98))
     msg = G_("default template arguments may not be used in function templates "
@@ -5277,7 +5278,7 @@ push_template_decl_real (tree decl, bool is_friend)
     is_friend = true;
 
   if (is_friend)
-    /* For a friend, we want the context of the friend function, not
+    /* For a friend, we want the context of the friend, not
        the type of which it is a friend.  */
     ctx = CP_DECL_CONTEXT (decl);
   else if (CP_DECL_CONTEXT (decl)
@@ -5380,9 +5381,12 @@ push_template_decl_real (tree decl, bool is_friend)
     }
 
   /* Check to see that the rules regarding the use of default
-     arguments are not being violated.  */
-  check_default_tmpl_args (decl, current_template_parms,
-                          is_primary, is_partial, /*is_friend_decl=*/0);
+     arguments are not being violated.  We check args for a friend
+     functions when we know whether it's a definition, introducing
+     declaration or re-declaration.  */
+  if (!is_friend || TREE_CODE (decl) != FUNCTION_DECL)
+    check_default_tmpl_args (decl, current_template_parms,
+                            is_primary, is_partial, is_friend);
 
   /* Ensure that there are no parameter packs in the type of this
      declaration that have not been expanded.  */
index c87d2cd09800ef83aa7b3d4bd104062c51837fd8..2a73f82c97f08a8247e89a5969af9f10a87f6f42 100644 (file)
@@ -1,3 +1,10 @@
+2017-12-14  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/59930
+       * g++.dg/cpp0x/temp_default4.C: Adjust diagnostic.
+       * g++.old-deja/g++.pt/friend23.C: Likewise.
+       * g++.old-deja/g++.pt/friend24.C: Delete.
+
 2017-12-15  Jakub Jelinek  <jakub@redhat.com>
 
        PR tree-optimization/83269
index 783ff5b19d9753a6092aac95af02ff4214bea063..0dc58548255d6645fd54e71e6d4af6bd7efe5621 100644 (file)
@@ -1,9 +1,9 @@
 // { dg-do compile { target c++11 } }
 
 class X {
-  template<typename T = int> friend void f(X) { }
+  template<typename T = int> friend void f(X) { } // OK
   template<typename T> friend void g(X); // { dg-message "previously declared here" }
-  template<typename T = int> friend void h(X); // { dg-error "function template friend" }
+  template<typename T = int> friend void h(X); // { dg-error "template friend" }
 };
 
 template<typename T = int> void g(X) // { dg-error "default template argument" }
index 93ce72e3025dd22bc4abd28a546fc39cc2d42674..b79a599a45e2d3360fb4f81364bf0017873555fe 100644 (file)
@@ -1,10 +1,9 @@
-// { dg-do assemble  }
+// PR 59930 (part)  templated class friend declarations cannot have
+// default args.
 
-template <class T = int> // { dg-message "note: original definition" }
+template <class T>
 struct S
 { 
-  template <class U = int>
-  friend class S; // { dg-error "redefinition of default argument" }
+  template <class U = int> friend class R; // { dg-error "template friend" }
+  template <class U = int> friend class S; // { dg-error "template friend" }
 };
-
-template struct S<int>;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend24.C b/gcc/testsuite/g++.old-deja/g++.pt/friend24.C
deleted file mode 100644 (file)
index 5a4116f..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// { dg-do assemble  }
-
-template <class T>
-struct S
-{
-  template <class U = T>
-  friend class S;
-
-  void f(T);
-};
-
-template struct S<int>;
-
-void g()
-{
-  S<> s;
-  s.f(3);
-}