This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PR 13592
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 19 Jan 2004 12:39:50 -0800
- Subject: C++ PATCH: PR 13592
- Reply-to: mark at codesourcery dot com
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);
+ }