GCC-3.4.6源代码学习笔记(116)
2010-10-19 11:25
441 查看
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
“名字屏蔽”系统地描述了名字屏蔽的规则。
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
。
在指定类中的查找
而如果指定的作用域是一个类,那么查找的就是除非静态数据成员以外的类成员。不过这里尚不检查是否有违反,这由外部调用它们的函数来检查(
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 )。 |
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
。
相关文章推荐
- GCC-3.4.6源代码学习笔记(22)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记(42)
- GCC-3.4.6源代码学习笔记(162)
- GCC-3.4.6源代码学习笔记(91)
- GCC-3.4.6源代码学习笔记(169)
- GCC-3.4.6源代码学习笔记(31)
- GCC-3.4.6源代码学习笔记(37)
- GCC-3.4.6源代码学习笔记(147)
- GCC-3.4.6源代码学习笔记(50)
- GCC-3.4.6源代码学习笔记(153)
- GCC-3.4.6源代码学习笔记(161)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(8)
- GCC-3.4.6源代码学习笔记(107)
- GCC-3.4.6源代码学习笔记(113)
- GCC-3.4.6源代码学习笔记(10续4)
- GCC-3.4.6源代码学习笔记(32)
- GCC-3.4.6源代码学习笔记(68)
- GCC-3.4.6源代码学习笔记(99)