(C++) fix pmfs and MI

Jason Merrill jason@cygnus.com
Tue Jul 27 17:45:00 GMT 1999


We were failing to compensate for the vtable adjustment when calculating
delta for a PMF.  Fixes g++.other/pmf4.C.

I added a macro DECL_VIRTUAL_CONTEXT to make it explicit when that's what
we want, since we're planning to fix DECL_CONTEXT to mean the real context.

1999-07-27  Jason Merrill  <jason@yorick.cygnus.com>

	* cp-tree.h (DECL_VIRTUAL_CONTEXT): New macro.
	* typeck.c (expand_ptrmemfunc_cst): Calculate delta correctly for
	virtual functions and MI.  Simplify.

Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.249
diff -c -p -r1.249 cp-tree.h
*** cp-tree.h	1999/07/27 18:15:20	1.249
--- cp-tree.h	1999/07/28 00:11:00
*************** struct lang_decl
*** 1403,1408 ****
--- 1403,1412 ----
  #define CP_DECL_CONTEXT(NODE) \
    (DECL_CONTEXT (NODE) ? DECL_CONTEXT (NODE) : global_namespace)
  #define FROB_CONTEXT(NODE)   ((NODE) == global_namespace ? NULL_TREE : (NODE))
+ 
+ /* For a virtual function, the base where we find its vtable entry.
+    For a non-virtual function, the base where it is defined.  */
+ #define DECL_VIRTUAL_CONTEXT(NODE) DECL_CONTEXT (NODE)
  
  /* 1 iff NODE has namespace scope, including the global namespace.  */
  #define DECL_NAMESPACE_SCOPE_P(NODE) \
Index: typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.178
diff -c -p -r1.178 typeck.c
*** typeck.c	1999/07/27 01:35:35	1.178
--- typeck.c	1999/07/28 00:11:00
*************** build_x_modify_expr (lhs, modifycode, rh
*** 6078,6085 ****
  
  /* Get difference in deltas for different pointer to member function
     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;
--- 6078,6090 ----
  
  /* Get difference in deltas for different pointer to member function
     types.  Return integer_zero_node, if FROM cannot be converted to a
!    TO type.  If FORCE is true, then allow reverse conversions as well.
  
+    Note that the naming of FROM and TO is kind of backwards; the return
+    value is what we add to a TO in order to get a FROM.  They are named
+    this way because we call this function to find out how to convert from
+    a pointer to member of FROM to a pointer to member of TO.  */
+ 
  static tree
  get_delta_difference (from, to, force)
       tree from, to;
*************** expand_ptrmemfunc_cst (cst, delta, idx, 
*** 6338,6374 ****
  {
    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));
      }
  }
  
--- 6343,6383 ----
  {
    tree type = TREE_TYPE (cst);
    tree fn = PTRMEM_CST_MEMBER (cst);
+   tree ptr_class, fn_class;
  
    my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
! 
!   /* The class that the function belongs to.  */
!   fn_class = DECL_CLASS_CONTEXT (fn);
! 
!   /* The class that we're creating a pointer to member of.  */
!   ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
! 
!   /* First, calculate the adjustment to the function's class.  */
!   *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0);
! 
    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;
      }
    else
      {
!       /* If we're dealing with a virtual function, we have to adjust 'this'
!          again, to point to the base which provides the vtable entry for
!          fn; the call will do the opposite adjustment.  */
!       tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
!       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,
! 			    get_vfield_offset (TYPE_BINFO (orig_class)));
      }
  }
  


More information about the Gcc-patches mailing list