If protected_accessible_p return nonzero, the derived tree of current class contains decl, and type must be its base (guaranteed by block at line 837 in protected_accessible_p), then it can directly go to check the accessibility from type, and it is OK with level no lower than protected. Otherwise, if the derived tree of current class doesn’t contain decl, or type isn’t its base, then it needs to see if current scope is a friend that can access decl. Parameter scope of friend_accessible_p is gotten by below current_scope.
550 tree
551 current_scope (void) in search.c
552 {
553 if (current_function_decl == NULL_TREE)
554 return current_class_type;
555 if (current_class_type == NULL_TREE)
556 return current_function_decl;
557 if ((DECL_FUNCTION_MEMBER_P (current_function_decl)
558 && same_type_p (DECL_CONTEXT (current_function_decl),
559 current_class_type))
560 || (DECL_FRIEND_CONTEXT (current_function_decl)
561 && same_type_p (DECL_FRIEND_CONTEXT (current_function_decl),
562 current_class_type)))
563 return current_function_decl;
564
565 return current_class_type;
566 }
The setting of current_class_type and current_function_decl is given as following.
|
current_class_type |
current_function_decl |
global |
NULL |
NULL |
function-local |
NULL |
SET |
class-local |
SET |
NULL |
class->function * |
SET |
SET |
function->class ** |
SET |
SET |
*: include class’s friend. **: GNU’s extension, local class within function
Now the case needs be covered is: class accepting current scope (class, or function) as friend contains decl, and type is one of its bases. In friend_accessible_p, parameter binfo comes from type.
855 static int
856 friend_accessible_p (tree scope, tree decl, tree binfo) in search.c
857 {
858 tree befriending_classes;
859 tree t;
860
861 if (!scope)
862 return 0;
863
864 if (TREE_CODE (scope) == FUNCTION_DECL
865 || DECL_FUNCTION_TEMPLATE_P (scope))
866 befriending_classes = DECL_BEFRIENDING_CLASSES (scope);
867 else if (TYPE_P (scope))
868 befriending_classes = CLASSTYPE_BEFRIENDING_CLASSES (scope);
869 else
870 return 0;
871
872 for (t = befriending_classes; t; t = TREE_CHAIN (t))
873 if (protected_accessible_p (decl, TREE_VALUE (t), binfo))
874 return 1;
875
876 /* Nested classes are implicitly friends of their enclosing types, as
877 per core issue 45 (this is a change from the standard). */
878 if (TYPE_P (scope))
879 for (t = TYPE_CONTEXT (scope); t && TYPE_P (t); t = TYPE_CONTEXT (t))
880 if (protected_accessible_p (decl, t, binfo))
881 return 1;
882
883 if (TREE_CODE (scope) == FUNCTION_DECL
884 || DECL_FUNCTION_TEMPLATE_P (scope))
885 {
886 /* Perhaps this SCOPE is a member of a class which is a
887 friend. */
888 if (DECL_CLASS_SCOPE_P (decl)
889 && friend_accessible_p (DECL_CONTEXT (scope), decl, binfo))
890 return 1;
891
892 /* Or an instantiation of something which is a friend. */
893 if (DECL_TEMPLATE_INFO (scope))
894 {
895 int ret;
896 /* Increment processing_template_decl to make sure that
897 dependent_type_p works correctly. */
898 ++processing_template_decl;
899 ret = friend_accessible_p (DECL_TI_TEMPLATE (scope), decl, binfo);
900 --processing_template_decl;
901 return ret;
902 }
903 }
904 else if (CLASSTYPE_TEMPLATE_INFO (scope))
905 {
906 int ret;
907 /* Increment processing_template_decl to make sure that
908 dependent_type_p works correctly. */
909 ++processing_template_decl;
910 ret = friend_accessible_p (CLASSTYPE_TI_TEMPLATE (scope), decl, binfo);
911 --processing_template_decl;
912 return ret;
913 }
914
915 return 0;
916 }
Above befriending_classes is the list of classes acceptting current class or function as friend. If for these classes, protected_accessible_p still returns 0, if scope is a class, then here it checks class containing scope one level up and up; while if scope is a funcction, then checks the case its containing class being a friend. Line 893 indicates a function template, DECL_TI_TEMPLATE is the node for its instantiation or specialization. And line 904 finds a class template, CLASSTYPE_TI_TEMPLATE is the node for its instantiation or specialization. Here checks if the specialization is the expected friend.
From above, if protected_accessible_p or friend_accessible_p returns nonzero, means decl and type are within the same derived tree. Then next, in accessible_p at line 1000, access_in_type is invoked to check the accessibility decl of from type. If it finds the result is above protected, of course type can access decl. But for friend, even private isn’t a problem. So if the result is private, it still needs to see if it is a friend. Further, there is even more complex case, for example:
class B;
class A {
private:
int i;
friend void f(B*);
};
class B : public A { };
void f(B* p) {
p->i = 1; // OK: B* can be implicitly cast to A*, and f has access to i in A
}
It is searched by dfs_accessible_p during traversing the derived tree of type by post-ordered. BINFO_ACCESS has been set at time access_in_type at line 1000 running. If it is ak_none, it means type is unrelated to decl.
778 static tree
779 dfs_accessible_p (tree binfo, void *data ATTRIBUTE_UNUSED) in search.c
780 {
781 access_kind access;
782
783 BINFO_MARKED (binfo) = 1;
784 access = BINFO_ACCESS (binfo);
785 if (access != ak_none
786 && is_friend (BINFO_TYPE (binfo), current_scope ()))
787 return binfo;
788
789 return NULL_TREE;
790 }
Likely, dfs_accessible_queue_p is the function ran in in-order and returns qualified binfo for stepping into.
759 static tree
760 dfs_accessible_queue_p (tree derived, int ix, void *data ATTRIBUTE_UNUSED)
761 {
762 tree binfo = BINFO_BASETYPE (derived, ix);
763
764 if (BINFO_MARKED (binfo))
765 return NULL_TREE;
766
767 /* If this class is inherited via private or protected inheritance,
768 then we can't see it, unless we are a friend of the derived class. */
769 if (BINFO_BASEACCESS (derived, ix) != access_public_node
770 && !is_friend (BINFO_TYPE (derived), current_scope ()))
771 return NULL_TREE;
772
773 return binfo;
774 }
This time, as long as finding out a matched type, it exits the traversal.