Studying note of GCC-3.4.6 source (83)

5.9.2. Access control

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.

 

 

你可能感兴趣的:(tree,Class,processing,Access,hierarchy,reference)