re PR c++/9030 (Template friends and access to local classes)
authorKriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
Wed, 8 Jan 2003 14:42:39 +0000 (14:42 +0000)
committerKriang Lerdsuwanakij <lerdsuwa@gcc.gnu.org>
Wed, 8 Jan 2003 14:42:39 +0000 (14:42 +0000)
PR c++/9030
* decl.c (make_typename_type): Check access only when tf_error.
(make_unbound_class_template): Likewise.
* pt.c (saved_access_scope): New variable.
(push_access_scope_real): New function.
(push_access_scope): Likewise.
(pop_access_scope): Likewise.
(tsubst_default_argument): Use them.
(instantiate_template): Likewise.
(regenerate_decl_from_template): Likewise.
(instantiate_decl): Likewise.
(get_mostly_instantiated_function_type): Likewise.

* g++.dg/template/friend12.C: New test.
* g++.dg/template/friend13.C: Likewise.
* g++.old-deja/g++.eh/spec6.C: Add missing error message.

From-SVN: r61046

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/friend12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/friend13.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.eh/spec6.C

index 9b7f67a..26207b7 100644 (file)
@@ -1,3 +1,18 @@
+2003-01-08  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
+       PR c++/9030
+       * decl.c (make_typename_type): Check access only when tf_error.
+       (make_unbound_class_template): Likewise.
+       * pt.c (saved_access_scope): New variable.
+       (push_access_scope_real): New function.
+       (push_access_scope): Likewise.
+       (pop_access_scope): Likewise.
+       (tsubst_default_argument): Use them.
+       (instantiate_template): Likewise.
+       (regenerate_decl_from_template): Likewise.
+       (instantiate_decl): Likewise.
+       (get_mostly_instantiated_function_type): Likewise.
+
 2003-01-07  Nathanael Nerode <neroden@gcc.gnu.org>
 
        * tree.c: Delete bogus #if 0 code.
index f814182..538519e 100644 (file)
@@ -5671,10 +5671,13 @@ make_typename_type (context, name, complain)
              return error_mark_node;
            }
 
-         if (complain & tf_parsing)
-           type_access_control (context, tmpl);
-         else
-           enforce_access (context, tmpl);
+         if (complain & tf_error)
+           {
+             if (complain & tf_parsing)
+               type_access_control (context, tmpl);
+             else
+               enforce_access (context, tmpl);
+           }
 
          return lookup_template_class (tmpl,
                                        TREE_OPERAND (fullname, 1),
@@ -5703,10 +5706,13 @@ make_typename_type (context, name, complain)
                  return error_mark_node;
                }
 
-             if (complain & tf_parsing)
-               type_access_control (context, t);
-             else
-               enforce_access (context, t);
+             if (complain & tf_error)
+               {
+                 if (complain & tf_parsing)
+                   type_access_control (context, t);
+                 else
+                   enforce_access (context, t);
+               }
 
              if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
                t = TREE_TYPE (t);
@@ -5774,10 +5780,13 @@ make_unbound_class_template (context, name, complain)
          return error_mark_node;
        }
       
-      if (complain & tf_parsing)
-       type_access_control (context, tmpl);
-      else
-       enforce_access (context, tmpl);
+      if (complain & tf_error)
+       {
+         if (complain & tf_parsing)
+           type_access_control (context, tmpl);
+         else
+           enforce_access (context, tmpl);
+       }
 
       return tmpl;
     }
index f7a9114..b63443b 100644 (file)
@@ -67,6 +67,8 @@ static size_t inline_parm_levels_used;
 
 static GTY(()) tree current_tinst_level;
 
+static GTY(()) tree saved_access_scope;
+
 /* A map from local variable declarations in the body of the template
    presently being instantiated to the corresponding instantiated
    local variables.  */
@@ -88,6 +90,9 @@ static htab_t local_specializations;
 #define GTB_IGNORE_TYPE 2 /* We don't need to try to unify the current
                             type with the desired type.  */
 
+static void push_access_scope_real PARAMS ((tree, tree, tree));
+static void push_access_scope PARAMS ((tree));
+static void pop_access_scope PARAMS ((tree));
 static int resolve_overloaded_unification PARAMS ((tree, tree, tree, tree,
                                                   unification_kind_t, int));
 static int try_one_overload PARAMS ((tree, tree, tree, tree, tree,
@@ -168,6 +173,80 @@ static int invalid_nontype_parm_type_p PARAMS ((tree, tsubst_flags_t));
 static int eq_local_specializations (const void *, const void *);
 static tree template_for_substitution (tree);
 
+/* Make the current scope suitable for access checking when we are
+   processing T.  T can be FUNCTION_DECL for instantiated function
+   template, TEMPLATE_DECL for uninstantiated one, or VAR_DECL for
+   static member variable (need by instantiate_decl).  ARGS is the 
+   template argument for TEMPLATE_DECL.  If CONTEXT is not NULL_TREE, 
+   this is used instead of the context of T.  */
+
+void
+push_access_scope_real (t, args, context)
+  tree t, args, context;
+{
+  if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t))
+    {
+      /* When we are processing specialization `foo<Outer>' for code like
+
+          template <class U> typename U::Inner foo ();
+          class Outer {
+            struct Inner {};
+            friend Outer::Inner foo<Outer> ();
+          };
+
+        `T' is a TEMPLATE_DECL, but `Outer' is only a friend of one of
+        its specialization.  We can get the FUNCTION_DECL with the right
+        information because this specialization has already been
+        registered by the friend declaration above.  */
+
+      if (DECL_FUNCTION_TEMPLATE_P (t) && args)
+       {
+         tree full_args = tsubst_template_arg_vector
+           (DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t)), args, tf_none);
+         tree spec = NULL_TREE;
+         if (full_args != error_mark_node)
+           spec = retrieve_specialization (t, full_args);
+         if (spec)
+           t = spec;
+       }
+
+      saved_access_scope = tree_cons
+       (NULL_TREE, current_function_decl, saved_access_scope);
+      current_function_decl = t;
+    }
+
+  if (!context)
+    context = DECL_CONTEXT (t);
+  if (context && TYPE_P (context))
+    push_nested_class (context, 2);
+}
+
+/* Like push_access_scope_real, but always uses DECL_CONTEXT.  */
+
+void
+push_access_scope (t)
+  tree t;
+{
+  push_access_scope_real (t, NULL_TREE, NULL_TREE);
+}
+
+/* Restore the scope set up by push_access_scope.  T is the node we
+   are processing.  */
+
+void
+pop_access_scope (t)
+  tree t;
+{
+  if (DECL_CLASS_SCOPE_P (t))
+    pop_nested_class ();
+
+  if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t))
+    {
+      current_function_decl = TREE_VALUE (saved_access_scope);
+      saved_access_scope = TREE_CHAIN (saved_access_scope);
+    }
+}
+
 /* Do any processing required when DECL (a member template
    declaration) is finished.  Returns the TEMPLATE_DECL corresponding
    to DECL, unless it is a specialization, in which case the DECL
@@ -5733,14 +5812,14 @@ tsubst_default_argument (fn, type, arg)
      ??? current_class_type affects a lot more than name lookup.  This is
      very fragile.  Fortunately, it will go away when we do 2-phase name
      binding properly.  */
-  if (DECL_CLASS_SCOPE_P (fn))
-    pushclass (DECL_CONTEXT (fn), 2);
+
+  /* FN is already the desired FUNCTION_DECL.  */
+  push_access_scope (fn);
 
   arg = tsubst_expr (arg, DECL_TI_ARGS (fn),
                     tf_error | tf_warning, NULL_TREE);
   
-  if (DECL_CLASS_SCOPE_P (fn))
-    popclass ();
+  pop_access_scope (fn);
 
   /* Make sure the default argument is reasonable.  */
   arg = check_default_argument (type, arg);
@@ -7873,17 +7952,17 @@ instantiate_template (tmpl, targ_ptr)
     }
 
   /* Make sure that we can see identifiers, and compute access
-     correctly.  */
-  if (DECL_CLASS_SCOPE_P (gen_tmpl))
-    pushclass (tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, tf_error,
-                      gen_tmpl), 1);
+     correctly.  The desired FUNCTION_DECL for FNDECL may or may not be
+     created earlier.  Let push_access_scope_real figure that out.  */
+  push_access_scope_real
+    (gen_tmpl, targ_ptr, tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, 
+                                tf_error, gen_tmpl));
 
   /* substitute template parameters */
   fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
                   targ_ptr, tf_error, gen_tmpl);
 
-  if (DECL_CLASS_SCOPE_P (gen_tmpl))
-    popclass ();
+  pop_access_scope (gen_tmpl);
 
   /* The DECL_TI_TEMPLATE should always be the immediate parent
      template, not the most general template.  */
@@ -7955,7 +8034,7 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
   int result;
 
   my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
-  
+
   fntype = TREE_TYPE (fn);
   if (explicit_targs)
     {
@@ -9977,6 +10056,7 @@ regenerate_decl_from_template (decl, tmpl)
      instantiation of a specialization, which it isn't: it's a full
      instantiation.  */
   gen_tmpl = most_general_template (tmpl);
+  push_access_scope_real (gen_tmpl, args, DECL_CONTEXT (decl));
   unregistered = unregister_specialization (decl, gen_tmpl);
 
   /* If the DECL was not unregistered then something peculiar is
@@ -9984,12 +10064,6 @@ regenerate_decl_from_template (decl, tmpl)
      register_specialization for it.  */
   my_friendly_assert (unregistered, 0);
 
-  if (DECL_CLASS_SCOPE_P (decl))
-    /* Make sure that we can see identifiers, and compute access
-       correctly, for the class members used in the declaration of
-       this static variable or function.  */
-    push_nested_class (DECL_CONTEXT (decl), 2);
-
   /* Do the substitution to get the new declaration.  */
   new_decl = tsubst (code_pattern, args, tf_error, NULL_TREE);
 
@@ -10010,9 +10084,7 @@ regenerate_decl_from_template (decl, tmpl)
       DECL_INITIAL (decl) = NULL_TREE;
     }
 
-  /* Pop the class context we pushed above.  */
-  if (DECL_CLASS_SCOPE_P (decl))
-    pop_nested_class ();
+  pop_access_scope (decl);
 
   /* The immediate parent of the new template is still whatever it was
      before, even though tsubst sets DECL_TI_TEMPLATE up as the most
@@ -10218,9 +10290,9 @@ instantiate_decl (d, defer_ok)
       tree type = TREE_TYPE (gen);
 
       /* Make sure that we can see identifiers, and compute access
-        correctly.  */
-      if (DECL_CLASS_SCOPE_P (d))
-       pushclass (DECL_CONTEXT (d), 1);
+        correctly.  D is already the target FUNCTION_DECL with the
+        right context.  */
+      push_access_scope (d);
 
       if (TREE_CODE (gen) == FUNCTION_DECL)
        {
@@ -10235,8 +10307,7 @@ instantiate_decl (d, defer_ok)
        }
       tsubst (type, gen_args, tf_error | tf_warning, d);
 
-      if (DECL_CLASS_SCOPE_P (d))
-       popclass ();
+      pop_access_scope (d);
     }
   
   if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
@@ -10597,8 +10668,7 @@ get_mostly_instantiated_function_type (decl)
         partial substitution here.  It depends only on outer template
         parameters, regardless of whether the innermost level is
         specialized or not.  */
-      if (DECL_CLASS_SCOPE_P (decl))
-       pushclass (DECL_CONTEXT (decl), 1);
+      push_access_scope (decl);
 
       /* Now, do the (partial) substitution to figure out the
         appropriate function type.  */
@@ -10611,8 +10681,7 @@ get_mostly_instantiated_function_type (decl)
       TREE_VEC_LENGTH (partial_args)--;
       tparms = tsubst_template_parms (tparms, partial_args, tf_error);
 
-      if (DECL_CLASS_SCOPE_P (decl))
-       popclass ();
+      pop_access_scope (decl);
     }
 
   return fn_type;
index ba32c50..848423d 100644 (file)
@@ -1,3 +1,10 @@
+2003-01-08  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
+       PR c++/9030
+       * g++.dg/template/friend12.C: New test.
+       * g++.dg/template/friend13.C: Likewise.
+       * g++.old-deja/g++.eh/spec6.C: Add missing error message.
+
 Wed Jan  8 11:41:47 CET 2003  Jan Hubicka  <jh@suse.cz>
 
        * gcc.dg/i386-cadd.c: New test.
diff --git a/gcc/testsuite/g++.dg/template/friend12.C b/gcc/testsuite/g++.dg/template/friend12.C
new file mode 100644 (file)
index 0000000..0cd561b
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-do compile }
+
+// Origin: Wolfgang Bangerth <bangerth@ticam.utexas.edu>
+
+// PR 9030.  Perform access checking to parameter and return type of 
+// function template correctly when the template is friend.
+
+template <class T> class Outer {
+  private:
+    struct Inner {};
+
+    template <class T_>
+    friend typename Outer<T_>::Inner foo ();
+};
+
+template <class T>
+typename Outer<T>::Inner
+foo () {
+  return typename Outer<T>::Inner();
+}
+
+void f() {
+  foo<int>();
+}
diff --git a/gcc/testsuite/g++.dg/template/friend13.C b/gcc/testsuite/g++.dg/template/friend13.C
new file mode 100644 (file)
index 0000000..6eebf6b
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-do compile }
+
+// Perform access checking to parameter and return type of 
+// function template correctly when only specialization is friend.
+
+template <class T>
+typename T::Inner
+foo () {
+  return typename T::Inner();
+}
+
+class Outer {
+  private:
+    struct Inner {};
+
+    friend Outer::Inner foo<Outer> ();
+};
+
+void f() {
+  foo<Outer>();
+}
index 1bde4cb..d9d4edf 100644 (file)
@@ -25,7 +25,7 @@ template<class T> void fnx(T *) throw(T){}  // ERROR - invalid use of void expre
 void fx()
 {
   fnx((int *)0);
-  fnx((void *)0);
+  fnx((void *)0);              // ERROR - instantiated from here
 }
 
 // [except.spec] 2, exception specifiers must be the same set of types (but