C++ PATCH for pointer-to-member functions

Mark Mitchell mark@codesourcery.com
Tue Mar 23 00:04:00 GMT 1999


Here's a little bit of cleanup for pointer-to-member functions.  We
now don't crash if a NULL pointer-to-member is used as a template
argument (we issue an error, as is proper).  We also print
every-so-slightly better error messages when talking about
pointer-to-members.  This patch also allows removal of some very ugly
name-mangling code in method.c that went poking about inside a
pointer-to-member to try to figure out what function was going to be
called.

-- 
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

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.
	
Index: testsuite/g++.old-deja/g++.pt/ptrmem6.C
===================================================================
RCS file: ptrmem6.C
diff -N ptrmem6.C
*** /dev/null	Sat Dec  5 20:30:03 1998
--- ptrmem6.C	Mon Mar 22 22:57:52 1999
***************
*** 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;
+ }
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.206
diff -c -p -r1.206 cp-tree.h
*** cp-tree.h	1999/03/09 23:02:27	1.206
--- cp-tree.h	1999/03/23 06:57:55
*************** extern int flag_new_for_scope;
*** 1682,1689 ****
  
  /* 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)
  /* 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.  */
--- 1682,1744 ----
  
  /* 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_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.  */
*************** extern int flag_new_for_scope;
*** 1698,1705 ****
  #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))
  
  /* For a pointer-to-member constant `X::Y' this is the RECORD_TYPE for
     `X'.  */
--- 1753,1760 ----
  #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) 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 ocp_convert				PROTO((tree, 
*** 2711,2717 ****
  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_expr_type_conversion		PROTO((int, tree, int));
  extern tree type_promotes_to			PROTO((tree));
  extern tree perform_qualification_conversions   PROTO((tree, tree));
--- 2766,2772 ----
  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((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_type_quals                
*** 3417,3422 ****
--- 3472,3481 ----
  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));
Index: cp/cvt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cvt.c,v
retrieving revision 1.53
diff -c -p -r1.53 cvt.c
*** cvt.c	1999/02/26 23:36:50	1.53
--- cvt.c	1999/03/23 06:57:56
*************** cp_convert_to_pointer (type, expr)
*** 85,91 ****
  	  return error_mark_node;
  	}
  
!       rval = build_type_conversion (CONVERT_EXPR, type, expr, 1);
        if (rval)
  	{
  	  if (rval == error_mark_node)
--- 85,91 ----
  	  return error_mark_node;
  	}
  
!       rval = build_type_conversion (type, expr, 1);
        if (rval)
  	{
  	  if (rval == error_mark_node)
*************** cp_convert_to_pointer (type, expr)
*** 177,185 ****
  	    }
  	}
  
!       if (TREE_CODE (type) == POINTER_TYPE
! 	  && TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
! 	  && TREE_CODE (TREE_TYPE (intype)) == OFFSET_TYPE)
  	{
  	  tree b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
  	  tree b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
--- 177,183 ----
  	    }
  	}
  
!       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));
*************** convert_to_reference (reftype, expr, con
*** 432,438 ****
        /* Look for a user-defined conversion to lvalue that we can use.  */
  
        rval_as_conversion
! 	= build_type_conversion (CONVERT_EXPR, reftype, expr, 1);
  
        if (rval_as_conversion && rval_as_conversion != error_mark_node
  	  && real_lvalue_p (rval_as_conversion))
--- 430,436 ----
        /* Look for a user-defined conversion to lvalue that we can use.  */
  
        rval_as_conversion
! 	= build_type_conversion (reftype, expr, 1);
  
        if (rval_as_conversion && rval_as_conversion != error_mark_node
  	  && real_lvalue_p (rval_as_conversion))
*************** ocp_convert (type, expr, convtype, flags
*** 735,741 ****
        if (IS_AGGR_TYPE (intype))
  	{
  	  tree rval;
! 	  rval = build_type_conversion (CONVERT_EXPR, type, e, 1);
  	  if (rval)
  	    return rval;
  	  if (flags & LOOKUP_COMPLAIN)
--- 733,739 ----
        if (IS_AGGR_TYPE (intype))
  	{
  	  tree rval;
! 	  rval = build_type_conversion (type, e, 1);
  	  if (rval)
  	    return rval;
  	  if (flags & LOOKUP_COMPLAIN)
*************** ocp_convert (type, expr, convtype, flags
*** 762,768 ****
        if (IS_AGGR_TYPE (TREE_TYPE (e)))
  	{
  	  tree rval;
! 	  rval = build_type_conversion (CONVERT_EXPR, type, e, 1);
  	  if (rval)
  	    return rval;
  	  else
--- 760,766 ----
        if (IS_AGGR_TYPE (TREE_TYPE (e)))
  	{
  	  tree rval;
! 	  rval = build_type_conversion (type, e, 1);
  	  if (rval)
  	    return rval;
  	  else
*************** convert_force (type, expr, convtype)
*** 948,955 ****
     (jason 8/9/95)  */
  
  tree
! build_type_conversion (code, xtype, expr, for_sure)
!      enum tree_code code ATTRIBUTE_UNUSED;
       tree xtype, expr;
       int for_sure;
  {
--- 946,952 ----
     (jason 8/9/95)  */
  
  tree
! build_type_conversion (xtype, expr, for_sure)
       tree xtype, expr;
       int for_sure;
  {
Index: cp/error.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/error.c,v
retrieving revision 1.68
diff -c -p -r1.68 error.c
*** error.c	1999/03/13 01:49:11	1.68
--- error.c	1999/03/23 06:57:57
*************** dump_expr (t, nop)
*** 1621,1628 ****
  	      dump_unary_op ("&", pfn, 0);
  	      break;
  	    }
! 	  if (TREE_CODE (idx) == INTEGER_CST
! 	      && TREE_INT_CST_HIGH (idx) == 0)
  	    {
  	      tree virtuals;
  	      unsigned HOST_WIDE_INT n;
--- 1621,1637 ----
  	      dump_unary_op ("&", pfn, 0);
  	      break;
  	    }
! 	  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;
Index: cp/expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/expr.c,v
retrieving revision 1.20
diff -c -p -r1.20 expr.c
*** expr.c	1998/12/16 21:15:23	1.20
--- expr.c	1999/03/23 06:57:57
*************** cplus_expand_expr (exp, target, tmode, m
*** 188,197 ****
  	  }
  	else
  	  {
! 	    /* We don't yet handle pointer-to-member functions this
! 	       way.  */
! 	    my_friendly_abort (0);
! 	    return 0;
  	  }
        }
  
--- 188,203 ----
  	  }
  	else
  	  {
! 	    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);
  	  }
        }
  
Index: cp/method.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/method.c,v
retrieving revision 1.94
diff -c -p -r1.94 method.c
*** method.c	1999/03/16 19:34:49	1.94
--- method.c	1999/03/23 06:57:58
*************** build_overload_value (type, value, in_te
*** 739,747 ****
        return;
      }
  
-   if (TYPE_PTRMEMFUNC_P (type))
-     type = TYPE_PTRMEMFUNC_FN_TYPE (type);
- 
    switch (TREE_CODE (type))
      {
      case INTEGER_TYPE:
--- 739,744 ----
*************** build_overload_value (type, value, in_te
*** 818,863 ****
  	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);
--- 815,820 ----
*************** build_overload_value (type, value, in_te
*** 893,898 ****
--- 850,884 ----
  	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)]);
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.270
diff -c -p -r1.270 pt.c
*** pt.c	1999/03/09 23:02:40	1.270
--- pt.c	1999/03/23 06:58:08
*************** convert_nontype_argument (type, expr)
*** 2577,2583 ****
--- 2577,2590 ----
         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
*************** convert_nontype_argument (type, expr)
*** 2597,2607 ****
  	    {
  	    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");
  	      return NULL_TREE;
  	    }
  
--- 2604,2620 ----
  	    {
  	    bad_argument:
  	      cp_error ("`%E' is not a valid template argument", expr);
! 	      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;
  	    }
  
*************** convert_nontype_argument (type, expr)
*** 2829,2835 ****
  	    expr_type != unknown_type_node)
  	  return error_mark_node;
  
! 	if (TREE_CODE (expr) == CONSTRUCTOR)
  	  {
  	    /* A ptr-to-member constant.  */
  	    if (!same_type_p (type, expr_type))
--- 2842,2848 ----
  	    expr_type != unknown_type_node)
  	  return error_mark_node;
  
! 	if (TREE_CODE (expr) == PTRMEM_CST)
  	  {
  	    /* A ptr-to-member constant.  */
  	    if (!same_type_p (type, expr_type))
Index: cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.144
diff -c -p -r1.144 typeck.c
*** typeck.c	1999/03/19 12:13:36	1.144
--- typeck.c	1999/03/23 06:58:12
*************** static int comp_ptr_ttypes_const PROTO((
*** 51,57 ****
  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));
--- 51,56 ----
*************** build_unary_op (code, xarg, noconvert)
*** 4705,4711 ****
  	    (arg, argtype,
  	     "attempt to take address of bit-field structure member `%s'");
  	else
! 	  addr = build1 (code, argtype, arg);
  
  	/* Address of a static or external variable or
  	   function counts as a constant */
--- 4705,4711 ----
  	    (arg, argtype,
  	     "attempt to take address of bit-field structure member `%s'");
  	else
! 	  addr = build1 (ADDR_EXPR, argtype, arg);
  
  	/* Address of a static or external variable or
  	   function counts as a constant */
*************** build_conditional_expr (ifexp, op1, op2)
*** 5247,5253 ****
  					  | TYPE_QUAL_RESTRICT));
  	  else
  	    tmp = type2;
! 	  tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0);
  	  if (tmp == NULL_TREE)
  	    {
  	      cp_error ("incompatible types `%T' and `%T' in `?:'",
--- 5247,5253 ----
  					  | TYPE_QUAL_RESTRICT));
  	  else
  	    tmp = type2;
! 	  tmp = build_type_conversion (tmp, op1, 0);
  	  if (tmp == NULL_TREE)
  	    {
  	      cp_error ("incompatible types `%T' and `%T' in `?:'",
*************** build_conditional_expr (ifexp, op1, op2)
*** 5273,5279 ****
  	  else
  	    tmp = type1;
  
! 	  tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0);
  	  if (tmp == NULL_TREE)
  	    {
  	      cp_error ("incompatible types `%T' and `%T' in `?:'",
--- 5273,5279 ----
  	  else
  	    tmp = type1;
  
! 	  tmp = build_type_conversion (tmp, op2, 0);
  	  if (tmp == NULL_TREE)
  	    {
  	      cp_error ("incompatible types `%T' and `%T' in `?:'",
*************** build_x_modify_expr (lhs, modifycode, rh
*** 6287,6293 ****
     types.  Return integer_zero_node, if FROM cannot be converted to a
     TO type.  If FORCE is true, then allow reverse conversions as well.  */
  
! static tree
  get_delta_difference (from, to, force)
       tree from, to;
       int force;
--- 6287,6293 ----
     types.  Return integer_zero_node, if FROM cannot be converted to a
     TO type.  If FORCE is true, then allow reverse conversions as well.  */
  
! tree
  get_delta_difference (from, to, force)
       tree from, to;
       int force;
*************** get_delta_difference (from, to, force)
*** 6352,6358 ****
    return BINFO_OFFSET (binfo);
  }
  
! static tree
  build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
       tree type, delta, idx, pfn, delta2;
  {
--- 6352,6358 ----
    return BINFO_OFFSET (binfo);
  }
  
! tree
  build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
       tree type, delta, idx, pfn, delta2;
  {
*************** build_ptrmemfunc (type, pfn, force)
*** 6444,6452 ****
    tree idx = integer_zero_node;
    tree delta = integer_zero_node;
    tree delta2 = integer_zero_node;
-   tree vfield_offset;
    tree npfn = NULL_TREE;
! 
    /* Handle multiple conversions of pointer to member functions.  */
    if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
      {
--- 6444,6452 ----
    tree idx = integer_zero_node;
    tree delta = integer_zero_node;
    tree delta2 = integer_zero_node;
    tree npfn = NULL_TREE;
!   tree fn;
!   
    /* Handle multiple conversions of pointer to member functions.  */
    if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
      {
*************** build_ptrmemfunc (type, pfn, force)
*** 6499,6548 ****
    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);
  
!   if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL)
!     warning ("assuming pointer to member function is non-virtual");
  
!   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);
! 
!       /* 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);
      }
-   else
-     {
-       idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
  
!       if (type == TREE_TYPE (pfn))
! 	{
! 	  npfn = pfn;
! 	}
!       else
! 	{
! 	  npfn = build1 (NOP_EXPR, type, pfn);
! 	  TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
! 	}
      }
  
!   return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2);
  }
  
  /* Convert value RHS to type TYPE as preparation for an assignment
--- 6499,6611 ----
    if (type_unknown_p (pfn))
      return instantiate_type (type, pfn, 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;
! }
! 
! /* Return the DELTA, IDX, PFN, and DELTA2 values for the PTRMEM_CST
!    given by CST.  */
! 
! 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);
  
!   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 (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));
!     }
! }
  
! /* 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_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


More information about the Gcc-patches mailing list