The behavor of perform_or_defer_access_check depends on the kind of deferring of the top element of the deferred_access_stack. If the top element is of dk_deferred, then every time invoking the function, arguments binfo and decl will be chained in deferred_access_checks. These checks are cached for further verification invoked by perform_deferred_access_checks, or next invocation of perform_or_defer_access_check.
And note that in last section, in pop_to_parent_deferring_access_checks, at time invokes this function, the top node of deferred_access_checks is temperarily removed, and it is controlled by the second node, which usually stands for the containing scope.
273 void
274 perform_or_defer_access_check (tree binfo, tree decl) in semantics.c
275 {
276 tree check;
277
278 my_friendly_assert (TREE_CODE (binfo) == TREE_VEC, 20030623);
279
280 /* If we are not supposed to defer access checks, just check now. */
281 if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
282 {
283 enforce_access (binfo, decl);
284 return;
285 }
286 /* Exit if we are in a context that no access checking is performed. */
287 else if (deferred_access_stack->deferring_access_checks_kind == dk_no_check)
288 return;
289
290 /* See if we are already going to perform this check. */
291 for (check = deferred_access_stack->deferred_access_checks;
292 check;
293 check = TREE_CHAIN (check))
294 if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
295 return;
296 /* If not, record the check. */
297 deferred_access_stack->deferred_access_checks
298 = tree_cons (binfo, decl,
299 deferred_access_stack->deferred_access_checks);
300 }
If the access checking needn’t to be deferred, the checking upon access to decl in scope specified by binfo is performed immediately. Also routine perform_deferred_access_checks will perform accessing checking for all deferred access checkings.
258 void
259 perform_deferred_access_checks (void) in semantics.c
260 {
261 tree deferred_check;
262 for (deferred_check = deferred_access_stack->deferred_access_checks;
263 deferred_check;
264 deferred_check = TREE_CHAIN (deferred_check))
265 /* Check access. */
266 enforce_access (TREE_PURPOSE (deferred_check),
267 TREE_VALUE (deferred_check));
268 }
See both routines depend on enforce_access to do the accessing checking.
3864 bool
3865 enforce_access (tree basetype_path, tree decl) in call.c
3866 {
3867 my_friendly_assert (TREE_CODE (basetype_path) == TREE_VEC, 20030624);
3868
3869 if (!accessible_p (basetype_path, decl))
3870 {
3871 if (TREE_PRIVATE (decl))
3872 cp_error_at ("`%+#D' is private", decl);
3873 else if (TREE_PROTECTED (decl))
3874 cp_error_at ("`%+#D' is protected", decl);
3875 else
3876 cp_error_at ("`%+#D' is inaccessible", decl);
3877 error ("within this context");
3878 return false;
3879 }
3880
3881 return true;
3882 }
Here in accessible_p, argument decl is a declaration from a base class of type, which was the class used to name decl. For example:
class A {
int a;
} cA;
cA.a = 5;
When doing accessing check, A will be type and a will be decl.
924 int
925 accessible_p (tree type, tree decl) in search.c
926 {
927 tree binfo;
928 tree t;
929 tree scope;
930 access_kind access;
931
932 /* Nonzero if it's OK to access DECL if it has protected
933 accessibility in TYPE. */
934 int protected_ok = 0;
935
936 /* If this declaration is in a block or namespace scope, there's no
937 access control. */
938 if (!TYPE_P (context_for_name_lookup (decl)))
939 return 1;
940
941 /* There is no need to perform access checks inside a thunk. */
942 scope = current_scope ();
943 if (scope && DECL_THUNK_P (scope))
944 return 1;
945
946 /* In a template declaration, we cannot be sure whether the
947 particular specialization that is instantiated will be a friend
948 or not. Therefore, all access checks are deferred until
949 instantiation. However, PROCESSING_TEMPLATE_DECL is set in the
950 parameter list for a template (because we may see dependent types
951 in default arguments for template parameters), and access
952 checking should be performed in the outermost parameter list. */
953 if (processing_template_decl
954 && (!processing_template_parmlist || processing_template_decl > 1))
955 return 1;
956
957 if (!TYPE_P (type))
958 {
959 binfo = type;
960 type = BINFO_TYPE (type);
961 }
962 else
963 binfo = TYPE_BINFO (type);
It first ensures that decl isn’t within a block (FOR block or WHILE block etc.) or namespace for which cases no access control applied. Routine context_for_name_lookup returns the binding scope within which decl will be looked up first. ANON_AGGR_TYPE_P at line 611 indicates within an anonymous union or struct type (which is prohibited by ISO C++), accoring to [3], “The names of the members of an anonymous union shall be distinct from the names of any other entity in the scope in which the anonymous union is declared. For the purpose of name lookup, after the anonymous union definition, the members of the anonymous union are considered to have been defined in the scope in which the anonymous union is declared.” So it needs go up one level.
600 tree
601 context_for_name_lookup (tree decl) in search.c
602 {
603 /* [class.union]
604
605 For the purposes of name lookup, after the anonymous union
606 definition, the members of the anonymous union are considered to
607 have been defined in the scope in which the anonymous union is
608 declared. */
609 tree context = DECL_CONTEXT (decl);
610
611 while (context && TYPE_P (context) && ANON_AGGR_TYPE_P (context))
612 context = TYPE_CONTEXT (context);
613 if (!context)
614 context = global_namespace;
615
616 return context;
617 }
Also skip access checking if we are within template declaration (not instantiation). At invoking accessible_p, argument type may be node of *_TYPE or binfo, so if decl is within a context enforces access checking, set type and binfo with correct content.
accessibe_p (continue)
965 /* [class.access.base]
966
967 A member m is accessible when named in class N if
968
969 --m as a member of N is public, or
970
971 --m as a member of N is private, and the reference occurs in a
972 member or friend of class N, or
973
974 --m as a member of N is protected, and the reference occurs in a
975 member or friend of class N, or in a member or friend of a
976 class P derived from N, where m as a member of P is private or
977 protected, or
978
979 --there exists a base class B of N that is accessible at the point
980 of reference, and m is accessible when named in class B.
981
982 We walk the base class hierarchy, checking these conditions. */
983
984 /* Figure out where the reference is occurring. Check to see if
985 DECL is private or protected in this scope, since that will
986 determine whether protected access is allowed. */
987 if (current_class_type)
988 protected_ok = protected_accessible_p (decl, current_class_type, binfo);
989
990 /* Now, loop through the classes of which we are a friend. */
991 if (!protected_ok)
992 protected_ok = friend_accessible_p (scope, decl, binfo);
993
994 /* Standardize the binfo that access_in_type will use. We don't
995 need to know what path was chosen from this point onwards. */
996 binfo = TYPE_BINFO (type);
997
998 /* Compute the accessibility of DECL in the class hierarchy
999 dominated by type. */
1000 access = access_in_type (type, decl);
1001 if (access == ak_public
1002 || (access == ak_protected && protected_ok))
1003 return 1;
1004 else
1005 {
1006 /* Walk the hierarchy again, looking for a base class that allows
1007 access. */
1008 t = dfs_walk (binfo, dfs_accessible_p, dfs_accessible_queue_p, 0);
1009 /* Clear any mark bits. Note that we have to walk the whole tree
1010 here, since we have aborted the previous walk from some point
1011 deep in the tree. */
1012 dfs_walk (binfo, dfs_unmark, 0, 0);
1013
1014 return t != NULL_TREE;
1015 }
1016 }
Above comments explain cases of accessible. For the forth case, for better understanding, we give an example in below:
class base {
public:
int i;
};
class D: public base {
private:
using base::i;
};
int main () {
D d;
d.i = 4; // error: ‘nt base::i’ inaccessible
base *pb = &d;
pb->i = 5; // OK
return 1;
}
Now it checks one by one.