如果 current_class_type 不是 NULL ,表明当前的作用域是一个类,而且我们正在这个类定义中。首先检查 decl 是否在这棵派生树里,并且为当前类节点可访问。
795 static int
796 protected_accessible_p (tree decl, tree derived, tree binfo) in search.c
797 {
798 access_kind access;
799
800 /* We're checking this clause from [class.access.base]
801
802 m as a member of N is protected, and the reference occurs in a
803 member or friend of class N, or in a member or friend of a
804 class P derived from N, where m as a member of P is private or
805 protected.
806
807 Here DERIVED is a possible P and DECL is m. accessible_p will
808 iterate over various values of N, but the access to m in DERIVED
809 does not change.
810
811 Note that I believe that the passage above is wrong, and should read
812 "...is private or protected or public"; otherwise you get bizarre results
813 whereby a public using-decl can prevent you from accessing a protected
814 member of a base. (jason 2000/02/28) */
815
816 /* If DERIVED isn't derived from m's class, then it can't be a P. */
817 if (!DERIVED_FROM_P (context_for_name_lookup (decl), derived))
818 return 0;
如果当前类不是从包含 decl 的类所派生, decl 的类型是不可访问的。例如:
class B {
protected :
class A {};
};
class D: public B {
A a;
};
类型 A 从 D 可访问,但是如果 D 不是从 B 派生的话, A 是不可访问的。
997 #define DERIVED_FROM_P (PARENT, TYPE) / in cp-tree.h
998 (lookup_base ((TYPE), (PARENT), ba_any, NULL) != NULL_TREE)
271 tree
272 lookup_base (tree t, tree base, base_access access, base_kind *kind_ptr) in search.c
273 {
274 tree binfo = NULL; /* The binfo we've found so far. */
275 tree t_binfo = NULL;
276 base_kind bk;
277
278 if (t == error_mark_node || base == error_mark_node)
279 {
280 if (kind_ptr)
281 *kind_ptr = bk_not_base;
282 return error_mark_node;
283 }
284 my_friendly_assert (TYPE_P (base), 20011127);
285
286 if (!TYPE_P (t))
287 {
288 t_binfo = t;
289 t = BINFO_TYPE (t);
290 }
291 else
292 t_binfo = TYPE_BINFO (t);
293
294 /* Ensure that the types are instantiated. */
295 t = complete_type (TYPE_MAIN_VARIANT (t));
296 base = complete_type (TYPE_MAIN_VARIANT (base));
297
298 bk = lookup_base_r (t_binfo, base, access, 0, &binfo);
在上面的调整后 , 在下面 , 参数 binfo 必须引用所考查的 “ 派生类 ” 的 binfo 部分 , 并且回忆通过其 BINFO_TYPE 域 , 我们可以获得这个考查的类。为了找出是否存在派生类,遍历派生树来查看,其中是否有节点正好就是 base 。
156 static base_kind
157 lookup_base_r (tree binfo, tree base, base_access access, in search.c
158 bool is_virtual, /* inside a virtual part */
159 tree *binfo_ptr)
160 {
161 int i;
162 tree bases, accesses;
163 base_kind found = bk_not_base;
164
165 if (same_type_p (BINFO_TYPE (binfo), base))
166 {
167 /* We have found a base. Check against what we have found
168 already. */
169 found = bk_same_type;
170 if (is_virtual)
171 found = bk_via_virtual;
172
173 if (!*binfo_ptr)
174 *binfo_ptr = binfo;
175 else if (binfo != *binfo_ptr)
176 {
177 if (access != ba_any)
178 *binfo_ptr = NULL;
179 else if (!is_virtual)
180 /* Prefer a non-virtual base. */
181 *binfo_ptr = binfo;
182 found = bk_ambig;
183 }
184
185 return found;
186 }
187
188 bases = BINFO_BASETYPES (binfo);
189 accesses = BINFO_BASEACCESSES (binfo);
190 if (!bases)
191 return bk_not_base;
192
193 for (i = TREE_VEC_LENGTH (bases); i--;)
194 {
195 tree base_binfo = TREE_VEC_ELT (bases, i);
196 base_kind bk;
197
198 bk = lookup_base_r (base_binfo, base,
199 access,
200 is_virtual || TREE_VIA_VIRTUAL (base_binfo),
201 binfo_ptr);
202
203 switch (bk)
204 {
205 case bk_ambig:
206 if (access != ba_any)
207 return bk;
208 found = bk;
209 break ;
210
211 case bk_same_type:
212 bk = bk_proper_base;
213 /* FALLTHROUGH */
214 case bk_proper_base:
215 my_friendly_assert (found == bk_not_base, 20010723);
216 found = bk;
217 break ;
218
219 case bk_via_virtual:
220 if (found != bk_ambig)
221 found = bk;
222 break ;
223
224 case bk_not_base:
225 break ;
226
227 default :
228 abort ();
229 }
230 }
231 return found;
232 }
注意出于查找二义派生( ambiguous derivation )的目的,当找到与 base 相同的节点时,这个遍历并不停止,而是完整地遍历该派生树。
在这个过程中, access 的值 ba_any 表示不要进行访问检查,允许二义的基类,非虚拟基类优先。这里 DERIVED_FROM_P 使用 ba_any ,因为它只想知道是否存在派生关系。不然的话,下面 switch 语句块就会被运行,在 325 行的 accessible_base_p (它进一步调用 accessible_p 来完成其工作)用于检查在派生类中,该基类是否可访问。
lookup_base (continue)
300 /* Check that the base is unambiguous and accessible. */
301 if (access != ba_any)
302 switch (bk)
303 {
304 case bk_not_base:
305 break ;
306
307 case bk_ambig:
308 binfo = NULL_TREE;
309 if (!(access & ba_quiet))
310 {
311 error ("`%T' is an ambiguous base of `%T'", base, t);
312 binfo = error_mark_node;
313 }
314 break ;
315
316 default :
317 if ((access & ~ba_quiet) != ba_ignore
318 /* If BASE is incomplete, then BASE and TYPE are probably
319 the same, in which case BASE is accessible. If they
320 are not the same, then TYPE is invalid. In that case,
321 there's no need to issue another error here, and
322 there's no implicit typedef to use in the code that
323 follows, so we skip the check. */
324 && COMPLETE_TYPE_P (base)
325 && !accessible_base_p (t, base))
326 {
327 if (!(access & ba_quiet))
328 {
329 error ("`%T' is an inaccessible base of `%T'", base, t);
330 binfo = error_mark_node;
331 }
332 else
333 binfo = NULL_TREE;
334 bk = bk_inaccessible;
335 }
336 break ;
337 }
338
339 if (kind_ptr)
340 *kind_ptr = bk;
341
342 return binfo;
343 }
在确认了 derived 从包含 decl 的类派生,那么就有可能从当前类可以访问 decl 。这个可能性由 access_in_type 来验证。
protected_accessible_p (continue)
820 access = access_in_type (derived, decl);
821
822 /* If m is inaccessible in DERIVED, then it's not a P. */
823 if (access == ak_none)
824 return 0;
825
826 /* [class.protected]
827
828 When a friend or a member function of a derived class references
829 a protected nonstatic member of a base class, an access check
830 applies in addition to those described earlier in clause
831 _class.access_) Except when forming a pointer to member
832 (_expr.unary.op_), the access must be through a pointer to,
833 reference to, or object of the derived class itself (or any class
834 derived from that class) (_expr.ref_). If the access is to form
835 a pointer to member, the nested-name-specifier shall name the
836 derived class (or any class derived from that class). */
837 if (DECL_NONSTATIC_MEMBER_P (decl))
838 {
839 /* We can tell through what the reference is occurring by
840 chasing BINFO up to the root. */
841 tree t = binfo;
842 while ( BINFO_INHERITANCE_CHAIN (t))
843 t = BINFO_INHERITANCE_CHAIN (t);
844
845 if (!DERIVED_FROM_P (derived, BINFO_TYPE (t)))
846 return 0;
847 }
848
849 return 1;
850 }
【 3 】给出了一个对应 826 行注释的例子。在下面的 27 行,在 D2 类里是可以访问 i 的。因此, 820 行 access_in_type (D2, i) 将返回 ak_protected ,但是 D2 , D1 没有派生关系, D2 不能访问 D1 基类 B 中的 i 。 837 行开始的语句块,能筛查这样的情况:如果是 D1 的 B 中的 i , 842 行的 WHILE 循环最终找到的是 D1 (在后面,我们可以看到 D2 和 D1 中的基类 B 的 binfo ,实际上是不同的实例)。
1 class B {
2 protected :
3 int i;
4 static int j;
5 };
6
7 class D1 : public B {};
8
9 class D2 : public B {
10 friend void fr(B*,D1*,D2*);
11 void mem(B*,D1*);
12 };
13
14 void fr(B* pb, D1* p1, D2* p2) {
15 pb->i = 1; // ill-formed
16 p1->i = 2; // ill-formed
17 p2->i = 3; // OK (access through a D2)
18 p2->B::i = 4; // OK (access through a D2, even though naming class is B)
19 int B::* pmi_B = &B::i; // ill-formed
20 int B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*)
21 B::j = 5; // OK (because refers to static member)
22 D2::j =6; // OK (because refers to static member)
23 }
24
25 void D2::mem(B* pb, D1* p1){
26 pb->i = 1; // ill-formed
27 p1->i = 2; // ill-formed
28 i = 3; // OK (access through this)
29 B::i = 4; // OK (access through this, qualification ignored)
30 int B::* pmi_B = &B::i; // ill-formed
31 int B::* pmi_B2 = &D2::i; // OK
32 j = 5; // OK (because j refers to static member)
33 B::j = 6; // OK (because B::j refers to static member)
34 }
35
36 void g(B* pb, D1* p1, D2* p2) {
37 pb->i = 1; // ill-formed
38 p1->i = 2; // ill-formed
30 p2->i = 3; // ill-formed
40 }
在后面的章节中,我们将会看到,首先,基类的类型节点必须是唯一的,一个类型只能有一个类型节点;另外,派生类中的基类不完全等同于基类类型本身,派生类中的基类只表示对象的一部分,基类的类型表示一个完整的对象。所以,出现在不同派生类中同一个基类,是各各不相同的。因此,前端使用了 binfo 这个对象(概念)来代表这些基类。注意,基类本身也有 binfo 对象,它和派生类中该基类的 binfo 对象不是一回事。在 Binfo及 basetype的细节 一节,有关于 binfo 内容的描述。
了解了这些之后,我们来看 access_in_type 函数。
735 static access_kind
736 access_in_type (tree type, tree decl) in search.c
737 {
738 tree binfo = TYPE_BINFO (type);
739
740 /* We must take into account
741
742 [class.paths]
743
744 If a name can be reached by several paths through a multiple
745 inheritance graph, the access is that of the path that gives
746 most access.
747
748 The algorithm we use is to make a post-order depth-first traversal
749 of the base-class hierarchy. As we come up the tree, we annotate
750 each node with the most lenient access. */
751 dfs_walk_real (binfo, 0, dfs_access_in_type , unmarkedp , decl);
752 dfs_walk (binfo, dfs_unmark, markedp, 0);
753
754 return BINFO_ACCESS (binfo);
755 }
函数 dfs_walk_real 遍历以 binfo 为根节点的派生树(更多时候 binfo 只是一棵子树),向它不同的参数传入函数指针,就能分别执行前序或者后序遍历。这里的参数 prefn 是 NULL ,我们执行后序遍历。
1682 tree
1683 dfs_walk_real (tree binfo, in search.c
1684 tree (*prefn) (tree, void *),
1685 tree (*postfn) (tree, void *),
1686 tree (*qfn) (tree, int, void *),
1687 void *data)
1688 {
1689 tree rval = NULL_TREE;
1630
1631 /* Call the pre-order walking function. */
1632 if (prefn)
1633 {
1634 rval = (*prefn) (binfo, data);
1635 if (rval)
1636 return rval;
1637 }
1638
1639 /* Process the basetypes. */
1640 if (BINFO_BASETYPES (binfo))
1641 {
1642 int i, n = TREE_VEC_LENGTH (BINFO_BASETYPES (binfo));
1643 for (i = 0; i != n; i++)
1644 {
1645 tree base_binfo;
1646
1647 if (qfn)
1648 base_binfo = (*qfn) (binfo, i, data);
1649 else
1650 base_binfo = BINFO_BASETYPE (binfo, i);
1651
1652 if (base_binfo)
1653 {
1654 rval = dfs_walk_real (base_binfo, prefn, postfn, qfn, data);
1655 if (rval)
1656 return rval;
1657 }
1658 }
1659 }
1660
1661 /* Call the post-order walking function. */
1662 if (postfn)
1663 rval = (*postfn) (binfo, data);
1664
1665 return rval;
1666 }
1640 行的 BINFO_BASETYPES 指出 binfo 所对应的部分是否具有基类,在具有基类的情况下, dfs_walk_real 将递归进入基类。如果我们给定了函数指针 qfn ,那么就由 qfn 指向的函数来选择基类。这里,我们给出的是 unmarkedp ,它找出没有访问过的基类的 binfo 。
2012 tree
2013 unmarkedp (tree derived, int ix, void *data ATTRIBUTE_UNUSED) in search.c
2014 {
2015 tree binfo = BINFO_BASETYPE (derived, ix);
2016
2017 return !BINFO_MARKED (binfo) ? binfo : NULL_TREE;
2018 }
函数 dfs_access_in_type 被用作以后序运行的参数 postfn 。通常,在第一个匹配的节点被找到后, dfs_walk_real 就会退出。不过, dfs_access_in_type 总是返回 NULL ,迫使遍历完整棵树。因此,整棵树的节点都会得到处理。
634 static tree
635 dfs_access_in_type (tree binfo, void *data) in search.c
636 {
637 tree decl = (tree) data;
638 tree type = BINFO_TYPE (binfo);
639 access_kind access = ak_none;
640
641 if (context_for_name_lookup (decl) == type)
642 {
643 /* If we have descended to the scope of DECL, just note the
644 appropriate access. */
645 if (TREE_PRIVATE (decl))
646 access = ak_private;
647 else if (TREE_PROTECTED (decl))
648 access = ak_protected;
649 else
650 access = ak_public;
651 }
652 else
653 {
654 /* First, check for an access-declaration that gives us more
655 access to the DECL. The CONST_DECL for an enumeration
656 constant will not have DECL_LANG_SPECIFIC, and thus no
657 DECL_ACCESS. */
658 if (DECL_LANG_SPECIFIC (decl) && !DECL_DISCRIMINATOR_P (decl))
659 {
660 tree decl_access = purpose_member (type, DECL_ACCESS (decl));
661
662 if (decl_access)
663 {
664 decl_access = TREE_VALUE (decl_access);
665
666 if (decl_access == access_public_node)
667 access = ak_public;
668 else if (decl_access == access_protected_node)
669 access = ak_protected;
670 else if (decl_access == access_private_node)
671 access = ak_private;
672 else
673 my_friendly_assert (false, 20030217);
674 }
675 }
676
677 if (!access)
678 {
679 int i;
680 int n_baselinks;
681 tree binfos, accesses;
682
683 /* Otherwise, scan our baseclasses, and pick the most favorable
684 access. */
685 binfos = BINFO_BASETYPES (binfo);
686 accesses = BINFO_BASEACCESSES (binfo);
687 n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
688 for (i = 0; i < n_baselinks; ++i)
689 {
690 tree base_binfo = TREE_VEC_ELT (binfos, i);
691 tree base_access = TREE_VEC_ELT (accesses, i);
692 access_kind base_access_now = BINFO_ACCESS (base_binfo);
693
694 if (base_access_now == ak_none || base_access_now == ak_private)
695 /* If it was not accessible in the base, or only
696 accessible as a private member, we can't access it
697 all. */
698 base_access_now = ak_none;
699 else if (base_access == access_protected_node)
700 /* Public and protected members in the base become
701 protected here. */
702 base_access_now = ak_protected;
703 else if (base_access == access_private_node)
704 /* Public and protected members in the base become
705 private here. */
706 base_access_now = ak_private;
707
708 /* See if the new access, via this base, gives more
709 access than our previous best access. */
710 if (base_access_now != ak_none
711 && (access == ak_none || base_access_now < access))
712 {
713 access = base_access_now;
714
715 /* If the new access is public, we can't do better. */
716 if (access == ak_public)
717 break ;
718 }
719 }
720 }
721 }
722
723 /* Note the access to DECL in TYPE. */
724 SET_BINFO_ACCESS (binfo, access);
725
726 /* Mark TYPE as visited so that if we reach it again we do not
727 duplicate our efforts here. */
728 BINFO_MARKED (binfo) = 1;
729
730 return NULL_TREE;
731 }
上面的 658 行,如果 decl 是一个在函数域中的 VAR_DECL , DECL_DISCRIMINATOR_P 为非 0 值。而域 DECL_ACCESS 是一个 tree_list ,它记录了 decl 在包含 decl 的所有类型中的访问类型。例如:
class A {
public :
int a;
};
class B: public A {
protected :
using A::a;
};
A 的 decl 将具有一个长度为 2 的 tree_list ,其第一个节点是数据对 {B , protected} ,第二个节点是 {A , public} 。如果类型没有定义 decl ,那么查看其基类,如下面的例子所示。
class C: public B {};
C 不出现在 DECL_ACCESS 这个 tree_list 里。但其基类 B 正是包含类。之前在处理 B 的时候,访问属性已经被找出,并保存入 BINFO_ACCESS(B) 。在 691 行, base_access 表示到该基类的访问属性,对于其取值, ak_none 的值是 0 , ak_public 是 1 , ak_protected 是 2 ,而 ak_privated 则是 3 。把这个属性和基类对 decl 的访问属性综合起来,%E