/*
 * Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *    		 Crown Copyright (c) 1997
 *    
 *    This TenDRA(r) Computer Program is subject to Copyright
 *    owned by the United Kingdom Secretary of State for Defence
 *    acting through the Defence Evaluation and Research Agency
 *    (DERA).  It is made available to Recipients with a
 *    royalty-free licence for its use, reproduction, transfer
 *    to other parties and amendment for any purpose not excluding
 *    product development provided that any such use et cetera
 *    shall be deemed to be acceptance of the following conditions:-
 *    
 *        (1) Its Recipients shall ensure that this Notice is
 *        reproduced upon any copies or amended versions of it;
 *    
 *        (2) Any amended version of it shall be clearly marked to
 *        show both the nature of and the organisation responsible
 *        for the relevant amendment or amendments;
 *    
 *        (3) Its onward transfer from a recipient to another
 *        party shall be deemed to be that party's acceptance of
 *        these conditions;
 *    
 *        (4) DERA gives no warranty or assurance as to its
 *        quality or suitability for any purpose and DERA accepts
 *        no liability whatsoever in relation to any use to which
 *        it may be put.
 *
 * $TenDRA: tendra/src/producers/common/construct/overload.c,v 1.8 2004/08/15 11:13:35 bp Exp $
 */


#include "config.h"
#include "producer.h"

#include "fmm.h"
#include "msgcat.h"

#include "c_types.h"
#include "ctype_ops.h"
#include "etype_ops.h"
#include "exp_ops.h"
#include "graph_ops.h"
#include "hashid_ops.h"
#include "id_ops.h"
#include "itype_ops.h"
#include "member_ops.h"
#include "nspace_ops.h"
#include "tok_ops.h"
#include "type_ops.h"
#include "error.h"
#include "catalog.h"
#include "assign.h"
#include "basetype.h"
#include "cast.h"
#include "chktype.h"
#include "class.h"
#include "construct.h"
#include "convert.h"
#include "copy.h"
#include "declare.h"
#include "derive.h"
#include "destroy.h"
#include "dump.h"
#include "exception.h"
#include "expression.h"
#include "function.h"
#include "hash.h"
#include "identifier.h"
#include "initialise.h"
#include "instance.h"
#include "namespace.h"
#include "operator.h"
#include "option.h"
#include "overload.h"
#include "predict.h"
#include "syntax.h"
#include "template.h"
#include "tokdef.h"
#include "token.h"
#include "ustring.h"


/*
 *    CANDIDATE LIST
 *
 *    This variable gives the main candidate list used in overload resolution.
 */

CANDIDATE_LIST candidates = { NULL, 0, 0, NULL, 0 };


/*
 *    ADD A CANDIDATE TO A LIST
 *
 *    This routine adds the candidate given by id, bid and kind to the
 *    candidate list p.
 */

static void
add_candidate(CANDIDATE_LIST *p, IDENTIFIER id, IDENTIFIER bid, int kind)
{
    CANDIDATE *q = p->elem;
    unsigned n = p->size;
    unsigned m = p->max_size;
    if (n >= m) {
		/* Increase size if necessary */
		m += 200;
		q = xrealloc (q, sizeof(*q) * m);
		p->elem = q;
		p->max_size = m;
    }
    q [n].func = id;
    q [n].base = bid;
    q [n].kind = kind;
    q [n].rank = RANK_NONE;
    q [n].convs = NULL;
    q [n].cond = NULL_exp;
    p->size = n + 1;
    return;
}


/*
 *    ADD AN IDENTIFIER TO A CANDIDATE LIST
 *
 *    This routine adds the overloaded function identifier id to the candidate
 *    list given by p.  The kind argument is stored in the kind field of each
 *    candidate.  The table of candidate functions may need extending.  Note
 *    that the candidates are added in the reverse order in which they were
 *    declared.
 */

void
add_candidates(CANDIDATE_LIST *p, IDENTIFIER id, int over, int kind)
{
    unsigned tag = TAG_id (id);
    switch (tag) {
	case id_function_tag :
	case id_mem_func_tag :
	case id_stat_mem_func_tag : {
	    /* Functions */
	    while (!IS_NULL_id (id)) {
			IDENTIFIER bid = DEREF_id (id_alias (id));
			add_candidate (p, id, bid, kind);
			if (!over) break;
			id = DEREF_id (id_function_etc_over (id));
	    }
	    break;
	}
	case id_builtin_tag : {
	    /* Built-in operators */
	    add_candidate (p, id, id, kind);
	    break;
	}
	case id_ambig_tag : {
	    /* Ambiguous functions */
	    LIST (IDENTIFIER) r = DEREF_list (id_ambig_ids (id));
	    if (over) over = DEREF_int (id_ambig_over (id));
	    while (!IS_NULL_list (r)) {
			IDENTIFIER rid = DEREF_id (HEAD_list (r));
			add_candidates (p, rid, over, kind);
			r = TAIL_list (r);
	    }
	    break;
	}
    }
    return;
}


/*
 *    LOOK UP A FUNCTION IN AN ARGUMENT NAMESPACE
 *
 *    This routine looks up the function id in the namespace containing the
 *    type name cid.  Any functions found are added to the candidate list p.
 */

static IDENTIFIER
koenig_id(CANDIDATE_LIST *p, IDENTIFIER id, IDENTIFIER cid, int kind)
{
    if (!IS_NULL_id (cid)) {
		NAMESPACE cns = DEREF_nspace (id_parent (cid));
		if (!IS_NULL_nspace (cns)) {
			switch (TAG_nspace (cns)) {
			case nspace_named_tag :
			case nspace_unnamed_tag :
			case nspace_global_tag : {
				/* Look up identifier in parent class */
				HASHID nm = DEREF_hashid (id_name (id));
				MEMBER mem = search_member (cns, nm, 0);
				if (!IS_NULL_member (mem)) {
					IDENTIFIER fid = DEREF_id (member_id (mem));
					if (!IS_NULL_id (fid) && !EQ_id (fid, id)) {
						add_candidates (p, fid, 1, kind);
						id = fid;
					}
				}
				break;
			}
			case nspace_ctype_tag : {
				/* Allow for nested classes */
				IDENTIFIER pid = DEREF_id (nspace_name (cns));
				id = koenig_id (p, id, pid, kind);
				break;
			}
			}
		}
    }
    return (id);
}


/*
 *    PERFORM ARGUMENT DEPENDENT NAME LOOK-UP FOR A CLASS
 *
 *    This routine performs argument dependent name look-up for the function
 *    id and the argument class type ct.
 */

static IDENTIFIER
koenig_class(CANDIDATE_LIST *p, IDENTIFIER id, CLASS_TYPE ct, int kind)
{
    TYPE form = DEREF_type (ctype_form (ct));
    if (IS_NULL_type (form)) {
		IDENTIFIER cid = DEREF_id (ctype_name (ct));
		GRAPH gr = DEREF_graph (ctype_base (ct));
		LIST (GRAPH) br = DEREF_list (graph_tails (gr));
		id = koenig_id (p, id, cid, kind);
		while (!IS_NULL_list (br)) {
			GRAPH gs = DEREF_graph (HEAD_list (br));
			CLASS_TYPE cs = DEREF_ctype (graph_head (gs));
			id = koenig_class (p, id, cs, kind);
			br = TAIL_list (br);
		}
    } else {
		id = koenig_candidates (p, id, form, kind);
    }
    return (id);
}


/*
 *    PERFORM ARGUMENT DEPENDENT NAME LOOK-UP FOR A TOKEN ARGUMENT
 *
 *    This routine performs argument dependent name look-up for the function
 *    id and the token argument tok.
 */

static IDENTIFIER
koenig_token(CANDIDATE_LIST *p, IDENTIFIER id, TOKEN tok, int kind)
{
    if (!IS_NULL_tok (tok)) {
		ASSERT (ORDER_tok == 10);
		switch (TAG_tok (tok)) {
	    case tok_type_tag : {
			TYPE t = DEREF_type (tok_type_value (tok));
			id = koenig_candidates (p, id, t, kind);
			break;
	    }
	    case tok_class_tag : {
			IDENTIFIER tid = DEREF_id (tok_class_value (tok));
			id = koenig_id (p, id, tid, kind);
			break;
	    }
		}
    }
    return (id);
}


/*
 *    PERFORM ARGUMENT DEPENDENT NAME LOOK-UP
 *
 *    This routine performs argument dependent name look-up for the function
 *    id and the argument type t, adding any candidates found to the list p.
 */

IDENTIFIER
koenig_candidates(CANDIDATE_LIST *p, IDENTIFIER id, TYPE t, int kind)
{
    if (!IS_NULL_type (t)) {
		ASSERT (ORDER_type == 18);
		switch (TAG_type (t)) {
	    case type_ptr_tag :
	    case type_ref_tag : {
			TYPE s = DEREF_type (type_ptr_etc_sub (t));
			id = koenig_candidates (p, id, s, kind);
			break;
	    }
	    case type_ptr_mem_tag : {
			CLASS_TYPE cs = DEREF_ctype (type_ptr_mem_of (t));
			TYPE s = DEREF_type (type_ptr_mem_sub (t));
			id = koenig_class (p, id, cs, kind);
			id = koenig_candidates (p, id, s, kind);
			break;
	    }
	    case type_func_tag : {
			TYPE r = DEREF_type (type_func_ret (t));
			LIST (TYPE) q = DEREF_list (type_func_ptypes (t));
			id = koenig_candidates (p, id, r, kind);
			while (!IS_NULL_list (q)) {
				TYPE s = DEREF_type (HEAD_list (q));
				id = koenig_candidates (p, id, s, kind);
				q = TAIL_list (q);
			}
			break;
	    }
	    case type_array_tag : {
			TYPE s = DEREF_type (type_array_sub (t));
			id = koenig_candidates (p, id, s, kind);
			break;
	    }
	    case type_compound_tag : {
			CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
			id = koenig_class (p, id, ct, kind);
			break;
	    }
	    case type_enumerate_tag : {
			ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t));
			IDENTIFIER eid = DEREF_id (etype_name (et));
			id = koenig_id (p, id, eid, kind);
			break;
	    }
	    case type_token_tag : {
			IDENTIFIER tid = DEREF_id (type_token_tok (t));
			LIST (TOKEN) args = DEREF_list (type_token_args (t));
			if (IS_id_token (tid)) {
				tid = DEREF_id (id_token_alt (tid));
			}
			id = koenig_id (p, id, tid, kind);
			while (!IS_NULL_list (args)) {
				TOKEN arg = DEREF_tok (HEAD_list (args));
				id = koenig_token (p, id, arg, kind);
				args = TAIL_list (args);
			}
			break;
	    }
	    case type_templ_tag : {
			TYPE s = DEREF_type (type_templ_defn (t));
			id = koenig_candidates (p, id, s, kind);
			break;
	    }
		}
    }
    return (id);
}


/*
 *    FREE A LIST OF CANDIDATES
 *
 *    This routine frees the elements of the candidate list p.
 */

void
free_candidates(CANDIDATE_LIST *p)
{
    xfree (p->elem);
    xfree (p->convs);
    p->elem = NULL;
    p->size = 0;
    p->max_size = 0;
    p->convs = NULL;
    p->nconvs = 0;
    return;
}


/*
 *    SWAP PARAMETER TYPE FIELDS FOR A FUNCTION
 *
 *    Overload resolution is based on the mtypes field of the function type.
 *    This routine can be used to force resolution on the ptypes field by
 *    swapping the two fields for the overloaded function identifier id.
 *    Note that after overload resolution the fields should be swapped back.
 */

void
swap_ptypes(IDENTIFIER id)
{
    LIST (TYPE) ptypes;
    LIST (TYPE) mtypes;
    TYPE fn = DEREF_type (id_function_etc_type (id));
    while (IS_type_templ (fn)) {
		/* Allow for template functions */
		fn = DEREF_type (type_templ_defn (fn));
    }
    ptypes = DEREF_list (type_func_ptypes (fn));
    mtypes = DEREF_list (type_func_mtypes (fn));
    if (!EQ_list (ptypes, mtypes)) {
		COPY_list (type_func_ptypes (fn), mtypes);
		COPY_list (type_func_mtypes (fn), ptypes);
    }
    return;
}


/*
 *    SWAP PARAMETER TYPE FIELDS FOR CANDIDATES FUNCTIONS
 *
 *    This routine swaps the parameter type fields for all the constructor
 *    candidates in p, starting with the nth entry.
 */

void
swap_candidates(CANDIDATE_LIST *p, unsigned n)
{
    unsigned i, m = p->size;
    for (i = n ; i < m ; i++) {
		CANDIDATE *r = p->elem + i;
		if (r->kind == KIND_CONSTR) {
			swap_ptypes (r->base);
		}
    }
    return;
}


/*
 *    LIST CANDIDATES FOR ERROR REPORTING
 *
 *    This routine appends messages listing all the candidates from the list
 *    p of rank at least rank to the end of the error message err.  No action
 *    is taken if err is the null error.
 */

ERROR
list_candidates(ERROR err, CANDIDATE_LIST *p, unsigned rank)
{
    if (!IS_NULL_err (err)) {
		ERROR err2 = ERR_over_match_viable_list ();
		if (!IS_NULL_err (err2)) {
			unsigned m = 0;
			CANDIDATE *q = p->elem;
			unsigned n = p->size;
			err = concat_error (err, err2);
			while (n) {
				CANDIDATE *r = q + (--n);
				if (r->rank >= rank) {
					/* List viable candidates */
					IDENTIFIER bid = r->base;
					DECL_SPEC ds = DEREF_dspec (id_storage (bid));
					if (!(ds & dspec_register)) {
						IDENTIFIER id = r->func;
						if (IS_id_builtin (id)) {
							/* Dump dummy built-in operators */
							if (do_dump) dump_builtin (id);
						}
						m++;
						err2 = ERR_fail_list_item (m, id, id_loc (id));
						err = concat_error (err, err2);
						ds |= dspec_register;
						COPY_dspec (id_storage (bid), ds);
					}
				}
			}
			if (m) {
				n = p->size;
				while (n) {
					/* Clear marks */
					CANDIDATE *r = q + (--n);
					IDENTIFIER bid = r->base;
					DECL_SPEC ds = DEREF_dspec (id_storage (bid));
					if (ds & dspec_register) {
						ds &= ~dspec_register;
						COPY_dspec (id_storage (bid), ds);
					}
				}
			}
			err = concat_error (err, ERR_fail_list_end (m));
		}
    }
    return (err);
}


/*
 *    OVERLOAD MATCHING INFORMATION
 *
 *    These variables are used to store information gained during overload
 *    resolution.  If match_no_args is nonzero it gives the number of
 *    candidates which take the right number of arguments, otherwise if it
 *    is zero it indicates that either there are no such functions or there
 *    is only one candidate.  Similarly match_no_viable gives the number of
 *    viable candidates (counting viable templates twice).
 */

unsigned match_no_args = 0;
unsigned match_no_viable = 0;
static unsigned viable_templates = 0;
int resolved_kind = KIND_FUNC;


/*
 *    IS A CANDIDATE FUNCTION PLAUSIBLE?
 *
 *    A candidate function is plausible for a list of arguments if it accepts
 *    that number of arguments.  This routine tests whether the candidate r
 *    is plausible.  It returns the absolute difference between the number
 *    of arguments and the number of parameters (i.e. zero for a plausible
 *    candidate).
 */

static unsigned
plausible_candidate(CANDIDATE *r, unsigned nargs)
{
    IDENTIFIER id = r->base;
    if (IS_id_builtin (id)) {
		/* Built-in candidates */
		LIST (TYPE) mtypes = DEREF_list (id_builtin_ptypes (id));
		unsigned npars = LENGTH_list (mtypes);
		if (nargs == npars) {
			/* Equal numbers of arguments and parameters */
			return (0);
		} else if (nargs > npars) {
			/* More arguments than parameters */
			return (nargs - npars);
		} else {
			/* Less arguments than parameters */
			return (npars - nargs);
		}
    } else {
		/* Function candidates */
		unsigned npars;
		LIST (TYPE) mtypes;
		TYPE fn = DEREF_type (id_function_etc_type (id));
		while (IS_type_templ (fn)) {
			/* Allow for template functions */
			fn = DEREF_type (type_templ_defn (fn));
		}
		mtypes = DEREF_list (type_func_mtypes (fn));
		npars = LENGTH_list (mtypes);
		if (nargs == npars) {
			/* Equal numbers of arguments and parameters */
			return (0);
		} else if (nargs > npars) {
			/* More arguments than parameters */
			int ell = DEREF_int (type_func_ellipsis (fn));
			if (ell) {
				/* Match with ellipsis */
				return (0);
			}
			return (nargs - npars);
		} else {
			/* Less arguments than parameters */
			unsigned margs = min_no_args (fn);
			if (nargs >= margs) {
				/* Match with default arguments */
				return (0);
			}
			return (margs - nargs);
		}
    }
    /* NOTREACHED */
}


/*
 *    INHERITANCE MATCHING FLAG
 *
 *    This flag may be set to true to make the match for the implicit
 *    this parameter for an inherited function as good as a match for
 *    a non-inherited function from the point of view of function
 *    overloading.
 */

int match_this = 0;


/*
 *    IS A PLAUSIBLE CANDIDATE FUNCTION VIABLE?
 *
 *    A plausible candidate function is viable for a list of arguments if
 *    there is an implicit conversion sequence for each argument to the
 *    corresponding parameter type.  This routine tests whether the plausible
 *    candidate r is viable, building up the corresponding list of conversions.
 *    It returns the number of arguments for which a sequence exists, plus
 *    one.
 */

static unsigned
viable_candidate(CANDIDATE *r, LIST (EXP) args, TYPE ret)
{
    TYPE rtype;
    int bind = 0;
    unsigned conv;
    unsigned match = 1;
    LIST (TYPE) mtypes;
    IDENTIFIER id = r->base;
    CONVERSION *convs = r->convs;
    HASHID nm = DEREF_hashid (id_name (id));
	
    /* Extract type information */
    if (IS_id_builtin (id)) {
		if (IS_hashid_op (nm)) {
			int op = DEREF_int (hashid_op_lex (nm));
			if (op == lex_assign) bind = 1;
		}
		mtypes = DEREF_list (id_builtin_ptypes (id));
		rtype = DEREF_type (id_builtin_ret (id));
    } else {
		LIST (TYPE) ptypes;
		TYPE fn = DEREF_type (id_function_etc_type (id));
		if (IS_type_templ (fn)) {
			/* Allow for template functions */
			ERROR err = NULL_err;
			if (r->kind == KIND_CONSTR) {
				/* Deal with swapped candidates */
				IDENTIFIER tid;
				EXP a = NULL_exp;
				LIST (EXP) dargs;
				swap_ptypes (id);
				CONS_exp (a, args, dargs);
				tid = deduce_args (id, dargs, 2, 0, 1, &err);
				DESTROY_CONS_exp (destroy, a, args, dargs);
				UNUSED (a);
				if (IS_NULL_id (tid)) {
					swap_ptypes (id);
					return (0);
				}
				swap_ptypes (tid);
				id = tid;
			} else {
				/* Deal with normal candidates */
				id = deduce_args (id, args, 2, 0, 1, &err);
				if (IS_NULL_id (id)) return (0);
			}
			fn = DEREF_type (id_function_etc_type (id));
			if (!IS_type_func (fn)) return (0);
			viable_templates++;
			r->func = id;
			r->base = id;
		}
		mtypes = DEREF_list (type_func_mtypes (fn));
		ptypes = DEREF_list (type_func_ptypes (fn));
		if (IS_hashid_constr (nm)) {
			rtype = DEREF_type (hashid_constr_type (nm));
		} else {
			rtype = DEREF_type (type_func_ret (fn));
		}
		if (!EQ_list (mtypes, ptypes)) {
			/* Member function */
			if (!IS_NULL_list (ptypes)) ptypes = TAIL_list (ptypes);
			if (EQ_list (mtypes, ptypes)) {
				/* Parameter types have been swapped */
				/* EMPTY */
			} else {
				/* Matching implicit this parameter */
				if (match_this) {
					/* Force exact match */
					bind = 2;
				} else {
					IDENTIFIER fid = r->func;
					DECL_SPEC ds = DEREF_dspec (id_storage (fid));
					if ((ds & dspec_inherit) && !(ds & dspec_alias)) {
						/* Inherited member function */
						bind = 3;
					} else {
						bind = 2;
					}
				}
			}
		}
    }
	
    /* Check for implicit conversion sequences */
    while (!IS_NULL_list (mtypes) && !IS_NULL_list (args)) {
		conv = convs->rank;
		if (conv == CONV_NONE) {
			/* Recalculate if necessary */
			EXP a = DEREF_exp (HEAD_list (args));
			TYPE t = DEREF_type (HEAD_list (mtypes));
			convs->to = t;
			if (IS_NULL_exp (a)) {
				/* A null expression counts as an exact match */
				convs->from = t;
				conv = CONV_EXACT;
			} else {
				/* Calculate conversion sequence */
				TYPE s = DEREF_type (exp_type (a));
				convs->from = s;
				if (IS_NULL_type (ret)) {
					conv = convert_seq (convs, a, bind, 0);
				} else {
					conv = std_convert_seq (convs, a, bind, 0);
				}
				convs->from = s;
				convs->to = t;
			}
		}
		if (conv != CONV_NONE) match++;
		convs->rank = conv;
		convs++;
		args = TAIL_list (args);
		mtypes = TAIL_list (mtypes);
		bind = 0;
    }
	
    /* Remaining arguments match with ellipsis */
    while (!IS_NULL_list (args)) {
		convs->rank = CONV_ELLIPSIS;
		convs++;
		match++;
		args = TAIL_list (args);
    }
	
    /* Check for return conversion sequences */
    if (!IS_NULL_type (ret)) {
		conv = convs->rank;
		if (conv == CONV_NONE) {
			convs->to = ret;
			convs->from = rtype;
			conv = std_convert_seq (convs, NULL_exp, 0, 0);
			convs->from = rtype;
			convs->to = ret;
		}
    } else {
		conv = CONV_ELLIPSIS;
    }
    convs->rank = conv;
    return (match);
}


/*
 *    COMPARE TWO FUNCTIONS
 *
 *    This routine compares the candidate functions rid and sid to determine
 *    which is better under the template specialisation rules.  It returns
 *    1 if rid is better than sid, 2 if sid is better than rid, and 0 otherwise.
 */

static int
compare_funcs(IDENTIFIER rid, IDENTIFIER sid)
{
    int res = 0;
    if (EQ_id (rid, sid)) {
		/* Select first if equal */
		res = 1;
    } else {
		if (IS_NULL_id (rid)) {
			res = 2;
		} else if (IS_NULL_id (sid)) {
			res = 1;
		} else {
			rid = find_template (rid, 0);
			sid = find_template (sid, 0);
			if (!IS_NULL_id (rid)) {
				if (!IS_NULL_id (sid)) {
					/* Both template functions */
					res = compare_specs (rid, sid);
				} else {
					/* rid is a template function */
					res = 2;
				}
			} else if (!IS_NULL_id (sid)) {
				/* sid is a template function */
				res = 1;
			}
		}
    }
    return (res);
}


/*
 *    COMPARE TWO CANDIDATE FUNCTIONS
 *
 *    This routine compares the candidate functions r and s for the argument
 *    list args and return type ret.  It returns 1 if r is better than s, 2 if
 *    s is better than r, and some other value otherwise.  Better in this
 *    sense means at least as good for all arguments, plus strictly better
 *    in at least one argument or the return type.
 */

static int
compare_candidates(CANDIDATE *r, CANDIDATE *s, LIST (EXP) args, TYPE ret)
{
    int res = 0;
    CONVERSION *cr = r->convs;
    CONVERSION *cs = s->convs;
	
    /* Compare each argument in turn */
    while (!IS_NULL_list (args)) {
		int cmp = compare_seq (cr, cs);
		if (cmp == 1) {
			/* r better in this argument */
			if (res == 2) return (0);
			res = 1;
		} else if (cmp == 2) {
			/* s better in this argument */
			if (res == 1) return (0);
			res = 2;
		}
		cr++;
		cs++;
		args = TAIL_list (args);
    }
	
    /* Tie breakers */
    if (res == 0) {
		res = compare_funcs (r->base, s->base);
		if (res == 0 && !IS_NULL_type (ret)) {
			/* Resolve on return type */
			res = compare_seq (cr, cs);
		}
    }
    return (res);
}


/*
 *    OVERLOADED FUNCTION RESOLUTION
 *
 *    This routine selects the best match from the list of overloaded function
 *    given by p based on the argument list args and the return type ret (which
 *    may be the null type).  The list of candidate functions will not be empty.
 *    If replay is true then the conversion sequences have already been
 *    calculated and only the final tournament to select the best viable
 *    candidate is necessary.
 */

CANDIDATE
*resolve_overload(CANDIDATE_LIST *p, LIST (EXP) args,
				  TYPE ret, int replay)
{
    unsigned round;
    unsigned match = 0;
    CANDIDATE *q = p->elem;
    CANDIDATE *best = q;
    CANDIDATE *beat = NULL;
    unsigned i, n = p->size;
	
    if (!replay) {
		/* Eliminate all non-viable candidates */
		unsigned nargs;
		unsigned margs;
		unsigned mconvs;
		unsigned best_margs;
		unsigned nconvs = p->nconvs;
		CONVERSION *convs = p->convs;
		
		/* Check for plausible candidates */
		nargs = LENGTH_list (args);
		best_margs = nargs + 1;
		for (i = 0 ; i < n ; i++) {
			CANDIDATE *r = q + i;
			if (r->rank != RANK_IGNORE) {
				margs = plausible_candidate (r, nargs);
				if (margs == 0) {
					/* Plausible candidate */
					r->rank = RANK_ARGS;
					best = r;
					match++;
				} else if (match == 0 && margs <= best_margs) {
					/* Most nearly plausible candidate so far */
					best_margs = margs;
					best = r;
				}
			}
		}
		match_no_args = match;
		if (match == 0) {
			/* No plausible candidates - return most nearly plausible */
			match_no_viable = 0;
			return (best);
		}
		
		/* Allocate room for conversion ranks */
		nargs++;
		mconvs = match * nargs;
		if (mconvs >= nconvs) {
			nconvs = mconvs + 200;
			convs = xrealloc (convs, sizeof(*convs) * nconvs);
			p->nconvs = nconvs;
			p->convs = convs;
		}
		
		/* Check for viable candidates */
		match = 0;
		best_margs = 0;
		viable_templates = 0;
		for (i = 0 ; i < n ; i++) {
			CANDIDATE *r = q + i;
			if (r->rank == RANK_ARGS) {
				/* Only check plausible candidates */
				unsigned m;
				r->convs = convs;
				for (m = 0 ; m < nargs ; m++) {
					convs->rank = CONV_NONE;
					convs++;
				}
				margs = viable_candidate (r, args, ret);
				if (margs == nargs) {
					/* Viable candidate */
					r->rank = RANK_VIABLE;
					best = r;
					match++;
				} else if (match == 0 && margs >= best_margs) {
					/* Most nearly viable candidate so far */
					best_margs = margs;
					best = r;
				}
			}
		}
		match_no_viable = match + viable_templates;
		if (match == 0) {
			/* No viable candidates - return most nearly viable */
			return (best);
		}
		if (match == 1) {
			/* Exactly one viable candidate - must be the winner */
			best->rank = RANK_BEST;
			return (best);
		}
    } else {
		/* Replay - pick a viable candidate */
		for (i = 0 ; i < n ; i++) {
			CANDIDATE *r = q + i;
			if (r->rank >= RANK_VIABLE) {
				r->rank = RANK_VIABLE;
				best = r;
				match++;
			}
		}
    }
	
    /* Play tournament among viable candidates */
    round = RANK_VIABLE;
    while (match > 1) {
		CANDIDATE *s = NULL;
		match = 0;
		for (i = 0 ; i < n ; i++) {
			CANDIDATE *r = q + i;
			if (r->rank == round) {
				/* Only check those through to this round */
				if (s == NULL) {
					/* r is first candidate in contest */
					s = r;
				} else {
					/* r is second candidate in contest */
					int cmp = compare_candidates (s, r, args, ret);
					if (cmp == 1) {
						/* s wins */
						s->rank = round + 1;
						r->rank = RANK_VIABLE;
						best = s;
						beat = r;
						match++;
					} else if (cmp == 2) {
						/* r wins */
						r->rank = round + 1;
						s->rank = RANK_VIABLE;
						best = r;
						beat = s;
						match++;
					} else {
						/* Draw - both eliminated */
						s->rank = RANK_VIABLE;
						r->rank = RANK_VIABLE;
					}
					s = NULL;
				}
			}
		}
		if (s != NULL) {
			/* Bye - s goes through */
			s->rank = round + 1;
			best = s;
			match++;
		}
		round++;
    }
	
    /* Examine the tournament winner */
    if (match == 1) {
		/* Tournament winner must now beat all the others */
		best->rank = RANK_BEST;
		for (i = 0 ; i < n ; i++) {
			CANDIDATE *r = q + i;
			if (r->rank >= RANK_VIABLE) {
				if (r == best) {
					/* Don't compare against self */
					/* EMPTY */
				} else if (r == beat) {
					/* This has already been beaten */
					/* EMPTY */
				} else {
					int cmp = compare_candidates (best, r, args, ret);
					if (cmp != 1) {
						/* r is at least as good as best */
						best->rank = RANK_VIABLE;
						break;
					}
				}
			}
		}
    } else {
		/* No clear tournament winner */
		if (best->rank >= RANK_VIABLE) best->rank = RANK_VIABLE;
    }
    return (best);
}


/*
 *    FIND A LIST OF POSSIBLE TYPE VALUES
 *
 *    This routine constructs a list of the possible resolutions for the
 *    target dependent type t or its promotion.  In the latter case prom
 *    is set to true.  If neither t or its promotion is target dependent
 *    then the empty list is returned.
 */

static LIST (TYPE)
possible_types(TYPE t, int *prom)
{
    LIST (TYPE) r = NULL_list (TYPE);
    switch (TAG_type (t)) {
	case type_integer_tag : {
	    /* Integral type */
	    INT_TYPE it = DEREF_itype (type_integer_rep (t));
	    r = DEREF_list (itype_cases (it));
	    if (LENGTH_list (r) == 1) {
			/* Type is not target dependent */
			t = DEREF_type (itype_prom (it));
			it = DEREF_itype (type_integer_rep (t));
			r = DEREF_list (itype_cases (it));
			if (LENGTH_list (r) == 1) {
				/* Promoted type is not target dependent */
				r = NULL_list (TYPE);
			} else {
				*prom = 1;
			}
	    }
	    break;
	}
	case type_bitfield_tag :
	case type_enumerate_tag : {
	    /* Enumeration and bitfield types */
	    t = promote_type (t);
	    r = possible_types (t, prom);
	    *prom = 1;
	    break;
	}
    }
    return (r);
}


/*
 *    CHECK FOR TARGET DEPENDENT OVERLOADED FUNCTION RESOLUTIONS
 *
 *    This routine is called when an ambiguous overload resolution is
 *    detected to determine which of the viable candidates to proceed with.
 *    The parameters are as in resolve_overload.
 */

CANDIDATE
*resolve_ambiguous(CANDIDATE_LIST *p, LIST (EXP) args,
				   TYPE ret, int depth)
{
    CANDIDATE *q = p->elem;
    CANDIDATE *best = q;
    unsigned i, n = p->size;
    unsigned overall_rank = RANK_VIABLE;
	
    /* Check for arguments of error type */
    if (depth == 0) {
		LIST (EXP) a = args;
		while (!IS_NULL_list (a)) {
			EXP e = DEREF_exp (HEAD_list (a));
			if (!IS_NULL_exp (e)) {
				TYPE t = DEREF_type (exp_type (e));
				if (IS_type_error (t)) {
					/* Error types are ignored */
					overall_rank = RANK_BEST;
					break;
				}
			}
			a = TAIL_list (a);
		}
    }
	
    /* Check for target dependent resolutions */
    if (overall_rank != RANK_BEST) {
		unsigned na = 0;
		LIST (EXP) a = args;
		EXP saved [100];
		EXP *save = saved;
		if (n >= 100) save = xmalloc_nof (EXP, n);
		for (i = 0 ; i < n ; i++) save [i] = NULL_exp;
		while (!IS_NULL_list (a)) {
			EXP e = DEREF_exp (HEAD_list (a));
			if (!IS_NULL_exp (e)) {
				int prom = 0;
				int have_match = 0;
				TYPE t = DEREF_type (exp_type (e));
				LIST (TYPE) pt = possible_types (t, &prom);
				if (!IS_NULL_list (pt)) {
					CANDIDATE *r;
					LIST (TYPE) ps = pt;
					unsigned new_rank = RANK_TARGET;
					if (prom) {
						/* Only use promoted types if no exact match */
						for (i = 0 ; i < n ; i++) {
							r = q + i;
							if (r->rank >= RANK_VIABLE) {
								if (r->convs [ na ].rank == CONV_EXACT) {
									ps = NULL_list (TYPE);
									new_rank = overall_rank;
									break;
								}
							}
						}
					}
					overall_rank = new_rank;
					while (!IS_NULL_list (ps)) {
						TYPE u = t;
						TYPE s = DEREF_type (HEAD_list (ps));
						COPY_type (exp_type (e), s);
						for (i = 0 ; i < n ; i++) {
							r = q + i;
							if (r->rank >= RANK_VIABLE) {
								/* Recalculate conversions */
								r->convs [ na ].rank = CONV_NONE;
								IGNORE viable_candidate (r, args, ret);
								r->rank = RANK_VIABLE;
							}
						}
						r = resolve_overload (p, args, ret, 1);
						if (r->rank == RANK_VIABLE) {
							/* Check further arguments */
							for (i = 0 ; i < n ; i++) {
								/* Save conditions */
								save [i] = q [i].cond;
								q [i].cond = NULL_exp;
							}
							r = resolve_ambiguous (p, args, ret, 1);
							for (i = 0 ; i < n ; i++) {
								/* Restore conditions */
								EXP c = q [i].cond;
								q [i].cond = save [i];
								save [i] = c;
							}
						}
						COPY_type (exp_type (e), t);
						if (r->rank >= RANK_TARGET) {
							/* Create condition for resolution */
							if (prom) u = promote_type (u);
							for (i = 0 ; i < n ; i++) {
								r = q + i;
								if (r->rank >= RANK_TARGET) {
									EXP c1, c2;
									TYPE ti = type_sint;
									TYPE tb = type_bool;
									NTEST nt = ntest_eq;
									MAKE_exp_rtti_no (ti, u, c1);
									MAKE_exp_rtti_no (ti, s, c2);
									MAKE_exp_compare (tb, nt, c1, c2, c1);
									c2 = save [i];
									if (!IS_NULL_exp (c2)) {
										MAKE_exp_log_and (tb, c1, c2, c1);
									}
									c2 = r->cond;
									if (!IS_NULL_exp (c2)) {
										MAKE_exp_log_or (tb, c1, c2, c1);
									}
									r->cond = c1;
									have_match = 1;
								}
								save [i] = NULL_exp;
							}
						} else if (option (OPT_overload_strict)) {
							/* Don't have match in all cases */
							have_match = 0;
							break;
						}
						ps = TAIL_list (ps);
					}
					if (!have_match) {
						overall_rank = RANK_VIABLE;
						break;
					}
				}
			}
			a = TAIL_list (a);
			na++;
		}
		if (save != saved) xfree (save);
    }
	
    /* Select last viable candidate */
    for (i = 0 ; i < n ; i++) {
		CANDIDATE *r = q + i;
		if (r->rank >= RANK_VIABLE) {
			if (overall_rank == RANK_TARGET) {
				if (IS_NULL_exp (r->cond)) {
					if (depth == 0) r->rank = RANK_ARGS;
				} else {
					r->rank = overall_rank;
					best = r;
				}
			} else {
				r->rank = overall_rank;
				best = r;
			}
		}
    }
    return (best);
}


/*
 *    LIST OF ALL AMBIGUOUS OVERLOADED FUNCTIONS
 *
 *    This list is used to hold all the dummy tokenised functions constructed
 *    to represent target dependent overload resolutions.  The functions are
 *    determined by the list of candidates, the list of argument types and
 *    the qualifier used.
 */

typedef struct ambig_func_tag {
    IDENTIFIER id;
    LIST (IDENTIFIER) funcs;
    LIST (TYPE) types;
    QUALIFIER qual;
    struct ambig_func_tag *next;
} AMBIG_FUNCTION;

static AMBIG_FUNCTION *all_ambig_funcs = NULL;


/*
 *    FIND A PREVIOUS AMBIGUOUS OVERLOADED FUNCTION
 *
 *    This routine searches the list of all ambiguous overloaded functions
 *    for one which candidate functions p, argument types q and qualifier
 *    qual.
 */

static IDENTIFIER
previous_ambig_func(LIST (IDENTIFIER) p, LIST (TYPE) q, QUALIFIER qual)
{
    AMBIG_FUNCTION *f = all_ambig_funcs;
    if (f) {
		unsigned np = LENGTH_list (p);
		unsigned nq = LENGTH_list (q);
		while (f != NULL) {
			if (f->qual == qual) {
				int ok = 1;
				LIST (IDENTIFIER) pf = f->funcs;
				LIST (TYPE) qf = f->types;
				if (LENGTH_list (pf) == np) {
					LIST (IDENTIFIER) pg = p;
					while (!IS_NULL_list (pg)) {
						IDENTIFIER nf = DEREF_id (HEAD_list (pf));
						IDENTIFIER ng = DEREF_id (HEAD_list (pg));
						if (!EQ_id (nf, ng)) {
							ok = 0;
							break;
						}
						pf = TAIL_list (pf);
						pg = TAIL_list (pg);
					}
				}
				if (ok && LENGTH_list (qf) == nq) {
					LIST (TYPE) qg = q;
					while (!IS_NULL_list (qg)) {
						TYPE tf = DEREF_type (HEAD_list (qf));
						TYPE tg = DEREF_type (HEAD_list (qg));
						if (!eq_type (tf, tg)) {
							ok = 0;
							break;
						}
						qf = TAIL_list (qf);
						qg = TAIL_list (qg);
					}
				}
				if (ok) return (f->id);
			}
			f = f->next;
		}
    }
    return (NULL_id);
}


/*
 *    CONSTRUCT AN AMBIGUOUS OVERLOADED FUNCTION
 *
 *    This routine constructs a dummy tokenised function to represent the
 *    target dependent overload resolution given by the candidates p for
 *    the function call 'id (args)' detected by the previous call to
 *    resolve_ambiguous.  Any errors arising are added to err.
 */

IDENTIFIER
make_ambig_func(CANDIDATE_LIST *p, IDENTIFIER id, LIST (EXP) args,
				QUALIFIER qual, ERROR *err)
{
    EXP res;
    TYPE fn;
    TOKEN tok;
    TYPE form;
    MEMBER mem;
    DECL_SPEC ds;
    IDENTIFIER tid;
    LIST (TYPE) mt;
    AMBIG_FUNCTION *all;
    TYPE ret = NULL_type;
    TYPE et = type_error;
    CANDIDATE *q = p->elem;
    unsigned i, n = p->size;
    NAMESPACE ns = crt_namespace;
    QUALIFIER cq = crt_id_qualifier;
    int tq = crt_templ_qualifier;
    int td = have_type_declaration;
    unsigned tag = id_function_tag;
    HASHID nm = DEREF_hashid (id_name (id));
	
    /* List of viable candidates */
    LIST (EXP) conds = NULL_list (EXP);
    LIST (TYPE) types = NULL_list (TYPE);
    LIST (IDENTIFIER) funcs = NULL_list (IDENTIFIER);
	
    /* Check function return types */
    for (i = 0 ; i < n ; i++) {
		CANDIDATE *r = q + i;
		if (r->rank >= RANK_VIABLE) {
			int suspect = 0;
			TYPE ta = NULL_type;
			IDENTIFIER fid = r->base;
			switch (TAG_id (fid)) {
			case id_builtin_tag : {
				ta = DEREF_type (id_builtin_ret (fid));
				break;
			}
			case id_function_tag : {
				TYPE fa = DEREF_type (id_function_type (fid));
				if (IS_type_func (fa)) {
					ta = DEREF_type (type_func_ret (fa));
				}
				break;
			}
			case id_mem_func_tag : {
				TYPE fa = DEREF_type (id_mem_func_type (fid));
				if (IS_type_func (fa)) {
					HASHID fnm = DEREF_hashid (id_name (fid));
					mt = DEREF_list (type_func_mtypes (fa));
					et = DEREF_type (HEAD_list (mt));
					if (IS_hashid_constr (fnm)) {
						ta = DEREF_type (hashid_constr_type (fnm));
					} else {
						ta = DEREF_type (type_func_ret (fa));
						tag = id_mem_func_tag;
					}
				}
				break;
			}
			case id_stat_mem_func_tag : {
				TYPE fa = DEREF_type (id_stat_mem_func_type (fid));
				if (IS_type_func (fa)) {
					mt = DEREF_list (type_func_mtypes (fa));
					et = DEREF_type (HEAD_list (mt));
					ta = DEREF_type (type_func_ret (fa));
					if (tag != id_mem_func_tag) {
						tag = id_stat_mem_func_tag;
					}
				}
				break;
			}
			}
			ret = common_type (ret, ta, &suspect);
			if (suspect) ret = NULL_type;
			CONS_exp (r->cond, conds, conds);
			CONS_id (fid, funcs, funcs);
		}
    }
    if (IS_NULL_type (ret)) {
		/* Couldn't bring return types to common type */
		ERROR err2 = ERR_over_match_best_common ();
		add_error (err, err2);
		ret = type_error;
    }
    if (err != KILL_err) {
		*err = list_candidates (*err, p, RANK_VIABLE);
    }
	
    /* Create list of argument types */
    while (!IS_NULL_list (args)) {
		TYPE t;
		EXP e = DEREF_exp (HEAD_list (args));
		if (IS_NULL_exp (e)) {
			t = et;
			et = type_error;
		} else {
			t = DEREF_type (exp_type (e));
			if (IS_type_bitfield (t)) {
				t = promote_type (t);
			} else {
				CV_SPEC cv = DEREF_cv (type_qual (t));
				if (cv & cv_lvalue) {
					MAKE_type_ref (cv_none, t, t);
				}
			}
		}
		CONS_type (t, types, types);
		args = TAIL_list (args);
    }
    types = REVERSE_list (types);
	
    /* Check for previous instance */
    tid = previous_ambig_func (funcs, types, qual);
    if (!IS_NULL_id (tid)) {
		DESTROY_list (funcs, SIZE_id);
		DESTROY_list (types, SIZE_type);
		free_exp_list (conds, 1);
		return (tid);
    }
	
    /* Create new instance */
    all = xmalloc (sizeof(*all));
    all->id = NULL_id;
    all->funcs = funcs;
    all->types = types;
    all->qual = qual;
    all->next = all_ambig_funcs;
    all_ambig_funcs = all;
	
    /* Scan through argument types */
    crt_id_qualifier = qual_none;
    crt_templ_qualifier = 0;
    have_type_declaration = TYPE_DECL_NONE;
    decl_loc = crt_loc;
    begin_param (id);
    mt = types;
    while (!IS_NULL_list (mt)) {
		HASHID pnm = lookup_anon ();
		IDENTIFIER pid = DEREF_id (hashid_id (pnm));
		TYPE t = DEREF_type (HEAD_list (mt));
		pid = make_param_decl (dspec_none, t, pid, CONTEXT_PARAMETER);
		init_param (pid, NULL_exp);
		mt = TAIL_list (mt);
    }
    fn = make_func_type (ret, FUNC_NONE, cv_none, empty_type_set);
    if (tag != id_function_tag) {
		mt = DEREF_list (type_func_ptypes (fn));
		mt = TAIL_list (mt);
		COPY_list (type_func_ptypes (fn), mt);
    }
    end_param ();
	
    /* Create a function identifier */
    ds = (dspec_static | dspec_token | dspec_reserve);
    MAKE_id_function_etc (tag, nm, ds, ns, crt_loc, fn, NULL_id, id);
	
    /* Create token identifier */
    ns = token_namespace;
    nm = lookup_anon ();
    mem = search_member (ns, nm, 1);
    MAKE_tok_func (fn, tok);
    MAKE_id_token (nm, ds, ns, crt_loc, tok, id, tid);
    MAKE_type_token (cv_none, tid, NULL_list (TOKEN), form);
    COPY_type (id_function_etc_form (id), form);
    set_member (mem, tid);
    tok = func_proc_token (tok);
	
    /* Define token */
    res = install_error (&crt_loc, ERR_over_match_best_install ());
    while (!IS_NULL_list (funcs)) {
		EXP c, f;
		LIST (EXP) fargs = NULL_list (EXP);
		LIST (IDENTIFIER) pids = DEREF_list (tok_proc_bids (tok));
		IDENTIFIER fid = DEREF_id (HEAD_list (funcs));
		DESTROY_CONS_exp (destroy, c, conds, conds);
		while (!IS_NULL_list (pids)) {
			/* Build up argument list */
			TYPE t;
			int prom = 0;
			LIST (TYPE) pt;
			IDENTIFIER pid = DEREF_id (HEAD_list (pids));
			EXP e = apply_exp_token (pid, NULL_list (TOKEN), 0);
			e = convert_reference (e, REF_NORMAL);
			t = DEREF_type (exp_type (e));
			pt = possible_types (t, &prom);
			if (!IS_NULL_list (pt)) {
				/* Mark target dependent arguments */
				MAKE_exp_paren (t, e, e);
			}
			CONS_exp (e, fargs, fargs);
			pids = TAIL_list (pids);
		}
		fargs = REVERSE_list (fargs);
		if (IS_id_builtin (fid)) {
			f = apply_builtin (fid, fargs);
		} else {
			HASHID fnm = DEREF_hashid (id_name (fid));
			use_func_id (fid, 1, 0);
			if (IS_hashid_constr (fnm)) {
				f = apply_constr (fid, fargs);
			} else {
				f = apply_func_id (fid, qual, NULL_graph, fargs);
			}
		}
		if (!IS_type_top_etc (ret)) {
			/* Convert to common return type */
			ERROR err2 = NULL_err;
			f = convert_reference (f, REF_ASSIGN);
			f = cast_exp (ret, f, &err2, CAST_IMPLICIT);
			if (!IS_NULL_err (err2)) report (crt_loc, err2);
		}
		if (IS_NULL_exp (res)) {
			free_exp (c, 1);
			res = f;
		} else {
			MAKE_exp_hash_if (ret, c, f, res, res);
		}
		funcs = TAIL_list (funcs);
    }
    IGNORE define_exp_token (tid, res, 1);
	
    /* Restore previous state */
    have_type_declaration = td;
    crt_templ_qualifier = tq;
    crt_id_qualifier = cq;
    all->id = id;
    return (id);
}


/*
 *    IS AN IDENTIFIER A FUNCTION TEMPLATE?
 *
 *    This routine returns true if id is a function template.  In this case
 *    overload resolution is always done even if id is not overloaded.
 */

static int
is_template_func(IDENTIFIER id)
{
    if (IS_id_function_etc (id)) {
		TYPE fn = DEREF_type (id_function_etc_type (id));
		if (IS_type_templ (fn)) return (1);
    }
    return (0);
}


/*
 *    RESOLVE AN OVERLOADED FUNCTION CALL
 *
 *    This routine resolves the overloaded function call 'id (args)' where
 *    id is an identifier expression.  dep is true when id is a simple
 *    unqualified function name.  It returns the identifier for id which
 *    provides the best match for the given arguments.  For ambiguities the
 *    identifier returned is the first of the viable functions to be declared
 *    (this is a side effect of the algorithm in resolve_overload and the
 *    way in which overloaded functions are represented).
 */

IDENTIFIER
resolve_call(IDENTIFIER id, LIST (EXP) args, QUALIFIER qual, int dep)
{
    /* Build up candidate list */
    unsigned sz;
    IDENTIFIER fid = id;
    CANDIDATE_LIST *p = &candidates;
    p->size = 0;
    if (dep) {
		/* Allow for argument dependent look-up */
		LIST (EXP) q = args;
		while (!IS_NULL_list (q)) {
			EXP a = DEREF_exp (HEAD_list (q));
			if (!IS_NULL_exp (a)) {
				TYPE t = DEREF_type (exp_type (a));
				IGNORE koenig_candidates (p, fid, t, KIND_FUNC);
			}
			q = TAIL_list (q);
		}
    }
    add_candidates (p, fid, 1, KIND_FUNC);
    sz = p->size;
    if (sz == 0) {
		/* No candidates */
		EXP a;
		int fn = 2;
		QUALIFIER cq = crt_id_qualifier;
		crt_id_qualifier = (qual & qual_explicit);
		if (qual & qual_mark) fn = 1;
		a = implicit_id_exp (fid, fn);
		if (IS_exp_identifier_etc (a)) {
			fid = DEREF_id (exp_identifier_etc_id (a));
			add_candidates (p, fid, 1, KIND_FUNC);
			sz = p->size;
			if (sz != 0) fid = p->elem [0].func;
		}
		crt_id_qualifier = cq;
    } else {
		fid = p->elem [0].func;
    }
	
    /* Resolve overloaded functions */
    if (sz > 1) {
		CANDIDATE *q = resolve_overload (p, args, NULL_type, 0);
		IDENTIFIER qid = q->func;
		unsigned rank = q->rank;
		int kind = q->kind;
		if (rank == RANK_BEST) {
			/* Unambiguous resolution */
			if (match_no_viable > 1) {
				ERROR err = ERR_over_match_call_ok (qid);
				if (!IS_NULL_err (err)) report (crt_loc, err);
			}
		} else if (rank == RANK_VIABLE) {
			/* Ambiguous resolution */
			q = resolve_ambiguous (p, args, NULL_type, 0);
			qid = q->func;
			rank = q->rank;
			if (rank == RANK_TARGET) {
				ERROR err = ERR_over_match_call_target (id);
				qid = make_ambig_func (p, qid, args, qual, &err);
				kind = KIND_FUNC;
				report (crt_loc, err);
			} else if (rank == RANK_VIABLE) {
				ERROR err = ERR_over_match_call_ambig (id);
				err = list_candidates (err, p, RANK_VIABLE);
				report (crt_loc, err);
			}
		} else {
			/* Unviable resolution */
			report (crt_loc, ERR_over_match_viable_none (id));
		}
		resolved_kind = kind;
		return (qid);
    }
	
    /* Check template functions */
    if (is_template_func (fid)) {
		ERROR err = NULL_err;
		IDENTIFIER qid = deduce_args (fid, args, 2, 0, 1, &err);
		if (IS_NULL_id (qid)) {
			/* No viable resolution */
			err = concat_error (err, ERR_over_match_viable_none (id));
			qid = fid;
		}
		if (!IS_NULL_err (err)) {
			/* Report any argument deduction errors */
			err = concat_error (err, ERR_temp_deduct_fail (id));
			report (crt_loc, err);
		} else {
			/* Successful argument deduction */
			report (crt_loc, ERR_over_match_call_ok (qid));
		}
		fid = qid;
    }
	
    /* Don't check non-overloaded functions */
    match_no_args = 0;
    match_no_viable = 0;
    resolved_kind = KIND_FUNC;
    return (fid);
}


/*
 *    RESOLVE AN AMBIGUOUS FUNCTION ADDRESS
 *
 *    This routine resolves the list of functions ids to see which is the
 *    best under the template specialisation rules.  If no one best candidate
 *    is found the null identifier is returned.  This rule is not actually
 *    in ISO C++, but it could have been.
 */

static IDENTIFIER
resolve_ambig_func(LIST (IDENTIFIER) ids, int depth)
{
    if (!IS_NULL_list (ids)) {
		int cmp;
		IDENTIFIER rid, sid;
		LIST (IDENTIFIER) pids = ids;
		
		/* Find the first two functions */
		rid = DEREF_id (HEAD_list (pids));
		pids = TAIL_list (pids);
		if (IS_NULL_list (pids)) return (rid);
		sid = DEREF_id (HEAD_list (pids));
		pids = TAIL_list (pids);
		
		/* Compare them */
		cmp = compare_funcs (rid, sid);
		if (cmp == 2) {
			rid = sid;
		} else if (cmp != 1) {
			rid = NULL_id;
		}
		
		/* Compare the winner against the best of the rest */
		sid = resolve_ambig_func (pids, depth + 1);
		cmp = compare_funcs (rid, sid);
		if (cmp == 2) {
			rid = sid;
		} else if (cmp != 1) {
			rid = NULL_id;
		}
		
		/* Check overall winner */
		if (depth == 0 && !IS_NULL_id (rid)) {
			pids = ids;
			while (!IS_NULL_list (pids)) {
				sid = DEREF_id (HEAD_list (pids));
				if (!EQ_id (rid, sid)) {
					cmp = compare_funcs (rid, sid);
					if (cmp != 1) return (NULL_id);
				}
				pids = TAIL_list (pids);
			}
		}
		return (rid);
    }
    return (NULL_id);
}


/*
 *    FIND AN OVERLOADED FUNCTION OF A GIVEN TYPE
 *
 *    This routine returns whichever of the set of overloaded or ambiguous
 *    functions id has type t.  Type deduction is allowed for the template
 *    parameters pids if templ is true. The null identifier is returned if
 *    none has the correct type, an ambiguous identifier is returned if
 *    more than one has the correct type (although overload resolution
 *    occurs if res is true).  If there is a match ignoring linkage
 *    specifiers then this is returned, the value of eq_func_type for the
 *    result is assigned to peq.
 */

IDENTIFIER
resolve_func(IDENTIFIER id, TYPE t, int templ, int res, LIST (IDENTIFIER) pids,
			 int *peq)
{
    int best = 2;
    IDENTIFIER rid = NULL_id;
    switch (TAG_id (id)) {
		
	case id_function_tag :
	case id_mem_func_tag :
	case id_stat_mem_func_tag : {
	    /* Check overloaded functions */
	    IDENTIFIER fid = id;
	    int have_templates = 0;
	    LIST (IDENTIFIER) rids = NULL_list (IDENTIFIER);
	    while (!IS_NULL_id (fid)) {
			TYPE s;
			int d = 0;
			int eq = 0;
			IDENTIFIER tid = fid;
			if (!IS_NULL_list (pids)) {
				/* Save template parameter values */
				d = save_token_args (pids, NULL_list (TOKEN));
			}
			s = DEREF_type (id_function_etc_type (fid));
			if (IS_type_templ (s) && templ) {
				/* Template functions */
				tid = deduce_func (tid, t, &eq);
				if (!IS_NULL_id (tid)) have_templates = 1;
			} else {
				/* Simple functions */
#if LANGUAGE_CPP
				eq = eq_func_type (s, t, 1, 0);
#else
				TYPE r = type_composite (s, t, 1, 0, KILL_err, 0);
				if (!IS_NULL_type (r)) eq = 3;
#endif
			}
			if (eq >= best) {
				if (eq > best) {
					/* Better match than previous */
					if (!IS_NULL_list (rids)) {
						DESTROY_list (rids, SIZE_id);
						rids = NULL_list (IDENTIFIER);
					}
					rid = NULL_id;
					best = eq;
				}
				if (!IS_NULL_id (rid)) {
					CONS_id (rid, rids, rids);
				}
				rid = tid;
			}
			if (!IS_NULL_list (pids)) {
				/* Restore template parameters */
				restore_token_args (pids, d);
			}
			fid = DEREF_id (id_function_etc_over (fid));
	    }
	    if (!IS_NULL_list (rids)) {
			/* Construct ambiguous result */
			HASHID nm;
			NAMESPACE ns;
			DECL_SPEC ds;
			CONS_id (rid, rids, rids);
			if (have_templates && res) {
				/* Perform overload resolution */
				rid = resolve_ambig_func (rids, 0);
				if (!IS_NULL_id (rid)) {
					DESTROY_list (rids, SIZE_id);
					break;
				}
			}
			nm = DEREF_hashid (id_name (id));
			ns = DEREF_nspace (id_parent (id));
			ds = find_ambig_dspec (rids);
			MAKE_id_ambig (nm, ds, ns, crt_loc, rids, 0, rid);
	    }
	    break;
	}
		
	case id_ambig_tag : {
	    /* Check ambiguous functions */
	    LIST (IDENTIFIER) rids = NULL_list (IDENTIFIER);
	    LIST (IDENTIFIER) p = DEREF_list (id_ambig_ids (id));
	    while (!IS_NULL_list (p)) {
			int eq = 0;
			IDENTIFIER pid = DEREF_id (HEAD_list (p));
			pid = resolve_func (pid, t, templ, 0, pids, &eq);
			if (!IS_NULL_id (pid) && eq >= best) {
				if (eq > best) {
					/* Better match than previous */
					if (!IS_NULL_list (rids)) {
						DESTROY_list (rids, SIZE_id);
						rids = NULL_list (IDENTIFIER);
					}
					rid = NULL_id;
					best = eq;
				}
				if (IS_id_ambig (pid)) {
					LIST (IDENTIFIER) q;
					q = DEREF_list (id_ambig_ids (pid));
					while (!IS_NULL_list (q)) {
						pid = DEREF_id (HEAD_list (q));
						if (!IS_NULL_id (rid)) {
							CONS_id (rid, rids, rids);
						}
						rid = pid;
						q = TAIL_list (q);
					}
				} else {
					if (!IS_NULL_id (rid)) {
						CONS_id (rid, rids, rids);
					}
					rid = pid;
				}
			}
			p = TAIL_list (p);
	    }
	    if (!IS_NULL_list (rids)) {
			HASHID nm;
			NAMESPACE ns;
			DECL_SPEC ds;
			CONS_id (rid, rids, rids);
			if (res) {
				/* Perform overload resolution */
				rid = resolve_ambig_func (rids, 0);
				if (!IS_NULL_id (rid)) {
					DESTROY_list (rids, SIZE_id);
					break;
				}
			}
			nm = DEREF_hashid (id_name (id));
			ns = DEREF_nspace (id_parent (id));
			ds = find_ambig_dspec (rids);
			MAKE_id_ambig (nm, ds, ns, crt_loc, rids, 0, rid);
	    }
	    break;
	}
    }
    if (IS_NULL_id (rid)) best = 0;
    *peq = best;
    return (rid);
}


/*
 *    CREATE A RESOLVED OVERLOADED FUNCTION EXPRESSION
 *
 *    This routine creates a resolved overloaded function expression for
 *    the function id.
 */

static EXP
make_resolved_exp(IDENTIFIER id, QUALIFIER q, EXP b, int addr, int paren)
{
    EXP e;
    TYPE fn = DEREF_type (id_function_etc_type (id));
    if (IS_id_mem_func (id)) {
		if (!IS_NULL_exp (b)) {
			report (crt_loc, ERR_expr_ref_call ());
			q = qual_nested;
		}
		MAKE_exp_member (fn, id, q, e);
    } else {
		MAKE_exp_identifier (fn, id, q, e);
		if (!IS_NULL_exp (b)) e = join_exp (b, e);
    }
    if (addr) {
		if (paren) e = make_paren_exp (e);
		e = make_ref_exp (e, 1);
    }
    return (e);
}


/*
 *    RESOLVE THE ADDRESS OF AN OVERLOADED FUNCTION
 *
 *    This routine checks the conversion of the expression e to type t.  If
 *    e is an overloaded function identifier expression and t is a function
 *    type, or pointer to function type, or pointer to member function type,
 *    then the various versions of e are checked for the one which matches
 *    the function type underlying t in the context of the template
 *    parameters pids.  An error is added to err if this does not exist.
 *    The result is the appropriate version of e.  Note that member
 *    expressions which resolve to static function members are replaced
 *    by identifier expressions at this stage (see make_id_exp).
 */

EXP
resolve_cast(TYPE t, EXP e, ERROR *err, int use, int rescan,
			 LIST (IDENTIFIER) pids)
{
    /* Check for identifier expressions */
    EXP a = e;
    QUALIFIER q;
    int addr = 0;
    int paren = 0;
    IDENTIFIER id;
    EXP b = NULL_exp;
    unsigned tag = TAG_exp (a);
    while (tag == exp_paren_tag) {
		a = DEREF_exp (exp_paren_arg (a));
		tag = TAG_exp (a);
    }
    if (tag == exp_address_tag) {
		/* Address expression */
		a = DEREF_exp (exp_address_arg (a));
		tag = TAG_exp (a);
		addr = 1;
    } else if (tag == exp_address_mem_tag) {
		/* Address of member expression */
		paren = DEREF_int (exp_address_mem_paren (a));
		a = DEREF_exp (exp_address_mem_arg (a));
		tag = TAG_exp (a);
		addr = 1;
    } else if (tag == exp_op_tag) {
		/* Check for undetermined address expressions */
		int op = DEREF_int (exp_op_lex (a));
		EXP c = DEREF_exp (exp_op_arg2 (a));
		if (op == lex_and_H1 && IS_NULL_exp (c)) {
			a = DEREF_exp (exp_op_arg1 (a));
			tag = TAG_exp (a);
			addr = 1;
		}
    }
    while (tag == exp_paren_tag) {
		a = DEREF_exp (exp_paren_arg (a));
		paren = 1;
		tag = TAG_exp (a);
    }
    if (tag == exp_call_tag) {
		/* Member reference expression */
		b = DEREF_exp (exp_call_arg (a));
		a = DEREF_exp (exp_call_ptr (a));
    }
    if (!IS_exp_identifier_etc (a)) {
		/* Not an identifier expression */
		return (e);
    }
	
    /* Mark identifiers as resolved */
    id = DEREF_id (exp_identifier_etc_id (a));
    q = DEREF_qual (exp_identifier_etc_qual (a));
    if (q & qual_mark) return (e);
    if (rescan) {
		/* Rescan function name if necessary */
		id = rescan_func_id (id, q);
    }
    q |= qual_mark;
	
    /* Check for overloaded functions */
    tag = TAG_id (id);
    switch (tag) {
		
	case id_function_tag :
	case id_mem_func_tag :
	case id_stat_mem_func_tag :
		function_lab : {
			/* Check functions for overloading */
			TYPE s;
			IDENTIFIER over;
			if (rescan) goto overload_lab;
			if (dependent_cast (id, t)) {
				/* Allow for template parameters */
				if (!IS_type_func (t)) t = rvalue_type (t);
				MAKE_exp_op (t, lex_function, e, NULL_exp, e);
				return (e);
			}
			over = DEREF_id (id_function_etc_over (id));
			if (!IS_NULL_id (over)) goto overload_lab;
			s = DEREF_type (id_function_etc_type (id));
			if (IS_type_templ (s)) goto overload_lab;
			if (tag == id_mem_func_tag) {
				if (!IS_NULL_exp (b) || addr) {
					/* Force error in this case */
					e = make_resolved_exp (id, q, b, addr, paren);
				}
			}
			if (use) {
				COPY_qual (exp_identifier_etc_qual (a), q);
				use_id (id, suppress_usage);
			}
			break;
		}
		
	case id_ambig_tag :
	case id_undef_tag :
		overload_lab : {
			/* Overloaded and ambiguous functions */
			TYPE fn = find_func_type (t);
			if (!IS_NULL_type (fn)) {
				/* Overload resolution */
				int eq = 0;
				IDENTIFIER rid;
				if (dependent_cast (id, t)) {
					/* Allow for template parameters */
					if (!IS_type_func (t)) t = rvalue_type (t);
					MAKE_exp_op (t, lex_function, e, NULL_exp, e);
					return (e);
				}
				if (tag == id_undef_tag) goto default_lab;
				rid = resolve_func (id, fn, 1, 0, pids, &eq);
				if (!IS_NULL_id (rid)) {
					if (IS_id_ambig (rid)) {
						/* Ambiguous resolution */
						if (use) {
							/* Select one function */
							LIST (IDENTIFIER) ids;
							IGNORE report_ambiguous (rid, 0, 0, 0);
							ids = DEREF_list (id_ambig_ids (rid));
							rid = resolve_ambig_func (ids, 0);
							if (IS_NULL_id (rid)) {
								rid = DEREF_id (HEAD_list (ids));
							}
						} else {
							e = NULL_exp;
							rid = NULL_id;
						}
					}
					if (!IS_NULL_id (rid)) {
						/* Unique resolution */
						report (crt_loc, ERR_over_over_ok (rid));
						e = make_resolved_exp (rid, q, b, addr, paren);
						if (use) use_id (rid, suppress_usage);
					}
				} else {
					/* Unsuccessful resolution */
					if (use) {
						add_error (err, ERR_over_over_none (id, fn));
						e = make_error_exp (0);
					} else {
						e = NULL_exp;
					}
				}
			} else {
				/* No context for resolution */
				if (tag == id_undef_tag) goto default_lab;
				if (use) {
					add_error (err, ERR_over_over_context (id));
					e = make_error_exp (0);
				} else {
					e = NULL_exp;
				}
			}
			break;
		}
		
	default :
		default_lab : {
			/* Other identifiers */
			if (rescan) {
				if (use) {
					EXP c = implicit_id_exp (id, 1);
					if (IS_exp_identifier_etc (c)) {
						id = DEREF_id (exp_identifier_etc_id (a));
						if (IS_id_function_etc (id)) {
							goto function_lab;
						}
					}
				} else {
					e = NULL_exp;
				}
			}
			break;
		}
    }
    return (e);
}


syntax highlighted by Code2HTML, v. 0.9.1