C++ PATCH: Implement new ABI pointers-to-member functions
Mark Mitchell
mark@codesourcery.com
Mon Feb 21 18:28:00 GMT 2000
The new ABI uses a different pointer to member format. Because of
thew new class layout algorithms, pointers to members don't need a
`delta2' field. The code to compare pointers to members, and
especially to convert them from base to derived, or vice versa, should
be tighter as well.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
2000-02-21 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (CPTI_VTABLE_INDEX_TYPE): New macro.
(CPTI_CLASS_STAR_TYPE): Remove.
(vtable_index_type): Likewise.
(class_star_type_node): Remove.
(TYPE_PTRMEMFUNC_FN_TYPE): Adjust for the new ABI.
(build_binary_op_nodefault): Remove.
* call.c (build_new_op): Use build_binary_op instead of
build_binary_op_nodefault.
* decl.c (init_decl_processing): Remove class_star_type_node
initialization. Make delta_type_node ptrdiff_type_node under the
new ABI. Initialize vtable_index_type.
(build_ptrmemfunc_type): Build different structures for the new
ABI.
(build_enumerator): Use build_binary_op instead of
build_binary_op_nodefault.
* method.c (build_overload_value): Mangle pointers-to-members
appropriately under the new ABI.
* typeck.c (build_array_ref): Use build_binary_op instead of
build_binary_op_nodefault.
(get_member_function_from_ptrfunc): Adjust for the new ABI.
(build_binary_op_nodefault): Rename to ...
(build_binary_op): ... this. Remove old version. Adjust for
pointer-to-member comparisons under the new ABI.
(build_ptrmemfunc1): Remove dead code. Adjust for the new ABI.
(build_ptrmemfunc): Adjust for the new ABI.
(expand_ptrmemfunc_cst): Likewise.
(delta2_from_ptrmemfunc): Assert that we're not using the new ABI.
(pfn_from_ptrmemfunc): Adjust for the new ABI.
Index: call.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/call.c,v
retrieving revision 1.193
diff -c -p -r1.193 call.c
*** call.c 2000/02/16 23:54:21 1.193
--- call.c 2000/02/22 02:25:47
*************** builtin:
*** 3408,3414 ****
case BIT_XOR_EXPR:
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
! return build_binary_op_nodefault (code, arg1, arg2, code);
case CONVERT_EXPR:
case NEGATE_EXPR:
--- 3408,3414 ----
case BIT_XOR_EXPR:
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
! return build_binary_op (code, arg1, arg2);
case CONVERT_EXPR:
case NEGATE_EXPR:
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.405
diff -c -p -r1.405 cp-tree.h
*** cp-tree.h 2000/02/21 04:19:11 1.405
--- cp-tree.h 2000/02/22 02:25:55
*************** enum cp_tree_index
*** 517,522 ****
--- 517,523 ----
CPTI_WCHAR_DECL,
CPTI_VTABLE_ENTRY_TYPE,
CPTI_DELTA_TYPE,
+ CPTI_VTABLE_INDEX_TYPE,
CPTI_CLEANUP_TYPE,
CPTI_TI_DESC_TYPE,
*************** enum cp_tree_index
*** 532,538 ****
CPTI_PTMD_DESC_TYPE,
CPTI_BASE_DESC_TYPE,
- CPTI_CLASS_STAR_TYPE,
CPTI_CLASS_TYPE,
CPTI_RECORD_TYPE,
CPTI_UNION_TYPE,
--- 533,538 ----
*************** extern tree cp_global_trees[CPTI_MAX];
*** 601,607 ****
--- 601,612 ----
#define void_zero_node cp_global_trees[CPTI_VOID_ZERO]
#define wchar_decl_node cp_global_trees[CPTI_WCHAR_DECL]
#define vtable_entry_type cp_global_trees[CPTI_VTABLE_ENTRY_TYPE]
+ /* The type used to represent an offset by which to adjust the `this'
+ pointer in pointer-to-member types and, when not using vtable
+ thunks, in vtables. */
#define delta_type_node cp_global_trees[CPTI_DELTA_TYPE]
+ /* The type used to represent an index into the vtable. */
+ #define vtable_index_type cp_global_trees[CPTI_VTABLE_INDEX_TYPE]
#define ti_desc_type_node cp_global_trees[CPTI_TI_DESC_TYPE]
#define bltn_desc_type_node cp_global_trees[CPTI_BLTN_DESC_TYPE]
*************** extern tree cp_global_trees[CPTI_MAX];
*** 616,622 ****
#define ptmd_desc_type_node cp_global_trees[CPTI_PTMD_DESC_TYPE]
#define base_desc_type_node cp_global_trees[CPTI_BASE_DESC_TYPE]
- #define class_star_type_node cp_global_trees[CPTI_CLASS_STAR_TYPE]
#define class_type_node cp_global_trees[CPTI_CLASS_TYPE]
#define record_type_node cp_global_trees[CPTI_RECORD_TYPE]
#define union_type_node cp_global_trees[CPTI_UNION_TYPE]
--- 621,626 ----
*************** extern int flag_new_for_scope;
*** 2498,2509 ****
function.
(Of course, the exact values may differ depending on the mangling
! scheme, sizes of types, and such.). */
/* Get the POINTER_TYPE to the METHOD_TYPE associated with this
pointer to member function. TYPE_PTRMEMFUNC_P _must_ be true,
before using this macro. */
! #define TYPE_PTRMEMFUNC_FN_TYPE(NODE) (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (NODE)))))))
/* Returns `A' for a type like `int (A::*)(double)' */
#define TYPE_PTRMEMFUNC_OBJECT_TYPE(NODE) \
--- 2502,2528 ----
function.
(Of course, the exact values may differ depending on the mangling
! scheme, sizes of types, and such.).
!
! Under the new ABI, we do:
!
! struct {
! __P __pfn;
! ptrdiff_t __delta;
! };
!
! (We don't need DELTA2, because the vtable is always the first thing
! in the object.) If the function is virtual, then PFN is one plus
! twice the index into the vtable; otherwise, it is just a pointer to
! the function. */
/* Get the POINTER_TYPE to the METHOD_TYPE associated with this
pointer to member function. TYPE_PTRMEMFUNC_P _must_ be true,
before using this macro. */
! #define TYPE_PTRMEMFUNC_FN_TYPE(NODE) \
! (flag_new_abi \
! ? (TREE_TYPE (TYPE_FIELDS (NODE))) \
! : (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (NODE))))))))
/* Returns `A' for a type like `int (A::*)(double)' */
#define TYPE_PTRMEMFUNC_OBJECT_TYPE(NODE) \
*************** extern tree build_function_call_maybe P
*** 4341,4347 ****
extern tree convert_arguments PARAMS ((tree, tree, tree, int));
extern tree build_x_binary_op PARAMS ((enum tree_code, tree, tree));
extern tree build_binary_op PARAMS ((enum tree_code, tree, tree));
- extern tree build_binary_op_nodefault PARAMS ((enum tree_code, tree, tree, enum tree_code));
extern tree build_x_unary_op PARAMS ((enum tree_code, tree));
extern tree build_unary_op PARAMS ((enum tree_code, tree, int));
extern tree unary_complex_lvalue PARAMS ((enum tree_code, tree));
--- 4360,4365 ----
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.547
diff -c -p -r1.547 decl.c
*** decl.c 2000/02/20 01:10:49 1.547
--- decl.c 2000/02/22 02:26:03
*************** tree error_mark_list;
*** 222,228 ****
tree __ptmf_desc_array_type, __ptmd_desc_array_type;
#endif
- tree class_star_type_node;
tree class_type_node, record_type_node, union_type_node, enum_type_node;
tree unknown_type_node;
--- 222,227 ----
*************** init_decl_processing ()
*** 6207,6221 ****
int_array_type_node
= build_array_type (integer_type_node, array_domain_type);
! /* This is just some anonymous class type. Nobody should ever
! need to look inside this envelope. */
! class_star_type_node = build_pointer_type (make_aggr_type (RECORD_TYPE));
!
! if (flag_huge_objects)
delta_type_node = long_integer_type_node;
else
delta_type_node = short_integer_type_node;
default_function_type
= build_function_type (integer_type_node, NULL_TREE);
--- 6206,6223 ----
int_array_type_node
= build_array_type (integer_type_node, array_domain_type);
! if (flag_new_abi)
! delta_type_node = ptrdiff_type_node;
! else if (flag_huge_objects)
delta_type_node = long_integer_type_node;
else
delta_type_node = short_integer_type_node;
+ if (flag_new_abi)
+ vtable_index_type = ptrdiff_type_node;
+ else
+ vtable_index_type = delta_type_node;
+
default_function_type
= build_function_type (integer_type_node, NULL_TREE);
*************** build_ptrmemfunc_type (type)
*** 8804,8830 ****
unqualified_variant
= build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type));
- u = make_aggr_type (UNION_TYPE);
- SET_IS_AGGR_TYPE (u, 0);
- fields[0] = build_lang_decl (FIELD_DECL, pfn_identifier, type);
- fields[1] = build_lang_decl (FIELD_DECL, delta2_identifier,
- delta_type_node);
- finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node);
- TYPE_NAME (u) = NULL_TREE;
-
t = make_aggr_type (RECORD_TYPE);
-
/* Let the front-end know this is a pointer to member function... */
TYPE_PTRMEMFUNC_FLAG (t) = 1;
/* ... and not really an aggregate. */
SET_IS_AGGR_TYPE (t, 0);
! fields[0] = build_lang_decl (FIELD_DECL, delta_identifier,
! delta_type_node);
! fields[1] = build_lang_decl (FIELD_DECL, index_identifier,
! delta_type_node);
! fields[2] = build_lang_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
! finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node);
/* Zap out the name so that the back-end will give us the debugging
information for this anonymous RECORD_TYPE. */
--- 8806,8841 ----
unqualified_variant
= build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type));
t = make_aggr_type (RECORD_TYPE);
/* Let the front-end know this is a pointer to member function... */
TYPE_PTRMEMFUNC_FLAG (t) = 1;
/* ... and not really an aggregate. */
SET_IS_AGGR_TYPE (t, 0);
! if (!flag_new_abi)
! {
! u = make_aggr_type (UNION_TYPE);
! SET_IS_AGGR_TYPE (u, 0);
! fields[0] = build_lang_decl (FIELD_DECL, pfn_identifier, type);
! fields[1] = build_lang_decl (FIELD_DECL, delta2_identifier,
! delta_type_node);
! finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node);
! TYPE_NAME (u) = NULL_TREE;
!
! fields[0] = build_lang_decl (FIELD_DECL, delta_identifier,
! delta_type_node);
! fields[1] = build_lang_decl (FIELD_DECL, index_identifier,
! delta_type_node);
! fields[2] = build_lang_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
! finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node);
! }
! else
! {
! fields[0] = build_lang_decl (FIELD_DECL, pfn_identifier, type);
! fields[1] = build_lang_decl (FIELD_DECL, delta_identifier,
! delta_type_node);
! finish_builtin_type (t, "__ptrmemfunc_type", fields, 1, ptr_type_node);
! }
/* Zap out the name so that the back-end will give us the debugging
information for this anonymous RECORD_TYPE. */
*************** build_enumerator (name, value, enumtype)
*** 12778,12787 ****
/* The next value is the previous value ... */
prev_value = DECL_INITIAL (TREE_VALUE (TYPE_VALUES (enumtype)));
/* ... plus one. */
! value = build_binary_op_nodefault (PLUS_EXPR,
! prev_value,
! integer_one_node,
! PLUS_EXPR);
if (tree_int_cst_lt (value, prev_value))
cp_error ("overflow in enumeration values at `%D'", name);
--- 12789,12797 ----
/* The next value is the previous value ... */
prev_value = DECL_INITIAL (TREE_VALUE (TYPE_VALUES (enumtype)));
/* ... plus one. */
! value = build_binary_op (PLUS_EXPR,
! prev_value,
! integer_one_node);
if (tree_int_cst_lt (value, prev_value))
cp_error ("overflow in enumeration values at `%D'", name);
Index: method.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/method.c,v
retrieving revision 1.136
diff -c -p -r1.136 method.c
*** method.c 2000/02/16 23:54:23 1.136
--- method.c 2000/02/22 02:26:05
*************** build_overload_value (type, value, flags
*** 851,856 ****
--- 851,857 ----
tree idx;
tree pfn;
tree delta2;
+ tree fn;
my_friendly_assert (TYPE_PTRMEMFUNC_P (type), 0);
*************** build_overload_value (type, value, flags
*** 872,888 ****
my_friendly_assert (TREE_CODE (value) == PTRMEM_CST, 0);
expand_ptrmemfunc_cst (value, &delta, &idx, &pfn, &delta2);
build_overload_int (delta, flags);
OB_PUTC ('_');
! build_overload_int (idx, flags);
! OB_PUTC ('_');
! if (pfn)
{
numeric_output_need_bar = 0;
! build_overload_identifier (DECL_ASSEMBLER_NAME
! (PTRMEM_CST_MEMBER (value)));
}
! else
{
OB_PUTC ('i');
build_overload_int (delta2, flags);
--- 873,898 ----
my_friendly_assert (TREE_CODE (value) == PTRMEM_CST, 0);
expand_ptrmemfunc_cst (value, &delta, &idx, &pfn, &delta2);
+ fn = PTRMEM_CST_MEMBER (value);
build_overload_int (delta, flags);
OB_PUTC ('_');
! if (!flag_new_abi)
! {
! build_overload_int (idx, flags);
! OB_PUTC ('_');
! }
! else if (DECL_VIRTUAL_P (fn))
! {
! build_overload_int (DECL_VINDEX (fn), flags);
! OB_PUTC ('_');
! }
!
! if (!DECL_VIRTUAL_P (fn))
{
numeric_output_need_bar = 0;
! build_overload_identifier (DECL_ASSEMBLER_NAME (fn));
}
! else if (!flag_new_abi)
{
OB_PUTC ('i');
build_overload_int (delta2, flags);
Index: typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.245
diff -c -p -r1.245 typeck.c
*** typeck.c 2000/02/16 23:54:23 1.245
--- typeck.c 2000/02/22 02:26:09
*************** build_array_ref (array, idx)
*** 2509,2516 ****
return error_mark_node;
}
! return build_indirect_ref (build_binary_op_nodefault (PLUS_EXPR, ar,
! ind, PLUS_EXPR),
"array indexing");
}
}
--- 2509,2515 ----
return error_mark_node;
}
! return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, ind),
"array indexing");
}
}
*************** get_member_function_from_ptrfunc (instan
*** 2836,2844 ****
fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
! delta = cp_convert (ptrdiff_type_node,
! build_component_ref (function, delta_identifier,
! NULL_TREE, 0));
e3 = PFN_FROM_PTRMEMFUNC (function);
/* This used to avoid checking for virtual functions if basetype
--- 2835,2845 ----
fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
! /* Convert down to the right base, before using the instance. */
! instance = convert_pointer_to_real (basetype, instance_ptr);
! if (instance == error_mark_node && instance_ptr != error_mark_node)
! return instance;
!
e3 = PFN_FROM_PTRMEMFUNC (function);
/* This used to avoid checking for virtual functions if basetype
*************** get_member_function_from_ptrfunc (instan
*** 2853,2879 ****
load-with-sign-extend, while the second used normal load then
shift to sign-extend. An optimizer flaw, perhaps, but it's
easier to make this change. */
! idx = save_expr (default_conversion
(build_component_ref (function,
index_identifier,
NULL_TREE, 0)));
! e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
!
! /* Convert down to the right base, before using the instance. */
! instance = convert_pointer_to_real (basetype, instance_ptr);
! if (instance == error_mark_node && instance_ptr != error_mark_node)
! return instance;
vtbl = convert_pointer_to (ptr_type_node, instance);
! delta2 = DELTA2_FROM_PTRMEMFUNC (function);
vtbl = build
(PLUS_EXPR,
build_pointer_type (build_pointer_type (vtable_entry_type)),
vtbl, cp_convert (ptrdiff_type_node, delta2));
vtbl = build_indirect_ref (vtbl, NULL_PTR);
! aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
! idx,
! integer_one_node));
if (! flag_vtable_thunks)
{
aref = save_expr (aref);
--- 2854,2895 ----
load-with-sign-extend, while the second used normal load then
shift to sign-extend. An optimizer flaw, perhaps, but it's
easier to make this change. */
! if (flag_new_abi)
! {
! idx = build_binary_op (TRUNC_DIV_EXPR,
! build1 (NOP_EXPR, vtable_index_type, e3),
! integer_two_node);
! e1 = build_binary_op (BIT_AND_EXPR,
! build1 (NOP_EXPR, vtable_index_type, e3),
! integer_one_node);
! }
! else
! {
! idx = save_expr (default_conversion
(build_component_ref (function,
index_identifier,
NULL_TREE, 0)));
! e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
! idx = build_binary_op (MINUS_EXPR, idx, integer_one_node);
! }
vtbl = convert_pointer_to (ptr_type_node, instance);
! delta = cp_convert (ptrdiff_type_node,
! build_component_ref (function, delta_identifier,
! NULL_TREE, 0));
! if (flag_new_abi)
! /* DELTA2 is the amount by which to adjust the `this' pointer
! to find the vtbl. */
! delta2 = delta;
! else
! delta2 = DELTA2_FROM_PTRMEMFUNC (function);
vtbl = build
(PLUS_EXPR,
build_pointer_type (build_pointer_type (vtable_entry_type)),
vtbl, cp_convert (ptrdiff_type_node, delta2));
vtbl = build_indirect_ref (vtbl, NULL_PTR);
! aref = build_array_ref (vtbl, idx);
!
if (! flag_vtable_thunks)
{
aref = save_expr (aref);
*************** build_x_binary_op (code, arg1, arg2)
*** 3237,3250 ****
return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
}
- tree
- build_binary_op (code, arg1, arg2)
- enum tree_code code;
- tree arg1, arg2;
- {
- return build_binary_op_nodefault (code, arg1, arg2, code);
- }
-
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
This function differs from `build' in several ways:
--- 3253,3258 ----
*************** build_binary_op (code, arg1, arg2)
*** 3255,3263 ****
are done in the narrower type when that gives the same result).
Constant folding is also done before the result is returned.
- ERROR_CODE is the code that determines what to say in error messages.
- It is usually, but not always, the same as CODE.
-
Note that the operands will never have enumeral types
because either they have just had the default conversions performed
or they have both just been converted to some other type in which
--- 3263,3268 ----
*************** build_binary_op (code, arg1, arg2)
*** 3267,3276 ****
multiple inheritance, and deal with pointer to member functions. */
tree
! build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
enum tree_code code;
tree orig_op0, orig_op1;
- enum tree_code error_code;
{
tree op0, op1;
register enum tree_code code0, code1;
--- 3272,3280 ----
multiple inheritance, and deal with pointer to member functions. */
tree
! build_binary_op (code, orig_op0, orig_op1)
enum tree_code code;
tree orig_op0, orig_op1;
{
tree op0, op1;
register enum tree_code code0, code1;
*************** build_binary_op_nodefault (code, orig_op
*** 3626,3727 ****
}
else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
{
! op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
! op1 = integer_zero_node;
result_type = TREE_TYPE (op0);
}
else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
! {
! op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
! op1 = integer_zero_node;
! result_type = TREE_TYPE (op0);
! }
else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
&& same_type_p (type0, type1))
- {
- /* The code we generate for the test is:
-
- (op0.index == op1.index
- && ((op1.index != -1 && op0.delta2 == op1.delta2)
- || op0.pfn == op1.pfn)) */
-
- tree index0 = build_component_ref (op0, index_identifier,
- NULL_TREE, 0);
- tree index1 = save_expr (build_component_ref (op1, index_identifier,
- NULL_TREE, 0));
- tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
- tree pfn1 = PFN_FROM_PTRMEMFUNC (op1);
- tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
- tree delta21 = DELTA2_FROM_PTRMEMFUNC (op1);
- tree e1, e2, e3;
- tree integer_neg_one_node
- = build_binary_op (MINUS_EXPR, integer_zero_node,
- integer_one_node);
- e1 = build_binary_op (EQ_EXPR, index0, index1);
- e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
- e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
- build_binary_op (EQ_EXPR, delta20, delta21));
- /* We can't use build_binary_op for this cmp because it would get
- confused by the ptr to method types and think we want pmfs. */
- e3 = build (EQ_EXPR, boolean_type_node, pfn0, pfn1);
- e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
- e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
- if (code == EQ_EXPR)
- return e2;
- return build_binary_op (EQ_EXPR, e2, integer_zero_node);
- }
- else if (TYPE_PTRMEMFUNC_P (type0)
- && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type0), type1))
{
! tree index0 = build_component_ref (op0, index_identifier,
! NULL_TREE, 0);
! tree index1;
! tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
! tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
! tree delta21 = integer_zero_node;
! tree e1, e2, e3;
! tree integer_neg_one_node
! = build_binary_op (MINUS_EXPR, integer_zero_node, integer_one_node);
! if (TREE_CODE (TREE_OPERAND (op1, 0)) == FUNCTION_DECL
! && DECL_VINDEX (TREE_OPERAND (op1, 0)))
! {
! /* Map everything down one to make room for
! the null pointer to member. */
! index1 = size_binop (PLUS_EXPR,
! DECL_VINDEX (TREE_OPERAND (op1, 0)),
! integer_one_node);
! op1 = integer_zero_node;
! delta21 = TYPE_VFIELD (TYPE_METHOD_BASETYPE
! (TREE_TYPE (type1)));
! delta21 = DECL_FIELD_BITPOS (delta21);
! delta21 = size_binop (FLOOR_DIV_EXPR, delta21,
! size_int (BITS_PER_UNIT));
! delta21 = convert (sizetype, delta21);
}
else
! index1 = integer_neg_one_node;
! {
! tree nop1 = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type0),
! op1);
! TREE_CONSTANT (nop1) = TREE_CONSTANT (op1);
! op1 = nop1;
! }
! e1 = build_binary_op (EQ_EXPR, index0, index1);
! e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
! e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
! build_binary_op (EQ_EXPR, delta20, delta21));
! /* We can't use build_binary_op for this cmp because it would get
confused by the ptr to method types and think we want pmfs. */
! e3 = build (EQ_EXPR, boolean_type_node, pfn0, op1);
! e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
! e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
if (code == EQ_EXPR)
! return e2;
! return build_binary_op (EQ_EXPR, e2, integer_zero_node);
}
! else if (TYPE_PTRMEMFUNC_P (type1)
! && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type1), type0))
! return build_binary_op (code, op1, op0);
break;
case MAX_EXPR:
--- 3630,3727 ----
}
else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
{
! if (flag_new_abi)
! {
! op0 = build_component_ref (op0, pfn_identifier, NULL_TREE, 0);
! op1 = cp_convert (TREE_TYPE (op0), integer_zero_node);
! }
! else
! {
! op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
! op1 = integer_zero_node;
! }
result_type = TREE_TYPE (op0);
}
else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
! return build_binary_op (code, op1, op0);
else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
&& same_type_p (type0, type1))
{
! /* E will be the final comparison. */
! tree e;
! /* E1 and E2 are for scratch. */
! tree e1;
! tree e2;
!
! if (flag_new_abi)
! {
! /* We generate:
!
! (op0.pfn == op1.pfn
! && (!op0.pfn || op0.delta == op1.delta))
!
! The reason for the `!op0.pfn' bit is that a NULL
! pointer-to-member is any member with a zero PFN; the
! DELTA field is unspecified. */
! tree pfn0;
! tree pfn1;
! tree delta0;
! tree delta1;
!
! pfn0 = pfn_from_ptrmemfunc (op0);
! pfn1 = pfn_from_ptrmemfunc (op1);
! delta0 = build_component_ref (op0, delta_identifier,
! NULL_TREE, 0);
! delta1 = build_component_ref (op1, delta_identifier,
! NULL_TREE, 0);
! e1 = build_binary_op (EQ_EXPR, delta0, delta1);
! e2 = build_binary_op (NE_EXPR,
! pfn0,
! cp_convert (TREE_TYPE (pfn0),
! integer_zero_node));
! e1 = build_binary_op (TRUTH_ORIF_EXPR, e1, e2);
! e2 = build (EQ_EXPR, boolean_type_node, pfn0, pfn1);
! e = build_binary_op (TRUTH_ANDIF_EXPR, e2, e1);
}
else
! {
! /* The code we generate for the test is:
!
! (op0.index == op1.index
! && ((op1.index != -1 && op0.delta2 == op1.delta2)
! || op0.pfn == op1.pfn)) */
!
! tree index0 = build_component_ref (op0, index_identifier,
! NULL_TREE, 0);
! tree index1 = save_expr (build_component_ref (op1, index_identifier,
! NULL_TREE, 0));
! tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
! tree pfn1 = PFN_FROM_PTRMEMFUNC (op1);
! tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
! tree delta21 = DELTA2_FROM_PTRMEMFUNC (op1);
! tree e3;
! tree integer_neg_one_node
! = build_binary_op (MINUS_EXPR, integer_zero_node,
! integer_one_node);
! e1 = build_binary_op (EQ_EXPR, index0, index1);
! e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
! e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
! build_binary_op (EQ_EXPR, delta20, delta21));
! /* We can't use build_binary_op for this cmp because it would get
confused by the ptr to method types and think we want pmfs. */
! e3 = build (EQ_EXPR, boolean_type_node, pfn0, pfn1);
! e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
! e = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
! }
if (code == EQ_EXPR)
! return e;
! return build_binary_op (EQ_EXPR, e, integer_zero_node);
}
! else if ((TYPE_PTRMEMFUNC_P (type0)
! && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type0), type1))
! || (TYPE_PTRMEMFUNC_P (type1)
! && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type1), type0)))
! my_friendly_abort (20000221);
break;
case MAX_EXPR:
*************** build_binary_op_nodefault (code, orig_op
*** 4059,4065 ****
if (!result_type)
{
cp_error ("invalid operands of types `%T' and `%T' to binary `%O'",
! TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), error_code);
return error_mark_node;
}
--- 4059,4065 ----
if (!result_type)
{
cp_error ("invalid operands of types `%T' and `%T' to binary `%O'",
! TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
return error_mark_node;
}
*************** get_delta_difference (from, to, force)
*** 6071,6147 ****
return BINFO_OFFSET (binfo);
}
tree
build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
tree type, delta, idx, pfn, delta2;
{
tree u;
!
! #if 0
! /* This is the old way we did it. We want to avoid calling
! digest_init, so that it can give an error if we use { } when
! initializing a pointer to member function. */
! if (pfn)
{
! u = build_nt (CONSTRUCTOR, NULL_TREE,
! tree_cons (pfn_identifier, pfn, NULL_TREE));
}
else
{
! u = build_nt (CONSTRUCTOR, NULL_TREE,
! tree_cons (delta2_identifier, delta2, NULL_TREE));
}
! u = build_nt (CONSTRUCTOR, NULL_TREE,
! tree_cons (NULL_TREE, delta,
! tree_cons (NULL_TREE, idx,
! tree_cons (NULL_TREE, u, NULL_TREE))));
!
! return digest_init (type, u, (tree*)0);
! #else
! tree delta_field, idx_field, pfn_or_delta2_field, pfn_field, delta2_field;
! tree subtype;
! int allconstant, allsimple;
! delta_field = TYPE_FIELDS (type);
! idx_field = TREE_CHAIN (delta_field);
! pfn_or_delta2_field = TREE_CHAIN (idx_field);
! subtype = TREE_TYPE (pfn_or_delta2_field);
! pfn_field = TYPE_FIELDS (subtype);
! delta2_field = TREE_CHAIN (pfn_field);
if (pfn)
{
! allconstant = TREE_CONSTANT (pfn);
! allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
! u = tree_cons (pfn_field, pfn, NULL_TREE);
}
else
{
! delta2 = convert_and_check (delta_type_node, delta2);
! allconstant = TREE_CONSTANT (delta2);
! allsimple = !! initializer_constant_valid_p (delta2, TREE_TYPE (delta2));
! u = tree_cons (delta2_field, delta2, NULL_TREE);
! }
! delta = convert_and_check (delta_type_node, delta);
! idx = convert_and_check (delta_type_node, idx);
! allconstant = allconstant && TREE_CONSTANT (delta) && TREE_CONSTANT (idx);
! allsimple = allsimple
! && initializer_constant_valid_p (delta, TREE_TYPE (delta))
! && initializer_constant_valid_p (idx, TREE_TYPE (idx));
!
! u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
! u = tree_cons (delta_field, delta,
! tree_cons (idx_field, idx,
! tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
u = build (CONSTRUCTOR, type, NULL_TREE, u);
TREE_CONSTANT (u) = allconstant;
TREE_STATIC (u) = allconstant && allsimple;
return u;
- #endif
}
/* Build a constructor for a pointer to member function. It can be
--- 6071,6171 ----
return BINFO_OFFSET (binfo);
}
+ /* Return a constructor for the pointer-to-member-function TYPE using
+ the other components as specified. */
+
tree
build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
tree type, delta, idx, pfn, delta2;
{
tree u;
! tree delta_field;
! tree idx_field;
! tree pfn_or_delta2_field;
! tree pfn_field;
! tree delta2_field;
! tree subtype;
! int allconstant, allsimple;
! /* Pull the FIELD_DECLs out of the type. */
! if (flag_new_abi)
{
! pfn_field = TYPE_FIELDS (type);
! delta_field = TREE_CHAIN (pfn_field);
! idx_field = NULL_TREE;
! pfn_or_delta2_field = NULL_TREE;
! delta2_field = NULL_TREE;
! subtype = NULL_TREE;
}
else
{
! delta_field = TYPE_FIELDS (type);
! idx_field = TREE_CHAIN (delta_field);
! pfn_or_delta2_field = TREE_CHAIN (idx_field);
! subtype = TREE_TYPE (pfn_or_delta2_field);
! pfn_field = TYPE_FIELDS (subtype);
! delta2_field = TREE_CHAIN (pfn_field);
}
! /* Make sure DELTA has the type we want. */
! delta = convert_and_check (delta_type_node, delta);
! /* Keep track of whether the initializer is a) constant, and b) can
! be done statically. */
! allconstant = TREE_CONSTANT (delta);
! allsimple = (initializer_constant_valid_p (delta, TREE_TYPE (delta))
! != NULL_TREE);
if (pfn)
{
! /* A non-virtual function. */
! if (!flag_new_abi)
! u = build_tree_list (pfn_field, pfn);
!
! allconstant &= TREE_CONSTANT (pfn);
! allsimple &= (initializer_constant_valid_p (pfn, TREE_TYPE (pfn))
! != NULL_TREE);
}
else
{
! /* A virtual function. */
! if (flag_new_abi)
! {
! allconstant &= TREE_CONSTANT (pfn);
! allsimple &= (initializer_constant_valid_p (pfn, TREE_TYPE (pfn))
! != NULL_TREE);
! }
! else
! {
! idx = convert_and_check (delta_type_node, idx);
! u = build_tree_list (delta2_field, delta2);
! allconstant &= TREE_CONSTANT (idx) && TREE_CONSTANT (delta2);
! allsimple &= ((initializer_constant_valid_p (idx, TREE_TYPE (idx))
! != NULL_TREE)
! && (initializer_constant_valid_p (delta2,
! TREE_TYPE (delta2))
! != NULL_TREE));
! }
! }
! /* Finish creating the initializer. */
! if (flag_new_abi)
! u = tree_cons (pfn_field, pfn,
! build_tree_list (delta_field, delta));
! else
! {
! u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
! u = tree_cons (delta_field, delta,
! tree_cons (idx_field,
! idx,
! build_tree_list (pfn_or_delta2_field,
! u)));
! }
u = build (CONSTRUCTOR, type, NULL_TREE, u);
TREE_CONSTANT (u) = allconstant;
TREE_STATIC (u) = allconstant && allsimple;
return u;
}
/* Build a constructor for a pointer to member function. It can be
*************** build_ptrmemfunc (type, pfn, force)
*** 6179,6193 ****
cp_error ("invalid conversion to type `%T' from type `%T'",
to_type, pfn_type);
if (TREE_CODE (pfn) == PTRMEM_CST)
{
/* We could just build the resulting CONSTRUCTOR now, but we
don't, relying on the general machinery below, together
! with constant-folding, to do the right thing. We don't
! want to return a PTRMEM_CST here, since a
! pointer-to-member constant is no longer a valid template
! argument once it is cast to any type, including its
! original type. */
expand_ptrmemfunc_cst (pfn, &ndelta, &idx, &npfn, &ndelta2);
if (npfn)
/* This constant points to a non-virtual function.
--- 6203,6235 ----
cp_error ("invalid conversion to type `%T' from type `%T'",
to_type, pfn_type);
+ /* We don't have to do any conversion to convert a
+ pointer-to-member to its own type. But, we don't want to
+ just return a PTRMEM_CST if there's an explicit cast; that
+ cast should make the expression an invalid template argument. */
+ if (TREE_CODE (pfn) != PTRMEM_CST && same_type_p (to_type, pfn_type))
+ return pfn;
+
+ if (flag_new_abi)
+ {
+ /* Under the new ABI, the conversion is easy. Just adjust
+ the DELTA field. */
+ npfn = build_component_ref (pfn, pfn_identifier, NULL_TREE, 0);
+ delta = build_component_ref (pfn, delta_identifier, NULL_TREE, 0);
+ delta = cp_convert (ptrdiff_type_node, delta);
+ n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
+ TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
+ force);
+ delta = build_binary_op (PLUS_EXPR, delta, n);
+ return build_ptrmemfunc1 (to_type, delta, NULL_TREE, npfn,
+ NULL_TREE);
+ }
+
if (TREE_CODE (pfn) == PTRMEM_CST)
{
/* We could just build the resulting CONSTRUCTOR now, but we
don't, relying on the general machinery below, together
! with constant-folding, to do the right thing. */
expand_ptrmemfunc_cst (pfn, &ndelta, &idx, &npfn, &ndelta2);
if (npfn)
/* This constant points to a non-virtual function.
*************** build_ptrmemfunc (type, pfn, force)
*** 6195,6206 ****
matter since we won't use it anyhow. */
ndelta2 = integer_zero_node;
}
- else if (same_type_p (to_type, pfn_type))
- /* We don't have to do any conversion. Note that we do this
- after checking for a PTRMEM_CST so that a PTRMEM_CST, cast
- to its own type, will not be considered a legal non-type
- template argument. */
- return pfn;
else
{
ndelta = cp_convert (ptrdiff_type_node,
--- 6237,6242 ----
*************** build_ptrmemfunc (type, pfn, force)
*** 6220,6227 ****
e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
/* If it's a virtual function, this is what we want. */
! e2 = build_ptrmemfunc1 (to_type, delta, idx,
! NULL_TREE, delta2);
pfn = PFN_FROM_PTRMEMFUNC (pfn);
npfn = build1 (NOP_EXPR, type, pfn);
--- 6256,6262 ----
e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
/* If it's a virtual function, this is what we want. */
! e2 = build_ptrmemfunc1 (to_type, delta, idx, NULL_TREE, delta2);
pfn = PFN_FROM_PTRMEMFUNC (pfn);
npfn = build1 (NOP_EXPR, type, pfn);
*************** build_ptrmemfunc (type, pfn, force)
*** 6229,6236 ****
/* But if it's a non-virtual function, or NULL, we use this
instead. */
! e3 = build_ptrmemfunc1 (to_type, delta,
! idx, npfn, NULL_TREE);
return build_conditional_expr (e1, e2, e3);
}
--- 6264,6270 ----
/* But if it's a non-virtual function, or NULL, we use this
instead. */
! e3 = build_ptrmemfunc1 (to_type, delta, idx, npfn, NULL_TREE);
return build_conditional_expr (e1, e2, e3);
}
*************** expand_ptrmemfunc_cst (cst, delta, idx,
*** 6279,6285 ****
if (!DECL_VIRTUAL_P (fn))
{
! *idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
*delta2 = NULL_TREE;
}
--- 6313,6322 ----
if (!DECL_VIRTUAL_P (fn))
{
! if (!flag_new_abi)
! *idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
! else
! *idx = NULL_TREE;
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
*delta2 = NULL_TREE;
}
*************** expand_ptrmemfunc_cst (cst, delta, idx,
*** 6292,6300 ****
tree binfo = binfo_or_else (orig_class, fn_class);
*delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo));
! /* Map everything down one to make room for the null PMF. */
! *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node);
! *pfn = NULL_TREE;
/* Offset from an object of PTR_CLASS to the vptr for ORIG_CLASS. */
*delta2 = size_binop (PLUS_EXPR, *delta,
--- 6329,6349 ----
tree binfo = binfo_or_else (orig_class, fn_class);
*delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo));
! if (!flag_new_abi)
! {
! /* Map everything down one to make room for the null PMF. */
! *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node);
! *pfn = NULL_TREE;
! }
! else
! {
! /* Under the new ABI, we set PFN to twice the index, plus
! one. */
! *idx = NULL_TREE;
! *pfn = size_binop (MULT_EXPR, DECL_VINDEX (fn), integer_two_node);
! *pfn = size_binop (PLUS_EXPR, *pfn, integer_one_node);
! *pfn = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
! }
/* Offset from an object of PTR_CLASS to the vptr for ORIG_CLASS. */
*delta2 = size_binop (PLUS_EXPR, *delta,
*************** tree
*** 6309,6314 ****
--- 6358,6365 ----
delta2_from_ptrmemfunc (t)
tree t;
{
+ my_friendly_assert (!flag_new_abi, 20000221);
+
if (TREE_CODE (t) == PTRMEM_CST)
{
tree delta;
*************** pfn_from_ptrmemfunc (t)
*** 6347,6357 ****
return pfn;
}
! return (build_component_ref
! (build_component_ref (t,
! pfn_or_delta2_identifier, NULL_TREE,
! 0),
! pfn_identifier, NULL_TREE, 0));
}
/* Convert value RHS to type TYPE as preparation for an assignment to
--- 6398,6411 ----
return pfn;
}
! if (flag_new_abi)
! return build_component_ref (t, pfn_identifier, NULL_TREE, 0);
! else
! return (build_component_ref
! (build_component_ref (t,
! pfn_or_delta2_identifier, NULL_TREE,
! 0),
! pfn_identifier, NULL_TREE, 0));
}
/* Convert value RHS to type TYPE as preparation for an assignment to
More information about the Gcc-patches
mailing list