This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: PR 13592


PR c++/13592 is a case where we mishandled a call to an object with an
overloaded "operator ()" that was a member of a template class.

I fixed this problem by eliminating a lot of crufty code that had been
effectively obsoleted by the new parser.

Tested on i686-pc-linux-gnu, applied on the mainline and on the 3.4
branch.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-01-19  Mark Mitchell  <mark@codesourcery.com>

	PR c++/13592
	* call.c (build_field_call): Remove.
	(n_build_method_call): Likewise.
	(build_method_call): Likewise.
	(build_new_method_call): Do not call build_field_call.
	* class.c (n_build_method_call): Remove.
	(print_class_statistics): Do not print it.
	* cp-tree.h (build_method_call): Remove declaration.
	(finish_object_call_expr): Likewise.
	(build_new_1): Do not use build_method_call.
	* parser.c (cp_parser_postfix_expression): Use finish_call_expr
	when the function appearing on the right-hand-side of "." or "->"
	is not actually a function.
	* pt.c (tsubst_copy_and_build): Likewise.
	* semantics.c (finish_object_call_expr): Remove.

2004-01-19  Mark Mitchell  <mark@codesourcery.com>

	PR c++/13592
	* g++.dg/template/call2.C: New test.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.452
diff -c -5 -p -r1.452 call.c
*** cp/call.c	16 Jan 2004 18:39:56 -0000	1.452
--- cp/call.c	19 Jan 2004 18:29:06 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 38,48 ****
  #include "diagnostic.h"
  #include "intl.h"
  #include "target.h"
  #include "convert.h"
  
- static tree build_field_call (tree, tree, tree);
  static struct z_candidate * tourney (struct z_candidate *);
  static int equal_functions (tree, tree);
  static int joust (struct z_candidate *, struct z_candidate *, bool);
  static int compare_ics (tree, tree);
  static tree build_over_call (struct z_candidate *, int);
--- 38,47 ----
*************** build_vfield_ref (tree datum, tree type)
*** 126,171 ****
  
    return build (COMPONENT_REF, TREE_TYPE (TYPE_VFIELD (type)),
  		datum, TYPE_VFIELD (type));
  }
  
- /* Build a call to a member of an object.  I.e., one that overloads
-    operator ()(), or is a pointer-to-function or pointer-to-method.  */
- 
- static tree
- build_field_call (tree instance_ptr, tree decl, tree parms)
- {
-   tree instance;
- 
-   if (decl == error_mark_node || decl == NULL_TREE)
-     return decl;
- 
-   if (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL)
-     {
-       /* If it's a field, try overloading operator (),
- 	 or calling if the field is a pointer-to-function.  */
-       instance = build_indirect_ref (instance_ptr, NULL);
-       instance = build_class_member_access_expr (instance, decl, 
- 						 /*access_path=*/NULL_TREE,
- 						 /*preserve_reference=*/false);
- 
-       if (instance == error_mark_node)
- 	return error_mark_node;
- 
-       if (IS_AGGR_TYPE (TREE_TYPE (instance)))
- 	return build_new_op (CALL_EXPR, LOOKUP_NORMAL,
- 			     instance, parms, NULL_TREE);
-       else if (TREE_CODE (TREE_TYPE (instance)) == FUNCTION_TYPE
- 	       || (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE
- 		   && (TREE_CODE (TREE_TYPE (TREE_TYPE (instance)))
- 		       == FUNCTION_TYPE)))
- 	return build_function_call (instance, parms);
-     }
- 
-   return NULL_TREE;
- }
- 
  /* Returns nonzero iff the destructor name specified in NAME
     (a BIT_NOT_EXPR) matches BASETYPE.  The operand of NAME can take many
     forms...  */
  
  bool
--- 125,134 ----
*************** build_call (tree function, tree parms)
*** 340,445 ****
  
     Note that NAME may refer to an instance variable name.  If
     `operator()()' is defined for the type of that field, then we return
     that result.  */
  
- #ifdef GATHER_STATISTICS
- extern int n_build_method_call;
- #endif
- 
- tree
- build_method_call (tree instance, tree name, tree parms,
-                    tree basetype_path, int flags)
- {
-   tree fn;
-   tree object_type;
-   tree template_args = NULL_TREE;
-   bool has_template_args = false;
- 
- #ifdef GATHER_STATISTICS
-   n_build_method_call++;
- #endif
- 
-   if (error_operand_p (instance)
-       || name == error_mark_node
-       || parms == error_mark_node)
-     return error_mark_node;
- 
-   my_friendly_assert (!processing_template_decl, 20030707);
- 
-   if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE)
-     instance = convert_from_reference (instance);
-   object_type = TREE_TYPE (instance);
- 
-   if (TREE_CODE (name) == BIT_NOT_EXPR)
-     {
-       tree instance_ptr;
- 
-       if (parms)
- 	error ("destructors take no parameters");
- 
-       if (! check_dtor_name (object_type, name))
- 	error
- 	  ("destructor name `~%T' does not match type `%T' of expression",
- 	   TREE_OPERAND (name, 0), object_type);
- 
-       if (! TYPE_HAS_DESTRUCTOR (complete_type (object_type)))
- 	return convert_to_void (instance, /*implicit=*/NULL);
-       instance = default_conversion (instance);
-       instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
-       return build_delete (build_pointer_type (object_type),
- 			   instance_ptr, sfk_complete_destructor,
- 			   LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
-     }
- 
-   if (!CLASS_TYPE_P (object_type))
-     {
-       if ((flags & LOOKUP_COMPLAIN) 
- 	  && TREE_TYPE (instance) != error_mark_node)
- 	error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
- 	       name, instance, object_type);
-       return error_mark_node;
-     }
- 
-   if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-     {
-       template_args = TREE_OPERAND (name, 1);
-       has_template_args = true;
-       name = TREE_OPERAND (name, 0);
-     }
-   if (TREE_CODE (name) == OVERLOAD)
-     name = DECL_NAME (get_first_fn (name));
-   else if (DECL_P (name))
-     name = DECL_NAME (name);
-   if (has_template_args)
-     fn = lookup_fnfields (object_type, name, /*protect=*/2);
-   else
-     fn = lookup_member (object_type, name, /*protect=*/2, /*want_type=*/false);
-   
-   if (fn && TREE_CODE (fn) == TREE_LIST)
-     {
-       error ("request for member `%D' is ambiguous", name);
-       print_candidates (fn);
-       return error_mark_node;
-     }
- 
-   /* If the name could not be found, issue an error.  */
-   if (!fn)
-     return unqualified_name_lookup_error (name);
- 
-   if (BASELINK_P (fn) && has_template_args)
-     BASELINK_FUNCTIONS (fn)
-       = build_nt (TEMPLATE_ID_EXPR,
- 		  BASELINK_FUNCTIONS (fn),
- 		  template_args);
-   if (BASELINK_P (fn) && basetype_path)
-     BASELINK_ACCESS_BINFO (fn) = basetype_path;
- 
-   return build_new_method_call (instance, fn, parms, 
- 				/*conversion_path=*/NULL_TREE, flags);
- }
- 
  /* New overloading code.  */
  
  struct z_candidate GTY(()) {
    /* The FUNCTION_DECL that will be called if this candidate is
       selected by overload resolution.  */
--- 303,312 ----
*************** build_new_method_call (tree instance, tr
*** 5056,5068 ****
    basetype = TYPE_MAIN_VARIANT (TREE_TYPE (instance));
    instance_ptr = build_this (instance);
  
    if (!BASELINK_P (fns))
      {
-       call = build_field_call (instance_ptr, fns, args);
-       if (call)
- 	goto finish;
        error ("call to non-function `%D'", fns);
        return error_mark_node;
      }
  
    if (!conversion_path)
--- 4923,4932 ----
*************** build_new_method_call (tree instance, tr
*** 5219,5229 ****
        /* In an expression of the form `a->f()' where `f' turns out to
  	 be a static member function, `a' is none-the-less evaluated.  */
        if (!is_dummy_object (instance_ptr) && TREE_SIDE_EFFECTS (instance))
  	call = build (COMPOUND_EXPR, TREE_TYPE (call), instance, call);
      }
-  finish:;
    
    if (processing_template_decl && call != error_mark_node)
      return build_min_non_dep
        (CALL_EXPR, call,
         build_min_nt (COMPONENT_REF, orig_instance, orig_fns),
--- 5083,5092 ----
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.595
diff -c -5 -p -r1.595 class.c
*** cp/class.c	13 Jan 2004 00:01:46 -0000	1.595
--- cp/class.c	19 Jan 2004 18:29:07 -0000
*************** int n_vtables = 0;
*** 225,235 ****
  int n_vtable_entries = 0;
  int n_vtable_searches = 0;
  int n_vtable_elems = 0;
  int n_convert_harshness = 0;
  int n_compute_conversion_costs = 0;
- int n_build_method_call = 0;
  int n_inner_fields_searched = 0;
  #endif
  
  /* Convert to or from a base subobject.  EXPR is an expression of type
     `A' or `A*', an expression of type `B' or `B*' is returned.  To
--- 225,234 ----
*************** void
*** 6286,6297 ****
  print_class_statistics (void)
  {
  #ifdef GATHER_STATISTICS
    fprintf (stderr, "convert_harshness = %d\n", n_convert_harshness);
    fprintf (stderr, "compute_conversion_costs = %d\n", n_compute_conversion_costs);
-   fprintf (stderr, "build_method_call = %d (inner = %d)\n",
- 	   n_build_method_call, n_inner_fields_searched);
    if (n_vtables)
      {
        fprintf (stderr, "vtables = %d; vtable searches = %d\n",
  	       n_vtables, n_vtable_searches);
        fprintf (stderr, "vtable entries = %d; vtable elems = %d\n",
--- 6285,6294 ----
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.946
diff -c -5 -p -r1.946 cp-tree.h
*** cp/cp-tree.h	9 Jan 2004 19:55:10 -0000	1.946
--- cp/cp-tree.h	19 Jan 2004 18:29:07 -0000
*************** enum overload_flags { NO_SPECIAL = 0, DT
*** 3297,3307 ****
  /* Some macros for char-based bitfields.  */
  #define B_SET(A,X) ((A)[(X)>>3] |=  (1 << ((X)&7)))
  #define B_CLR(A,X) ((A)[(X)>>3] &= ~(1 << ((X)&7)))
  #define B_TST(A,X) ((A)[(X)>>3] &   (1 << ((X)&7)))
  
! /* These are uses as bits in flags passed to build_method_call
     to control its error reporting behavior.
  
     LOOKUP_PROTECT means flag access violations.
     LOOKUP_COMPLAIN mean complain if no suitable member function
       matching the arguments is found.
--- 3297,3307 ----
  /* Some macros for char-based bitfields.  */
  #define B_SET(A,X) ((A)[(X)>>3] |=  (1 << ((X)&7)))
  #define B_CLR(A,X) ((A)[(X)>>3] &= ~(1 << ((X)&7)))
  #define B_TST(A,X) ((A)[(X)>>3] &   (1 << ((X)&7)))
  
! /* These are uses as bits in flags passed to build_new_method_call
     to control its error reporting behavior.
  
     LOOKUP_PROTECT means flag access violations.
     LOOKUP_COMPLAIN mean complain if no suitable member function
       matching the arguments is found.
*************** extern bool check_dtor_name (tree, tree)
*** 3510,3520 ****
  
  extern tree build_vfield_ref			(tree, tree);
  extern tree build_conditional_expr		(tree, tree, tree);
  extern tree build_addr_func (tree);
  extern tree build_call (tree, tree);
- extern tree build_method_call (tree, tree, tree, tree, int);
  extern bool null_ptr_cst_p (tree);
  extern bool sufficient_parms_p (tree);
  extern tree type_decays_to (tree);
  extern tree build_user_type_conversion (tree, tree, int);
  extern tree build_new_function_call (tree, tree);
--- 3510,3519 ----
*************** extern tree finish_stmt_expr_expr 		(tre
*** 4060,4070 ****
  extern tree finish_stmt_expr                    (tree, bool);
  extern tree perform_koenig_lookup               (tree, tree);
  extern tree finish_call_expr                    (tree, tree, bool, bool);
  extern tree finish_increment_expr               (tree, enum tree_code);
  extern tree finish_this_expr                    (void);
- extern tree finish_object_call_expr             (tree, tree, tree);
  extern tree finish_pseudo_destructor_expr       (tree, tree, tree);
  extern tree finish_unary_op_expr                (enum tree_code, tree);
  extern tree finish_compound_literal             (tree, tree);
  extern tree finish_fname                        (tree);
  extern int begin_function_definition            (tree, tree, tree);
--- 4059,4068 ----
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.356
diff -c -5 -p -r1.356 init.c
*** cp/init.c	16 Jan 2004 19:28:09 -0000	1.356
--- cp/init.c	19 Jan 2004 18:29:08 -0000
*************** expand_default_init (tree binfo, tree tr
*** 1249,1260 ****
     don't necessarily know by looking at EXP where its virtual
     baseclass fields should really be pointing.  But we do know
     from TRUE_EXP.  In constructors, we don't know anything about
     the value being initialized.
  
!    FLAGS is just passes to `build_method_call'.  See that function for
!    its description.  */
  
  static void
  expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags)
  {
    tree type = TREE_TYPE (exp);
--- 1249,1260 ----
     don't necessarily know by looking at EXP where its virtual
     baseclass fields should really be pointing.  But we do know
     from TRUE_EXP.  In constructors, we don't know anything about
     the value being initialized.
  
!    FLAGS is just passed to `build_new_method_call'.  See that function
!    for its description.  */
  
  static void
  expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags)
  {
    tree type = TREE_TYPE (exp);
*************** build_new_1 (tree exp)
*** 2029,2038 ****
--- 2029,2039 ----
  				build_tree_list (NULL_TREE, class_size))));
      }
    else
      {
        tree fnname;
+       tree fns;
  
        fnname = ansi_opname (code);
  
        if (!globally_qualified_p 
  	  && CLASS_TYPE_P (true_type)
*************** build_new_1 (tree exp)
*** 2047,2061 ****
  	      cookie_size = get_cookie_size (true_type);
  	      size = size_binop (PLUS_EXPR, size, cookie_size);
  	    }
  	  /* Create the argument list.  */
  	  args = tree_cons (NULL_TREE, size, placement);
! 	  /* Call the function.  */
! 	  alloc_call = build_method_call (build_dummy_object (true_type),
! 					  fnname, args, 
! 					  TYPE_BINFO (true_type),
! 					  LOOKUP_NORMAL);
  	}
        else
  	{
  	  /* Use a global operator new.  */
  	  /* See if a cookie might be required.  */
--- 2048,2069 ----
  	      cookie_size = get_cookie_size (true_type);
  	      size = size_binop (PLUS_EXPR, size, cookie_size);
  	    }
  	  /* Create the argument list.  */
  	  args = tree_cons (NULL_TREE, size, placement);
! 	  /* Do name-lookup to find the appropriate operator.  */
! 	  fns = lookup_fnfields (true_type, fnname, /*protect=*/2);
! 	  if (TREE_CODE (fns) == TREE_LIST)
! 	    {
! 	      error ("request for member `%D' is ambiguous", fnname);
! 	      print_candidates (fns);
! 	      return error_mark_node;
! 	    }
! 	  alloc_call = build_new_method_call (build_dummy_object (true_type),
! 					      fns, args,
! 					      /*conversion_path=*/NULL_TREE,
! 					      LOOKUP_NORMAL);
  	}
        else
  	{
  	  /* Use a global operator new.  */
  	  /* See if a cookie might be required.  */
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.157
diff -c -5 -p -r1.157 parser.c
*** cp/parser.c	16 Jan 2004 12:29:40 -0000	1.157
--- cp/parser.c	19 Jan 2004 18:29:08 -0000
*************** cp_parser_postfix_expression (cp_parser 
*** 3759,3774 ****
  		  {
  		    postfix_expression
  		      = build_min_nt (CALL_EXPR, postfix_expression, args);
  		    break;
  		  }
! 		  
! 		postfix_expression
! 		  = (build_new_method_call 
! 		     (instance, fn, args, NULL_TREE, 
! 		      (idk == CP_ID_KIND_QUALIFIED 
! 		       ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
  	      }
  	    else if (TREE_CODE (postfix_expression) == OFFSET_REF
  		     || TREE_CODE (postfix_expression) == MEMBER_REF
  		     || TREE_CODE (postfix_expression) == DOTSTAR_EXPR)
  	      postfix_expression = (build_offset_ref_call_from_tree
--- 3759,3780 ----
  		  {
  		    postfix_expression
  		      = build_min_nt (CALL_EXPR, postfix_expression, args);
  		    break;
  		  }
! 
! 		if (BASELINK_P (fn))
! 		  postfix_expression
! 		    = (build_new_method_call 
! 		       (instance, fn, args, NULL_TREE, 
! 			(idk == CP_ID_KIND_QUALIFIED 
! 			 ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
! 		else
! 		  postfix_expression
! 		    = finish_call_expr (postfix_expression, args,
! 					/*disallow_virtual=*/false,
! 					/*koenig_p=*/false);
  	      }
  	    else if (TREE_CODE (postfix_expression) == OFFSET_REF
  		     || TREE_CODE (postfix_expression) == MEMBER_REF
  		     || TREE_CODE (postfix_expression) == DOTSTAR_EXPR)
  	      postfix_expression = (build_offset_ref_call_from_tree
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.817
diff -c -5 -p -r1.817 pt.c
*** cp/pt.c	19 Jan 2004 00:47:55 -0000	1.817
--- cp/pt.c	19 Jan 2004 18:29:09 -0000
*************** tsubst_copy_and_build (tree t, 
*** 8277,8291 ****
  	function = convert_from_reference (function);
  
  	if (TREE_CODE (function) == OFFSET_REF)
  	  return build_offset_ref_call_from_tree (function, call_args);
  	if (TREE_CODE (function) == COMPONENT_REF)
! 	  return (build_new_method_call 
! 		  (TREE_OPERAND (function, 0),
! 		   TREE_OPERAND (function, 1),
! 		   call_args, NULL_TREE, 
! 		   qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL));
  	return finish_call_expr (function, call_args, 
  				 /*disallow_virtual=*/qualified_p,
  				 koenig_p);
        }
  
--- 8277,8298 ----
  	function = convert_from_reference (function);
  
  	if (TREE_CODE (function) == OFFSET_REF)
  	  return build_offset_ref_call_from_tree (function, call_args);
  	if (TREE_CODE (function) == COMPONENT_REF)
! 	  {
! 	    if (!BASELINK_P (TREE_OPERAND (function, 1)))
! 	      return finish_call_expr (function, call_args,
! 				       /*disallow_virtual=*/false,
! 				       /*koenig_p=*/false);
! 	    else
! 	      return (build_new_method_call 
! 		      (TREE_OPERAND (function, 0),
! 		       TREE_OPERAND (function, 1),
! 		       call_args, NULL_TREE, 
! 		       qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL));
! 	  }
  	return finish_call_expr (function, call_args, 
  				 /*disallow_virtual=*/qualified_p,
  				 koenig_p);
        }
  
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.381
diff -c -5 -p -r1.381 semantics.c
*** cp/semantics.c	5 Jan 2004 05:47:16 -0000	1.381
--- cp/semantics.c	19 Jan 2004 18:29:11 -0000
*************** finish_this_expr (void)
*** 1772,1817 ****
      }
  
    return result;
  }
  
- /* Finish a member function call using OBJECT and ARGS as arguments to
-    FN.  Returns an expression for the call.  */
- 
- tree 
- finish_object_call_expr (tree fn, tree object, tree args)
- {
-   if (DECL_DECLARES_TYPE_P (fn))
-     {
-       if (processing_template_decl)
- 	/* This can happen on code like:
- 
- 	   class X;
- 	   template <class T> void f(T t) {
- 	     t.X();
- 	   }  
- 
- 	   We just grab the underlying IDENTIFIER.  */
- 	fn = DECL_NAME (fn);
-       else
- 	{
- 	  error ("calling type `%T' like a method", fn);
- 	  return error_mark_node;
- 	}
-     }
-   
-   if (processing_template_decl)
-     return build_nt (CALL_EXPR,
- 		     build_nt (COMPONENT_REF, object, fn),
- 		     args);
- 
-   if (name_p (fn))
-     return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
-   else
-     return build_new_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
- }
- 
  /* Finish a pseudo-destructor expression.  If SCOPE is NULL, the
     expression was of the form `OBJECT.~DESTRUCTOR' where DESTRUCTOR is
     the TYPE for the type given.  If SCOPE is non-NULL, the expression
     was of the form `OBJECT.SCOPE::~DESTRUCTOR'.  */
  
--- 1772,1781 ----
Index: testsuite/g++.dg/template/call2.C
===================================================================
RCS file: testsuite/g++.dg/template/call2.C
diff -N testsuite/g++.dg/template/call2.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/call2.C	19 Jan 2004 18:29:13 -0000
***************
*** 0 ****
--- 1,14 ----
+ // PR c++/13592
+ 
+ struct S { 
+   void operator()(int); 
+ }; 
+  
+ struct A { 
+   template <typename> void foo(); 
+   S s; 
+ }; 
+  
+ template <typename> void A::foo() { 
+   s(0); 
+ } 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]