cp-tree.h (lang_type): Remove has_assignment and has_real_assignment.
authorMark Mitchell <mark@codesourcery.com>
Wed, 24 Mar 1999 01:10:13 +0000 (01:10 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Wed, 24 Mar 1999 01:10:13 +0000 (01:10 +0000)
* cp-tree.h (lang_type): Remove has_assignment and
has_real_assignment.  Add befriending_classes.
(TYPE_HAS_ASSIGNMENT): Remove.
(TYPE_HAS_REAL_ASSIGNMENT): Likewise.
(CLASSTYPE_BEFRIENDING_CLASSES): New macro.
(lang_decl): Document.
(DECL_BEFRIENDING_CLASSES): New macro.
(FRIEND_NAME): Move declaration to more obvious location.
(FRIEND_DECLS): Likewise.
* class.c (finish_struct_1): Don't use TYPE_HAS_REAL_ASSIGNMENT.
* decl.c (duplicate_decls): Copy DECL_BEFRIENDING_CLASSES.
(fixup_anonymous_union): Don't use TYPE_HAS_ASSIGNMENT.
(grok_op_properties): Likewise.
* friend.c (is_friend): Use FRIEND_NAME and FRIEND_DECLS.
(add_friend): Likewise.  Don't do weird things with assignment
operators.  Update DECL_BEFRIENDING_CLASSES.
(add_friends): Don't do weird things with assignment operators.
(make_friend_class): Likewise.  Update
CLASSTYPE_BEFRIENDING_CLASSES.
* pt.c (instantiate_class_template): Don't set
TYPE_HAS_ASSIGNMENT.
(tsubst_copy): Substitute the TREE_TYPE for more unary
expressions.
* ptree.c (print_lang_type): Don't look at TYPE_HAS_ASSIGNMENT.
* search.c (protected_accessible_p): New function.
(friend_accessible_p): Likewise.
(accessible_p): Use them.

From-SVN: r25940

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/friend.c
gcc/cp/pt.c
gcc/cp/ptree.c
gcc/cp/search.c
gcc/testsuite/g++.old-deja/g++.other/friend1.C

index 3bac892ca8e576de998086079a6eef16979cf770..d0f66bce36e7693dd881b613f14b3abcd97ccfd7 100644 (file)
@@ -1,3 +1,33 @@
+1999-03-24  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (lang_type): Remove has_assignment and
+       has_real_assignment.  Add befriending_classes.
+       (TYPE_HAS_ASSIGNMENT): Remove.
+       (TYPE_HAS_REAL_ASSIGNMENT): Likewise.
+       (CLASSTYPE_BEFRIENDING_CLASSES): New macro.
+       (lang_decl): Document.
+       (DECL_BEFRIENDING_CLASSES): New macro.
+       (FRIEND_NAME): Move declaration to more obvious location.
+       (FRIEND_DECLS): Likewise.
+       * class.c (finish_struct_1): Don't use TYPE_HAS_REAL_ASSIGNMENT.
+       * decl.c (duplicate_decls): Copy DECL_BEFRIENDING_CLASSES.
+       (fixup_anonymous_union): Don't use TYPE_HAS_ASSIGNMENT.
+       (grok_op_properties): Likewise.
+       * friend.c (is_friend): Use FRIEND_NAME and FRIEND_DECLS.
+       (add_friend): Likewise.  Don't do weird things with assignment
+       operators.  Update DECL_BEFRIENDING_CLASSES.
+       (add_friends): Don't do weird things with assignment operators.
+       (make_friend_class): Likewise.  Update
+       CLASSTYPE_BEFRIENDING_CLASSES.
+       * pt.c (instantiate_class_template): Don't set
+       TYPE_HAS_ASSIGNMENT. 
+       (tsubst_copy): Substitute the TREE_TYPE for more unary
+       expressions.
+       * ptree.c (print_lang_type): Don't look at TYPE_HAS_ASSIGNMENT.
+       * search.c (protected_accessible_p): New function.
+       (friend_accessible_p): Likewise.
+       (accessible_p): Use them.
+       
 1999-03-23  Mark Mitchell  <mark@codesourcery.com>
 
        * pt.c (convert_nontype_argument): Don't create things that aren't
index 6d8a4d61e507256c0eed653b4733a2b7eadcea92..07f8f9737e146ff0e7d58a5ad80f2b18f5f227b5 100644 (file)
@@ -3808,7 +3808,6 @@ finish_struct_1 (t, warn_anon)
   if (! IS_SIGNATURE (t))
     CLASSTYPE_NON_AGGREGATE (t)
       = ! aggregate || has_virtual || TYPE_HAS_CONSTRUCTOR (t);
-  TYPE_HAS_REAL_ASSIGNMENT (t) |= TYPE_HAS_ASSIGNMENT (t);
   TYPE_HAS_REAL_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t);
   TYPE_HAS_COMPLEX_ASSIGN_REF (t)
     |= TYPE_HAS_ASSIGN_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t);
index 59f3e30a3bbca06904cd62da9bcfb1aca502a3f3..307df1dd989aba1eb9714f5ede9ecb3c18b4d386 100644 (file)
@@ -683,12 +683,12 @@ struct lang_type
     {
       unsigned has_type_conversion : 1;
       unsigned has_init_ref : 1;
-      unsigned has_assignment : 1;
       unsigned has_default_ctor : 1;
       unsigned uses_multiple_inheritance : 1;
       unsigned const_needs_init : 1;
       unsigned ref_needs_init : 1;
       unsigned has_const_assign_ref : 1;
+      unsigned anon_union : 1;
 
       unsigned has_nonpublic_ctor : 2;
       unsigned has_nonpublic_assign_ref : 2;
@@ -721,22 +721,20 @@ struct lang_type
       unsigned has_opaque_typedecls : 1;
       unsigned sigtable_has_been_generated : 1;
       unsigned was_anonymous : 1;
-      unsigned has_real_assignment : 1;
       unsigned has_real_assign_ref : 1;
       unsigned has_const_init_ref : 1;
-
       unsigned has_complex_init_ref : 1;
+
       unsigned has_complex_assign_ref : 1;
       unsigned has_abstract_assign_ref : 1;
       unsigned non_aggregate : 1;
       unsigned is_partial_instantiation : 1;
       unsigned has_mutable : 1;
-      unsigned anon_union : 1;
 
       /* The MIPS compiler gets it wrong if this struct also
         does not fill out to a multiple of 4 bytes.  Add a
         member `dummy' with new bits if you go over the edge.  */
-      unsigned dummy : 9;
+      unsigned dummy : 11;
     } type_flags;
 
   int n_ancestors;
@@ -772,8 +770,8 @@ struct lang_type
   union tree_node *signature;
   union tree_node *signature_pointer_to;
   union tree_node *signature_reference_to;
-
   union tree_node *template_info;
+  tree befriending_classes;
 };
 
 /* Indicates whether or not (and how) a template was expanded for this class.
@@ -789,13 +787,6 @@ struct lang_type
 /* List of friends which were defined inline in this class definition.  */
 #define CLASSTYPE_INLINE_FRIENDS(NODE) (TYPE_NONCOPIED_PARTS (NODE))
 
-/* Nonzero for _CLASSTYPE means that the _CLASSTYPE either has
-   a special meaning for the assignment operator ("operator="),
-   or one of its fields (or base members) has a special meaning
-   defined.  */
-#define TYPE_HAS_ASSIGNMENT(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_assignment)
-#define TYPE_HAS_REAL_ASSIGNMENT(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_real_assignment)
-
 /* Nonzero for _CLASSTYPE means that operator new and delete are defined,
    respectively.  */
 #define TYPE_GETS_NEW(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.gets_new)
@@ -1057,11 +1048,15 @@ struct lang_type
 /* Same, but cache a list whose value is the binfo of this type.  */
 #define CLASSTYPE_BINFO_AS_LIST(NODE) (TYPE_LANG_SPECIFIC(NODE)->binfo_as_list)
 
-/* A list of class types with which this type is a friend.  The
+/* A list of class types of which this type is a friend.  The
    TREE_VALUE is normally a TYPE, but will be a TEMPLATE_DECL in the
    case of a template friend.  */
 #define CLASSTYPE_FRIEND_CLASSES(NODE) (TYPE_LANG_SPECIFIC(NODE)->friend_classes)
 
+/* A list of the classes which grant friendship to this class.  */
+#define CLASSTYPE_BEFRIENDING_CLASSES(NODE) \
+  (TYPE_LANG_SPECIFIC (NODE)->befriending_classes)
+
 /* Say whether this node was declared as a "class" or a "struct".  */
 #define CLASSTYPE_DECLARED_CLASS(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.declared_class)
 
@@ -1169,6 +1164,15 @@ struct lang_type
 /* The binding level associated with the namespace.  */
 #define NAMESPACE_LEVEL(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.level)
 \f
+
+/* If a DECL has DECL_LANG_SPECIFIC, it is either a lang_decl_flags or
+   a lang_decl (which has lang_decl_flags as its initial prefix).  A
+   FUNCTION_DECL, NAMESPACE_DECL, TYPE_DECL, or USING_DECL may have a
+   full lang_decl.  A FIELD_DECL, or a static data member VAR_DECL,
+   will have only lang_decl_flags.  Thus, one should only access the
+   members of lang_decl that are not in lang_decl_flags for DECLs that
+   are not FIELD_DECLs or VAR_DECLs.  */
+
 struct lang_decl_flags
 {
 #ifdef ONLY_INT_FIELDS
@@ -1215,6 +1219,7 @@ struct lang_decl
   struct lang_decl_flags decl_flags;
 
   tree main_decl_variant;
+  tree befriending_classes;
   struct pending_inline *pending_inline_info;
 };
 
@@ -1281,6 +1286,10 @@ struct lang_decl
    member functions for this class.  */
 #define DECL_FRIEND_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.friend_attr)
 
+/* A TREE_LIST of the types which have befriended this FUNCTION_DECL.  */
+#define DECL_BEFRIENDING_CLASSES(NODE) \
+  (DECL_LANG_SPECIFIC(NODE)->befriending_classes)
+
 /* Nonzero for FUNCTION_DECL means that this decl is a static
    member function.  */
 #define DECL_STATIC_FUNCTION_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.static_function)
@@ -1822,6 +1831,8 @@ extern int flag_new_for_scope;
    the TREE_PUROSE will be the class type, and the TREE_VALUE will be
    NULL_TREE.  */
 #define DECL_FRIENDLIST(NODE)          (DECL_INITIAL (NODE))
+#define FRIEND_NAME(LIST) (TREE_PURPOSE (LIST))
+#define FRIEND_DECLS(LIST) (TREE_VALUE (LIST))
 
 /* The DECL_ACCESS, if non-NULL, is a TREE_LIST.  The TREE_PURPOSE of
    each node is a type; the TREE_VALUE is the access granted for this
@@ -2677,9 +2688,6 @@ extern tree current_class_name;   /* IDENTIFIER_NODE: name of current class */
 #define same_or_base_type_p(type1, type2) \
   comptypes ((type1), (type2), COMPARE_BASE)
 
-#define FRIEND_NAME(LIST) (TREE_PURPOSE (LIST))
-#define FRIEND_DECLS(LIST) (TREE_VALUE (LIST))
-
 /* These macros are used to access a TEMPLATE_PARM_INDEX.  */
 #define TEMPLATE_PARM_IDX(NODE) (((template_parm_index*) NODE)->index)
 #define TEMPLATE_PARM_LEVEL(NODE) (((template_parm_index*) NODE)->level)
index e7272ff0b4a66638a9b2ba0217b6f0addfc532ab..64c8a6595f5ca94d96c7713bd44723c8cd6d8faf 100644 (file)
@@ -3326,6 +3326,13 @@ duplicate_decls (newdecl, olddecl)
       DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
       DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
       olddecl_friend = DECL_FRIEND_P (olddecl);
+
+      /* Only functions have DECL_BEFRIENDING_CLASSES.  */
+      if (TREE_CODE (newdecl) == FUNCTION_DECL
+         || DECL_FUNCTION_TEMPLATE_P (newdecl))
+       DECL_BEFRIENDING_CLASSES (newdecl)
+         = chainon (DECL_BEFRIENDING_CLASSES (newdecl),
+                    DECL_BEFRIENDING_CLASSES (olddecl));
     }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -6668,7 +6675,6 @@ fixup_anonymous_union (t)
   TYPE_HAS_INIT_REF (t) = 0;
   TYPE_HAS_CONST_INIT_REF (t) = 0;
   TYPE_HAS_ASSIGN_REF (t) = 0;
-  TYPE_HAS_ASSIGNMENT (t) = 0;
   TYPE_HAS_CONST_ASSIGN_REF (t) = 0;
 
   /* Splice the implicitly generated functions out of the TYPE_METHODS
@@ -11804,7 +11810,7 @@ grok_op_properties (decl, virtualp, friendp)
       if (name == ansi_opname[(int) MODIFY_EXPR]
          && !(DECL_TEMPLATE_INSTANTIATION (decl)
               && is_member_template (DECL_TI_TEMPLATE (decl))))
-       TYPE_HAS_ASSIGNMENT (current_class_type) = 1;
+       ;
       else if (name == ansi_opname[(int) CALL_EXPR])
        TYPE_OVERLOADS_CALL_EXPR (current_class_type) = 1;
       else if (name == ansi_opname[(int) ARRAY_REF])
index 30b3c510972757c61a070b8ed1601b9086b7a52a..2a69acd8d84d688cdcfc8d6299b873ae922d3d61 100644 (file)
@@ -61,9 +61,9 @@ is_friend (type, supplicant)
 
       for (; list ; list = TREE_CHAIN (list))
        {
-         if (name == TREE_PURPOSE (list))
+         if (name == FRIEND_NAME (list))
            {
-             tree friends = TREE_VALUE (list);
+             tree friends = FRIEND_DECLS (list);
              for (; friends ; friends = TREE_CHAIN (friends))
                {
                  if (same_type_p (ctype, TREE_PURPOSE (friends)))
@@ -148,11 +148,13 @@ add_friend (type, decl)
   tree list = DECL_FRIENDLIST (typedecl);
   tree name = DECL_NAME (decl);
 
+  type = TREE_TYPE (typedecl);
+
   while (list)
     {
-      if (name == TREE_PURPOSE (list))
+      if (name == FRIEND_NAME (list))
        {
-         tree friends = TREE_VALUE (list);
+         tree friends = FRIEND_DECLS (list);
          for (; friends ; friends = TREE_CHAIN (friends))
            {
              if (decl == TREE_VALUE (friends))
@@ -170,21 +172,13 @@ add_friend (type, decl)
        }
       list = TREE_CHAIN (list);
     }
+
   DECL_FRIENDLIST (typedecl)
     = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
                 DECL_FRIENDLIST (typedecl));
-  if (DECL_NAME (decl) == ansi_opname[(int) MODIFY_EXPR])
-    {
-      tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
-      TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
-      if (parmtypes && TREE_CHAIN (parmtypes))
-       {
-         tree parmtype = TREE_VALUE (TREE_CHAIN (parmtypes));
-         if (TREE_CODE (parmtype) == REFERENCE_TYPE
-             && TREE_TYPE (parmtypes) == TREE_TYPE (typedecl))
-           TYPE_HAS_ASSIGN_REF (TREE_TYPE (typedecl)) = 1;
-       }
-    }
+  DECL_BEFRIENDING_CLASSES (decl) 
+    = tree_cons (NULL_TREE, type,
+                DECL_BEFRIENDING_CLASSES (decl));
 }
 
 /* Declare that every member function NAME in FRIEND_TYPE
@@ -199,9 +193,9 @@ add_friends (type, name, friend_type)
 
   while (list)
     {
-      if (name == TREE_PURPOSE (list))
+      if (name == FRIEND_NAME (list))
        {
-         tree friends = TREE_VALUE (list);
+         tree friends = FRIEND_DECLS (list);
          while (friends && TREE_PURPOSE (friends) != friend_type)
            friends = TREE_CHAIN (friends);
          if (friends)
@@ -226,13 +220,6 @@ add_friends (type, name, friend_type)
     = tree_cons (name,
                 build_tree_list (friend_type, NULL_TREE),
                 DECL_FRIENDLIST (typedecl));
-  if (! strncmp (IDENTIFIER_POINTER (name),
-                IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]),
-                strlen (IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]))))
-    {
-      TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
-      sorry ("declaring \"friend operator =\" will not find \"operator = (X&)\" if it exists");
-    }
 }
 
 /* Make FRIEND_TYPE a friend class to TYPE.  If FRIEND_TYPE has already
@@ -309,6 +296,11 @@ make_friend_class (type, friend_type)
     {
       CLASSTYPE_FRIEND_CLASSES (type)
        = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
+      if (is_template_friend)
+       friend_type = TREE_TYPE (friend_type);
+      CLASSTYPE_BEFRIENDING_CLASSES (friend_type)
+       = tree_cons (NULL_TREE, type, 
+                    CLASSTYPE_BEFRIENDING_CLASSES (friend_type)); 
     }
 }
 
index aa8c9e99c102deebfb85b9563cf7875cf4f74655..f7372dd42e1635f988029ccc91cb5e7361e16342 100644 (file)
@@ -4783,7 +4783,6 @@ instantiate_class_template (type)
 
   TYPE_HAS_CONSTRUCTOR (type) = TYPE_HAS_CONSTRUCTOR (pattern);
   TYPE_HAS_DESTRUCTOR (type) = TYPE_HAS_DESTRUCTOR (pattern);
-  TYPE_HAS_ASSIGNMENT (type) = TYPE_HAS_ASSIGNMENT (pattern);
   TYPE_OVERLOADS_CALL_EXPR (type) = TYPE_OVERLOADS_CALL_EXPR (pattern);
   TYPE_OVERLOADS_ARRAY_REF (type) = TYPE_OVERLOADS_ARRAY_REF (pattern);
   TYPE_OVERLOADS_ARROW (type) = TYPE_OVERLOADS_ARROW (pattern);
@@ -6682,7 +6681,7 @@ tsubst_copy (t, args, complain, in_decl)
     case THROW_EXPR:
     case TYPEID_EXPR:
       return build1
-       (code, NULL_TREE,
+       (code, tsubst (TREE_TYPE (t), args, complain, in_decl),
         tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl));
 
     case PLUS_EXPR:
index 4fb0413b9c0efa829ef9cab57e9897ee94a602f4..2cff6552ed9bc90c1ad90e3e6ea70a4c9e82b6ca 100644 (file)
@@ -113,8 +113,6 @@ print_lang_type (file, node, indent)
     fputs (" delete", file);
   if (TYPE_GETS_DELETE (node) & 2)
     fputs (" delete[]", file);
-  if (TYPE_HAS_ASSIGNMENT (node))
-    fputs (" has=", file);
   if (TYPE_HAS_ASSIGN_REF (node))
     fputs (" this=(X&)", file);
   if (TYPE_OVERLOADS_CALL_EXPR (node))
index 0218b56827ddccdce62c04a96949ded0f6e7ada0..a5301beb8b00737e4a25da6378ca0883229ff16b 100644 (file)
@@ -147,6 +147,8 @@ static tree access_in_type PROTO ((tree, tree));
 static tree dfs_canonical_queue PROTO ((tree, void *));
 static tree dfs_assert_unmarked_p PROTO ((tree, void *));
 static void assert_canonical_unmarked PROTO ((tree));
+static int protected_accessible_p PROTO ((tree, tree, tree, tree));
+static int friend_accessible_p PROTO ((tree, tree, tree, tree));
 
 /* Allocate a level of searching.  */
 
@@ -846,6 +848,116 @@ dfs_accessible_p (binfo, data)
   return NULL_TREE;
 }
 
+/* Returns non-zero if it is OK to access DECL when named in TYPE
+   through an object indiated by BINFO in the context of DERIVED.  */
+
+static int
+protected_accessible_p (type, decl, derived, binfo)
+     tree type;
+     tree decl;
+     tree derived;
+     tree binfo;
+{
+  tree access;
+
+  /* We're checking this clause from [class.access.base]
+
+       m as a member of N is protected, and the reference occurs in a
+       member or friend of class N, or in a member or friend of a
+       class P derived from N, where m as a member of P is private or
+       protected.  
+
+    If DERIVED isn't derived from TYPE, then it certainly does not
+    apply.  */
+  if (!DERIVED_FROM_P (type, derived))
+    return 0;
+
+  access = access_in_type (derived, decl);
+  if (same_type_p (derived, type))
+    {
+      if (access != access_private_node)
+       return 0;
+    }
+  else if (access != access_private_node
+          && access != access_protected_node)
+    return 0;
+  
+  /* [class.protected]
+
+     When a friend or a member function of a derived class references
+     a protected nonstatic member of a base class, an access check
+     applies in addition to those described earlier in clause
+     _class.access_.4) Except when forming a pointer to member
+     (_expr.unary.op_), the access must be through a pointer to,
+     reference to, or object of the derived class itself (or any class
+     derived from that class) (_expr.ref_).  If the access is to form
+     a pointer to member, the nested-name-specifier shall name the
+     derived class (or any class derived from that class).  */
+  if (DECL_NONSTATIC_MEMBER_P (decl))
+    {
+      /* We can tell through what the reference is occurring by
+        chasing BINFO up to the root.  */
+      tree t = binfo;
+      while (BINFO_INHERITANCE_CHAIN (t))
+       t = BINFO_INHERITANCE_CHAIN (t);
+      
+      if (!DERIVED_FROM_P (derived, BINFO_TYPE (t)))
+       return 0;
+    }
+
+  return 1;
+}
+
+/* Returns non-zero if SCOPE is a friend of a type which would be able
+   to acces DECL, named in TYPE, through the object indicated by
+   BINFO.  */
+
+static int
+friend_accessible_p (scope, type, decl, binfo)
+     tree scope;
+     tree type;
+     tree decl;
+     tree binfo;
+{
+  tree befriending_classes;
+  tree t;
+
+  if (!scope)
+    return 0;
+
+  if (TREE_CODE (scope) == FUNCTION_DECL
+      || DECL_FUNCTION_TEMPLATE_P (scope))
+    befriending_classes = DECL_BEFRIENDING_CLASSES (scope);
+  else if (TYPE_P (scope))
+    befriending_classes = CLASSTYPE_BEFRIENDING_CLASSES (scope);
+  else
+    return 0;
+
+  for (t = befriending_classes; t; t = TREE_CHAIN (t))
+    if (protected_accessible_p (type, decl, TREE_VALUE (t), binfo))
+      return 1;
+
+  if (TREE_CODE (scope) == FUNCTION_DECL
+      || DECL_FUNCTION_TEMPLATE_P (scope))
+    {
+      /* Perhaps this SCOPE is a member of a class which is a 
+        friend.  */ 
+      if (friend_accessible_p (DECL_CLASS_CONTEXT (scope), type,
+                              decl, binfo))
+       return 1;
+
+      /* Or an instantiation of something which is a friend.  */
+      if (DECL_TEMPLATE_INFO (scope))
+       return friend_accessible_p (DECL_TI_TEMPLATE (scope),
+                                   type, decl, binfo);
+    }
+  else if (CLASSTYPE_TEMPLATE_INFO (scope))
+    return friend_accessible_p (CLASSTYPE_TI_TEMPLATE (scope),
+                               type, decl, binfo);
+
+  return 0;
+}
+   
 /* DECL is a declaration from a base class of TYPE, which was the
    classs used to name DECL.  Return non-zero if, in the current
    context, DECL is accessible.  If TYPE is actually a BINFO node,
@@ -858,7 +970,6 @@ accessible_p (type, decl)
      tree decl;
      
 {
-  tree scope;
   tree binfo;
   tree t;
 
@@ -909,48 +1020,16 @@ accessible_p (type, decl)
   /* Figure out where the reference is occurring.  Check to see if
      DECL is private or protected in this scope, since that will
      determine whether protected access in TYPE allowed.  */
-  if (current_class_type
-      && DERIVED_FROM_P (type, current_class_type))
-    {
-      tree access = access_in_type (current_class_type, decl);
-      if (same_type_p (current_class_type, type)
-         && access == access_private_node)
-       protected_ok = 1;
-      else if (access && (access == access_private_node
-                         || access == access_protected_node))
-       protected_ok = 1;
-    }
+  if (current_class_type)
+    protected_ok 
+      = protected_accessible_p (type, decl, current_class_type,
+                               binfo);
 
-  /* Now, loop through the classes of which SCOPE is a friend.  */
-  if (!protected_ok && scope)
-    {
-      /* FIXME: Implement this.  Right now, we have no way of knowing
-               which classes befriend a particular function or class.  */
-    }
-
-  /* [class.protected]
+  /* Now, loop through the classes of which we are a friend.  */
+  if (!protected_ok)
+    protected_ok = friend_accessible_p (current_scope (),
+                                       type, decl, binfo);
 
-     When a friend or a member function of a derived class references
-     a protected nonstatic member of a base class, an access check
-     applies in addition to those described earlier in clause
-     _class.access_.4) Except when forming a pointer to member
-     (_expr.unary.op_), the access must be through a pointer to,
-     reference to, or object of the derived class itself (or any class
-     derived from that class) (_expr.ref_).  If the access is to form
-     a pointer to member, the nested-name-specifier shall name the
-     derived class (or any class derived from that class).  */
-  if (protected_ok && DECL_NONSTATIC_MEMBER_P (decl))
-    {
-      /* We can tell through what the reference is occurring by
-        chasing BINFO up to the root.  */
-      t = binfo;
-      while (BINFO_INHERITANCE_CHAIN (t))
-       t = BINFO_INHERITANCE_CHAIN (t);
-      
-      if (!DERIVED_FROM_P (current_class_type, BINFO_TYPE (t)))
-       protected_ok = 0;
-    }
-  
   /* Standardize on the same that will access_in_type will use.  We
      don't need to know what path was chosen from this point onwards.  */ 
   binfo = TYPE_BINFO (type);
index ef90607eaebc355041352a4bd8b9ebad7cbaac47..76fcebe1fae8fca848deee650e130ae4ac2ec028 100644 (file)
@@ -9,21 +9,77 @@
 // From: Alexandre Oliva <oliva@dcc.unicamp.br>
 // Date: 06 Mar 1998 01:43:18 -0300
 
+template <int*>
+class X {};
+
+template <typename T>
+void g();
+
+struct S;
+
+template <typename T>
+struct R;
 
 class B {
 protected:
   int i; // ERROR - in this context
-  static int j; // gets bogus error - XFAIL *-*-*
+  static int j;
 };
 
 class D : public B {
-    friend void f();
+  friend void f();
+  template <typename T>
+  friend void g();
+  friend struct S;
+  template <typename T>
+  friend struct R;
+};
+
+struct S {
+  void h();
+  X<&B::j> x;
+};
+
+template <typename T>
+struct R {
+  void h();
+  X<&B::j> x;
 };
 
 void f()
 {
     ((B*)0)->i = 3; // ERROR - protected
     ((D*)0)->i = 4;
-    B::j = 5;                  // gets bogus error - XFAIL *-*-*
+    B::j = 5;
     D::j = 6;
 }
+
+template <typename T>
+void g()
+{
+    ((B*)0)->i = 3; // ERROR - protected
+    ((D*)0)->i = 4;
+    B::j = 5;
+    D::j = 6;
+}
+
+template void g<int>();
+
+void S::h()
+{
+  ((B*)0)->i = 3; // ERROR - protected
+  ((D*)0)->i = 4;
+  B::j = 5;
+  D::j = 6;
+}
+
+template <typename T>
+void R<T>::h() 
+{
+  ((B*)0)->i = 3; // ERROR - protected
+  ((D*)0)->i = 4;
+  B::j = 5;
+  D::j = 6;
+}
+
+template struct R<double>;