]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR c++/13495
authorlerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 20 Oct 2004 16:20:50 +0000 (16:20 +0000)
committerlerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 20 Oct 2004 16:20:50 +0000 (16:20 +0000)
* decl.c (make_unbound_class_template): Add PARM_LIST parameter.
* cp-tree.h (make_unbound_class_template): Adjust prototype.
* parser.c (cp_parser_lookup_name): Adjust call to
make_unbound_class_template.
(cp_parser_single_declaration): Handle member class of class
template as template friend parsing correctly.
* friend.c (is_friend): Call is_specialization_of_friend for
template friend class.
(make_friend_class): Handle member class of class template as
template friend.
* pt.c (is_specialization_of_friend): Likewise.
(instantiate_class_template): Likewise.
(tsubst): Adjust call to make_unbound_class_template.

* g++.dg/template/memfriend9.C: New test.
* g++.dg/template/memfriend10.C: Likewise.
* g++.dg/template/memfriend11.C: Likewise.
* g++.dg/template/memfriend12.C: Likewise.
* g++.dg/template/memfriend13.C: Likewise.
* g++.dg/template/memfriend14.C: Likewise.
* g++.dg/template/memfriend15.C: Likewise.
* g++.dg/template/memfriend16.C: Likewise.
* g++.dg/template/memfriend17.C: Likewise.
* g++.old-deja/g++.pt/friend44.C: Remove bogus error.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@89335 138bc75d-0d04-0410-961f-82ee72b054a4

17 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/friend.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/memfriend10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend17.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend9.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/friend44.C

index 6dc5345e2822584050d4df8533a2dabc99371e9a..a90cc61f575fc53c7ce077bdc1ba73229d32be42 100644 (file)
@@ -1,3 +1,20 @@
+2004-10-20  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
+       PR c++/13495
+       * decl.c (make_unbound_class_template): Add PARM_LIST parameter.
+       * cp-tree.h (make_unbound_class_template): Adjust prototype.
+       * parser.c (cp_parser_lookup_name): Adjust call to
+       make_unbound_class_template.
+       (cp_parser_single_declaration): Handle member class of class
+       template as template friend parsing correctly.
+       * friend.c (is_friend): Call is_specialization_of_friend for
+       template friend class.
+       (make_friend_class): Handle member class of class template as
+       template friend.
+       * pt.c (is_specialization_of_friend): Likewise.
+       (instantiate_class_template): Likewise.
+       (tsubst): Adjust call to make_unbound_class_template.
+
 2004-10-20  Nathan Sidwell  <nathan@codesourcery.com>
 
        * typeck.c (composite_pointer_type): Add comment about DR 195
index 6534170392ef205834b0ece64b4d79fe6c2a2505..0f75fce38124836eaa90dd60b39a5c7cb10db579 100644 (file)
@@ -3689,7 +3689,7 @@ extern tree define_label                  (location_t, tree);
 extern void check_goto                         (tree);
 extern void define_case_label                  (void);
 extern tree make_typename_type                 (tree, tree, tsubst_flags_t);
-extern tree make_unbound_class_template                (tree, tree, tsubst_flags_t);
+extern tree make_unbound_class_template                (tree, tree, tree, tsubst_flags_t);
 extern tree check_for_out_of_scope_variable     (tree);
 extern tree build_library_fn                   (tree, tree);
 extern tree build_library_fn_ptr               (const char *, tree);
index 00844fdbd0ba2c218056a2a7bda3234c45593770..21ffb519e8254f5e27d2929662f8c7469ba82864 100644 (file)
@@ -2730,14 +2730,18 @@ make_typename_type (tree context, tree name, tsubst_flags_t complain)
   return build_typename_type (context, name, fullname);
 }
 
-/* Resolve `CONTEXT::template NAME'.  Returns an appropriate type,
-   unless an error occurs, in which case error_mark_node is returned.
-   If we locate a TYPE_DECL, we return that, rather than the _TYPE it
-   corresponds to.  If COMPLAIN zero, don't complain about any errors
-   that occur.  */
+/* Resolve `CONTEXT::template NAME'.  Returns a TEMPLATE_DECL if the name
+   can be resolved or an UNBOUND_CLASS_TEMPLATE, unless an error occurs, 
+   in which case error_mark_node is returned.
+
+   If PARM_LIST is non-NULL, also make sure that the template parameter
+   list of TEMPLATE_DECL matches.
+
+   If COMPLAIN zero, don't complain about any errors that occur.  */
 
 tree
-make_unbound_class_template (tree context, tree name, tsubst_flags_t complain)
+make_unbound_class_template (tree context, tree name, tree parm_list,
+                            tsubst_flags_t complain)
 {
   tree t;
   tree d;
@@ -2763,6 +2767,17 @@ make_unbound_class_template (tree context, tree name, tsubst_flags_t complain)
          return error_mark_node;
        }
 
+      if (parm_list
+         && !comp_template_parms (DECL_TEMPLATE_PARMS (tmpl), parm_list))
+       {
+         if (complain & tf_error)
+           {
+             error ("template parameters do not match template");
+             cp_error_at ("%qD declared here", tmpl);
+           }
+         return error_mark_node;
+       }
+
       if (complain & tf_error)
        perform_or_defer_access_check (TYPE_BINFO (context), tmpl);
 
@@ -2780,6 +2795,7 @@ make_unbound_class_template (tree context, tree name, tsubst_flags_t complain)
   TYPE_STUB_DECL (TREE_TYPE (d)) = d;
   DECL_CONTEXT (d) = FROB_CONTEXT (context);
   DECL_ARTIFICIAL (d) = 1;
+  DECL_TEMPLATE_PARMS (d) = parm_list;
 
   return t;
 }
index 6ab9d731ca5eea8aef115bc80d524d54f71ad0de..2d177a084f3361e989b3731c7727cbc4ea542e2f 100644 (file)
@@ -92,7 +92,7 @@ is_friend (tree type, tree supplicant)
          tree t = TREE_VALUE (list);
 
          if (TREE_CODE (t) == TEMPLATE_DECL ? 
-             is_specialization_of (TYPE_MAIN_DECL (supplicant), t) :
+             is_specialization_of_friend (TYPE_MAIN_DECL (supplicant), t) :
              same_type_p (supplicant, t))
            return 1;
        }
@@ -197,7 +197,31 @@ void
 make_friend_class (tree type, tree friend_type, bool complain)
 {
   tree classes;
-  int is_template_friend;
+
+  /* CLASS_TEMPLATE_DEPTH counts the number of template headers for
+     the enclosing class.  FRIEND_DEPTH counts the number of template
+     headers used for this friend declaration.  TEMPLATE_MEMBER_P,
+     defined inside the `if' block for TYPENAME_TYPE case, is true if
+     a template header in FRIEND_DEPTH is intended for DECLARATOR.
+     For example, the code
+
+       template <class T> struct A {
+        template <class U> struct B {
+          template <class V> template <class W>
+            friend class C<V>::D;
+        };
+       };
+
+     will eventually give the following results
+
+     1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U').
+     2. FRIEND_DEPTH equals 2 (for `V' and `W').
+     3. TEMPLATE_MEMBER_P is true (for `W').
+
+     The friend is a template friend iff FRIEND_DEPTH is nonzero.  */
+
+  int class_template_depth = template_class_depth (type);
+  int friend_depth = processing_template_decl - class_template_depth;
 
   if (! IS_AGGR_TYPE (friend_type))
     {
@@ -205,7 +229,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
       return;
     }
 
-  if (processing_template_decl > template_class_depth (type))
+  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.  */
@@ -221,8 +245,6 @@ make_friend_class (tree type, tree friend_type, bool complain)
                 friend_type);
          return;
        }
-  
-      is_template_friend = 1;
     }
   else if (same_type_p (type, friend_type))
     {
@@ -231,8 +253,6 @@ make_friend_class (tree type, tree friend_type, bool complain)
                 type);
       return;
     }
-  else
-    is_template_friend = 0;
 
   /* [temp.friend]
 
@@ -240,13 +260,75 @@ make_friend_class (tree type, tree friend_type, bool complain)
      class template, a specialization of a function template or
      class template, or an ordinary (nontemplate) function or
      class.  */
-  if (!is_template_friend)
+  if (!friend_depth)
     ;/* ok */
   else if (TREE_CODE (friend_type) == TYPENAME_TYPE)
     {
-      /* template <class T> friend typename S<T>::X; */
-      error ("typename type %q#T declared %<friend%>", friend_type);
-      return;
+      if (TREE_CODE (TYPENAME_TYPE_FULLNAME (friend_type))
+         == TEMPLATE_ID_EXPR)
+       {
+         /* template <class U> friend class T::X<U>; */
+         /* [temp.friend]
+            Friend declarations shall not declare partial
+            specializations.  */
+         error ("partial specialization %qT declared %<friend%>",
+                friend_type);
+         return;
+       }
+      else
+       {
+         /* We will figure this out later.  */
+         bool template_member_p = false;
+
+         tree ctype = TYPE_CONTEXT (friend_type);
+         tree name = TYPE_IDENTIFIER (friend_type);
+         tree decl;
+
+         if (!uses_template_parms_level (ctype, class_template_depth
+                                                + friend_depth))
+           template_member_p = true;
+
+         if (class_template_depth)
+           {
+             /* We rely on tsubst_friend_class to check the
+                validity of the declaration later.  */
+             if (template_member_p)
+               friend_type
+                 = make_unbound_class_template (ctype,
+                                                name,
+                                                current_template_parms,
+                                                tf_error);
+             else
+               friend_type
+                 = make_typename_type (ctype, name, tf_error);
+           }
+         else
+           {
+             decl = lookup_member (ctype, name, 0, true);
+             if (!decl)
+               {
+                 error ("%qT is not a member of %qT", name, ctype);
+                 return;
+               }
+             if (template_member_p && !DECL_CLASS_TEMPLATE_P (decl))
+               {
+                 error ("%qT is not a member class template of %qT",
+                        name, ctype);
+                 cp_error_at ("%qD declared here", decl);
+                 return;
+               }
+             if (!template_member_p && (TREE_CODE (decl) != TYPE_DECL
+                                        || !CLASS_TYPE_P (TREE_TYPE (decl))))
+               {
+                 error ("%qT is not a nested class of %qT",
+                        name, ctype);
+                 cp_error_at ("%qD declared here", decl);
+                 return;
+               }
+
+             friend_type = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl));
+           }
+       }
     }
   else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
     {
@@ -260,10 +342,13 @@ make_friend_class (tree type, tree friend_type, bool complain)
       error ("%q#T is not a template", friend_type);
       return;
     }
-
-  if (is_template_friend)
+  else
+    /* template <class T> friend class A; where A is a template */
     friend_type = CLASSTYPE_TI_TEMPLATE (friend_type);
 
+  if (friend_type == error_mark_node)
+    return;
+
   /* See if it is already a friend.  */
   for (classes = CLASSTYPE_FRIEND_CLASSES (type);
        classes;
@@ -297,7 +382,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
 
       CLASSTYPE_FRIEND_CLASSES (type)
        = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
-      if (is_template_friend)
+      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
        friend_type = TREE_TYPE (friend_type);
       if (!uses_template_parms (type))
        CLASSTYPE_BEFRIENDING_CLASSES (friend_type)
index df3cb6526de5ee7ba043a85c2deb1bb73b603273..fc947a5936f518b40e5bef9494ead468e0e81bdf 100644 (file)
@@ -14158,7 +14158,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
                                                  /*complain=*/1));
          else if (is_template)
            decl = make_unbound_class_template (parser->scope,
-                                               name,
+                                               name, NULL_TREE,
                                                /*complain=*/1);
          else
            decl = build_nt (SCOPE_REF, parser->scope, name);
@@ -14847,6 +14847,21 @@ cp_parser_single_declaration (cp_parser* parser,
       if (cp_parser_declares_only_class_p (parser))
        {
          decl = shadow_tag (&decl_specifiers);
+
+         /* In this case:
+
+              struct C {
+                friend template <typename T> struct A<T>::B;
+              };
+
+            A<T>::B will be represented by a TYPENAME_TYPE, and
+            therefore not recognized by shadow_tag.  */
+         if (friend_p && *friend_p
+             && !decl
+             && decl_specifiers.type
+             && TYPE_P (decl_specifiers.type))
+           decl = decl_specifiers.type;
+
          if (decl && decl != error_mark_node)
            decl = TYPE_NAME (decl);
          else
index 18e3c0a057dd0d23b5153d6ea6c01fa38b85b2a4..1ced2389f90f932cb07f8967a9a6f1a66203ae6a 100644 (file)
@@ -939,7 +939,8 @@ is_specialization_of_friend (tree decl, tree friend)
   bool need_template = true;
   int template_depth;
 
-  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
+             || TREE_CODE (decl) == TYPE_DECL);
 
   /* For [temp.friend/6] when FRIEND is an ordinary member function
      of a template class, we want to check if DECL is a specialization
@@ -948,16 +949,20 @@ is_specialization_of_friend (tree decl, tree friend)
       && DECL_TEMPLATE_INFO (friend)
       && !DECL_USE_TEMPLATE (friend))
     {
+      /* We want a TEMPLATE_DECL for `is_specialization_of'.  */
       friend = DECL_TI_TEMPLATE (friend);
       need_template = false;
     }
+  else if (TREE_CODE (friend) == TEMPLATE_DECL
+          && !PRIMARY_TEMPLATE_P (friend))
+    need_template = false;
 
   /* There is nothing to do if this is not a template friend.  */
   if (TREE_CODE (friend) != TEMPLATE_DECL)
-    return 0;
+    return false;
 
   if (is_specialization_of (decl, friend))
-    return 1;
+    return true;
 
   /* [temp.friend/6]
      A member of a class template may be declared to be a friend of a
@@ -986,17 +991,25 @@ is_specialization_of_friend (tree decl, tree friend)
                               CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (friend))))
     {
       /* Next, we check the members themselves.  In order to handle
-        a few tricky cases like
+        a few tricky cases, such as when FRIEND's are
 
           template <class T> friend void A<T>::g(T t);
           template <class T> template <T t> friend void A<T>::h();
 
-        we need to figure out what ARGS is (corresponding to `T' in above
-        examples) from DECL for later processing.  */
+        and DECL's are
+
+          void A<int>::g(int);
+          template <int> void A<int>::h();
+
+        we need to figure out ARGS, the template arguments from
+        the context of DECL.  This is required for template substitution
+        of `T' in the function parameter of `g' and template parameter
+        of `h' in the above examples.  Here ARGS corresponds to `int'.  */
 
       tree context = DECL_CONTEXT (decl);
       tree args = NULL_TREE;
       int current_depth = 0;
+
       while (current_depth < template_depth)
        {
          if (CLASSTYPE_TEMPLATE_INFO (context))
@@ -1023,7 +1036,7 @@ is_specialization_of_friend (tree decl, tree friend)
          is_template = DECL_TEMPLATE_INFO (decl)
                        && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl));
          if (need_template ^ is_template)
-           return 0;
+           return false;
          else if (is_template)
            {
              /* If both are templates, check template parameter list.  */
@@ -1033,7 +1046,7 @@ is_specialization_of_friend (tree decl, tree friend)
              if (!comp_template_parms
                     (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl)),
                      friend_parms))
-               return 0;
+               return false;
 
              decl_type = TREE_TYPE (DECL_TI_TEMPLATE (decl));
            }
@@ -1043,11 +1056,11 @@ is_specialization_of_friend (tree decl, tree friend)
          friend_type = tsubst_function_type (TREE_TYPE (friend), args,
                                              tf_none, NULL_TREE);
          if (friend_type == error_mark_node)
-           return 0;
+           return false;
 
          /* Check if return types match.  */
          if (!same_type_p (TREE_TYPE (decl_type), TREE_TYPE (friend_type)))
-           return 0;
+           return false;
 
          /* Check if function parameter types match, ignoring the
             `this' parameter.  */
@@ -1057,11 +1070,46 @@ is_specialization_of_friend (tree decl, tree friend)
            friend_args_type = TREE_CHAIN (friend_args_type);
          if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
            decl_args_type = TREE_CHAIN (decl_args_type);
-         if (compparms (decl_args_type, friend_args_type))
-           return 1;
+
+         return compparms (decl_args_type, friend_args_type);
+       }
+      else
+       {
+         /* DECL is a TYPE_DECL */
+         bool is_template;
+         tree decl_type = TREE_TYPE (decl);
+
+         /* Make sure that both DECL and FRIEND are templates or
+            non-templates.  */
+         is_template
+           = CLASSTYPE_TEMPLATE_INFO (decl_type)
+             && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (decl_type));
+
+         if (need_template ^ is_template)
+           return false;
+         else if (is_template)
+           {
+             tree friend_parms;
+             /* If both are templates, check the name of the two
+                TEMPLATE_DECL's first because is_friend didn't.  */
+             if (DECL_NAME (CLASSTYPE_TI_TEMPLATE (decl_type))
+                 != DECL_NAME (friend))
+               return false;
+
+             /* Now check template parameter list.  */
+             friend_parms
+               = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend),
+                                        args, tf_none);
+             return comp_template_parms
+               (DECL_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (decl_type)),
+                friend_parms);
+           }
+         else
+           return (DECL_NAME (decl)
+                   == DECL_NAME (friend));
        }
     }
-  return 0;
+  return false;
 }
 
 /* Register the specialization SPEC as a specialization of TMPL with
@@ -5691,15 +5739,37 @@ instantiate_class_template (tree type)
              /* Build new CLASSTYPE_FRIEND_CLASSES.  */
 
              tree friend_type = t;
-             tree new_friend_type;
+             bool adjust_processing_template_decl = false;
 
              if (TREE_CODE (friend_type) == TEMPLATE_DECL)
-               new_friend_type = tsubst_friend_class (friend_type, args);
+               {
+                 friend_type = tsubst_friend_class (friend_type, args);
+                 adjust_processing_template_decl = true;
+               }
+             else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE)
+               {
+                 friend_type = tsubst (friend_type, args,
+                                       tf_error | tf_warning, NULL_TREE);
+                 if (TREE_CODE (friend_type) == TEMPLATE_DECL)
+                   friend_type = TREE_TYPE (friend_type);
+                 adjust_processing_template_decl = true;
+               }
+             else if (TREE_CODE (friend_type) == TYPENAME_TYPE)
+               {
+                 friend_type = tsubst (friend_type, args,
+                                       tf_error | tf_warning, NULL_TREE);
+                 /* Bump processing_template_decl for correct
+                    dependent_type_p calculation.  */
+                 ++processing_template_decl;
+                 if (dependent_type_p (friend_type))
+                   adjust_processing_template_decl = true;
+                 --processing_template_decl;
+               }
              else if (uses_template_parms (friend_type))
-               new_friend_type = tsubst (friend_type, args,
-                                         tf_error | tf_warning, NULL_TREE);
+               friend_type = tsubst (friend_type, args,
+                                     tf_error | tf_warning, NULL_TREE);
              else if (CLASSTYPE_USE_TEMPLATE (friend_type))
-               new_friend_type = friend_type;
+               friend_type = friend_type;
              else 
                {
                  tree ns = decl_namespace_context (TYPE_MAIN_DECL (friend_type));
@@ -5707,12 +5777,12 @@ instantiate_class_template (tree type)
                  /* The call to xref_tag_from_type does injection for friend
                     classes.  */
                  push_nested_namespace (ns);
-                 new_friend_type = 
+                 friend_type = 
                    xref_tag_from_type (friend_type, NULL_TREE, 1);
                  pop_nested_namespace (ns);
                }
 
-             if (TREE_CODE (friend_type) == TEMPLATE_DECL)
+             if (adjust_processing_template_decl)
                /* Trick make_friend_class into realizing that the friend
                   we're adding is a template, not an ordinary class.  It's
                   important that we use make_friend_class since it will
@@ -5720,11 +5790,10 @@ instantiate_class_template (tree type)
                   information.  */
                ++processing_template_decl;
 
-             if (new_friend_type != error_mark_node)
-               make_friend_class (type, new_friend_type,
-                                  /*complain=*/false);
+             if (friend_type != error_mark_node)
+               make_friend_class (type, friend_type, /*complain=*/false);
 
-             if (TREE_CODE (friend_type) == TEMPLATE_DECL)
+             if (adjust_processing_template_decl)
                --processing_template_decl;
            }
          else
@@ -7283,11 +7352,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
                                     in_decl, /*entering_scope=*/1);
        tree name = TYPE_IDENTIFIER (t);
+       tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t));
 
        if (ctx == error_mark_node || name == error_mark_node)
          return error_mark_node;
 
-       return make_unbound_class_template (ctx, name, complain);
+       if (parm_list)
+         parm_list = tsubst_template_parms (parm_list, args, complain);
+       return make_unbound_class_template (ctx, name, parm_list, complain);
       }
 
     case INDIRECT_REF:
index 04c73cd9989c5459858f15510e9671cd11e2233f..f072df9f7b69db53978c5df064b6f47a9a96286b 100644 (file)
@@ -1,3 +1,17 @@
+2004-10-20  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
+       PR c++/13495
+       * g++.dg/template/memfriend9.C: New test.
+       * g++.dg/template/memfriend10.C: Likewise.
+       * g++.dg/template/memfriend11.C: Likewise.
+       * g++.dg/template/memfriend12.C: Likewise.
+       * g++.dg/template/memfriend13.C: Likewise.
+       * g++.dg/template/memfriend14.C: Likewise.
+       * g++.dg/template/memfriend15.C: Likewise.
+       * g++.dg/template/memfriend16.C: Likewise.
+       * g++.dg/template/memfriend17.C: Likewise.
+       * g++.old-deja/g++.pt/friend44.C: Remove bogus error.
+
 2004-10-20  Nathan Sidwell  <nathan@codesourcery.com>
 
        * g++.dg/conversion/dr195.C: New.
diff --git a/gcc/testsuite/g++.dg/template/memfriend10.C b/gcc/testsuite/g++.dg/template/memfriend10.C
new file mode 100644 (file)
index 0000000..4fe760a
--- /dev/null
@@ -0,0 +1,71 @@
+// { dg-do compile }
+
+// Copyright (C) 2004 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Nested class template of class template as friend
+
+template <class T> struct A
+{
+  template <class U> struct B
+  {
+    void f();
+  };
+};
+
+class C {
+  int i;
+  template <class T> template <class U> friend struct A<T>::B;
+};
+
+template <class T> struct A<T*>
+{
+  template <class U> struct B
+  {
+    void f();
+  };
+};
+
+template <> struct A<char>
+{
+  template <class U> struct B
+  {
+    void f();
+  };
+};
+
+template <class T> template <class U> void A<T>::B<U>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <class T> template <class U> void A<T*>::B<U>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <class U> void A<char>::B<U>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <> void A<char>::B<int>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+int main()
+{
+  A<int>::B<int> b1;
+  b1.f();
+  A<int *>::B<int> b2;
+  b2.f();
+  A<char>::B<char> b3;
+  b3.f();
+  A<char>::B<int> b4;
+  b4.f();
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend11.C b/gcc/testsuite/g++.dg/template/memfriend11.C
new file mode 100644 (file)
index 0000000..d06a936
--- /dev/null
@@ -0,0 +1,73 @@
+// { dg-do compile }
+
+// Copyright (C) 2004 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Nest class template of class template as friend
+
+template<class T> struct A
+{
+  template <T t> struct B
+  {
+    void f();
+  };
+};
+
+class C {
+  int i;
+  template<class T> template <T t> friend struct A<T>::B;
+};
+
+template<class T> struct A<T*>
+{
+  template <T* t> struct B
+  {
+    void f();
+  };
+};
+
+template<> struct A<char>
+{
+  template <char t> struct B
+  {
+    void f();
+  };
+};
+
+template<class T> template <T t> void A<T>::B<t>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template<class T> template <T* t> void A<T*>::B<t>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <char t> void A<char>::B<t>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <> void A<char>::B<'b'>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+int d2 = 0;
+
+int main()
+{
+  A<int>::B<0> b1;
+  b1.f();
+  A<int *>::B<&d2> b2;
+  b2.f();
+  A<char>::B<'a'> b3;
+  b3.f();
+  A<char>::B<'b'> b4;
+  b4.f();
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend12.C b/gcc/testsuite/g++.dg/template/memfriend12.C
new file mode 100644 (file)
index 0000000..77f8214
--- /dev/null
@@ -0,0 +1,63 @@
+// { dg-do compile }
+
+// Copyright (C) 2004 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Nested class of class template as friend
+
+template<class T> struct A
+{
+  struct B
+  {
+    void f();
+  };
+};
+
+template <class U> class C {
+  int i;
+  template<class T> friend struct A<T>::B;
+};
+
+template<class T> struct A<T*>
+{
+  struct B
+  {
+    void f();
+  };
+};
+
+template<> struct A<char>
+{
+  struct B
+  {
+    void f();
+  };
+};
+
+template<class T> void A<T>::B::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+template<class T> void A<T*>::B::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+void A<char>::B::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+int main()
+{
+  A<int>::B b1;
+  b1.f();
+  A<int *>::B b2;
+  b2.f();
+  A<char>::B b3;
+  b3.f();
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend13.C b/gcc/testsuite/g++.dg/template/memfriend13.C
new file mode 100644 (file)
index 0000000..7faed22
--- /dev/null
@@ -0,0 +1,71 @@
+// { dg-do compile }
+
+// Copyright (C) 2004 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Nested class template of class template as friend
+
+template <class T> struct A
+{
+  template <class U> struct B
+  {
+    void f();
+  };
+};
+
+template <class V> class C {
+  int i;
+  template <class T> template <class U> friend struct A<T>::B;
+};
+
+template <class T> struct A<T*>
+{
+  template <class U> struct B
+  {
+    void f();
+  };
+};
+
+template <> struct A<char>
+{
+  template <class U> struct B
+  {
+    void f();
+  };
+};
+
+template <class T> template <class U> void A<T>::B<U>::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+template <class T> template <class U> void A<T*>::B<U>::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+template <class U> void A<char>::B<U>::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+template <> void A<char>::B<int>::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+int main()
+{
+  A<int>::B<int> b1;
+  b1.f();
+  A<int *>::B<int> b2;
+  b2.f();
+  A<char>::B<char> b3;
+  b3.f();
+  A<char>::B<int> b4;
+  b4.f();
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend14.C b/gcc/testsuite/g++.dg/template/memfriend14.C
new file mode 100644 (file)
index 0000000..86d2d3f
--- /dev/null
@@ -0,0 +1,73 @@
+// { dg-do compile }
+
+// Copyright (C) 2004 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Nest class template of class template as friend
+
+template<class T> struct A
+{
+  template <T t> struct B
+  {
+    void f();
+  };
+};
+
+template <class U> class C {
+  int i;
+  template<class T> template <T t> friend struct A<T>::B;
+};
+
+template<class T> struct A<T*>
+{
+  template <T* t> struct B
+  {
+    void f();
+  };
+};
+
+template<> struct A<char>
+{
+  template <char t> struct B
+  {
+    void f();
+  };
+};
+
+template<class T> template <T t> void A<T>::B<t>::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+template<class T> template <T* t> void A<T*>::B<t>::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+template <char t> void A<char>::B<t>::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+template <> void A<char>::B<'b'>::f()
+{
+  C<int> c;
+  c.i = 0;
+}
+
+int d2 = 0;
+
+int main()
+{
+  A<int>::B<0> b1;
+  b1.f();
+  A<int *>::B<&d2> b2;
+  b2.f();
+  A<char>::B<'a'> b3;
+  b3.f();
+  A<char>::B<'b'> b4;
+  b4.f();
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend15.C b/gcc/testsuite/g++.dg/template/memfriend15.C
new file mode 100644 (file)
index 0000000..08db7ae
--- /dev/null
@@ -0,0 +1,34 @@
+// { dg-do compile }
+
+// Copyright (C) 2004 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Nested class of class template as friend
+
+template<class T> struct A
+{
+  struct B1
+  {
+  };
+  struct B2
+  {
+    void f();
+  };
+};
+
+class C {
+  int i;       // { dg-error "private" }
+  template<class T> friend struct A<T>::B1;
+};
+
+template<class T> void A<T>::B2::f()
+{
+  C c;
+  c.i = 0;     // { dg-error "context" }
+}
+
+int main()
+{
+  A<int>::B2 b1;
+  b1.f();      // { dg-error "instantiated" }
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend16.C b/gcc/testsuite/g++.dg/template/memfriend16.C
new file mode 100644 (file)
index 0000000..a4eeafd
--- /dev/null
@@ -0,0 +1,34 @@
+// { dg-do compile }
+
+// Copyright (C) 2004 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Nested class of class template as friend
+
+template<class T> struct A
+{
+  template <class U> struct B1
+  {
+  };
+  template <class U> struct B2
+  {
+    void f();
+  };
+};
+
+class C {
+  int i;       // { dg-error "private" }
+  template<class T> template <class U> friend struct A<T>::B1;
+};
+
+template<class T> template <class U> void A<T>::B2<U>::f()
+{
+  C c;
+  c.i = 0;     // { dg-error "context" }
+}
+
+int main()
+{
+  A<int>::B2<int> b1;
+  b1.f();      // { dg-error "instantiated" }
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend17.C b/gcc/testsuite/g++.dg/template/memfriend17.C
new file mode 100644 (file)
index 0000000..fd26bc0
--- /dev/null
@@ -0,0 +1,46 @@
+// { dg-do compile }
+
+// Origin: Giovanni Bajo <giovannibajo@libero.it>
+
+// PR c++/13495: Nested class as template friend.
+
+template<typename T>
+class A{
+public:
+    class B
+    {
+        void func1(void);
+        void func2(void);
+    };
+};
+
+template<typename Q>
+class F1
+{
+    friend class A<Q>::B;
+    enum { foo = 0 };  // { dg-error "private" }
+};
+
+template<typename Q>
+class F2
+{
+    template<typename T>
+    friend class A<T>::B;
+    enum { foo = 0 };
+};
+
+template <typename T>
+void A<T>::B::func1(void)
+{
+    (void)F1<T>::foo;
+    (void)F2<T>::foo;
+}
+
+template <typename T>
+void A<T>::B::func2(void)
+{
+    (void)F1<T*>::foo; // { dg-error "context" }
+    (void)F2<T*>::foo;
+}
+
+template class A<int>; // { dg-error "instantiated" }
diff --git a/gcc/testsuite/g++.dg/template/memfriend9.C b/gcc/testsuite/g++.dg/template/memfriend9.C
new file mode 100644 (file)
index 0000000..9c92601
--- /dev/null
@@ -0,0 +1,63 @@
+// { dg-do compile }
+
+// Copyright (C) 2004 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Nested class of class template as friend
+
+template<class T> struct A
+{
+  struct B
+  {
+    void f();
+  };
+};
+
+class C {
+  int i;
+  template<class T> friend struct A<T>::B;
+};
+
+template<class T> struct A<T*>
+{
+  struct B
+  {
+    void f();
+  };
+};
+
+template<> struct A<char>
+{
+  struct B
+  {
+    void f();
+  };
+};
+
+template<class T> void A<T>::B::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template<class T> void A<T*>::B::f()
+{
+  C c;
+  c.i = 0;
+}
+
+void A<char>::B::f()
+{
+  C c;
+  c.i = 0;
+}
+
+int main()
+{
+  A<int>::B b1;
+  b1.f();
+  A<int *>::B b2;
+  b2.f();
+  A<char>::B b3;
+  b3.f();
+}
index 1f79172906145ec0bf0c85b175cba57b8f80a9f7..1d2c1d1f9b67b06ed314ac6b2c320d86847f51dd 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-do run }
+// { dg-do compile }
 // Test that template friends referring to class template members are
 // respected.
 
@@ -15,7 +15,7 @@ class B
 {
   template <class T> friend int A<T>::f (T);
   template <class T> friend struct A<T>::AI;
-  int a; // { dg-bogus "" "" { xfail *-*-* } }
+  int a;
 public:
   B(): a(0) { }
 };
@@ -29,7 +29,7 @@ template <class T> int A<T>::f (T)
 template <class T> int A<T>::AI::f (T)
 {
   B b;
-  return b.a; // { dg-bogus "" "" { xfail *-*-* } }
+  return b.a;
 }
 
 int main ()