#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
#include "output.h"
#include "flags.h"
#include "rtl.h"
#include "toplev.h"
#include "expr.h"
#include "diagnostic.h"
#include "intl.h"
#include "target.h"
#include "convert.h"
typedef enum conversion_kind {
ck_identity,
ck_lvalue,
ck_qual,
ck_std,
ck_ptr,
ck_pmem,
ck_base,
ck_ref_bind,
ck_user,
ck_ambig,
ck_rvalue
} conversion_kind;
typedef enum conversion_rank {
cr_identity,
cr_exact,
cr_promotion,
cr_std,
cr_pbool,
cr_user,
cr_ellipsis,
cr_bad
} conversion_rank;
typedef struct conversion conversion;
struct conversion {
conversion_kind kind;
conversion_rank rank;
BOOL_BITFIELD user_conv_p : 1;
BOOL_BITFIELD ellipsis_p : 1;
BOOL_BITFIELD this_p : 1;
BOOL_BITFIELD bad_p : 1;
BOOL_BITFIELD need_temporary_p : 1;
BOOL_BITFIELD check_copy_constructor_p : 1;
BOOL_BITFIELD base_p : 1;
tree type;
union {
conversion *next;
tree expr;
} u;
struct z_candidate *cand;
};
#define CONVERSION_RANK(NODE) \
((NODE)->bad_p ? cr_bad \
: (NODE)->ellipsis_p ? cr_ellipsis \
: (NODE)->user_conv_p ? cr_user \
: (NODE)->rank)
static struct obstack conversion_obstack;
static bool conversion_obstack_initialized;
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 (conversion *, conversion *);
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, \
true, \
false)
#define convert_like_with_context(CONV, EXPR, FN, ARGNO) \
convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0, \
true, \
false)
static tree convert_like_real (conversion *, tree, tree, int, int, bool,
bool);
static void op_error (enum tree_code, enum tree_code, tree, tree,
tree, const char *);
static tree build_object_call (tree, tree);
static tree resolve_args (tree);
static struct z_candidate *build_user_type_conversion_1 (tree, tree, int);
static void print_z_candidate (const char *, struct z_candidate *);
static void print_z_candidates (struct z_candidate *);
static tree build_this (tree);
static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
static bool any_strictly_viable (struct z_candidate *);
static struct z_candidate *add_template_candidate
(struct z_candidate **, tree, tree, tree, tree, tree,
tree, tree, int, unification_kind_t);
static struct z_candidate *add_template_candidate_real
(struct z_candidate **, tree, tree, tree, tree, tree,
tree, tree, int, tree, unification_kind_t);
static struct z_candidate *add_template_conv_candidate
(struct z_candidate **, tree, tree, tree, tree, tree, tree);
static void add_builtin_candidates
(struct z_candidate **, enum tree_code, enum tree_code,
tree, tree *, int);
static void add_builtin_candidate
(struct z_candidate **, enum tree_code, enum tree_code,
tree, tree, tree, tree *, tree *, int);
static bool is_complete (tree);
static void build_builtin_candidate
(struct z_candidate **, tree, tree, tree, tree *, tree *,
int);
static struct z_candidate *add_conv_candidate
(struct z_candidate **, tree, tree, tree, tree, tree);
static struct z_candidate *add_function_candidate
(struct z_candidate **, tree, tree, tree, tree, tree, int);
static conversion *implicit_conversion (tree, tree, tree, bool, int);
static conversion *standard_conversion (tree, tree, tree, bool, int);
static conversion *reference_binding (tree, tree, tree, bool, int);
static conversion *build_conv (conversion_kind, tree, conversion *);
static bool is_subseq (conversion *, conversion *);
static tree maybe_handle_ref_bind (conversion **);
static void maybe_handle_implicit_object (conversion **);
static struct z_candidate *add_candidate
(struct z_candidate **, tree, tree, size_t,
conversion **, tree, tree, int);
static tree source_type (conversion *);
static void add_warning (struct z_candidate *, struct z_candidate *);
static bool reference_related_p (tree, tree);
static bool reference_compatible_p (tree, tree);
static conversion *convert_class_to_reference (tree, tree, tree);
static conversion *direct_reference_binding (tree, conversion *);
static bool promoted_arithmetic_type_p (tree);
static conversion *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 void add_candidates (tree, tree, tree, bool, tree, tree,
int, struct z_candidate **);
static conversion *merge_conversion_sequences (conversion *, conversion *);
static bool magic_varargs_p (tree);
typedef void (*diagnostic_fn_t) (const char *, ...) ATTRIBUTE_GCC_CXXDIAG(1,2);
static tree build_temp (tree, tree, int, diagnostic_fn_t *);
static void check_constructor_callable (tree, tree);
bool
check_dtor_name (tree basetype, tree name)
{
if (name == error_mark_node)
return true;
if (TREE_CODE (name) == TYPE_DECL)
name = TREE_TYPE (name);
else if (TYPE_P (name))
;
else if (TREE_CODE (name) == IDENTIFIER_NODE)
{
if ((IS_AGGR_TYPE (basetype) && name == constructor_name (basetype))
|| (TREE_CODE (basetype) == ENUMERAL_TYPE
&& name == TYPE_IDENTIFIER (basetype)))
return true;
else
name = get_type_value (name);
}
else
{
gcc_assert (DECL_CLASS_TEMPLATE_P (name));
return false;
}
if (!name)
return false;
return same_type_p (TYPE_MAIN_VARIANT (basetype), TYPE_MAIN_VARIANT (name));
}
tree
build_addr_func (tree function)
{
tree type = TREE_TYPE (function);
if (TREE_CODE (type) == METHOD_TYPE)
{
if (TREE_CODE (function) == OFFSET_REF)
{
tree object = build_address (TREE_OPERAND (function, 0));
return get_member_function_from_ptrfunc (&object,
TREE_OPERAND (function, 1));
}
function = build_address (function);
}
else
function = decay_conversion (function);
return function;
}
tree
build_call (tree function, tree parms)
{
int is_constructor = 0;
int nothrow;
tree tmp;
tree decl;
tree result_type;
tree fntype;
function = build_addr_func (function);
gcc_assert (TYPE_PTR_P (TREE_TYPE (function)));
fntype = TREE_TYPE (TREE_TYPE (function));
gcc_assert (TREE_CODE (fntype) == FUNCTION_TYPE
|| TREE_CODE (fntype) == METHOD_TYPE);
result_type = TREE_TYPE (fntype);
if (TREE_CODE (function) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
{
decl = TREE_OPERAND (function, 0);
if (!TREE_USED (decl))
{
gcc_assert (DECL_ARTIFICIAL (decl)
|| !strncmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
"__", 2));
mark_used (decl);
}
}
else
decl = NULL_TREE;
nothrow = ((decl && TREE_NOTHROW (decl))
|| TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (function))));
if (decl && TREE_THIS_VOLATILE (decl) && cfun)
current_function_returns_abnormally = 1;
if (decl && TREE_DEPRECATED (decl))
warn_deprecated_use (decl);
require_complete_eh_spec_types (fntype, decl);
if (decl && DECL_CONSTRUCTOR_P (decl))
is_constructor = 1;
if (! decl || ! DECL_BUILT_IN (decl))
for (tmp = parms; tmp; tmp = TREE_CHAIN (tmp))
if (is_empty_class (TREE_TYPE (TREE_VALUE (tmp)))
&& ! TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (tmp))))
{
tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (TREE_VALUE (tmp)));
TREE_VALUE (tmp) = build2 (COMPOUND_EXPR, TREE_TYPE (t),
TREE_VALUE (tmp), t);
}
function = build3 (CALL_EXPR, result_type, function, parms, NULL_TREE);
TREE_HAS_CONSTRUCTOR (function) = is_constructor;
TREE_NOTHROW (function) = nothrow;
return function;
}
typedef struct z_candidate z_candidate;
typedef struct candidate_warning candidate_warning;
struct candidate_warning {
z_candidate *loser;
candidate_warning *next;
};
struct z_candidate {
tree fn;
tree args;
conversion **convs;
size_t num_convs;
conversion *second_conv;
int viable;
tree access_path;
tree conversion_path;
tree template_decl;
candidate_warning *warnings;
z_candidate *next;
};
bool
null_ptr_cst_p (tree t)
{
t = integral_constant_value (t);
if (t == null_node)
return true;
if (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)) && integer_zerop (t))
{
STRIP_NOPS (t);
if (!TREE_CONSTANT_OVERFLOW (t))
return true;
}
return false;
}
bool
sufficient_parms_p (tree parmlist)
{
for (; parmlist && parmlist != void_list_node;
parmlist = TREE_CHAIN (parmlist))
if (!TREE_PURPOSE (parmlist))
return false;
return true;
}
static void *
conversion_obstack_alloc (size_t n)
{
void *p;
if (!conversion_obstack_initialized)
{
gcc_obstack_init (&conversion_obstack);
conversion_obstack_initialized = true;
}
p = obstack_alloc (&conversion_obstack, n);
memset (p, 0, n);
return p;
}
static conversion *
alloc_conversion (conversion_kind kind)
{
conversion *c;
c = (conversion *) conversion_obstack_alloc (sizeof (conversion));
c->kind = kind;
return c;
}
#ifdef ENABLE_CHECKING
void
validate_conversion_obstack (void)
{
if (conversion_obstack_initialized)
gcc_assert ((obstack_next_free (&conversion_obstack)
== obstack_base (&conversion_obstack)));
}
#endif
static conversion **
alloc_conversions (size_t n)
{
return (conversion **) conversion_obstack_alloc (n * sizeof (conversion *));
}
static conversion *
build_conv (conversion_kind code, tree type, conversion *from)
{
conversion *t;
conversion_rank rank = CONVERSION_RANK (from);
t = alloc_conversion (code);
t->type = type;
t->u.next = from;
switch (code)
{
case ck_ptr:
case ck_pmem:
case ck_base:
case ck_std:
if (rank < cr_std)
rank = cr_std;
break;
case ck_qual:
if (rank < cr_exact)
rank = cr_exact;
break;
default:
break;
}
t->rank = rank;
t->user_conv_p = (code == ck_user || from->user_conv_p);
t->bad_p = from->bad_p;
t->base_p = false;
return t;
}
static conversion *
build_identity_conv (tree type, tree expr)
{
conversion *c;
c = alloc_conversion (ck_identity);
c->type = type;
c->u.expr = expr;
return c;
}
static conversion *
build_ambiguous_conv (tree type, tree expr)
{
conversion *c;
c = alloc_conversion (ck_ambig);
c->type = type;
c->u.expr = expr;
return c;
}
tree
strip_top_quals (tree t)
{
if (TREE_CODE (t) == ARRAY_TYPE)
return t;
return cp_build_qualified_type (t, 0);
}
static conversion *
standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
int flags)
{
enum tree_code fcode, tcode;
conversion *conv;
bool fromref = false;
to = non_reference (to);
if (TREE_CODE (from) == REFERENCE_TYPE)
{
fromref = true;
from = TREE_TYPE (from);
}
to = strip_top_quals (to);
from = strip_top_quals (from);
if ((TYPE_PTRFN_P (to) || TYPE_PTRMEMFUNC_P (to))
&& expr && type_unknown_p (expr))
{
expr = instantiate_type (to, expr, tf_conv);
if (expr == error_mark_node)
return NULL;
from = TREE_TYPE (expr);
}
fcode = TREE_CODE (from);
tcode = TREE_CODE (to);
conv = build_identity_conv (from, expr);
if (fcode == FUNCTION_TYPE || fcode == ARRAY_TYPE)
{
from = type_decays_to (from);
fcode = TREE_CODE (from);
conv = build_conv (ck_lvalue, from, conv);
}
else if (fromref || (expr && lvalue_p (expr)))
{
if (expr)
{
tree bitfield_type;
bitfield_type = is_bitfield_expr_with_lowered_type (expr);
if (bitfield_type)
{
from = strip_top_quals (bitfield_type);
fcode = TREE_CODE (from);
}
}
conv = build_conv (ck_rvalue, from, conv);
}
if (tcode == COMPLEX_TYPE && fcode == COMPLEX_TYPE)
{
conversion *part_conv = standard_conversion
(TREE_TYPE (to), TREE_TYPE (from), NULL_TREE, c_cast_p, flags);
if (part_conv)
{
conv = build_conv (part_conv->kind, to, conv);
conv->rank = part_conv->rank;
}
else
conv = NULL;
return conv;
}
if (same_type_p (from, to))
return conv;
if ((tcode == POINTER_TYPE || TYPE_PTR_TO_MEMBER_P (to))
&& expr && null_ptr_cst_p (expr))
conv = build_conv (ck_std, to, conv);
else if ((tcode == INTEGER_TYPE && fcode == POINTER_TYPE)
|| (tcode == POINTER_TYPE && fcode == INTEGER_TYPE))
{
conv = build_conv (ck_std, to, conv);
conv->bad_p = true;
}
else if (tcode == ENUMERAL_TYPE && fcode == INTEGER_TYPE)
{
conv = build_conv (ck_std, to, conv);
conv->bad_p = true;
}
else if ((tcode == POINTER_TYPE && fcode == POINTER_TYPE)
|| (TYPE_PTRMEM_P (to) && TYPE_PTRMEM_P (from)))
{
tree to_pointee;
tree from_pointee;
if (tcode == POINTER_TYPE
&& same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (from),
TREE_TYPE (to)))
;
else if (VOID_TYPE_P (TREE_TYPE (to))
&& !TYPE_PTRMEM_P (from)
&& TREE_CODE (TREE_TYPE (from)) != FUNCTION_TYPE)
{
tree nfrom = TREE_TYPE (from);
if (c_dialect_objc ())
nfrom = objc_non_volatilized_type (nfrom);
from = build_pointer_type
(cp_build_qualified_type (void_type_node,
cp_type_quals (nfrom)));
conv = build_conv (ck_ptr, from, conv);
}
else if (TYPE_PTRMEM_P (from))
{
tree fbase = TYPE_PTRMEM_CLASS_TYPE (from);
tree tbase = TYPE_PTRMEM_CLASS_TYPE (to);
if (DERIVED_FROM_P (fbase, tbase)
&& (same_type_ignoring_top_level_qualifiers_p
(TYPE_PTRMEM_POINTED_TO_TYPE (from),
TYPE_PTRMEM_POINTED_TO_TYPE (to))))
{
from = build_ptrmem_type (tbase,
TYPE_PTRMEM_POINTED_TO_TYPE (from));
conv = build_conv (ck_pmem, from, conv);
}
else if (!same_type_p (fbase, tbase))
return NULL;
}
else if (IS_AGGR_TYPE (TREE_TYPE (from))
&& IS_AGGR_TYPE (TREE_TYPE (to))
&& DERIVED_FROM_P (TREE_TYPE (to), TREE_TYPE (from))
&& COMPLETE_TYPE_P (TREE_TYPE (from)))
{
tree fr = c_dialect_objc () ?
objc_non_volatilized_type (TREE_TYPE (from))
: TREE_TYPE (from);
from =
cp_build_qualified_type (TREE_TYPE (to),
cp_type_quals (fr));
from = build_pointer_type (from);
conv = build_conv (ck_ptr, from, conv);
conv->base_p = true;
}
if (tcode == POINTER_TYPE)
{
to_pointee = TREE_TYPE (to);
from_pointee = TREE_TYPE (from);
}
else
{
to_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (to);
from_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (from);
}
if (same_type_p (from, to))
;
else if (c_cast_p && comp_ptr_ttypes_const (to, from))
conv = build_conv (ck_qual, to, conv);
else if (!c_cast_p && comp_ptr_ttypes (to_pointee, from_pointee))
conv = build_conv (ck_qual, to, conv);
else if (expr && string_conv_p (to, expr, 0))
conv = build_conv (ck_qual, to, conv);
else if (c_dialect_objc ()
&& objc_compare_types (to, from, -4, NULL_TREE))
conv = build_conv (ck_ptr, to, conv);
else if (ptr_reasonably_similar (to_pointee, from_pointee))
{
conv = build_conv (ck_ptr, to, conv);
conv->bad_p = true;
}
else
return NULL;
from = to;
}
else if (TYPE_PTRMEMFUNC_P (to) && TYPE_PTRMEMFUNC_P (from))
{
tree fromfn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from));
tree tofn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to));
tree fbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fromfn)));
tree tbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (tofn)));
if (!DERIVED_FROM_P (fbase, tbase)
|| !same_type_p (TREE_TYPE (fromfn), TREE_TYPE (tofn))
|| !compparms (TREE_CHAIN (TYPE_ARG_TYPES (fromfn)),
TREE_CHAIN (TYPE_ARG_TYPES (tofn)))
|| cp_type_quals (fbase) != cp_type_quals (tbase))
return NULL;
from = cp_build_qualified_type (tbase, cp_type_quals (fbase));
from = build_method_type_directly (from,
TREE_TYPE (fromfn),
TREE_CHAIN (TYPE_ARG_TYPES (fromfn)));
from = build_ptrmemfunc_type (build_pointer_type (from));
conv = build_conv (ck_pmem, from, conv);
conv->base_p = true;
}
else if (tcode == BOOLEAN_TYPE)
{
if (ARITHMETIC_TYPE_P (from)
|| fcode == ENUMERAL_TYPE
|| fcode == POINTER_TYPE
|| TYPE_PTR_TO_MEMBER_P (from))
{
conv = build_conv (ck_std, to, conv);
if (fcode == POINTER_TYPE
|| TYPE_PTRMEM_P (from)
|| (TYPE_PTRMEMFUNC_P (from)
&& conv->rank < cr_pbool))
conv->rank = cr_pbool;
return conv;
}
return NULL;
}
else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
|| tcode == REAL_TYPE)
{
if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE))
return NULL;
conv = build_conv (ck_std, to, conv);
if (same_type_p (to, type_promotes_to (from))
&& conv->u.next->rank <= cr_promotion)
conv->rank = cr_promotion;
}
else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
&& vector_types_convertible_p (from, to, false))
return build_conv (ck_std, to, conv);
else if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE)
&& IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
&& is_properly_derived_from (from, to))
{
if (conv->kind == ck_rvalue)
conv = conv->u.next;
conv = build_conv (ck_base, to, conv);
conv->need_temporary_p = true;
}
else
return NULL;
return conv;
}
static bool
reference_related_p (tree t1, tree t2)
{
t1 = TYPE_MAIN_VARIANT (t1);
t2 = TYPE_MAIN_VARIANT (t2);
return (same_type_p (t1, t2)
|| (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2)
&& DERIVED_FROM_P (t1, t2)));
}
static bool
reference_compatible_p (tree t1, tree t2)
{
return (reference_related_p (t1, t2)
&& at_least_as_qualified_p (t1, t2));
}
static conversion *
convert_class_to_reference (tree t, tree s, tree expr)
{
tree conversions;
tree arglist;
conversion *conv;
tree reference_type;
struct z_candidate *candidates;
struct z_candidate *cand;
bool any_viable_p;
conversions = lookup_conversions (s);
if (!conversions)
return NULL;
candidates = 0;
arglist = build_int_cst (build_pointer_type (s), 0);
arglist = build_tree_list (NULL_TREE, arglist);
reference_type = build_reference_type (t);
while (conversions)
{
tree fns = TREE_VALUE (conversions);
for (; fns; fns = OVL_NEXT (fns))
{
tree f = OVL_CURRENT (fns);
tree t2 = TREE_TYPE (TREE_TYPE (f));
cand = NULL;
if (TREE_CODE (f) == TEMPLATE_DECL)
{
cand = add_template_candidate (&candidates,
f, s,
NULL_TREE,
arglist,
reference_type,
TYPE_BINFO (s),
TREE_PURPOSE (conversions),
LOOKUP_NORMAL,
DEDUCE_CONV);
if (cand)
{
f = cand->fn;
t2 = TREE_TYPE (TREE_TYPE (f));
if (TREE_CODE (t2) != REFERENCE_TYPE
|| !reference_compatible_p (t, TREE_TYPE (t2)))
{
candidates = candidates->next;
cand = NULL;
}
}
}
else if (TREE_CODE (t2) == REFERENCE_TYPE
&& reference_compatible_p (t, TREE_TYPE (t2)))
cand = add_function_candidate (&candidates, f, s, arglist,
TYPE_BINFO (s),
TREE_PURPOSE (conversions),
LOOKUP_NORMAL);
if (cand)
{
conversion *identity_conv;
identity_conv
= build_identity_conv (TREE_TYPE (TREE_TYPE
(TREE_TYPE (cand->fn))),
NULL_TREE);
cand->second_conv
= (direct_reference_binding
(reference_type, identity_conv));
cand->second_conv->bad_p |= cand->convs[0]->bad_p;
}
}
conversions = TREE_CHAIN (conversions);
}
candidates = splice_viable (candidates, pedantic, &any_viable_p);
if (!any_viable_p)
return NULL;
cand = tourney (candidates);
if (!cand)
return NULL;
cand->args = tree_cons (NULL_TREE,
build_this (expr),
TREE_CHAIN (cand->args));
conv = build_conv (ck_user,
TREE_TYPE (TREE_TYPE (cand->fn)),
build_identity_conv (TREE_TYPE (expr), expr));
conv->cand = cand;
cand->second_conv = merge_conversion_sequences (conv, cand->second_conv);
if (cand->viable == -1)
conv->bad_p = true;
return cand->second_conv;
}
static conversion *
direct_reference_binding (tree type, conversion *conv)
{
tree t;
gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
gcc_assert (TREE_CODE (conv->type) != REFERENCE_TYPE);
t = TREE_TYPE (type);
if (!same_type_ignoring_top_level_qualifiers_p (t, conv->type))
{
conv = build_conv (ck_base, t, conv);
conv->need_temporary_p = false;
}
return build_conv (ck_ref_bind, type, conv);
}
static conversion *
reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
{
conversion *conv = NULL;
tree to = TREE_TYPE (rto);
tree from = rfrom;
bool related_p;
bool compatible_p;
cp_lvalue_kind lvalue_p = clk_none;
if (TREE_CODE (to) == FUNCTION_TYPE && expr && type_unknown_p (expr))
{
expr = instantiate_type (to, expr, tf_none);
if (expr == error_mark_node)
return NULL;
from = TREE_TYPE (expr);
}
if (TREE_CODE (from) == REFERENCE_TYPE)
{
lvalue_p = clk_ordinary;
from = TREE_TYPE (from);
}
else if (expr)
lvalue_p = real_lvalue_p (expr);
related_p = reference_related_p (to, from);
if (related_p && c_cast_p
&& !at_least_as_qualified_p (to, from))
to = build_qualified_type (to, cp_type_quals (from));
compatible_p = reference_compatible_p (to, from);
if (lvalue_p && compatible_p)
{
conv = build_identity_conv (from, expr);
conv = direct_reference_binding (rto, conv);
if ((lvalue_p & clk_bitfield) != 0
|| ((lvalue_p & clk_packed) != 0 && !TYPE_PACKED (to)))
conv->need_temporary_p = true;
return conv;
}
else if (CLASS_TYPE_P (from) && !(flags & LOOKUP_NO_CONVERSION))
{
conv = convert_class_to_reference (to, from, expr);
if (conv)
return conv;
}
if (flags & LOOKUP_NO_TEMP_BIND)
return NULL;
if (!CP_TYPE_CONST_NON_VOLATILE_P (to))
return NULL;
if (CLASS_TYPE_P (from) && compatible_p)
{
conv = build_identity_conv (from, expr);
conv = direct_reference_binding (rto, conv);
if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE))
conv->u.next->check_copy_constructor_p = true;
return conv;
}
if (related_p && !at_least_as_qualified_p (to, from))
return NULL;
conv = implicit_conversion (to, from, expr, c_cast_p,
flags);
if (!conv)
return NULL;
conv = build_conv (ck_ref_bind, rto, conv);
conv->need_temporary_p = true;
return conv;
}
static conversion *
implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
int flags)
{
conversion *conv;
if (from == error_mark_node || to == error_mark_node
|| expr == error_mark_node)
return NULL;
if (c_dialect_objc ())
from = objc_non_volatilized_type (from);
if (TREE_CODE (to) == REFERENCE_TYPE)
conv = reference_binding (to, from, expr, c_cast_p, flags);
else
conv = standard_conversion (to, from, expr, c_cast_p, flags);
if (conv)
return conv;
if (expr != NULL_TREE
&& (IS_AGGR_TYPE (from)
|| IS_AGGR_TYPE (to))
&& (flags & LOOKUP_NO_CONVERSION) == 0)
{
struct z_candidate *cand;
cand = build_user_type_conversion_1
(to, expr, LOOKUP_ONLYCONVERTING);
if (cand)
conv = cand->second_conv;
return conv;
}
return NULL;
}
static struct z_candidate *
add_candidate (struct z_candidate **candidates,
tree fn, tree args,
size_t num_convs, conversion **convs,
tree access_path, tree conversion_path,
int viable)
{
struct z_candidate *cand = (struct z_candidate *)
conversion_obstack_alloc (sizeof (struct z_candidate));
cand->fn = fn;
cand->args = args;
cand->convs = convs;
cand->num_convs = num_convs;
cand->access_path = access_path;
cand->conversion_path = conversion_path;
cand->viable = viable;
cand->next = *candidates;
*candidates = cand;
return cand;
}
static struct z_candidate *
add_function_candidate (struct z_candidate **candidates,
tree fn, tree ctype, tree arglist,
tree access_path, tree conversion_path,
int flags)
{
tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (fn));
int i, len;
conversion **convs;
tree parmnode, argnode;
tree orig_arglist;
int viable = 1;
gcc_assert (!DECL_ANTICIPATED (fn) || DECL_HIDDEN_FRIEND_P (fn));
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 = alloc_conversions (len);
parmnode = parmlist;
for (i = 0; i < len; ++i)
{
if (parmnode == NULL_TREE || parmnode == void_list_node)
break;
parmnode = TREE_CHAIN (parmnode);
}
if (i < len && parmnode)
viable = 0;
else if (!sufficient_parms_p (parmnode))
viable = 0;
if (! viable)
goto out;
parmnode = parmlist;
argnode = arglist;
for (i = 0; i < len; ++i)
{
tree arg = TREE_VALUE (argnode);
tree argtype = lvalue_type (arg);
conversion *t;
int is_this;
if (parmnode == void_list_node)
break;
is_this = (i == 0 && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
&& ! DECL_CONSTRUCTOR_P (fn));
if (parmnode)
{
tree parmtype = TREE_VALUE (parmnode);
if (ctype && is_this)
{
parmtype
= build_qualified_type (ctype,
TYPE_QUALS (TREE_TYPE (parmtype)));
parmtype = build_pointer_type (parmtype);
}
t = implicit_conversion (parmtype, argtype, arg,
false, flags);
}
else
{
t = build_identity_conv (argtype, arg);
t->ellipsis_p = true;
}
if (t && is_this)
t->this_p = true;
convs[i] = t;
if (! t)
{
viable = 0;
break;
}
if (t->bad_p)
viable = -1;
if (parmnode)
parmnode = TREE_CHAIN (parmnode);
argnode = TREE_CHAIN (argnode);
}
out:
return add_candidate (candidates, fn, orig_arglist, len, convs,
access_path, conversion_path, viable);
}
static struct z_candidate *
add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
tree arglist, tree access_path, tree conversion_path)
{
tree totype = TREE_TYPE (TREE_TYPE (fn));
int i, len, viable, flags;
tree parmlist, parmnode, argnode;
conversion **convs;
for (parmlist = totype; TREE_CODE (parmlist) != FUNCTION_TYPE; )
parmlist = TREE_TYPE (parmlist);
parmlist = TYPE_ARG_TYPES (parmlist);
len = list_length (arglist) + 1;
convs = alloc_conversions (len);
parmnode = parmlist;
argnode = arglist;
viable = 1;
flags = LOOKUP_NORMAL;
if (*candidates && (*candidates)->fn == totype)
return NULL;
for (i = 0; i < len; ++i)
{
tree arg = i == 0 ? obj : TREE_VALUE (argnode);
tree argtype = lvalue_type (arg);
conversion *t;
if (i == 0)
t = implicit_conversion (totype, argtype, arg, false,
flags);
else if (parmnode == void_list_node)
break;
else if (parmnode)
t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg,
false, flags);
else
{
t = build_identity_conv (argtype, arg);
t->ellipsis_p = true;
}
convs[i] = t;
if (! t)
break;
if (t->bad_p)
viable = -1;
if (i == 0)
continue;
if (parmnode)
parmnode = TREE_CHAIN (parmnode);
argnode = TREE_CHAIN (argnode);
}
if (i < len)
viable = 0;
if (!sufficient_parms_p (parmnode))
viable = 0;
return add_candidate (candidates, totype, arglist, len, convs,
access_path, conversion_path, viable);
}
static void
build_builtin_candidate (struct z_candidate **candidates, tree fnname,
tree type1, tree type2, tree *args, tree *argtypes,
int flags)
{
conversion *t;
conversion **convs;
size_t num_convs;
int viable = 1, i;
tree types[2];
types[0] = type1;
types[1] = type2;
num_convs = args[2] ? 3 : (args[1] ? 2 : 1);
convs = alloc_conversions (num_convs);
for (i = 0; i < 2; ++i)
{
if (! args[i])
break;
t = implicit_conversion (types[i], argtypes[i], args[i],
false, flags);
if (! t)
{
viable = 0;
t = build_identity_conv (types[i], NULL_TREE);
}
else if (t->bad_p)
viable = 0;
convs[i] = t;
}
if (args[2])
{
convs[2] = convs[1];
convs[1] = convs[0];
t = implicit_conversion (boolean_type_node, argtypes[2], args[2],
false, flags);
if (t)
convs[0] = t;
else
viable = 0;
}
add_candidate (candidates, fnname, NULL_TREE,
num_convs, convs,
NULL_TREE,
NULL_TREE,
viable);
}
static bool
is_complete (tree t)
{
return COMPLETE_TYPE_P (complete_type (t));
}
static bool
promoted_arithmetic_type_p (tree type)
{
return ((INTEGRAL_TYPE_P (type)
&& same_type_p (type_promotes_to (type), type))
|| TREE_CODE (type) == REAL_TYPE);
}
static void
add_builtin_candidate (struct z_candidate **candidates, enum tree_code code,
enum tree_code code2, tree fnname, tree type1,
tree type2, tree *args, tree *argtypes, int flags)
{
switch (code)
{
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
args[1] = integer_zero_node;
type2 = integer_type_node;
break;
default:
break;
}
switch (code)
{
case POSTDECREMENT_EXPR:
case PREDECREMENT_EXPR:
if (TREE_CODE (type1) == BOOLEAN_TYPE)
return;
case POSTINCREMENT_EXPR:
case PREINCREMENT_EXPR:
if (ARITHMETIC_TYPE_P (type1) || TYPE_PTROB_P (type1))
{
type1 = build_reference_type (type1);
break;
}
return;
case INDIRECT_REF:
if (TREE_CODE (type1) == POINTER_TYPE
&& (TYPE_PTROB_P (type1)
|| TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE))
break;
return;
case UNARY_PLUS_EXPR:
if (TREE_CODE (type1) == POINTER_TYPE)
break;
case NEGATE_EXPR:
if (ARITHMETIC_TYPE_P (type1))
break;
return;
case BIT_NOT_EXPR:
if (INTEGRAL_TYPE_P (type1))
break;
return;
case MEMBER_REF:
if (TREE_CODE (type1) == POINTER_TYPE
&& TYPE_PTR_TO_MEMBER_P (type2))
{
tree c1 = TREE_TYPE (type1);
tree c2 = TYPE_PTRMEM_CLASS_TYPE (type2);
if (IS_AGGR_TYPE (c1) && DERIVED_FROM_P (c2, c1)
&& (TYPE_PTRMEMFUNC_P (type2)
|| is_complete (TYPE_PTRMEM_POINTED_TO_TYPE (type2))))
break;
}
return;
case MINUS_EXPR:
if (TYPE_PTROB_P (type1) && TYPE_PTROB_P (type2))
break;
if (TYPE_PTROB_P (type1) && INTEGRAL_TYPE_P (type2))
{
type2 = ptrdiff_type_node;
break;
}
case MULT_EXPR:
case TRUNC_DIV_EXPR:
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
break;
return;
case EQ_EXPR:
case NE_EXPR:
if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
|| (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2)))
break;
if (TYPE_PTR_TO_MEMBER_P (type1) && null_ptr_cst_p (args[1]))
{
type2 = type1;
break;
}
if (TYPE_PTR_TO_MEMBER_P (type2) && null_ptr_cst_p (args[0]))
{
type1 = type2;
break;
}
case LT_EXPR:
case GT_EXPR:
case LE_EXPR:
case GE_EXPR:
case MAX_EXPR:
case MIN_EXPR:
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
break;
if (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
break;
if (TREE_CODE (type1) == ENUMERAL_TYPE
&& TREE_CODE (type2) == ENUMERAL_TYPE)
break;
if (TYPE_PTR_P (type1)
&& null_ptr_cst_p (args[1])
&& !uses_template_parms (type1))
{
type2 = type1;
break;
}
if (null_ptr_cst_p (args[0])
&& TYPE_PTR_P (type2)
&& !uses_template_parms (type2))
{
type1 = type2;
break;
}
return;
case PLUS_EXPR:
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
break;
case ARRAY_REF:
if (INTEGRAL_TYPE_P (type1) && TYPE_PTROB_P (type2))
{
type1 = ptrdiff_type_node;
break;
}
if (TYPE_PTROB_P (type1) && INTEGRAL_TYPE_P (type2))
{
type2 = ptrdiff_type_node;
break;
}
return;
case TRUNC_MOD_EXPR:
case BIT_AND_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case LSHIFT_EXPR:
case RSHIFT_EXPR:
if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2))
break;
return;
case MODIFY_EXPR:
switch (code2)
{
case PLUS_EXPR:
case MINUS_EXPR:
if (TYPE_PTROB_P (type1) && INTEGRAL_TYPE_P (type2))
{
type2 = ptrdiff_type_node;
break;
}
case MULT_EXPR:
case TRUNC_DIV_EXPR:
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
break;
return;
case TRUNC_MOD_EXPR:
case BIT_AND_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case LSHIFT_EXPR:
case RSHIFT_EXPR:
if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2))
break;
return;
case NOP_EXPR:
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
break;
if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
|| (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
|| (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2))
|| ((TYPE_PTRMEMFUNC_P (type1)
|| TREE_CODE (type1) == POINTER_TYPE)
&& null_ptr_cst_p (args[1])))
{
type2 = type1;
break;
}
return;
default:
gcc_unreachable ();
}
type1 = build_reference_type (type1);
break;
case COND_EXPR:
if (promoted_arithmetic_type_p (type1)
&& promoted_arithmetic_type_p (type2))
break;
if (!(TYPE_PTR_P (type1) || TYPE_PTR_TO_MEMBER_P (type1))
|| !(TYPE_PTR_P (type2) || TYPE_PTR_TO_MEMBER_P (type2)))
return;
break;
default:
gcc_unreachable ();
}
if (type2 && !same_type_p (type1, type2)
&& TREE_CODE (type1) == TREE_CODE (type2)
&& (TREE_CODE (type1) == REFERENCE_TYPE
|| (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
|| (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2))
|| TYPE_PTRMEMFUNC_P (type1)
|| IS_AGGR_TYPE (type1)
|| TREE_CODE (type1) == ENUMERAL_TYPE))
{
build_builtin_candidate
(candidates, fnname, type1, type1, args, argtypes, flags);
build_builtin_candidate
(candidates, fnname, type2, type2, args, argtypes, flags);
return;
}
build_builtin_candidate
(candidates, fnname, type1, type2, args, argtypes, flags);
}
tree
type_decays_to (tree type)
{
if (TREE_CODE (type) == ARRAY_TYPE)
return build_pointer_type (TREE_TYPE (type));
if (TREE_CODE (type) == FUNCTION_TYPE)
return build_pointer_type (type);
return type;
}
static void
add_builtin_candidates (struct z_candidate **candidates, enum tree_code code,
enum tree_code code2, tree fnname, tree *args,
int flags)
{
int ref1, i;
int enum_p = 0;
tree type, argtypes[3];
tree types[2];
for (i = 0; i < 3; ++i)
{
if (args[i])
argtypes[i] = lvalue_type (args[i]);
else
argtypes[i] = NULL_TREE;
}
switch (code)
{
case POSTINCREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case PREDECREMENT_EXPR:
case MODIFY_EXPR:
ref1 = 1;
break;
case TRUTH_NOT_EXPR:
build_builtin_candidate
(candidates, fnname, boolean_type_node,
NULL_TREE, args, argtypes, flags);
return;
case TRUTH_ORIF_EXPR:
case TRUTH_ANDIF_EXPR:
build_builtin_candidate
(candidates, fnname, boolean_type_node,
boolean_type_node, args, argtypes, flags);
return;
case ADDR_EXPR:
case COMPOUND_EXPR:
case COMPONENT_REF:
return;
case COND_EXPR:
case EQ_EXPR:
case NE_EXPR:
case LT_EXPR:
case LE_EXPR:
case GT_EXPR:
case GE_EXPR:
enum_p = 1;
default:
ref1 = 0;
}
types[0] = types[1] = NULL_TREE;
for (i = 0; i < 2; ++i)
{
if (! args[i])
;
else if (IS_AGGR_TYPE (argtypes[i]))
{
tree convs;
if (i == 0 && code == MODIFY_EXPR && code2 == NOP_EXPR)
return;
convs = lookup_conversions (argtypes[i]);
if (code == COND_EXPR)
{
if (real_lvalue_p (args[i]))
types[i] = tree_cons
(NULL_TREE, build_reference_type (argtypes[i]), types[i]);
types[i] = tree_cons
(NULL_TREE, TYPE_MAIN_VARIANT (argtypes[i]), types[i]);
}
else if (! convs)
return;
for (; convs; convs = TREE_CHAIN (convs))
{
type = TREE_TYPE (TREE_TYPE (OVL_CURRENT (TREE_VALUE (convs))));
if (i == 0 && ref1
&& (TREE_CODE (type) != REFERENCE_TYPE
|| CP_TYPE_CONST_P (TREE_TYPE (type))))
continue;
if (code == COND_EXPR && TREE_CODE (type) == REFERENCE_TYPE)
types[i] = tree_cons (NULL_TREE, type, types[i]);
type = non_reference (type);
if (i != 0 || ! ref1)
{
type = TYPE_MAIN_VARIANT (type_decays_to (type));
if (enum_p && TREE_CODE (type) == ENUMERAL_TYPE)
types[i] = tree_cons (NULL_TREE, type, types[i]);
if (INTEGRAL_TYPE_P (type))
type = type_promotes_to (type);
}
if (! value_member (type, types[i]))
types[i] = tree_cons (NULL_TREE, type, types[i]);
}
}
else
{
if (code == COND_EXPR && real_lvalue_p (args[i]))
types[i] = tree_cons
(NULL_TREE, build_reference_type (argtypes[i]), types[i]);
type = non_reference (argtypes[i]);
if (i != 0 || ! ref1)
{
type = TYPE_MAIN_VARIANT (type_decays_to (type));
if (enum_p && TREE_CODE (type) == ENUMERAL_TYPE)
types[i] = tree_cons (NULL_TREE, type, types[i]);
if (INTEGRAL_TYPE_P (type))
type = type_promotes_to (type);
}
types[i] = tree_cons (NULL_TREE, type, types[i]);
}
}
for (; types[0]; types[0] = TREE_CHAIN (types[0]))
{
if (types[1])
for (type = types[1]; type; type = TREE_CHAIN (type))
add_builtin_candidate
(candidates, code, code2, fnname, TREE_VALUE (types[0]),
TREE_VALUE (type), args, argtypes, flags);
else
add_builtin_candidate
(candidates, code, code2, fnname, TREE_VALUE (types[0]),
NULL_TREE, args, argtypes, flags);
}
}
static struct z_candidate*
add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
tree ctype, tree explicit_targs, tree arglist,
tree return_type, tree access_path,
tree conversion_path, int flags, tree obj,
unification_kind_t strict)
{
int ntparms = DECL_NTPARMS (tmpl);
tree targs = make_tree_vec (ntparms);
tree args_without_in_chrg = arglist;
struct z_candidate *cand;
int i;
tree fn;
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tmpl))
args_without_in_chrg = TREE_CHAIN (args_without_in_chrg);
if ((DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (tmpl)
|| DECL_BASE_CONSTRUCTOR_P (tmpl))
&& CLASSTYPE_VBASECLASSES (DECL_CONTEXT (tmpl)))
args_without_in_chrg = TREE_CHAIN (args_without_in_chrg);
i = fn_type_unification (tmpl, explicit_targs, targs,
args_without_in_chrg,
return_type, strict, flags);
if (i != 0)
return NULL;
fn = instantiate_template (tmpl, targs, tf_none);
if (fn == error_mark_node)
return NULL;
if (DECL_CONSTRUCTOR_P (fn) && list_length (arglist) == 2)
{
tree arg_types = FUNCTION_FIRST_USER_PARMTYPE (fn);
if (arg_types && same_type_p (TYPE_MAIN_VARIANT (TREE_VALUE (arg_types)),
ctype))
return NULL;
}
if (obj != NULL_TREE)
cand = add_conv_candidate (candidates, fn, obj, access_path,
conversion_path, arglist);
else
cand = add_function_candidate (candidates, fn, ctype,
arglist, access_path,
conversion_path, flags);
if (DECL_TI_TEMPLATE (fn) != tmpl)
cand->template_decl = tree_cons (tmpl, targs, NULL_TREE);
else
cand->template_decl = DECL_TEMPLATE_INFO (fn);
return cand;
}
static struct z_candidate *
add_template_candidate (struct z_candidate **candidates, tree tmpl, tree ctype,
tree explicit_targs, tree arglist, tree return_type,
tree access_path, tree conversion_path, int flags,
unification_kind_t strict)
{
return
add_template_candidate_real (candidates, tmpl, ctype,
explicit_targs, arglist, return_type,
access_path, conversion_path,
flags, NULL_TREE, strict);
}
static struct z_candidate *
add_template_conv_candidate (struct z_candidate **candidates, tree tmpl,
tree obj, tree arglist, tree return_type,
tree access_path, tree conversion_path)
{
return
add_template_candidate_real (candidates, tmpl, NULL_TREE, NULL_TREE,
arglist, return_type, access_path,
conversion_path, 0, obj, DEDUCE_CONV);
}
static struct z_candidate*
splice_viable (struct z_candidate *cands,
bool strict_p,
bool *any_viable_p)
{
struct z_candidate *viable;
struct z_candidate **last_viable;
struct z_candidate **cand;
viable = NULL;
last_viable = &viable;
*any_viable_p = false;
cand = &cands;
while (*cand)
{
struct z_candidate *c = *cand;
if (strict_p ? c->viable == 1 : c->viable)
{
*last_viable = c;
*cand = c->next;
c->next = NULL;
last_viable = &c->next;
*any_viable_p = true;
}
else
cand = &c->next;
}
return viable ? viable : cands;
}
static bool
any_strictly_viable (struct z_candidate *cands)
{
for (; cands; cands = cands->next)
if (cands->viable == 1)
return true;
return false;
}
static tree
build_this (tree obj)
{
if (processing_template_decl)
return build_address (obj);
return build_unary_op (ADDR_EXPR, obj, 0);
}
static inline int
equal_functions (tree fn1, tree fn2)
{
if (DECL_LOCAL_FUNCTION_P (fn1) || DECL_LOCAL_FUNCTION_P (fn2)
|| DECL_EXTERN_C_FUNCTION_P (fn1))
return decls_match (fn1, fn2);
return fn1 == fn2;
}
static void
print_z_candidate (const char *msgstr, struct z_candidate *candidate)
{
if (TREE_CODE (candidate->fn) == IDENTIFIER_NODE)
{
if (candidate->num_convs == 3)
inform ("%s %D(%T, %T, %T) <built-in>", msgstr, candidate->fn,
candidate->convs[0]->type,
candidate->convs[1]->type,
candidate->convs[2]->type);
else if (candidate->num_convs == 2)
inform ("%s %D(%T, %T) <built-in>", msgstr, candidate->fn,
candidate->convs[0]->type,
candidate->convs[1]->type);
else
inform ("%s %D(%T) <built-in>", msgstr, candidate->fn,
candidate->convs[0]->type);
}
else if (TYPE_P (candidate->fn))
inform ("%s %T <conversion>", msgstr, candidate->fn);
else if (candidate->viable == -1)
inform ("%s %+#D <near match>", msgstr, candidate->fn);
else
inform ("%s %+#D", msgstr, candidate->fn);
}
static void
print_z_candidates (struct z_candidate *candidates)
{
const char *str;
struct z_candidate *cand1;
struct z_candidate **cand2;
for (cand1 = candidates; cand1; cand1 = cand1->next)
{
tree fn = cand1->fn;
if (TREE_CODE (fn) != FUNCTION_DECL)
continue;
cand2 = &cand1->next;
while (*cand2)
{
if (TREE_CODE ((*cand2)->fn) == FUNCTION_DECL
&& equal_functions (fn, (*cand2)->fn))
*cand2 = (*cand2)->next;
else
cand2 = &(*cand2)->next;
}
}
if (!candidates)
return;
str = _("candidates are:");
print_z_candidate (str, candidates);
if (candidates->next)
{
size_t len = gcc_gettext_width (str) + 1;
char *spaces = (char *) alloca (len);
memset (spaces, ' ', len-1);
spaces[len - 1] = '\0';
candidates = candidates->next;
do
{
print_z_candidate (spaces, candidates);
candidates = candidates->next;
}
while (candidates);
}
}
static conversion *
merge_conversion_sequences (conversion *user_seq, conversion *std_seq)
{
conversion **t;
gcc_assert (user_seq->kind == ck_user);
t = &(std_seq);
while ((*t)->kind != ck_identity)
t = &((*t)->u.next);
*t = user_seq;
std_seq->user_conv_p = true;
return std_seq;
}
static struct z_candidate *
build_user_type_conversion_1 (tree totype, tree expr, int flags)
{
struct z_candidate *candidates, *cand;
tree fromtype = TREE_TYPE (expr);
tree ctors = NULL_TREE;
tree conv_fns = NULL_TREE;
conversion *conv = NULL;
tree args = NULL_TREE;
bool any_viable_p;
gcc_assert (!IS_AGGR_TYPE (fromtype) || !IS_AGGR_TYPE (totype)
|| !DERIVED_FROM_P (totype, fromtype));
if (IS_AGGR_TYPE (totype))
ctors = lookup_fnfields (totype, complete_ctor_identifier, 0);
if (IS_AGGR_TYPE (fromtype))
conv_fns = lookup_conversions (fromtype);
candidates = 0;
flags |= LOOKUP_NO_CONVERSION;
if (ctors)
{
tree t;
ctors = BASELINK_FUNCTIONS (ctors);
t = build_int_cst (build_pointer_type (totype), 0);
args = build_tree_list (NULL_TREE, expr);
gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (OVL_CURRENT (ctors))
&& !DECL_HAS_VTT_PARM_P (OVL_CURRENT (ctors)));
args = tree_cons (NULL_TREE, t, args);
}
for (; ctors; ctors = OVL_NEXT (ctors))
{
tree ctor = OVL_CURRENT (ctors);
if (DECL_NONCONVERTING_P (ctor))
continue;
if (TREE_CODE (ctor) == TEMPLATE_DECL)
cand = add_template_candidate (&candidates, ctor, totype,
NULL_TREE, args, NULL_TREE,
TYPE_BINFO (totype),
TYPE_BINFO (totype),
flags,
DEDUCE_CALL);
else
cand = add_function_candidate (&candidates, ctor, totype,
args, TYPE_BINFO (totype),
TYPE_BINFO (totype),
flags);
if (cand)
cand->second_conv = build_identity_conv (totype, NULL_TREE);
}
if (conv_fns)
args = build_tree_list (NULL_TREE, build_this (expr));
for (; conv_fns; conv_fns = TREE_CHAIN (conv_fns))
{
tree fns;
tree conversion_path = TREE_PURPOSE (conv_fns);
int convflags = LOOKUP_NO_CONVERSION;
if (TREE_CODE (totype) == REFERENCE_TYPE)
convflags |= LOOKUP_NO_TEMP_BIND;
for (fns = TREE_VALUE (conv_fns); fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) == TEMPLATE_DECL)
cand = add_template_candidate (&candidates, fn, fromtype,
NULL_TREE,
args, totype,
TYPE_BINFO (fromtype),
conversion_path,
flags,
DEDUCE_CONV);
else
cand = add_function_candidate (&candidates, fn, fromtype,
args,
TYPE_BINFO (fromtype),
conversion_path,
flags);
if (cand)
{
conversion *ics
= implicit_conversion (totype,
TREE_TYPE (TREE_TYPE (cand->fn)),
0,
false, convflags);
cand->second_conv = ics;
if (!ics)
cand->viable = 0;
else if (candidates->viable == 1 && ics->bad_p)
cand->viable = -1;
}
}
}
candidates = splice_viable (candidates, pedantic, &any_viable_p);
if (!any_viable_p)
return NULL;
cand = tourney (candidates);
if (cand == 0)
{
if (flags & LOOKUP_COMPLAIN)
{
error ("conversion from %qT to %qT is ambiguous",
fromtype, totype);
print_z_candidates (candidates);
}
cand = candidates;
cand->second_conv = build_ambiguous_conv (totype, expr);
cand->second_conv->user_conv_p = true;
if (!any_strictly_viable (candidates))
cand->second_conv->bad_p = true;
return cand;
}
conv = build_conv
(ck_user,
(DECL_CONSTRUCTOR_P (cand->fn)
? totype : non_reference (TREE_TYPE (TREE_TYPE (cand->fn)))),
build_identity_conv (TREE_TYPE (expr), expr));
conv->cand = cand;
cand->second_conv = merge_conversion_sequences (conv,
cand->second_conv);
if (cand->viable == -1)
cand->second_conv->bad_p = true;
return cand;
}
tree
build_user_type_conversion (tree totype, tree expr, int flags)
{
struct z_candidate *cand
= build_user_type_conversion_1 (totype, expr, flags);
if (cand)
{
if (cand->second_conv->kind == ck_ambig)
return error_mark_node;
expr = convert_like (cand->second_conv, expr);
return convert_from_reference (expr);
}
return NULL_TREE;
}
static tree
resolve_args (tree args)
{
tree t;
for (t = args; t; t = TREE_CHAIN (t))
{
tree arg = TREE_VALUE (t);
if (error_operand_p (arg))
return error_mark_node;
else if (VOID_TYPE_P (TREE_TYPE (arg)))
{
error ("invalid use of void expression");
return error_mark_node;
}
else if (invalid_nonstatic_memfn_p (arg))
return error_mark_node;
}
return args;
}
static struct z_candidate *
perform_overload_resolution (tree fn,
tree args,
struct z_candidate **candidates,
bool *any_viable_p)
{
struct z_candidate *cand;
tree explicit_targs = NULL_TREE;
int template_only = 0;
*candidates = NULL;
*any_viable_p = true;
gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
|| TREE_CODE (fn) == TEMPLATE_DECL
|| TREE_CODE (fn) == OVERLOAD
|| TREE_CODE (fn) == TEMPLATE_ID_EXPR);
gcc_assert (!args || TREE_CODE (args) == TREE_LIST);
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
{
explicit_targs = TREE_OPERAND (fn, 1);
fn = TREE_OPERAND (fn, 0);
template_only = 1;
}
add_candidates (fn, args, explicit_targs, template_only,
NULL_TREE,
NULL_TREE,
LOOKUP_NORMAL,
candidates);
*candidates = splice_viable (*candidates, pedantic, any_viable_p);
if (!*any_viable_p)
return NULL;
cand = tourney (*candidates);
return cand;
}
tree
build_new_function_call (tree fn, tree args, bool koenig_p)
{
struct z_candidate *candidates, *cand;
bool any_viable_p;
void *p;
tree result;
args = resolve_args (args);
if (args == error_mark_node)
return error_mark_node;
if (!koenig_p)
{
tree orig_fn = fn;
fn = remove_hidden_names (fn);
if (!fn)
{
error ("no matching function for call to %<%D(%A)%>",
DECL_NAME (OVL_CURRENT (orig_fn)), args);
return error_mark_node;
}
}
p = conversion_obstack_alloc (0);
cand = perform_overload_resolution (fn, args, &candidates, &any_viable_p);
if (!cand)
{
if (!any_viable_p && candidates && ! candidates->next)
return build_function_call (candidates->fn, args);
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
fn = TREE_OPERAND (fn, 0);
if (!any_viable_p)
error ("no matching function for call to %<%D(%A)%>",
DECL_NAME (OVL_CURRENT (fn)), args);
else
error ("call of overloaded %<%D(%A)%> is ambiguous",
DECL_NAME (OVL_CURRENT (fn)), args);
if (candidates)
print_z_candidates (candidates);
result = error_mark_node;
}
else
result = build_over_call (cand, LOOKUP_NORMAL);
obstack_free (&conversion_obstack, p);
return result;
}
tree
build_operator_new_call (tree fnname, tree args,
tree *size, tree *cookie_size,
tree *fn)
{
tree fns;
struct z_candidate *candidates;
struct z_candidate *cand;
bool any_viable_p;
if (fn)
*fn = NULL_TREE;
args = tree_cons (NULL_TREE, *size, args);
args = resolve_args (args);
if (args == error_mark_node)
return args;
fns = lookup_function_nonclass (fnname, args, false);
cand = perform_overload_resolution (fns, args, &candidates, &any_viable_p);
if (!cand)
{
if (!any_viable_p)
error ("no matching function for call to %<%D(%A)%>",
DECL_NAME (OVL_CURRENT (fns)), args);
else
error ("call of overloaded %<%D(%A)%> is ambiguous",
DECL_NAME (OVL_CURRENT (fns)), args);
if (candidates)
print_z_candidates (candidates);
return error_mark_node;
}
if (*cookie_size)
{
bool use_cookie = true;
if (!abi_version_at_least (2))
{
tree placement = TREE_CHAIN (args);
if (placement && !TREE_CHAIN (placement)
&& same_type_p (TREE_TYPE (TREE_VALUE (placement)),
ptr_type_node))
use_cookie = false;
}
else
{
tree arg_types;
arg_types = TYPE_ARG_TYPES (TREE_TYPE (cand->fn));
arg_types = TREE_CHAIN (arg_types);
if (arg_types
&& TREE_CHAIN (arg_types) == void_list_node
&& same_type_p (TREE_VALUE (arg_types),
ptr_type_node))
use_cookie = false;
}
if (use_cookie)
{
*size = size_binop (PLUS_EXPR, *size, *cookie_size);
TREE_VALUE (args) = *size;
}
else
*cookie_size = NULL_TREE;
}
if (fn)
*fn = cand->fn;
return build_over_call (cand, LOOKUP_NORMAL);
}
static tree
build_object_call (tree obj, tree args)
{
struct z_candidate *candidates = 0, *cand;
tree fns, convs, mem_args = NULL_TREE;
tree type = TREE_TYPE (obj);
bool any_viable_p;
tree result = NULL_TREE;
void *p;
if (TYPE_PTRMEMFUNC_P (type))
{
error ("pointer-to-member function %E cannot be called without an object; consider using .* or ->*", obj);
return error_mark_node;
}
if (TYPE_BINFO (type))
{
fns = lookup_fnfields (TYPE_BINFO (type), ansi_opname (CALL_EXPR), 1);
if (fns == error_mark_node)
return error_mark_node;
}
else
fns = NULL_TREE;
args = resolve_args (args);
if (args == error_mark_node)
return error_mark_node;
p = conversion_obstack_alloc (0);
if (fns)
{
tree base = BINFO_TYPE (BASELINK_BINFO (fns));
mem_args = tree_cons (NULL_TREE, build_this (obj), args);
for (fns = BASELINK_FUNCTIONS (fns); fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) == TEMPLATE_DECL)
add_template_candidate (&candidates, fn, base, NULL_TREE,
mem_args, NULL_TREE,
TYPE_BINFO (type),
TYPE_BINFO (type),
LOOKUP_NORMAL, DEDUCE_CALL);
else
add_function_candidate
(&candidates, fn, base, mem_args, TYPE_BINFO (type),
TYPE_BINFO (type), LOOKUP_NORMAL);
}
}
convs = lookup_conversions (type);
for (; convs; convs = TREE_CHAIN (convs))
{
tree fns = TREE_VALUE (convs);
tree totype = TREE_TYPE (TREE_TYPE (OVL_CURRENT (fns)));
if ((TREE_CODE (totype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
|| (TREE_CODE (totype) == REFERENCE_TYPE
&& TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
|| (TREE_CODE (totype) == REFERENCE_TYPE
&& TREE_CODE (TREE_TYPE (totype)) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (totype))) == FUNCTION_TYPE))
for (; fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) == TEMPLATE_DECL)
add_template_conv_candidate
(&candidates, fn, obj, args, totype,
NULL_TREE,
NULL_TREE);
else
add_conv_candidate (&candidates, fn, obj, args,
NULL_TREE,
NULL_TREE);
}
}
candidates = splice_viable (candidates, pedantic, &any_viable_p);
if (!any_viable_p)
{
error ("no match for call to %<(%T) (%A)%>", TREE_TYPE (obj), args);
print_z_candidates (candidates);
result = error_mark_node;
}
else
{
cand = tourney (candidates);
if (cand == 0)
{
error ("call of %<(%T) (%A)%> is ambiguous", TREE_TYPE (obj), args);
print_z_candidates (candidates);
result = error_mark_node;
}
else if (TREE_CODE (cand->fn) == FUNCTION_DECL
&& DECL_OVERLOADED_OPERATOR_P (cand->fn) == CALL_EXPR)
result = build_over_call (cand, LOOKUP_NORMAL);
else
{
obj = convert_like_with_context (cand->convs[0], obj, cand->fn, -1);
obj = convert_from_reference (obj);
result = build_function_call (obj, args);
}
}
obstack_free (&conversion_obstack, p);
return result;
}
static void
op_error (enum tree_code code, enum tree_code code2,
tree arg1, tree arg2, tree arg3, const char *problem)
{
const char *opname;
if (code == MODIFY_EXPR)
opname = assignment_operator_name_info[code2].name;
else
opname = operator_name_info[code].name;
switch (code)
{
case COND_EXPR:
error ("%s for ternary %<operator?:%> in %<%E ? %E : %E%>",
problem, arg1, arg2, arg3);
break;
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
error ("%s for %<operator%s%> in %<%E%s%>", problem, opname, arg1, opname);
break;
case ARRAY_REF:
error ("%s for %<operator[]%> in %<%E[%E]%>", problem, arg1, arg2);
break;
case REALPART_EXPR:
case IMAGPART_EXPR:
error ("%s for %qs in %<%s %E%>", problem, opname, opname, arg1);
break;
default:
if (arg2)
error ("%s for %<operator%s%> in %<%E %s %E%>",
problem, opname, arg1, opname, arg2);
else
error ("%s for %<operator%s%> in %<%s%E%>",
problem, opname, opname, arg1);
break;
}
}
static conversion *
conditional_conversion (tree e1, tree e2)
{
tree t1 = non_reference (TREE_TYPE (e1));
tree t2 = non_reference (TREE_TYPE (e2));
conversion *conv;
bool good_base;
if (real_lvalue_p (e2))
{
conv = implicit_conversion (build_reference_type (t2),
t1,
e1,
false,
LOOKUP_NO_TEMP_BIND);
if (conv)
return conv;
}
if (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2)
&& ((good_base = DERIVED_FROM_P (t2, t1)) || DERIVED_FROM_P (t1, t2)))
{
if (good_base && at_least_as_qualified_p (t2, t1))
{
conv = build_identity_conv (t1, e1);
if (!same_type_p (TYPE_MAIN_VARIANT (t1),
TYPE_MAIN_VARIANT (t2)))
conv = build_conv (ck_base, t2, conv);
else
conv = build_conv (ck_rvalue, t2, conv);
return conv;
}
else
return NULL;
}
else
return implicit_conversion (t2, t1, e1, false,
LOOKUP_NORMAL);
}
tree
build_conditional_expr (tree arg1, tree arg2, tree arg3)
{
tree arg2_type;
tree arg3_type;
tree result = NULL_TREE;
tree result_type = NULL_TREE;
bool lvalue_p = true;
struct z_candidate *candidates = 0;
struct z_candidate *cand;
void *p;
if (!arg2)
{
if (pedantic)
pedwarn ("ISO C++ forbids omitting the middle term of a ?: expression");
if (real_lvalue_p (arg1))
arg2 = arg1 = stabilize_reference (arg1);
else
arg2 = arg1 = save_expr (arg1);
}
arg1 = perform_implicit_conversion (boolean_type_node, arg1);
if (error_operand_p (arg1)
|| error_operand_p (arg2)
|| error_operand_p (arg3))
return error_mark_node;
arg2_type = unlowered_expr_type (arg2);
arg3_type = unlowered_expr_type (arg3);
if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type))
{
if (!VOID_TYPE_P (arg2_type))
arg2 = decay_conversion (arg2);
if (!VOID_TYPE_P (arg3_type))
arg3 = decay_conversion (arg3);
arg2_type = TREE_TYPE (arg2);
arg3_type = TREE_TYPE (arg3);
if (TREE_CODE (arg2) == THROW_EXPR
&& TREE_CODE (arg3) != THROW_EXPR)
{
if (!VOID_TYPE_P (arg3_type))
arg3 = force_rvalue (arg3);
arg3_type = TREE_TYPE (arg3);
result_type = arg3_type;
}
else if (TREE_CODE (arg2) != THROW_EXPR
&& TREE_CODE (arg3) == THROW_EXPR)
{
if (!VOID_TYPE_P (arg2_type))
arg2 = force_rvalue (arg2);
arg2_type = TREE_TYPE (arg2);
result_type = arg2_type;
}
else if (VOID_TYPE_P (arg2_type) && VOID_TYPE_P (arg3_type))
result_type = void_type_node;
else
{
error ("%qE has type %<void%> and is not a throw-expression",
VOID_TYPE_P (arg2_type) ? arg2 : arg3);
return error_mark_node;
}
lvalue_p = false;
goto valid_operands;
}
else if (!same_type_p (arg2_type, arg3_type)
&& (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)))
{
conversion *conv2;
conversion *conv3;
p = conversion_obstack_alloc (0);
conv2 = conditional_conversion (arg2, arg3);
conv3 = conditional_conversion (arg3, arg2);
if ((conv2 && !conv2->bad_p
&& conv3 && !conv3->bad_p)
|| (conv2 && conv2->kind == ck_ambig)
|| (conv3 && conv3->kind == ck_ambig))
{
error ("operands to ?: have different types %qT and %qT",
arg2_type, arg3_type);
result = error_mark_node;
}
else if (conv2 && (!conv2->bad_p || !conv3))
{
arg2 = convert_like (conv2, arg2);
arg2 = convert_from_reference (arg2);
arg2_type = TREE_TYPE (arg2);
if (error_operand_p (arg2))
result = error_mark_node;
}
else if (conv3 && (!conv3->bad_p || !conv2))
{
arg3 = convert_like (conv3, arg3);
arg3 = convert_from_reference (arg3);
arg3_type = TREE_TYPE (arg3);
if (error_operand_p (arg3))
result = error_mark_node;
}
obstack_free (&conversion_obstack, p);
if (result)
return result;
if ((conv2 || conv3)
&& CLASS_TYPE_P (arg2_type)
&& TYPE_QUALS (arg2_type) != TYPE_QUALS (arg3_type))
arg2_type = arg3_type =
cp_build_qualified_type (arg2_type,
TYPE_QUALS (arg2_type)
| TYPE_QUALS (arg3_type));
}
if (real_lvalue_p (arg2)
&& real_lvalue_p (arg3)
&& same_type_p (arg2_type, arg3_type))
{
result_type = arg2_type;
goto valid_operands;
}
lvalue_p = false;
if (!same_type_p (arg2_type, arg3_type)
&& (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)))
{
tree args[3];
conversion *conv;
bool any_viable_p;
args[0] = arg2;
args[1] = arg3;
args[2] = arg1;
add_builtin_candidates (&candidates,
COND_EXPR,
NOP_EXPR,
ansi_opname (COND_EXPR),
args,
LOOKUP_NORMAL);
candidates = splice_viable (candidates, pedantic, &any_viable_p);
if (!any_viable_p)
{
op_error (COND_EXPR, NOP_EXPR, arg1, arg2, arg3, "no match");
print_z_candidates (candidates);
return error_mark_node;
}
cand = tourney (candidates);
if (!cand)
{
op_error (COND_EXPR, NOP_EXPR, arg1, arg2, arg3, "no match");
print_z_candidates (candidates);
return error_mark_node;
}
conv = cand->convs[0];
arg1 = convert_like (conv, arg1);
conv = cand->convs[1];
arg2 = convert_like (conv, arg2);
conv = cand->convs[2];
arg3 = convert_like (conv, arg3);
}
arg2 = force_rvalue (arg2);
if (!CLASS_TYPE_P (arg2_type))
arg2_type = TREE_TYPE (arg2);
arg3 = force_rvalue (arg3);
if (!CLASS_TYPE_P (arg2_type))
arg3_type = TREE_TYPE (arg3);
if (arg2 == error_mark_node || arg3 == error_mark_node)
return error_mark_node;
if (same_type_p (arg2_type, arg3_type))
result_type = arg2_type;
else if ((ARITHMETIC_TYPE_P (arg2_type)
|| TREE_CODE (arg2_type) == ENUMERAL_TYPE)
&& (ARITHMETIC_TYPE_P (arg3_type)
|| TREE_CODE (arg3_type) == ENUMERAL_TYPE))
{
result_type = type_after_usual_arithmetic_conversions (arg2_type,
arg3_type);
if (TREE_CODE (arg2_type) == ENUMERAL_TYPE
&& TREE_CODE (arg3_type) == ENUMERAL_TYPE)
warning (0, "enumeral mismatch in conditional expression: %qT vs %qT",
arg2_type, arg3_type);
else if (extra_warnings
&& ((TREE_CODE (arg2_type) == ENUMERAL_TYPE
&& !same_type_p (arg3_type, type_promotes_to (arg2_type)))
|| (TREE_CODE (arg3_type) == ENUMERAL_TYPE
&& !same_type_p (arg2_type, type_promotes_to (arg3_type)))))
warning (0, "enumeral and non-enumeral type in conditional expression");
arg2 = perform_implicit_conversion (result_type, arg2);
arg3 = perform_implicit_conversion (result_type, arg3);
}
else if ((null_ptr_cst_p (arg2)
&& (TYPE_PTR_P (arg3_type) || TYPE_PTR_TO_MEMBER_P (arg3_type)))
|| (null_ptr_cst_p (arg3)
&& (TYPE_PTR_P (arg2_type) || TYPE_PTR_TO_MEMBER_P (arg2_type)))
|| (TYPE_PTR_P (arg2_type) && TYPE_PTR_P (arg3_type))
|| (TYPE_PTRMEM_P (arg2_type) && TYPE_PTRMEM_P (arg3_type))
|| (TYPE_PTRMEMFUNC_P (arg2_type) && TYPE_PTRMEMFUNC_P (arg3_type)))
{
result_type = composite_pointer_type (arg2_type, arg3_type, arg2,
arg3, "conditional expression");
if (result_type == error_mark_node)
return error_mark_node;
arg2 = perform_implicit_conversion (result_type, arg2);
arg3 = perform_implicit_conversion (result_type, arg3);
}
if (!result_type)
{
error ("operands to ?: have different types %qT and %qT",
arg2_type, arg3_type);
return error_mark_node;
}
valid_operands:
result = fold_if_not_in_template (build3 (COND_EXPR, result_type, arg1,
arg2, arg3));
if (!lvalue_p)
{
if (CLASS_TYPE_P (TREE_TYPE (result)))
result = get_target_expr (result);
result = rvalue (result);
}
return result;
}
static tree
prep_operand (tree operand)
{
if (operand)
{
if (CLASS_TYPE_P (TREE_TYPE (operand))
&& CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (operand)))
instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (operand)));
}
return operand;
}
static void
add_candidates (tree fns, tree args,
tree explicit_targs, bool template_only,
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;
non_static_args = NULL_TREE;
while (fns)
{
tree fn;
tree fn_args;
fn = OVL_CURRENT (fns);
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
{
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
fn_args = args;
if (TREE_CODE (fn) == TEMPLATE_DECL)
add_template_candidate (candidates,
fn,
ctype,
explicit_targs,
fn_args,
NULL_TREE,
access_path,
conversion_path,
flags,
DEDUCE_CALL);
else if (!template_only)
add_function_candidate (candidates,
fn,
ctype,
fn_args,
access_path,
conversion_path,
flags);
fns = OVL_NEXT (fns);
}
}
tree
build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
bool *overloaded_p)
{
struct z_candidate *candidates = 0, *cand;
tree arglist, fnname;
tree args[3];
tree result = NULL_TREE;
bool result_valid_p = false;
enum tree_code code2 = NOP_EXPR;
conversion *conv;
void *p;
bool strict_p;
bool any_viable_p;
if (error_operand_p (arg1)
|| error_operand_p (arg2)
|| error_operand_p (arg3))
return error_mark_node;
if (code == MODIFY_EXPR)
{
code2 = TREE_CODE (arg3);
arg3 = NULL_TREE;
fnname = ansi_assopname (code2);
}
else
fnname = ansi_opname (code);
arg1 = prep_operand (arg1);
switch (code)
{
case NEW_EXPR:
case VEC_NEW_EXPR:
case VEC_DELETE_EXPR:
case DELETE_EXPR:
gcc_unreachable ();
case CALL_EXPR:
return build_object_call (arg1, arg2);
default:
break;
}
arg2 = prep_operand (arg2);
arg3 = prep_operand (arg3);
if (code == COND_EXPR)
{
if (arg2 == NULL_TREE
|| TREE_CODE (TREE_TYPE (arg2)) == VOID_TYPE
|| TREE_CODE (TREE_TYPE (arg3)) == VOID_TYPE
|| (! IS_OVERLOAD_TYPE (TREE_TYPE (arg2))
&& ! IS_OVERLOAD_TYPE (TREE_TYPE (arg3))))
goto builtin;
}
else if (! IS_OVERLOAD_TYPE (TREE_TYPE (arg1))
&& (! arg2 || ! IS_OVERLOAD_TYPE (TREE_TYPE (arg2))))
goto builtin;
if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
arg2 = integer_zero_node;
arglist = NULL_TREE;
if (arg3)
arglist = tree_cons (NULL_TREE, arg3, arglist);
if (arg2)
arglist = tree_cons (NULL_TREE, arg2, arglist);
arglist = tree_cons (NULL_TREE, arg1, arglist);
p = conversion_obstack_alloc (0);
add_candidates (lookup_function_nonclass (fnname, arglist, true),
arglist, NULL_TREE, false, NULL_TREE, NULL_TREE,
flags, &candidates);
if (CLASS_TYPE_P (TREE_TYPE (arg1)))
{
tree fns;
fns = lookup_fnfields (TREE_TYPE (arg1), fnname, 1);
if (fns == error_mark_node)
{
result = error_mark_node;
goto user_defined_result_ready;
}
if (fns)
add_candidates (BASELINK_FUNCTIONS (fns), arglist,
NULL_TREE, false,
BASELINK_BINFO (fns),
TYPE_BINFO (TREE_TYPE (arg1)),
flags, &candidates);
}
if (code == COND_EXPR)
{
args[0] = arg2;
args[1] = arg3;
args[2] = arg1;
}
else
{
args[0] = arg1;
args[1] = arg2;
args[2] = NULL_TREE;
}
add_builtin_candidates (&candidates, code, code2, fnname, args, flags);
switch (code)
{
case COMPOUND_EXPR:
case ADDR_EXPR:
strict_p = true;
break;
default:
strict_p = pedantic;
break;
}
candidates = splice_viable (candidates, strict_p, &any_viable_p);
if (!any_viable_p)
{
switch (code)
{
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
if (flags & LOOKUP_COMPLAIN)
pedwarn ("no %<%D(int)%> declared for postfix %qs, "
"trying prefix operator instead",
fnname,
operator_name_info[code].name);
if (code == POSTINCREMENT_EXPR)
code = PREINCREMENT_EXPR;
else
code = PREDECREMENT_EXPR;
result = build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE,
overloaded_p);
break;
case ADDR_EXPR:
case COMPOUND_EXPR:
case COMPONENT_REF:
result = NULL_TREE;
result_valid_p = true;
break;
default:
if (flags & LOOKUP_COMPLAIN)
{
op_error (code, code2, arg1, arg2, arg3, "no match");
print_z_candidates (candidates);
}
result = error_mark_node;
break;
}
}
else
{
cand = tourney (candidates);
if (cand == 0)
{
if (flags & LOOKUP_COMPLAIN)
{
op_error (code, code2, arg1, arg2, arg3, "ambiguous overload");
print_z_candidates (candidates);
}
result = error_mark_node;
}
else if (TREE_CODE (cand->fn) == FUNCTION_DECL)
{
if (overloaded_p)
*overloaded_p = true;
result = build_over_call (cand, LOOKUP_NORMAL);
}
else
{
if (cand->warnings)
{
struct candidate_warning *w;
for (w = cand->warnings; w; w = w->next)
joust (cand, w->loser, 1);
}
switch (code)
{
case GT_EXPR:
case LT_EXPR:
case GE_EXPR:
case LE_EXPR:
case EQ_EXPR:
case NE_EXPR:
if (TREE_CODE (TREE_TYPE (arg1)) == ENUMERAL_TYPE
&& TREE_CODE (TREE_TYPE (arg2)) == ENUMERAL_TYPE
&& (TYPE_MAIN_VARIANT (TREE_TYPE (arg1))
!= TYPE_MAIN_VARIANT (TREE_TYPE (arg2))))
{
warning (0, "comparison between %q#T and %q#T",
TREE_TYPE (arg1), TREE_TYPE (arg2));
}
break;
default:
break;
}
conv = cand->convs[0];
if (conv->kind == ck_ref_bind)
conv = conv->u.next;
arg1 = convert_like (conv, arg1);
if (arg2)
{
conv = cand->convs[1];
if (conv->kind == ck_ref_bind)
conv = conv->u.next;
arg2 = convert_like (conv, arg2);
}
if (arg3)
{
conv = cand->convs[2];
if (conv->kind == ck_ref_bind)
conv = conv->u.next;
arg3 = convert_like (conv, arg3);
}
}
}
user_defined_result_ready:
obstack_free (&conversion_obstack, p);
if (result || result_valid_p)
return result;
builtin:
switch (code)
{
case MODIFY_EXPR:
return build_modify_expr (arg1, code2, arg2);
case INDIRECT_REF:
return build_indirect_ref (arg1, "unary *");
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
case TRUNC_DIV_EXPR:
case GT_EXPR:
case LT_EXPR:
case GE_EXPR:
case LE_EXPR:
case EQ_EXPR:
case NE_EXPR:
case MAX_EXPR:
case MIN_EXPR:
case LSHIFT_EXPR:
case RSHIFT_EXPR:
case TRUNC_MOD_EXPR:
case BIT_AND_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
return cp_build_binary_op (code, arg1, arg2);
case UNARY_PLUS_EXPR:
case NEGATE_EXPR:
case BIT_NOT_EXPR:
case TRUTH_NOT_EXPR:
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
return build_unary_op (code, arg1, candidates != 0);
case ARRAY_REF:
return build_array_ref (arg1, arg2);
case COND_EXPR:
return build_conditional_expr (arg1, arg2, arg3);
case MEMBER_REF:
return build_m_component_ref (build_indirect_ref (arg1, NULL), arg2);
case ADDR_EXPR:
case COMPONENT_REF:
case COMPOUND_EXPR:
return NULL_TREE;
default:
gcc_unreachable ();
}
return NULL_TREE;
}
tree
build_op_delete_call (enum tree_code code, tree addr, tree size,
bool global_p, tree placement,
tree alloc_fn)
{
tree fn = NULL_TREE;
tree fns, fnname, argtypes, args, type;
int pass;
if (addr == error_mark_node)
return error_mark_node;
type = strip_array_types (TREE_TYPE (TREE_TYPE (addr)));
fnname = ansi_opname (code);
if (CLASS_TYPE_P (type)
&& COMPLETE_TYPE_P (complete_type (type))
&& !global_p)
{
fns = lookup_fnfields (TYPE_BINFO (type), fnname, 1);
if (fns == error_mark_node)
return error_mark_node;
}
else
fns = NULL_TREE;
if (fns == NULL_TREE)
fns = lookup_name_nonclass (fnname);
if (placement)
{
gcc_assert (alloc_fn != NULL_TREE);
argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn)));
args = TREE_CHAIN (TREE_OPERAND (placement, 1));
}
else
{
argtypes = void_list_node;
args = NULL_TREE;
}
addr = cp_convert (ptr_type_node, addr);
for (pass = 0; pass < (placement ? 1 : 2); ++pass)
{
for (fn = BASELINK_P (fns) ? BASELINK_FUNCTIONS (fns) : fns;
fn;
fn = OVL_NEXT (fn))
{
tree t;
t = TYPE_ARG_TYPES (TREE_TYPE (OVL_CURRENT (fn)));
if (!same_type_p (TREE_VALUE (t), ptr_type_node))
continue;
t = TREE_CHAIN (t);
if (pass == 0)
{
tree a = argtypes;
while (a && t)
{
if (!same_type_p (TREE_VALUE (a), TREE_VALUE (t)))
break;
a = TREE_CHAIN (a);
t = TREE_CHAIN (t);
}
if (!a && !t)
break;
}
else if (pass == 1
&& t
&& same_type_p (TREE_VALUE (t), sizetype)
&& TREE_CHAIN (t) == void_list_node)
break;
}
if (fn)
break;
}
if (fn)
{
fn = OVL_CURRENT (fn);
if (DECL_CLASS_SCOPE_P (fn))
perform_or_defer_access_check (TYPE_BINFO (type), fn, fn);
if (pass == 0)
args = tree_cons (NULL_TREE, addr, args);
else
args = tree_cons (NULL_TREE, addr,
build_tree_list (NULL_TREE, size));
if (placement)
{
mark_used (fn);
return build_cxx_call (fn, args);
}
else
return build_function_call (fn, args);
}
if (alloc_fn)
{
if (!placement)
warning (0, "no corresponding deallocation function for `%D'",
alloc_fn);
return NULL_TREE;
}
error ("no suitable %<operator %s%> for %qT",
operator_name_info[(int)code].name, type);
return error_mark_node;
}
bool
enforce_access (tree basetype_path, tree decl, tree diag_decl)
{
gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
if (!accessible_p (basetype_path, decl, true))
{
if (TREE_PRIVATE (decl))
error ("%q+#D is private", diag_decl);
else if (TREE_PROTECTED (decl))
error ("%q+#D is protected", diag_decl);
else
error ("%q+#D is inaccessible", diag_decl);
error ("within this context");
return false;
}
return true;
}
static int really_call_constructor_p (tree, tree, tree);
static int
really_call_constructor_p (tree expr, tree convfn, tree totype)
{
if (0
&& TREE_CODE (expr) == INDIRECT_REF
&& TREE_CODE (TREE_TYPE (convfn)) == METHOD_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (convfn))) == REFERENCE_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_TYPE (convfn)))) == RECORD_TYPE
&& TREE_TYPE (TREE_TYPE (TREE_TYPE (convfn))) == totype
&& TREE_TYPE (expr) == totype)
return 0;
return 1;
}
static void
check_constructor_callable (tree type, tree expr)
{
build_special_member_call (NULL_TREE,
complete_ctor_identifier,
build_tree_list (NULL_TREE, expr),
type,
LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING
| LOOKUP_NO_CONVERSION
| LOOKUP_CONSTRUCTOR_CALLABLE);
}
static tree
build_temp (tree expr, tree type, int flags,
diagnostic_fn_t *diagnostic_fn)
{
int savew, savee;
savew = warningcount, savee = errorcount;
expr = build_special_member_call (NULL_TREE,
complete_ctor_identifier,
build_tree_list (NULL_TREE, expr),
type, flags);
if (warningcount > savew)
*diagnostic_fn = warning0;
else if (errorcount > savee)
*diagnostic_fn = error;
else
*diagnostic_fn = NULL;
return expr;
}
static tree
convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
int inner, bool issue_conversion_warnings,
bool c_cast_p)
{
tree totype = convs->type;
diagnostic_fn_t diagnostic_fn;
if (convs->bad_p
&& convs->kind != ck_user
&& convs->kind != ck_ambig
&& convs->kind != ck_ref_bind)
{
conversion *t = convs;
for (; t; t = convs->u.next)
{
if (t->kind == ck_user || !t->bad_p)
{
expr = convert_like_real (t, expr, fn, argnum, 1,
false,
false);
break;
}
else if (t->kind == ck_ambig)
return convert_like_real (t, expr, fn, argnum, 1,
false,
false);
else if (t->kind == ck_identity)
break;
}
pedwarn ("invalid conversion from %qT to %qT", TREE_TYPE (expr), totype);
if (fn)
pedwarn (" initializing argument %P of %qD", argnum, fn);
return cp_convert (totype, expr);
}
if (issue_conversion_warnings)
{
tree t = non_reference (totype);
if (ARITHMETIC_TYPE_P (t) && expr == null_node)
{
if (fn)
warning (OPT_Wconversion, "passing NULL to non-pointer argument %P of %qD",
argnum, fn);
else
warning (OPT_Wconversion, "converting to non-pointer type %qT from NULL", t);
}
if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
&& TREE_CODE (t) == INTEGER_TYPE)
{
if (fn)
warning (OPT_Wconversion, "passing %qT for argument %P to %qD",
TREE_TYPE (expr), argnum, fn);
else
warning (OPT_Wconversion, "converting to %qT from %qT", t, TREE_TYPE (expr));
}
}
switch (convs->kind)
{
case ck_user:
{
struct z_candidate *cand = convs->cand;
tree convfn = cand->fn;
tree args;
if (DECL_CONSTRUCTOR_P (convfn))
{
tree t = build_int_cst (build_pointer_type (DECL_CONTEXT (convfn)),
0);
args = build_tree_list (NULL_TREE, expr);
gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (convfn)
&& !DECL_HAS_VTT_PARM_P (convfn));
args = tree_cons (NULL_TREE, t, args);
}
else
args = build_this (expr);
expr = build_over_call (cand, LOOKUP_NORMAL);
if (DECL_CONSTRUCTOR_P (convfn))
expr = build_cplus_new (totype, expr);
if (IS_AGGR_TYPE (totype)
&& really_call_constructor_p (expr, convfn, totype)
&& (inner >= 0 || !lvalue_p (expr)))
{
expr = (build_temp
(expr, totype,
LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING|LOOKUP_NO_CONVERSION,
&diagnostic_fn));
if (diagnostic_fn)
{
if (fn)
diagnostic_fn
(" initializing argument %P of %qD from result of %qD",
argnum, fn, convfn);
else
diagnostic_fn
(" initializing temporary from result of %qD", convfn);
}
expr = build_cplus_new (totype, expr);
}
return expr;
}
case ck_identity:
if (type_unknown_p (expr))
expr = instantiate_type (totype, expr, tf_warning_or_error);
if (inner >= 0)
expr = decl_constant_value (expr);
if (convs->check_copy_constructor_p)
check_constructor_callable (totype, expr);
return expr;
case ck_ambig:
return build_user_type_conversion
(totype, convs->u.expr, LOOKUP_NORMAL);
default:
break;
};
expr = convert_like_real (convs->u.next, expr, fn, argnum,
convs->kind == ck_ref_bind ? -1 : 1,
false,
c_cast_p);
if (expr == error_mark_node)
return error_mark_node;
switch (convs->kind)
{
case ck_rvalue:
expr = convert_bitfield_to_declared_type (expr);
if (! IS_AGGR_TYPE (totype))
return expr;
case ck_base:
if (convs->kind == ck_base && !convs->need_temporary_p)
{
if (convs->check_copy_constructor_p)
check_constructor_callable (TREE_TYPE (expr), expr);
expr = build_unary_op (ADDR_EXPR, expr, 0);
expr = convert_to_base (expr, build_pointer_type (totype),
!c_cast_p, true);
expr = build_indirect_ref (expr, "implicit conversion");
return expr;
}
expr = build_temp (expr, totype, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
&diagnostic_fn);
if (diagnostic_fn && fn)
diagnostic_fn (" initializing argument %P of %qD", argnum, fn);
return build_cplus_new (totype, expr);
case ck_ref_bind:
{
tree ref_type = totype;
if (convs->need_temporary_p || !lvalue_p (expr))
{
tree type = convs->u.next->type;
cp_lvalue_kind lvalue = real_lvalue_p (expr);
if (!CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
{
if (lvalue & clk_bitfield)
error ("cannot bind bitfield %qE to %qT",
expr, ref_type);
else if (lvalue & clk_packed)
error ("cannot bind packed field %qE to %qT",
expr, ref_type);
else
error ("cannot bind rvalue %qE to %qT", expr, ref_type);
return error_mark_node;
}
if ((lvalue & clk_packed)
&& CLASS_TYPE_P (type)
&& !TYPE_HAS_TRIVIAL_INIT_REF (type))
{
error ("cannot bind packed field %qE to %qT",
expr, ref_type);
return error_mark_node;
}
expr = build_target_expr_with_type (expr, type);
}
expr = build_unary_op (ADDR_EXPR, expr, 1);
if (expr == error_mark_node)
return error_mark_node;
expr = cp_convert (build_pointer_type (TREE_TYPE (ref_type)),
expr);
return build_nop (ref_type, expr);
}
case ck_lvalue:
return decay_conversion (expr);
case ck_qual:
string_conv_p (totype, expr, 1);
break;
case ck_ptr:
if (convs->base_p)
expr = convert_to_base (expr, totype, !c_cast_p,
false);
return build_nop (totype, expr);
case ck_pmem:
return convert_ptrmem (totype, expr, false,
c_cast_p);
default:
break;
}
if (issue_conversion_warnings)
expr = convert_and_check (totype, expr);
else
expr = convert (totype, expr);
return expr;
}
static tree
call_builtin_trap (void)
{
tree fn = implicit_built_in_decls[BUILT_IN_TRAP];
gcc_assert (fn != NULL);
fn = build_call (fn, NULL_TREE);
return fn;
}
tree
convert_arg_to_ellipsis (tree arg)
{
arg = decay_conversion (arg);
if (TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE
&& (TYPE_PRECISION (TREE_TYPE (arg))
< TYPE_PRECISION (double_type_node)))
arg = convert_to_real (double_type_node, arg);
else if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (arg)))
arg = perform_integral_promotions (arg);
arg = require_complete_type (arg);
if (arg != error_mark_node
&& !pod_type_p (TREE_TYPE (arg)))
{
if (!skip_evaluation)
warning (0, "cannot pass objects of non-POD type %q#T through %<...%>; "
"call will abort at runtime", TREE_TYPE (arg));
arg = call_builtin_trap ();
arg = build2 (COMPOUND_EXPR, integer_type_node, arg,
integer_zero_node);
}
return arg;
}
tree
build_x_va_arg (tree expr, tree type)
{
if (processing_template_decl)
return build_min (VA_ARG_EXPR, type, expr);
type = complete_type_or_else (type, NULL_TREE);
if (expr == error_mark_node || !type)
return error_mark_node;
if (! pod_type_p (type))
{
tree type1 = non_reference (type);
warning (0, "cannot receive objects of non-POD type %q#T through %<...%>; "
"call will abort at runtime", type);
expr = convert (build_pointer_type (type1), null_node);
expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr),
call_builtin_trap (), expr);
expr = build_indirect_ref (expr, NULL);
return expr;
}
return build_va_arg (expr, type);
}
tree
cxx_type_promotes_to (tree type)
{
tree promote;
type = type_decays_to (type);
promote = type_promotes_to (type);
if (same_type_p (type, promote))
promote = type;
return promote;
}
tree
convert_default_arg (tree type, tree arg, tree fn, int parmnum)
{
if (TREE_CODE (arg) == DEFAULT_ARG)
{
error ("the default argument for parameter %d of %qD has "
"not yet been parsed",
parmnum, fn);
return error_mark_node;
}
if (fn && DECL_TEMPLATE_INFO (fn))
arg = tsubst_default_argument (fn, type, arg);
arg = break_out_target_exprs (arg);
if (TREE_CODE (arg) == CONSTRUCTOR)
{
arg = digest_init (type, arg);
arg = convert_for_initialization (0, type, arg, LOOKUP_NORMAL,
"default argument", fn, parmnum);
}
else
{
if (!CONSTANT_CLASS_P (arg))
arg = unshare_expr (arg);
arg = convert_for_initialization (0, type, arg, LOOKUP_NORMAL,
"default argument", fn, parmnum);
arg = convert_for_arg_passing (type, arg);
}
return arg;
}
tree
type_passed_as (tree type)
{
if (TREE_ADDRESSABLE (type))
{
type = build_reference_type (type);
type = build_qualified_type (type, TYPE_QUAL_RESTRICT);
}
else if (targetm.calls.promote_prototypes (type)
&& INTEGRAL_TYPE_P (type)
&& COMPLETE_TYPE_P (type)
&& INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
TYPE_SIZE (integer_type_node)))
type = integer_type_node;
return type;
}
tree
convert_for_arg_passing (tree type, tree val)
{
val = convert_bitfield_to_declared_type (val);
if (val == error_mark_node)
;
else if (TREE_ADDRESSABLE (type))
val = build1 (ADDR_EXPR, build_reference_type (type), val);
else if (targetm.calls.promote_prototypes (type)
&& INTEGRAL_TYPE_P (type)
&& COMPLETE_TYPE_P (type)
&& INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
TYPE_SIZE (integer_type_node)))
val = perform_integral_promotions (val);
if (warn_missing_format_attribute)
{
tree rhstype = TREE_TYPE (val);
const enum tree_code coder = TREE_CODE (rhstype);
const enum tree_code codel = TREE_CODE (type);
if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
&& coder == codel
&& check_missing_format_attribute (type, rhstype))
warning (OPT_Wmissing_format_attribute,
"argument of function call might be a candidate for a format attribute");
}
return val;
}
static bool
magic_varargs_p (tree fn)
{
if (DECL_BUILT_IN (fn))
switch (DECL_FUNCTION_CODE (fn))
{
case BUILT_IN_CLASSIFY_TYPE:
case BUILT_IN_CONSTANT_P:
case BUILT_IN_NEXT_ARG:
case BUILT_IN_STDARG_START:
case BUILT_IN_VA_START:
return true;
default:;
}
return false;
}
static tree
build_over_call (struct z_candidate *cand, int flags)
{
tree fn = cand->fn;
tree args = cand->args;
conversion **convs = cand->convs;
conversion *conv;
tree converted_args = NULL_TREE;
tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
tree arg, val;
int i = 0;
int is_method = 0;
if (processing_template_decl)
{
tree expr;
tree return_type;
return_type = TREE_TYPE (TREE_TYPE (fn));
expr = build3 (CALL_EXPR, return_type, fn, args, NULL_TREE);
if (TREE_THIS_VOLATILE (fn) && cfun)
current_function_returns_abnormally = 1;
if (!VOID_TYPE_P (return_type))
require_complete_type (return_type);
return convert_from_reference (expr);
}
if (cand->warnings)
{
struct candidate_warning *w;
for (w = cand->warnings; w; w = w->next)
joust (cand, w->loser, 1);
}
if (DECL_FUNCTION_MEMBER_P (fn))
{
if (DECL_TEMPLATE_INFO (fn)
&& DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
perform_or_defer_access_check (cand->access_path,
DECL_TI_TEMPLATE (fn), fn);
else
perform_or_defer_access_check (cand->access_path, fn, fn);
}
if (args && TREE_CODE (args) != TREE_LIST)
args = build_tree_list (NULL_TREE, args);
arg = args;
if (DECL_CONSTRUCTOR_P (fn))
{
converted_args = tree_cons (NULL_TREE, TREE_VALUE (arg), converted_args);
arg = TREE_CHAIN (arg);
parm = TREE_CHAIN (parm);
gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (fn));
if (DECL_HAS_VTT_PARM_P (fn))
{
converted_args = tree_cons
(NULL_TREE, TREE_VALUE (arg), converted_args);
arg = TREE_CHAIN (arg);
parm = TREE_CHAIN (parm);
}
}
else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
{
tree parmtype = TREE_VALUE (parm);
tree argtype = TREE_TYPE (TREE_VALUE (arg));
tree converted_arg;
tree base_binfo;
if (convs[i]->bad_p)
pedwarn ("passing %qT as %<this%> argument of %q#D discards qualifiers",
TREE_TYPE (argtype), fn);
gcc_assert (TREE_CODE (parmtype) == POINTER_TYPE);
gcc_assert (cand->conversion_path != NULL_TREE);
converted_arg = build_base_path (PLUS_EXPR,
TREE_VALUE (arg),
cand->conversion_path,
1);
if (!accessible_base_p (TREE_TYPE (argtype),
BINFO_TYPE (cand->conversion_path), true))
error ("%qT is not an accessible base of %qT",
BINFO_TYPE (cand->conversion_path),
TREE_TYPE (argtype));
base_binfo = lookup_base (TREE_TYPE (TREE_TYPE (converted_arg)),
TREE_TYPE (parmtype), ba_unique, NULL);
converted_arg = build_base_path (PLUS_EXPR, converted_arg,
base_binfo, 1);
converted_args = tree_cons (NULL_TREE, converted_arg, converted_args);
parm = TREE_CHAIN (parm);
arg = TREE_CHAIN (arg);
++i;
is_method = 1;
}
for (; arg && parm;
parm = TREE_CHAIN (parm), arg = TREE_CHAIN (arg), ++i)
{
tree type = TREE_VALUE (parm);
conv = convs[i];
if (conv->kind == ck_rvalue
&& !TREE_ADDRESSABLE (complete_type (type)))
conv = conv->u.next;
val = convert_like_with_context
(conv, TREE_VALUE (arg), fn, i - is_method);
val = convert_for_arg_passing (type, val);
converted_args = tree_cons (NULL_TREE, val, converted_args);
}
for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm), i++)
converted_args
= tree_cons (NULL_TREE,
convert_default_arg (TREE_VALUE (parm),
TREE_PURPOSE (parm),
fn, i - is_method),
converted_args);
for (; arg; arg = TREE_CHAIN (arg))
{
tree a = TREE_VALUE (arg);
if (magic_varargs_p (fn))
;
else
a = convert_arg_to_ellipsis (a);
converted_args = tree_cons (NULL_TREE, a, converted_args);
}
converted_args = nreverse (converted_args);
check_function_arguments (TYPE_ATTRIBUTES (TREE_TYPE (fn)),
converted_args, TYPE_ARG_TYPES (TREE_TYPE (fn)));
if (! flag_elide_constructors)
;
else if (cand->num_convs == 1 && DECL_COPY_CONSTRUCTOR_P (fn))
{
tree targ;
arg = skip_artificial_parms_for (fn, converted_args);
arg = TREE_VALUE (arg);
targ = arg;
while (TREE_CODE (targ) == NOP_EXPR
|| TREE_CODE (targ) == NON_LVALUE_EXPR
|| TREE_CODE (targ) == CONVERT_EXPR)
targ = TREE_OPERAND (targ, 0);
if (TREE_CODE (targ) == ADDR_EXPR)
{
targ = TREE_OPERAND (targ, 0);
if (!same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (TREE_TYPE (arg)), TREE_TYPE (targ)))
targ = NULL_TREE;
}
else
targ = NULL_TREE;
if (targ)
arg = targ;
else
arg = build_indirect_ref (arg, 0);
if (TYPE_HAS_COMPLEX_INIT_REF (DECL_CONTEXT (fn)))
mark_used (fn);
if (integer_zerop (TREE_VALUE (args)))
{
if (TREE_CODE (arg) == TARGET_EXPR)
return arg;
else if (TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
return build_target_expr_with_type (arg, DECL_CONTEXT (fn));
}
else if (TREE_CODE (arg) == TARGET_EXPR
|| TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
{
tree to = stabilize_reference
(build_indirect_ref (TREE_VALUE (args), 0));
val = build2 (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
return val;
}
}
else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
&& copy_fn_p (fn)
&& TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CONTEXT (fn)))
{
tree to = stabilize_reference
(build_indirect_ref (TREE_VALUE (converted_args), 0));
tree type = TREE_TYPE (to);
tree as_base = CLASSTYPE_AS_BASE (type);
arg = TREE_VALUE (TREE_CHAIN (converted_args));
if (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (as_base)))
{
arg = build_indirect_ref (arg, 0);
val = build2 (MODIFY_EXPR, TREE_TYPE (to), to, arg);
}
else
{
tree args, t;
args = tree_cons (NULL, TYPE_SIZE_UNIT (as_base), NULL);
args = tree_cons (NULL, arg, args);
t = build_unary_op (ADDR_EXPR, to, 0);
args = tree_cons (NULL, t, args);
t = implicit_built_in_decls[BUILT_IN_MEMCPY];
t = build_call (t, args);
t = convert (TREE_TYPE (TREE_VALUE (args)), t);
val = build_indirect_ref (t, 0);
}
return val;
}
mark_used (fn);
if (DECL_VINDEX (fn)
&& (TARGET_KEXTABI
|| (flags & LOOKUP_NONVIRTUAL) == 0))
{
tree t, *p = &TREE_VALUE (converted_args);
tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (*p)),
DECL_CONTEXT (fn),
ba_any, NULL);
gcc_assert (binfo && binfo != error_mark_node);
*p = build_base_path (PLUS_EXPR, *p, binfo, 1);
if (TREE_SIDE_EFFECTS (*p))
*p = save_expr (*p);
t = build_pointer_type (TREE_TYPE (fn));
if (DECL_CONTEXT (fn) && TYPE_JAVA_INTERFACE (DECL_CONTEXT (fn)))
fn = build_java_interface_fn_ref (fn, *p);
else if (flags & LOOKUP_NONVIRTUAL) {
tree call_site_type = TREE_TYPE (cand->access_path);
tree fn_class_type = DECL_CLASS_CONTEXT (fn);
gcc_assert (call_site_type != NULL &&
fn_class_type != NULL &&
AGGREGATE_TYPE_P (call_site_type) &&
AGGREGATE_TYPE_P (fn_class_type));
gcc_assert (lookup_base(TYPE_MAIN_VARIANT (call_site_type),
TYPE_MAIN_VARIANT (fn_class_type),
ba_any | ba_quiet,
NULL) != NULL);
if (BINFO_N_BASE_BINFOS (TYPE_BINFO (call_site_type)) > 1
|| CLASSTYPE_VBASECLASSES (call_site_type))
error ("indirect virtual calls are invalid for a type that uses multiple or virtual inheritance");
fn = (build_vfn_ref_using_vtable
(BINFO_VTABLE (TYPE_BINFO (call_site_type)),
DECL_VINDEX (fn)));
fn = build1 (NOP_EXPR, t, fn);
}
else
fn = build_vfn_ref (*p, DECL_VINDEX (fn));
TREE_TYPE (fn) = t;
}
else if (DECL_INLINE (fn))
fn = inline_conversion (fn);
else
fn = build_addr_func (fn);
return build_cxx_call (fn, converted_args);
}
tree
build_cxx_call (tree fn, tree args)
{
tree fndecl;
fn = build_call (fn, args);
fndecl = get_callee_fndecl (fn);
if ((!fndecl || !TREE_NOTHROW (fndecl))
&& at_function_scope_p ()
&& cfun)
cp_function_chain->can_throw = 1;
fn = fold_if_not_in_template (fn);
if (VOID_TYPE_P (TREE_TYPE (fn)))
return fn;
fn = require_complete_type (fn);
if (fn == error_mark_node)
return error_mark_node;
if (IS_AGGR_TYPE (TREE_TYPE (fn)))
fn = build_cplus_new (TREE_TYPE (fn), fn);
return convert_from_reference (fn);
}
static GTY(()) tree java_iface_lookup_fn;
static tree
build_java_interface_fn_ref (tree fn, tree instance)
{
tree lookup_args, lookup_fn, method, idx;
tree klass_ref, iface, iface_ref;
int i;
if (!java_iface_lookup_fn)
{
tree endlink = build_void_list_node ();
tree t = tree_cons (NULL_TREE, ptr_type_node,
tree_cons (NULL_TREE, ptr_type_node,
tree_cons (NULL_TREE, java_int_type_node,
endlink)));
java_iface_lookup_fn
= builtin_function ("_Jv_LookupInterfaceMethodIdx",
build_function_type (ptr_type_node, t),
0, NOT_BUILT_IN, NULL, NULL_TREE);
}
klass_ref = build_vtbl_ref (build_indirect_ref (instance, 0),
integer_zero_node);
iface = DECL_CONTEXT (fn);
iface_ref = lookup_field (iface, get_identifier ("class$"), 0, false);
if (!iface_ref || TREE_CODE (iface_ref) != VAR_DECL
|| DECL_CONTEXT (iface_ref) != iface)
{
error ("could not find class$ field in java interface type %qT",
iface);
return error_mark_node;
}
iface_ref = build_address (iface_ref);
iface_ref = convert (build_pointer_type (iface), iface_ref);
i = 1;
for (method = TYPE_METHODS (iface); method; method = TREE_CHAIN (method))
{
if (!DECL_VIRTUAL_P (method))
continue;
if (fn == method)
break;
i++;
}
idx = build_int_cst (NULL_TREE, i);
lookup_args = tree_cons (NULL_TREE, klass_ref,
tree_cons (NULL_TREE, iface_ref,
build_tree_list (NULL_TREE, idx)));
lookup_fn = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (java_iface_lookup_fn)),
java_iface_lookup_fn);
return build3 (CALL_EXPR, ptr_type_node, lookup_fn, lookup_args, NULL_TREE);
}
tree
in_charge_arg_for_name (tree name)
{
if (name == base_ctor_identifier
|| name == base_dtor_identifier)
return integer_zero_node;
else if (name == complete_ctor_identifier)
return integer_one_node;
else if (name == complete_dtor_identifier)
return integer_two_node;
else if (name == deleting_dtor_identifier)
return integer_three_node;
gcc_unreachable ();
return NULL_TREE;
}
tree
build_special_member_call (tree instance, tree name, tree args,
tree binfo, int flags)
{
tree fns;
tree class_type;
gcc_assert (name == complete_ctor_identifier
|| name == base_ctor_identifier
|| name == complete_dtor_identifier
|| name == base_dtor_identifier
|| name == deleting_dtor_identifier
|| name == ansi_assopname (NOP_EXPR));
if (TYPE_P (binfo))
{
if (!complete_type_or_else (binfo, NULL_TREE))
return error_mark_node;
binfo = TYPE_BINFO (binfo);
}
gcc_assert (binfo != NULL_TREE);
class_type = BINFO_TYPE (binfo);
if (name == complete_ctor_identifier && !instance)
{
instance = build_int_cst (build_pointer_type (class_type), 0);
instance = build1 (INDIRECT_REF, class_type, instance);
}
else
{
if (name == complete_dtor_identifier
|| name == base_dtor_identifier
|| name == deleting_dtor_identifier)
gcc_assert (args == NULL_TREE);
if (!same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (instance), BINFO_TYPE (binfo)))
{
if (name != ansi_assopname (NOP_EXPR))
instance = convert_to_base_statically (instance, binfo);
else
instance = build_base_path (PLUS_EXPR, instance,
binfo, 1);
}
}
gcc_assert (instance != NULL_TREE);
fns = lookup_fnfields (binfo, name, 1);
if ((name == base_ctor_identifier
|| name == base_dtor_identifier)
&& CLASSTYPE_VBASECLASSES (class_type))
{
tree vtt;
tree sub_vtt;
vtt = TREE_CHAIN (CLASSTYPE_VTABLES (current_class_type));
vtt = decay_conversion (vtt);
vtt = build3 (COND_EXPR, TREE_TYPE (vtt),
build2 (EQ_EXPR, boolean_type_node,
current_in_charge_parm, integer_zero_node),
current_vtt_parm,
vtt);
gcc_assert (BINFO_SUBVTT_INDEX (binfo));
sub_vtt = build2 (PLUS_EXPR, TREE_TYPE (vtt), vtt,
BINFO_SUBVTT_INDEX (binfo));
args = tree_cons (NULL_TREE, sub_vtt, args);
}
return build_new_method_call (instance, fns, args,
TYPE_BINFO (BINFO_TYPE (binfo)),
flags, NULL);
}
static char *
name_as_c_string (tree name, tree type, bool *free_p)
{
char *pretty_name;
*free_p = false;
if (IDENTIFIER_CTOR_OR_DTOR_P (name))
{
pretty_name
= (char *) IDENTIFIER_POINTER (constructor_name (type));
if (name == complete_dtor_identifier
|| name == base_dtor_identifier
|| name == deleting_dtor_identifier)
{
pretty_name = concat ("~", pretty_name, NULL);
*free_p = true;
}
}
else if (IDENTIFIER_TYPENAME_P (name))
{
pretty_name = concat ("operator ",
type_as_string (TREE_TYPE (name),
TFF_PLAIN_IDENTIFIER),
NULL);
*free_p = true;
}
else
pretty_name = (char *) IDENTIFIER_POINTER (name);
return pretty_name;
}
tree
build_new_method_call (tree instance, tree fns, tree args,
tree conversion_path, int flags,
tree *fn_p)
{
struct z_candidate *candidates = 0, *cand;
tree explicit_targs = NULL_TREE;
tree basetype = NULL_TREE;
tree access_binfo;
tree optype;
tree mem_args = NULL_TREE, instance_ptr;
tree name;
tree user_args;
tree call;
tree fn;
tree class_type;
int template_only = 0;
bool any_viable_p;
tree orig_instance;
tree orig_fns;
tree orig_args;
void *p;
gcc_assert (instance != NULL_TREE);
if (fn_p)
*fn_p = NULL_TREE;
if (error_operand_p (instance)
|| error_operand_p (fns)
|| args == error_mark_node)
return error_mark_node;
if (!BASELINK_P (fns))
{
error ("call to non-function %qD", fns);
return error_mark_node;
}
orig_instance = instance;
orig_fns = fns;
orig_args = args;
if (!conversion_path)
conversion_path = BASELINK_BINFO (fns);
access_binfo = BASELINK_ACCESS_BINFO (fns);
optype = BASELINK_OPTYPE (fns);
fns = BASELINK_FUNCTIONS (fns);
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
{
explicit_targs = TREE_OPERAND (fns, 1);
fns = TREE_OPERAND (fns, 0);
template_only = 1;
}
gcc_assert (TREE_CODE (fns) == FUNCTION_DECL
|| TREE_CODE (fns) == TEMPLATE_DECL
|| TREE_CODE (fns) == OVERLOAD);
fn = get_first_fn (fns);
name = DECL_NAME (fn);
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (instance));
gcc_assert (CLASS_TYPE_P (basetype));
if (processing_template_decl)
{
instance = build_non_dependent_expr (instance);
args = build_non_dependent_args (orig_args);
}
user_args = args;
if (IDENTIFIER_CTOR_OR_DTOR_P (name))
{
gcc_assert (name != ctor_identifier);
gcc_assert (name != dtor_identifier);
if ((name == base_ctor_identifier || name == base_dtor_identifier)
&& CLASSTYPE_VBASECLASSES (basetype))
user_args = TREE_CHAIN (user_args);
}
args = resolve_args (args);
if (args == error_mark_node)
return error_mark_node;
instance_ptr = build_this (instance);
if (DECL_DESTRUCTOR_P (fn))
{
tree type = build_pointer_type (basetype);
if (!same_type_p (type, TREE_TYPE (instance_ptr)))
instance_ptr = build_nop (type, instance_ptr);
name = complete_dtor_identifier;
}
class_type = (conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE);
mem_args = tree_cons (NULL_TREE, instance_ptr, args);
p = conversion_obstack_alloc (0);
for (fn = fns; fn; fn = OVL_NEXT (fn))
{
tree t = OVL_CURRENT (fn);
tree this_arglist;
if ((flags & LOOKUP_ONLYCONVERTING)
&& DECL_NONCONVERTING_P (t))
continue;
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t))
this_arglist = mem_args;
else
this_arglist = args;
if (TREE_CODE (t) == TEMPLATE_DECL)
add_template_candidate (&candidates, t,
class_type,
explicit_targs,
this_arglist, optype,
access_binfo,
conversion_path,
flags,
DEDUCE_CALL);
else if (! template_only)
add_function_candidate (&candidates, t,
class_type,
this_arglist,
access_binfo,
conversion_path,
flags);
}
candidates = splice_viable (candidates, pedantic, &any_viable_p);
if (!any_viable_p)
{
if (!COMPLETE_TYPE_P (basetype))
cxx_incomplete_type_error (instance_ptr, basetype);
else
{
char *pretty_name;
bool free_p;
pretty_name = name_as_c_string (name, basetype, &free_p);
error ("no matching function for call to %<%T::%s(%A)%#V%>",
basetype, pretty_name, user_args,
TREE_TYPE (TREE_TYPE (instance_ptr)));
if (free_p)
free (pretty_name);
}
print_z_candidates (candidates);
call = error_mark_node;
}
else
{
cand = tourney (candidates);
if (cand == 0)
{
char *pretty_name;
bool free_p;
pretty_name = name_as_c_string (name, basetype, &free_p);
error ("call of overloaded %<%s(%A)%> is ambiguous", pretty_name,
user_args);
print_z_candidates (candidates);
if (free_p)
free (pretty_name);
call = error_mark_node;
}
else
{
fn = cand->fn;
if (!(flags & LOOKUP_NONVIRTUAL)
&& DECL_PURE_VIRTUAL_P (fn)
&& instance == current_class_ref
&& (DECL_CONSTRUCTOR_P (current_function_decl)
|| DECL_DESTRUCTOR_P (current_function_decl)))
warning (0, (DECL_CONSTRUCTOR_P (current_function_decl) ?
"abstract virtual %q#D called from constructor"
: "abstract virtual %q#D called from destructor"),
fn);
if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
&& is_dummy_object (instance_ptr))
{
error ("cannot call member function %qD without object",
fn);
call = error_mark_node;
}
else
{
if (DECL_VINDEX (fn) && ! (flags & LOOKUP_NONVIRTUAL)
&& resolves_to_fixed_type_p (instance, 0))
flags |= LOOKUP_NONVIRTUAL;
if (fn_p)
*fn_p = fn;
call = build_over_call (cand, flags);
if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
&& !is_dummy_object (instance_ptr)
&& TREE_SIDE_EFFECTS (instance_ptr))
call = build2 (COMPOUND_EXPR, TREE_TYPE (call),
instance_ptr, call);
else if (call != error_mark_node
&& DECL_DESTRUCTOR_P (cand->fn)
&& !VOID_TYPE_P (TREE_TYPE (call)))
call = build_nop (void_type_node, call);
}
}
}
if (processing_template_decl && call != error_mark_node)
call = (build_min_non_dep
(CALL_EXPR, call,
build_min_nt (COMPONENT_REF, orig_instance, orig_fns, NULL_TREE),
orig_args, NULL_TREE));
obstack_free (&conversion_obstack, p);
return call;
}
static bool
is_subseq (conversion *ics1, conversion *ics2)
{
while (ics1->kind == ck_rvalue
|| ics1->kind == ck_lvalue)
ics1 = ics1->u.next;
while (1)
{
while (ics2->kind == ck_rvalue
|| ics2->kind == ck_lvalue)
ics2 = ics2->u.next;
if (ics2->kind == ck_user
|| ics2->kind == ck_ambig
|| ics2->kind == ck_identity)
return false;
ics2 = ics2->u.next;
if (ics2->kind == ics1->kind
&& same_type_p (ics2->type, ics1->type)
&& same_type_p (ics2->u.next->type,
ics1->u.next->type))
return true;
}
}
bool
is_properly_derived_from (tree derived, tree base)
{
if (!IS_AGGR_TYPE_CODE (TREE_CODE (derived))
|| !IS_AGGR_TYPE_CODE (TREE_CODE (base)))
return false;
return (!same_type_ignoring_top_level_qualifiers_p (derived, base)
&& DERIVED_FROM_P (base, derived));
}
static void
maybe_handle_implicit_object (conversion **ics)
{
if ((*ics)->this_p)
{
conversion *t = *ics;
tree reference_type;
reference_type = TREE_TYPE (t->type);
reference_type = build_reference_type (reference_type);
if (t->kind == ck_qual)
t = t->u.next;
if (t->kind == ck_ptr)
t = t->u.next;
t = build_identity_conv (TREE_TYPE (t->type), NULL_TREE);
t = direct_reference_binding (reference_type, t);
*ics = t;
}
}
static tree
maybe_handle_ref_bind (conversion **ics)
{
if ((*ics)->kind == ck_ref_bind)
{
conversion *old_ics = *ics;
tree type = TREE_TYPE (old_ics->type);
*ics = old_ics->u.next;
(*ics)->user_conv_p = old_ics->user_conv_p;
(*ics)->bad_p = old_ics->bad_p;
return type;
}
return NULL_TREE;
}
static int
compare_ics (conversion *ics1, conversion *ics2)
{
tree from_type1;
tree from_type2;
tree to_type1;
tree to_type2;
tree deref_from_type1 = NULL_TREE;
tree deref_from_type2 = NULL_TREE;
tree deref_to_type1 = NULL_TREE;
tree deref_to_type2 = NULL_TREE;
conversion_rank rank1, rank2;
tree target_type1;
tree target_type2;
maybe_handle_implicit_object (&ics1);
maybe_handle_implicit_object (&ics2);
target_type1 = maybe_handle_ref_bind (&ics1);
target_type2 = maybe_handle_ref_bind (&ics2);
rank1 = CONVERSION_RANK (ics1);
rank2 = CONVERSION_RANK (ics2);
if (rank1 > rank2)
return -1;
else if (rank1 < rank2)
return 1;
if (rank1 == cr_bad)
{
if (ics1->user_conv_p > ics2->user_conv_p
|| ics1->rank > ics2->rank)
return -1;
else if (ics1->user_conv_p < ics2->user_conv_p
|| ics1->rank < ics2->rank)
return 1;
}
if (ics1->ellipsis_p)
return 0;
if (ics1->user_conv_p)
{
conversion *t1;
conversion *t2;
for (t1 = ics1; t1->kind != ck_user; t1 = t1->u.next)
if (t1->kind == ck_ambig)
return 0;
for (t2 = ics2; t2->kind != ck_user; t2 = t2->u.next)
if (t2->kind == ck_ambig)
return 0;
if (t1->cand->fn != t2->cand->fn)
return 0;
from_type1 = t1->type;
from_type2 = t2->type;
}
else
{
conversion *t1;
conversion *t2;
t1 = ics1;
while (t1->kind != ck_identity)
t1 = t1->u.next;
from_type1 = t1->type;
t2 = ics2;
while (t2->kind != ck_identity)
t2 = t2->u.next;
from_type2 = t2->type;
}
if (same_type_p (from_type1, from_type2))
{
if (is_subseq (ics1, ics2))
return 1;
if (is_subseq (ics2, ics1))
return -1;
}
if (ics1->rank < ics2->rank)
return 1;
else if (ics2->rank < ics1->rank)
return -1;
to_type1 = ics1->type;
to_type2 = ics2->type;
if (TYPE_PTR_P (from_type1)
&& TYPE_PTR_P (from_type2)
&& TYPE_PTR_P (to_type1)
&& TYPE_PTR_P (to_type2))
{
deref_from_type1 = TREE_TYPE (from_type1);
deref_from_type2 = TREE_TYPE (from_type2);
deref_to_type1 = TREE_TYPE (to_type1);
deref_to_type2 = TREE_TYPE (to_type2);
}
else if ((TYPE_PTRMEM_P (from_type1) && TYPE_PTRMEM_P (from_type2)
&& TYPE_PTRMEM_P (to_type1) && TYPE_PTRMEM_P (to_type2))
|| (TYPE_PTRMEMFUNC_P (from_type1)
&& TYPE_PTRMEMFUNC_P (from_type2)
&& TYPE_PTRMEMFUNC_P (to_type1)
&& TYPE_PTRMEMFUNC_P (to_type2)))
{
deref_to_type1 = TYPE_PTRMEM_CLASS_TYPE (from_type1);
deref_to_type2 = TYPE_PTRMEM_CLASS_TYPE (from_type2);
deref_from_type1 = TYPE_PTRMEM_CLASS_TYPE (to_type1);
deref_from_type2 = TYPE_PTRMEM_CLASS_TYPE (to_type2);
}
if (deref_from_type1 != NULL_TREE
&& IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type1))
&& IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type2)))
{
if (TREE_CODE (deref_to_type1) == VOID_TYPE
&& TREE_CODE (deref_to_type2) == VOID_TYPE)
{
if (is_properly_derived_from (deref_from_type1,
deref_from_type2))
return -1;
else if (is_properly_derived_from (deref_from_type2,
deref_from_type1))
return 1;
}
else if (TREE_CODE (deref_to_type1) == VOID_TYPE
|| TREE_CODE (deref_to_type2) == VOID_TYPE)
{
if (same_type_p (deref_from_type1, deref_from_type2))
{
if (TREE_CODE (deref_to_type2) == VOID_TYPE)
{
if (is_properly_derived_from (deref_from_type1,
deref_to_type1))
return 1;
}
else if (is_properly_derived_from (deref_from_type1,
deref_to_type2))
return -1;
}
}
else if (IS_AGGR_TYPE_CODE (TREE_CODE (deref_to_type1))
&& IS_AGGR_TYPE_CODE (TREE_CODE (deref_to_type2)))
{
if (same_type_p (deref_from_type1, deref_from_type2))
{
if (is_properly_derived_from (deref_to_type1,
deref_to_type2))
return 1;
else if (is_properly_derived_from (deref_to_type2,
deref_to_type1))
return -1;
}
else if (same_type_p (deref_to_type1, deref_to_type2))
{
if (is_properly_derived_from (deref_from_type2,
deref_from_type1))
return 1;
else if (is_properly_derived_from (deref_from_type1,
deref_from_type2))
return -1;
}
}
}
else if (CLASS_TYPE_P (non_reference (from_type1))
&& same_type_p (from_type1, from_type2))
{
tree from = non_reference (from_type1);
if (is_properly_derived_from (from, to_type1)
&& is_properly_derived_from (from, to_type2))
{
if (is_properly_derived_from (to_type1, to_type2))
return 1;
else if (is_properly_derived_from (to_type2, to_type1))
return -1;
}
}
else if (CLASS_TYPE_P (non_reference (to_type1))
&& same_type_p (to_type1, to_type2))
{
tree to = non_reference (to_type1);
if (is_properly_derived_from (from_type1, to)
&& is_properly_derived_from (from_type2, to))
{
if (is_properly_derived_from (from_type2, from_type1))
return 1;
else if (is_properly_derived_from (from_type1, from_type2))
return -1;
}
}
if (ics1->kind == ck_qual
&& ics2->kind == ck_qual
&& same_type_p (from_type1, from_type2))
return comp_cv_qual_signature (to_type1, to_type2);
if (target_type1 && target_type2
&& same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
return comp_cv_qualification (target_type2, target_type1);
return 0;
}
static tree
source_type (conversion *t)
{
for (;; t = t->u.next)
{
if (t->kind == ck_user
|| t->kind == ck_ambig
|| t->kind == ck_identity)
return t->type;
}
gcc_unreachable ();
}
static void
add_warning (struct z_candidate *winner, struct z_candidate *loser)
{
candidate_warning *cw = (candidate_warning *)
conversion_obstack_alloc (sizeof (candidate_warning));
cw->loser = loser;
cw->next = winner->warnings;
winner->warnings = cw;
}
static int
joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn)
{
int winner = 0;
int off1 = 0, off2 = 0;
size_t i;
size_t len;
if (cand1->viable > cand2->viable)
return 1;
if (cand1->viable < cand2->viable)
return -1;
if (cand1->fn == cand2->fn
&& (IS_TYPE_OR_DECL_P (cand1->fn)))
return 1;
len = cand1->num_convs;
if (len != cand2->num_convs)
{
int static_1 = DECL_STATIC_FUNCTION_P (cand1->fn);
int static_2 = DECL_STATIC_FUNCTION_P (cand2->fn);
gcc_assert (static_1 != static_2);
if (static_1)
off2 = 1;
else
{
off1 = 1;
--len;
}
}
for (i = 0; i < len; ++i)
{
conversion *t1 = cand1->convs[i + off1];
conversion *t2 = cand2->convs[i + off2];
int comp = compare_ics (t1, t2);
if (comp != 0)
{
if (warn_sign_promo
&& (CONVERSION_RANK (t1) + CONVERSION_RANK (t2)
== cr_std + cr_promotion)
&& t1->kind == ck_std
&& t2->kind == ck_std
&& TREE_CODE (t1->type) == INTEGER_TYPE
&& TREE_CODE (t2->type) == INTEGER_TYPE
&& (TYPE_PRECISION (t1->type)
== TYPE_PRECISION (t2->type))
&& (TYPE_UNSIGNED (t1->u.next->type)
|| (TREE_CODE (t1->u.next->type)
== ENUMERAL_TYPE)))
{
tree type = t1->u.next->type;
tree type1, type2;
struct z_candidate *w, *l;
if (comp > 0)
type1 = t1->type, type2 = t2->type,
w = cand1, l = cand2;
else
type1 = t2->type, type2 = t1->type,
w = cand2, l = cand1;
if (warn)
{
warning (OPT_Wsign_promo, "passing %qT chooses %qT over %qT",
type, type1, type2);
warning (OPT_Wsign_promo, " in call to %qD", w->fn);
}
else
add_warning (w, l);
}
if (winner && comp != winner)
{
winner = 0;
goto tweak;
}
winner = comp;
}
}
if (winner && warn_conversion && cand1->second_conv
&& (!DECL_CONSTRUCTOR_P (cand1->fn) || !DECL_CONSTRUCTOR_P (cand2->fn))
&& winner != compare_ics (cand1->second_conv, cand2->second_conv))
{
struct z_candidate *w, *l;
bool give_warning = false;
if (winner == 1)
w = cand1, l = cand2;
else
w = cand2, l = cand1;
if (DECL_CONTEXT (w->fn) == DECL_CONTEXT (l->fn)
&& !DECL_CONSTRUCTOR_P (w->fn) && !DECL_CONSTRUCTOR_P (l->fn))
{
tree t = TREE_TYPE (TREE_TYPE (l->fn));
tree f = TREE_TYPE (TREE_TYPE (w->fn));
if (TREE_CODE (t) == TREE_CODE (f) && POINTER_TYPE_P (t))
{
t = TREE_TYPE (t);
f = TREE_TYPE (f);
}
if (!comp_ptr_ttypes (t, f))
give_warning = true;
}
else
give_warning = true;
if (!give_warning)
;
else if (warn)
{
tree source = source_type (w->convs[0]);
if (! DECL_CONSTRUCTOR_P (w->fn))
source = TREE_TYPE (source);
warning (OPT_Wconversion, "choosing %qD over %qD", w->fn, l->fn);
warning (OPT_Wconversion, " for conversion from %qT to %qT",
source, w->second_conv->type);
inform (" because conversion sequence for the argument is better");
}
else
add_warning (w, l);
}
if (winner)
return winner;
if (!cand1->template_decl && cand2->template_decl)
return 1;
else if (cand1->template_decl && !cand2->template_decl)
return -1;
if (cand1->template_decl && cand2->template_decl)
{
winner = more_specialized_fn
(TI_TEMPLATE (cand1->template_decl),
TI_TEMPLATE (cand2->template_decl),
cand1->num_convs + DECL_CONSTRUCTOR_P (cand1->fn));
if (winner)
return winner;
}
if (cand1->second_conv)
{
winner = compare_ics (cand1->second_conv, cand2->second_conv);
if (winner)
return winner;
}
if (TREE_CODE (cand1->fn) == IDENTIFIER_NODE
|| TREE_CODE (cand2->fn) == IDENTIFIER_NODE)
{
for (i = 0; i < len; ++i)
if (!same_type_p (cand1->convs[i]->type,
cand2->convs[i]->type))
break;
if (i == cand1->num_convs)
{
if (cand1->fn == cand2->fn)
return 1;
else if (TREE_CODE (cand1->fn) == IDENTIFIER_NODE)
return -1;
else
return 1;
}
}
if (DECL_P (cand1->fn) && DECL_P (cand2->fn)
&& equal_functions (cand1->fn, cand2->fn))
return 1;
tweak:
if (!pedantic)
{
conversion_rank rank1 = cr_identity, rank2 = cr_identity;
struct z_candidate *w = 0, *l = 0;
for (i = 0; i < len; ++i)
{
if (CONVERSION_RANK (cand1->convs[i+off1]) > rank1)
rank1 = CONVERSION_RANK (cand1->convs[i+off1]);
if (CONVERSION_RANK (cand2->convs[i + off2]) > rank2)
rank2 = CONVERSION_RANK (cand2->convs[i + off2]);
}
if (rank1 < rank2)
winner = 1, w = cand1, l = cand2;
if (rank1 > rank2)
winner = -1, w = cand2, l = cand1;
if (winner)
{
if (warn)
{
pedwarn ("\
ISO C++ says that these are ambiguous, even \
though the worst conversion for the first is better than \
the worst conversion for the second:");
print_z_candidate (_("candidate 1:"), w);
print_z_candidate (_("candidate 2:"), l);
}
else
add_warning (w, l);
return winner;
}
}
gcc_assert (!winner);
return 0;
}
static struct z_candidate *
tourney (struct z_candidate *candidates)
{
struct z_candidate *champ = candidates, *challenger;
int fate;
int champ_compared_to_predecessor = 0;
for (challenger = champ->next; challenger; )
{
fate = joust (champ, challenger, 0);
if (fate == 1)
challenger = challenger->next;
else
{
if (fate == 0)
{
champ = challenger->next;
if (champ == 0)
return NULL;
champ_compared_to_predecessor = 0;
}
else
{
champ = challenger;
champ_compared_to_predecessor = 1;
}
challenger = champ->next;
}
}
for (challenger = candidates;
challenger != champ
&& !(champ_compared_to_predecessor && challenger->next == champ);
challenger = challenger->next)
{
fate = joust (champ, challenger, 0);
if (fate != 1)
return NULL;
}
return champ;
}
bool
can_convert (tree to, tree from)
{
return can_convert_arg (to, from, NULL_TREE, LOOKUP_NORMAL);
}
bool
can_convert_arg (tree to, tree from, tree arg, int flags)
{
conversion *t;
void *p;
bool ok_p;
p = conversion_obstack_alloc (0);
t = implicit_conversion (to, from, arg, false,
flags);
ok_p = (t && !t->bad_p);
obstack_free (&conversion_obstack, p);
return ok_p;
}
bool
can_convert_arg_bad (tree to, tree from, tree arg)
{
conversion *t;
void *p;
p = conversion_obstack_alloc (0);
t = implicit_conversion (to, from, arg, false,
LOOKUP_NORMAL);
obstack_free (&conversion_obstack, p);
return t != NULL;
}
tree
perform_implicit_conversion (tree type, tree expr)
{
conversion *conv;
void *p;
if (error_operand_p (expr))
return error_mark_node;
p = conversion_obstack_alloc (0);
conv = implicit_conversion (type, TREE_TYPE (expr), expr,
false,
LOOKUP_NORMAL);
if (!conv)
{
error ("could not convert %qE to %qT", expr, type);
expr = error_mark_node;
}
else if (processing_template_decl)
{
if (TREE_TYPE (expr) != type)
expr = build_nop (type, expr);
}
else
expr = convert_like (conv, expr);
obstack_free (&conversion_obstack, p);
return expr;
}
tree
perform_direct_initialization_if_possible (tree type,
tree expr,
bool c_cast_p)
{
conversion *conv;
void *p;
if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
if (CLASS_TYPE_P (type))
{
expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
build_tree_list (NULL_TREE, expr),
type, LOOKUP_NORMAL);
return build_cplus_new (type, expr);
}
p = conversion_obstack_alloc (0);
conv = implicit_conversion (type, TREE_TYPE (expr), expr,
c_cast_p,
LOOKUP_NORMAL);
if (!conv || conv->bad_p)
expr = NULL_TREE;
else
expr = convert_like_real (conv, expr, NULL_TREE, 0, 0,
false,
c_cast_p);
obstack_free (&conversion_obstack, p);
return expr;
}
tree
make_temporary_var_for_ref_to_temp (tree decl, tree type)
{
tree var;
var = create_temporary_var (type);
if (TREE_STATIC (decl))
{
tree name;
TREE_STATIC (var) = 1;
name = mangle_ref_init_variable (decl);
DECL_NAME (var) = name;
SET_DECL_ASSEMBLER_NAME (var, name);
var = pushdecl_top_level (var);
}
else
maybe_push_cleanup_level (type);
return var;
}
tree
initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
{
conversion *conv;
void *p;
if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
p = conversion_obstack_alloc (0);
conv = reference_binding (type, TREE_TYPE (expr), expr, false,
LOOKUP_NORMAL);
if (!conv || conv->bad_p)
{
if (!(TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)
&& !real_lvalue_p (expr))
error ("invalid initialization of non-const reference of "
"type %qT from a temporary of type %qT",
type, TREE_TYPE (expr));
else
error ("invalid initialization of reference of type "
"%qT from expression of type %qT", type,
TREE_TYPE (expr));
return error_mark_node;
}
gcc_assert (conv->kind == ck_ref_bind);
if (decl)
{
tree var;
tree base_conv_type;
conv = conv->u.next;
if (conv->kind == ck_base)
{
if (conv->check_copy_constructor_p)
check_constructor_callable (TREE_TYPE (expr), expr);
base_conv_type = conv->type;
conv = conv->u.next;
}
else
base_conv_type = NULL_TREE;
expr = convert_like_real (conv, expr,
NULL_TREE, 0,
-1,
true,
false);
if (error_operand_p (expr))
expr = error_mark_node;
else
{
if (!real_lvalue_p (expr))
{
tree init;
tree type;
type = TREE_TYPE (expr);
var = make_temporary_var_for_ref_to_temp (decl, type);
layout_decl (var, 0);
if (TREE_CODE (expr) != TARGET_EXPR)
expr = get_target_expr (expr);
init = build2 (INIT_EXPR, type, var, expr);
if (at_function_scope_p ())
{
add_decl_expr (var);
*cleanup = cxx_maybe_build_cleanup (var);
}
else
{
rest_of_decl_compilation (var, 1, at_eof);
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
static_aggregates = tree_cons (NULL_TREE, var,
static_aggregates);
}
expr = build_address (var);
if (base_conv_type)
expr = convert_to_base (expr,
build_pointer_type (base_conv_type),
true,
true);
expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
}
else
expr = build_unary_op (ADDR_EXPR, expr, 0);
if (base_conv_type)
expr = (perform_implicit_conversion
(build_pointer_type (base_conv_type), expr));
expr = build_nop (type, expr);
}
}
else
expr = convert_like (conv, expr);
obstack_free (&conversion_obstack, p);
return expr;
}
#include "gt-cp-call.h"