current_class_type if not NULL, indicates current scope is a class, and we are within its definition. So first checks if decl is within the derivation tree, and accessible by current class.
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;
if current class is not derived from the type enclosing decl, the type of decl is inaccessible. For example,
class B {
protected:
class A {};
};
class D: public B {
A a;
};
Type A is accessible in D; but if D is not derived from B, A is inaccessible.
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);
After the calibration above, in below, argument binfo must refer to the binfo part of the in-question “derived type”, and remember via its BINFO_TYPE field we can get the in-question type. To find out if derivation exists, the derivation tree is walked through to see there is a node that is exactly the same as 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 }
Note that the traversal is not stopped when finding out a node the same as base, but till throughout the whole tree on the chance of finding out ambiguous derivation.
During the procedure, access of ba_any means do not check access, allow an ambiguous base, prefer a non-virtual base. Here DERIVED_FROM_P uses ba_any for it just want to know if any derivative relation. Otherwise, switch block below will be run, accessible_base_p (it further calls accessible_p to do its job) at line 325 checks if the base is accessible by the derived.
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 }
After ensuring that derived derives from type enclosing decl, it is possible that decl is accessible within current type. This accessibility is verified by 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] gives an example for comment at line 826. Below at line 27, in D2, it can accessible i. So, at line 820, access_in_type (D2, i) will return ak_protected. But D2 and D1 don’t derive from each other, D2 can’t access i in D1’s base B. Statement block beginning at line 837 can filter out this case: if it is i in D1’s B, WHILE loop at line 842 finally will get D1 (because, in later, we will see that binfos of base B in D2 and D1, in fact, are different instances).
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 }
In later paragraphs, we can see that type node of base class must be unique, one type should have only one type node. Besides, the base in derived isn’t the same as the base type itself, the base in derived only stands for part of an object, but the base type describes a complete object. So the base appears in different deriveds should be regarded as different. Thus, the front-end use object (concept) binfo to stand for these bases. Note that the base type has binfo object too, but it also isn’t the same thing as binfos in the deriveds. In section Details of binfo and basetype, there is a description about binfo’s content..
After knowing that, we come to see 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 }
Function dfs_walk_real traverses the derivation tree rooted by binfo (more frequently, binfo is a sub-tree), passing function pointer via its parameters, it can execute pre-order or post-order traversal. Here prefn is NULL, running the post-order one.
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 }
BINFO_BASETYPES at line 1640, indicates if the part specified by binfo has bases. If so, dfs_walk_real will recurse into the bases. If we appoint function pointer qfn, then function referred will be invoked to select the base. Here we use unmarkedp, which finds out the binfo of un-visited bases.
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 }
Routine dfs_access_in_type is used as argument postfn ran in post-order. Normally dfs_walk_real will exit when first matched node is found. However, dfs_access_in_type always returns NULL and forces the full-walk of the tree. So all nodes of the tree will be processed.
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 }
Above at line 658, DECL_DISCRIMINATOR_P is nonzero if decl is a VAR_DECL within a function scope. And DECL_ACCESS field is a tree_list which records the accessibility of decl within enclosing types. For example:
class A {
public:
int a;
};
class B: public A {
protected:
using A::a;
};
Decl of a will has a tree_list of length 2, with first node of pair {B, protected}, and the second {A, public}. And if the type doesn’t define decl, it looks into its bases as explained by following extra class.
class C: public B {};
C is absent in the tree_list of DECL_ACCESS. But its base B is the enclosing type. The accessibility has been found out and recorded it into BINFO_ACCESS(B) when handling B just before. At line 691 base_access indicates the accessiblility to this base, and value of ak_none is 0, ak_public is 1, ak_protected is 2, and ak_privated is 3. Combines it with the accessibility of decl from the base, we can get the final accessibility of decl from this derived.
Then SET_BINFO_ACCESS at line 724 records the result. It sees that every node of the derived tree is set with the accessibility of decl.
627 #define SET_BINFO_ACCESS(NODE, ACCESS) / in search.c
628 ((TREE_PUBLIC (NODE) = ((ACCESS) & 2) != 0), /
629 (TREE_PRIVATE (NODE) = ((ACCESS) & 1) != 0))
Correspondingly BINFO_ACCESS restores the result saved.
622 #define BINFO_ACCESS(NODE) / in search.c
623 ((access_kind) ((TREE_PUBLIC (NODE) << 1) | TREE_PRIVATE (NODE)
At line 752 in access_in_type, dfs_walk(binfo, dfs_unmark, markedp, 0) directly calls dfs_walk_real (binfo, 0, dfs_unmark, markedp, 0). It clears the mark made at line 728 above.
In fact, here what protected_accessible_p does, is to check if the derived tree rooted by current class contains node specified by decl.