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

5.9.2.1.    是否从当前类访问

如果 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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值