C++ Patch (Was: Virtual Mem Func Ptr Call Fails When Base Class Has No Vtable)

Martin v. Loewis martinATmira.isdn.cs.tu-berlin.de
Wed Sep 15 01:12:00 GMT 1999


> Yes, sounds like the right fix to me.  Please do up the fix and submit
> it.

Attached below. Because of re-indentation, it looks larger than it
actually is.

> `if that function is virtual the function actually called will be the
> final overrider'

Ok. Since that distinguishes between qualified and non-qualified
calls, a word about pointer-to-member calls would have done good.

Regards,
Martin

1999-09-15  Martin v. Loewis  <martin@mira.isdn.cs.tu-berlin.de>

	* typeck.c (get_member_function_from_ptrfunc): Always consider
	virtuality inside member pointer.

// Based on a test case by Andrew Bell <andrew.bell@bigfoot.com>
// Check for pointer-to-virtual-function calls on 
// bases without virtual functions.

struct B{};

struct D:B{
  virtual void foo();
};

void D::foo(){}

int main()
{
  B *b = new D;
  void (B::*f)() = static_cast<void (B::*)()>(&D::foo);
  (b->*f)();
}

Index: typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.209
diff -c -3 -p -r1.209 typeck.c
*** typeck.c	1999/09/13 13:41:30	1.209
--- typeck.c	1999/09/15 08:02:28
*************** get_member_function_from_ptrfunc (instan
*** 2818,2883 ****
  					       NULL_TREE, 0));
        e3 = PFN_FROM_PTRMEMFUNC (function);
  
!       if (TYPE_SIZE (basetype) != NULL_TREE
! 	  && ! TYPE_VIRTUAL_P (basetype))
! 	/* If basetype doesn't have virtual functions, don't emit code to
! 	   handle that case.  */
! 	e1 = e3;
!       else
! 	{
! 	  /* Promoting idx before saving it improves performance on RISC
! 	     targets.  Without promoting, the first compare used
! 	     load-with-sign-extend, while the second used normal load then
! 	     shift to sign-extend.  An optimizer flaw, perhaps, but it's
! 	     easier to make this change.  */
! 	  idx = save_expr (default_conversion
! 			   (build_component_ref (function,
! 						 index_identifier,
! 						 NULL_TREE, 0)));
! 	  e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
! 
! 	  /* Convert down to the right base, before using the instance.  */
! 	  instance = convert_pointer_to_real (basetype, instance_ptr);
! 	  if (instance == error_mark_node && instance_ptr != error_mark_node)
! 	    return instance;
! 
! 	  vtbl = convert_pointer_to (ptr_type_node, instance);
! 	  delta2 = DELTA2_FROM_PTRMEMFUNC (function);
! 	  vtbl = build
! 	    (PLUS_EXPR,
! 	     build_pointer_type (build_pointer_type (vtable_entry_type)),
! 	     vtbl, cp_convert (ptrdiff_type_node, delta2));
! 	  vtbl = build_indirect_ref (vtbl, NULL_PTR);
! 	  aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
! 							 idx,
! 							 integer_one_node));
! 	  if (! flag_vtable_thunks)
! 	    {
! 	      aref = save_expr (aref);
  
! 	      delta = build_binary_op
! 		(PLUS_EXPR,
! 		 build_conditional_expr (e1,
! 					 build_component_ref (aref,
! 							      delta_identifier,
! 							      NULL_TREE, 0),
! 					 integer_zero_node),
! 		 delta);
! 	    }
  
! 	  if (flag_vtable_thunks)
! 	    e2 = aref;
! 	  else
! 	    e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
! 	  TREE_TYPE (e2) = TREE_TYPE (e3);
! 	  e1 = build_conditional_expr (e1, e2, e3);
  
! 	  /* Make sure this doesn't get evaluated first inside one of the
! 	     branches of the COND_EXPR.  */
! 	  if (TREE_CODE (instance_ptr) == SAVE_EXPR)
! 	    e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
! 			instance_ptr, e1);
  	}
  
        *instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
  				instance_ptr, delta);
--- 2818,2880 ----
  					       NULL_TREE, 0));
        e3 = PFN_FROM_PTRMEMFUNC (function);
  
!       /* This used avoid checking for virtual functions if basetype
! 	 has no virtual functions, according to an earlier ANSI draft.
! 	 With the final ISO C++ rules, such an optimization is
! 	 incorrect.  */
  
!       /* Promoting idx before saving it improves performance on RISC
! 	 targets.  Without promoting, the first compare used
! 	 load-with-sign-extend, while the second used normal load then
! 	 shift to sign-extend.  An optimizer flaw, perhaps, but it's
! 	 easier to make this change.  */
!       idx = save_expr (default_conversion
! 		       (build_component_ref (function,
! 					     index_identifier,
! 					     NULL_TREE, 0)));
!       e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
  
!       /* Convert down to the right base, before using the instance.  */
!       instance = convert_pointer_to_real (basetype, instance_ptr);
!       if (instance == error_mark_node && instance_ptr != error_mark_node)
! 	return instance;
  
!       vtbl = convert_pointer_to (ptr_type_node, instance);
!       delta2 = DELTA2_FROM_PTRMEMFUNC (function);
!       vtbl = build
! 	(PLUS_EXPR,
! 	 build_pointer_type (build_pointer_type (vtable_entry_type)),
! 	 vtbl, cp_convert (ptrdiff_type_node, delta2));
!       vtbl = build_indirect_ref (vtbl, NULL_PTR);
!       aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
! 						     idx,
! 						     integer_one_node));
!       if (! flag_vtable_thunks)
! 	{
! 	  aref = save_expr (aref);
! 	  
! 	  delta = build_binary_op
! 	    (PLUS_EXPR,
! 	     build_conditional_expr (e1,
! 				     build_component_ref (aref,
! 							  delta_identifier,
! 							  NULL_TREE, 0),
! 				     integer_zero_node),
! 	     delta);
  	}
+ 
+       if (flag_vtable_thunks)
+ 	e2 = aref;
+       else
+ 	e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
+       TREE_TYPE (e2) = TREE_TYPE (e3);
+       e1 = build_conditional_expr (e1, e2, e3);
+       
+       /* Make sure this doesn't get evaluated first inside one of the
+ 	 branches of the COND_EXPR.  */
+       if (TREE_CODE (instance_ptr) == SAVE_EXPR)
+ 	e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
+ 		    instance_ptr, e1);
  
        *instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
  				instance_ptr, delta);


More information about the Gcc-bugs mailing list