cp-tree.h (TYPE_PTRMEMFUNC_P): Use TYPE_PTRMEMFUNC_FLAG.
* cp-tree.h (TYPE_PTRMEMFUNC_P): Use TYPE_PTRMEMFUNC_FLAG. Document internals of pointer-to-member-functions. (DELTA2_FROM_PTRMEMFUNC): Make it call delta2_from_ptrmemfunc. (PFN_FROM_PTRMEMFUNC): Similarly. (build_type_conversion): Remove unused parameter. (build_ptrmemfunc1): Declare. (expand_ptrmemfunc_cst): New function. (delta2_from_ptrmemfunc): Likewise. (pfn_from_ptrmemfunc): Likewise. * cvt.c (cp_convert_to_pointer): Remove unused parameter to build_type_conversion. Use TYPE_PTRMEM_P for readability. (convert_to_reference): Remove unused parameter to build_type_conversion. (ocp_convert): Likewise. (build_user_type_conversion): Likewise. * error.c (dump_expr): Handle NULL pointer-to-member functions. * expr.c (cplus_expand_expr): Handle PTRMEM_CSTs for functions. * method.c (build_overload_value): Don't go splitting CONSTRUCTORs open when handling pointer-to-member functions. * pt.c (convert_nontype_argument): Clean up error messages. Be more stringent with pointers-to-members. * typeck.c (build_ptrmemfunc1): Don't declare. Make it global. (build_unary_op): Tidy ever-so-slightly. (build_conditional_expr): Remove extra parameter to build_type_conversion. (build_ptrmemfunc): Build PTRMEM_CSTs if we know what function we're using. (expand_ptrmemfunc_cst): Define. (delta2_from_ptrmemfunc): Likewise. (pfn_from_ptrmemfunc): Likewise. From-SVN: r25913
This commit is contained in:
parent
edebba7aae
commit
e08a8f45f5
9 changed files with 309 additions and 110 deletions
|
@ -1,3 +1,36 @@
|
|||
1999-03-22 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* cp-tree.h (TYPE_PTRMEMFUNC_P): Use TYPE_PTRMEMFUNC_FLAG.
|
||||
Document internals of pointer-to-member-functions.
|
||||
(DELTA2_FROM_PTRMEMFUNC): Make it call delta2_from_ptrmemfunc.
|
||||
(PFN_FROM_PTRMEMFUNC): Similarly.
|
||||
(build_type_conversion): Remove unused parameter.
|
||||
(build_ptrmemfunc1): Declare.
|
||||
(expand_ptrmemfunc_cst): New function.
|
||||
(delta2_from_ptrmemfunc): Likewise.
|
||||
(pfn_from_ptrmemfunc): Likewise.
|
||||
* cvt.c (cp_convert_to_pointer): Remove unused parameter to
|
||||
build_type_conversion. Use TYPE_PTRMEM_P for readability.
|
||||
(convert_to_reference): Remove unused parameter to
|
||||
build_type_conversion.
|
||||
(ocp_convert): Likewise.
|
||||
(build_user_type_conversion): Likewise.
|
||||
* error.c (dump_expr): Handle NULL pointer-to-member functions.
|
||||
* expr.c (cplus_expand_expr): Handle PTRMEM_CSTs for functions.
|
||||
* method.c (build_overload_value): Don't go splitting CONSTRUCTORs
|
||||
open when handling pointer-to-member functions.
|
||||
* pt.c (convert_nontype_argument): Clean up error messages. Be
|
||||
more stringent with pointers-to-members.
|
||||
* typeck.c (build_ptrmemfunc1): Don't declare. Make it global.
|
||||
(build_unary_op): Tidy ever-so-slightly.
|
||||
(build_conditional_expr): Remove extra parameter to
|
||||
build_type_conversion.
|
||||
(build_ptrmemfunc): Build PTRMEM_CSTs if we know what function
|
||||
we're using.
|
||||
(expand_ptrmemfunc_cst): Define.
|
||||
(delta2_from_ptrmemfunc): Likewise.
|
||||
(pfn_from_ptrmemfunc): Likewise.
|
||||
|
||||
1999-03-19 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* init.c (build_member_call): Handle template-id expressions
|
||||
|
|
|
@ -1682,8 +1682,63 @@ extern int flag_new_for_scope;
|
|||
|
||||
/* Nonzero for _TYPE node means that this type is a pointer to member
|
||||
function type. */
|
||||
#define TYPE_PTRMEMFUNC_P(NODE) (TREE_CODE(NODE) == RECORD_TYPE && TYPE_LANG_SPECIFIC(NODE)->type_flags.ptrmemfunc_flag)
|
||||
#define TYPE_PTRMEMFUNC_FLAG(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.ptrmemfunc_flag)
|
||||
#define TYPE_PTRMEMFUNC_P(NODE) \
|
||||
(TREE_CODE(NODE) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (NODE))
|
||||
#define TYPE_PTRMEMFUNC_FLAG(NODE) \
|
||||
(TYPE_LANG_SPECIFIC(NODE)->type_flags.ptrmemfunc_flag)
|
||||
|
||||
/* A pointer-to-function member type looks like:
|
||||
|
||||
struct {
|
||||
short __delta;
|
||||
short __index;
|
||||
union {
|
||||
P __pfn;
|
||||
short __delta2;
|
||||
} __pfn_or_delta2;
|
||||
};
|
||||
|
||||
where P is a POINTER_TYPE to a METHOD_TYPE appropriate for the
|
||||
pointer to member. The fields are used as follows:
|
||||
|
||||
If __INDEX is -1, then the function to call is non-virtual, and
|
||||
is located at the address given by __PFN.
|
||||
|
||||
If __INDEX is zero, then this a NULL pointer-to-member.
|
||||
|
||||
Otherwise, the function to call is virtual. Then, __DELTA2 gives
|
||||
the offset from an instance of the object to the virtual function
|
||||
table, and __INDEX - 1 is the index into the vtable to use to
|
||||
find the function.
|
||||
|
||||
The value to use for the THIS parameter is the address of the
|
||||
object plus __DELTA.
|
||||
|
||||
For example, given:
|
||||
|
||||
struct B1 {
|
||||
int i;
|
||||
};
|
||||
|
||||
struct B2 {
|
||||
double d;
|
||||
void f();
|
||||
};
|
||||
|
||||
struct S : public B1, B2 {};
|
||||
|
||||
the pointer-to-member for `&S::f' looks like:
|
||||
|
||||
{ 4, -1, { &f__2B2 } };
|
||||
|
||||
The `4' means that given an `S*' you have to add 4 bytes to get to
|
||||
the address of the `B2*'. Then, the -1 indicates that this is a
|
||||
non-virtual function. Of course, `&f__2B2' is the name of that
|
||||
function.
|
||||
|
||||
(Of course, the exactl 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. */
|
||||
|
@ -1698,8 +1753,8 @@ extern int flag_new_for_scope;
|
|||
#define TYPE_GET_PTRMEMFUNC_TYPE(NODE) ((tree)TYPE_LANG_SPECIFIC(NODE))
|
||||
#define TYPE_SET_PTRMEMFUNC_TYPE(NODE, VALUE) (TYPE_LANG_SPECIFIC(NODE) = ((struct lang_type *)(void*)(VALUE)))
|
||||
/* These are to get the delta2 and pfn fields from a TYPE_PTRMEMFUNC_P. */
|
||||
#define DELTA2_FROM_PTRMEMFUNC(NODE) (build_component_ref (build_component_ref ((NODE), pfn_or_delta2_identifier, NULL_TREE, 0), delta2_identifier, NULL_TREE, 0))
|
||||
#define PFN_FROM_PTRMEMFUNC(NODE) (build_component_ref (build_component_ref ((NODE), pfn_or_delta2_identifier, NULL_TREE, 0), pfn_identifier, NULL_TREE, 0))
|
||||
#define DELTA2_FROM_PTRMEMFUNC(NODE) delta2_from_ptrmemfunc ((NODE))
|
||||
#define PFN_FROM_PTRMEMFUNC(NODE) pfn_from_ptrmemfunc ((NODE))
|
||||
|
||||
/* For a pointer-to-member constant `X::Y' this is the RECORD_TYPE for
|
||||
`X'. */
|
||||
|
@ -2711,7 +2766,7 @@ extern tree ocp_convert PROTO((tree, tree, int, int));
|
|||
extern tree cp_convert PROTO((tree, tree));
|
||||
extern tree convert PROTO((tree, tree));
|
||||
extern tree convert_force PROTO((tree, tree, int));
|
||||
extern tree build_type_conversion PROTO((enum tree_code, tree, tree, int));
|
||||
extern tree build_type_conversion PROTO((tree, tree, int));
|
||||
extern tree build_expr_type_conversion PROTO((int, tree, int));
|
||||
extern tree type_promotes_to PROTO((tree));
|
||||
extern tree perform_qualification_conversions PROTO((tree, tree));
|
||||
|
@ -3417,6 +3472,10 @@ extern int cp_type_quals PROTO((tree));
|
|||
extern int cp_has_mutable_p PROTO((tree));
|
||||
extern int at_least_as_qualified_p PROTO((tree, tree));
|
||||
extern int more_qualified_p PROTO((tree, tree));
|
||||
extern tree build_ptrmemfunc1 PROTO((tree, tree, tree, tree, tree));
|
||||
extern void expand_ptrmemfunc_cst PROTO((tree, tree *, tree *, tree *, tree *));
|
||||
extern tree delta2_from_ptrmemfunc PROTO((tree));
|
||||
extern tree pfn_from_ptrmemfunc PROTO((tree));
|
||||
|
||||
/* in typeck2.c */
|
||||
extern tree error_not_base_type PROTO((tree, tree));
|
||||
|
|
15
gcc/cp/cvt.c
15
gcc/cp/cvt.c
|
@ -85,7 +85,7 @@ cp_convert_to_pointer (type, expr)
|
|||
return error_mark_node;
|
||||
}
|
||||
|
||||
rval = build_type_conversion (CONVERT_EXPR, type, expr, 1);
|
||||
rval = build_type_conversion (type, expr, 1);
|
||||
if (rval)
|
||||
{
|
||||
if (rval == error_mark_node)
|
||||
|
@ -177,9 +177,7 @@ cp_convert_to_pointer (type, expr)
|
|||
}
|
||||
}
|
||||
|
||||
if (TREE_CODE (type) == POINTER_TYPE
|
||||
&& TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
|
||||
&& TREE_CODE (TREE_TYPE (intype)) == OFFSET_TYPE)
|
||||
if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|
||||
{
|
||||
tree b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
|
||||
tree b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
|
||||
|
@ -432,7 +430,7 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
|
|||
/* Look for a user-defined conversion to lvalue that we can use. */
|
||||
|
||||
rval_as_conversion
|
||||
= build_type_conversion (CONVERT_EXPR, reftype, expr, 1);
|
||||
= build_type_conversion (reftype, expr, 1);
|
||||
|
||||
if (rval_as_conversion && rval_as_conversion != error_mark_node
|
||||
&& real_lvalue_p (rval_as_conversion))
|
||||
|
@ -735,7 +733,7 @@ ocp_convert (type, expr, convtype, flags)
|
|||
if (IS_AGGR_TYPE (intype))
|
||||
{
|
||||
tree rval;
|
||||
rval = build_type_conversion (CONVERT_EXPR, type, e, 1);
|
||||
rval = build_type_conversion (type, e, 1);
|
||||
if (rval)
|
||||
return rval;
|
||||
if (flags & LOOKUP_COMPLAIN)
|
||||
|
@ -762,7 +760,7 @@ ocp_convert (type, expr, convtype, flags)
|
|||
if (IS_AGGR_TYPE (TREE_TYPE (e)))
|
||||
{
|
||||
tree rval;
|
||||
rval = build_type_conversion (CONVERT_EXPR, type, e, 1);
|
||||
rval = build_type_conversion (type, e, 1);
|
||||
if (rval)
|
||||
return rval;
|
||||
else
|
||||
|
@ -948,8 +946,7 @@ convert_force (type, expr, convtype)
|
|||
(jason 8/9/95) */
|
||||
|
||||
tree
|
||||
build_type_conversion (code, xtype, expr, for_sure)
|
||||
enum tree_code code ATTRIBUTE_UNUSED;
|
||||
build_type_conversion (xtype, expr, for_sure)
|
||||
tree xtype, expr;
|
||||
int for_sure;
|
||||
{
|
||||
|
|
|
@ -1621,8 +1621,17 @@ dump_expr (t, nop)
|
|||
dump_unary_op ("&", pfn, 0);
|
||||
break;
|
||||
}
|
||||
if (TREE_CODE (idx) == INTEGER_CST
|
||||
&& TREE_INT_CST_HIGH (idx) == 0)
|
||||
else if (TREE_CODE (idx) == INTEGER_CST
|
||||
&& tree_int_cst_equal (idx, integer_zero_node))
|
||||
{
|
||||
/* A NULL pointer-to-member constant. */
|
||||
OB_PUTS ("((");
|
||||
dump_type (TREE_TYPE (t), 0);
|
||||
OB_PUTS (") 0)");
|
||||
break;
|
||||
}
|
||||
else if (TREE_CODE (idx) == INTEGER_CST
|
||||
&& TREE_INT_CST_HIGH (idx) == 0)
|
||||
{
|
||||
tree virtuals;
|
||||
unsigned HOST_WIDE_INT n;
|
||||
|
|
|
@ -188,10 +188,16 @@ cplus_expand_expr (exp, target, tmode, modifier)
|
|||
}
|
||||
else
|
||||
{
|
||||
/* We don't yet handle pointer-to-member functions this
|
||||
way. */
|
||||
my_friendly_abort (0);
|
||||
return 0;
|
||||
tree delta;
|
||||
tree idx;
|
||||
tree pfn;
|
||||
tree delta2;
|
||||
|
||||
expand_ptrmemfunc_cst (exp, &delta, &idx, &pfn, &delta2);
|
||||
|
||||
return expand_expr (build_ptrmemfunc1 (type, delta, idx,
|
||||
pfn, delta2),
|
||||
target, tmode, modifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -739,9 +739,6 @@ build_overload_value (type, value, in_template)
|
|||
return;
|
||||
}
|
||||
|
||||
if (TYPE_PTRMEMFUNC_P (type))
|
||||
type = TYPE_PTRMEMFUNC_FN_TYPE (type);
|
||||
|
||||
switch (TREE_CODE (type))
|
||||
{
|
||||
case INTEGER_TYPE:
|
||||
|
@ -818,46 +815,6 @@ build_overload_value (type, value, in_template)
|
|||
return;
|
||||
}
|
||||
case POINTER_TYPE:
|
||||
if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
|
||||
&& TREE_CODE (value) != ADDR_EXPR)
|
||||
{
|
||||
if (TREE_CODE (value) == CONSTRUCTOR)
|
||||
{
|
||||
/* This is dangerous code, crack built up pointer to members. */
|
||||
tree args = CONSTRUCTOR_ELTS (value);
|
||||
tree a1 = TREE_VALUE (args);
|
||||
tree a2 = TREE_VALUE (TREE_CHAIN (args));
|
||||
tree a3 = CONSTRUCTOR_ELTS (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))));
|
||||
a3 = TREE_VALUE (a3);
|
||||
STRIP_NOPS (a3);
|
||||
if (TREE_CODE (a1) == INTEGER_CST
|
||||
&& TREE_CODE (a2) == INTEGER_CST)
|
||||
{
|
||||
build_overload_int (a1, in_template);
|
||||
OB_PUTC ('_');
|
||||
build_overload_int (a2, in_template);
|
||||
OB_PUTC ('_');
|
||||
if (TREE_CODE (a3) == ADDR_EXPR)
|
||||
{
|
||||
a3 = TREE_OPERAND (a3, 0);
|
||||
if (TREE_CODE (a3) == FUNCTION_DECL)
|
||||
{
|
||||
numeric_output_need_bar = 0;
|
||||
build_overload_identifier (DECL_ASSEMBLER_NAME (a3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (a3) == INTEGER_CST)
|
||||
{
|
||||
OB_PUTC ('i');
|
||||
build_overload_int (a3, in_template);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
sorry ("template instantiation with pointer to method that is too complex");
|
||||
return;
|
||||
}
|
||||
if (TREE_CODE (value) == INTEGER_CST)
|
||||
{
|
||||
build_overload_int (value, in_template);
|
||||
|
@ -893,6 +850,35 @@ build_overload_value (type, value, in_template)
|
|||
my_friendly_abort (71);
|
||||
break; /* not really needed */
|
||||
|
||||
case RECORD_TYPE:
|
||||
{
|
||||
tree delta;
|
||||
tree idx;
|
||||
tree pfn;
|
||||
tree delta2;
|
||||
|
||||
my_friendly_assert (TYPE_PTRMEMFUNC_P (type), 0);
|
||||
my_friendly_assert (TREE_CODE (value) == PTRMEM_CST, 0);
|
||||
|
||||
expand_ptrmemfunc_cst (value, &delta, &idx, &pfn, &delta2);
|
||||
build_overload_int (delta, in_template);
|
||||
OB_PUTC ('_');
|
||||
build_overload_int (idx, in_template);
|
||||
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, in_template);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
sorry ("conversion of %s as template parameter",
|
||||
tree_code_name [(int) TREE_CODE (type)]);
|
||||
|
|
25
gcc/cp/pt.c
25
gcc/cp/pt.c
|
@ -2577,7 +2577,14 @@ convert_nontype_argument (type, expr)
|
|||
Check this first since if expr_type is the unknown_type_node
|
||||
we would otherwise complain below. */
|
||||
;
|
||||
else if (TYPE_PTRMEM_P (expr_type)
|
||||
|| TYPE_PTRMEMFUNC_P (expr_type))
|
||||
{
|
||||
if (TREE_CODE (expr) != PTRMEM_CST)
|
||||
goto bad_argument;
|
||||
}
|
||||
else if (TYPE_PTR_P (expr_type)
|
||||
|| TYPE_PTRMEM_P (expr_type)
|
||||
|| TREE_CODE (expr_type) == ARRAY_TYPE
|
||||
|| TREE_CODE (type) == REFERENCE_TYPE
|
||||
/* If expr is the address of an overloaded function, we
|
||||
|
@ -2597,11 +2604,17 @@ convert_nontype_argument (type, expr)
|
|||
{
|
||||
bad_argument:
|
||||
cp_error ("`%E' is not a valid template argument", expr);
|
||||
error ("it must be %s%s with external linkage",
|
||||
TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
|
||||
? "a pointer to " : "",
|
||||
TREE_CODE (TREE_TYPE (TREE_TYPE (expr))) == FUNCTION_TYPE
|
||||
? "a function" : "an object");
|
||||
if (TYPE_PTR_P (expr_type))
|
||||
{
|
||||
if (TREE_CODE (TREE_TYPE (expr_type)) == FUNCTION_TYPE)
|
||||
cp_error ("it must be the address of a function with external linkage");
|
||||
else
|
||||
cp_error ("it must be the address of an object with external linkage");
|
||||
}
|
||||
else if (TYPE_PTRMEM_P (expr_type)
|
||||
|| TYPE_PTRMEMFUNC_P (expr_type))
|
||||
cp_error ("it must be a pointer-to-member of the form `&X::Y'");
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
|
@ -2829,7 +2842,7 @@ convert_nontype_argument (type, expr)
|
|||
expr_type != unknown_type_node)
|
||||
return error_mark_node;
|
||||
|
||||
if (TREE_CODE (expr) == CONSTRUCTOR)
|
||||
if (TREE_CODE (expr) == PTRMEM_CST)
|
||||
{
|
||||
/* A ptr-to-member constant. */
|
||||
if (!same_type_p (type, expr_type))
|
||||
|
|
144
gcc/cp/typeck.c
144
gcc/cp/typeck.c
|
@ -51,7 +51,6 @@ static int comp_ptr_ttypes_const PROTO((tree, tree));
|
|||
static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
|
||||
static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
|
||||
tree, int));
|
||||
static tree build_ptrmemfunc1 PROTO((tree, tree, tree, tree, tree));
|
||||
static tree common_base_type PROTO((tree, tree));
|
||||
#if 0
|
||||
static tree convert_sequence PROTO((tree, tree));
|
||||
|
@ -4705,7 +4704,7 @@ build_unary_op (code, xarg, noconvert)
|
|||
(arg, argtype,
|
||||
"attempt to take address of bit-field structure member `%s'");
|
||||
else
|
||||
addr = build1 (code, argtype, arg);
|
||||
addr = build1 (ADDR_EXPR, argtype, arg);
|
||||
|
||||
/* Address of a static or external variable or
|
||||
function counts as a constant */
|
||||
|
@ -5247,7 +5246,7 @@ build_conditional_expr (ifexp, op1, op2)
|
|||
| TYPE_QUAL_RESTRICT));
|
||||
else
|
||||
tmp = type2;
|
||||
tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0);
|
||||
tmp = build_type_conversion (tmp, op1, 0);
|
||||
if (tmp == NULL_TREE)
|
||||
{
|
||||
cp_error ("incompatible types `%T' and `%T' in `?:'",
|
||||
|
@ -5273,7 +5272,7 @@ build_conditional_expr (ifexp, op1, op2)
|
|||
else
|
||||
tmp = type1;
|
||||
|
||||
tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0);
|
||||
tmp = build_type_conversion (tmp, op2, 0);
|
||||
if (tmp == NULL_TREE)
|
||||
{
|
||||
cp_error ("incompatible types `%T' and `%T' in `?:'",
|
||||
|
@ -6352,7 +6351,7 @@ get_delta_difference (from, to, force)
|
|||
return BINFO_OFFSET (binfo);
|
||||
}
|
||||
|
||||
static tree
|
||||
tree
|
||||
build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
|
||||
tree type, delta, idx, pfn, delta2;
|
||||
{
|
||||
|
@ -6444,9 +6443,9 @@ build_ptrmemfunc (type, pfn, force)
|
|||
tree idx = integer_zero_node;
|
||||
tree delta = integer_zero_node;
|
||||
tree delta2 = integer_zero_node;
|
||||
tree vfield_offset;
|
||||
tree npfn = NULL_TREE;
|
||||
|
||||
tree fn;
|
||||
|
||||
/* Handle multiple conversions of pointer to member functions. */
|
||||
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
|
||||
{
|
||||
|
@ -6499,50 +6498,113 @@ build_ptrmemfunc (type, pfn, force)
|
|||
if (type_unknown_p (pfn))
|
||||
return instantiate_type (type, pfn, 1);
|
||||
|
||||
if (!force
|
||||
&& comp_target_types (type, TREE_TYPE (pfn), 0) != 1)
|
||||
cp_error ("conversion to `%T' from `%T'", type, TREE_TYPE (pfn));
|
||||
fn = TREE_OPERAND (pfn, 0);
|
||||
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
|
||||
npfn = make_node (PTRMEM_CST);
|
||||
TREE_TYPE (npfn) = build_ptrmemfunc_type (type);
|
||||
PTRMEM_CST_MEMBER (npfn) = fn;
|
||||
return npfn;
|
||||
}
|
||||
|
||||
/* Allow pointer to member conversions here. */
|
||||
delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
|
||||
TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
|
||||
force);
|
||||
delta2 = build_binary_op (PLUS_EXPR, delta2, delta, 1);
|
||||
/* Return the DELTA, IDX, PFN, and DELTA2 values for the PTRMEM_CST
|
||||
given by CST. */
|
||||
|
||||
if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL)
|
||||
warning ("assuming pointer to member function is non-virtual");
|
||||
void
|
||||
expand_ptrmemfunc_cst (cst, delta, idx, pfn, delta2)
|
||||
tree cst;
|
||||
tree *delta;
|
||||
tree *idx;
|
||||
tree *pfn;
|
||||
tree *delta2;
|
||||
{
|
||||
tree type = TREE_TYPE (cst);
|
||||
tree fn = PTRMEM_CST_MEMBER (cst);
|
||||
|
||||
if (TREE_CODE (TREE_OPERAND (pfn, 0)) == FUNCTION_DECL
|
||||
&& DECL_VINDEX (TREE_OPERAND (pfn, 0)))
|
||||
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
|
||||
|
||||
*delta
|
||||
= get_delta_difference (TYPE_METHOD_BASETYPE
|
||||
(TREE_TYPE (fn)),
|
||||
TYPE_PTRMEMFUNC_OBJECT_TYPE (type),
|
||||
/*force=*/0);
|
||||
if (!DECL_VIRTUAL_P (fn))
|
||||
{
|
||||
/* Find the offset to the vfield pointer in the object. */
|
||||
vfield_offset = get_binfo (DECL_CONTEXT (TREE_OPERAND (pfn, 0)),
|
||||
DECL_CLASS_CONTEXT (TREE_OPERAND (pfn, 0)),
|
||||
0);
|
||||
vfield_offset = get_vfield_offset (vfield_offset);
|
||||
delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2);
|
||||
|
||||
/* Map everything down one to make room for the null pointer to member. */
|
||||
idx = size_binop (PLUS_EXPR,
|
||||
DECL_VINDEX (TREE_OPERAND (pfn, 0)),
|
||||
integer_one_node);
|
||||
*idx = size_binop (MINUS_EXPR, integer_zero_node,
|
||||
integer_one_node);
|
||||
*pfn = build_addr_func (fn);
|
||||
if (!same_type_p (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)),
|
||||
TYPE_PTRMEMFUNC_OBJECT_TYPE (type)))
|
||||
*pfn = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
|
||||
*pfn);
|
||||
*delta2 = NULL_TREE;
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
|
||||
*idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn),
|
||||
integer_one_node);
|
||||
*pfn = NULL_TREE;
|
||||
*delta2 = get_binfo (DECL_CONTEXT (fn),
|
||||
DECL_CLASS_CONTEXT (fn),
|
||||
0);
|
||||
*delta2 = get_vfield_offset (*delta2);
|
||||
*delta2 = size_binop (PLUS_EXPR, *delta2,
|
||||
build_binary_op (PLUS_EXPR,
|
||||
*delta,
|
||||
integer_zero_node,
|
||||
1));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == TREE_TYPE (pfn))
|
||||
{
|
||||
npfn = pfn;
|
||||
}
|
||||
else
|
||||
{
|
||||
npfn = build1 (NOP_EXPR, type, pfn);
|
||||
TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
|
||||
}
|
||||
/* Return an expression for DELTA2 from the pointer-to-member function
|
||||
given by T. */
|
||||
|
||||
tree
|
||||
delta2_from_ptrmemfunc (t)
|
||||
tree t;
|
||||
{
|
||||
if (TREE_CODE (t) == PTRMEM_CST)
|
||||
{
|
||||
tree delta;
|
||||
tree idx;
|
||||
tree pfn;
|
||||
tree delta2;
|
||||
|
||||
expand_ptrmemfunc_cst (t, &delta, &idx, &pfn, &delta2);
|
||||
if (delta2)
|
||||
return delta2;
|
||||
}
|
||||
|
||||
return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2);
|
||||
return (build_component_ref
|
||||
(build_component_ref (t,
|
||||
pfn_or_delta2_identifier, NULL_TREE,
|
||||
0),
|
||||
delta2_identifier, NULL_TREE, 0));
|
||||
}
|
||||
|
||||
/* Return an expression for PFN from the pointer-to-member function
|
||||
given by T. */
|
||||
|
||||
tree
|
||||
pfn_from_ptrmemfunc (t)
|
||||
tree t;
|
||||
{
|
||||
if (TREE_CODE (t) == PTRMEM_CST)
|
||||
{
|
||||
tree delta;
|
||||
tree idx;
|
||||
tree pfn;
|
||||
tree delta2;
|
||||
|
||||
expand_ptrmemfunc_cst (t, &delta, &idx, &pfn, &delta2);
|
||||
if (pfn)
|
||||
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
|
||||
|
|
34
gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
Normal file
34
gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Build don't link:
|
||||
|
||||
class A {
|
||||
public:
|
||||
virtual void f();
|
||||
int i;
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
public:
|
||||
void f();
|
||||
int j;
|
||||
};
|
||||
|
||||
template <void (A::*)() >
|
||||
void g() {}
|
||||
template <int A::*>
|
||||
void h() {}
|
||||
|
||||
|
||||
int main() {
|
||||
g<&A::f>();
|
||||
h<&A::i>();
|
||||
g<&B::f>(); // ERROR -
|
||||
h<&B::j>(); // ERROR -
|
||||
g<(void (A::*)()) &A::f>(); // ERROR - XFAIL *-*-*
|
||||
h<(int A::*) &A::i>(); // ERROR -
|
||||
g<(void (A::*)()) &B::f>(); // ERROR -
|
||||
h<(int A::*) &B::j>(); // ERROR -
|
||||
g<(void (A::*)()) 0>(); // ERROR -
|
||||
h<(int A::*) 0>(); // ERROR -
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue