aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>1999-03-24 01:10:13 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1999-03-24 01:10:13 +0000
commit6a629cac2b8bc32566f6990f649ced12cbba5ff4 (patch)
treeafe04b327c1dd8e574626fedc7a32975682b1f90 /gcc
parent7ad3a049d39ae396220cbd7350ee753054d22afb (diff)
downloadgcc-6a629cac2b8bc32566f6990f649ced12cbba5ff4.zip
gcc-6a629cac2b8bc32566f6990f649ced12cbba5ff4.tar.gz
gcc-6a629cac2b8bc32566f6990f649ced12cbba5ff4.tar.bz2
cp-tree.h (lang_type): Remove has_assignment and has_real_assignment.
* 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog30
-rw-r--r--gcc/cp/class.c1
-rw-r--r--gcc/cp/cp-tree.h42
-rw-r--r--gcc/cp/decl.c10
-rw-r--r--gcc/cp/friend.c42
-rw-r--r--gcc/cp/pt.c3
-rw-r--r--gcc/cp/ptree.c2
-rw-r--r--gcc/cp/search.c161
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/friend1.C62
9 files changed, 260 insertions, 93 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3bac892..d0f66bc 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 6d8a4d6..07f8f97 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 59f3e30..307df1d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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)
+
+/* 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)
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e7272ff..64c8a65 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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])
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 30b3c51..2a69acd 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -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));
}
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index aa8c9e9..f7372dd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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:
diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c
index 4fb0413..2cff655 100644
--- a/gcc/cp/ptree.c
+++ b/gcc/cp/ptree.c
@@ -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))
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 0218b56..a5301be 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -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);
diff --git a/gcc/testsuite/g++.old-deja/g++.other/friend1.C b/gcc/testsuite/g++.old-deja/g++.other/friend1.C
index ef90607..76fcebe 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/friend1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/friend1.C
@@ -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>;