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

来源:互联网 发布:淘宝网秋季修身连衣裙 编辑:程序博客网 时间:2024/06/05 14:49

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)               insearch.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 isthe binfo associated with the found member, note,

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

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

1285     members. It isused for ambiguity checking and the hidden

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

1287     non-functionmember 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 thescope of this class, and the value has already

1313         been lookedup. Just return the cached value.  */

1314       returnfield;

1315   }

 

参考图形binfo间的关系,显然上面的type指向与binfo关联的RECORD_TYPE节点。对于name,如果在1307行的IDENTIFIER_CLASS_VALUE不是NULLname被声明在当前类中,并且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 parsingthis 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

};

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

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

 

1008 struct lookup_field_info{                                                                         insearch.c

1009  /* The type inwhich we're looking.  */

1010  tree type;

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

1012  tree name;

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

1014  tree rval;

1015  /* The path toRVAL.  */

1016  tree rval_binfo;

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

1018    candidates.  */

1019  tree ambiguous;

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

1021  int want_type;

1022  /* If somethingwent 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,                                                                                 insearch.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     builtup 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       gotodone;

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   returnrval;

1676 }

 

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

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

 

1136 static tree

1137 lookup_field_r (tree binfo, void *data)                                                        insearch.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 fora function. There can't be a function and a data

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

1145     with the samename, 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 adata member or type.  */

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

1156

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

1158     then there'snothing to do.  */

1159   if (!nval)

1160     returnNULL_TREE;

 

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

 

1458 int

1459 lookup_fnfields_1 (tree type, tree name)                                                      insearch.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 arefirst...  */

1483   if (name == ctor_identifier)

1484     return(methods[CLASSTYPE_CONSTRUCTOR_SLOT]

1485           ? CLASSTYPE_CONSTRUCTOR_SLOT : -1);

1486   /* and destructorsare 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)                                insearch.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 ofthe vector may have some unused slots at the

1419         end.  */

1420       if (!fn)

1421         break;

1422

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

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

1425         is nomatching 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 thefirst pass we only consider exact matches. If

1433           the typesmatch, this slot is the one where the right

1434           conversionoperators can be found.  */

1435         if (TREE_CODE (fn) != TEMPLATE_DECL

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

1437           returni;

1438       }

1439       else

1440       {

1441         /* On thesecond pass we look for template conversion

1442           operators.It may be possible to instantiate the

1443           template toget the type desired. All of the template

1444           conversionoperators share a slot. By looking for

1445           templatessecond we ensure that specializations are

1446           preferredover templates.  */

1447         if (TREE_CODE (fn) == TEMPLATE_DECL)

1448           returni;

1449       }

1450     }

1451

1452   return -1;

1453 }

 

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

 

lookup_fnfields_1 (continue)

 

1493   /* Skip theconversion 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 iscomplete, 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 slotmay be empty; we allocate more slots than we

1514         need. In thatcase, 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         returni;

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         returni;

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 notfields at all;

437        instead TYPE_FIELDS is theTEMPLATE_PARM_INDEX. (Miraculously,

438        the code often worked even when wetreated the index as a list

439        offields!)

440        TheTYPE_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         /* Wemight have a nested class and a field with the

468            same name; we sorted themappropriately via

469            field_decl_cmp, so just look for thefirst 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       /* Fornow, 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 ofthe compiler can't

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

515          from TYPE_FIELDS anyhow; seehandle_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/hewants.  */

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 lookingup a type (as with an elaborated type specifier)

1163     we ignore allnon-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 theaggregate has no user defined constructors, we allow

1170         it to havefields with the same name as the enclosing type.

1171         If we arelooking 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         returnNULL_TREE;

1188     }

1189   }

1190

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

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

1193       && template_self_reference_p(type, nval))

1194     returnNULL_TREE;

 

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

class A {

public:

    classa { public: int i; };

    int a;

};

 

int main () {

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

    return0;

}

为了是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 lookupalready 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 previousvalue hides the new one.  */

1207       ;

1208     else

1209     {

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

1211         candidates.  */

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

1213       {

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

1215            what wepreviously thought was a reasonable candidate

1216            to thelist.  */

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   returnNULL_TREE;

1234 }

 

在上面的lfi中,rval域记录了最后的查找结果,而rval_binfo则是对应的binfo。因为lfi在整个遍历中都存活着,这些域如果不是NULL,则表示了有二义性的可能,除非rval_binfobinfo(现在正在查找的类型)具有继承关系。另一个例外是这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中的rvalrval_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 notinterested in ambiguities, don't report them;

1335     just returnNULL_TREE.  */

1336   if (!protect && lfi.ambiguous)

1337     returnNULL_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, accesscontrol is

1350     applied to thefunction 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   returnbaselink;

1261 }

 

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

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

在结束这一节之前,让我们看一下,在lookup_member1327行的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 forconstructors or destructors in base classes. */

1048   if (IDENTIFIER_CTOR_OR_DTOR_P (lfi->name))

1049     returnNULL_TREE;

1050

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

1052     don't need tolook.  */

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

1054     returnNULL_TREE;

1055

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

1057   if (BINFO_DEPENDENT_BASE_P (binfo))

1058     returnNULL_TREE;

1059   

1060   return binfo;

1061 }

 

上面在1053行,binfo可能是在由lfi->rval_binfo支配的类层次树中的原始original_binfobinfo,或者是一个复制的binfo。对于复制的binfooriginal_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查找出来的结果不要求为该对象表达式的类中唯一的基类,只要被限定idqualified id)命名的实体是对象表达式的类的成员并且根据10.2没有二义性。

struct A {

int a;

};

struct B: virtualA { };

struct C: B { };

struct D: B { };

struct E: publicC, public D { };

struct F: publicA { };

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 aclass.  */

13816     if (CLASS_TYPE_P(object_type))

13817       /* If theOBJECT_TYPE is a template specialization, it may

13818         beinstantiated during name lookup. In that case, errors

13819         may be issued. Even if we rollback thecurrent 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 theenclosing 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_memberlookup_name_real都能保证找到的结果没有二义性。

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