decl.c (xref_tag): Revise handling of nested template declarations.
authorMark Mitchell <mark@codesourcery.com>
Sat, 17 Apr 1999 14:15:29 +0000 (14:15 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sat, 17 Apr 1999 14:15:29 +0000 (14:15 +0000)
* decl.c (xref_tag): Revise handling of nested template
declarations.
* pt.c (check_explicit_specialization): Tweak handling of friend
templates in template classes.
(tsubst_friend_class): Handle friend declarations for nested
member template classes.

From-SVN: r26520

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/pt.c
gcc/testsuite/g++.old-deja/g++.pt/friend41.C [new file with mode: 0644]

index 67cc7e1f019f249d2436e81002ab0a618c9696b5..ceb79ca46f2cc642ab793f634cdde66be5e6f693 100644 (file)
@@ -1,3 +1,12 @@
+1999-04-17  Mark Mitchell  <mark@codesourcery.com>
+
+       * decl.c (xref_tag): Revise handling of nested template
+       declarations.
+       * pt.c (check_explicit_specialization): Tweak handling of friend
+       templates in template classes.
+       (tsubst_friend_class): Handle friend declarations for nested
+       member template classes.
+       
 1999-04-16  Mark Mitchell  <mark@codesourcery.com>
 
        * class.c (finish_struct): Remove unused variable.
index 5730719c89b449a31e225cd7186afa04b97e804c..87eae50b715b481526a12184b57dbcf1a926de66 100644 (file)
@@ -12323,6 +12323,7 @@ xref_tag (code_type_node, name, globalize)
   struct binding_level *b = current_binding_level;
   int got_type = 0;
   tree attributes = NULL_TREE;
+  tree context = NULL_TREE;
 
   /* If we are called from the parser, code_type_node will sometimes be a
      TREE_LIST.  This indicates that the user wrote
@@ -12375,72 +12376,87 @@ xref_tag (code_type_node, name, globalize)
     }
   else
     {
-      if (current_class_type 
-         && template_class_depth (current_class_type) 
-         && PROCESSING_REAL_TEMPLATE_DECL_P ())
-      /* Since GLOBALIZE is non-zero, we are not looking at a
-        definition of this tag.  Since, in addition, we are currently
-        processing a (member) template declaration of a template
-        class, we don't want to do any lookup at all; consider:
-
-          template <class X>
-          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;
-
-        say, when we should tsubst into `U' when instantiating S2.  */
-       ref = NULL_TREE;
-      else 
+      if (t)
        {
-         if (t)
-           {
-             /* [dcl.type.elab] If the identifier resolves to a
-                typedef-name or a template type-parameter, the
-                elaborated-type-specifier is ill-formed.  */
-             if (t != TYPE_MAIN_VARIANT (t)
-                 || (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t)))
-               cp_pedwarn ("using typedef-name `%D' after `%s'",
-                           TYPE_NAME (t), tag_name (tag_code));
-             else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
-               cp_error ("using template type parameter `%T' after `%s'",
-                         t, tag_name (tag_code));
-
-             ref = t;
-           }
-         else
-           ref = lookup_tag (code, name, b, 0);
+         /* [dcl.type.elab] If the identifier resolves to a
+            typedef-name or a template type-parameter, the
+            elaborated-type-specifier is ill-formed.  */
+         if (t != TYPE_MAIN_VARIANT (t)
+             || (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t)))
+           cp_pedwarn ("using typedef-name `%D' after `%s'",
+                       TYPE_NAME (t), tag_name (tag_code));
+         else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+           cp_error ("using template type parameter `%T' after `%s'",
+                     t, tag_name (tag_code));
+
+         ref = t;
+       }
+      else
+       ref = lookup_tag (code, name, b, 0);
          
-         if (! ref)
-           {
-             /* Try finding it as a type declaration.  If that wins,
-                use it.  */ 
-             ref = lookup_name (name, 1);
-
-             if (ref != NULL_TREE
-                 && processing_template_decl
-                 && DECL_CLASS_TEMPLATE_P (ref)
-                 && template_class_depth (current_class_type) == 0)
-               /* Since GLOBALIZE is true, we're declaring a global
+      if (! ref)
+       {
+         /* Try finding it as a type declaration.  If that wins,
+            use it.  */ 
+         ref = lookup_name (name, 1);
+
+         if (ref != NULL_TREE
+             && processing_template_decl
+             && DECL_CLASS_TEMPLATE_P (ref)
+             && template_class_depth (current_class_type) == 0)
+           /* Since GLOBALIZE is true, we're declaring a global
               template, so we want this type.  */
-               ref = DECL_RESULT (ref);
+           ref = DECL_RESULT (ref);
 
-             if (ref && TREE_CODE (ref) == TYPE_DECL
-                 && TREE_CODE (TREE_TYPE (ref)) == code)
-               ref = TREE_TYPE (ref);
-             else
-               ref = NULL_TREE;
-           }
+         if (ref && TREE_CODE (ref) == TYPE_DECL
+             && TREE_CODE (TREE_TYPE (ref)) == code)
+           ref = TREE_TYPE (ref);
+         else
+           ref = NULL_TREE;
+       }
+
+      if (ref && current_class_type 
+         && template_class_depth (current_class_type) 
+         && PROCESSING_REAL_TEMPLATE_DECL_P ()) 
+       {
+         /* Since GLOBALIZE is non-zero, we are not looking at a
+            definition of this tag.  Since, in addition, we are currently
+            processing a (member) template declaration of a template
+            class, we must be very careful; consider:
+
+              template <class X>
+              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;
+
+            say, when we should tsubst into `U' when instantiating
+            S2.  On the other hand, when presented with:
+
+                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.  */
+         context = TYPE_CONTEXT (ref);
+         ref = NULL_TREE;
        }
     }
 
@@ -12487,6 +12503,7 @@ xref_tag (code_type_node, name, globalize)
          struct binding_level *old_b = class_binding_level;
 
          ref = make_lang_type (code);
+         TYPE_CONTEXT (ref) = context;
 
          if (tag_code == signature_type)
            {
index d73f18299f64737a106903f54785db7beab21a58..b26b88a4dcccc8b7f25243b1b76b05f04c3e24fa 100644 (file)
@@ -1281,7 +1281,6 @@ check_explicit_specialization (declarator, decl, template_count, flags)
 
   if (specialization || member_specialization || explicit_instantiation)
     {
-      tree gen_tmpl;
       tree tmpl = NULL_TREE;
       tree targs = NULL_TREE;
 
@@ -1435,13 +1434,34 @@ check_explicit_specialization (declarator, decl, template_count, flags)
        return error_mark_node;
       else
        {
-         gen_tmpl = most_general_template (tmpl);
+         tree gen_tmpl = most_general_template (tmpl);
 
          if (explicit_instantiation)
            {
              /* We don't set DECL_EXPLICIT_INSTANTIATION here; that
-                is done by do_decl_instantiation later.  */
-             decl = instantiate_template (tmpl, innermost_args (targs));
+                is done by do_decl_instantiation later.  */ 
+
+             int arg_depth = TMPL_ARGS_DEPTH (targs);
+             int parm_depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));
+
+             if (arg_depth > parm_depth)
+               {
+                 /* If TMPL is not the most general template (for
+                    example, if TMPL is a friend template that is
+                    injected into namespace scope), then there will
+                    be too many levels fo TARGS.  Remove some of them
+                    here.  */
+                 int i;
+                 tree new_targs;
+
+                 new_targs = make_temp_vec (parm_depth);
+                 for (i = arg_depth - parm_depth; i < arg_depth; ++i)
+                   TREE_VEC_ELT (new_targs, i - (arg_depth - parm_depth))
+                     = TREE_VEC_ELT (targs, i);
+                 targs = new_targs;
+               }
+                 
+             decl = instantiate_template (tmpl, targs);
              return decl;
            }
          
@@ -4583,11 +4603,29 @@ tsubst_friend_class (friend_tmpl, args)
      tree args;
 {
   tree friend_type;
-  tree tmpl = lookup_name (DECL_NAME (friend_tmpl), 1); 
+  tree tmpl;
 
-  tmpl = maybe_get_template_decl_from_type_decl (tmpl);
+  /* First, we look for a class template.  */
+  tmpl = lookup_name (DECL_NAME (friend_tmpl), /*prefer_type=*/0); 
+  
+  /* But, if we don't find one, it might be because we're in a
+     situation like this:
+
+       template <class T>
+       struct S {
+         template <class U>
+        friend struct S;
+       };
+
+     Here, in the scope of (say) S<int>, `S' is bound to a TYPE_DECL
+     for `S<int>', not the TEMPLATE_DECL.  */
+  if (!DECL_CLASS_TEMPLATE_P (tmpl))
+    {
+      tmpl = lookup_name (DECL_NAME (friend_tmpl), /*prefer_type=*/1);
+      tmpl = maybe_get_template_decl_from_type_decl (tmpl);
+    }
 
-  if (tmpl != NULL_TREE && DECL_CLASS_TEMPLATE_P (tmpl))
+  if (tmpl && DECL_CLASS_TEMPLATE_P (tmpl))
     {
       /* The friend template has already been declared.  Just
         check to see that the declarations match, and install any new
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend41.C b/gcc/testsuite/g++.old-deja/g++.pt/friend41.C
new file mode 100644 (file)
index 0000000..d6b74a0
--- /dev/null
@@ -0,0 +1,21 @@
+// Build don't link:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+template <class T>
+class S {
+public:
+  template <class U>
+  class C {
+  public:
+    void f() { S::i = 3; }
+  };
+
+  template <class U>
+  friend class C;
+
+private:
+  static int i;
+};
+
+
+template void S<int>::C<double>::f();