/* Functions related to invoking methods and overloaded functions.
- Copyright (C) 1987, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com) and
hacked by Brendan Kehoe (brendan@cygnus.com).
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* High-level class interface. */
#include <stdio.h>
#include "cp-tree.h"
#include "class.h"
+#include "output.h"
#include "flags.h"
#include "obstack.h"
extern void sorry ();
extern int inhibit_warnings;
-extern int flag_assume_nonnull_objects;
extern tree ctor_label, dtor_label;
-/* From typeck.c: */
-extern tree unary_complex_lvalue ();
-
/* Compute the ease with which a conversion can be performed
between an expected and the given type. */
-static struct harshness_code convert_harshness ();
+static struct harshness_code convert_harshness PROTO((register tree, register tree, tree));
#define EVIL_RETURN(ARG) ((ARG).code = EVIL_CODE, (ARG))
+#define STD_RETURN(ARG) ((ARG).code = STD_CODE, (ARG))
#define QUAL_RETURN(ARG) ((ARG).code = QUAL_CODE, (ARG))
#define TRIVIAL_RETURN(ARG) ((ARG).code = TRIVIAL_CODE, (ARG))
#define ZERO_RETURN(ARG) ((ARG).code = 0, (ARG))
struct harshness_code h;
register enum tree_code codel;
register enum tree_code coder;
+ int lvalue;
h.code = 0;
h.distance = 0;
n_convert_harshness++;
#endif
- if (TYPE_PTRMEMFUNC_P (type))
- type = TYPE_PTRMEMFUNC_FN_TYPE (type);
- if (TYPE_PTRMEMFUNC_P (parmtype))
- parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype);
-
if (TREE_CODE (parmtype) == REFERENCE_TYPE)
{
if (parm)
parm = convert_from_reference (parm);
parmtype = TREE_TYPE (parmtype);
+ lvalue = 1;
}
+ else if (parm)
+ lvalue = lvalue_p (parm);
+ else
+ lvalue = 0;
+
+ if (TYPE_PTRMEMFUNC_P (type))
+ type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+ if (TYPE_PTRMEMFUNC_P (parmtype))
+ parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype);
codel = TREE_CODE (type);
coder = TREE_CODE (parmtype);
if (coder == ERROR_MARK)
return EVIL_RETURN (h);
+ if (codel == REFERENCE_TYPE)
+ {
+ tree ttl, ttr;
+ int constp = parm ? TREE_READONLY (parm) : TYPE_READONLY (parmtype);
+ int volatilep = (parm ? TREE_THIS_VOLATILE (parm)
+ : TYPE_VOLATILE (parmtype));
+ register tree intype = TYPE_MAIN_VARIANT (parmtype);
+ register enum tree_code form = TREE_CODE (intype);
+ int penalty = 0;
+
+ ttl = TREE_TYPE (type);
+
+ /* Only allow const reference binding if we were given a parm to deal
+ with, since it isn't really a conversion. This is a hack to
+ prevent build_type_conversion from finding this conversion, but
+ still allow overloading to find it. */
+ if (! lvalue && ! (parm && TYPE_READONLY (ttl)))
+ return EVIL_RETURN (h);
+
+ if ((TYPE_READONLY (ttl) < constp)
+ || (TYPE_VOLATILE (ttl) < volatilep))
+ return EVIL_RETURN (h);
+
+ /* When passing a non-const argument into a const reference, dig it a
+ little, so a non-const reference is preferred over this one. */
+ penalty = ((TYPE_READONLY (ttl) > constp)
+ + (TYPE_VOLATILE (ttl) > volatilep));
+
+ ttl = TYPE_MAIN_VARIANT (ttl);
+
+ if (form == OFFSET_TYPE)
+ {
+ intype = TREE_TYPE (intype);
+ form = TREE_CODE (intype);
+ }
+
+ ttr = intype;
+
+ if (TREE_CODE (ttl) == ARRAY_TYPE && TREE_CODE (ttr) == ARRAY_TYPE)
+ {
+ if (comptypes (ttl, ttr, 1))
+ return ZERO_RETURN (h);
+ return EVIL_RETURN (h);
+ }
+
+ h = convert_harshness (ttl, ttr, NULL_TREE);
+ if (penalty && h.code == 0)
+ {
+ h.code = QUAL_CODE;
+ h.int_penalty = penalty;
+ }
+ return h;
+ }
+
if (codel == POINTER_TYPE && fntype_p (parmtype))
{
tree p1, p2;
if (coder != TREE_CODE (type))
return EVIL_RETURN (h);
+ if (type != parmtype && coder == METHOD_TYPE)
+ {
+ tree ttl = TYPE_METHOD_BASETYPE (type);
+ tree ttr = TYPE_METHOD_BASETYPE (parmtype);
+
+ int b_or_d = get_base_distance (ttr, ttl, 0, (tree*)0);
+ if (b_or_d < 0)
+ {
+ b_or_d = get_base_distance (ttl, ttr, 0, (tree*)0);
+ if (b_or_d < 0)
+ return EVIL_RETURN (h);
+ h.distance = -b_or_d;
+ }
+ else
+ h.distance = b_or_d;
+ h.code = STD_CODE;
+
+ type = build_function_type
+ (TREE_TYPE (type), TREE_CHAIN (TYPE_ARG_TYPES (type)));
+ parmtype = build_function_type
+ (TREE_TYPE (parmtype), TREE_CHAIN (TYPE_ARG_TYPES (parmtype)));
+ }
+
/* We allow the default conversion between function type
and pointer-to-function type for free. */
- if (type == parmtype)
- return ZERO_RETURN (h);
+ if (comptypes (type, parmtype, 1))
+ return h;
+
+ if (pedantic)
+ return EVIL_RETURN (h);
/* Compare return types. */
p1 = TREE_TYPE (type);
if (! BINFO_OFFSET_ZEROP (binfo))
{
+#if 0
static int explained = 0;
if (h2.distance < 0)
- message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p2, p1);
+ message_2_types (sorry, "cannot cast `%s' to `%s' at function call site", p2, p1);
else
- message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p1, p2);
+ message_2_types (sorry, "cannot cast `%s' to `%s' at function call site", p1, p2);
if (! explained++)
sorry ("(because pointer values change during conversion)");
+#endif
return EVIL_RETURN (h);
}
}
}
else if (codel == POINTER_TYPE && coder == OFFSET_TYPE)
{
+ tree ttl, ttr;
+
/* Get to the OFFSET_TYPE that this might be. */
type = TREE_TYPE (type);
if (coder != TREE_CODE (type))
return EVIL_RETURN (h);
- if (TYPE_OFFSET_BASETYPE (type) == TYPE_OFFSET_BASETYPE (parmtype))
+ ttl = TYPE_OFFSET_BASETYPE (type);
+ ttr = TYPE_OFFSET_BASETYPE (parmtype);
+
+ if (ttl == ttr)
h.code = 0;
- else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (type),
- TYPE_OFFSET_BASETYPE (parmtype)))
- {
- h.code = STD_CODE;
- h.distance = 1;
- }
- else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (parmtype),
- TYPE_OFFSET_BASETYPE (type)))
+ else
{
+ int b_or_d = get_base_distance (ttr, ttl, 0, (tree*)0);
+ if (b_or_d < 0)
+ {
+ b_or_d = get_base_distance (ttl, ttr, 0, (tree*)0);
+ if (b_or_d < 0)
+ return EVIL_RETURN (h);
+ h.distance = -b_or_d;
+ }
+ else
+ h.distance = b_or_d;
h.code = STD_CODE;
- h.distance = -1;
}
- else
- return EVIL_RETURN (h);
+
/* Now test the OFFSET_TYPE's target compatibility. */
type = TREE_TYPE (type);
parmtype = TREE_TYPE (parmtype);
if (coder == VOID_TYPE)
return EVIL_RETURN (h);
+ if (codel == BOOLEAN_TYPE)
+ {
+ if (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE)
+ return STD_RETURN (h);
+ else if (coder == POINTER_TYPE || coder == OFFSET_TYPE)
+ {
+ /* Make this worse than any conversion to another pointer.
+ FIXME this is how I think the language should work, but it may not
+ end up being how the language is standardized (jason 1/30/95). */
+ h.distance = 32767;
+ return STD_RETURN (h);
+ }
+ return EVIL_RETURN (h);
+ }
+
if (INTEGRAL_CODE_P (codel))
{
/* Control equivalence of ints an enums. */
== TYPE_MAIN_VARIANT (type_promotes_to (parmtype)))
{
h.code = PROMO_CODE;
-#if 0 /* What purpose does this serve? -jason */
- /* A char, short, wchar_t, etc., should promote to an int if
- it can handle it, otherwise to an unsigned. So we'll make
- an unsigned. */
- if (type != integer_type_node)
- h.int_penalty = 1;
-#endif
}
else
h.code = STD_CODE;
}
/* Convert arrays which have not previously been converted. */
- if (codel == ARRAY_TYPE)
- codel = POINTER_TYPE;
if (coder == ARRAY_TYPE)
- coder = POINTER_TYPE;
+ {
+ coder = POINTER_TYPE;
+ if (parm)
+ {
+ parm = decay_conversion (parm);
+ parmtype = TREE_TYPE (parm);
+ }
+ else
+ parmtype = build_pointer_type (TREE_TYPE (parmtype));
+ }
/* Conversions among pointers */
if (codel == POINTER_TYPE && coder == POINTER_TYPE)
register tree ttr = TYPE_MAIN_VARIANT (TREE_TYPE (parmtype));
int penalty = 4 * (ttl != ttr);
- /* Anything converts to void *. void * converts to anything.
- Since these may be `const void *' (etc.) use VOID_TYPE
- instead of void_type_node. Otherwise, the targets must be the same,
- except that we do allow (at some cost) conversion between signed and
- unsigned pointer types. */
+ /* Anything converts to void *. Since this may be `const void *'
+ (etc.) use VOID_TYPE instead of void_type_node. Otherwise, the
+ targets must be the same, except that we do allow (at some cost)
+ conversion between signed and unsigned pointer types. */
if ((TREE_CODE (ttl) == METHOD_TYPE
|| TREE_CODE (ttl) == FUNCTION_TYPE)
}
#if 1
- if (TREE_CODE (ttl) != VOID_TYPE && TREE_CODE (ttr) != VOID_TYPE)
+ if (TREE_CODE (ttl) != VOID_TYPE
+ && (TREE_CODE (ttr) != VOID_TYPE || !parm || !integer_zerop (parm)))
{
- if (TREE_UNSIGNED (ttl) != TREE_UNSIGNED (ttr))
- {
- ttl = unsigned_type (ttl);
- ttr = unsigned_type (ttr);
- penalty = 10;
- }
- if (! comp_target_types (ttl, ttr, 0))
+ if (comp_target_types (type, parmtype, 1) <= 0)
return EVIL_RETURN (h);
}
#else
&& (ttl = unsigned_type (ttl),
ttr = unsigned_type (ttr),
penalty = 10, 0))
- || (comp_target_types (ttl, ttr, 0))))
+ || (comp_target_types (ttl, ttr, 0) > 0)))
return EVIL_RETURN (h);
#endif
- if (penalty == 10 || ttr == ttl)
+ if (ttr == ttl)
{
tree tmp1 = TREE_TYPE (type), tmp2 = TREE_TYPE (parmtype);
- /* If one was unsigned but the other wasn't, then we need to
- do a standard conversion from T to unsigned T. */
- if (penalty == 10)
- h.code = PROMO_CODE; /* was STD_CODE */
- else
- h.code = 0;
-
+ h.code = 0;
/* Note conversion from `T*' to `const T*',
or `T*' to `volatile T*'. */
- if (ttl == ttr
- && ((TYPE_READONLY (tmp1) != TREE_READONLY (tmp2))
- || (TYPE_VOLATILE (tmp1) != TYPE_VOLATILE (tmp2))))
+ if ((TYPE_READONLY (tmp1) < TREE_READONLY (tmp2))
+ || (TYPE_VOLATILE (tmp1) < TYPE_VOLATILE (tmp2)))
+ h.code = EVIL_CODE;
+ else if ((TYPE_READONLY (tmp1) != TREE_READONLY (tmp2))
+ || (TYPE_VOLATILE (tmp1) != TYPE_VOLATILE (tmp2)))
h.code |= QUAL_CODE;
h.distance = 0;
if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
{
- int b_or_d = get_base_distance (ttl, ttr, 0, 0);
+ int b_or_d = get_base_distance (ttl, ttr, 0, (tree*)0);
if (b_or_d < 0)
{
- b_or_d = get_base_distance (ttr, ttl, 0, 0);
+ b_or_d = get_base_distance (ttr, ttl, 0, (tree*)0);
if (b_or_d < 0)
return EVIL_RETURN (h);
h.distance = -b_or_d;
h.distance = CLASSTYPE_MAX_DEPTH (ttr)+1;
return h;
}
+
h.code = penalty ? STD_CODE : PROMO_CODE;
+ /* Catch things like `const char *' -> `const void *'
+ vs `const char *' -> `void *'. */
+ if (ttl != ttr)
+ {
+ tree tmp1 = TREE_TYPE (type), tmp2 = TREE_TYPE (parmtype);
+ if ((TYPE_READONLY (tmp1) < TREE_READONLY (tmp2))
+ || (TYPE_VOLATILE (tmp1) < TYPE_VOLATILE (tmp2)))
+ h.code = EVIL_CODE;
+ else if ((TYPE_READONLY (tmp1) > TREE_READONLY (tmp2))
+ || (TYPE_VOLATILE (tmp1) > TYPE_VOLATILE (tmp2)))
+ h.code |= QUAL_CODE;
+ }
return h;
}
&& IS_SIGNATURE_POINTER (type) && IS_SIGNATURE (TREE_TYPE (parmtype)))
return ZERO_RETURN (h);
- if (codel == REFERENCE_TYPE)
+ if (codel == RECORD_TYPE && coder == RECORD_TYPE)
{
- tree ttl, ttr;
- int constp = parm ? TREE_READONLY (parm) : TYPE_READONLY (parmtype);
- int volatilep = (parm ? TREE_THIS_VOLATILE (parm)
- : TYPE_VOLATILE (parmtype));
- register tree intype = TYPE_MAIN_VARIANT (parmtype);
- register enum tree_code form = TREE_CODE (intype);
- int penalty = 0;
-
- ttl = TREE_TYPE (type);
-
- /* When passing a non-const argument into a const reference (or vice
- versa), dig it a little, so a non-const reference is preferred
- over this one. (mrs) */
- if (TYPE_READONLY (ttl) != constp
- || TYPE_VOLATILE (ttl) != volatilep)
- penalty = 2;
- else
- penalty = 0;
-
- ttl = TYPE_MAIN_VARIANT (ttl);
-
- if (form == OFFSET_TYPE)
+ int b_or_d = get_base_distance (type, parmtype, 0, (tree*)0);
+ if (b_or_d < 0)
{
- intype = TREE_TYPE (intype);
- form = TREE_CODE (intype);
+ b_or_d = get_base_distance (parmtype, type, 0, (tree*)0);
+ if (b_or_d < 0)
+ return EVIL_RETURN (h);
+ h.distance = -b_or_d;
}
-
- if (ttl == intype && penalty == 0)
- return ZERO_RETURN (h);
else
- penalty = 2;
+ h.distance = b_or_d;
+ h.code = STD_CODE;
+ return h;
+ }
+ return EVIL_RETURN (h);
+}
- if (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (intype))
- {
- ttl = unsigned_type (ttl);
- intype = unsigned_type (intype);
- penalty += 2;
- }
+/* A clone of build_type_conversion for checking user-defined conversions in
+ overload resolution. */
- ttr = intype;
+int
+user_harshness (type, parmtype)
+ register tree type, parmtype;
+{
+ tree conv;
+ tree winner = NULL_TREE;
+ int code;
- /* If the initializer is not an lvalue, then it does not
- matter if we make life easier for the programmer
- by creating a temporary variable with which to
- hold the result. */
- if (parm && (INTEGRAL_CODE_P (coder)
- || coder == REAL_TYPE)
- && ! lvalue_p (parm))
- {
- h = convert_harshness (ttl, ttr, NULL_TREE);
- if (penalty > 2 || h.code != 0)
- h.code |= STD_CODE;
- else
- h.code |= TRIVIAL_CODE;
- h.distance = 0;
- return h;
- }
+ {
+ tree typename = build_typename_overload (type);
+ if (lookup_fnfields (TYPE_BINFO (parmtype), typename, 0))
+ return 0;
+ }
+
+ for (conv = lookup_conversions (parmtype); conv; conv = TREE_CHAIN (conv))
+ {
+ struct harshness_code tmp;
+ tree cand = TREE_VALUE (conv);
- if (ttl == ttr)
+ if (winner && winner == cand)
+ continue;
+
+ tmp = convert_harshness (type, TREE_TYPE (TREE_TYPE (cand)), NULL_TREE);
+ if ((tmp.code < USER_CODE) && (tmp.distance >= 0))
{
- if (penalty > 2)
- {
- h.code = STD_CODE;
- h.distance = 0;
- }
+ if (winner)
+ return EVIL_CODE;
else
{
- h.code = TRIVIAL_CODE;
- /* We set this here so that build_overload_call_real will be
- able to see the penalty we found, rather than just looking
- at a TRIVIAL_CODE with no other information. */
- h.int_penalty = penalty;
+ winner = cand;
+ code = tmp.code;
}
- return h;
}
+ }
- /* Pointers to voids always convert for pointers. But
- make them less natural than more specific matches. */
- if (TREE_CODE (ttl) == POINTER_TYPE && TREE_CODE (ttr) == POINTER_TYPE)
- {
- if (TREE_TYPE (ttl) == void_type_node
- || TREE_TYPE (ttr) == void_type_node)
- {
- h.code = STD_CODE;
- h.distance = 0;
- return h;
- }
- }
+ if (winner)
+ return code;
- /* Here it does matter. If this conversion is from derived to base,
- allow it. Otherwise, types must be compatible in the strong sense. */
- if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
- {
- int b_or_d = get_base_distance (ttl, ttr, 0, 0);
- if (b_or_d < 0)
- {
- b_or_d = get_base_distance (ttr, ttl, 0, 0);
- if (b_or_d < 0)
- return EVIL_RETURN (h);
- h.distance = -b_or_d;
- }
- /* Say that this conversion is relatively painless.
- If it turns out that there is a user-defined X(X&)
- constructor, then that will be invoked, but that's
- preferable to dealing with other user-defined conversions
- that may produce surprising results. */
- else
- h.distance = b_or_d;
- h.code = STD_CODE;
- return h;
- }
+ return -1;
+}
- if (comp_target_types (ttl, intype, 1))
- {
- if (penalty)
- h.code = STD_CODE;
- h.distance = 0;
- return h;
- }
- }
- if (codel == RECORD_TYPE && coder == RECORD_TYPE)
- {
- int b_or_d = get_base_distance (type, parmtype, 0, 0);
- if (b_or_d < 0)
- {
- b_or_d = get_base_distance (parmtype, type, 0, 0);
- if (b_or_d < 0)
- return EVIL_RETURN (h);
- h.distance = -b_or_d;
- }
- else
- h.distance = b_or_d;
- h.code = STD_CODE;
- return h;
- }
- return EVIL_RETURN (h);
+int
+can_convert (to, from)
+ tree to, from;
+{
+ struct harshness_code h;
+ h = convert_harshness (to, from, NULL_TREE);
+ return (h.code < USER_CODE) && (h.distance >= 0);
+}
+
+int
+can_convert_arg (to, from, arg)
+ tree to, from, arg;
+{
+ struct harshness_code h;
+ h = convert_harshness (to, from, arg);
+ return (h.code < USER_CODE) && (h.distance >= 0);
}
#ifdef DEBUG_MATCHING
int strike_index = 0, win;
struct harshness_code lose;
+ extern int cp_silent;
#ifdef GATHER_STATISTICS
n_compute_conversion_costs++;
#endif
+#ifndef DEBUG_MATCHING
+ /* We don't emit any warnings or errors while trying out each candidate. */
+ cp_silent = 1;
+#endif
+
cp->function = function;
cp->arg = tta ? TREE_VALUE (tta) : NULL_TREE;
cp->u.bad_arg = 0; /* optimistic! */
cp->h.code = 0;
cp->h.distance = 0;
cp->h.int_penalty = 0;
- bzero (cp->harshness,
+ bzero ((char *) cp->harshness,
(cp->h_len + 1) * sizeof (struct harshness_code));
while (ttf && tta)
{
cp->h.code = EVIL_CODE;
cp->u.bad_arg = -1;
+ cp_silent = 0;
return;
}
else
{
cp->h.code = EVIL_CODE;
cp->u.bad_arg = -2;
+ cp_silent = 0;
return;
}
/* Store index of first default. */
if (dont_convert_types)
{
cp->h.code = EVIL_CODE;
+ cp_silent = 0;
return;
}
if (TYPE_LANG_SPECIFIC (actual_type)
&& TYPE_HAS_CONVERSION (actual_type))
{
- tree conv;
- /* Don't issue warnings since we're only groping
- around for the right answer, we haven't yet
- committed to going with this solution. */
- int old_inhibit_warnings = inhibit_warnings;
-
- inhibit_warnings = 1;
- conv = build_type_conversion
- (CALL_EXPR, TREE_VALUE (ttf), TREE_VALUE (tta), 0);
- inhibit_warnings = old_inhibit_warnings;
-
- if (conv)
- {
- if (conv == error_mark_node)
- win += 2;
- else
- {
- win++;
- if (TREE_CODE (conv) != CALL_EXPR)
- extra_conversions = 1;
- }
- }
- else if (TREE_CODE (TREE_VALUE (ttf)) == REFERENCE_TYPE)
+ int extra = user_harshness (formal_type, actual_type);
+
+ if (extra == EVIL_CODE)
+ win += 2;
+ else if (extra >= 0)
{
- conv = build_type_conversion (CALL_EXPR, formal_type,
- TREE_VALUE (tta), 0);
- if (conv)
- {
- if (conv == error_mark_node)
- win += 2;
- else
- {
- win++;
- if (TREE_CODE (conv) != CALL_EXPR)
- extra_conversions = 1;
- }
- }
+ win++;
+ extra_conversions = extra;
}
}
}
cp->h.code |= ELLIPSIS_CODE;
if (user_strikes)
cp->h.code |= USER_CODE;
+ cp_silent = 0;
#ifdef DEBUG_MATCHING
cp_error ("final eval %s", print_harshness (&cp->h));
#endif
LEN is the length of the parameter list. */
static struct candidate *
-ideal_candidate (basetype, candidates, n_candidates, parms, len)
- tree basetype;
+ideal_candidate (candidates, n_candidates, len)
struct candidate *candidates;
int n_candidates;
- tree parms;
int len;
{
struct candidate *cp = candidates+n_candidates;
list for the last argument is the intersection of all the best-liked
functions. */
-#if 0
- for (i = 0; i < len; i++)
- {
- qsort (candidates, n_candidates, sizeof (struct candidate),
- rank_for_overload);
- best_code = cp[-1].h.code;
-
- /* To find out functions that are worse than that represented
- by BEST_CODE, we can't just do a comparison like h.code>best_code.
- The total harshness for the "best" fn may be 8|8 for two args, and
- the harshness for the next-best may be 8|2. If we just compared,
- that would be checking 8>10, which would lead to the next-best
- being disqualified. What we actually want to do is get rid
- of functions that are definitely worse than that represented
- by best_code, i.e. those which have bits set higher than the
- highest in best_code. Sooooo, what we do is clear out everything
- represented by best_code, and see if we still come up with something
- higher. If so (e.g., 8|8 vs 8|16), it'll disqualify it properly. */
- for (j = n_candidates-2; j >= 0; j--)
- if ((candidates[j].h.code & ~best_code) > best_code)
- candidates[j].h.code = EVIL_CODE;
- }
-
- if (cp[-1].h.code & EVIL_CODE)
- return NULL;
-#else
qsort (candidates, n_candidates, sizeof (struct candidate),
rank_for_overload);
best_code = cp[-1].h.code;
-#endif
/* If they're at least as good as each other, do an arg-by-arg check. */
if (! strictly_better (cp[-1].h.code, cp[-2].h.code))
rval = build (COMPONENT_REF, TREE_TYPE (CLASSTYPE_VFIELD (type)),
datum, CLASSTYPE_VFIELD (type));
else
- rval = build_component_ref (datum, DECL_NAME (CLASSTYPE_VFIELD (type)), 0, 0);
+ rval = build_component_ref (datum, DECL_NAME (CLASSTYPE_VFIELD (type)), NULL_TREE, 0);
flag_assume_nonnull_objects = old_assume_nonnull_objects;
return rval;
{
tree field, instance;
- if (instance_ptr == current_class_decl)
+ if (instance_ptr == current_class_ptr)
{
/* Check to see if we really have a reference to an instance variable
with `operator()()' overloaded. */
{
/* If it's a field, try overloading operator (),
or calling if the field is a pointer-to-function. */
- instance = build_component_ref_1 (C_C_D, field, 0);
+ instance = build_component_ref_1 (current_class_ref, field, 0);
if (instance == error_mark_node)
return error_mark_node;
if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == FUNCTION_TYPE)
return build_function_call (instance, parms);
else if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == METHOD_TYPE)
- return build_function_call (instance, tree_cons (NULL_TREE, current_class_decl, parms));
+ return build_function_call (instance, tree_cons (NULL_TREE, current_class_ptr, parms));
}
}
return NULL_TREE;
if (TREE_PURPOSE (tags) == inner_name)
{
if (inner_types == NULL_TREE)
- return DECL_NESTED_TYPENAME (TYPE_NAME (TREE_VALUE (tags)));
+ return TYPE_NAME (TREE_VALUE (tags));
return resolve_scope_to_name (TREE_VALUE (tags), inner_types);
}
tags = TREE_CHAIN (tags);
}
-#if 0
- /* XXX This needs to be fixed better. */
- if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
- {
- sorry ("nested class lookup in template type");
- return NULL_TREE;
- }
-#endif
-
/* Look for a TYPE_DECL. */
for (tags = TYPE_FIELDS (type); tags; tags = TREE_CHAIN (tags))
if (TREE_CODE (tags) == TYPE_DECL && DECL_NAME (tags) == inner_name)
{
/* Code by raeburn. */
if (inner_types == NULL_TREE)
- return DECL_NESTED_TYPENAME (tags);
+ return tags;
return resolve_scope_to_name (TREE_TYPE (tags), inner_types);
}
if (outer_type == NULL_TREE)
{
+ tree x;
/* If we have something that's already a type by itself,
use that. */
if (IDENTIFIER_HAS_TYPE_VALUE (inner_name))
inner_type);
return inner_name;
}
+
+ x = lookup_name (inner_name, 0);
+
+ if (x && TREE_CODE (x) == NAMESPACE_DECL)
+ {
+ x = lookup_namespace_name (x, inner_type);
+ return x;
+ }
return NULL_TREE;
}
/* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'.
This is how virtual function calls are avoided. */
tree
-build_scoped_method_call (exp, scopes, name, parms)
- tree exp, scopes, name, parms;
+build_scoped_method_call (exp, basetype, name, parms)
+ tree exp, basetype, name, parms;
{
/* Because this syntactic form does not allow
a pointer to a base class to be `stolen',
that happens here.
@@ But we do have to check access privileges later. */
- tree basename = resolve_scope_to_name (NULL_TREE, scopes);
- tree basetype, binfo, decl;
+ tree binfo, decl;
tree type = TREE_TYPE (exp);
if (type == error_mark_node
- || basename == NULL_TREE)
+ || basetype == error_mark_node)
return error_mark_node;
- basetype = IDENTIFIER_TYPE_VALUE (basename);
+ if (current_template_parms)
+ {
+ if (TREE_CODE (name) == BIT_NOT_EXPR)
+ {
+ tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 1);
+ name = build_min_nt (BIT_NOT_EXPR, type);
+ }
+ name = build_min_nt (SCOPE_REF, basetype, name);
+ return build_min_nt (METHOD_CALL_EXPR, name, exp, parms, NULL_TREE);
+ }
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
/* Destructors can be "called" for simple types; see 5.2.4 and 12.4 Note
that explicit ~int is caught in the parser; this deals with typedefs
and template parms. */
- if (TREE_CODE (name) == BIT_NOT_EXPR && ! is_aggr_typedef (basename, 0))
+ if (TREE_CODE (name) == BIT_NOT_EXPR && ! IS_AGGR_TYPE (basetype))
{
if (type != basetype)
cp_error ("type of `%E' does not match destructor type `%T' (type was `%T')",
exp, basetype, type);
- name = IDENTIFIER_TYPE_VALUE (TREE_OPERAND (name, 0));
- if (basetype != name)
- cp_error ("qualified type `%T' does not match destructor type `%T'",
+ name = TREE_OPERAND (name, 0);
+ if (basetype != name && basetype != get_type_value (name))
+ cp_error ("qualified type `%T' does not match destructor name `~%T'",
basetype, name);
- return void_zero_node;
+ return convert (void_type_node, exp);
}
- if (! is_aggr_typedef (basename, 1))
+ if (! is_aggr_type (basetype, 1))
return error_mark_node;
if (! IS_AGGR_TYPE (type))
decl = build_indirect_ref (convert_pointer_to (binfo,
build_unary_op (ADDR_EXPR, exp, 0)), NULL_PTR);
else
- decl = build_scoped_ref (exp, scopes);
+ decl = build_scoped_ref (exp, basetype);
/* Call to a destructor. */
if (TREE_CODE (name) == BIT_NOT_EXPR)
{
/* Explicit call to destructor. */
name = TREE_OPERAND (name, 0);
- if (name != constructor_name (TREE_TYPE (decl)))
+ if (! (name == TYPE_MAIN_VARIANT (TREE_TYPE (decl))
+ || name == constructor_name (TREE_TYPE (decl))
+ || TREE_TYPE (decl) == get_type_value (name)))
{
cp_error
- ("qualified type `%T' does not match destructor type `%T'",
+ ("qualified type `%T' does not match destructor name `~%T'",
TREE_TYPE (decl), name);
return error_mark_node;
}
if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
- return void_zero_node;
+ return convert (void_type_node, exp);
return build_delete (TREE_TYPE (decl), decl, integer_two_node,
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR,
cp_error_at (" %D", candidates[i].function);
}
+/* We want the address of a function or method. We avoid creating a
+ pointer-to-member function. */
+tree
+build_addr_func (function)
+ tree function;
+{
+ tree type = TREE_TYPE (function);
+
+ /* We have to do these by hand to avoid real pointer to member
+ functions. */
+ if (TREE_CODE (type) == METHOD_TYPE)
+ {
+ tree addr;
+
+ type = build_pointer_type (type);
+
+ if (mark_addressable (function) == 0)
+ return error_mark_node;
+
+ addr = build1 (ADDR_EXPR, type, function);
+
+ /* Address of a static or external variable or function counts
+ as a constant */
+ if (staticp (function))
+ TREE_CONSTANT (addr) = 1;
+
+ function = addr;
+ }
+ else
+ function = default_conversion (function);
+
+ return function;
+}
+
+/* Build a CALL_EXPR, we can handle FUNCTION_TYPEs, METHOD_TYPEs, or
+ POINTER_TYPE to those. Note, pointer to member function types
+ (TYPE_PTRMEMFUNC_P) must be handled by our callers. */
+tree
+build_call (function, result_type, parms)
+ tree function, result_type, parms;
+{
+ int is_constructor = 0;
+
+ function = build_addr_func (function);
+
+ if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
+ {
+ sorry ("unable to call pointer to member function here");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (function) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
+ && DECL_CONSTRUCTOR_P (TREE_OPERAND (function, 0)))
+ is_constructor = 1;
+
+ function = build_nt (CALL_EXPR, function, parms, NULL_TREE);
+ TREE_HAS_CONSTRUCTOR (function) = is_constructor;
+ TREE_TYPE (function) = result_type;
+ TREE_SIDE_EFFECTS (function) = 1;
+
+ return function;
+}
+
+static tree
+default_parm_conversions (parms, last)
+ tree parms, *last;
+{
+ tree parm, parmtypes = NULL_TREE;
+
+ *last = NULL_TREE;
+
+ for (parm = parms; parm; parm = TREE_CHAIN (parm))
+ {
+ tree t = TREE_TYPE (TREE_VALUE (parm));
+
+ if (TREE_CODE (t) == OFFSET_TYPE
+ || TREE_CODE (t) == METHOD_TYPE
+ || TREE_CODE (t) == FUNCTION_TYPE)
+ {
+ TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
+ t = TREE_TYPE (TREE_VALUE (parm));
+ }
+
+ if (t == error_mark_node)
+ return error_mark_node;
+
+ *last = build_tree_list (NULL_TREE, t);
+ parmtypes = chainon (parmtypes, *last);
+ }
+
+ return parmtypes;
+}
+
+
/* Build something of the form ptr->method (args)
or object.method (args). This can also build
calls to constructors, and find friends.
{
register tree function, fntype, value_type;
register tree basetype, save_basetype;
- register tree baselink, result, method_name, parmtypes, parm;
+ register tree baselink, result, parmtypes, parm;
tree last;
int pass;
- enum access_type access = access_public;
+ tree access = access_public_node;
+ tree orig_basetype = basetype_path ? BINFO_TYPE (basetype_path) : NULL_TREE;
/* Range of cases for vtable optimization. */
enum vtable_needs { not_needed, maybe_needed, unneeded, needed };
enum vtable_needs need_vtbl = not_needed;
char *name_kind;
+ tree save_name = name;
int ever_seen = 0;
tree instance_ptr = NULL_TREE;
int all_virtual = flag_all_virtual;
|| (instance != NULL_TREE && TREE_TYPE (instance) == error_mark_node))
return error_mark_node;
+ if (current_template_parms)
+ {
+ if (TREE_CODE (name) == BIT_NOT_EXPR)
+ {
+ tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 1);
+ name = build_min_nt (BIT_NOT_EXPR, type);
+ }
+
+ return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE);
+ }
+
/* This is the logic that magically deletes the second argument to
operator delete, if it is not needed. */
if (name == ansi_opname[(int) DELETE_EXPR] && list_length (parms)==2)
result = build_method_call (instance, name, parms, basetype_path,
(LOOKUP_SPECULATIVELY|flags)
&~LOOKUP_COMPLAIN);
- /* If it works, return it. */
- if (result && result != error_mark_node)
+ /* If it finds a match, return it. */
+ if (result)
return build_method_call (instance, name, parms, basetype_path, flags);
/* If it doesn't work, two argument delete must work */
TREE_CHAIN (parms) = save_last;
}
/* We already know whether it's needed or not for vec delete. */
else if (name == ansi_opname[(int) VEC_DELETE_EXPR]
+ && TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
&& ! TYPE_VEC_DELETE_TAKES_SIZE (TREE_TYPE (instance)))
TREE_CHAIN (parms) = NULL_TREE;
if (parms)
error ("destructors take no parameters");
basetype = TREE_TYPE (instance);
- if (! ((IS_AGGR_TYPE (basetype)
- && name == constructor_name (basetype))
+ if (TREE_CODE (basetype) == REFERENCE_TYPE)
+ basetype = TREE_TYPE (basetype);
+ if (! (name == basetype
+ || (IS_AGGR_TYPE (basetype)
+ && name == constructor_name (basetype))
|| basetype == get_type_value (name)))
{
cp_error ("destructor name `~%D' does not match type `%T' of expression",
name, basetype);
- return void_zero_node;
+ return convert (void_type_node, instance);
}
if (! TYPE_HAS_DESTRUCTOR (basetype))
- return void_zero_node;
+ return convert (void_type_node, instance);
instance = default_conversion (instance);
instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
return build_delete (build_pointer_type (basetype),
;
/* call to a constructor... */
else if (basetype_path)
- basetype = BINFO_TYPE (basetype_path);
+ {
+ basetype = BINFO_TYPE (basetype_path);
+ if (name == TYPE_IDENTIFIER (basetype))
+ name = ctor_identifier;
+ }
else if (IDENTIFIER_HAS_TYPE_VALUE (name))
{
basetype = IDENTIFIER_TYPE_VALUE (name);
- name = constructor_name_full (basetype);
+ name = ctor_identifier;
}
else
{
{
/* Canonicalize the typedef name. */
basetype = TREE_TYPE (typedef_name);
- name = TYPE_IDENTIFIER (basetype);
+ name = ctor_identifier;
}
else
{
return error_mark_node;
}
}
- else if (instance == C_C_D || instance == current_class_decl)
+ else if (instance == current_class_ref || instance == current_class_ptr)
{
/* When doing initialization, we side-effect the TREE_TYPE of
- C_C_D, hence we cannot set up BASETYPE from CURRENT_CLASS_TYPE. */
- basetype = TREE_TYPE (C_C_D);
+ current_class_ref, hence we cannot set up BASETYPE from CURRENT_CLASS_TYPE. */
+ basetype = TREE_TYPE (current_class_ref);
/* Anything manifestly `this' in constructors and destructors
has a known type, so virtual function tables are not needed. */
need_vtbl = (dtor_label || ctor_label)
? unneeded : maybe_needed;
- instance = C_C_D;
- instance_ptr = current_class_decl;
- result = build_field_call (TYPE_BINFO (current_class_type),
- instance_ptr, name, parms);
+ /* If `this' is a signature pointer and `name' is not a constructor,
+ we are calling a signature member function. In that case, set the
+ `basetype' to the signature type and dereference the `optr' field. */
+ if (IS_SIGNATURE_POINTER (basetype)
+ && TYPE_IDENTIFIER (basetype) != name)
+ {
+ basetype = SIGNATURE_TYPE (basetype);
+ instance_ptr = build_optr_ref (instance);
+ instance_ptr = convert (build_pointer_type (basetype), instance_ptr);
+ basetype_path = TYPE_BINFO (basetype);
+ }
+ else
+ {
+ instance = current_class_ref;
+ instance_ptr = current_class_ptr;
+ basetype_path = TYPE_BINFO (current_class_type);
+ }
+ result = build_field_call (basetype_path, instance_ptr, name, parms);
if (result)
return result;
within the scope of this function. */
if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
need_vtbl = maybe_needed;
- instance_ptr = build1 (ADDR_EXPR, TYPE_POINTER_TO (basetype), instance);
+ instance_ptr = build1 (ADDR_EXPR, build_pointer_type (basetype), instance);
}
else
{
}
else
{
- if (! IS_AGGR_TYPE (basetype))
+ if (! IS_AGGR_TYPE (basetype)
+ && ! (TYPE_LANG_SPECIFIC (basetype)
+ && (IS_SIGNATURE_POINTER (basetype)
+ || IS_SIGNATURE_REFERENCE (basetype))))
goto non_aggr_error;
/* If `instance' is a signature pointer/reference and `name' is
basetype = SIGNATURE_TYPE (basetype);
if ((IS_SIGNATURE (basetype)
- && (instance_ptr = build_optr_ref (instance)))
+ && (instance_ptr = instance))
|| (lvalue_p (instance)
&& (instance_ptr = build_unary_op (ADDR_EXPR, instance, 0)))
|| (instance_ptr = unary_complex_lvalue (ADDR_EXPR, instance)))
we can manage. */
tree temp = get_temp_name (TREE_TYPE (instance), 0);
if (IS_AGGR_TYPE (TREE_TYPE (instance)))
- expand_aggr_init (temp, instance, 0);
+ expand_aggr_init (temp, instance, 0, flags);
else
{
store_init_value (temp, instance);
if (TREE_CODE (instance) != CALL_EXPR)
my_friendly_abort (125);
if (TYPE_NEEDS_CONSTRUCTING (basetype))
- instance = build_cplus_new (basetype, instance, 0);
+ instance = build_cplus_new (basetype, instance);
else
{
instance = get_temp_name (basetype, 0);
instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
}
/* @@ Should we call comp_target_types here? */
- inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));
+ if (IS_SIGNATURE (basetype))
+ inst_ptr_basetype = basetype;
+ else
+ inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));
if (TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (inst_ptr_basetype))
basetype = inst_ptr_basetype;
else
{
- instance_ptr = convert (TYPE_POINTER_TO (basetype), instance_ptr);
+ instance_ptr = convert (build_pointer_type (basetype), instance_ptr);
if (instance_ptr == error_mark_node)
return error_mark_node;
}
}
}
- if (TYPE_SIZE (basetype) == 0)
+ if (save_name == ctor_identifier)
+ save_name = TYPE_IDENTIFIER (basetype);
+
+ if (TYPE_SIZE (complete_type (basetype)) == 0)
{
/* This is worth complaining about, I think. */
cp_error ("cannot lookup method in incomplete type `%T'", basetype);
save_basetype = TYPE_MAIN_VARIANT (basetype);
-#if 0
- if (all_virtual == 1
- && (! strncmp (IDENTIFIER_POINTER (name), OPERATOR_METHOD_FORMAT,
- OPERATOR_METHOD_LENGTH)
- || instance_ptr == NULL_TREE
- || (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype) == 0)))
- all_virtual = 0;
-#endif
-
- last = NULL_TREE;
- for (parmtypes = NULL_TREE, parm = parms; parm; parm = TREE_CHAIN (parm))
+ parmtypes = default_parm_conversions (parms, &last);
+ if (parmtypes == error_mark_node)
{
- tree t = TREE_TYPE (TREE_VALUE (parm));
- if (TREE_CODE (t) == OFFSET_TYPE)
- {
- /* Convert OFFSET_TYPE entities to their normal selves. */
- TREE_VALUE (parm) = resolve_offset_ref (TREE_VALUE (parm));
- t = TREE_TYPE (TREE_VALUE (parm));
- }
- if (TREE_CODE (TREE_VALUE (parm)) == OFFSET_REF
- && TREE_CODE (t) == METHOD_TYPE)
- {
- TREE_VALUE (parm) = build_unary_op (ADDR_EXPR, TREE_VALUE (parm), 0);
- }
- if (TREE_CODE (t) == ARRAY_TYPE)
- {
- /* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
- This eliminates needless calls to `compute_conversion_costs'. */
- TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
- t = TREE_TYPE (TREE_VALUE (parm));
- }
- if (t == error_mark_node)
- return error_mark_node;
- last = build_tree_list (NULL_TREE, t);
- parmtypes = chainon (parmtypes, last);
+ return error_mark_node;
}
- if (instance)
+ if (instance && IS_SIGNATURE (basetype))
+ {
+ /* @@ Should this be the constp/volatilep flags for the optr field
+ of the signature pointer? */
+ constp = TYPE_READONLY (basetype);
+ volatilep = TYPE_VOLATILE (basetype);
+ parms = tree_cons (NULL_TREE, instance_ptr, parms);
+ }
+ else if (instance)
{
/* TREE_READONLY (instance) fails for references. */
constp = TYPE_READONLY (TREE_TYPE (TREE_TYPE (instance_ptr)));
parmtypes = tree_cons (NULL_TREE, integer_type_node, parmtypes);
}
- if (flag_this_is_variable > 0)
- {
- constp = 0;
- volatilep = 0;
- parms = tree_cons (NULL_TREE, build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node), parms);
- }
- else
- {
- constp = 0;
- volatilep = 0;
- instance_ptr = build_new (NULL_TREE, basetype, void_type_node, 0);
- if (instance_ptr == error_mark_node)
- return error_mark_node;
- instance_ptr = save_expr (instance_ptr);
- TREE_CALLS_NEW (instance_ptr) = 1;
- instance = build_indirect_ref (instance_ptr, NULL_PTR);
-
- /* If it's a default argument initialized from a ctor, what we get
- from instance_ptr will match the arglist for the FUNCTION_DECL
- of the constructor. */
- if (parms && TREE_CODE (TREE_VALUE (parms)) == CALL_EXPR
- && TREE_OPERAND (TREE_VALUE (parms), 1)
- && TREE_CALLS_NEW (TREE_VALUE (TREE_OPERAND (TREE_VALUE (parms), 1))))
- parms = build_tree_list (NULL_TREE, instance_ptr);
- else
- parms = tree_cons (NULL_TREE, instance_ptr, parms);
- }
+ constp = 0;
+ volatilep = 0;
+ instance_ptr = build_int_2 (0, 0);
+ TREE_TYPE (instance_ptr) = build_pointer_type (basetype);
+ parms = tree_cons (NULL_TREE, instance_ptr, parms);
}
parmtypes = tree_cons (NULL_TREE, TREE_TYPE (instance_ptr), parmtypes);
/* Look up function name in the structure type definition. */
+ /* FIXME Axe most of this now? */
if ((IDENTIFIER_HAS_TYPE_VALUE (name)
&& ! IDENTIFIER_OPNAME_P (name)
- && IS_AGGR_TYPE (IDENTIFIER_TYPE_VALUE (name))
- && TREE_CODE (IDENTIFIER_TYPE_VALUE (name)) != UNINSTANTIATED_P_TYPE)
- || name == constructor_name (basetype))
+ && IS_AGGR_TYPE (IDENTIFIER_TYPE_VALUE (name)))
+ || name == constructor_name (basetype)
+ || name == ctor_identifier)
{
tree tmp = NULL_TREE;
if (IDENTIFIER_TYPE_VALUE (name) == basetype
- || name == constructor_name (basetype))
+ || name == constructor_name (basetype)
+ || name == ctor_identifier)
tmp = TYPE_BINFO (basetype);
else
tmp = get_binfo (IDENTIFIER_TYPE_VALUE (name), basetype, 0);
if (result == error_mark_node)
return error_mark_node;
-
- /* Now, go look for this method name. We do not find destructors here.
-
- Putting `void_list_node' on the end of the parmtypes
- fakes out `build_decl_overload' into doing the right thing. */
- TREE_CHAIN (last) = void_list_node;
- method_name = build_decl_overload (name, parmtypes,
- 1 + (name == constructor_name (save_basetype)
- || name == constructor_name_full (save_basetype)));
- TREE_CHAIN (last) = NULL_TREE;
-
for (pass = 0; pass < 2; pass++)
{
struct candidate *candidates;
int len;
unsigned best = 1;
- /* This increments every time we go up the type hierarchy.
- The idea is to prefer a function of the derived class if possible. */
- int b_or_d = 0;
-
baselink = result;
if (pass > 0)
candidates
= (struct candidate *) alloca ((ever_seen+1)
* sizeof (struct candidate));
- bzero (candidates, (ever_seen + 1) * sizeof (struct candidate));
+ bzero ((char *) candidates, (ever_seen + 1) * sizeof (struct candidate));
cp = candidates;
len = list_length (parms);
ever_seen = 0;
tree parm = instance_ptr;
if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE)
- {
- /* TREE_VALUE (parms) may have been modified by now;
- restore it to its original value. */
- TREE_VALUE (parms) = parm;
- friend_parms = parms;
- }
+ parm = convert_from_reference (parm);
else if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
- {
- tree new_type;
- parm = build_indirect_ref (parm, "friendifying parms (compiler error)");
- new_type = c_build_type_variant (TREE_TYPE (parm), constp,
- volatilep);
- new_type = build_reference_type (new_type);
- parm = convert (new_type, parm);
- friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
- }
+ parm = build_indirect_ref (parm, "friendifying parms (compiler error)");
else
my_friendly_abort (167);
+ friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
+
cp->h_len = len;
cp->harshness = (struct harshness_code *)
alloca ((len + 1) * sizeof (struct harshness_code));
- result = build_overload_call (name, friend_parms, 0, cp);
+ result = build_overload_call_real (name, friend_parms, 0, cp, 1);
+
/* If it turns out to be the one we were actually looking for
(it was probably a friend function), the return the
good result. */
}
}
- while (baselink)
+ if (baselink)
{
/* We have a hit (of sorts). If the parameter list is
"error_mark_node", or some variant thereof, it won't
basetype_path = TREE_VALUE (basetype_path);
basetype = BINFO_TYPE (basetype_path);
- /* Cast the instance variable if necessary. */
- if (basetype != TYPE_MAIN_VARIANT
- (TREE_TYPE (TREE_TYPE (TREE_VALUE (parms)))))
- {
- if (basetype == save_basetype)
- TREE_VALUE (parms) = instance_ptr;
- else
- {
- tree type = build_pointer_type
- (build_type_variant (basetype, constp, volatilep));
- TREE_VALUE (parms) = convert_force (type, instance_ptr);
- }
- }
-
- /* FIXME: this is the wrong place to get an error. Hopefully
- the access-control rewrite will make this change more cleanly. */
- if (TREE_VALUE (parms) == error_mark_node)
- return error_mark_node;
-
- if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function)))
- function = DECL_CHAIN (function);
-
for (; function; function = DECL_CHAIN (function))
{
#ifdef GATHER_STATISTICS
&& ! DECL_STATIC_FUNCTION_P (function))
continue;
- if (pass == 0
- && DECL_ASSEMBLER_NAME (function) == method_name)
- goto found;
-
if (pass > 0)
{
tree these_parms = parms;
cp->function = function;
cp->basetypes = basetype_path;
+ /* Don't allow non-converting constructors to convert. */
+ if (flags & LOOKUP_ONLYCONVERTING
+ && DECL_LANG_SPECIFIC (function)
+ && DECL_NONCONVERTING_P (function))
+ continue;
+
/* No "two-level" conversions. */
if (flags & LOOKUP_NO_CONVERSION
&& (cp->h.code & USER_CODE))
continue;
- /* If we used default parameters, we must
- check to see whether anyone else might
- use them also, and report a possible
- ambiguity. */
- if (! TYPE_USES_MULTIPLE_INHERITANCE (save_basetype)
- && cp->harshness[len].distance == 0
- && cp->h.code < best)
- {
- if (! DECL_STATIC_FUNCTION_P (function))
- TREE_VALUE (parms) = cp->arg;
- if (best == 1)
- goto found_and_maybe_warn;
- }
cp++;
}
}
}
- /* Now we have run through one link's member functions.
- arrange to head-insert this link's links. */
- baselink = next_baselink (baselink);
- b_or_d += 1;
- /* Don't grab functions from base classes. lookup_fnfield will
- do the work to get us down into the right place. */
- baselink = NULL_TREE;
}
+
if (pass == 0)
{
tree igv = lookup_name_nonclass (name);
TREE_CHAIN (last) = void_list_node;
if (flags & LOOKUP_GLOBAL)
cp_error ("no global or member function `%D(%A)' defined",
- name, parmtypes);
+ save_name, parmtypes);
else
cp_error ("no member function `%T::%D(%A)' defined",
- save_basetype, name, TREE_CHAIN (parmtypes));
+ save_basetype, save_name, TREE_CHAIN (parmtypes));
return error_mark_node;
}
continue;
if (cp - candidates > 1)
{
int n_candidates = cp - candidates;
+ extern int warn_synth;
TREE_VALUE (parms) = instance_ptr;
- cp = ideal_candidate (save_basetype, candidates,
- n_candidates, parms, len);
+ cp = ideal_candidate (candidates, n_candidates, len);
if (cp == (struct candidate *)0)
{
if (flags & LOOKUP_COMPLAIN)
{
- cp_error ("call of overloaded %s `%D' is ambiguous",
- name_kind, name);
+ TREE_CHAIN (last) = void_list_node;
+ cp_error ("call of overloaded %s `%D(%A)' is ambiguous",
+ name_kind, save_name, TREE_CHAIN (parmtypes));
print_n_candidates (candidates, n_candidates);
}
return error_mark_node;
}
if (cp->h.code & EVIL_CODE)
return error_mark_node;
+ if (warn_synth
+ && DECL_NAME (cp->function) == ansi_opname[MODIFY_EXPR]
+ && DECL_ARTIFICIAL (cp->function)
+ && n_candidates == 2)
+ {
+ cp_warning ("using synthesized `%#D' for copy assignment",
+ cp->function);
+ cp_warning_at (" where cfront would use `%#D'",
+ candidates->function);
+ }
}
else if (cp[-1].h.code & EVIL_CODE)
{
if (flags & LOOKUP_COMPLAIN)
cp_error ("ambiguous type conversion requested for %s `%D'",
- name_kind, name);
+ name_kind, save_name);
return error_mark_node;
}
else
else if (ever_seen > 1)
{
TREE_CHAIN (last) = void_list_node;
- cp_error ("no matching function for call to `%T::%D (%A)'",
- TREE_TYPE (TREE_TYPE (instance_ptr)),
- name, TREE_CHAIN (parmtypes));
+ cp_error ("no matching function for call to `%T::%D (%A)%V'",
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (instance_ptr))),
+ save_name, TREE_CHAIN (parmtypes),
+ TREE_TYPE (TREE_TYPE (instance_ptr)));
TREE_CHAIN (last) = NULL_TREE;
print_candidates (found_fns);
}
if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
== LOOKUP_COMPLAIN)
{
- cp_error ("%T has no method named %D", save_basetype, name);
+ cp_error ("%T has no method named %D", save_basetype, save_name);
return error_mark_node;
}
return NULL_TREE;
if (flags & LOOKUP_PROTECT)
access = compute_access (basetype_path, function);
- if (access == access_private)
+ if (access == access_private_node)
{
if (flags & LOOKUP_COMPLAIN)
{
}
return error_mark_node;
}
- else if (access == access_protected)
+ else if (access == access_protected_node)
{
if (flags & LOOKUP_COMPLAIN)
{
type (if it exists) is a pointer to. */
if (DECL_ABSTRACT_VIRTUAL_P (function)
- && instance == C_C_D
+ && instance == current_class_ref
&& DECL_CONSTRUCTOR_P (current_function_decl)
&& ! (flags & LOOKUP_NONVIRTUAL)
&& value_member (function, get_abstract_virtuals (basetype)))
cp_error ("abstract virtual `%#D' called from constructor", function);
- if (IS_SIGNATURE (basetype) && static_call_context)
+ if (IS_SIGNATURE (basetype))
{
- cp_error ("cannot call signature member function `%T::%D' without signature pointer/reference",
- basetype, name);
- return error_mark_node;
+ if (static_call_context)
+ {
+ cp_error ("cannot call signature member function `%T::%D' without signature pointer/reference",
+ basetype, save_name);
+ return error_mark_node;
}
- else if (IS_SIGNATURE (basetype))
- return build_signature_method_call (basetype, instance, function, parms);
+ return build_signature_method_call (basetype, instance, function, parms);
+ }
function = DECL_MAIN_VARIANT (function);
- /* Declare external function if necessary. */
- assemble_external (function);
+ mark_used (function);
+
+ /* Is it a synthesized method that needs to be synthesized? */
+ if (DECL_ARTIFICIAL (function) && ! DECL_INITIAL (function)
+ /* Kludge: don't synthesize for default args. */
+ && current_function_decl)
+ synthesize_method (function);
+
+ if (pedantic && DECL_THIS_INLINE (function) && ! DECL_ARTIFICIAL (function)
+ && ! DECL_INITIAL (function) && ! DECL_PENDING_INLINE_INFO (function)
+ && ! (DECL_TEMPLATE_INFO (function)
+ && TREE_LANG_FLAG_0 (DECL_TEMPLATE_INFO (function))))
+ cp_warning ("inline function `%#D' called before definition", function);
fntype = TREE_TYPE (function);
if (TREE_CODE (fntype) == POINTER_TYPE)
if (TREE_CODE (fntype) == METHOD_TYPE && static_call_context
&& !DECL_CONSTRUCTOR_P (function))
{
- /* Let's be nice to the user for now, and give reasonable
- default behavior. */
- instance_ptr = current_class_decl;
+ /* Let's be nasty to the user now, and give reasonable
+ error messages. */
+ instance_ptr = current_class_ptr;
if (instance_ptr)
{
if (basetype != current_class_type)
{
- tree binfo = get_binfo (basetype, current_class_type, 1);
- if (binfo == NULL_TREE)
- {
- error_not_base_type (function, current_class_type);
- return error_mark_node;
- }
- else if (basetype == error_mark_node)
+ if (basetype == error_mark_node)
return error_mark_node;
+ else
+ {
+ if (orig_basetype != NULL_TREE)
+ error_not_base_type (orig_basetype, current_class_type);
+ else
+ error_not_base_type (function, current_class_type);
+ return error_mark_node;
+ }
}
}
/* Only allow a static member function to call another static member
value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
- if (TYPE_SIZE (value_type) == 0)
+ if (TYPE_SIZE (complete_type (value_type)) == 0)
{
if (flags & LOOKUP_COMPLAIN)
incomplete_type_error (0, value_type);
{
int sub_flags = DECL_CONSTRUCTOR_P (function) ? flags : LOOKUP_NORMAL;
basetype = TREE_TYPE (instance);
- if (TYPE_METHOD_BASETYPE (TREE_TYPE (function)) != TYPE_MAIN_VARIANT (basetype)
- && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+ if (TYPE_METHOD_BASETYPE (TREE_TYPE (function))
+ != TYPE_MAIN_VARIANT (basetype))
{
basetype = DECL_CLASS_CONTEXT (function);
instance_ptr = convert_pointer_to (basetype, instance_ptr);
convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), function, LOOKUP_NORMAL));
}
-#if 0
- /* Constructors do not overload method calls. */
- else if (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype)
- && name != TYPE_IDENTIFIER (basetype)
- && (TREE_CODE (function) != FUNCTION_DECL
- || strncmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)),
- OPERATOR_METHOD_FORMAT,
- OPERATOR_METHOD_LENGTH))
- && (may_be_remote (basetype) || instance != C_C_D))
- {
- tree fn_as_int;
-
- parms = TREE_CHAIN (parms);
-
- if (!all_virtual && TREE_CODE (function) == FUNCTION_DECL)
- fn_as_int = build_unary_op (ADDR_EXPR, function, 0);
- else
- fn_as_int = convert (TREE_TYPE (default_conversion (function)), DECL_VINDEX (function));
- if (all_virtual == 1)
- fn_as_int = convert (integer_type_node, fn_as_int);
-
- result = build_opfncall (METHOD_CALL_EXPR, LOOKUP_NORMAL, instance, fn_as_int, parms);
-
- if (result == NULL_TREE)
- {
- compiler_error ("could not overload `operator->()(...)'");
- return error_mark_node;
- }
- else if (result == error_mark_node)
- return error_mark_node;
-
-#if 0
- /* Do this if we want the result of operator->() to inherit
- the type of the function it is subbing for. */
- TREE_TYPE (result) = value_type;
-#endif
-
- return result;
- }
-#endif
+ if (parms == error_mark_node
+ || (parms && TREE_CHAIN (parms) == error_mark_node))
+ return error_mark_node;
if (need_vtbl == needed)
{
GNU_xref_call (current_function_decl,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)));
- {
- int is_constructor;
-
- if (TREE_CODE (function) == FUNCTION_DECL)
- {
- is_constructor = DECL_CONSTRUCTOR_P (function);
- if (DECL_INLINE (function))
- function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
- else
- {
- assemble_external (function);
- TREE_USED (function) = 1;
- function = default_conversion (function);
- }
- }
- else
- {
- is_constructor = 0;
- function = default_conversion (function);
- }
-
- result = build_nt (CALL_EXPR, function, parms, NULL_TREE);
-
- TREE_TYPE (result) = value_type;
- TREE_SIDE_EFFECTS (result) = 1;
- TREE_RAISES (result)
- = TYPE_RAISES_EXCEPTIONS (fntype) || (parms && TREE_RAISES (parms));
- TREE_HAS_CONSTRUCTOR (result) = is_constructor;
- return result;
- }
+ result = build_call (function, value_type, parms);
+ result = convert_from_reference (result);
+ return result;
}
/* Similar to `build_method_call', but for overloaded non-member functions.
function's new name. */
tree
-build_overload_call_real (fnname, parms, flags, final_cp, buildxxx)
+build_overload_call_real (fnname, parms, flags, final_cp, require_complete)
tree fnname, parms;
int flags;
struct candidate *final_cp;
- int buildxxx;
+ int require_complete;
{
/* must check for overloading here */
- tree overload_name, functions, function, parm;
- tree parmtypes = NULL_TREE, last = NULL_TREE;
+ tree functions, function, parm;
+ tree parmtypes, last;
register tree outer;
int length;
int parmlength = list_length (parms);
final_cp[1].h.code = EVIL_CODE;
}
- for (parm = parms; parm; parm = TREE_CHAIN (parm))
+ parmtypes = default_parm_conversions (parms, &last);
+ if (parmtypes == error_mark_node)
{
- register tree t = TREE_TYPE (TREE_VALUE (parm));
-
- if (t == error_mark_node)
- {
- if (final_cp)
- final_cp->h.code = EVIL_CODE;
- return error_mark_node;
- }
- if (TREE_CODE (t) == ARRAY_TYPE || TREE_CODE (t) == OFFSET_TYPE)
- {
- /* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
- Also convert OFFSET_TYPE entities to their normal selves.
- This eliminates needless calls to `compute_conversion_costs'. */
- TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
- t = TREE_TYPE (TREE_VALUE (parm));
- }
- last = build_tree_list (NULL_TREE, t);
- parmtypes = chainon (parmtypes, last);
+ if (final_cp)
+ final_cp->h.code = EVIL_CODE;
+ return error_mark_node;
}
+
if (last)
TREE_CHAIN (last) = void_list_node;
else
{
candidates
= (struct candidate *)alloca ((length+1) * sizeof (struct candidate));
- bzero (candidates, (length + 1) * sizeof (struct candidate));
+ bzero ((char *) candidates, (length + 1) * sizeof (struct candidate));
}
cp = candidates;
function = outer;
if (TREE_CODE (function) != FUNCTION_DECL
&& ! (TREE_CODE (function) == TEMPLATE_DECL
- && ! DECL_TEMPLATE_IS_CLASS (function)
&& TREE_CODE (DECL_TEMPLATE_RESULT (function)) == FUNCTION_DECL))
{
enum tree_code code = TREE_CODE (function);
TYPE_ARG_TYPES (TREE_TYPE (function)),
parms, &template_cost, 0);
if (i == 0)
- function = instantiate_template (function, targs);
+ {
+ function = instantiate_template (function, targs);
+ if (function == error_mark_node)
+ return function;
+ }
}
if (TREE_CODE (function) == TEMPLATE_DECL)
if (cp - candidates > 1)
{
struct candidate *best_cp
- = ideal_candidate (NULL_TREE, candidates,
- cp - candidates, parms, parmlength);
+ = ideal_candidate (candidates, cp - candidates, parmlength);
if (best_cp == (struct candidate *)0)
{
if (flags & LOOKUP_COMPLAIN)
if (final_cp)
return rval;
- return buildxxx ? build_function_call_real (rval, parms, 0, flags)
- : build_function_call_real (rval, parms, 1, flags);
+ return build_function_call_real (rval, parms, require_complete, flags);
}
if (flags & LOOKUP_SPECULATIVELY)
return error_mark_node;
}
+/* This requires a complete type on the result of the call. */
tree
-build_overload_call (fnname, parms, flags, final_cp)
- tree fnname, parms;
- int flags;
- struct candidate *final_cp;
-{
- return build_overload_call_real (fnname, parms, flags, final_cp, 0);
-}
-
-tree
-build_overload_call_maybe (fnname, parms, flags, final_cp)
+build_overload_call (fnname, parms, flags)
tree fnname, parms;
int flags;
- struct candidate *final_cp;
{
- return build_overload_call_real (fnname, parms, flags, final_cp, 1);
+ return build_overload_call_real (fnname, parms, flags, (struct candidate *)0, 1);
}