Studying note of GCC-3.4.6 source (162 - continue)
2011-02-19 11:44
337 查看
At line 5350 current_class_ptr
is the PARM_DECL for the `this'
pointer, when we're processing a member function. See that in below only the type
of instance
can be known for sure it returns non-null. Compared with condition at line
5281, which indicates a pointer, and in C++, it can be variant types in the
class hierarchy to support polymorphism. So it has to return NULL_TREE as
result.
5275
static
tree
5276
fixed_type_or_null
(tree instance, int*
nonnull, int* cdtorp)
in
class.c
5277
{
5278
switch
(TREE_CODE (instance))
5279
{
5280
case
INDIRECT_REF:
5281
if (POINTER_TYPE_P (TREE_TYPE (instance)))
5282
return
NULL_TREE;
5283
else
5284
return
fixed_type_or_null
(TREE_OPERAND
(instance, 0),
5285
nonnull, cdtorp);
5286
5287
case
CALL_EXPR:
5288
/* This is a
call to a constructor, hence it's never zero.
*/
5289
if (TREE_HAS_CONSTRUCTOR (instance))
5290
{
5291
if (nonnull)
5292
*nonnull = 1;
5293
return
TREE_TYPE (instance);
5294
}
5295
return
NULL_TREE;
5296
5297
case
SAVE_EXPR:
5298
/* This is a
call to a constructor, hence it's never zero.
*/
5299
if (TREE_HAS_CONSTRUCTOR (instance))
5300
{
5301
if (nonnull)
5302
*nonnull = 1;
5303
return
TREE_TYPE (instance);
5304
}
5305
return
fixed_type_or_null
(TREE_OPERAND (instance, 0),
nonnull, cdtorp);
5306
5307
case
RTL_EXPR:
5308
return
NULL_TREE;
5309
5310
case
PLUS_EXPR:
5311
case
MINUS_EXPR:
5312
if (TREE_CODE (TREE_OPERAND (instance,
0)) == ADDR_EXPR)
5313
return
fixed_type_or_null
(TREE_OPERAND
(instance, 0), nonnull, cdtorp);
5314
if (TREE_CODE (TREE_OPERAND (instance,
1)) == INTEGER_CST)
5315
/* Propagate
nonnull.
*/
5316
return
fixed_type_or_null
(TREE_OPERAND
(instance, 0), nonnull, cdtorp);
5317
return
NULL_TREE;
5318
5319
case
NOP_EXPR:
5320
case
CONVERT_EXPR:
5321
return
fixed_type_or_null
(TREE_OPERAND (instance, 0),
nonnull, cdtorp);
5322
5323
case
ADDR_EXPR:
5324
if (nonnull)
5325
*nonnull = 1;
5326
return
fixed_type_or_null
(TREE_OPERAND (instance, 0),
nonnull, cdtorp);
5327
5328
case
COMPONENT_REF:
5329
return
fixed_type_or_null
(TREE_OPERAND (instance, 1),
nonnull, cdtorp);
5330
5331
case
VAR_DECL:
5332
case
FIELD_DECL:
5333
if (TREE_CODE (TREE_TYPE (instance)) ==
ARRAY_TYPE
5334
&& IS_AGGR_TYPE (TREE_TYPE
(TREE_TYPE (instance))))
5335
{
5336
if (nonnull)
5337
*nonnull = 1;
5338
return
TREE_TYPE (TREE_TYPE (instance));
5339
}
5340
/* fall through...
*/
5341
case
TARGET_EXPR:
5342
case
PARM_DECL:
5343
case
RESULT_DECL:
5344
if (IS_AGGR_TYPE (TREE_TYPE (instance)))
5345
{
5346
if (nonnull)
5347
*nonnull = 1;
5348
return
TREE_TYPE (instance);
5349
}
5350
else if (instance == current_class_ptr
)
5351
{
5352
if (nonnull)
5353
*nonnull = 1;
5354
5355
/* if we're in a ctor or dtor, we know our
type.
*/
5356
if (DECL_LANG_SPECIFIC (current_function_decl
)
5357
&& (DECL_CONSTRUCTOR_P (current_function_decl
)
5358
|| DECL_DESTRUCTOR_P (current_function_decl
)))
5359
{
5360
if (cdtorp)
5361
*cdtorp = 1;
5362
return
TREE_TYPE (TREE_TYPE (instance));
5363
}
5364
}
5365
else if (TREE_CODE (TREE_TYPE (instance))
== REFERENCE_TYPE)
5366
{
5367
/* Reference
variables should be references to objects.
*/
5368
if (nonnull)
5369
*nonnull = 1;
5370
5371
/*
DECL_VAR_MARKED_P is used to prevent recursion; a
5372
variable's initializer
may refer to the variable
5373
itself.
*/
5374
if (TREE_CODE (instance) == VAR_DECL
5375
&& DECL_INITIAL (instance)
5376
&& !DECL_VAR_MARKED_P
(instance))
5377
{
5378
tree type;
5379
DECL_VAR_MARKED_P (instance) = 1;
5380
type = fixed_type_or_null
(DECL_INITIAL (instance),
5381
nonnull,
cdtorp);
5382
DECL_VAR_MARKED_P (instance) = 0;
5383
return
type;
5384
}
5385
}
5386
return
NULL_TREE;
5387
5388
default
:
5389
return
NULL_TREE;
5390
}
5391
}
Arriving here, fixed_type_p
is 0 if type of expr
is unknown for certainty
(polymorphism may be in used), or is -1 if expr
is constructor or destructor, otherwise is 1
as type is known for certainty. And v_binfo
is not NULL if there is virtual base involved.
build_base_path (continue)
293
if (want_pointer && !nonnull)
294
null_test = build (EQ_EXPR,
boolean_type_node, expr, integer_zero_node);
295
296
offset = BINFO_OFFSET (binfo);
If no vritual base found, offset
gotten at line 296 is all wanted. Code in
below then generates the expression (taking example 4 as instance in pseudo
code):
*(&b +
offset (A));
And if b
originally is a pointer, it will generate code to guard NULL
pointer too as below (taking example 5 as instance):
pa? (pa +
offset (A)) : 0;
build_base_path (continue)
350
target_type = code == PLUS_EXPR ?
BINFO_TYPE (binfo) : BINFO_TYPE (d_binfo);
351
352
target_type = cp_build_qualified_type
353
(target_type, cp_type_quals (TREE_TYPE
(TREE_TYPE (expr))));
354
ptr_target_type = build_pointer_type
(target_type);
355
if (want_pointer)
356
target_type = ptr_target_type;
357
358
expr = build1
(NOP_EXPR, ptr_target_type, expr);
359
360
if (!integer_zerop (offset))
361
expr = build
(code,
ptr_target_type, expr, offset);
362
else
363
null_test = NULL;
364
365
if (!want_pointer)
366
expr = build_indirect_ref
(expr, NULL);
367
368
if (null_test)
369
expr = build
(COND_EXPR, target_type, null_test,
370
build1
(NOP_EXPR, target_type, integer_zero_node),
371
expr);
372
373
return
expr;
374
}
However, if the conversion involves virtual base and expr
’s
dynamic type isn’t the same as static type, offset
gotten at line 296 is just the beginning.
build_base_path (continue)
298
if (v_binfo && fixed_type_p <= 0)
299
{
300
/* Going via
virtual base V_BINFO. We need the static offset
301
from V_BINFO to
BINFO, and the dynamic offset from D_BINFO to
302
V_BINFO. That
offset is an entry in D_BINFO's vtable.
*/
303
tree v_offset;
304
305
if (fixed_type_p < 0 && in_base_initializer
)
306
{
307
/* In a base
member initializer, we cannot rely on
308
the vtable
being set up. We have to use the vtt_parm.
*/
309
tree derived = BINFO_INHERITANCE_CHAIN
(v_binfo);
310
311
v_offset = build
(PLUS_EXPR, TREE_TYPE (current_vtt_parm
),
312
current_vtt_parm
, BINFO_VPTR_INDEX
(derived));
313
314
v_offset = build1
(INDIRECT_REF,
315
TREE_TYPE (TYPE_VFIELD
(BINFO_TYPE (derived))),
316
v_offset);
317
318
}
319
else
320
v_offset = build_vfield_ref
(build_indirect_ref (expr, NULL),
321
TREE_TYPE
(TREE_TYPE (expr)));
322
323
v_offset = build
(PLUS_EXPR, TREE_TYPE (v_offset),
324
v_offset,
BINFO_VPTR_FIELD (v_binfo));
325
v_offset = build1
(NOP_EXPR,
326
build_pointer_type (ptrdiff_type_node
),
327
v_offset);
328
v_offset = build_indirect_ref
(v_offset, NULL);
329
330
offset = convert_to_integer (ptrdiff_type_node
,
331
size_diffop (offset,
332
BINFO_OFFSET (v_binfo)));
333
334
if (!integer_zerop (offset))
335
v_offset = build
(code, ptrdiff_type_node
,
v_offset, offset);
336
337
if (fixed_type_p < 0)
338
/* Negative
fixed_type_p means this is a constructor or destructor;
339
virtual base layout is fixed in in-charge
[cd]tors, but not in
340
base
[cd]tors.
*/
341
offset = build
(COND_EXPR, ptrdiff_type_node
,
342
build
(EQ_EXPR, boolean_type_node,
343
current_in_charge_parm
, integer_zero_node),
344
v_offset,
345
BINFO_OFFSET (binfo));
346
else
347
offset = v_offset;
348
}
If there is virtual base between and it must use vtable to do the
conversion between the derived and the base, above at line 305 in
_base_initializer
is nonzero if it
is handling a base initializer, for which case vtable is not created. So it
needs use the placeholder current_vtt_parm
to indicate to involvement of
the vtable.
Function build_indirect_ref
builds INDIRECT_REF for
pointer type or reference type. For example, if p
is a pointer, then the
INDIRECT_REF node stands for the expression “*p”.
2028
tree
2029
build_indirect_ref
(tree ptr, const
char *errorstring)
in typeck.c
2030
{
2031
tree pointer, type;
2032
2033
if (ptr == error_mark_node)
2034
return
error_mark_node;
2035
2036
if (ptr == current_class_ptr
)
2037
return
current_class_ref
;
2038
2039
pointer = (TREE_CODE (TREE_TYPE (ptr)) ==
REFERENCE_TYPE
2040
? ptr : decay_conversion (ptr));
2041
type = TREE_TYPE (pointer);
2042
2043
if (TYPE_PTR_P (type) || TREE_CODE (type) ==
REFERENCE_TYPE)
2044
{
2045
/* [expr.unary.op]
2046
2047
If the type of the
expression is "pointer to T," the type
2048
of the result is
"T."
2049
2050
We must use the canonical
variant because certain parts of
2051
the back end, like fold, do
pointer comparisons between
2052
types.
*/
2053
tree t = canonical_type_variant (TREE_TYPE
(type));
2054
2055
if (VOID_TYPE_P (t))
2056
{
2057
/* A pointer to
incomplete type (other than cv void) can be
2058
dereferenced
[expr.unary.op]/1
*/
2059
error ("`%T' is not a
pointer-to-object type", type);
2060
return
error_mark_node;
2061
}
2062
else if (TREE_CODE (pointer) == ADDR_EXPR
2063
&& same_type_p (t, TREE_TYPE
(TREE_OPERAND (pointer, 0))))
2064
/* The POINTER
was something like `&x'.
We simplify
`*&x' to
2065
`x'.
*/
2066
return
TREE_OPERAND (pointer, 0);
2067
else
2068
{
2069
tree ref = build1
(INDIRECT_REF, t, pointer);
2070
2071
/* We *must*
set TREE_READONLY when dereferencing a pointer to const,
2072
so that we get the proper
error message if the result is used
2073
to assign to. Also, &*
is supposed to be a no-op.
*/
2074
TREE_READONLY (ref) = CP_TYPE_CONST_P
(t);
2075
TREE_THIS_VOLATILE (ref) =
CP_TYPE_VOLATILE_P (t);
2076
TREE_SIDE_EFFECTS (ref)
2077
= (TREE_THIS_VOLATILE (ref) ||
TREE_SIDE_EFFECTS (pointer));
2078
return
ref;
2079
}
2080
}
2081
/* `pointer' won't
be an error_mark_node if we were given a
2082
pointer to member, so it's
cool to check for this here.
*/
2083
else if (TYPE_PTR_TO_MEMBER_P (type))
2084
error ("invalid use of `%s' on pointer
to member", errorstring);
2085
else if (pointer != error_mark_node)
2086
{
2087
if (errorstring)
2088
error ("invalid type argument of
`%s'", errorstring);
2089
else
2090
error ("invalid type argument");
2091
}
2092
return
error_mark_node;
2093
}
As we have seen TYPE_VFIELD is the artificial field generated by the
compiler for class containing vtable. Now it also acts as a placeholder, it
will be replaced with the real address of vtable later.
115
tree
116
build_vfield_ref
(tree datum, tree type)
in
call.c
117
{
118
if (datum == error_mark_node)
119
return
error_mark_node;
120
121
if (TREE_CODE (TREE_TYPE (datum)) ==
REFERENCE_TYPE)
122
datum = convert_from_reference (datum);
123
124
if (TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (type)
125
&&
!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (datum), type))
126
datum = convert_to_base (datum, type, /*check_access=*/
false);
127
128
return
build
(COMPONENT_REF, TREE_TYPE (TYPE_VFIELD (type)),
129
datum, TYPE_VFIELD (type));
130
}
Remember BINFO_VPTR_FIELD at line 324 is set for virtual base, in
which is an INTEGER_CST indicating the index of the entry in the vtable
recording the offset of the virtual base from the base of the derived (why not
BINFO_OFFSET (vbase)? because C++ standard requires accessing virtual base by
help of BINFO_VPTR_FIELD).
Note that if binfo
is
derived by v_binfo
,
then offset
at line 330 gets the relative offset between these two bases as indicated by
below figure (the red
arrow
is the offset
gotten at line 330).
Then line 334 introduces a minor optimizaton, note that code
of
MINUS_EXPR with v_binfo
not NULL is not allowed and error message is given at line 280. So at line 335, v_offset
at right hand side refers to the binfo of the virtual base via vtable, and plus
offset
gotten at line 330, v_offset
at left hand side then points to the
binfo in interesting. Following offset
is updated accordingly to record the
offset into the most derived class.
For our example 5, expr
generated finally would be:
(pa + offset
(A))? (pa + offset (A)): 0;
Back into get_member_function_from_ptrfunc
,
instance_ptr
is now the above statement returned by build_base_path
. Consider following example,
it gives output “C::f” (note that in class C, vtable entry of f of B1, B2, and
A are all overrided as C::f with appropriate thunk, which give us promise
here):
class
A { public
:
example
- 6
virtual
A*
f () { printf ("A::f/n"); return
0; }
virtual
A*
f1 () { printf ("A::f1/n"); return
0;
}
virtual
~A() {}
};
class
B1 : virtual
public
A { public
:
virtual
B1* f1 () { printf
("B1::f1/n"); return
0; } };
class
B2 : virtual
public
A {};
class
C: public
B1, public
B2 { public
:
virtual C* f () { printf ("C::f/n"); return
0; } };
int main() {
B2 *pc = new
C; // no matter declare
pc as A*, B1*, B2*, or C*, get same result, as // they all derive from A, and
pfn is declared as within A
A* (A::*pfn) () = &B2::f; // same result, use either B1, B2, A, or C at rhs
(pc->*pfn)();
delete
pc;
return
0;
}
For this example, instance_ptr
holds the statement to adjust pa
from B2* to A* (“B2 *pc = new C;” carries a
pointer converted from C* to B2* already); and delta
below gotten at line 2357
records the offset determined by statement “A* (A::*pfn) () = &B2::f;”
(it is 0 because the statement indicate a
meaningless adjustment from A to A). Then by expression: “instance_ptr +
delta”, it locates the base that defining the function specified by the pointer
to method; then idx is the index into the vtable for the virtual function (or
function address converting in type of vtable for non-virtual function).
get_member_function_from_ptrfunc
(continue)
2383
/* ...and then
the delta in the PMF.
*/
2384
instance_ptr =
build
(PLUS_EXPR, TREE_TYPE (instance_ptr),
2385
instance_ptr, delta);
2386
2387
/* Hand back the
adjusted 'this' argument to our caller.
*/
2388
*instance_ptrptr = instance_ptr;
2389
2390
/* Next extract
the vtable pointer from the object.
*/
2391
vtbl = build1
(NOP_EXPR, build_pointer_type
(vtbl_ptr_type_node),
2392
instance_ptr);
2393
vtbl = build_indirect_ref
(vtbl, NULL);
2394
2395
/* Finally,
extract the function pointer from the vtable.
*/
2396
e2 = fold (build
(PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx));
2397
e2 = build_indirect_ref
(e2, NULL);
2398
TREE_CONSTANT (e2) = 1;
2399
2400
/* When using
function descriptors, the address of the
2401
vtable entry is treated as a
function pointer.
*/
2402
if (TARGET_VTABLE_USES_DESCRIPTORS)
2403
e2 = build1
(NOP_EXPR, TREE_TYPE (e2),
2404
build_unary_op (ADDR_EXPR, e2, /*noconvert=*/
1));
2405
2406
TREE_TYPE (e2) = TREE_TYPE (e3);
2407
e1 = build_conditional_expr (e1, e2, e3);
2408
2409
/* Make sure this
doesn't get evaluated first inside one of the
2410
branches of the
COND_EXPR.
*/
2411
if (instance_save_expr)
2412
e1 = build
(COMPOUND_EXPR, TREE_TYPE (e1),
2413
instance_save_expr, e1);
2414
2415
function = e1;
2416
}
2417
return
function;
2418
}
In section of class
layout, we have seen that vptr is always placed at the beginning of the class.
So the code snippet generated would be like below for example 5:
idx =
(vtable_index_type) pfn;
// pfn returned by PFN_FROM_PTRMEMFUNC
instance_ptr
= instance_ptr? instance_ptr + offset (A): 0;
(idx
& 1)? *(((vtbl_ptr_type_node) instance_ptr) + (idx-1)): pfn;
At this point, for a
pointer-to-method, we have known which function is expected, and expression to
locate the location of the function is ready and returned to build_addr_func
,
then immediately to build_function_call
. Note that function
below now holds the expression for locating the function and its type is the
pointer of the function.
build_function_call (continue)
2464
if (function == error_mark_node)
2465
return
error_mark_node;
2466
2467
fntype = TREE_TYPE (function);
2468
2469
if (TYPE_PTRMEMFUNC_P (fntype))
2470
{
2471
error ("must use .* or ->* to call
pointer-to-member function in `%E (...)'",
2472
original);
2473
return
error_mark_node;
2474
}
2475
2476
is_method = (TREE_CODE (fntype) == POINTER_TYPE
2477
&& TREE_CODE (TREE_TYPE
(fntype)) == METHOD_TYPE);
2478
2479
if (!((TREE_CODE (fntype) == POINTER_TYPE
2480
&& TREE_CODE (TREE_TYPE
(fntype)) == FUNCTION_TYPE)
2481
|| is_method
2482
|| TREE_CODE (function) == TEMPLATE_ID_EXPR))
2483
{
2484
error ("`%E' cannot be used as a
function", original);
2485
return
error_mark_node;
2486
}
2487
2488
/* fntype now gets
the type of function pointed to.
*/
2489
fntype = TREE_TYPE (fntype);
2490
2491
/* Convert the
parameters to the types declared in the
2492
function prototype, or apply
default promotions.
*/
2493
2494
coerced_params = convert_arguments
(TYPE_ARG_TYPES (fntype),
2495
params,
fndecl, LOOKUP_NORMAL);
2496
if (coerced_params == error_mark_node)
2497
return
error_mark_node;
2498
2499
/* Check for errors
in format strings.
*/
2500
2501
if (warn_format
)
2502
check_function_format (NULL,
TYPE_ATTRIBUTES (fntype), coerced_params);
2503
2504
/* Recognize
certain built-in functions so we can make tree-codes
2505
other than CALL_EXPR. We do
this when it enables fold-const.c
2506
to do something useful.
*/
2507
2508
if (TREE_CODE (function) == ADDR_EXPR
2509
&& TREE_CODE (TREE_OPERAND
(function, 0)) == FUNCTION_DECL
2510
&& DECL_BUILT_IN (TREE_OPERAND
(function, 0)))
2511
{
2512
result = expand_tree_builtin (TREE_OPERAND
(function, 0),
2513
params,
coerced_params);
2514
if (result)
2515
return
result;
2516
}
2517
2518
return
build_cxx_call
(function, params, coerced_params);
2519
}
So fntype
at line 2489 refers to the type of the function in used. Then it needs do
conversion for the arguments according to the parameters declaration.
is the PARM_DECL for the `this'
pointer, when we're processing a member function. See that in below only the type
of instance
can be known for sure it returns non-null. Compared with condition at line
5281, which indicates a pointer, and in C++, it can be variant types in the
class hierarchy to support polymorphism. So it has to return NULL_TREE as
result.
5275
static
tree
5276
fixed_type_or_null
(tree instance, int*
nonnull, int* cdtorp)
in
class.c
5277
{
5278
switch
(TREE_CODE (instance))
5279
{
5280
case
INDIRECT_REF:
5281
if (POINTER_TYPE_P (TREE_TYPE (instance)))
5282
return
NULL_TREE;
5283
else
5284
return
fixed_type_or_null
(TREE_OPERAND
(instance, 0),
5285
nonnull, cdtorp);
5286
5287
case
CALL_EXPR:
5288
/* This is a
call to a constructor, hence it's never zero.
*/
5289
if (TREE_HAS_CONSTRUCTOR (instance))
5290
{
5291
if (nonnull)
5292
*nonnull = 1;
5293
return
TREE_TYPE (instance);
5294
}
5295
return
NULL_TREE;
5296
5297
case
SAVE_EXPR:
5298
/* This is a
call to a constructor, hence it's never zero.
*/
5299
if (TREE_HAS_CONSTRUCTOR (instance))
5300
{
5301
if (nonnull)
5302
*nonnull = 1;
5303
return
TREE_TYPE (instance);
5304
}
5305
return
fixed_type_or_null
(TREE_OPERAND (instance, 0),
nonnull, cdtorp);
5306
5307
case
RTL_EXPR:
5308
return
NULL_TREE;
5309
5310
case
PLUS_EXPR:
5311
case
MINUS_EXPR:
5312
if (TREE_CODE (TREE_OPERAND (instance,
0)) == ADDR_EXPR)
5313
return
fixed_type_or_null
(TREE_OPERAND
(instance, 0), nonnull, cdtorp);
5314
if (TREE_CODE (TREE_OPERAND (instance,
1)) == INTEGER_CST)
5315
/* Propagate
nonnull.
*/
5316
return
fixed_type_or_null
(TREE_OPERAND
(instance, 0), nonnull, cdtorp);
5317
return
NULL_TREE;
5318
5319
case
NOP_EXPR:
5320
case
CONVERT_EXPR:
5321
return
fixed_type_or_null
(TREE_OPERAND (instance, 0),
nonnull, cdtorp);
5322
5323
case
ADDR_EXPR:
5324
if (nonnull)
5325
*nonnull = 1;
5326
return
fixed_type_or_null
(TREE_OPERAND (instance, 0),
nonnull, cdtorp);
5327
5328
case
COMPONENT_REF:
5329
return
fixed_type_or_null
(TREE_OPERAND (instance, 1),
nonnull, cdtorp);
5330
5331
case
VAR_DECL:
5332
case
FIELD_DECL:
5333
if (TREE_CODE (TREE_TYPE (instance)) ==
ARRAY_TYPE
5334
&& IS_AGGR_TYPE (TREE_TYPE
(TREE_TYPE (instance))))
5335
{
5336
if (nonnull)
5337
*nonnull = 1;
5338
return
TREE_TYPE (TREE_TYPE (instance));
5339
}
5340
/* fall through...
*/
5341
case
TARGET_EXPR:
5342
case
PARM_DECL:
5343
case
RESULT_DECL:
5344
if (IS_AGGR_TYPE (TREE_TYPE (instance)))
5345
{
5346
if (nonnull)
5347
*nonnull = 1;
5348
return
TREE_TYPE (instance);
5349
}
5350
else if (instance == current_class_ptr
)
5351
{
5352
if (nonnull)
5353
*nonnull = 1;
5354
5355
/* if we're in a ctor or dtor, we know our
type.
*/
5356
if (DECL_LANG_SPECIFIC (current_function_decl
)
5357
&& (DECL_CONSTRUCTOR_P (current_function_decl
)
5358
|| DECL_DESTRUCTOR_P (current_function_decl
)))
5359
{
5360
if (cdtorp)
5361
*cdtorp = 1;
5362
return
TREE_TYPE (TREE_TYPE (instance));
5363
}
5364
}
5365
else if (TREE_CODE (TREE_TYPE (instance))
== REFERENCE_TYPE)
5366
{
5367
/* Reference
variables should be references to objects.
*/
5368
if (nonnull)
5369
*nonnull = 1;
5370
5371
/*
DECL_VAR_MARKED_P is used to prevent recursion; a
5372
variable's initializer
may refer to the variable
5373
itself.
*/
5374
if (TREE_CODE (instance) == VAR_DECL
5375
&& DECL_INITIAL (instance)
5376
&& !DECL_VAR_MARKED_P
(instance))
5377
{
5378
tree type;
5379
DECL_VAR_MARKED_P (instance) = 1;
5380
type = fixed_type_or_null
(DECL_INITIAL (instance),
5381
nonnull,
cdtorp);
5382
DECL_VAR_MARKED_P (instance) = 0;
5383
return
type;
5384
}
5385
}
5386
return
NULL_TREE;
5387
5388
default
:
5389
return
NULL_TREE;
5390
}
5391
}
Arriving here, fixed_type_p
is 0 if type of expr
is unknown for certainty
(polymorphism may be in used), or is -1 if expr
is constructor or destructor, otherwise is 1
as type is known for certainty. And v_binfo
is not NULL if there is virtual base involved.
build_base_path (continue)
293
if (want_pointer && !nonnull)
294
null_test = build (EQ_EXPR,
boolean_type_node, expr, integer_zero_node);
295
296
offset = BINFO_OFFSET (binfo);
If no vritual base found, offset
gotten at line 296 is all wanted. Code in
below then generates the expression (taking example 4 as instance in pseudo
code):
*(&b +
offset (A));
And if b
originally is a pointer, it will generate code to guard NULL
pointer too as below (taking example 5 as instance):
pa? (pa +
offset (A)) : 0;
build_base_path (continue)
350
target_type = code == PLUS_EXPR ?
BINFO_TYPE (binfo) : BINFO_TYPE (d_binfo);
351
352
target_type = cp_build_qualified_type
353
(target_type, cp_type_quals (TREE_TYPE
(TREE_TYPE (expr))));
354
ptr_target_type = build_pointer_type
(target_type);
355
if (want_pointer)
356
target_type = ptr_target_type;
357
358
expr = build1
(NOP_EXPR, ptr_target_type, expr);
359
360
if (!integer_zerop (offset))
361
expr = build
(code,
ptr_target_type, expr, offset);
362
else
363
null_test = NULL;
364
365
if (!want_pointer)
366
expr = build_indirect_ref
(expr, NULL);
367
368
if (null_test)
369
expr = build
(COND_EXPR, target_type, null_test,
370
build1
(NOP_EXPR, target_type, integer_zero_node),
371
expr);
372
373
return
expr;
374
}
However, if the conversion involves virtual base and expr
’s
dynamic type isn’t the same as static type, offset
gotten at line 296 is just the beginning.
build_base_path (continue)
298
if (v_binfo && fixed_type_p <= 0)
299
{
300
/* Going via
virtual base V_BINFO. We need the static offset
301
from V_BINFO to
BINFO, and the dynamic offset from D_BINFO to
302
V_BINFO. That
offset is an entry in D_BINFO's vtable.
*/
303
tree v_offset;
304
305
if (fixed_type_p < 0 && in_base_initializer
)
306
{
307
/* In a base
member initializer, we cannot rely on
308
the vtable
being set up. We have to use the vtt_parm.
*/
309
tree derived = BINFO_INHERITANCE_CHAIN
(v_binfo);
310
311
v_offset = build
(PLUS_EXPR, TREE_TYPE (current_vtt_parm
),
312
current_vtt_parm
, BINFO_VPTR_INDEX
(derived));
313
314
v_offset = build1
(INDIRECT_REF,
315
TREE_TYPE (TYPE_VFIELD
(BINFO_TYPE (derived))),
316
v_offset);
317
318
}
319
else
320
v_offset = build_vfield_ref
(build_indirect_ref (expr, NULL),
321
TREE_TYPE
(TREE_TYPE (expr)));
322
323
v_offset = build
(PLUS_EXPR, TREE_TYPE (v_offset),
324
v_offset,
BINFO_VPTR_FIELD (v_binfo));
325
v_offset = build1
(NOP_EXPR,
326
build_pointer_type (ptrdiff_type_node
),
327
v_offset);
328
v_offset = build_indirect_ref
(v_offset, NULL);
329
330
offset = convert_to_integer (ptrdiff_type_node
,
331
size_diffop (offset,
332
BINFO_OFFSET (v_binfo)));
333
334
if (!integer_zerop (offset))
335
v_offset = build
(code, ptrdiff_type_node
,
v_offset, offset);
336
337
if (fixed_type_p < 0)
338
/* Negative
fixed_type_p means this is a constructor or destructor;
339
virtual base layout is fixed in in-charge
[cd]tors, but not in
340
base
[cd]tors.
*/
341
offset = build
(COND_EXPR, ptrdiff_type_node
,
342
build
(EQ_EXPR, boolean_type_node,
343
current_in_charge_parm
, integer_zero_node),
344
v_offset,
345
BINFO_OFFSET (binfo));
346
else
347
offset = v_offset;
348
}
If there is virtual base between and it must use vtable to do the
conversion between the derived and the base, above at line 305 in
_base_initializer
is nonzero if it
is handling a base initializer, for which case vtable is not created. So it
needs use the placeholder current_vtt_parm
to indicate to involvement of
the vtable.
Function build_indirect_ref
builds INDIRECT_REF for
pointer type or reference type. For example, if p
is a pointer, then the
INDIRECT_REF node stands for the expression “*p”.
2028
tree
2029
build_indirect_ref
(tree ptr, const
char *errorstring)
in typeck.c
2030
{
2031
tree pointer, type;
2032
2033
if (ptr == error_mark_node)
2034
return
error_mark_node;
2035
2036
if (ptr == current_class_ptr
)
2037
return
current_class_ref
;
2038
2039
pointer = (TREE_CODE (TREE_TYPE (ptr)) ==
REFERENCE_TYPE
2040
? ptr : decay_conversion (ptr));
2041
type = TREE_TYPE (pointer);
2042
2043
if (TYPE_PTR_P (type) || TREE_CODE (type) ==
REFERENCE_TYPE)
2044
{
2045
/* [expr.unary.op]
2046
2047
If the type of the
expression is "pointer to T," the type
2048
of the result is
"T."
2049
2050
We must use the canonical
variant because certain parts of
2051
the back end, like fold, do
pointer comparisons between
2052
types.
*/
2053
tree t = canonical_type_variant (TREE_TYPE
(type));
2054
2055
if (VOID_TYPE_P (t))
2056
{
2057
/* A pointer to
incomplete type (other than cv void) can be
2058
dereferenced
[expr.unary.op]/1
*/
2059
error ("`%T' is not a
pointer-to-object type", type);
2060
return
error_mark_node;
2061
}
2062
else if (TREE_CODE (pointer) == ADDR_EXPR
2063
&& same_type_p (t, TREE_TYPE
(TREE_OPERAND (pointer, 0))))
2064
/* The POINTER
was something like `&x'.
We simplify
`*&x' to
2065
`x'.
*/
2066
return
TREE_OPERAND (pointer, 0);
2067
else
2068
{
2069
tree ref = build1
(INDIRECT_REF, t, pointer);
2070
2071
/* We *must*
set TREE_READONLY when dereferencing a pointer to const,
2072
so that we get the proper
error message if the result is used
2073
to assign to. Also, &*
is supposed to be a no-op.
*/
2074
TREE_READONLY (ref) = CP_TYPE_CONST_P
(t);
2075
TREE_THIS_VOLATILE (ref) =
CP_TYPE_VOLATILE_P (t);
2076
TREE_SIDE_EFFECTS (ref)
2077
= (TREE_THIS_VOLATILE (ref) ||
TREE_SIDE_EFFECTS (pointer));
2078
return
ref;
2079
}
2080
}
2081
/* `pointer' won't
be an error_mark_node if we were given a
2082
pointer to member, so it's
cool to check for this here.
*/
2083
else if (TYPE_PTR_TO_MEMBER_P (type))
2084
error ("invalid use of `%s' on pointer
to member", errorstring);
2085
else if (pointer != error_mark_node)
2086
{
2087
if (errorstring)
2088
error ("invalid type argument of
`%s'", errorstring);
2089
else
2090
error ("invalid type argument");
2091
}
2092
return
error_mark_node;
2093
}
As we have seen TYPE_VFIELD is the artificial field generated by the
compiler for class containing vtable. Now it also acts as a placeholder, it
will be replaced with the real address of vtable later.
115
tree
116
build_vfield_ref
(tree datum, tree type)
in
call.c
117
{
118
if (datum == error_mark_node)
119
return
error_mark_node;
120
121
if (TREE_CODE (TREE_TYPE (datum)) ==
REFERENCE_TYPE)
122
datum = convert_from_reference (datum);
123
124
if (TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (type)
125
&&
!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (datum), type))
126
datum = convert_to_base (datum, type, /*check_access=*/
false);
127
128
return
build
(COMPONENT_REF, TREE_TYPE (TYPE_VFIELD (type)),
129
datum, TYPE_VFIELD (type));
130
}
Remember BINFO_VPTR_FIELD at line 324 is set for virtual base, in
which is an INTEGER_CST indicating the index of the entry in the vtable
recording the offset of the virtual base from the base of the derived (why not
BINFO_OFFSET (vbase)? because C++ standard requires accessing virtual base by
help of BINFO_VPTR_FIELD).
Note that if binfo
is
derived by v_binfo
,
then offset
at line 330 gets the relative offset between these two bases as indicated by
below figure (the red
arrow
is the offset
gotten at line 330).
Then line 334 introduces a minor optimizaton, note that code
of
MINUS_EXPR with v_binfo
not NULL is not allowed and error message is given at line 280. So at line 335, v_offset
at right hand side refers to the binfo of the virtual base via vtable, and plus
offset
gotten at line 330, v_offset
at left hand side then points to the
binfo in interesting. Following offset
is updated accordingly to record the
offset into the most derived class.
For our example 5, expr
generated finally would be:
(pa + offset
(A))? (pa + offset (A)): 0;
Back into get_member_function_from_ptrfunc
,
instance_ptr
is now the above statement returned by build_base_path
. Consider following example,
it gives output “C::f” (note that in class C, vtable entry of f of B1, B2, and
A are all overrided as C::f with appropriate thunk, which give us promise
here):
class
A { public
:
example
- 6
virtual
A*
f () { printf ("A::f/n"); return
0; }
virtual
A*
f1 () { printf ("A::f1/n"); return
0;
}
virtual
~A() {}
};
class
B1 : virtual
public
A { public
:
virtual
B1* f1 () { printf
("B1::f1/n"); return
0; } };
class
B2 : virtual
public
A {};
class
C: public
B1, public
B2 { public
:
virtual C* f () { printf ("C::f/n"); return
0; } };
int main() {
B2 *pc = new
C; // no matter declare
pc as A*, B1*, B2*, or C*, get same result, as // they all derive from A, and
pfn is declared as within A
A* (A::*pfn) () = &B2::f; // same result, use either B1, B2, A, or C at rhs
(pc->*pfn)();
delete
pc;
return
0;
}
For this example, instance_ptr
holds the statement to adjust pa
from B2* to A* (“B2 *pc = new C;” carries a
pointer converted from C* to B2* already); and delta
below gotten at line 2357
records the offset determined by statement “A* (A::*pfn) () = &B2::f;”
(it is 0 because the statement indicate a
meaningless adjustment from A to A). Then by expression: “instance_ptr +
delta”, it locates the base that defining the function specified by the pointer
to method; then idx is the index into the vtable for the virtual function (or
function address converting in type of vtable for non-virtual function).
get_member_function_from_ptrfunc
(continue)
2383
/* ...and then
the delta in the PMF.
*/
2384
instance_ptr =
build
(PLUS_EXPR, TREE_TYPE (instance_ptr),
2385
instance_ptr, delta);
2386
2387
/* Hand back the
adjusted 'this' argument to our caller.
*/
2388
*instance_ptrptr = instance_ptr;
2389
2390
/* Next extract
the vtable pointer from the object.
*/
2391
vtbl = build1
(NOP_EXPR, build_pointer_type
(vtbl_ptr_type_node),
2392
instance_ptr);
2393
vtbl = build_indirect_ref
(vtbl, NULL);
2394
2395
/* Finally,
extract the function pointer from the vtable.
*/
2396
e2 = fold (build
(PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx));
2397
e2 = build_indirect_ref
(e2, NULL);
2398
TREE_CONSTANT (e2) = 1;
2399
2400
/* When using
function descriptors, the address of the
2401
vtable entry is treated as a
function pointer.
*/
2402
if (TARGET_VTABLE_USES_DESCRIPTORS)
2403
e2 = build1
(NOP_EXPR, TREE_TYPE (e2),
2404
build_unary_op (ADDR_EXPR, e2, /*noconvert=*/
1));
2405
2406
TREE_TYPE (e2) = TREE_TYPE (e3);
2407
e1 = build_conditional_expr (e1, e2, e3);
2408
2409
/* Make sure this
doesn't get evaluated first inside one of the
2410
branches of the
COND_EXPR.
*/
2411
if (instance_save_expr)
2412
e1 = build
(COMPOUND_EXPR, TREE_TYPE (e1),
2413
instance_save_expr, e1);
2414
2415
function = e1;
2416
}
2417
return
function;
2418
}
In section of class
layout, we have seen that vptr is always placed at the beginning of the class.
So the code snippet generated would be like below for example 5:
idx =
(vtable_index_type) pfn;
// pfn returned by PFN_FROM_PTRMEMFUNC
instance_ptr
= instance_ptr? instance_ptr + offset (A): 0;
(idx
& 1)? *(((vtbl_ptr_type_node) instance_ptr) + (idx-1)): pfn;
At this point, for a
pointer-to-method, we have known which function is expected, and expression to
locate the location of the function is ready and returned to build_addr_func
,
then immediately to build_function_call
. Note that function
below now holds the expression for locating the function and its type is the
pointer of the function.
build_function_call (continue)
2464
if (function == error_mark_node)
2465
return
error_mark_node;
2466
2467
fntype = TREE_TYPE (function);
2468
2469
if (TYPE_PTRMEMFUNC_P (fntype))
2470
{
2471
error ("must use .* or ->* to call
pointer-to-member function in `%E (...)'",
2472
original);
2473
return
error_mark_node;
2474
}
2475
2476
is_method = (TREE_CODE (fntype) == POINTER_TYPE
2477
&& TREE_CODE (TREE_TYPE
(fntype)) == METHOD_TYPE);
2478
2479
if (!((TREE_CODE (fntype) == POINTER_TYPE
2480
&& TREE_CODE (TREE_TYPE
(fntype)) == FUNCTION_TYPE)
2481
|| is_method
2482
|| TREE_CODE (function) == TEMPLATE_ID_EXPR))
2483
{
2484
error ("`%E' cannot be used as a
function", original);
2485
return
error_mark_node;
2486
}
2487
2488
/* fntype now gets
the type of function pointed to.
*/
2489
fntype = TREE_TYPE (fntype);
2490
2491
/* Convert the
parameters to the types declared in the
2492
function prototype, or apply
default promotions.
*/
2493
2494
coerced_params = convert_arguments
(TYPE_ARG_TYPES (fntype),
2495
params,
fndecl, LOOKUP_NORMAL);
2496
if (coerced_params == error_mark_node)
2497
return
error_mark_node;
2498
2499
/* Check for errors
in format strings.
*/
2500
2501
if (warn_format
)
2502
check_function_format (NULL,
TYPE_ATTRIBUTES (fntype), coerced_params);
2503
2504
/* Recognize
certain built-in functions so we can make tree-codes
2505
other than CALL_EXPR. We do
this when it enables fold-const.c
2506
to do something useful.
*/
2507
2508
if (TREE_CODE (function) == ADDR_EXPR
2509
&& TREE_CODE (TREE_OPERAND
(function, 0)) == FUNCTION_DECL
2510
&& DECL_BUILT_IN (TREE_OPERAND
(function, 0)))
2511
{
2512
result = expand_tree_builtin (TREE_OPERAND
(function, 0),
2513
params,
coerced_params);
2514
if (result)
2515
return
result;
2516
}
2517
2518
return
build_cxx_call
(function, params, coerced_params);
2519
}
So fntype
at line 2489 refers to the type of the function in used. Then it needs do
conversion for the arguments according to the parameters declaration.
相关文章推荐
- Studying note of GCC-3.4.6 source (162)
- Studying note of GCC-3.4.6 source (148 continue)
- Studying note of GCC-3.4.6 source (142 - continue)
- Studying note of GCC-3.4.6 source (100 continue)
- Studying note of GCC-3.4.6 source (129 continue)
- Studying note of GCC-3.4.6 source (140 - continue)
- Studying note of GCC-3.4.6 source (148)
- Studying note of GCC-3.4.6 source (52)
- Studying note of GCC-3.4.6 source (59)
- Studying note of GCC-3.4.6 source (68)
- Studying note of GCC-3.4.6 source (82)
- Studying note of GCC-3.4.6 source (89)
- Studying note of GCC-3.4.6 source (91)
- Studying note of GCC-3.4.6 source (106)
- Studying note of GCC-3.4.6 source (112)
- Studying note of GCC-3.4.6 source (1)
- Studying note of GCC-3.4.6 source (139)
- Studying note of GCC-3.4.6 source (141 - cont 2)
- Studying note of GCC-3.4.6 source (150)
- Studying note of GCC-3.4.6 source (157)