From e08a8f45f515854210dc47d78e13302536d2fc35 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Tue, 23 Mar 1999 00:01:48 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 33 +++++ gcc/cp/cp-tree.h | 69 ++++++++- gcc/cp/cvt.c | 15 +- gcc/cp/error.c | 13 +- gcc/cp/expr.c | 14 +- gcc/cp/method.c | 72 ++++------ gcc/cp/pt.c | 25 +++- gcc/cp/typeck.c | 146 ++++++++++++++------ gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C | 34 +++++ 9 files changed, 310 insertions(+), 111 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 384e3e9141e..3dd84a890eb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,36 @@ +1999-03-22 Mark Mitchell + + * 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 * init.c (build_member_call): Handle template-id expressions diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 551803bb6ad..59f3e30a3bb 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 9f29c658697..72721ce9bca 100644 --- a/gcc/cp/cvt.c +++ b/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; { diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 7ca64092407..90f0a369758 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -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; diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 3dc8eae26e6..22dd0751319 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -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); } } diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 096d6628b94..ecfa82c4012 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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)]); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4e9c52fc588..38e317c5468 100644 --- a/gcc/cp/pt.c +++ b/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)) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index cfd931927ea..c1aa2142a90 100644 --- a/gcc/cp/typeck.c +++ b/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)); - - /* 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 diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C new file mode 100644 index 00000000000..946e6244f4a --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C @@ -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 g() {} +template +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; +} -- 2.30.2