GCC-3.4.6源代码学习笔记(154)
2011-01-29 15:17
351 查看
5.13.1.2.3.1.
案例学习:到指针的转换
5.13.1.2.3.1.1.
从类到指针
到指针的转换是很有趣的,值得一看。处理这个转换的函数是下面的
cp_convert_to_pointer
。类可以被转换到指针类型,仅当它定义了一个这样做的用户定义转换。
76
static
tree
77
cp_convert_to_pointer
(tree type, tree
expr, bool force)
in
cvt.c
78
{
79
tree intype = TREE_TYPE (expr);
80
enum
tree_code form;
81
tree rval;
82
if (intype == error_mark_node)
83
return
error_mark_node;
84
85
if (IS_AGGR_TYPE (intype))
86
{
87
intype = complete_type
(intype);
88
if (!COMPLETE_TYPE_P (intype))
89
{
90
error ("can't convert from incomplete
type `%T' to `%T'",
91
intype, type);
92
return
error_mark_node;
93
}
94
95
rval = build_type_conversion
(type, expr);
96
if (rval)
97
{
98
if
(rval == error_mark_node)
99
error ("conversion of `%E' from `%T'
to `%T' is ambiguous",
100
expr, intype, type);
101
return
rval;
102
}
103
}
函数
build_type_conversion
,
build_user_type_conversion
的定义如下。显然它查找这个用户定义的转换操作符,并产生执行转换的代码。
995
tree
996
build_type_conversion
(tree xtype, tree
expr)
in
cvt.c
997
{
998
/* C++: check to
see if we can convert this aggregate type
999
into the required
type.
*/
1000
return
build_user_type_conversion
(xtype, expr,
LOOKUP_NORMAL);
1001
}
2522
tree
2523
build_user_type_conversion
(tree totype, tree expr, int flags)
in call.c
2524
{
2525
struct
z_candidate *cand
2526
= build_user_type_conversion_1
(totype, expr, flags);
2527
2528
if (cand)
2529
{
2530
if (TREE_CODE (cand->second_conv) ==
AMBIG_CONV)
2531
return
error_mark_node;
2532
return
convert_from_reference
(convert_like
(cand->second_conv, expr));
2533
}
2534
return
NULL_TREE;
2535
}
5.13.1.2.3.1.2.
到
void*
或函数指针
那么在下面的
type
是转换的目标类型,
106
行的条件为“
void*
”或函数指针的
type
所满足。而
intype
是表达式
expr
的类型。
cp_convert_to_pointer (continue)
105
/* Handle
anachronistic conversions from (::*)() to cv void* or (*)().
*/
106
if (TREE_CODE (type) == POINTER_TYPE
107
&& (TREE_CODE (TREE_TYPE (type))
== FUNCTION_TYPE
108
|| VOID_TYPE_P (TREE_TYPE (type))))
109
{
110
/* Allow an
implicit this pointer for pointer to member
111
functions.
*/
112
if (TYPE_PTRMEMFUNC_P (intype))
113
{
114
if
(pedantic
|| warn_pmf2ptr
)
115
pedwarn ("converting from `%T' to
`%T'", intype, type);
116
if
(TREE_CODE (expr) == PTRMEM_CST)
117
expr = build_address
(PTRMEM_CST_MEMBER (expr));
118
else
119
{
120
tree decl = maybe_dummy_object
(TYPE_PTRMEM_CLASS_TYPE (intype),
121
0);
122
decl = build_address (decl);
123
expr = get_member_function_from_ptrfunc
(&decl, expr);
124
}
125
}
126
else if (TREE_CODE (TREE_TYPE (expr)) ==
METHOD_TYPE)
127
{
128
if
(pedantic
|| warn_pmf2ptr
)
129
pedwarn ("converting from `%T' to
`%T'", intype, type);
130
expr = build_addr_func
(expr);
131
}
132
if (TREE_CODE (TREE_TYPE (expr)) ==
POINTER_TYPE)
133
return
build_nop (type, expr);
134
intype = TREE_TYPE (expr);
135
}
如果
intype
是方法指针的类型,这个转换可能是危险的代码;因此给出警告。而如果
expr
是一个
PTRMEM_CST
——一个成员指针常量,只需要获取这个成员的地址。不过,对于
expr
是指向方法的指针的情况,要求在调用
get_member_function_from_ptrfunc
中有隐含的
this
指针实参来解析这个指针。因而需要调用
maybe_dummy_object
来构建该类型用于解析的假的实例。
1717
tree
1718
maybe_dummy_object
(tree type, tree* binfop)
in
cp/tree.c
1719
{
1720
tree decl, context;
1721
tree binfo;
1722
1723
if (current_class_type
1724
&& (binfo = lookup_base
(current_class_type
, type,
1725
ba_ignore | ba_quiet, NULL)))
1726
context = current_class_type
;
1727
else
1728
{
1729
/*
Reference from a nested class member function.
*/
1730
context = type;
1731
binfo = TYPE_BINFO (type);
1732
}
1733
1734
if (binfop)
1735
*binfop = binfo;
1736
1737
if (current_class_ref
&&
context == current_class_type
1738
/*
Kludge: Make sure that current_class_type is actually
1739
correct. It might not be if we're in
the middle of
1740
tsubst_default_argument.
*/
1741
&& same_type_p
(TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref
)),
1742
current_class_type
))
1743
decl = current_class_ref
;
1744
else
1745
decl = build_dummy_object
(context);
1746
1747
return
decl;
1748
}
首先,为这个假的对象设立相应的上下文;如果“
this
”指针是可用的,就把它用作这个假对象;否则,通过下面的函数构建该对象的一个
NULL
指针。
1706
tree
1707
build_dummy_object
(tree type)
in
cp/tree.c
1708
{
1709
tree decl = build1
(NOP_EXPR, build_pointer_type
(type),
void_zero_node);
1710
return
build_indirect_ref
(decl, NULL);
1711
}
5.13.1.2.3.1.3.
在类指针之间
如果源类型及目标类型都是指向类的指针,它们必须有继承关系;否则就是一个错误。而如果目标类型是指向方法的指针,把其他类型的指针转换到它是不允许的。那么对于标量指针之间,及标量指针与类指针之间的转换,只需为该转换构建
NOP_EXPR
。
这包括了【
3
】条文
5.2.10
“
Reinterpret_cast
”,条款
7
所定义的情况:
cp_convert_to_pointer (continue)
137
if (expr == error_mark_node)
138
return
error_mark_node;
139
140
form = TREE_CODE (intype);
141
142
if (POINTER_TYPE_P (intype))
143
{
144
intype = TYPE_MAIN_VARIANT (intype);
145
146
if (TYPE_MAIN_VARIANT (type) != intype
147
&& TREE_CODE (type) == POINTER_TYPE
148
&& TREE_CODE (TREE_TYPE (type)) ==
RECORD_TYPE
149
&& IS_AGGR_TYPE (TREE_TYPE (type))
150
&& IS_AGGR_TYPE (TREE_TYPE (intype))
151
&& TREE_CODE (TREE_TYPE (intype)) ==
RECORD_TYPE)
152
{
153
enum
tree_code code = PLUS_EXPR;
154
tree binfo;
155
tree intype_class;
156
tree type_class;
157
bool same_p;
158
159
intype_class = TREE_TYPE (intype);
160
type_class = TREE_TYPE (type);
161
162
same_p = same_type_p (TYPE_MAIN_VARIANT
(intype_class),
163
TYPE_MAIN_VARIANT
(type_class));
164
binfo = NULL_TREE;
165
/* Try derived to base conversion.
*/
166
if
(!same_p)
167
binfo = lookup_base
(intype_class, type_class, ba_check, NULL);
168
if
(!same_p && !binfo)
169
{
170
/* Try base to derived conversion.
*/
171
binfo = lookup_base
(type_class, intype_class, ba_check, NULL);
172
code = MINUS_EXPR;
173
}
174
if
(binfo == error_mark_node)
175
return
error_mark_node;
176
if
(binfo || same_p)
177
{
178
if (binfo)
179
expr = build_base_path
(code, expr, binfo, 0);
180
/* Add any qualifier conversions.
*/
181
return
build_nop (type, expr);
182
}
183
}
184
185
if (TYPE_PTRMEMFUNC_P (type))
186
{
187
error ("cannot convert `%E' from type
`%T' to type `%T'",
188
expr, intype, type);
189
return
error_mark_node;
190
}
191
192
return
build_nop (type, expr);
193
}
5.13.1.2.3.1.4.
指向成员的指针之间
下面,
TYPE_PTRMEM_P
成立,如果这是一个指向数据成员的指针。
注意到当到达这里,该语句一定通过了解析过程中的语法检查;因此
TREE_TYPE (type)
必定匹配下面的
TREE_TYPE (intype)
。在上面的例子中,该转换可以被隐式地执行;除非该转换是自虚拟基类——这只能通过
reinterpret_cast
来完成,正如【
3
】条文
5.2.10
“
Reinterpret_cast
”,条款
3
定义的:“
由
reinterpret_cast
执行的映射是由实现定义的。
[
注意:它可能,或可能不,
产生一个不同于原始值的表达
]
”。
GCC
选择对于这种
自虚拟基类的
转换不做任何事。考虑下面的例子:
class
C {};
class
D {
public
:
C dc;
};
class
B: public
virtual
D {
public
:
C bc;
};
C* func (B* b) { return
&b->bc; }
int main () {
D d;
func (&d);
return
0;
}
编译器给出如下的消息(它违反了【
3
】条文
4.11
“成员指针的转换”,条款
2
):
test2.cpp: In function ‘int
main()’:
test2.cpp:17: error:
invalid conversion from ‘D*’ to ‘B*’
test2.cpp:17:
error:
initializing argument 1 of ‘C*
func(B*)’
test2.cpp:17: error:
cannot convert from base ‘D’ to derived type ‘B’ via virtual base ‘D’
前两个
error
是在
convert_like_real
的
3944
及
3946
行给出的;最后一个则是在这里。
如果
type
及
intype
没有继承关系,注意到下面在
204
及
207
行的
lookup_base
将返回
NULL
(如果基类是不可访问或具二义性,将返回
error_mark_node
),这也是仅为
reinterpret_cast
所允许的情形,如下面【
3
】的条文
5.2.10
“
Reinterpret_cast
”:
看到其结果是不确定的,这就是为什么
reinterpret_cast
是一个危险的操作符,它应该被小心使用。对于
type
及
intype
不具有继承关系的情形,
GCC
在
236
行为之构建了
NOP_EXPR
。并且注意到如果我们能来到这里,相应的转换表达式必定通过了语法检查。
cp_convert_to_pointer (continue)
194
else if (TYPE_PTRMEM_P (type) &&
TYPE_PTRMEM_P (intype))
195
{
196
tree b1;
197
tree b2;
198
tree binfo;
199
enum
tree_code code = PLUS_EXPR;
200
base_kind bk;
201
202
b1 = TYPE_PTRMEM_CLASS_TYPE (type);
203
b2 = TYPE_PTRMEM_CLASS_TYPE (intype);
204
binfo = lookup_base
(b1, b2, ba_check, &bk);
205
if (!binfo)
206
{
207
binfo = lookup_base
(b2, b1, ba_check, &bk);
208
code = MINUS_EXPR;
209
}
210
if (binfo == error_mark_node)
211
return
error_mark_node;
212
213
if (bk == bk_via_virtual)
214
{
215
if
(force)
216
warning ("pointer to member cast from
`%T' to `%T' is via virtual base",
217
intype, type);
218
else
219
{
220
error ("pointer to member cast from
`%T' to `%T' is via virtual base",
221
intype, type);
222
return
error_mark_node;
223
}
224
/* This is a reinterpret cast, whose result is unspecified.
225
We choose to do nothing.
*/
226
return
build1
(NOP_EXPR, type,
expr);
227
}
228
229
if (TREE_CODE (expr) == PTRMEM_CST)
230
expr = cplus_expand_constant (expr);
231
232
if (binfo && !integer_zerop (BINFO_OFFSET (binfo)))
233
expr =
size_binop
(code,
234
build_nop (sizetype, expr),
235
BINFO_OFFSET (binfo));
236
return
build_nop (type, expr);
237
}
238
else if (TYPE_PTRMEMFUNC_P (type) &&
TYPE_PTRMEMFUNC_P (intype))
239
return
build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
而如果这些类型具有继承关系,前端会相应地调整类实例。
5.13.1.2.3.1.5.
从成员函数指针到其它指针类型
那么下面的代码处理以下与
reinterpret_cast
相关的情形:
下面的
type
是目的类型,而
form
应该是“
from
”的笔误。注意到成员指针不能保存在任一整数类型中,因为事实上,它包含了两个部分——对象及成员。
cp_convert_to_pointer (continue)
240
else if (TYPE_PTRMEMFUNC_P (intype))
241
{
242
if (!warn_pmf2ptr
)
243
{
244
if
(TREE_CODE (expr) == PTRMEM_CST)
245
return
cp_convert_to_pointer
(type,
246
PTRMEM_CST_MEMBER (expr),
247
force);
248
else if (TREE_CODE (expr) == OFFSET_REF)
249
{
250
tree object = TREE_OPERAND (expr, 0);
251
return
get_member_function_from_ptrfunc
(&object,
252
TREE_OPERAND (expr, 1));
253
}
254
}
255
error ("cannot convert `%E' from type
`%T' to type `%T'",
256
expr, intype, type);
257
return
error_mark_node;
258
}
259
260
if (integer_zerop
(expr))
261
{
262
if (TYPE_PTRMEMFUNC_P (type))
263
return
build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
264
265
if (TYPE_PTRMEM_P (type))
266
/* A NULL
pointer-to-member is represented by -1, not by
267
zero.
*/
268
expr = build_int_2
(-1, -1);
269
else
270
expr = build_int_2
(0, 0);
271
TREE_TYPE (expr) = type;
272
/* Fix up the
representation of -1 if appropriate.
*/
273
force_fit_type
(expr, 0);
274
return
expr;
275
}
276
else if (TYPE_PTR_TO_MEMBER_P (type)
&& INTEGRAL_CODE_P (form))
277
{
278
error ("invalid conversion from '%T'
to '%T'", intype, type);
279
return
error_mark_node;
280
}
281
282
if (INTEGRAL_CODE_P (form))
283
{
284
if (TYPE_PRECISION (intype) == POINTER_SIZE)
285
return
build1
(CONVERT_EXPR, type, expr);
286
expr = cp_convert (c_common_type_for_size
(POINTER_SIZE, 0), expr);
287
/* Modes may be
different but sizes should be the same.
*/
288
if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE
(expr)))
289
!= GET_MODE_SIZE (TYPE_MODE (type)))
290
/* There is
supposed to be some integral type
291
that is the same width as a pointer.
*/
292
abort ();
293
return
convert_to_pointer (type, expr);
294
}
295
296
if (type_unknown_p (expr))
297
return
instantiate_type
(type, expr, tf_error |
tf_warning);
298
299
error ("cannot convert `%E' from type
`%T' to type `%T'",
300
expr, intype, type);
301
return
error_mark_node;
302
}
现在回到
ocp_convert
中的过程。注意下面的
e
来自
expr
,因此
720
行的
dtype
是表达式的类型;而
code
是目的类型的节点编码。那么如果目的类型是类类型,如
729
行所示,如果源类型与目的类型具有继承关系,或者源类型定义了到目的类型的转换操作符,这个转换是可能的。
ocp_convert
(continue)
705
(code == VECTOR_TYPE)
706
return
fold
(convert_to_vector (type, e));
707
if (code == REAL_TYPE || code ==
COMPLEX_TYPE)
708
{
709
if (IS_AGGR_TYPE (TREE_TYPE (e)))
710
{
711
tree rval;
712
rval = build_type_conversion (type, e);
713
if (rval)
714
return
rval;
715
else
716
if (flags & LOOKUP_COMPLAIN)
717
error ("`%#T' used where a
floating point value was expected",
718
TREE_TYPE (e));
719
}
720
if (code == REAL_TYPE)
710
return
fold (convert_to_real (type, e));
711
else if (code == COMPLEX_TYPE)
712
return
fold (convert_to_complex (type, e));
713
}
714
715
/* New C++
semantics: since assignment is now based on
716
memberwise
copying, if the rhs type is derived from the
717
lhs type, then we
may still do a conversion.
*/
718
if (IS_AGGR_TYPE_CODE (code))
719
{
720
tree dtype = TREE_TYPE (e);
721
tree ctor = NULL_TREE;
722
723
dtype = TYPE_MAIN_VARIANT (dtype);
724
725
/* Conversion
between aggregate types. New C++ semantics allow
726
objects of
derived type to be cast to objects of base type.
727
Old semantics only allowed this between
pointers.
728
729
There may be some ambiguity between using a
constructor
730
vs. using a type conversion operator when both
apply.
*/
731
732
ctor = e;
733
734
if (abstract_virtuals_error
(NULL_TREE, type))
735
return
error_mark_node;
736
737
if ((flags & LOOKUP_ONLYCONVERTING)
738
&& ! (IS_AGGR_TYPE (dtype)
&& DERIVED_FROM_P
(type, dtype)))
739
/* For
copy-initialization, first we create a temp of the proper type
740
with a user-defined conversion sequence,
then we direct-initialize
741
the
target with the temp (see [dcl.init]).
*/
742
ctor = build_user_type_conversion
(type, ctor,
flags);
743
else
744
ctor = build_special_member_call
(NULL_TREE,
745
complete_ctor_identifier
,
746
build_tree_list (NULL_TREE, ctor),
747
TYPE_BINFO
(type), flags);
748
if (ctor)
749
return
build_cplus_new
(type, ctor);
750
}
751
752
if (flags & LOOKUP_COMPLAIN)
753
error ("conversion from `%T' to
non-scalar type `%T' requested",
754
TREE_TYPE (expr), type);
755
if (flags & LOOKUP_SPECULATIVELY)
756
return
NULL_TREE;
757
return
error_mark_node;
758
}
案例学习:到指针的转换
5.13.1.2.3.1.1.
从类到指针
到指针的转换是很有趣的,值得一看。处理这个转换的函数是下面的
cp_convert_to_pointer
。类可以被转换到指针类型,仅当它定义了一个这样做的用户定义转换。
76
static
tree
77
cp_convert_to_pointer
(tree type, tree
expr, bool force)
in
cvt.c
78
{
79
tree intype = TREE_TYPE (expr);
80
enum
tree_code form;
81
tree rval;
82
if (intype == error_mark_node)
83
return
error_mark_node;
84
85
if (IS_AGGR_TYPE (intype))
86
{
87
intype = complete_type
(intype);
88
if (!COMPLETE_TYPE_P (intype))
89
{
90
error ("can't convert from incomplete
type `%T' to `%T'",
91
intype, type);
92
return
error_mark_node;
93
}
94
95
rval = build_type_conversion
(type, expr);
96
if (rval)
97
{
98
if
(rval == error_mark_node)
99
error ("conversion of `%E' from `%T'
to `%T' is ambiguous",
100
expr, intype, type);
101
return
rval;
102
}
103
}
函数
build_type_conversion
,
build_user_type_conversion
的定义如下。显然它查找这个用户定义的转换操作符,并产生执行转换的代码。
995
tree
996
build_type_conversion
(tree xtype, tree
expr)
in
cvt.c
997
{
998
/* C++: check to
see if we can convert this aggregate type
999
into the required
type.
*/
1000
return
build_user_type_conversion
(xtype, expr,
LOOKUP_NORMAL);
1001
}
2522
tree
2523
build_user_type_conversion
(tree totype, tree expr, int flags)
in call.c
2524
{
2525
struct
z_candidate *cand
2526
= build_user_type_conversion_1
(totype, expr, flags);
2527
2528
if (cand)
2529
{
2530
if (TREE_CODE (cand->second_conv) ==
AMBIG_CONV)
2531
return
error_mark_node;
2532
return
convert_from_reference
(convert_like
(cand->second_conv, expr));
2533
}
2534
return
NULL_TREE;
2535
}
5.13.1.2.3.1.2.
到
void*
或函数指针
那么在下面的
type
是转换的目标类型,
106
行的条件为“
void*
”或函数指针的
type
所满足。而
intype
是表达式
expr
的类型。
cp_convert_to_pointer (continue)
105
/* Handle
anachronistic conversions from (::*)() to cv void* or (*)().
*/
106
if (TREE_CODE (type) == POINTER_TYPE
107
&& (TREE_CODE (TREE_TYPE (type))
== FUNCTION_TYPE
108
|| VOID_TYPE_P (TREE_TYPE (type))))
109
{
110
/* Allow an
implicit this pointer for pointer to member
111
functions.
*/
112
if (TYPE_PTRMEMFUNC_P (intype))
113
{
114
if
(pedantic
|| warn_pmf2ptr
)
115
pedwarn ("converting from `%T' to
`%T'", intype, type);
116
if
(TREE_CODE (expr) == PTRMEM_CST)
117
expr = build_address
(PTRMEM_CST_MEMBER (expr));
118
else
119
{
120
tree decl = maybe_dummy_object
(TYPE_PTRMEM_CLASS_TYPE (intype),
121
0);
122
decl = build_address (decl);
123
expr = get_member_function_from_ptrfunc
(&decl, expr);
124
}
125
}
126
else if (TREE_CODE (TREE_TYPE (expr)) ==
METHOD_TYPE)
127
{
128
if
(pedantic
|| warn_pmf2ptr
)
129
pedwarn ("converting from `%T' to
`%T'", intype, type);
130
expr = build_addr_func
(expr);
131
}
132
if (TREE_CODE (TREE_TYPE (expr)) ==
POINTER_TYPE)
133
return
build_nop (type, expr);
134
intype = TREE_TYPE (expr);
135
}
如果
intype
是方法指针的类型,这个转换可能是危险的代码;因此给出警告。而如果
expr
是一个
PTRMEM_CST
——一个成员指针常量,只需要获取这个成员的地址。不过,对于
expr
是指向方法的指针的情况,要求在调用
get_member_function_from_ptrfunc
中有隐含的
this
指针实参来解析这个指针。因而需要调用
maybe_dummy_object
来构建该类型用于解析的假的实例。
1717
tree
1718
maybe_dummy_object
(tree type, tree* binfop)
in
cp/tree.c
1719
{
1720
tree decl, context;
1721
tree binfo;
1722
1723
if (current_class_type
1724
&& (binfo = lookup_base
(current_class_type
, type,
1725
ba_ignore | ba_quiet, NULL)))
1726
context = current_class_type
;
1727
else
1728
{
1729
/*
Reference from a nested class member function.
*/
1730
context = type;
1731
binfo = TYPE_BINFO (type);
1732
}
1733
1734
if (binfop)
1735
*binfop = binfo;
1736
1737
if (current_class_ref
&&
context == current_class_type
1738
/*
Kludge: Make sure that current_class_type is actually
1739
correct. It might not be if we're in
the middle of
1740
tsubst_default_argument.
*/
1741
&& same_type_p
(TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref
)),
1742
current_class_type
))
1743
decl = current_class_ref
;
1744
else
1745
decl = build_dummy_object
(context);
1746
1747
return
decl;
1748
}
首先,为这个假的对象设立相应的上下文;如果“
this
”指针是可用的,就把它用作这个假对象;否则,通过下面的函数构建该对象的一个
NULL
指针。
1706
tree
1707
build_dummy_object
(tree type)
in
cp/tree.c
1708
{
1709
tree decl = build1
(NOP_EXPR, build_pointer_type
(type),
void_zero_node);
1710
return
build_indirect_ref
(decl, NULL);
1711
}
5.13.1.2.3.1.3.
在类指针之间
如果源类型及目标类型都是指向类的指针,它们必须有继承关系;否则就是一个错误。而如果目标类型是指向方法的指针,把其他类型的指针转换到它是不允许的。那么对于标量指针之间,及标量指针与类指针之间的转换,只需为该转换构建
NOP_EXPR
。
这包括了【
3
】条文
5.2.10
“
Reinterpret_cast
”,条款
7
所定义的情况:
7. 指向一个对象的指针可用被显式地转换到一个不同类型的对象。除了转换类型为“ T1 指针类型”的一个右值到类型“ T2 指针类型”(其中 T1 及 T2 是对象类型,并且 T2 所要求的对齐不小于 T1 ),然后回到其初始类型,产生初始的指针值之外;这样的一个指针转换的结果是未定义的。 |
137
if (expr == error_mark_node)
138
return
error_mark_node;
139
140
form = TREE_CODE (intype);
141
142
if (POINTER_TYPE_P (intype))
143
{
144
intype = TYPE_MAIN_VARIANT (intype);
145
146
if (TYPE_MAIN_VARIANT (type) != intype
147
&& TREE_CODE (type) == POINTER_TYPE
148
&& TREE_CODE (TREE_TYPE (type)) ==
RECORD_TYPE
149
&& IS_AGGR_TYPE (TREE_TYPE (type))
150
&& IS_AGGR_TYPE (TREE_TYPE (intype))
151
&& TREE_CODE (TREE_TYPE (intype)) ==
RECORD_TYPE)
152
{
153
enum
tree_code code = PLUS_EXPR;
154
tree binfo;
155
tree intype_class;
156
tree type_class;
157
bool same_p;
158
159
intype_class = TREE_TYPE (intype);
160
type_class = TREE_TYPE (type);
161
162
same_p = same_type_p (TYPE_MAIN_VARIANT
(intype_class),
163
TYPE_MAIN_VARIANT
(type_class));
164
binfo = NULL_TREE;
165
/* Try derived to base conversion.
*/
166
if
(!same_p)
167
binfo = lookup_base
(intype_class, type_class, ba_check, NULL);
168
if
(!same_p && !binfo)
169
{
170
/* Try base to derived conversion.
*/
171
binfo = lookup_base
(type_class, intype_class, ba_check, NULL);
172
code = MINUS_EXPR;
173
}
174
if
(binfo == error_mark_node)
175
return
error_mark_node;
176
if
(binfo || same_p)
177
{
178
if (binfo)
179
expr = build_base_path
(code, expr, binfo, 0);
180
/* Add any qualifier conversions.
*/
181
return
build_nop (type, expr);
182
}
183
}
184
185
if (TYPE_PTRMEMFUNC_P (type))
186
{
187
error ("cannot convert `%E' from type
`%T' to type `%T'",
188
expr, intype, type);
189
return
error_mark_node;
190
}
191
192
return
build_nop (type, expr);
193
}
5.13.1.2.3.1.4.
指向成员的指针之间
下面,
TYPE_PTRMEM_P
成立,如果这是一个指向数据成员的指针。
注意到当到达这里,该语句一定通过了解析过程中的语法检查;因此
TREE_TYPE (type)
必定匹配下面的
TREE_TYPE (intype)
。在上面的例子中,该转换可以被隐式地执行;除非该转换是自虚拟基类——这只能通过
reinterpret_cast
来完成,正如【
3
】条文
5.2.10
“
Reinterpret_cast
”,条款
3
定义的:“
由
reinterpret_cast
执行的映射是由实现定义的。
[
注意:它可能,或可能不,
产生一个不同于原始值的表达
]
”。
GCC
选择对于这种
自虚拟基类的
转换不做任何事。考虑下面的例子:
class
C {};
class
D {
public
:
C dc;
};
class
B: public
virtual
D {
public
:
C bc;
};
C* func (B* b) { return
&b->bc; }
int main () {
D d;
func (&d);
return
0;
}
编译器给出如下的消息(它违反了【
3
】条文
4.11
“成员指针的转换”,条款
2
):
test2.cpp: In function ‘int
main()’:
test2.cpp:17: error:
invalid conversion from ‘D*’ to ‘B*’
test2.cpp:17:
error:
initializing argument 1 of ‘C*
func(B*)’
test2.cpp:17: error:
cannot convert from base ‘D’ to derived type ‘B’ via virtual base ‘D’
前两个
error
是在
convert_like_real
的
3944
及
3946
行给出的;最后一个则是在这里。
如果
type
及
intype
没有继承关系,注意到下面在
204
及
207
行的
lookup_base
将返回
NULL
(如果基类是不可访问或具二义性,将返回
error_mark_node
),这也是仅为
reinterpret_cast
所允许的情形,如下面【
3
】的条文
5.2.10
“
Reinterpret_cast
”:
9. 一个“指向具有类型 T1 的 X 成员的指针”的右值,可以被显式地转换到一个“指向具有类型 T2 的 Y 成员的指针”的右值,如果 T1 及 T2 都是函数类型或两者都是对象类型。空成员指针值( 4.11 )可以被转换到目的类型的空成员指针值。这个转换的结果是不确定的,除了以下情形以外: — 转换“成员函数指针”类型的一个右值到另外的成员函数指针类型,再转换回原始类型,产生原始的成员指针值。 — 转换 “指向具有类型 T1 的 X 成员的指针”类型的一个右值到“指向具有类型 T2 的 Y 成员的指针”的类型(其中 T2 的对齐要求不强于 T1 ( no stricter than )),再转换回原始类型,产生原始的成员指针值。 |
reinterpret_cast
是一个危险的操作符,它应该被小心使用。对于
type
及
intype
不具有继承关系的情形,
GCC
在
236
行为之构建了
NOP_EXPR
。并且注意到如果我们能来到这里,相应的转换表达式必定通过了语法检查。
cp_convert_to_pointer (continue)
194
else if (TYPE_PTRMEM_P (type) &&
TYPE_PTRMEM_P (intype))
195
{
196
tree b1;
197
tree b2;
198
tree binfo;
199
enum
tree_code code = PLUS_EXPR;
200
base_kind bk;
201
202
b1 = TYPE_PTRMEM_CLASS_TYPE (type);
203
b2 = TYPE_PTRMEM_CLASS_TYPE (intype);
204
binfo = lookup_base
(b1, b2, ba_check, &bk);
205
if (!binfo)
206
{
207
binfo = lookup_base
(b2, b1, ba_check, &bk);
208
code = MINUS_EXPR;
209
}
210
if (binfo == error_mark_node)
211
return
error_mark_node;
212
213
if (bk == bk_via_virtual)
214
{
215
if
(force)
216
warning ("pointer to member cast from
`%T' to `%T' is via virtual base",
217
intype, type);
218
else
219
{
220
error ("pointer to member cast from
`%T' to `%T' is via virtual base",
221
intype, type);
222
return
error_mark_node;
223
}
224
/* This is a reinterpret cast, whose result is unspecified.
225
We choose to do nothing.
*/
226
return
build1
(NOP_EXPR, type,
expr);
227
}
228
229
if (TREE_CODE (expr) == PTRMEM_CST)
230
expr = cplus_expand_constant (expr);
231
232
if (binfo && !integer_zerop (BINFO_OFFSET (binfo)))
233
expr =
size_binop
(code,
234
build_nop (sizetype, expr),
235
BINFO_OFFSET (binfo));
236
return
build_nop (type, expr);
237
}
238
else if (TYPE_PTRMEMFUNC_P (type) &&
TYPE_PTRMEMFUNC_P (intype))
239
return
build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
而如果这些类型具有继承关系,前端会相应地调整类实例。
5.13.1.2.3.1.5.
从成员函数指针到其它指针类型
那么下面的代码处理以下与
reinterpret_cast
相关的情形:
4. 一个指针可用被显式地转换到任意足够大保存它的整数类型。其映射函数是实现定义的 [ 注意:对于那些知道底层机器寻址结构的人来说,这不足为奇 ] 。 5. 一个整数类型或枚举类型的值可以被显式地转换到一个指针。一个指针转换到足够大小的一个整数(如果在实现中有这样对象的存在),然后转换回同样的指针类型,将得到其原始值;指针与整数映射的其他方面则是由实现确定的。 6. 指向一个函数的指针可用被显式地转换到指向另一个函数类型的指针。通过一个指向别的函数类型的指针( 8.3.5 )来调用这个函数,其行为是未定义的。除了把类型“ T1 指针”的一个右值转换到“ T2 指针”类型(其中 T1 及 T2 都是函数类型),然后转换回其原始类型,产生原始的指针值之外,这样的一个指针转换的结果是不确定的。 [ 注意:参考 4.10 ,关于更多指针转换的细节 ] 。 8. 空指针值( 4.10 )被转换到目的类型的空指针值。 |
type
是目的类型,而
form
应该是“
from
”的笔误。注意到成员指针不能保存在任一整数类型中,因为事实上,它包含了两个部分——对象及成员。
cp_convert_to_pointer (continue)
240
else if (TYPE_PTRMEMFUNC_P (intype))
241
{
242
if (!warn_pmf2ptr
)
243
{
244
if
(TREE_CODE (expr) == PTRMEM_CST)
245
return
cp_convert_to_pointer
(type,
246
PTRMEM_CST_MEMBER (expr),
247
force);
248
else if (TREE_CODE (expr) == OFFSET_REF)
249
{
250
tree object = TREE_OPERAND (expr, 0);
251
return
get_member_function_from_ptrfunc
(&object,
252
TREE_OPERAND (expr, 1));
253
}
254
}
255
error ("cannot convert `%E' from type
`%T' to type `%T'",
256
expr, intype, type);
257
return
error_mark_node;
258
}
259
260
if (integer_zerop
(expr))
261
{
262
if (TYPE_PTRMEMFUNC_P (type))
263
return
build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
264
265
if (TYPE_PTRMEM_P (type))
266
/* A NULL
pointer-to-member is represented by -1, not by
267
zero.
*/
268
expr = build_int_2
(-1, -1);
269
else
270
expr = build_int_2
(0, 0);
271
TREE_TYPE (expr) = type;
272
/* Fix up the
representation of -1 if appropriate.
*/
273
force_fit_type
(expr, 0);
274
return
expr;
275
}
276
else if (TYPE_PTR_TO_MEMBER_P (type)
&& INTEGRAL_CODE_P (form))
277
{
278
error ("invalid conversion from '%T'
to '%T'", intype, type);
279
return
error_mark_node;
280
}
281
282
if (INTEGRAL_CODE_P (form))
283
{
284
if (TYPE_PRECISION (intype) == POINTER_SIZE)
285
return
build1
(CONVERT_EXPR, type, expr);
286
expr = cp_convert (c_common_type_for_size
(POINTER_SIZE, 0), expr);
287
/* Modes may be
different but sizes should be the same.
*/
288
if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE
(expr)))
289
!= GET_MODE_SIZE (TYPE_MODE (type)))
290
/* There is
supposed to be some integral type
291
that is the same width as a pointer.
*/
292
abort ();
293
return
convert_to_pointer (type, expr);
294
}
295
296
if (type_unknown_p (expr))
297
return
instantiate_type
(type, expr, tf_error |
tf_warning);
298
299
error ("cannot convert `%E' from type
`%T' to type `%T'",
300
expr, intype, type);
301
return
error_mark_node;
302
}
现在回到
ocp_convert
中的过程。注意下面的
e
来自
expr
,因此
720
行的
dtype
是表达式的类型;而
code
是目的类型的节点编码。那么如果目的类型是类类型,如
729
行所示,如果源类型与目的类型具有继承关系,或者源类型定义了到目的类型的转换操作符,这个转换是可能的。
ocp_convert
(continue)
705
(code == VECTOR_TYPE)
706
return
fold
(convert_to_vector (type, e));
707
if (code == REAL_TYPE || code ==
COMPLEX_TYPE)
708
{
709
if (IS_AGGR_TYPE (TREE_TYPE (e)))
710
{
711
tree rval;
712
rval = build_type_conversion (type, e);
713
if (rval)
714
return
rval;
715
else
716
if (flags & LOOKUP_COMPLAIN)
717
error ("`%#T' used where a
floating point value was expected",
718
TREE_TYPE (e));
719
}
720
if (code == REAL_TYPE)
710
return
fold (convert_to_real (type, e));
711
else if (code == COMPLEX_TYPE)
712
return
fold (convert_to_complex (type, e));
713
}
714
715
/* New C++
semantics: since assignment is now based on
716
memberwise
copying, if the rhs type is derived from the
717
lhs type, then we
may still do a conversion.
*/
718
if (IS_AGGR_TYPE_CODE (code))
719
{
720
tree dtype = TREE_TYPE (e);
721
tree ctor = NULL_TREE;
722
723
dtype = TYPE_MAIN_VARIANT (dtype);
724
725
/* Conversion
between aggregate types. New C++ semantics allow
726
objects of
derived type to be cast to objects of base type.
727
Old semantics only allowed this between
pointers.
728
729
There may be some ambiguity between using a
constructor
730
vs. using a type conversion operator when both
apply.
*/
731
732
ctor = e;
733
734
if (abstract_virtuals_error
(NULL_TREE, type))
735
return
error_mark_node;
736
737
if ((flags & LOOKUP_ONLYCONVERTING)
738
&& ! (IS_AGGR_TYPE (dtype)
&& DERIVED_FROM_P
(type, dtype)))
739
/* For
copy-initialization, first we create a temp of the proper type
740
with a user-defined conversion sequence,
then we direct-initialize
741
the
target with the temp (see [dcl.init]).
*/
742
ctor = build_user_type_conversion
(type, ctor,
flags);
743
else
744
ctor = build_special_member_call
(NULL_TREE,
745
complete_ctor_identifier
,
746
build_tree_list (NULL_TREE, ctor),
747
TYPE_BINFO
(type), flags);
748
if (ctor)
749
return
build_cplus_new
(type, ctor);
750
}
751
752
if (flags & LOOKUP_COMPLAIN)
753
error ("conversion from `%T' to
non-scalar type `%T' requested",
754
TREE_TYPE (expr), type);
755
if (flags & LOOKUP_SPECULATIVELY)
756
return
NULL_TREE;
757
return
error_mark_node;
758
}
相关文章推荐
- GCC-3.4.6源代码学习笔记(86)
- GCC-3.4.6源代码学习笔记(164)
- GCC-3.4.6源代码学习笔记(114)
- GCC-3.4.6源代码学习笔记(31)
- GCC-3.4.6源代码学习笔记(117)
- GCC-3.4.6源代码学习笔记(37)
- GCC-3.4.6源代码学习笔记(50)
- GCC-3.4.6源代码学习笔记(131)
- GCC-3.4.6源代码学习笔记(123)
- GCC-3.4.6源代码学习笔记(127)
- GCC-3.4.6源代码学习笔记(77)
- GCC-3.4.6源代码学习笔记(42)
- GCC-3.4.6源代码学习笔记(136)
- GCC-3.4.6源代码学习笔记(109)
- GCC-3.4.6源代码学习笔记(139-续1)
- GCC-3.4.6源代码学习笔记(140)
- GCC-3.4.6源代码学习笔记(32)
- GCC-3.4.6源代码学习笔记(144)
- GCC-3.4.6源代码学习笔记(68)
- GCC-3.4.6源代码学习笔记(148)