GCC-3.4.6源代码学习笔记(145)
2011-01-15 11:24
459 查看
5.13.
解析后阶段
5.13.1.
预备知识—转换的细节
5.13.1.1.
确定合适的转换
C++是一个强类型语言。不过,在实践中,我们总是可以写出这样的代码:“
1 + 5.0f;
”,其中“
1
”
是整数类型,而“
5.0f
”是一个浮点类型。我们甚至可以写出更惊人的代码,像这样:“
a + b;
”,假定“
a
”及“
b
”都是某个类的实例。这是因为编译器将为我们产生执行必要、合适转换的代码。在这一节中,我们将看到编译器在背后使用的转换,及由语言标准所制定的转换规则。
我们首先从函数
can_convert_arg
开始,该函数用于测试两个指定的类型是否匹配。
5996
bool
5997
can_convert_arg
(tree to, tree from,
tree arg)
in
call.c
5998
{
5999
tree t = implicit_conversion
(to, from, arg, LOOKUP_NORMAL);
6000
return
(t
&& ! ICS_BAD_FLAG (t));
6001
}
由其名字所显示,由下面函数执行的转换,是编译器可以自由使用的,只要它觉得合适。
它是
C++
语言一个有趣及强大的特性;而且经常给程序员,甚至老鸟带来困惑。【
3
】,章节
13.3.3
.1
“隐含转换序列”详细解释了什么是隐式转换:
1. 一个隐式转换序列是,把一个函数调用中的一个实参转换到对应形参的类型的,转换序列。如条文 4 所定义,这个转换序列是一个隐式转换,这意味着它遵守对象初始化,及单个表达式引用( reference by a single expression )的规则( 8.5 , 8.5.3 )。 2. 隐式转换序列只关心实参的类型, cv- 限定( cv-qualification ),及左值性( lvalueness );以及如何转换这些来匹配形参的对应属性。其他属性,例如实参的生命周期,存储类别,对齐,或访问性,及实参是否是一个位域( bit-field ),都被忽略。因而,虽然对于一个指定的形参 - 实参对可以定义出一个隐式转换序列,在最后的分析中,该从实参到形参的转换仍可能被发现是错误的。 3. 一个良好的隐式转换序列是以下形式之一: — 一个标准转换序列( 13.3.3 .1.1 ), — 一个用户定义转换序列( 13.3.3 .1.2 ),或者 — 一个省略( ellipsis )转换序列( 13.3.3 .1.3 )。 4. 不过,当考虑由 13.3.1 .3 选定的用于一个类拷贝初始化第二步中临时对象拷贝,或由 13.3.1.4 , 13.3.1.5 ,或 13.3.1.6 中所有情况下选定的,一个用户定义转换函数的实参时,只允许标准转换序列及省略转换序列。 5. 在形参类型是一个引用的情况下,参见 13.3.3 .1.4. (引用绑定 reference binding ) 6. 当形参类型不是一个引用时,隐式转换序列从实参表达式塑造出形参的一个拷贝初始化。该隐式转换序列被要求把实参表达式转换到形参类型的一个右值。 [ 注意:当该形参是一个类类型,这是一个以条文 13 为目的的概念上的转换( this is a conceptual conversion defined for the purposes of clause 13 );事实上的初始化依据构造函数来定义,而不是一个转换 ] 。任何最上层的 cv- 限定上的差异,被初始化本身所包括,不会构成一个转换。 [ 例如:一个具有类型 A 的形参可以被一个具有类型 const A 的实参初始化。这个情形下的隐式转换序列是恒等序列( the identity sequence );从 const A 到 A ,不包含“转换” ] 。当形参具有一个类类型,并且实参表达式具有相同的类型,该隐式转换序列是一个恒等转换( identity conversion )。当形参具有一个类类型,而实参表达式具有一个派生类类型,隐式转换序列是一个派生类到基类的 derived-to-base 转换。 [ 注意:没有这样的标准转换;这个 derived-to-base 转换仅存在于隐式转换序列的描述中 ] 。一个 derived-to-base 转换具有转换等级( Conversion rank )( 13.3.3 .1.1 )。 7. 在所有的上下文中,当转换到隐含对象形参,或转换到一个赋值操作的左侧操作数时, 仅允许不构建用于结果的临时对象的标准转换序列。 8. 如果匹配一个实参到一个形参类型不要求转换,这个隐式转换序列是包含恒等转换的标准转换序列( 13.3.3 .1.1 )。 9. 如果不能找到一个转换序列来转换一个实参到形参的类型,或者该转换是错误的,则不能形成隐式转换序列。 10. 如果存在多个不同的转换序列把实参转换到形参的类型,与该形参关联的隐式转换序列被定义为显示出二义性转换序列的唯一的转换序列( the unique conversion sequence designated the ambiguous conversion sequence )。出于以 13.3.3 .2 中所描述的隐式转换排名的目的,二义性转换序列被作为用户定义序列来处理,即与其他用户定义转换序列无法区分(二义性转换序列被安排做与用户定义转换序列等级相同,是因为对于一个实参,仅当涉及不同的用户定义转换时,才可能存在多个转换序列。二义性转换序列与其他用户转换序列不可区分,在于它至少代表了 2 个用户定义转换序列,每个具有不同的用户定义转换,而其他用户定义转换序列必然与其中至少一个不能区分。 这个规则防止一个函数因为其某个形参的二义性转换序列,而成为不可行。考虑这个例子, class B; class A { A (B&); }; class B { operator A (); }; class C { C (B&); }; void f(A) { } void f(C) { } B b; f(b); // 二义性的,因为 b -> C 通过构造函数,而 // b -> A 通过构造函数或转换函数 如果没有这个规则,对于调用 f(b) , f(A) 将被取消作为可行函数,从而导致重载解析选择 f(C) 作为实际的调用,尽管显然地,它不是最佳选择。另一方面,如果声明了一个 f(B) ,那么 f(b) 将被解析为 f(B) ,因为与 f(B) 的完全匹配优于匹配 f(A) 所要求的序列。 如果一个使用二义性转换序列的函数被选择为最佳可行函数,该调用将是错误的,因为该调用中某个实参的转换是有二义性的。 11. 上面提及的隐式转换序列的 3 种形式定义在以下子条文中。 |
lvalue
)及右值(
rvalue
)的概念。一个左值是指一个对象或函数。它必须是一个可取值的实体。即如果它是指对象的话,该对象应该能够被放在一个赋值操作的左手侧(这也是为什么它被称为左值)。而非左值的就被称为右值(它们不能用在赋值操作的左手侧)。
1097
static
tree
1098
implicit_conversion
(tree to, tree from, tree expr, int flags)
in call.c
1099
{
1100
tree conv;
1101
1102
if (from == error_mark_node
|| to == error_mark_node
1103
|| expr ==
error_mark_node)
1104
return
NULL_TREE;
1105
1106
if (TREE_CODE (to) ==
REFERENCE_TYPE)
1107
conv = reference_binding
(to, from, expr, flags);
1108
else
1109
conv = standard_conversion
(to, from, expr, flags);
1110
1111
if (conv)
1112
return
conv;
1113
1114
if (expr != NULL_TREE
1115
&& (IS_AGGR_TYPE
(from)
1116
|| IS_AGGR_TYPE
(to))
1117
&& (flags &
LOOKUP_NO_CONVERSION) == 0)
1118
{
1119
struct
z_candidate
*cand;
1120
1121
cand = build_user_type_conversion_1
1122
(to, expr,
LOOKUP_ONLYCONVERTING);
1123
if (cand)
1124
conv =
cand->second_conv;
1125
1126
/*
We used to try to bind a reference to a temporary here, but that
1127
now
handled by the recursive call to this function at the end
1128
of
reference_binding.
*/
1129
return
conv;
1130
}
1131
1132
return
NULL_TREE;
1133
}
看到转换处理函数可能会相互递归,在这里,为了处理引用类型,该函数再一次调用了
reference_binding
。不过,因为我们正在表达式的树中前进,只要没有回环的依赖,就不会有无限递归。因为
C++
是要求使用前必须声明的语言,相互依赖是非法的;解析器应该能够找出这个非法的形式。
5.13.1.1.1.
标准转换序列
【
3
】章节
13.3.3
.1.1
“标准转换序列”给出关于序列的细节。
1. 表 9 总结了在条文 4 中定义的转换( “标准转换”,【 3 】的章节 4 )并划分为 4 个不相交的类别:左值转型( Lvalue Transformation ),限定调整( Qualification Adjustment ),提升( Promotion ),以及转换( Conversion )。 [ 注意:这些分类就左值性, cv- 限定性,及数据表达方面而言,是正交的:左值转型不会改变类型的 cv- 限定性及数据表达;限定调整不会改变类型的左值性及数据表达;而提升及转换不会改变类型的左值性及 cv- 限定性。 ] 2. [ 注意: 如条文 4 所描述,应该标准转换序列要么本身是恒等转换(即,没有转换),要么包含其他属于这 4 个类别的 1 到 3 个转换( consists of one to three conversions from the other four categories )。在单个标准转换序列中,每个类别最多允许一个转换。如果在该序列中有 2 个或以上的转换,这些转换以规范的次序应用:左值转型 ,提升 或转换 ,限定调整 。 —end note ] 3. 在表 9 中的每个转换都具有关联的等级(精确匹配,提升,或转换)。这些都用于评价标准转换序列( 13.3.3 .2 )。一个转换序列的等级通过考察序列中的每个转换的等级,及任意引用绑定的等级( rank of any reference binding )( 13.3.3.1.4 )来决定。如果任意一个具有转换等级,该序列就是转换等级;否则,如果任意一个具有提升等级,该序列就是提升等级;否则,该序列就是精确匹配等级。 表 9 : - 转换
|
472~479
行对重载的解析(在后面有关引用绑定的章节再来看它,记得
type_unknown_p
返回
true
,如果
expr
是一个重载)。还要记住下面的
standard_conversion
处理隐式转换,它只考虑上面提到的转换;千万不要把它与强制转换混淆。
456
static
tree
457
standard_conversion
(tree to, tree from,
tree expr, int flags)
in
call.c
458
{
459
enum
tree_code fcode, tcode;
460
tree conv;
461
bool fromref = false;
462
463
to = v (to);
464
if (TREE_CODE (from) == REFERENCE_TYPE)
465
{
466
fromref = true;
467
from = TREE_TYPE (from);
468
}
469
to = strip_top_quals (to);
470
from = strip_top_quals (from);
471
472
if ((TYPE_PTRFN_P (to) || TYPE_PTRMEMFUNC_P
(to))
473
&& expr && type_unknown_p
(expr))
474
{
475
expr = instantiate_type (to, expr,
tf_conv);
476
if (expr == error_mark_node)
477
return
NULL_TREE;
478
from = TREE_TYPE (expr);
479
}
480
481
fcode = TREE_CODE (from);
482
tcode = TREE_CODE (to);
483
484
conv = build1
(IDENTITY_CONV, from, expr);
485
486
if (fcode == FUNCTION_TYPE)
487
{
488
from = build_pointer_type
(from);
489
fcode = TREE_CODE (from);
490
conv = build_conv
(LVALUE_CONV, from, conv);
491
}
492
else if (fcode == ARRAY_TYPE)
493
{
494
from = build_pointer_type
(TREE_TYPE (from));
495
fcode = TREE_CODE (from);
496
conv = build_conv
(LVALUE_CONV, from, conv);
497
}
498
else if (fromref || (expr
&& lvalue_p
(expr)))
499
conv = build_conv
(RVALUE_CONV, from, conv);
500
501
/* Allow conversion
between `__complex__' data types.
*/
502
if (tcode == COMPLEX_TYPE && fcode ==
COMPLEX_TYPE)
503
{
504
/* The standard
conversion sequence to convert FROM to TO is
505
the standard
conversion sequence to perform componentwise
506
conversion.
*/
507
tree part_conv = standard_conversion
508
(TREE_TYPE (to), TREE_TYPE (from),
NULL_TREE, flags);
509
510
if (part_conv)
511
{
512
conv = build_conv
(TREE_CODE (part_conv), to, conv);
513
ICS_STD_RANK (conv) = ICS_STD_RANK
(part_conv);
514
}
515
else
516
conv = NULL_TREE;
517
518
return
conv;
519
}
520
521
if (same_type_p (from, to))
522
return
conv;
484
行为恒等转换构建了
IDENTITY_COV
。
*_CONV
节点的
type
表示转换的源类型,而它的第一个操作数是需要转换的表达式。因此转换序列将是一个大的嵌套的
*_CONV
节点,最上层的
*_CONV
是最后执行的,而最里层的是首先执行且永远是
IDENTITY_CONV
。
在前端的内部为转换定义了如下的等级,而不是如上面表
9
所定义的那些。注意到值越小表示等级越优先。
343
#define
IDENTITY_RANK
0
in
call.c
344
#define
EXACT_RANK
1
345
#define
PROMO_RANK
2
346
#define
STD_RANK
3
347
#define
PBOOL_RANK
4
348
#define
USER_RANK
5
349
#define
ELLIPSIS_RANK
6
350
#define
BAD_RANK
7
在内部可以产生的转换有:
IDENTITY_CONV
,
LVALUE_CONV
,
QUAL_CONV
,
STD_CONV
,
PTR_CONV
,
PMEM_CONV
,
BASE_CONV
,
REF_BIND
,
USER_CONV
,
AMBIG_CONV
,及
RVALUE_CONV
。
408
static
tree
409
build_conv
(enum
tree_code code, tree type, tree from)
in
call.c
410
{
411
tree t;
412
int rank = ICS_STD_RANK (from);
413
414
/* We can't use
buildl1 here because CODE could be USER_CONV, which
415
takes two
arguments. In that case, the caller is responsible for
416
filling in the
second argument.
*/
417
t
=
make_node
(code);
418
TREE_TYPE (t) = type;
419
TREE_OPERAND (t, 0) = from;
420
421
switch
(code)
422
{
423
case
PTR_CONV:
424
case
PMEM_CONV:
425
case
BASE_CONV:
426
case
STD_CONV:
427
if
(rank < STD_RANK)
428
rank = STD_RANK;
429
break
;
430
431
case
QUAL_CONV:
432
if (rank < EXACT_RANK)
433
rank = EXACT_RANK;
434
435
default
:
436
break
;
437
}
438
ICS_STD_RANK (t) = rank;
439
ICS_USER_FLAG (t) = (code == USER_CONV || ICS_USER_FLAG (from));
440
ICS_BAD_FLAG (t) = ICS_BAD_FLAG (from);
441
return
t;
442
}
在上面的函数里,
ICS_STD_RANK
将保存所见到的最大的等级值,在后面的章节我们将看到它的使用。
而在上面
standard_conversion
的
486
及
492
行处理函数到指针与数组到指针的转换,它们在【
3
】条文
4.2
“数组到指针转换”及条文
4.3
“函数到指针转换”中描述如下:
1. 具有类型“ array ofN T ”或“ array of unknown bound of T ”的一个左值或右值可以被转换到一个类型为“ pointer to T ”的右值。其结果是指向数组第一个元素的指针。 2. 一个非宽字符的字符串( 2.13.4 )可以被转换到一个类型为“ pointer to char ”的右值;一个宽字符的字符串可以被转换到一个类型为“ pointer to wchar_t ”的右值。在这两种情况中,其结果是指向数组第一个元素的指针。仅当目标类型是一个明确恰当的指针时,才考虑该转换;而当仅是一般的从左值到右值的转换时,不考虑该转换。 [ 注意:不推荐使用这个转换。参见附录 D 。 ] 出于在重载解析( 13.3.3.1.1 )中评估的目的,这个转换被视为一个跟有一个限定转换( 4.4 )的数组到指针的转换。 [ 例如:作为一个数组到指针转换, "abc" 被转换到“ pointer to const char ”;然后作为一个限定转换,转换到“ pointer to char ”。 ] |
1. 函数类型 T 的一个左值可以被转换到类型“ pointer to T ”的一个右值。其结果是指向该函数的指针。(这个转换不能应用于非静态成员函数,因为一个非静态成员函数的左值是无法得到的。) 2. [ 注意:参见 13.4 ,用于重载函数的补充规则。 ] |
1
,类型“
pointer to
T
”的右值表示该指针本身是不能修改的,但其内容可以改变。例如:
char a[10];
char *p = …;
a = p;
// a is
converted to rvalue of char*, assignment not allowed
*(a+1) = *p;
// object pointed
by a+1 is lvalue, it is OK
与下面的条文相比,这
2
个条文包含了指针类型的构建,前端必须能从其他左值转型中区分出这两种情况。因此前端为它们使用了
LVALUE_CONV
。
然后在
standard_conversion
中,如果满足在
498
行条件,需要实现【
3
】条文
4.1
“左值到右值转换”的条款
1
。这一次前端使用
RVALUE_CONV
。
LVALUE_CONV
与
RVALUE_CONV
的一个区别在于当构建
LVALUE_CONV
时,我们已经知道这个右值了(在
488
及
494
行构建的指针类型),而对于
RVALUE_CONV
,在这一点上,这个右值是未知的,在后面前端需要调用
decay_conversion
来执行真正的转换。
1. 一个非函数,非数组类型的左值( 3.10 )可以被转换到一个右值。如果 T 是一个未完成的类型,必须这个转换的程序就是错误的。如果该左值引用的对象不是一个类型 T 或从 T 派生类型的对象,或者该对象未初始化,必须这个转换的程序具有不确定的行为。如果 T 是非类类型,该右值的类型是 T 的非 cv 限定的版本。否则,该右值的类型是 T 。 [ 在 C++ 类中,右值可以具有 cv- 限定的类型(因为它们都是对象)。这不同于 ISO C ,在 ISO C 里,非左值不能是 cv- 限定的类型。 ] 2. 由左值表示的对象的值是右值的结果( The value contained in the object indicated by the lvalue is the rvalue result )。当在 sizeof ( 5.3.3 )的操作数中发生一个左值到右值的转换,包含在被引用对象中的值是不可访问的,因为这个操作符不会对其操作数求值。 |
ref
,它可以判断这个表达式是否为左值。看到上面为指针类型构建的
LVALUE_CONV
,该函数判定为右值。这个函数应该被仔细研究。
211
int
212
lvalue_p
(tree ref)
in
tree.c
213
{
214
return
215
(lvalue_p_1
(ref,
/*class rvalue ok*/
1) != clk_none);
216
}
而我们要区分的左值的类型如下。
2964
typedef
enum
cp_lvalue_kind {
in
cp-tree.h
2965
clk_none = 0,
/* Things that
are not an lvalue.
*/
2966
clk_ordinary = 1, /* An ordinary lvalue.
*/
2967
clk_class = 2,
/* An rvalue of
class-type.
*/
2968
clk_bitfield = 4, /* An lvalue for a bit-field.
*/
2969
clk_packed = 8
/* An lvalue for
a packed field.
*/
2970
} cp_lvalue_kind
;
在【
3
】,条文
3.10
(左值及右值)给出如下解释。
1. 任一表达式要么是左值,要么是右值。 2. 左值指一个对象或函数。一些右值表达式——它们具有类或 cv- 限定的类类型——也指向对象(调用构造函数或返回一个引用对象的类类型的函数的表达式,而且在这样的对象上可以调用成员函数,但这些表达式不是左值)。 3. [ 注意:某些内建操作符及函数调用会产生左值。 [ 例如:如果 E 是一个指针类型的表达式,那么 *E 是一个左值的表达式,引用 E 所指向的对象或函数。另一个例子,函数 int& f(); 产生一个左值,因此调用 f() 是一个左值表达式。 ]] 4. [ 注意:某些内建操作符期望左值的操作数。 [ 例如:内建的赋值操作符都期望其左侧操作数是左值 ] 。其他内建操作符产生右值,而一些则期望右值。 [ 例如:一元及二元操作符 + 期望右值的参数,并产生右值的结果 ] 。在条文 5 对每个内建操作符的讨论说明了它是否期望左值操作数,及它是否产生左值结果 ] 。 5. 调用一个不返回引用的函数的结果是一个右值。用户定义操作符是函数,这些操作符是否期望或产生左值,由其参数及返回类型决定。 6. 保存一个由到非引用类型的转换( cast )引致的临时对象的表达式是一个右值(这包括使用函数记号(即,显式类型转换, 5.2.3 )所显式创建的对象。 7. 在任何时候,一个左值出现在一个期望右值的上下文中,该左值被转换为一个右值;参见 4.1 , 4.2 ,及 4.3 。 8. 在 8.5.3 对引用初始化,及在 12.2 对临时对象的讨论,显示了在其他重要的上下文中左值及右值的行为。 9. 类右值可以有 cv- 限定的类型;非类右值总是非 cv- 限定的类型。右值应该总是具有完成的类型或 void 类型;除了这些类型。左值还可以具有未完成的类型。 10. 为了修改一个对象,该对象的一个左值是必要的;除了类类型的右值,在特定的环境下,可以用于修改其所指对象。 [ 例如:对一个对象调用成员函数( 9.3 )可以修改这个对象。 ] 11. 函数不可修改,但函数的指针是可修改的。 12. 一个未完成类型的指针是可修改的。在程序中的某一点,当所指向的类型完成,该指针所指向的对象亦可修改。 13. 一个 const- 限定的表达式的指称对象不应该被修改(通过这个表达式),除非它具有类类型,并且有一个可变( mutable )成分,该成分可以被修改( 7.1.5.1 )。 14. 如果一个表达式可以被用于修改它所引用的对象,该表达式被称为可修改。一个尝试通过一个不可修改的左值或右值表达式来修改对象的程序是不合法的。 15. 如果一个程序尝试,通过以下类型以外的一个左值,来访问一个对象的存储值,其行为是未不可预测的(这个列表的意图是指出那些一个对象可能或不可能被别名( alias )的环境: — 该对象的动态类型( dynamic type ), — 该对象的动态类型的一个 cv- 限定的版本, — 该对象的动态类型所对应的有符号或无符号类型, — 该对象的动态类型的一个 cv- 限定版本所对应的有符号或无符号类型, — 一个聚合或 union 类型,在其成员中包含上述类型之一(包括,递归地,一个子聚合或被包含的( contained ) union 的一个成员), — 该对象的动态类型的基类类型(可能有 cv- 限定), — 字符或无符号字符类型。 |
a.fa();
”,其中给定的对象可能是不可取址的(例如,在语句“
A().fa();
”中,“
A()
”返回了一个右值),非静态方法被认为是右值。另外,表达式“
A().fa();
”可以修改这个对象,因此如果不要求严格的左值(参数
treat_class_rvalues_as_lvalues
为
1
),“
A()
”可被视为左值。注意
156
行的
TARGET_EXPR
,它将封装刚才提及的“
A()
”返回的临时对象(注意
161
行的注释)。
62
static
cp_lvalue_kind
63
lvalue_p_1
(tree ref,
in
tree.c
64
int treat_class_rvalues_as_lvalues)
65
{
66
cp_lvalue_kind op1_lvalue_kind = clk_none;
67
cp_lvalue_kind op2_lvalue_kind = clk_none;
68
69
if (TREE_CODE (TREE_TYPE (ref)) ==
REFERENCE_TYPE)
70
return
clk_ordinary;
71
72
if (ref == current_class_ptr
)
73
return
clk_none;
74
75
switch
(TREE_CODE (ref))
76
{
77
/* preincrements and predecrements are valid
lvals, provided
78
what they refer
to are valid lvals.
*/
79
case
PREINCREMENT_EXPR:
80
case
PREDECREMENT_EXPR:
81
case
SAVE_EXPR:
82
case
UNSAVE_EXPR:
83
case
TRY_CATCH_EXPR:
84
case
WITH_CLEANUP_EXPR:
85
case
REALPART_EXPR:
86
case
IMAGPART_EXPR:
87
return
lvalue_p_1 (TREE_OPERAND (ref, 0),
88
treat_class_rvalues_as_lvalues);
89
90
case
COMPONENT_REF:
91
op1_lvalue_kind = lvalue_p_1
(TREE_OPERAND (ref, 0),
92
treat_class_rvalues_as_lvalues);
93
/* In an
expression of the form "X.Y", the packed-ness of the
94
expression
does not depend on "X".
*/
95
op1_lvalue_kind &= ~clk_packed;
96
/* Look at the member designator.
*/
97
if (!op1_lvalue_kind
98
/* The
"field" can be a FUNCTION_DECL or an OVERLOAD in some
99
situations.
*/
100
|| TREE_CODE (TREE_OPERAND (ref, 1))
!= FIELD_DECL)
101
;
102
else if (DECL_C_BIT_FIELD (TREE_OPERAND
(ref, 1)))
103
{
104
/* Clear the
ordinary bit. If this object was a class
105
rvalue we
want to preserve that information.
*/
106
op1_lvalue_kind &= ~clk_ordinary;
107
/* The lvalue
is for a bitfield.
*/
108
op1_lvalue_kind |= clk_bitfield;
109
}
110
else if (DECL_PACKED (TREE_OPERAND (ref,
1)))
111
op1_lvalue_kind |= clk_packed;
112
113
return
op1_lvalue_kind;
114
115
case
STRING_CST:
116
return
clk_ordinary;
117
118
case
VAR_DECL:
119
if (TREE_READONLY (ref) && !
TREE_STATIC (ref)
120
&& DECL_LANG_SPECIFIC (ref)
121
&& DECL_IN_AGGR_P (ref))
122
return
clk_none;
123
case
INDIRECT_REF:
124
case
ARRAY_REF:
125
case
PARM_DECL:
126
case
RESULT_DECL:
127
if (TREE_CODE (TREE_TYPE (ref)) !=
METHOD_TYPE)
128
return
clk_ordinary;
129
break
;
130
131
/* A currently unresolved scope ref.
*/
132
case
SCOPE_REF:
133
abort ();
134
case
MAX_EXPR:
135
case
MIN_EXPR:
136
op1_lvalue_kind = lvalue_p_1
(TREE_OPERAND (ref, 0),
137
treat_class_rvalues_as_lvalues);
138
op2_lvalue_kind = lvalue_p_1
(TREE_OPERAND (ref, 1),
139
treat_class_rvalues_as_lvalues);
140
break
;
141
142
case
COND_EXPR:
143
op1_lvalue_kind = lvalue_p_1
(TREE_OPERAND (ref, 1),
144
treat_class_rvalues_as_lvalues);
145
op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND
(ref, 2),
146
treat_class_rvalues_as_lvalues);
147
break
;
148
149
case
MODIFY_EXPR:
150
return
clk_ordinary;
151
152
case
COMPOUND_EXPR:
153
return
lvalue_p_1 (TREE_OPERAND (ref, 1),
154
treat_class_rvalues_as_lvalues);
155
156
case
TARGET_EXPR:
157
return
treat_class_rvalues_as_lvalues ? clk_class : clk_none;
158
159
case
CALL_EXPR:
160
case
VA_ARG_EXPR:
161
/* Any
class-valued call would be wrapped in a TARGET_EXPR.
*/
162
return
clk_none;
163
164
case
FUNCTION_DECL:
165
/* All
functions (except non-static-member functions) are
166
lvalues.
*/
167
return
(DECL_NONSTATIC_MEMBER_FUNCTION_P (ref)
168
? clk_none : clk_ordinary);
169
170
case
NON_DEPENDENT_EXPR:
171
/* We must
consider NON_DEPENDENT_EXPRs to be lvalues so that
172
things like
"&E" where "E" is an expression with a
173
non-dependent
type work. It is safe to be lenient because an
174
error will be
issued when the template is instantiated if "E"
175
is not an
lvalue.
*/
176
return
clk_ordinary;
177
178
default
:
179
break
;
180
}
181
182
/* If one operand is
not an lvalue at all, then this expression is
183
not an
lvalue.
*/
184
if (!op1_lvalue_kind || !op2_lvalue_kind)
185
return
clk_none;
186
187
/* Otherwise, it's
an lvalue, and it has all the odd properties
188
contributed by
either operand.
*/
189
op1_lvalue_kind = op1_lvalue_kind |
op2_lvalue_kind;
190
/* It's not an
ordinary lvalue if it involves either a bit-field or
191
a class
rvalue.
*/
192
if ((op1_lvalue_kind & ~clk_ordinary) !=
clk_none)
193
op1_lvalue_kind &= ~clk_ordinary;
194
return
op1_lvalue_kind;
195
}
上面的
NON_DEPENDENT_EXPR
是用于非类型依赖,但出现在模板中的表达式的占位符。看到
INDIRECT_REF
是左值(不过指针本身是右值,它是上面条款
3
所描述的情况);而普通的变量也是左值(
118
行);另外如果数组被引用,其引用是左值,否则该数组将被衰退为右值的指针类型。接着注意
149
行的
MODIFY_EXPR
,它毫无疑问是左值,而随后的
COMPOUND_EXPR
依赖于其第二个操作数。而对于可能包含左值操作数的表达式,
lvalue_p_1
递归入操作数。
值得注意的是,“
int& f();
”的调用表达式“
f();
”是一个左值,但是像“
f() = 5;
”这样的表达式是非法的;这个左值可以被直接使用的情况是把“
f()
”用作参数,
125
行的
PARM_DECL
覆盖了这个用法;因此不在
PARM_DECL
里的
CALL_EXPR
被视为右值。另外,
PARM_DECL
,
RESULT_DECL
,
ARRAY_REF
,
INDIRECT_REF
作为左值,其类型不能是类的非静态方法。
standard_conversion (continue)
524
if ((tcode == POINTER_TYPE ||
TYPE_PTR_TO_MEMBER_P (to))
525
&& expr && null_ptr_cst_p
(expr))
526
conv = build_conv
(STD_CONV, to, conv);
527
else if (tcode == POINTER_TYPE &&
fcode == POINTER_TYPE
528
&& TREE_CODE (TREE_TYPE (to))
== VECTOR_TYPE
529
&& TREE_CODE (TREE_TYPE (from))
== VECTOR_TYPE
530
&& ((*targetm
.vector_opaque_p) (TREE_TYPE
(to))
531
|| (*targetm
.vector_opaque_p)
(TREE_TYPE (from))))
532
conv = build_conv
(STD_CONV, to, conv);
533
else
if ((tcode == INTEGER_TYPE && fcode == POINTER_TYPE)
534
|| (tcode == POINTER_TYPE && fcode == INTEGER_TYPE))
535
{
536
/* For backwards
brain damage compatibility, allow interconversion of
537
pointers and
integers with a pedwarn.
*/
538
conv = build_conv
(STD_CONV, to, conv);
539
ICS_BAD_FLAG (conv) = 1;
540
}
541
else if (tcode == ENUMERAL_TYPE &&
fcode == INTEGER_TYPE)
542
{
543
/* For backwards
brain damage compatibility, allow interconversion of
544
enums and
integers with a pedwarn.
*/
545
conv = build_conv
(STD_CONV, to, conv);
546
ICS_BAD_FLAG (conv) = 1;
547
}
注意上面,指针与整数及整数与枚举值之间的转换,在
C++
的语言环境中,都是不良转换(不过在
C
下,仅会给出警告)。因此这些转换会被记录,并给予最低的等级。
standard_conversion (continue)
548
else if ((tcode == POINTER_TYPE &&
fcode == POINTER_TYPE)
549
|| (TYPE_PTRMEM_P (to) &&
TYPE_PTRMEM_P (from)))
550
{
551
tree to_pointee;
552
tree from_pointee;
553
554
if (tcode == POINTER_TYPE
555
&&
same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (from),
556
TREE_TYPE (to)))
557
;
558
else if (VOID_TYPE_P (TREE_TYPE (to))
559
&& !TYPE_PTRMEM_P (from)
560
&& TREE_CODE (TREE_TYPE
(from)) != FUNCTION_TYPE)
561
{
562
from = build_pointer_type
563
(cp_build_qualified_type
(void_type_node,
564
cp_type_quals (TREE_TYPE (from))));
565
conv = build_conv
(PTR_CONV, from, conv);
566
}
567
else if (TYPE_PTRMEM_P (from))
568
{
569
tree fbase = TYPE_PTRMEM_CLASS_TYPE
(from);
570
tree tbase = TYPE_PTRMEM_CLASS_TYPE (to);
571
572
if (DERIVED_FROM_P (fbase, tbase)
573
&&
(same_type_ignoring_top_level_qualifiers_p
574
(TYPE_PTRMEM_POINTED_TO_TYPE (from),
575
TYPE_PTRMEM_POINTED_TO_TYPE
(to))))
576
{
577
from = build_ptrmem_type (tbase,
578
TYPE_PTRMEM_POINTED_TO_TYPE (from));
579
conv = build_conv
(PMEM_CONV, from, conv);
580
}
581
else if (!same_type_p (fbase, tbase))
582
return
NULL;
583
}
584
else if (IS_AGGR_TYPE (TREE_TYPE (from))
585
&& IS_AGGR_TYPE (TREE_TYPE
(to))
586
/* [conv.ptr]
587
588
An rvalue of
type "pointer to cv D," where D is a
589
class type,
can be converted to an rvalue of type
590
"pointer
to cv B," where B is a base class (clause
591
_class.derived_) of D. If B is an inaccessible
592
(clause
_class.access_) or ambiguous
593
(_class.member.lookup_) base class of D, a program
594
that
necessitates this conversion is ill-formed.
*/
595
/* Therefore,
we use DERIVED_FROM_P, and not
596
ACESSIBLY_UNIQUELY_DERIVED_FROM_P,
in this test.
*/
597
&& DERIVED_FROM_P (TREE_TYPE
(to), TREE_TYPE (from)))
598
{
599
from =
600
cp_build_qualified_type (TREE_TYPE
(to),
601
cp_type_quals
(TREE_TYPE (from)));
602
from = build_pointer_type
(from);
603
conv = build_conv
(PTR_CONV, from, conv);
604
}
605
606
if (tcode == POINTER_TYPE)
607
{
608
to_pointee = TREE_TYPE (to);
609
from_pointee = TREE_TYPE (from);
610
}
611
else
612
{
613
to_pointee = TYPE_PTRMEM_POINTED_TO_TYPE
(to);
614
from_pointee =
TYPE_PTRMEM_POINTED_TO_TYPE (from);
615
}
616
617
if (same_type_p (from, to))
618
/* OK */
;
619
else if (comp_ptr_ttypes (to_pointee,
from_pointee))
620
conv = build_conv
(QUAL_CONV, to, conv);
621
else if (expr && string_conv_p (to,
expr, 0))
622
/* converting
from string constant to char *.
*/
623
conv = build_conv
(QUAL_CONV, to, conv);
624
else if (ptr_reasonably_similar
(to_pointee, from_pointee))
625
{
626
conv = build_conv
(PTR_CONV, to, conv);
627
ICS_BAD_FLAG (conv) = 1;
628
}
629
else
630
return
0;
631
632
from = to;
633
}
同样在【
3
】条文
4.10
“指针转换”中,有以下段落。并注意到在函数的
499
行把左值转换为右值,上面的
conv
保存了这个转换。
1. 一个空指针常量是一个整型常量表达式( 5.19 )的右值,它被评估为整形值 0 。一个空指针常量可以被转换到一个指针类型;其结果是这个类型的空指针值,并且可以与其它指向对象或指向函数的指针值区分开来。 2 个相同类型的空指针值应该是相等的。一个空指针常量到 cv- 限定类型指针的转换是单个转换,而不是一个包含指针转换再加上限定转换( 4.4 )的转换序列。 2. 类型“ pointer to cv T ”,其中 T 是一个对象类型,的一个右值,可以被转换到类型“ pointer to cv void ”的一个右值。其结果指向类型 T 的对象所在内存位置的开头,仿佛该对象是类型 T 作为最后派生类的对象( most derived object (1.8) of type T )(即,不是作为基类子对象)。 3. 类型“ pointer to cv D ”,其中 D 是一个类类型,的一个右值,可以被转换到类型“ pointer to cv B ”,其中 B 是 D 的一个基类(条文 10 ),的一个右值。如果 B 是 D 的一个不可访问(条文 11 )或有二义性( 10.2 )的基类,必须这个转换的程序是非法的。转换的结果是指向派生类对象的基类子对象的指针。空指针值被转换为目标类型的空指针值。 |
1
由上面
526
行代码实现。它是单个
STD_CONV
。而条款
2
的条件由
558 ~ 560
行的代码来测试。
584 ~ 597
行的条件则实现条款
3
。
条文
4.11
“成员指针的转换”显示如下。
1. 一个空指针常量( 4.10 )可以被转换到成员指针;其结果是这个类型的空成员指针值,它与其它从非空指针常量构建的成员指针区分开来。两个相同类型的空成员指针应该是相等的。从一个空指针常量到具有 cv- 限定类型的成员指针的转换是单个转换,而不是包含成员指针转换,及限定转换( 4.4 )的转换序列。 2. 类型“ pointer to member of B of type cv T ”,其中 B 是一个类类型,的一个右值,可以被转换到类型“ pointer to member of D of type cv T ”,其中 D 是 B 的派生类(条文 10 ),的一个右值。如果 B 是 D 的一个不可访问(条文 11 ),或有二义性( 10.2 )或虚拟( 10.1 )的基类,必须这个转换的程序是非法的。转换的结果指向相同的成员,就像转换发生前的成员指针,不过它指向基类的成员,就好像它是派生类的一个成员。该结果指向 D 实例中 B 的成员。因为结果具有类型“ pointer to member of D of type cv T ”,它可以通过一个 D 对象解引用( dereference )。其结果相当于 B 的成员指针被 D 中 B 的子对象解引用。空成员指针值被转换到目标类型的空成员指针值。 [ 成员指针转换的规则(从基类成员指针到派生类成员指针)看起来与指向对象指针的规则相反(从派生类指针到基类指针)( 4.10 ,条文 10 )。为了确保类型安全,这个转换是必要的。注意到一个成员指针不是一个对象指针或函数指针,并且这些指针的转换规则不适用于成员指针。特别的,一个成员指针不能被转换到一个 void* 。 ] |
1
被上面
526
行的代码所覆盖。而条款
2
由
567
行的代码块所处理。来到
617
行,经过上面的转换序列,现在
from
及
to
应该或者是相同的类型,或者仅是
cv-
限定符的不同;否则,意味着没有可用的转换。
下面方法指针之间的转换类似于成员指针之间的转换。注意到
fromfn
及
tofn
分别是所指向的函数;
fbase
及
tbase
是各自的隐含的
this
指针。因此能执行的转换是:类型“
pointer to method of
B of type cv T
”,其中
B
是一个类类型,的一个右值,可用被转换到类型“
pointer to the
same
method of D of type cv T
”,其中
D
是
B
的一个派生类,的一个右值。并且看到在这里“相同”的含义要比重载中更严格些。
standard_conversion (continue)
634
else if (TYPE_PTRMEMFUNC_P (to) &&
TYPE_PTRMEMFUNC_P (from))
635
{
636
tree fromfn = TREE_TYPE
(TYPE_PTRMEMFUNC_FN_TYPE (from));
637
tree tofn = TREE_TYPE
(TYPE_PTRMEMFUNC_FN_TYPE (to));
638
tree fbase = TREE_TYPE (TREE_VALUE
(TYPE_ARG_TYPES (fromfn)));
639
tree tbase = TREE_TYPE (TREE_VALUE
(TYPE_ARG_TYPES (tofn)));
640
641
if (!DERIVED_FROM_P (fbase, tbase)
642
|| !same_type_p (TREE_TYPE (fromfn),
TREE_TYPE (tofn))
643
|| !compparms (TREE_CHAIN
(TYPE_ARG_TYPES (fromfn)),
644
TREE_CHAIN (TYPE_ARG_TYPES
(tofn)))
645
|| cp_type_quals (fbase) !=
cp_type_quals (tbase))
646
return
0;
647
648
from = cp_build_qualified_type (tbase,
cp_type_quals (fbase));
649
from = build_method_type_directly
(from,
650
TREE_TYPE
(fromfn),
651
TREE_CHAIN
(TYPE_ARG_TYPES (fromfn)));
652
from = build_ptrmemfunc_type (build_pointer_type
(from));
653
conv = build_conv
(PMEM_CONV, from, conv);
654
}
【
3
】条文
4.12
“布尔型转换”对以下的转换给出了指引。
1. 算术类型,枚举类型,指针类型,或成员指针类型的一个右值可以被转换为一个布尔类型的右值。一个 0 值,空指针值,或空成员指针值被转换为 false ;其他值被转换为 true 。 |
standard_conversion (continue)
655
else if (tcode == BOOLEAN_TYPE)
656
{
657
/* [conv.bool]
658
659
An rvalue of
arithmetic, enumeration, pointer, or pointer to
660
member type can
be converted to an rvalue of type bool.
*/
661
if (ARITHMETIC_TYPE_P (from)
662
||
fcode == ENUMERAL_TYPE
663
|| fcode == POINTER_TYPE
664
|| TYPE_PTR_TO_MEMBER_P (from))
665
{
666
conv = build_conv
(STD_CONV, to, conv);
667
if (fcode == POINTER_TYPE
668
|| TYPE_PTRMEM_P (from)
669
|| (TYPE_PTRMEMFUNC_P (from)
670
&& ICS_STD_RANK (conv) <
PBOOL_RANK))
671
ICS_STD_RANK (conv) = PBOOL_RANK;
672
return
conv;
673
}
674
675
return
NULL_TREE;
676
}
那么下面的代码处理由【
3
】,条文
4.5
“整型提升”,
4.6
“浮点型提升”,
4.7
“整型转换”,
4.8
“浮点型转换”,及
4.9
“浮点整型转换”所描述的转换。下面的段落是其细节。
1. 类型 char , signed char , unsigned char , short int ,或 unsigned short int 的一个右值可以被转换为类型 int 的一个右值,如果 int 可以表示源类型的所有值;否则,源右值可以被转换为类型 unsigned int 的一个右值。 2. 类型 wchar_t ( 3.9.1 )或枚举类型( 7.2 )的一个右值可以被转换为以下类型中第一个可以表示源类型所有值的类型的一个右值: int , unsigned int , long ,或 unsigned long 。 3. 一个整型位域( 9.6 )的右值可以被转换为类型 int 的一个右值,如果 int 可以表示该位域的所有值;否则,它可以被转换为类型 unsigned int ,如果 unsigned int 可以表示其所有值。如果位域还要大,不会对其应用整型提升。如果该位域具有枚举的类型,出于提升的目的,它亦被视为该类型的其他值。 4. 类型 bool 的一个右值可以被转换为类型 int 的一个右值, false 成为 0 而 true 成为 1 。 5. 这些转换被称为整型提升( integral promotion )。 |
1. 类型 float 的一个右值可以被转换为类型 double 的一个右值。其值不变。 2. 这个转换被称为浮点提升( floating point promotion )。 |
1. 一个整型的右值可以被转换为另一个整型的右值。一个枚举类型的右值可以被转换为一个整型的右值。 2. 如果目标类型是无符号的,其结果值是与源整数同余的( congruent )最小无符号整数。(模 2n ,其中 n 是用于表示该无符号类型的比特数)。 [ 注意:在一个 2 进制补码表示中,这个转换只是概念上的,位模式( bit pattern )没有变化(如果没有发生截断)。 ] 3. 如果目标类型是有符号的,值不会改变,如果目标类型(及位域宽度)能表示它;否则,其值取决于编译器实现。 4. 如果目标类型是 bool ,参见 4.12 。如果源类型是 bool ,值 false 被转换为 0 ,值 true 被转换为 1 。 5. 整形提升不包括在整形转换中。 |
1. 一个浮点类型的右值可以被转换到另一个浮点类型的右值。如果源值可以被目标类型精确表示,转换的结果就是这个精确表示。如果源值位于目标类型所能表示的 2 个相邻值之间,转换的结果依赖于编译器实现对两者的选择。否则,其行为是未定义的。 2. 浮点提升不包括在浮点转换中。 |
1. 一个浮点类型的右值可以被转换为一个整形的右值。该转换就是截断;即,小数部分被舍弃。如果截断后的值不能被目标类型表示,其行为是未定义的。 [ 注意:如果目标类型是 bool ,参见 4.12 。 ] 2. 一个整形或枚举类型的右值可以被转换为一个浮点类型的右值。如果可能,其结果是精确的。否则,依赖于编译器的实现,选择次高或次低的表示值。 [ 注意:如果该整数不能被该浮点类型的一个值精确表示,会发生精度丢失 ] 。如果源类型是 bool ,值 false 被转换为 0 而值 true 转换为 1 。 |
到
690
行的代码覆盖了上面所提及的所有的情形。因为
PROMO_RANK
要优于
STD_RANK
,编译器总是尽可能使用
PROMO_RANK
。
standard_conversion (continue)
677
/* We don't check
for ENUMERAL_TYPE here because there are no standard
678
conversions to
enum type.
*/
679
else if (tcode == INTEGER_TYPE || tcode ==
BOOLEAN_TYPE
680
|| tcode == REAL_TYPE)
681
{
682
if (! (INTEGRAL_CODE_P (fcode) || fcode ==
REAL_TYPE))
683
return
0;
684
conv = build_conv
(STD_CONV, to, conv);
685
686
/* Give this a
better rank if it's a promotion.
*/
687
if (same_type_p (to, type_promotes_to
(from))
688
&& ICS_STD_RANK (TREE_OPERAND
(conv, 0)) <= PROMO_RANK)
689
ICS_STD_RANK (conv) = PROMO_RANK;
690
}
691
else if (fcode == VECTOR_TYPE &&
tcode == VECTOR_TYPE
692
&& ((*targetm
.vector_opaque_p) (from)
693
|| (*targetm
.vector_opaque_p) (to)))
694
return
build_conv
(STD_CONV, to, conv);
695
else if (!(flags &
LOOKUP_CONSTRUCTOR_CALLABLE)
696
&& IS_AGGR_TYPE (to)
&& IS_AGGR_TYPE (from)
697
&& is_properly_derived_from
(from, to))
698
{
699
if (TREE_CODE (conv) == RVALUE_CONV)
700
conv = TREE_OPERAND (conv, 0);
701
conv = build_conv
(BASE_CONV, to, conv);
702
/* The
derived-to-base conversion indicates the initialization
703
of a parameter
with base type from an object of a derived
704
type. A
temporary object is created to hold the result of
705
the
conversion.
*/
706
NEED_TEMPORARY_P (conv) = 1;
707
}
708
else
709
return
0;
710
711
return
conv;
712
}
695
到
707
行的代码处理派生类到基类的转换,它由条文“隐式转换序列”的条款
6
所定义。
相关文章推荐
- GCC-3.4.6源代码学习笔记(47)
- GCC-3.4.6源代码学习笔记(64)
- GCC-3.4.6源代码学习笔记(15)
- GCC-3.4.6源代码学习笔记(148 - 续)
- GCC-3.4.6源代码学习笔记(124)
- GCC-3.4.6源代码学习笔记(181)
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(165)
- GCC-3.4.6源代码学习笔记(110)
- GCC-3.4.6源代码学习笔记(28)
- GCC-3.4.6源代码学习笔记 当前目录
- GCC-3.4.6源代码学习笔记(62)
- GCC-3.4.6源代码学习笔记(34)
- GCC-3.4.6源代码学习笔记(173)
- GCC-3.4.6源代码学习笔记(20)
- GCC-3.4.6源代码学习笔记(73)
- GCC-3.4.6源代码学习笔记(79)
- GCC-3.4.6源代码学习笔记(177)
- GCC-3.4.6源代码学习笔记(159)
- GCC-3.4.6源代码学习笔记(138)