OSDN Git Service

PR c++/4403
authorlerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 Mar 2005 14:51:25 +0000 (14:51 +0000)
committerlerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 Mar 2005 14:51:25 +0000 (14:51 +0000)
PR c++/9783, DR433
* name-lookup.c (pushtag): Skip template parameter scope when
scope is ts_global.  Don't push tag into template parameter
scope.
* pt.c (instantiate_class_template): Reorder friend class
template substitution to handle non-dependent friend class
that hasn't been previously declared.

* g++.dg/template/friend34.C: New test.
* g++.dg/template/friend35.C: Likewise.
* g++.old-deja/g++.pt/inherit2.C: Remove XFAIL's.

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

gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/friend34.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/friend35.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/inherit2.C

index e2a7de3..0ac2a84 100644 (file)
@@ -1,5 +1,16 @@
 2005-03-14  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
 
+       PR c++/4403
+       PR c++/9783, DR433
+       * name-lookup.c (pushtag): Skip template parameter scope when
+       scope is ts_global.  Don't push tag into template parameter
+       scope.
+       * pt.c (instantiate_class_template): Reorder friend class
+       template substitution to handle non-dependent friend class
+       that hasn't been previously declared.
+
+2005-03-14  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
        Friend class name lookup 5/n
        PR c++/1016
        * cp-tree.h (pushtag): Adjust declaration.
index 4a5429c..fda7d34 100644 (file)
@@ -4571,10 +4571,19 @@ maybe_process_template_type_declaration (tree type, int is_friend,
   return decl;
 }
 
-/* Push a tag name NAME for struct/class/union/enum type TYPE.
-   Normally put it into the inner-most non-sk_cleanup scope,
-   but if GLOBALIZE is true, put it in the inner-most non-class scope.
-   The latter is needed for implicit declarations.
+/* Push a tag name NAME for struct/class/union/enum type TYPE.  In case
+   that the NAME is a class template, the tag is processed but not pushed.
+
+   The pushed scope depend on the SCOPE parameter:
+   - When SCOPE is TS_CURRENT, put it into the inner-most non-sk_cleanup
+     scope.
+   - When SCOPE is TS_GLOBAL, put it in the inner-most non-class and
+     non-template-parameter scope.  This case is needed for forward
+     declarations.
+   - When SCOPE is TS_WITHIN_ENCLOSING_NON_CLASS, this is similar to
+     TS_GLOBAL case except that names within template-parameter scopes
+     are not pushed at all.
+
    Returns TYPE upon success and ERROR_MARK_NODE otherwise.  */
 
 tree
@@ -4590,10 +4599,9 @@ pushtag (tree name, tree type, tag_scope scope)
         /* Neither are the scopes used to hold template parameters
            for an explicit specialization.  For an ordinary template
            declaration, these scopes are not scopes from the point of
-           view of the language -- but we need a place to stash
-           things that will go in the containing namespace when the
-           template is instantiated.  */
-        || (b->kind == sk_template_parms && b->explicit_spec_p)
+           view of the language.  */
+        || (b->kind == sk_template_parms
+            && (b->explicit_spec_p || scope == ts_global))
         || (b->kind == sk_class
             && (scope != ts_current
                 /* We may be defining a new type in the initializer
@@ -4666,7 +4674,7 @@ pushtag (tree name, tree type, tag_scope scope)
              else
                pushdecl_class_level (d);
            }
-         else
+         else if (b->kind != sk_template_parms)
            d = pushdecl_with_scope (d, b);
 
          if (d == error_mark_node)
index 1147f79..51d32b3 100644 (file)
@@ -5781,11 +5781,13 @@ instantiate_class_template (tree type)
 
              if (TREE_CODE (friend_type) == TEMPLATE_DECL)
                {
+                 /* template <class T> friend class C;  */
                  friend_type = tsubst_friend_class (friend_type, args);
                  adjust_processing_template_decl = true;
                }
              else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE)
                {
+                 /* template <class T> friend class C::D;  */
                  friend_type = tsubst (friend_type, args,
                                        tf_error | tf_warning, NULL_TREE);
                  if (TREE_CODE (friend_type) == TEMPLATE_DECL)
@@ -5794,6 +5796,15 @@ instantiate_class_template (tree type)
                }
              else if (TREE_CODE (friend_type) == TYPENAME_TYPE)
                {
+                 /* This could be either
+
+                      friend class T::C;
+
+                    when dependent_type_p is false or
+
+                      template <class U> friend class T::C;
+
+                    otherwise.  */
                  friend_type = tsubst (friend_type, args,
                                        tf_error | tf_warning, NULL_TREE);
                  /* Bump processing_template_decl for correct
@@ -5803,13 +5814,14 @@ instantiate_class_template (tree type)
                    adjust_processing_template_decl = true;
                  --processing_template_decl;
                }
-             else if (uses_template_parms (friend_type))
-               friend_type = tsubst (friend_type, args,
-                                     tf_error | tf_warning, NULL_TREE);
-             else if (CLASSTYPE_USE_TEMPLATE (friend_type))
-               friend_type = friend_type;
-             else 
+             else if (!CLASSTYPE_USE_TEMPLATE (friend_type)
+                      && hidden_name_p (TYPE_NAME (friend_type)))
                {
+                 /* friend class C;
+
+                    where C hasn't been declared yet.  Let's lookup name
+                    from namespace scope directly, bypassing any name that
+                    come from dependent base class.  */
                  tree ns = decl_namespace_context (TYPE_MAIN_DECL (friend_type));
 
                  /* The call to xref_tag_from_type does injection for friend
@@ -5817,9 +5829,22 @@ instantiate_class_template (tree type)
                  push_nested_namespace (ns);
                  friend_type = 
                    xref_tag_from_type (friend_type, NULL_TREE, 
-                                       /*tag_scope=*/ts_global);
+                                       /*tag_scope=*/ts_current);
                  pop_nested_namespace (ns);
                }
+             else if (uses_template_parms (friend_type))
+               /* friend class C<T>;  */
+               friend_type = tsubst (friend_type, args,
+                                     tf_error | tf_warning, NULL_TREE);
+             /* Otherwise it's
+
+                  friend class C;
+
+                where C is already declared or
+
+                  friend class C<int>;
+
+                We don't have to do anything in these cases.  */
 
              if (adjust_processing_template_decl)
                /* Trick make_friend_class into realizing that the friend
index 993b95b..841c733 100644 (file)
@@ -1,5 +1,13 @@
 2005-03-14  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
 
+       PR c++/4403
+       PR c++/9783, DR433
+       * g++.dg/template/friend34.C: New test.
+       * g++.dg/template/friend35.C: Likewise.
+       * g++.old-deja/g++.pt/inherit2.C: Remove XFAIL's.
+
+2005-03-14  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
        Friend class name lookup 5/n
        PR c++/1016
        * g++.dg/lookup/hidden-class1.C: New test.
diff --git a/gcc/testsuite/g++.dg/template/friend34.C b/gcc/testsuite/g++.dg/template/friend34.C
new file mode 100644 (file)
index 0000000..555cf35
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile }
+
+// Origin: mleone@pixar.com
+//        Wolfgang Bangerth <bangerth@ticam.utexas.edu>
+
+// PR c++/9783: Forward declaration of class in template.
+
+template <typename T>
+struct C {
+  void foo (struct X *);
+};
+
+struct X {};
+
+template <typename T>
+void C<T>::foo(struct X *) {}
diff --git a/gcc/testsuite/g++.dg/template/friend35.C b/gcc/testsuite/g++.dg/template/friend35.C
new file mode 100644 (file)
index 0000000..b150ccd
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do compile }
+
+// Origin: Giovanni Bajo <giovannibajo@libero.it>
+
+// PR c++/4403: Incorrect friend class chosen during instantiation.
+
+template <typename T>
+struct A
+{
+  struct F;
+};
+template <typename T>
+struct B : A<T>
+{
+  friend struct F;
+private:
+  int priv;
+};
+struct F
+{
+  void func(void)
+  {
+    B<int> b;
+    b.priv = 0;
+  }
+};
index 2ae5672..136050d 100644 (file)
@@ -24,8 +24,8 @@ template <class T> class B
   static T value_AC;
 };
 template <typename T> T B<T>::valueA_AA;
-template <typename T> T B<T>::valueA_AC;// { dg-error "" "" { xfail *-*-* } } private - 
-template <typename T> T B<T>::value_AC;        // { dg-bogus "" "" { xfail *-*-* } }  - 
+template <typename T> T B<T>::valueA_AC;// { dg-error "" "" } private - 
+template <typename T> T B<T>::value_AC;        // { dg-bogus "" "" }  - 
 
 // this one is a friend
 template <class T> struct A<T>::AA
@@ -41,7 +41,7 @@ template <class T> struct A<T>::AC
 {
   T M ()
   {
-    return B<T>::valueA_AC;    // { dg-error "" "" { xfail *-*-* } } within this context - 
+    return B<T>::valueA_AC;    // { dg-error "" "" } within this context - 
   }
 };
 
@@ -50,7 +50,7 @@ struct AC
 {
   int M ()
   {
-    return B<int>::value_AC;   // { dg-bogus "" "" { xfail *-*-* } }  - 
+    return B<int>::value_AC;   // { dg-bogus "" "" }  - 
   }
 };