re PR c++/7129 (ICE with min/max assignment operators (<?= and >?=))

PR c++/7129
	* call.c (z_candidate): Add args.
	(convert_class_to_reference): Set it.
	(implicit_conversion): Tidy.
	(add_candidate): Add args parameter.
	(add_function_candidate): Adjust call to add_candidate.
	(add_conv_candidate): Likewise.
	(build_builtin_candidate): Likewise.
	(build_user_type_conversion_1): Eliminate wasteful tree_cons
	usage.
	(build_new_function_call): Likewise.
	(build_object_call): Likewise.
	(add_candidates): New function.
	(build_new_op): Use it.
	(covert_like_real): Adjust call to build_over_call.
	(build_over_call): Remove args parameter.
	* operators.def: Add <?= and >?=.

	PR c++/7129
	* testsuite/g++.dg/ext/max.C: New test.

From-SVN: r62370
This commit is contained in:
Mark Mitchell 2003-02-04 07:23:14 +00:00 committed by Mark Mitchell
parent b3a8389d18
commit b80f8ef302
5 changed files with 195 additions and 150 deletions

View File

@ -1,3 +1,23 @@
2003-02-03 Mark Mitchell <mark@codesourcery.com>
PR c++/7129
* call.c (z_candidate): Add args.
(convert_class_to_reference): Set it.
(implicit_conversion): Tidy.
(add_candidate): Add args parameter.
(add_function_candidate): Adjust call to add_candidate.
(add_conv_candidate): Likewise.
(build_builtin_candidate): Likewise.
(build_user_type_conversion_1): Eliminate wasteful tree_cons
usage.
(build_new_function_call): Likewise.
(build_object_call): Likewise.
(add_candidates): New function.
(build_new_op): Use it.
(covert_like_real): Adjust call to build_over_call.
(build_over_call): Remove args parameter.
* operators.def: Add <?= and >?=.
2003-02-01 Richard Sandiford <rsandifo@redhat.com>
* typeck.c (build_indirect_ref): Don't check flag_volatile.

View File

@ -44,7 +44,7 @@ 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 *, tree, int);
static tree build_over_call (struct z_candidate *, int);
static tree build_java_interface_fn_ref (tree, tree);
#define convert_like(CONV, EXPR) \
convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0)
@ -92,7 +92,7 @@ static bool is_subseq (tree, tree);
static tree maybe_handle_ref_bind (tree *);
static void maybe_handle_implicit_object (tree *);
static struct z_candidate *add_candidate
(struct z_candidate *, tree, tree, tree, tree, int);
(struct z_candidate *, tree, tree, tree, tree, tree, int);
static tree source_type (tree);
static void add_warning (struct z_candidate *, struct z_candidate *);
static bool reference_related_p (tree, tree);
@ -104,6 +104,8 @@ static tree conditional_conversion (tree, tree);
static char *name_as_c_string (tree, tree, bool *);
static tree call_builtin_trap (void);
static tree prep_operand (tree);
static struct z_candidate *add_candidates (tree, tree, tree, tree,
int, struct z_candidate *);
tree
build_vfield_ref (tree datum, tree type)
@ -556,6 +558,8 @@ struct z_candidate GTY(()) {
/* The FUNCTION_DECL that will be called if this candidate is
selected by overload resolution. */
tree fn;
/* The arguments to use when calling this function. */
tree args;
tree convs;
tree second_conv;
int viable;
@ -1034,6 +1038,12 @@ convert_class_to_reference (tree t, tree s, tree expr)
if (!cand)
return NULL_TREE;
/* Now that we know that this is the function we're going to use fix
the dummy first argument. */
cand->args = tree_cons (NULL_TREE,
build_this (expr),
TREE_CHAIN (cand->args));
conv = build1 (IDENTITY_CONV, s, expr);
conv = build_conv (USER_CONV, TREE_TYPE (TREE_TYPE (cand->fn)),
conv);
@ -1269,11 +1279,12 @@ implicit_conversion (tree to, tree from, tree expr, int flags)
conv = standard_conversion (to, from, expr);
if (conv)
;
else if (expr != NULL_TREE
&& (IS_AGGR_TYPE (from)
|| IS_AGGR_TYPE (to))
&& (flags & LOOKUP_NO_CONVERSION) == 0)
return conv;
if (expr != NULL_TREE
&& (IS_AGGR_TYPE (from)
|| IS_AGGR_TYPE (to))
&& (flags & LOOKUP_NO_CONVERSION) == 0)
{
cand = build_user_type_conversion_1
(to, expr, LOOKUP_ONLYCONVERTING);
@ -1283,9 +1294,10 @@ implicit_conversion (tree to, tree from, tree expr, int flags)
/* We used to try to bind a reference to a temporary here, but that
is now handled by the recursive call to this function at the end
of reference_binding. */
return conv;
}
return conv;
return NULL_TREE;
}
/* Add a new entry to the list of candidates. Used by the add_*_candidate
@ -1293,13 +1305,14 @@ implicit_conversion (tree to, tree from, tree expr, int flags)
static struct z_candidate *
add_candidate (struct z_candidate *candidates,
tree fn, tree convs, tree access_path, tree
conversion_path, int viable)
tree fn, tree args, tree convs, tree access_path,
tree conversion_path, int viable)
{
struct z_candidate *cand
= (struct z_candidate *) ggc_alloc_cleared (sizeof (struct z_candidate));
cand->fn = fn;
cand->args = args;
cand->convs = convs;
cand->access_path = access_path;
cand->conversion_path = conversion_path;
@ -1326,6 +1339,7 @@ add_function_candidate (struct z_candidate *candidates,
int i, len;
tree convs;
tree parmnode, argnode;
tree orig_arglist;
int viable = 1;
/* The `this', `in_chrg' and VTT arguments to constructors are not
@ -1333,8 +1347,11 @@ add_function_candidate (struct z_candidate *candidates,
if (DECL_CONSTRUCTOR_P (fn))
{
parmlist = skip_artificial_parms_for (fn, parmlist);
orig_arglist = arglist;
arglist = skip_artificial_parms_for (fn, arglist);
}
else
orig_arglist = arglist;
len = list_length (arglist);
convs = make_tree_vec (len);
@ -1432,7 +1449,7 @@ add_function_candidate (struct z_candidate *candidates,
}
out:
return add_candidate (candidates, fn, convs, access_path,
return add_candidate (candidates, fn, orig_arglist, convs, access_path,
conversion_path, viable);
}
@ -1509,7 +1526,7 @@ add_conv_candidate (struct z_candidate *candidates, tree fn, tree obj,
if (!sufficient_parms_p (parmnode))
viable = 0;
return add_candidate (candidates, totype, convs, access_path,
return add_candidate (candidates, totype, arglist, convs, access_path,
conversion_path, viable);
}
@ -1556,7 +1573,7 @@ build_builtin_candidate (struct z_candidate *candidates, tree fnname,
viable = 0;
}
return add_candidate (candidates, fnname, convs,
return add_candidate (candidates, fnname, /*args=*/NULL_TREE, convs,
/*access_path=*/NULL_TREE,
/*conversion_path=*/NULL_TREE,
viable);
@ -2396,7 +2413,6 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
tree fromtype = TREE_TYPE (expr);
tree ctors = NULL_TREE, convs = NULL_TREE, *p;
tree args = NULL_TREE;
tree templates = NULL_TREE;
/* We represent conversion within a hierarchy using RVALUE_CONV and
BASE_CONV, as specified by [over.best.ics]; these become plain
@ -2438,16 +2454,13 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
continue;
if (TREE_CODE (ctor) == TEMPLATE_DECL)
{
templates = tree_cons (NULL_TREE, ctor, templates);
candidates =
add_template_candidate (candidates, ctor, totype,
NULL_TREE, args, NULL_TREE,
TYPE_BINFO (totype),
TYPE_BINFO (totype),
flags,
DEDUCE_CALL);
}
candidates =
add_template_candidate (candidates, ctor, totype,
NULL_TREE, args, NULL_TREE,
TYPE_BINFO (totype),
TYPE_BINFO (totype),
flags,
DEDUCE_CALL);
else
candidates = add_function_candidate (candidates, ctor, totype,
args, TYPE_BINFO (totype),
@ -2487,15 +2500,12 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
So we pass fromtype as CTYPE to add_*_candidate. */
if (TREE_CODE (fn) == TEMPLATE_DECL)
{
templates = tree_cons (NULL_TREE, fn, templates);
candidates =
add_template_candidate (candidates, fn, fromtype, NULL_TREE,
args, totype, TYPE_BINFO (fromtype),
conversion_path,
flags,
DEDUCE_CONV);
}
candidates =
add_template_candidate (candidates, fn, fromtype, NULL_TREE,
args, totype, TYPE_BINFO (fromtype),
conversion_path,
flags,
DEDUCE_CONV);
else
candidates = add_function_candidate (candidates, fn, fromtype,
args,
@ -2695,7 +2705,6 @@ build_new_function_call (tree fn, tree args)
|| TREE_CODE (fn) == TEMPLATE_DECL)
{
tree t1;
tree templates = NULL_TREE;
args = resolve_args (args);
@ -2709,14 +2718,11 @@ build_new_function_call (tree fn, tree args)
my_friendly_assert (!DECL_FUNCTION_MEMBER_P (t), 20020913);
if (TREE_CODE (t) == TEMPLATE_DECL)
{
templates = tree_cons (NULL_TREE, t, templates);
candidates = add_template_candidate
(candidates, t, NULL_TREE, explicit_targs, args,
NULL_TREE, /*access_path=*/NULL_TREE,
/*conversion_path=*/NULL_TREE,
LOOKUP_NORMAL, DEDUCE_CALL);
}
candidates = add_template_candidate
(candidates, t, NULL_TREE, explicit_targs, args,
NULL_TREE, /*access_path=*/NULL_TREE,
/*conversion_path=*/NULL_TREE,
LOOKUP_NORMAL, DEDUCE_CALL);
else if (! template_only)
candidates = add_function_candidate
(candidates, t, NULL_TREE, args,
@ -2745,7 +2751,7 @@ build_new_function_call (tree fn, tree args)
return error_mark_node;
}
return build_over_call (cand, args, LOOKUP_NORMAL);
return build_over_call (cand, LOOKUP_NORMAL);
}
/* This is not really overloaded. */
@ -2787,14 +2793,12 @@ build_object_call (tree obj, tree args)
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) == TEMPLATE_DECL)
{
candidates
= add_template_candidate (candidates, fn, base, NULL_TREE,
mem_args, NULL_TREE,
TYPE_BINFO (type),
TYPE_BINFO (type),
LOOKUP_NORMAL, DEDUCE_CALL);
}
candidates
= add_template_candidate (candidates, fn, base, NULL_TREE,
mem_args, NULL_TREE,
TYPE_BINFO (type),
TYPE_BINFO (type),
LOOKUP_NORMAL, DEDUCE_CALL);
else
candidates = add_function_candidate
(candidates, fn, base, mem_args, TYPE_BINFO (type),
@ -2855,7 +2859,7 @@ build_object_call (tree obj, tree args)
DECL_NAME here. */
if (TREE_CODE (cand->fn) == FUNCTION_DECL
&& DECL_OVERLOADED_OPERATOR_P (cand->fn) == CALL_EXPR)
return build_over_call (cand, mem_args, LOOKUP_NORMAL);
return build_over_call (cand, LOOKUP_NORMAL);
obj = convert_like_with_context
(TREE_VEC_ELT (cand->convs, 0), obj, cand->fn, -1);
@ -3317,13 +3321,78 @@ prep_operand (tree operand)
return operand;
}
/* Add each of the viable functions in FNS (a FUNCTION_DECL or
OVERLOAD) to the CANDIDATES, returning an updated list of
CANDIDATES. The ARGS are the arguments provided to the call,
without any implicit object parameter. CONVERSION_PATH,
ACCESS_PATH, and FLAGS are as for add_function_candidate. */
static struct z_candidate *
add_candidates (tree fns, tree args,
tree conversion_path, tree access_path,
int flags,
struct z_candidate *candidates)
{
tree ctype;
tree non_static_args;
ctype = conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE;
/* Delay creating the implicit this parameter until it is needed. */
non_static_args = NULL_TREE;
while (fns)
{
tree fn;
tree fn_args;
fn = OVL_CURRENT (fns);
/* Figure out which set of arguments to use. */
if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
{
/* If this function is a non-static member, prepend the implicit
object parameter. */
if (!non_static_args)
non_static_args = tree_cons (NULL_TREE,
build_this (TREE_VALUE (args)),
TREE_CHAIN (args));
fn_args = non_static_args;
}
else
/* Otherwise, just use the list of arguments provided. */
fn_args = args;
if (TREE_CODE (fn) == TEMPLATE_DECL)
candidates = add_template_candidate (candidates,
fn,
ctype,
NULL_TREE,
fn_args,
NULL_TREE,
access_path,
conversion_path,
flags,
DEDUCE_CALL);
else
candidates = add_function_candidate (candidates,
fn,
ctype,
fn_args,
access_path,
conversion_path,
flags);
fns = OVL_NEXT (fns);
}
return candidates;
}
tree
build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
{
struct z_candidate *candidates = 0, *cand;
tree fns, mem_arglist = NULL_TREE, arglist, fnname;
tree arglist, fnname;
tree args[3];
enum tree_code code2 = NOP_EXPR;
tree templates = NULL_TREE;
tree conv;
bool viable_candidates;
@ -3385,98 +3454,45 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
arglist = tree_cons (NULL_TREE, arg2, arglist);
arglist = tree_cons (NULL_TREE, arg1, arglist);
fns = lookup_function_nonclass (fnname, arglist);
if (fns && TREE_CODE (fns) == TREE_LIST)
fns = TREE_VALUE (fns);
for (; fns; fns = OVL_NEXT (fns))
/* Add namespace-scope operators to the list of functions to
consider. */
candidates = add_candidates (lookup_function_nonclass (fnname, arglist),
arglist, NULL_TREE, NULL_TREE,
flags, candidates);
/* Add class-member operators to the candidate set. */
if (CLASS_TYPE_P (TREE_TYPE (arg1)))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) == TEMPLATE_DECL)
{
templates = tree_cons (NULL_TREE, fn, templates);
candidates
= add_template_candidate (candidates, fn, NULL_TREE, NULL_TREE,
arglist, TREE_TYPE (fnname),
/*access_path=*/NULL_TREE,
/*conversion_path=*/NULL_TREE,
flags, DEDUCE_CALL);
}
else
candidates = add_function_candidate (candidates, fn, NULL_TREE,
arglist,
/*access_path=*/NULL_TREE,
/*conversion_path=*/NULL_TREE,
flags);
}
tree fns;
if (IS_AGGR_TYPE (TREE_TYPE (arg1)))
{
fns = lookup_fnfields (TYPE_BINFO (TREE_TYPE (arg1)), fnname, 1);
if (fns == error_mark_node)
return fns;
if (fns)
candidates = add_candidates (BASELINK_FUNCTIONS (fns), arglist,
BASELINK_BINFO (fns),
TYPE_BINFO (TREE_TYPE (arg1)),
flags, candidates);
}
/* Rearrange the arguments for ?: so that add_builtin_candidate only has
to know about two args; a builtin candidate will always have a first
parameter of type bool. We'll handle that in
build_builtin_candidate. */
if (code == COND_EXPR)
{
args[0] = arg2;
args[1] = arg3;
args[2] = arg1;
}
else
fns = NULL_TREE;
if (fns)
{
tree conversion_path = BASELINK_BINFO (fns);
mem_arglist = tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
for (fns = BASELINK_FUNCTIONS (fns); fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
tree this_arglist;
tree access_path = TYPE_BINFO (TREE_TYPE (arg1));
if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
this_arglist = mem_arglist;
else
this_arglist = arglist;
if (TREE_CODE (fn) == TEMPLATE_DECL)
{
/* A member template. */
templates = tree_cons (NULL_TREE, fn, templates);
candidates
= add_template_candidate (candidates, fn,
BINFO_TYPE (conversion_path),
NULL_TREE,
this_arglist, TREE_TYPE (fnname),
access_path, conversion_path,
flags, DEDUCE_CALL);
}
else
candidates = add_function_candidate
(candidates, fn, BINFO_TYPE (conversion_path), this_arglist,
access_path, conversion_path, flags);
}
args[0] = arg1;
args[1] = arg2;
args[2] = NULL_TREE;
}
{
tree args[3];
/* Rearrange the arguments for ?: so that add_builtin_candidate only has
to know about two args; a builtin candidate will always have a first
parameter of type bool. We'll handle that in
build_builtin_candidate. */
if (code == COND_EXPR)
{
args[0] = arg2;
args[1] = arg3;
args[2] = arg1;
}
else
{
args[0] = arg1;
args[1] = arg2;
args[2] = NULL_TREE;
}
candidates = add_builtin_candidates
(candidates, code, code2, fnname, args, flags);
}
candidates = add_builtin_candidates
(candidates, code, code2, fnname, args, flags);
switch (code)
{
@ -3559,11 +3575,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
: candidates->fn);
}
return build_over_call
(cand,
TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
? mem_arglist : arglist,
LOOKUP_NORMAL);
return build_over_call (cand, LOOKUP_NORMAL);
}
/* Check for comparison of different enum types. */
@ -3907,7 +3919,7 @@ convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner)
}
else
args = build_this (expr);
expr = build_over_call (cand, args, LOOKUP_NORMAL);
expr = build_over_call (cand, LOOKUP_NORMAL);
/* If this is a constructor or a function returning an aggr type,
we need to build up a TARGET_EXPR. */
@ -4238,9 +4250,10 @@ convert_for_arg_passing (tree type, tree val)
bitmask of various LOOKUP_* flags which apply to the call itself. */
static tree
build_over_call (struct z_candidate *cand, tree args, int flags)
build_over_call (struct z_candidate *cand, int flags)
{
tree fn = cand->fn;
tree args = cand->args;
tree convs = cand->convs;
tree converted_args = NULL_TREE;
tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
@ -4702,7 +4715,6 @@ build_new_method_call (tree instance, tree fns, tree args,
tree mem_args = NULL_TREE, instance_ptr;
tree name;
tree user_args;
tree templates = NULL_TREE;
tree call;
tree fn;
tree class_type;
@ -4807,7 +4819,6 @@ build_new_method_call (tree instance, tree fns, tree args,
if (TREE_CODE (t) == TEMPLATE_DECL)
{
/* A member template. */
templates = tree_cons (NULL_TREE, t, templates);
candidates =
add_template_candidate (candidates, t,
class_type,
@ -4888,10 +4899,10 @@ build_new_method_call (tree instance, tree fns, tree args,
flags |= LOOKUP_NONVIRTUAL;
if (TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE)
call = build_over_call (cand, mem_args, flags);
call = build_over_call (cand, flags);
else
{
call = build_over_call (cand, args, flags);
call = build_over_call (cand, flags);
/* 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))

View File

@ -5,7 +5,7 @@
non-overloadable operators (like the `?:' ternary operator).
Written by Mark Mitchell <mark@codesourcery.com>
Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
@ -40,7 +40,7 @@ Boston, MA 02111-1307, USA. */
assignment operators, the same tree-codes are reused; i.e.,
`operator +' will also have PLUS_EXPR as its CODE.
NEW_MANGLING
MANGLING
The mangling prefix for the operator, as a C string, and as
mangled under the new ABI. For `operator +', for example, this
@ -127,7 +127,7 @@ DEF_SIMPLE_OPERATOR ("->", COMPONENT_REF, "pt", 2)
DEF_SIMPLE_OPERATOR ("[]", ARRAY_REF, "ix", 2)
DEF_SIMPLE_OPERATOR ("++", POSTINCREMENT_EXPR, "pp", 2)
DEF_SIMPLE_OPERATOR ("--", POSTDECREMENT_EXPR, "mm", 2)
/* These are extensions. */
/* These operators are GNU extensions. */
DEF_SIMPLE_OPERATOR ("<?", MIN_EXPR, "v23min", 2)
DEF_SIMPLE_OPERATOR (">?", MAX_EXPR, "v23max", 2)
/* This one is needed for mangling. */
@ -145,6 +145,9 @@ DEF_ASSN_OPERATOR ("|=", BIT_IOR_EXPR, "oR", 2)
DEF_ASSN_OPERATOR ("^=", BIT_XOR_EXPR, "eO", 2)
DEF_ASSN_OPERATOR ("<<=", LSHIFT_EXPR, "lS", 2)
DEF_ASSN_OPERATOR (">>=", RSHIFT_EXPR, "rS", 2)
/* These operators are GNU extensions. */
DEF_ASSN_OPERATOR ("<?=", MIN_EXPR, "v23miN", 2);
DEF_ASSN_OPERATOR (">?=", MAX_EXPR, "v23maX", 2);
/* Ternary operators. */
DEF_SIMPLE_OPERATOR ("?:", COND_EXPR, "qu", 3)

View File

@ -1,3 +1,8 @@
2003-02-03 Mark Mitchell <mark@codesourcery.com>
PR c++/7129
* testsuite/g++.dg/ext/max.C: New test.
Mon Feb 3 16:05:11 CET 2003 Jan Hubicka <jh@suse.cz>
* gcc.c-torture/execute/20030203-1.c: New test.

View File

@ -0,0 +1,6 @@
struct s_t {
};
void foo(void) {
s_t s; int i;
s<?=i; // { dg-error "" }
}