void add_friend (tree type, tree decl, bool complain) { tree typedecl; tree list; tree name; tree ctx; if (decl == error_mark_node) return; typedecl = TYPE_MAIN_DECL (type); list = DECL_FRIENDLIST (typedecl); name = DECL_NAME (decl); type = TREE_TYPE (typedecl); while (list) { if (name == FRIEND_NAME (list)) { tree friends = FRIEND_DECLS (list); for (; friends ; friends = TREE_CHAIN (friends)) { if (decl == TREE_VALUE (friends)) { if (complain) warning (OPT_Wredundant_decls, "%qD is already a friend of class %qT", decl, type); return; } } maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1); TREE_VALUE (list) = tree_cons (NULL_TREE, decl, TREE_VALUE (list)); return; } list = TREE_CHAIN (list); } ctx = DECL_CONTEXT (decl); if (ctx && CLASS_TYPE_P (ctx) && !uses_template_parms (ctx)) perform_or_defer_access_check (TYPE_BINFO (ctx), decl, decl, tf_warning_or_error); maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1); DECL_FRIENDLIST (typedecl) = tree_cons (DECL_NAME (decl), build_tree_list (NULL_TREE, decl), DECL_FRIENDLIST (typedecl)); if (!uses_template_parms (type)) DECL_BEFRIENDING_CLASSES (decl) = tree_cons (NULL_TREE, type, DECL_BEFRIENDING_CLASSES (decl)); }
int is_friend (tree type, tree supplicant) { int declp; tree list; tree context; if (supplicant == NULL_TREE || type == NULL_TREE) return 0; declp = DECL_P (supplicant); if (declp) /* It's a function decl. */ { tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); tree name = DECL_NAME (supplicant); for (; list ; list = TREE_CHAIN (list)) { if (name == FRIEND_NAME (list)) { tree friends = FRIEND_DECLS (list); for (; friends ; friends = TREE_CHAIN (friends)) { tree this_friend = TREE_VALUE (friends); if (this_friend == NULL_TREE) continue; if (supplicant == this_friend) return 1; if (is_specialization_of_friend (supplicant, this_friend)) return 1; } break; } } } else /* It's a type. */ { if (same_type_p (supplicant, type)) return 1; list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type))); for (; list ; list = TREE_CHAIN (list)) { tree t = TREE_VALUE (list); if (TREE_CODE (t) == TEMPLATE_DECL ? is_specialization_of_friend (TYPE_MAIN_DECL (supplicant), t) : same_type_p (supplicant, t)) return 1; } } if (declp) { if (DECL_FUNCTION_MEMBER_P (supplicant)) context = DECL_CONTEXT (supplicant); else context = NULL_TREE; } else { if (TYPE_CLASS_SCOPE_P (supplicant)) /* Nested classes get the same access as their enclosing types, as per DR 45 (this is a change from the standard). */ context = TYPE_CONTEXT (supplicant); else /* Local classes have the same access as the enclosing function. */ context = decl_function_context (TYPE_MAIN_DECL (supplicant)); } /* A namespace is not friend to anybody. */ if (context && TREE_CODE (context) == NAMESPACE_DECL) context = NULL_TREE; if (context) return is_friend (type, context); return 0; }