5.13.1.2.3.1.1. From class to pointer
Conversion to pointers is interesting, it worthes a look. The function handling this conversion is cp_convert_to_pointer below. Class can only be converted to pointer type if it defines a user-defined conversion to do so.
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 }
Function build_type_conversion , and build_user_type_conversion have below definitions. Clearly, it searches the operator defined by user, and emits code to perform this conversion.
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. To void* or function pointer
Then below type is the target of the conversion, condition at line 106 is satisfied by type of void* or function pointer. And intype is the type of expression (expr ) below.
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 }
If intype is of type of method pointer, this conversion may be dangerous code; so gives warning about it. Then if expr is a PTRMEM_CST which is a pointer-to-member constants; it just takes the address of the method speicifed. However, for expr of pointer-to-member, it requires the implicit this argument in invoking get_member_function_from_ptrfunc to resolve the pointer. So it needs maybe_dummy_object to create the dummy instance of the type for the resolution.
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 }
First of all, sets up the corresponding context for the dummy object; if “this” pointer is available, just uses it as the dummy object; otherwise, builds a NULL pointer of the object by below function.
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. Between pointers of class
If both source and target types are pointers to class, they must have inheritance relation; otherwise it is an error. Then if the target type is pointer-to-method, converting other pointer type to it is not allowed. Then for case of between pointer-to-scalar and pointer-to-scalar, and case of between pointer-to-scalar and pointer-to-class, just builds NOP_EXPR for the conversion.
It includes case as [3] clause 5.2.10 “Reinterpret_cast”, terms 7 defines below:
7. A pointer to an object can be explicitly converted to a pointer to an object of different type. Except that converting an rvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. |
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. Between pointers-to-member
Below, TYPE_PTRMEM_P holds if it is a pointer to data-member of a class.
Note that when arriving here, the statement must pass the semantic checking during parsing the assignment; so TREE_TYPE (type) must match TREE_TYPE (intype) below. In above example, the conversion can be done implicitly except the conversion is from virtual base, which should only be executed by reinterpret_cast , as [3] clause 5.2.10 “Reinterpret_cast”, terms 3 defines: “ The mapping performed by reinterpret_cast is implementation-defined. [Note: it might, or might not, produce a representation different from the original value.] ”. GCC selects to do nothing for this kind of conversion involves virtual base. Consider below example:
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;
}
The compile gives below messages (it a violation of [3], clause 4.11 “pointer to member conversions”, terms 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’
The former two are issued at line 3944, 3946 in convert_like_real , the last one is given here.
If type and intype haven’t inheritant relation, note that lookup_base below at line 204 and 207 should return NULL (it would return error_mark_node when base is inaccessible or ambiguous), which is also only allowed by reinterpret_cast as below [3] clause 5.2.10 “Reinterpret_cast”:
9. An rvalue of type “pointer to member of X of type T1” can be explicitly converted to an rvalue of type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types. The null member pointer value (4.11) is converted to the null member pointer value of the destination type. The result of this conversion is unspecified , except in the following cases: — converting an rvalue of type “pointer to member function” to a different pointer to member function type and back to its original type yields the original pointer to member value. — converting an rvalue of type “pointer to data member of X of type T1” to the type “pointer to data member of Y of type T2” (where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer to member value. |
See the result is unspecified, that is why reinterpret_cast is a dangerous operator and should be used with care. For the case of type and intype haven’t inheritant relation,, GCC builds the NOP_EXPR at line 236. And note that if we can come here, the corresponding conversion expression must pass the semantics checking.
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);
And if those types have inheritant relation, the front-end needs adjust the class instances appropriately.
5.13.1.2.3.1.5. From pointers-to-method to other pointer type
Then below code handles the following cases related to reinterpret_cast .
4. A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined [Note: it is intended to be unsurprising to those who know the addressing structure of the underlying machine.] 5. A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined. 6. A pointer to a function can be explicitly converted to a pointer to a function of a different type. The effect of calling a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition of the function is undefined. Except that converting an rvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [Note: see also 4.10 for more details of pointer conversions.] 8. The null pointer value (4.10) is converted to the null pointer value of the destination type. |
Below type is the target type, and form should be slip of a pen of “from”. And note that pointer-to-member can’t be held by any integer type as it in fact contains two parts – the object and the member.
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 }
Now back to procedure of ocp_convert . Note e below comes from expr , so dtype at line 720 is the type of the expression; and code is the tree code of target type. Then if the target type is class type as line 729 indicates, the conversion is possible if the source type has inheritance relation with the target, or the source type defines user-defined conversion to the target type.
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 }