GCC-3.4.6源代码学习笔记(83)

5.9.2. 访问控制

函数perform_or_defer_access_check的行为取决于deferred_access_stack栈顶成员的延迟类型。如果栈顶成员是类型dk_deferred,那么对该函数的每次调用,实参binfodecl将被链入deferred_access_checks。这些检查被缓存起来,由后来的perform_deferred_access_checks或者perform_or_defer_access_check的另一次调用,来执行验证。

注意到在上一节,在pop_to_parent_deferring_access_checks中,在调用下面这个函数的时候,deferred_access_checks的栈顶节点暂时被移走了,它由第二个节点来控制,这个节点通常代表上一级的作用域。

 

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  }

 

如果访问检查不需要被推迟,那么对由binfo指定的作用域中的decl的访问,立即执行访问检查。同样函数perform_deferred_access_checks也可执行所有的延迟访问检查。

 

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  }

 

2个函数都依赖enforce_access来执行访问检查。

 

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 }

 

这里在accessible_p中,参数decl是一个从type类型基类来的声明,type是声明了decl的类。例如:

        class A {

               int a;

        } cA;

     cA.a = 5;

当进行访问控制检查时,A将是type,而a将是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);

 

首先确认decl不是在一个块里FORWHILE块等),或者在名字空间中,这些域里都没有访问控制实施。函数context_for_name_lookup返回decl将首先被查找的绑定域。611行的ANON_AGGR_TYPE_P表示的是匿名的unionstruct类型(这是ISO C++不允许的),根据【3】,“一个匿名union的成员名字应该区别于,该匿名union声明所在域中的其它实体名字。出于名字查找的目的,在匿名union定义的后面,其成员被视为定义在其声明所在的域中。”因此,需要上升一级。

 

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  }

 

如果在模板声明(不是具现)中,同样跳过访问控制检查。在调用accessible_p时,参数type可以是*_TYPEbinfo节点,因此如果decl所在域执行访问控制检查,需要妥善设定typebinfo

 

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 }

 

上面的注释解释了几种可访问的情况:1)类的公有成员;2)虽然是私有成员,但通过友元来访问;3)是保护成员,但是通过派生类来访问;4)在引用处,存在可访问的基类,通过该基类可以访问该指定的成员。对于第4点,为了便于理解,我们给出一个例子:

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;

}

下面开始逐个来检查。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值