* 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
+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
/* 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. */
#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'. */
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));
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));
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)
}
}
- 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));
/* 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))
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)
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
(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;
{
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;
}
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);
}
}
return;
}
- if (TYPE_PTRMEMFUNC_P (type))
- type = TYPE_PTRMEMFUNC_FN_TYPE (type);
-
switch (TREE_CODE (type))
{
case INTEGER_TYPE:
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);
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)]);
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
{
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;
}
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))
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));
(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 */
| 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 `?:'",
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 `?:'",
return BINFO_OFFSET (binfo);
}
-static tree
+tree
build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
tree type, delta, idx, pfn, delta2;
{
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)))
{
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));
-
- /* 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);
+ 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;
+}
- if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL)
- warning ("assuming pointer to member function is non-virtual");
+/* Return the DELTA, IDX, PFN, and DELTA2 values for the PTRMEM_CST
+ given by CST. */
- if (TREE_CODE (TREE_OPERAND (pfn, 0)) == FUNCTION_DECL
- && DECL_VINDEX (TREE_OPERAND (pfn, 0)))
- {
- /* 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);
+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);
- /* 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);
+ 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))
+ {
+ *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_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_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),
+ pfn_identifier, NULL_TREE, 0));
}
/* Convert value RHS to type TYPE as preparation for an assignment
--- /dev/null
+// 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;
+}