Studying note of GCC-3.4.6 source (84)

5.9.2.1.    If accessible from current class

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.

 

你可能感兴趣的:(tree,null,Class,Access,inheritance,traversal)