如果 protected_accessible_p 返回非 0 值,当前类的派生树包含了 decl ,而且 type 是当前类的一个基类( protected_accessible_p 的 837 行语句块保证),那么可以直接去检查其访问属性,而且 protected 以上即可。否则,如果当前类的派生树不包含 decl ,或者 type 不是当前类的基类,那么需要检查当前作用域是否是可以访问 decl 的友元。函数 friend_accessible_p 的参数 scope (当前作用域)由下面的 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 }
current_class_type 和 current_function_decl 的设置情况如下表给出。
|
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 |
* :包括类的函数友元。 ** : GNU 的扩展,函数内的局部类
这时需要考虑的情况就是:接受当前域(可以是类,或者函数)作为友元的类包含了 decl ,而且 type 是其的一个基类。在函数 friend_accessible_p 中,参数 binfo 来自 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 }
上面的 befriending_classes 就是当前函数或类作为友元的类的列表。如果对于这些类, protected_accessible_p 还是返回 0 ,如果 scope 代表一个类,那么这里的做法是继续逐级检查包含 scope 的类;而如果 scope 代表一个类方法,则继续考察其所在类作为友元的情形。 893 行表示该方法是一个模板函数, DECL_TI_TEMPLATE 是代表其特化或具现的节点。而 904 行表示是一个模板类, CLASSTYPE_TI_TEMPLATE 是代表其特化或具现的节点。这是考察模板的特化类型是否是所期望的友元。
从上面看到,如果 protected_accessible_p 或 friend_accessible_p 返回非 0 值,表明 decl 和 type 都在同一棵派生树里。那么接下来,在 accessible_p 的 1000 行,调用 access_in_type 来考察 type 对 decl 的访问属性。如果结果在 protected 级别以上,毫无疑问, type 可以访问 decl 。但是对于友元来说, private 级别也不是问题。因此,如果结果是 private ,那么还要看一下是否为友元。而且还有更复杂的情况,比如:
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
}
这通过后序遍历 type 的派生树时,执行 dfs_accessible_p 的方法来查找。 BINFO_ACCESS 在 1000 行的 access_in_type 执行时,就被设置好了。如果它是 ak_none ,就表明该类与 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 }
类似的, dfs_accessible_queue_p 返回合适的 binfo 来递归地进入。它以中序遍历派生树。
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 }
这一次,只要找到一个合适的类,就返回。