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

5.12.4.1.1.2.1.1.2.            在指定类中的查找

而如果指定的作用域是一个类,那么查找的就是除非静态数据成员以外的类成员。不过这里尚不检查是否有违反,这由外部调用它们的函数来检查( build_offset_ref )。

在一个指定的类作用域中的查找工作,具体由 lookup_member 来进行。在这个函数中,注意参数 want_type 如果是 true ,这表示我们应该仅返回 TYPE_DECL 节点;参数 xbasetype 指向类的类型节点;而参数 protect 传入为 0 ,表示不要进行访问控制检查,并且对于有二义性的查找,我们应该返回 NULL

 

1275 tree

1276 lookup_member (tree xbasetype, tree name, int protect, bool want_type)               in search.c

1277 {

1278    tree rval, rval_binfo = NULL_TREE;

1279    tree type = NULL_TREE, basetype_path = NULL_TREE;

1280    struct lookup_field_info lfi;

1281

1282    /* rval_binfo is the binfo associated with the found member, note,

1283      this can be set with useful information, even when rval is not

1284      set, because it must deal with ALL members, not just non-function

1285      members. It is used for ambiguity checking and the hidden

1286      checks. Whereas rval is only set if a proper (not hidden)

1287      non-function member is found.  */

1288

1289    const char *errstr = 0;

1290

1291    my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 20030624);

1292

1293    if (TREE_CODE (xbasetype) == TREE_VEC)

1294    {

1295      type = BINFO_TYPE (xbasetype);

1296      basetype_path = xbasetype;

1297    }

1298    else

1299    {

1300      my_friendly_assert(IS_AGGR_TYPE_CODE(TREE_CODE(xbasetype)), 20030624);

1301      type = xbasetype;

1302      basetype_path = TYPE_BINFO (type);

1303      my_friendly_assert (!BINFO_INHERITANCE_CHAIN (basetype_path), 980827);

1304    }

1305

1306    if (type == current_class_type && TYPE_BEING_DEFINED (type)

1307        && IDENTIFIER_CLASS_VALUE (name))

1308    {

1309      tree field = IDENTIFIER_CLASS_VALUE (name);

1310      if (! is_overloaded_fn (field)

1311          && ! (want_type && TREE_CODE (field) != TYPE_DECL))

1312        /* We're in the scope of this class, and the value has already

1313          been looked up. Just return the cached value.  */

1314        return field;

1315    }

 

参考图形 binfo间的关系 ,显然上面的 type 指向与 binfo 关联的 RECORD_TYPE 节点。对于 name ,如果在 1307 行的 IDENTIFIER_CLASS_VALUE 不是 NULL name 被声明在当前类中,并且 IDENTIFIER_CLASS_VALUE 是其对应的声明。

如果封闭类( enclosing class )正在定义中(一定是 current_class_type ),如果由 IDENTIFIER_CLASS_VALUE 返回的对象是函数声明,那么我们需要继续下面的处理,因为方法 / 函数是可以重载的,因此有可能我们找到的是前一个定义。除此之外,如果 TYPE_DECL 是期望的返回值,但找到域不是 TYPE_DECL ,我们也需要进行处理(这里考虑如下代码:

struct F {

    int innerType;

};

 

struct G: public F {

    typedef int innerType;  // we are parsing this field, IDENTIFIER_CLASS_VALUE      // (innerType) still points to F::innerType

};

域“ typedef int innerType ”需要被加入类定义,必须摒弃找到的“ int innerType ”;而对于代码:

struct F {

    typedef int innerType;

};

 

struct G: public F {

    void func(int innerType);       // we are parsing this field

};

我们只需返回 F innerType ,编译器随后会发现这个错误。

如果我们不能从 IDENTIFIER_CLASS_VALUE 所支持的快速查找中获益(只要 type 不是正在定义中,就没有风险,因为 IDENTIFIER_CLASS_VALUE 这时保存了前一次找出的链接)。我们不得不用强硬的方法来进行查找。

 

1008 struct lookup_field_info {                                                                         in search.c

1009   /* The type in which we're looking.  */

1010   tree type;

1011   /* The name of the field for which we're looking.  */

1012   tree name;

1013   /* If non-NULL, the current result of the lookup.  */

1014   tree rval;

1015   /* The path to RVAL.  */

1016   tree rval_binfo;

1017   /* If non-NULL, the lookup was ambiguous, and this is a list of the

1018     candidates.  */

1019   tree ambiguous;

1020   /* If nonzero, we are looking for types, not data members.  */

1021   int want_type;

1022   /* If something went wrong, a message indicating what.  */

1023   const char *errstr;

1024 };

 

上面的结构体将被用来传递指引在被查找集中的查找过程的信息。并且它也将带回查找结果。

 

lookup_member (continue)

 

1317    complete_type (type);

1318

1319 #ifdef GATHER_STATISTICS

1320    n_calls_lookup_field ++;

1321 #endif /* GATHER_STATISTICS */

1322

1323    memset (&lfi, 0, sizeof (lfi));

1324    lfi.type = type;

1325    lfi.name = name;

1326    lfi.want_type = want_type;

1327    bfs_walk (basetype_path, &lookup_field_r , &lookup_field_queue_p , &lfi);

 

函数 bfs_walk 遍历由 basetype_path 支配的类层次结构。然后在这个宽度优先的前序遍历中,函数 lookup_field_r 为层次结构中的每个类所调用。如果这个函数返回非 NULL ,这个值被立即返回并且结束遍历。这意味着我们已经找到期望的东西,而且它在派生程度最高的子类中。

 

1607 static tree

1608 bfs_walk (tree binfo,                                                                                 in search.c

1609           tree (*fn) (tree, void *),

1610           tree (*qfn) (tree, int, void *),

1611           void *data)

1612 {

1613    tree rval = NULL_TREE;

1614

1615    tree bases_initial[BFS_WALK_INITIAL_QUEUE_SIZE];

1616    /* A circular queue of the base classes of BINFO. These will be

1617      built up in breadth-first order, except where QFN prunes the

1618      search.  */

1619    size_t head, tail;

1620    size_t base_buffer_size = BFS_WALK_INITIAL_QUEUE_SIZE;

1621    tree *base_buffer = bases_initial;

1622

1623    head = tail = 0;

1624    base_buffer[tail++] = binfo;

1625

1626    while (head != tail)

1627    {

1628      int n_bases, ix;

1629      tree binfo = base_buffer[head++];

1630      if (head == base_buffer_size)

1631        head = 0;

1632

1633      /* Is this the one we're looking for? If so, we're done.  */

1634      rval = fn (binfo, data);

1635      if (rval)

1636        goto done;

1637

1638      n_bases = BINFO_N_BASETYPES (binfo);

1639      for (ix = 0; ix != n_bases; ix++)

1640      {

1641        tree base_binfo;

1642     

1643        if (qfn)

1644          base_binfo = (*qfn) (binfo, ix, data);

1645        else

1646          base_binfo = BINFO_BASETYPE (binfo, ix);

1647     

1648        if (base_binfo)

1649        {

1650          base_buffer[tail++] = base_binfo;

1651          if (tail == base_buffer_size)

1652            tail = 0;

1653          if (tail == head)

1654          {

1655            tree *new_buffer = xmalloc (2 * base_buffer_size

1656                                    * sizeof (tree));

1657            memcpy (&new_buffer[0], &base_buffer[0],

1658                    tail * sizeof (tree));

1659            memcpy (&new_buffer[head + base_buffer_size],

1660                    &base_buffer[head],

1661                    (base_buffer_size - head) * sizeof (tree));

1662            if (base_buffer_size != BFS_WALK_INITIAL_QUEUE_SIZE)

1663              free (base_buffer);

1664            base_buffer = new_buffer;

1665            head += base_buffer_size;

1666            base_buffer_size *= 2;

1667          }

1668        }

1669      }

1670    }

1671

1672   done:

1673    if (base_buffer_size != BFS_WALK_INITIAL_QUEUE_SIZE)

1674      free (base_buffer);

1675    return rval;

1676 }

 

上面缓存 bases_initial 通过把树以前序展开入一个数组来辅助遍历。可以期望一个编译单元中的类层次结构树通常是相当简单的( BFS_WALK_INITIAL_QUEUE_SIZE 10 )。

在每次调用中,一个表示从当前访问子类到 basetype_path 的路径的 binfo 被传给 lookup_field_r 。而 lookup_field_queue_p lookup_field_r 选出合格的对象。

 

1136 static tree

1137 lookup_field_r (tree binfo, void *data)                                                        in search.c

1138 {

1139    struct lookup_field_info *lfi = (struct lookup_field_info *) data;

1140    tree type = BINFO_TYPE (binfo);

1141    tree nval = NULL_TREE;

1142

1143    /* First, look for a function. There can't be a function and a data

1144      member with the same name, and if there's a function and a type

1145      with the same name, the type is hidden by the function.  */

1146    if (!lfi->want_type)

1147    {

1148      int idx = lookup_fnfields_1 (type, lfi->name);

1149      if (idx >= 0)

1150        nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);

1151    }

1152

1153    if (!nval)

1154      /* Look for a data member or type.  */

1155      nval = lookup_field_1 (type, lfi->name, lfi->want_type);

1156

1157    /* If there is no declaration with the indicated name in this type,

1158      then there's nothing to do.  */

1159    if (!nval)

1160      return NULL_TREE;

 

在类的节点中,其方法被记录在一个向量( vector 中); lookup_fnfields_1 返回由 name 所指定方法所对应的索引。下面的 CLASSTYPE_METHOD_VEC 就是这个向量。

 

1458 int

1459 lookup_fnfields_1 (tree type, tree name)                                                      in search.c

1460 {

1461    tree method_vec;

1462    tree *methods;

1463    tree tmp;

1464    int i;

1465    int len;

1466

1467    if (!CLASS_TYPE_P (type))

1468      return -1;

1469

1470    method_vec = CLASSTYPE_METHOD_VEC (type);

1471

1472    if (!method_vec)

1473      return -1;

1474

1475    methods = &TREE_VEC_ELT (method_vec, 0);

1476    len = TREE_VEC_LENGTH (method_vec);

1477

1478 #ifdef GATHER_STATISTICS

1479    n_calls_lookup_fnfields_1 ++;

1480 #endif /* GATHER_STATISTICS */

1481

1482    /* Constructors are first...  */

1483    if (name == ctor_identifier)

1484      return (methods[CLASSTYPE_CONSTRUCTOR_SLOT]

1485            ? CLASSTYPE_CONSTRUCTOR_SLOT : -1);

1486    /* and destructors are second.  */

1487    if (name == dtor_identifier)

1488      return (methods[CLASSTYPE_DESTRUCTOR_SLOT]

1489            ? CLASSTYPE_DESTRUCTOR_SLOT : -1);

1490    if (IDENTIFIER_TYPENAME_P (name))

1491      return lookup_conversion_operator (type, TREE_TYPE (name));

 

构造函数及析构函数,如果被定义了,它们被放置在固定的地方,因为它们是最常调用的方法。如果有作为转换操作符的构造函数,它们紧跟随后。对于转换操作符的查找有点麻烦,如 ISO-IEC-14882-2003 所要求,对于同名的转换操作符,非模板的版本要优先于模板版本。

 

1404 static int

1405 lookup_conversion_operator (tree class_type, tree type)                                in search.c

1406 {

1407    int pass;

1408    int i;

1409

1410    tree methods = CLASSTYPE_METHOD_VEC (class_type);

1411

1412    for (pass = 0; pass < 2; ++pass)

1413      for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;

1414           i < TREE_VEC_LENGTH (methods);

1415          ++i)

1416      {

1417        tree fn = TREE_VEC_ELT (methods, i);

1418        /* The size of the vector may have some unused slots at the

1419          end.  */

1420        if (!fn)

1421          break ;

1422

1423        /* All the conversion operators come near the beginning of the

1424          class. Therefore, if FN is not a conversion operator, there

1425          is no matching conversion operator in CLASS_TYPE.  * /

1426        fn = OVL_CURRENT (fn);

1427        if (!DECL_CONV_FN_P (fn))

1428          break ;

1429       

1430        if (pass == 0)

1431        {

1432          /* On the first pass we only consider exact matches. If

1433            the types match, this slot is the one where the right

1434            conversion operators can be found.  */

1435          if (TREE_CODE (fn) != TEMPLATE_DECL

1436            && same_type_p (DECL_CONV_FN_TYPE (fn), type))

1437            return i;

1438        }

1439        else

1440        {

1441          /* On the second pass we look for template conversion

1442            operators. It may be possible to instantiate the

1443            template to get the type desired. All of the template

1444            conversion operators share a slot. By looking for

1445            templates second we ensure that specializations are

1446            preferred over templates.  */

1447          if (TREE_CODE (fn) == TEMPLATE_DECL)

1448            return i;

1449        }

1450      }

1451

1452    return -1;

1453 }

 

对于其他方法,则需要老老实实地在这个向量中查找。对于解析过的类,其方法已经按其名字所对应的标识符的地址排序,因此可以使用二分查找;而对于正在解析的类,其方法还未排序,只能依次查找。

 

lookup_fnfields_1 (continue)

 

1493    /* Skip the conversion operators.  */

1494    i = CLASSTYPE_FIRST_CONVERSION_SLOT;

1495    while (i < len && methods[i] && DECL_CONV_FN_P (OVL_CURRENT (methods[i])))

1496      i++;

1497

1498    /* If the type is complete, use binary search.  */

1499    if (COMPLETE_TYPE_P (type))

1500    {

1501      int lo = i;

1502      int hi = len;

1503

1504      while (lo < hi)

1505      {

1506        i = (lo + hi) / 2;

1507

1508 #ifdef GATHER_STATISTICS

1509        n_outer_fields_searched ++;

1510 #endif /* GATHER_STATISTICS */

1511

1512        tmp = methods[i];

1513        /* This slot may be empty; we allocate more slots than we

1514          need. In that case, the entry we're looking for is

1515           closer to the beginning of the list.  */

1516        if (tmp)

1517          tmp = DECL_NAME (OVL_CURRENT (tmp));

1518        if (!tmp || tmp > name)

1519          hi = i;

1520        else if (tmp < name)

1521          lo = i + 1;

1522        else

1523          return i;

1524      }

1525    }

1526    else

1527      for (; i < len && methods[i]; ++i)

1528      {

1529 #ifdef GATHER_STATISTICS

1530        n_outer_fields_searched ++;

1531 #endif /* GATHER_STATISTICS */

1532       

1533        tmp = OVL_CURRENT (methods[i]);

1534        if (DECL_NAME (tmp) == name)

1535          return i;

1536      }

1537

1538    return -1;

1539 }

 

查找转换操作符由上述代码完成,不过 lookup_field _r 也可被用于查找数据成员或类中的类型,在这里我们也看一下这部分功能。

查找数据成员由 lookup_field_1 完成,看到如果不是严格地要求 TYPE_DECL ,方法( method )将隐藏同名的类型。

 

427  tree

428  lookup_field_1 (tree type, tree name, bool want_type)                                   in search.c

429  {

430    tree field;

431 

432    if (TREE_CODE (type) == TEMPLATE_TYPE_PARM

433        || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM

434        || TREE_CODE (type) == TYPENAME_TYPE)

435      /* The TYPE_FIELDS of a TEMPLATE_TYPE_PARM and

436        BOUND_TEMPLATE_TEMPLATE_PARM are not fields at all;

437        instead TYPE_FIELDS is the TEMPLATE_PARM_INDEX. (Miraculously,

438        the code often worked even when we treated the index as a list

439        of fields!)

440        The TYPE_FIELDS of TYPENAME_TYPE is its TYPENAME_TYPE_FULLNAME. */

441      return NULL_TREE;

442 

443    if (TYPE_NAME (type)

444        && DECL_LANG_SPECIFIC (TYPE_NAME (type))

445        && DECL_SORTED_FIELDS (TYPE_NAME (type)))

446    {

447      tree *fields = &DECL_SORTED_FIELDS (TYPE_NAME (type))->elts[0];

448      int lo = 0, hi = DECL_SORTED_FIELDS (TYPE_NAME (type))->len;

449      int i;

450 

451      while (lo < hi)

452      {

453        i = (lo + hi) / 2;

454 

455    #ifdef GATHER_STATISTICS

456        n_fields_searched ++;

457    #endif /* GATHER_STATISTICS */

458 

459        if (DECL_NAME (fields[i]) > name)

460          hi = i;

461        else if (DECL_NAME (fields[i]) < name)

462          lo = i + 1;

463        else

464        {

465          field = NULL_TREE;

466 

467           /* We might have a nested class and a field with the

468            same name; we sorted them appropriately via

469            field_decl_cmp, so just look for the first or last

470            field with this name.  */

471           if (want_type)

472          {

473            do

474              field = fields[i--];

475            while (i >= lo && DECL_NAME (fields[i]) == name);

476            if (TREE_CODE (field) != TYPE_DECL

477               && !DECL_CLASS_TEMPLATE_P (field))

478              field = NULL_TREE;

479          }

480          else

481          {

482            do

483              field = fields[i++];

484            while (i < hi && DECL_NAME (fields[i]) == name);

485          }

486          return field;

487        }

488      }

489      return NULL_TREE;

490    }

491 

492    field = TYPE_FIELDS (type);

493 

494  #ifdef GATHER_STATISTICS

495    n_calls_lookup_field_1 ++;

496  #endif /* GATHER_STATISTICS */

497    for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))

498    {

499  #ifdef GATHER_STATISTICS

500      n_fields_searched ++;

501  #endif /* GATHER_STATISTICS */

502      my_friendly_assert (DECL_P (field), 0);

503      if (DECL_NAME (field) == NULL_TREE

504        && ANON_AGGR_TYPE_P (TREE_TYPE (field)))

505      {

506        tree temp = lookup_field_1 (TREE_TYPE (field), name, want_type);

507        if (temp)

508          return temp;

509      }

510      if (TREE_CODE (field) == USING_DECL)

511         /* For now, we're just treating member using declarations as

512          old ARM-style access declarations. Thus, there's no reason

513          to return a USING_DECL, and the rest of the compiler can't

514          handle it. Once the class is defined, these are purged

515          from TYPE_FIELDS anyhow; see handle_using_decl.  */

516        continue ;

517 

518      if (DECL_NAME (field) == name

519        && (!want_type

520            || TREE_CODE (field) == TYPE_DECL

521            || DECL_CLASS_TEMPLATE_P (field)))

522        return field;

523    }

524    /* Not found.  */

525    if (name == vptr_identifier )

526    {

527      /* Give the user what s/he thinks s/he wants.  */

528      if (TYPE_POLYMORPHIC_P (type))

529        return TYPE_VFIELD (type);

530    }

531    return NULL_TREE;

532  }

 

这个函数类似于 lookup_fnfields_1 的后半部分。注意在 444 行,在 C++ 前端中, *_DECL 节点中具有 DECL_LANG_SPECIFIC 部分。对于类,虚表( vtable )被链接在 TYPE_FIELDS 的头部,它被虚表指针( vptr_identifier )所指向。注意只有定义了虚函数或从虚基类派生的类才具有虚表及虚表指针。

如果我们查找一个类型,但所找到的( nval )不是 TYPE_DECL 并且与当前类同名;对于这个情况, nval 一定不是方法(在 1148 行的 lookup_fnfields_1 被跳过),而是一个域。正如下面 1169 行的注释所描述的, nval 可以是与类型同名的一个域。回忆对于类,为其有 TYPE_DECL 被构建,并且链入 TYPE_FIELDS ,因此在 1173 行的 FOR 循环查找这个 TYPE_DECL

 

lookup_field_r (continue)

 

1162    /* If we're looking up a type (as with an elaborated type specifier)

1163      we ignore all non-types we find.  */

1164    if (lfi->want_type && TREE_CODE (nval) != TYPE_DECL

1165        && !DECL_CLASS_TEMPLATE_P (nval))

1166    {

1167      if (lfi->name == TYPE_IDENTIFIER (type))

1168      {

1169        /* If the aggregate has no user defined constructors, we allow

1170          it to have fields with the same name as the enclosing type.

1171          If we are looking for that name, find the corresponding

1172          TYPE_DECL.  */

1173        for (nval = TREE_CHAIN (nval); nval; nval = TREE_CHAIN (nval))

1174          if (DECL_NAME (nval) == lfi->name

1175                && TREE_CODE (nval) == TYPE_DECL)

1176            break ;

1177      }

1178      else

1179         nval = NULL_TREE;

1180      if (!nval && CLASSTYPE_NESTED_UTDS (type) != NULL)

1181      {

1182        binding_entry e = binding_table_find (CLASSTYPE_NESTED_UTDS (type),

1183                                        lfi->name);

1184        if (e != NULL)

1185          nval = TYPE_MAIN_DECL (e->type);

1186        else

1187          return NULL_TREE;

1188      }

1189    }

1190

1191    /* You must name a template base class with a template-id.  */

1192    if (!same_type_p (type, lfi->type)

1193        && template_self_reference_p (type, nval))

1194      return NULL_TREE;

 

上面,在 1180 行, CLASSTYPE_NESTED_UTDS 是在类中找到的嵌套用户定义类型(类或枚举)的字典。如果 nval 不是 TYPE_DECL 并且不与类的同名,我们进入 1180 行的 IF 块;在这种情况下, nval 可能会屏蔽在类中声明的类型。比如:

class A {

public :

    class a { public : int i; };

    int a;

};

 

int main () {

    class A::a a;     // class A::a is the elaborated-type-specifier

    return 0;

}

为了是 IF 块找出被域‘ a ’所屏蔽的类型‘ a ’,必须使用 elaborated-type-specifier 来显式地指明类型(看到这在上面会使得 want_type 成为 true )。

以下,【 3 】,条款 3.3.7 “名字屏蔽”系统地描述了名字屏蔽的规则。

1.  在一个嵌套声明域或派生类中,一个名字可以被同名的显式声明所屏蔽( 10.2 )。

2.  一个类名( 9.1 )或枚举名( 7.2 )可以被在同一个域中声明的对象,函数或枚举值的名字所屏蔽。如果一个类或枚举类型与同名的一个对象,函数或枚举值,以任意的次序,声明在同一个域中,该类或枚举类型在该对象,函数或枚举值可见处被屏蔽。

3.  在一个方法的定义中的一个局部声明屏蔽在该类中声明的同名成员;参考 3.3.6 。在一个派生类中的一个成员声明(条款 10 )屏蔽基类中声明的同名成员;参考 10.2

4.  在查找被一个名字空间名所限定的名字的过程中,那些通过 using-directive 可见的声明为包含这个 using-directive 的名字空间内的同名声明所屏蔽;参考( 3.4.3.2 )。

5.  如果一个名字在作用域内并且没有被屏蔽,它被称为可见( visible )。

 

lookup_field_r (continue)

 

1196    /* If the lookup already found a match, and the new value doesn't

1197      hide the old one, we might have an ambiguity.  */

1198    if (lfi->rval_binfo

1199        && !is_subobject_of_p (lfi->rval_binfo, binfo))

1200     

1201    {

1202      if (nval == lfi->rval && shared_member_p (nval))

1203         /* The two things are really the same.  */

1204         ;

1205      else if (is_subobject_of_p (binfo, lfi->rval_binfo))

1206          /* The previous value hides the new one.  */

1207         ;

1208      else

1209      {

1210          /* We have a real ambiguity. We keep a chain of all the

1211          candidates.  */

1212          if (!lfi->ambiguous && lfi->rval)

1213        {

1214          /* This is the first time we noticed an ambiguity. Add

1215             what we previously thought was a reasonable candidate

1216             to the list.  */

1217          lfi->ambiguous = tree_cons (NULL_TREE, lfi->rval, NULL_TREE);

1218          TREE_TYPE (lfi->ambiguous) = error_mark_node;

1219        }

1220

1221         /* Add the new value.  */

1222        lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);

1223        TREE_TYPE (lfi->ambiguous) = error_mark_node;

1224        lfi->errstr = "request for member `%D' is ambiguous";

1225      }

1226    }

1227    else

1228    {

1229       lfi->rval = nval;

1230      lfi->rval_binfo = binfo;

1231    }

1232

1233    return NULL_TREE;

1234 }

 

在上面的 lfi 中, rval 域记录了最后的查找结果,而 rval_binfo 则是对应的 binfo 。因为 lfi 在整个遍历中都存活着,这些域如果不是 NULL ,则表示了有二义性的可能,除非 rval_binfo binfo (现在正在查找的类型)具有继承关系。另一个例外是这 2 个项都是同一个。

 

1114 static int

1115 is_subobject_of_p (tree parent, tree binfo)                                                   in search.c

1116 {

1117    tree probe;

1118   

1119    for (probe = parent; probe; probe = BINFO_INHERITANCE_CHAIN (probe))

1120    {

1121      if (probe == binfo)

1122       return 1;

1123      if (TREE_VIA_VIRTUAL (probe))

1124       return (purpose_member (BINFO_TYPE (probe),

1125                       CLASSTYPE_VBASECLASSES (BINFO_TYPE (binfo)))

1126             != NULL_TREE);

1127    }

1128    return 0;

1129 }

 

函数 is_subobject_of_p 分辨给定的类型是否具有继承关系。它的实现简单直接。

在遍历后,如果有所发现, lfi 中的 rval rval_binfo 记录了查找的结果。而且如果发现了二义性,具有二义性的域被记录在 ambiguous 域。

 

lookup_member (continue)

 

1328    rval = lfi.rval;

1329    rval_binfo = lfi.rval_binfo;

1330    if (rval_binfo)

1331      type = BINFO_TYPE (rval_binfo);

1332    errstr = lfi.errstr;

1333

1334    /* If we are not interested in ambiguities, don't report them;

1335      just return NULL_TREE.  */

1336    if (!protect && lfi.ambiguous)

1337      return NULL_TREE;

1338   

1339    if (protect == 2)

1340    {

1341      if (lfi.ambiguous)

1342       return lfi.ambiguous;

1343      else

1344       protect = 0;

1345    }

1346

1347    /* [class.access]

1348

1349      In the case of overloaded function names, access control is

1350      applied to the function selected by overloaded resolution.  */

1351    if (rval && protect && !is_overloaded_fn (rval))

1352      perform_or_defer_access_check (basetype_path, rval);

1353

1354    if (errstr && protect)

1355    {

1356      error (errstr, name, type);

1357      if (lfi.ambiguous)

1358        print_candidates (lfi.ambiguous);

1359      rval = error_mark_node;

1360    }

1361

1362    if (rval && is_overloaded_fn (rval))

1363      rval = build_baselink (rval_binfo, basetype_path, rval,

1364                        (IDENTIFIER_TYPENAME_P (name)

1365                         ? TREE_TYPE (name): NULL_TREE));

1366    return rval;

1367 }

 

注意上面的 is_overloaded_fn 返回 true 如果 rval 可以被重载。对于可以被重载及访问的方法,要构建 BASELINK 节点,它代表对一个或一组基类的方法的引用。注意到类本身可以作为自己的基类。

 

1240 tree

1241 build_baselink (tree binfo, tree access_binfo, tree functions, tree optype)

1242 {

1243    tree baselink;

1244

1245    my_friendly_assert (TREE_CODE (functions) == FUNCTION_DECL

1246                     || TREE_CODE (functions) == TEMPLATE_DECL

1247                     || TREE_CODE (functions) == TEMPLATE_ID_EXPR

1248                     || TREE_CODE (functions) == OVERLOAD,

1249                     20020730);

1250    my_friendly_assert (!optype || TYPE_P (optype), 20020730);

1251    my_friendly_assert (TREE_TYPE (functions), 20020805);

1252

1253    baselink = make_node (BASELINK);

1254    TREE_TYPE (baselink) = TREE_TYPE (functions);

1255    BASELINK_BINFO (baselink) = binfo;

1256    BASELINK_ACCESS_BINFO (baselink) = access_binfo;

1257    BASELINK_FUNCTIONS (baselink) = functions;

1258    BASELINK_OPTYPE (baselink) = optype;

1259

1260    return baselink;

1261 }

 

BASELINK_FUNCTIONS 给出了对应于函数的 FUNCTION_DECL TEMPLATE_DECL OVERLOAD TEMPLATE_ID_EXPR BASELINK_BINFO 给出了这些函数所来自的基类,即,在调用这些函数之前,“ this ”指针需要被转换至的基类(这个 BINFO 指示了 BASELINK_FUNCTIONS 所来自的基类)。 BASELINK_ACCESS_BINFO 给出了命名这些函数的基类(在这个 BINFO 中开始查找由这个 baselink 所指明的函数。这个基类通常用来确定由重载解析所选定函数的可访问性)。 BASELINK_BINFO BASELINK_ACCESS_BINFO 可能会由 adjust_result_of_qualified_name_lookup 调整。

一个 BASELINK 是一个表达式; BASELINK TREE_TYPE 给出了表达式的类型。这个类型或者是一个 FUNCTION_TYPE METHOD_TYPE 或者表示重载函数的 unknown_type_node

在结束这一节之前,让我们看一下,在 lookup_member 1327 行的 bfs_walk 中,如何选择合适的 binfo 。这是函数 lookup_field_queue_p

 

1041 static tree

1042 lookup_field_queue_p (tree derived, int ix, void *data)

1043 {

1044    tree binfo = BINFO_BASETYPE (derived, ix);

1045    struct lookup_field_info *lfi = (struct lookup_field_info *) data;

1046

1047    /* Don't look for constructors or destructors in base classes.  */

1048    if (IDENTIFIER_CTOR_OR_DTOR_P (lfi->name))

1049      return NULL_TREE;

1050

1051    /* If this base class is hidden by the best-known value so far, we

1052      don't need to look.  */

1053    if (lfi->rval_binfo && original_binfo (binfo, lfi->rval_binfo))

1054      return NULL_TREE;

1055

1056    /* If this is a dependent base, don't look in it.  */

1057    if (BINFO_DEPENDENT_BASE_P (binfo))

1058      return NULL_TREE;

1059   

1060    return binfo;

1061 }

 

上面在 1053 行, binfo 可能是在由 lfi->rval_binfo 支配的类层次树中的原始 original_binfo binfo ,或者是一个复制的 binfo 。对于复制的 binfo original_binfo 返回 NULL ,否则返回层次树中的原始的 binfo

那么如果 original_binfo 返回值不为 NULL ,表示 lfi->rval_binfo (记住这个域保存了发现所查找名字的 binfo )包含了 binfo 作为基类,不需要在其中查找。

5.12.4.1.1.2.1.2.    在指定对象中查找

而对于类似“ a->b ”或“ a.b ”的表达式,作用域‘ a ’被记录在“ parser->context->object_type ”,此时它被下面的 object_type 所指向。【 3 】规定:

如果在一个类成员访问中的 id-expression 是一个以下形式的 qualified-id

class-name-or-namespace-name::...

跟在操作符 . -> 后的 class-name-or-namespace-name 同时在整个 postfix-expression 上下文中及对象表达式( object-expression )的类的作用域中查找。如果只在该对象表达式的类的作用域中找到该名字,该名字应该是一个类名。如果仅在整个 postfix-expression 的上下文中找到该名字,这个名字应该是一个类名或名字空间名。如果在 2 个上下文中都找到这个名字, 它们应该指向同一个实体。 [ 注意: class-name-or-namespace-name 查找出来的结果不要求为该对象表达式的类中唯一的基类,只要被限定 id qualified id )命名的实体是对象表达式的类的成员并且根据 10.2 没有二义性。

struct A {

int a;

};

struct B: virtual A { };

struct C: B { };

struct D: B { };

struct E: public C, public D { };

struct F: public A { };

void f() {

E e;

e.B::a = 0; // OK, only one A::a in E

F f;

f.A::a = 1; // OK, A::a is a member of F

}

不过我尚未想明白什么情况下 class-name-or-namespace-name 可以是名字空间名 L 。例如:

namespace NA {

int i;

struct A { };

void func () {

   A a;

   a.NA::i = 5;

}

}

 

int main () {

    return 1;

}

根据上面的规则,“ a.NA::i ”中的 NA 将在 func 所在上下文查找,并最终确定为名字空间名,但是在 finish_class_member_access_expr 中,这个表达式最终被确认为错误。

 

cp_parser_lookup_name (continue)

 

13811    else if (object_type)

13812    {

13813      tree object_decl = NULL_TREE;

13814      /* Look up the name in the scope of the OBJECT_TYPE, unless the

13815         OBJECT_TYPE is not a class.  */

13816      if (CLASS_TYPE_P (object_type))

13817         /* If the OBJECT_TYPE is a template specialization, it may

13818          be instantiated during name lookup. In that case, errors

13819          may be issued. Even if we rollback the current tentative

13820          parse, those errors are valid.  */

13821           object_decl = lookup_member (object_type,

13822                                      name,

13823                                      /*protect=*/ 0, is_type);

13824       /* Look it up in the enclosing context, too.  */

13825      decl = lookup_name_real (name, is_type, /*nonclass=*/ 0,

13826                             is_namespace, flags);

13827      parser->object_scope = object_type;

13828      parser->qualifying_scope = NULL_TREE;

13829      if (object_decl)

13830         decl = object_decl;

13831    }

 

3 】并没有规定在 2 个上下文中同时找到名字时采取何者。 GCC 采用在对象表达式的类作用域中找到的那个。注意,函数 lookup_member lookup_name_real 都能保证找到的结果没有二义性。

上面在 13827 行, parser object_scope qualifying_scope 保存了最后一次查找所在的作用域。如果使用了形如“ x->y ”或“ x.y ”的表达式,使用 object_scope ,它分别给出类型“ *x ”或“ x ”;对于形如“ X::Y ”的表达式,使用 qualifying_scope ,它指向 X

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值