GCC-3.4.6源代码学习笔记(154)
来源:互联网 发布:sql substr 编辑:程序博客网 时间:2024/06/10 03:49
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, treeexpr, bool force) incvt.c
78 {
79 tree intype = TREE_TYPE (expr);
80 enumtree_code form;
81 tree rval;
82 if (intype == error_mark_node)
83 returnerror_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 incompletetype `%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, treeexpr) incvt.c
997 {
998 /* C++: check tosee if we can convert this aggregate type
999 into the requiredtype. */
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 structz_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 returnNULL_TREE;
2535 }
5.13.1.2.3.1.2. 到void*或函数指针
那么在下面的type是转换的目标类型,106行的条件为“void*”或函数指针的type所满足。而intype是表达式expr的类型。
cp_convert_to_pointer (continue)
105 /* Handleanachronistic 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 animplicit 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) incp/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 inthe 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 returndecl;
1748 }
首先,为这个假的对象设立相应的上下文;如果“this”指针是可用的,就把它用作这个假对象;否则,通过下面的函数构建该对象的一个NULL指针。
1706 tree
1707 build_dummy_object(tree type) incp/tree.c
1708 {
1709 tree decl = build1(NOP_EXPR, build_pointer_type (type),void_zero_node);
1710 returnbuild_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),然后回到其初始类型,产生初始的指针值之外;这样的一个指针转换的结果是未定义的。
cp_convert_to_pointer (continue)
137 if (expr == error_mark_node)
138 returnerror_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 enumtree_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 returnbuild_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 ‘intmain()’:
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 returnbuild_nop (type, expr);
237 }
238 else if (TYPE_PTRMEMFUNC_P (type) &&TYPE_PTRMEMFUNC_P (intype))
239 returnbuild_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 returnerror_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 NULLpointer-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 therepresentation of -1 if appropriate. */
273 force_fit_type(expr, 0);
274 returnexpr;
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 returnerror_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 bedifferent 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 issupposed to be some integral type
291 that is the same width as a pointer. */
292 abort ();
293 returnconvert_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 returnerror_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 returnrval;
715 else
716 if (flags & LOOKUP_COMPLAIN)
717 error ("`%#T' used where afloating point value was expected",
718 TREE_TYPE (e));
719 }
720 if (code == REAL_TYPE)
710 returnfold (convert_to_real (type, e));
711 else if (code == COMPLEX_TYPE)
712 returnfold (convert_to_complex (type, e));
713 }
714
715 /* New C++semantics: since assignment is now based on
716 memberwisecopying, if the rhs type is derived from the
717 lhs type, then wemay 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 /* Conversionbetween aggregate types. New C++ semantics allow
726 objects ofderived type to be cast to objects of base type.
727 Old semantics only allowed this betweenpointers.
728
729 There may be some ambiguity between using aconstructor
730 vs. using a type conversion operator when bothapply. */
731
732 ctor = e;
733
734 if (abstract_virtuals_error(NULL_TREE, type))
735 returnerror_mark_node;
736
737 if ((flags & LOOKUP_ONLYCONVERTING)
738 && ! (IS_AGGR_TYPE (dtype)&& DERIVED_FROM_P (type, dtype)))
739 /* Forcopy-initialization, first we create a temp of the proper type
740 with a user-defined conversion sequence,then we direct-initialize
741 thetarget 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' tonon-scalar type `%T' requested",
754 TREE_TYPE (expr), type);
755 if (flags & LOOKUP_SPECULATIVELY)
756 returnNULL_TREE;
757 returnerror_mark_node;
758 }
- GCC-3.4.6源代码学习笔记(154)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- 第一次来到这里啊,求罩啊
- 我们的“抗日战争”
- 很浪费时间的三件事
- Welcome!
- poj 1026解题报告
- GCC-3.4.6源代码学习笔记(154)
- Felix 教你做字库——打印出手写效果,偷懒人士专用
- QT4版mini电话薄设计
- Studying note of GCC-3.4.6 source (154)
- Examsoon IBM 000-104認證考試題庫資訊
- 循序渐进学习使用WinPcap(一)
- Win32 API 使用通用的方法
- hi
- Hello