/*
 * 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/convert.c,v 1.9 2004/08/14 15:15:35 bp Exp $
 */


#include "config.h"
#include "producer.h"
#include "c_types.h"
#include "ctype_ops.h"
#include "etype_ops.h"
#include "exp_ops.h"
#include "ftype_ops.h"
#include "graph_ops.h"
#include "hashid_ops.h"
#include "id_ops.h"
#include "itype_ops.h"
#include "nat_ops.h"
#include "type_ops.h"
#include "error.h"
#include "catalog.h"
#include "option.h"
#include "basetype.h"
#include "cast.h"
#include "check.h"
#include "chktype.h"
#include "constant.h"
#include "construct.h"
#include "convert.h"
#include "derive.h"
#include "expression.h"
#include "function.h"
#include "identifier.h"
#include "initialise.h"
#include "instance.h"
#include "inttype.h"
#include "literal.h"
#include "member.h"
#include "namespace.h"
#include "overload.h"
#include "predict.h"
#include "quality.h"
#include "syntax.h"
#include "template.h"
#include "tokdef.h"
#include "token.h"


/*
 *    FIND THE PROMOTION OF A TYPE
 *
 *    This routine finds the promoted type for the type t.  For integral
 *    types the promoted type is calculated and stored when the type is
 *    first constructed.  Enumeration types and bitfield types are promoted
 *    according to their underlying types.  Other types (including floating
 *    point types) are their own promotions.
 */

TYPE
promote_type(TYPE t)
{
    switch (TAG_type (t)) {
	case type_integer_tag : {
	    /* Retrieve the promotion of an integral type */
	    INT_TYPE it = DEREF_itype (type_integer_rep (t));
	    t = DEREF_type (itype_prom (it));
	    break;
	}
	case type_enumerate_tag : {
	    /* Find the underlying type of an enumeration */
	    ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t));
	    t = DEREF_type (etype_rep (et));
	    t = promote_type (t);
	    break;
	}
	case type_bitfield_tag : {
	    /* Retrieve the promotion of a bitfield type */
	    INT_TYPE it = DEREF_itype (type_bitfield_defn (t));
	    t = DEREF_type (itype_prom (it));
	    break;
	}
    }
    return (t);
}


/*
 *    FIND THE ARGUMENT PROMOTION OF A TYPE
 *
 *    This routine finds the argument promotion type for the type t.  This
 *    is identical to the normal arithmetic promotion type for integral types,
 *    but differs for floating point types (float promotes to double etc.).
 *    Any errors are added to the end of err.
 */

TYPE
arg_promote_type(TYPE t, ERROR *err)
{
    switch (TAG_type (t)) {
	case type_integer_tag :
	case type_enumerate_tag :
	case type_bitfield_tag : {
	    /* Promote integral types */
	    t = promote_type (t);
	    break;
	}
	case type_floating_tag : {
	    /* Retrieve the promotion of a floating point type */
	    FLOAT_TYPE ft = DEREF_ftype (type_floating_rep (t));
	    t = DEREF_type (ftype_arg_prom (ft));
	    break;
	}
	case type_top_tag :
	case type_bottom_tag : {
	    /* Can't have 'void' arguments */
	    add_error (err, ERR_basic_fund_void_exp (t));
	    break;
	}
	case type_func_tag : {
	    /* Apply function-to-pointer conversion */
	    MAKE_type_ptr (cv_none, t, t);
	    break;
	}
	case type_array_tag : {
	    /* Apply array-to-pointer conversion */
	    TYPE s = DEREF_type (type_array_sub (t));
	    MAKE_type_ptr (cv_none, s, t);
	    break;
	}
	case type_compound_tag : {
	    /* Types with constructors are suspicious */
	    if (pass_complex_type (t)) {
			add_error (err, ERR_expr_call_struct (t));
	    }
	    break;
	}
    }
    return (t);
}


/*
 *    IS A TYPE EQUAL TO ITS ARGUMENT PROMOTION TYPE?
 *
 *    This routine checks whether the integral or floating point type t is
 *    equal to its argument promotion type.
 */

int
is_arg_promote(TYPE t)
{
    int eq = 1;
    if (!IS_NULL_type (t)) {
		t = expand_type (t, 1);
		switch (TAG_type (t)) {
	    case type_integer_tag :
	    case type_floating_tag : {
			TYPE s = arg_promote_type (t, KILL_err);
			if (!EQ_type (s, t)) {
				int ft = force_tokdef;
				force_tokdef = 0;
				eq = eq_type_unqual (s, t);
				force_tokdef = ft;
			}
			break;
	    }
		}
    }
    return (eq);
}


/*
 *    FIND THE TYPE WHICH PROMOTES TO A GIVEN TYPE
 *
 *    This routine is a partial inverse to arg_promote_type which finds a
 *    type whose promotion is t.
 */

TYPE
unpromote_type(TYPE t)
{
    if (!IS_NULL_type (t)) {
		switch (TAG_type (t)) {
	    case type_integer_tag : {
			INT_TYPE it = DEREF_itype (type_integer_rep (t));
			INT_TYPE is = DEREF_itype (type_integer_sem (t));
			if (!EQ_itype (is, it)) t = make_itype (is, is);
			break;
	    }
	    case type_floating_tag : {
			FLOAT_TYPE ft = DEREF_ftype (type_floating_rep (t));
			FLOAT_TYPE fs = DEREF_ftype (type_floating_sem (t));
			if (!EQ_ftype (fs, ft)) t = make_ftype (fs, fs);
			break;
	    }
		}
    }
    return (t);
}


/*
 *    FIND THE TYPE FOR AN ARITHMETIC OPERATION
 *
 *    This routine performs finds the result type for an arithmetic operation
 *    involving operands of types t and s.  These will always be arithmetic
 *    types.  The operands a and b are passed in order to help determine the
 *    semantic type of the result.
 */

TYPE
arith_type(TYPE t, TYPE s, EXP a, EXP b)
{
    TYPE r;
    if (EQ_type (t, s)) {
		/* Equal types, promote the result */
		r = promote_type (t);
    } else {
		unsigned nt = TAG_type (t);
		unsigned ns = TAG_type (s);
		if (nt == type_floating_tag) {
			if (ns == type_floating_tag) {
				/* Two floating point types */
				r = arith_ftype (t, s);
			} else {
				/* If there is one floating type, this is the result */
				r = t;
			}
		} else {
			if (ns == type_floating_tag) {
				/* If there is one floating type, this is the result */
				r = s;
			} else {
				/* Two integer types, promote them both */
				TYPE pt = promote_type (t);
				TYPE ps = promote_type (s);
				if (EQ_type (pt, ps)) {
					r = pt;
				} else {
					r = arith_itype (pt, ps, a, b);
				}
			}
		}
    }
    return (r);
}


/*
 *    QUALIFIER DEPTH
 *
 *    The value qualifier depth is set by check_qualifier to the depth of
 *    the deepest different cv-qualifier it encounters.  The easy cases
 *    are 0 (the types are identically qualified) and 1 (the conversion
 *    is of the form 'cv1 T *' to 'cv2 T *').  The value qualifier_diff
 *    gives the qualifiers added at this stage.
 */

int qualifier_depth = 0;
static CV_SPEC qualifier_diff = cv_none;


/*
 *    CHECK QUALIFICATION CONVERSIONS
 *
 *    This routine checks for qualification conversions from the pointer or
 *    pointer to member type s to the pointer or pointer to member type t.
 *    For the qualification conversion to be valid, the two types have to obey
 *    four rules.  They have to be similar (i.e. the same up to cv-qualifiers)
 *    - this is assumed to be true if safe is true.  Each target qualifier
 *    must be more const-qualified and more volatile-qualified than the
 *    corresponding source qualifier.  Finally if two qualifiers differ
 *    then all the previous target qualifiers must involve const.  The C
 *    rules are slightly different.  Only one level of pointers is
 *    considered and the types pointed to must be compatible.  Note that
 *    for pointer to member types it is not checked that the underlying
 *    classes are the same at the top level.  This is to allow base class
 *    pointer to member conversion to be checked elsewhere.
 */

unsigned
check_qualifier(TYPE t, TYPE s, int safe)
{
    int j = 0;
    int all_const = 1;
    unsigned res = QUAL_EQUAL;
    t = expand_type (t, 1);
    s = expand_type (s, 1);
    qualifier_depth = 0;
    qualifier_diff = cv_none;
    while (!EQ_type (t, s)) {
        unsigned nt = TAG_type (t);
        unsigned ns = TAG_type (s);
		CV_SPEC qt = DEREF_cv (type_qual (t));
		CV_SPEC qs = DEREF_cv (type_qual (s));
		
		/* Check qualifiers */
		if (j == 0) {
			/* Don't bother with top level qualifiers */
			/* EMPTY */
		} else {
			if (nt == type_array_tag) qt = find_cv_qual (t);
			if (ns == type_array_tag) qs = find_cv_qual (s);
			qt &= cv_qual;
			qs &= cv_qual;
			if (qt != qs) {
				CV_SPEC qr = (qs & ~qt);
				if (qr & cv_const) res &= ~QUAL_CONST;
				if (qr & cv_volatile) res &= ~QUAL_VOLATILE;
				res &= ~QUAL_EXACT;
				if (!all_const) {
					/* For inequality should have all consts in t */
					res &= ~QUAL_ALL_CONST;
				}
				qualifier_depth = j;
				qualifier_diff = (qt & ~qs);
			}
			if (!(qt & cv_const)) all_const = 0;
		}
		
		/* Check next type */
		switch (nt) {
			
	    case type_ptr_tag :
	    case type_ref_tag : {
			/* Pointer types */
			if (ns != nt) goto error_lab;
#if LANGUAGE_C
			if (j > 0) goto error_lab;
#endif
			t = DEREF_type (type_ptr_etc_sub (t));
			s = DEREF_type (type_ptr_etc_sub (s));
			break;
	    }
			
#if LANGUAGE_CPP
	    case type_ptr_mem_tag : {
			/* Pointer to member types */
			CLASS_TYPE cs, ct;
			if (ns != nt) goto error_lab;
			ct = DEREF_ctype (type_ptr_mem_of (t));
			cs = DEREF_ctype (type_ptr_mem_of (s));
			if (j == 0) {
				/* Top level classes checked elsewhere */
				/* EMPTY */
			} else if (!eq_ctype (ct, cs)) {
				/* Must point to members of the same class */
				if (in_template_decl) {
					/* Mark template parameter types */
					TYPE ft = DEREF_type (ctype_form (ct));
					TYPE fs = DEREF_type (ctype_form (cs));
					if (is_templ_depend (ft)) res |= QUAL_TEMPL;
					if (is_templ_depend (fs)) res |= QUAL_TEMPL;
				}
				res &= ~(QUAL_EXACT | QUAL_SIMILAR);
				return (res);
			}
			t = DEREF_type (type_ptr_mem_sub (t));
			s = DEREF_type (type_ptr_mem_sub (s));
			break;
	    }
#endif
			
	    case type_func_tag : {
			/* Function types */
			int eq;
			if (ns != nt) goto error_lab;
			if (safe) {
				eq = 3;
			} else {
				eq = eq_func_type (t, s, 1, 0);
				if (eq < 2) goto error_lab;
			}
			if (res == QUAL_EQUAL) res |= QUAL_FUNC;
			if (eq != 3) {
				/* Linkage specifiers don't match */
				res &= ~(QUAL_EXACT | QUAL_SIMILAR);
			}
			return (res);
	    }
			
	    case type_top_tag :
	    case type_bottom_tag :
	    case type_compound_tag : {
			/* Don't trust 'safe' in these cases */
			if (ns == nt && eq_type_unqual (t, s)) return (res);
			goto error_lab;
	    }
			
	    default : {
			/* Check other types */
			if (safe) return (res);
			if (ns == nt && eq_type_unqual (t, s)) return (res);
			goto error_lab;
	    }
			
			error_lab : {
				/* Unequal types */
#if LANGUAGE_C
				TYPE r = type_composite (t, s, 1, 0, KILL_err, 0);
				if (!IS_NULL_type (r)) {
					if (IS_type_func (r)) {
						if (res == QUAL_EQUAL) res |= QUAL_FUNC;
					}
					return (res);
				}
#endif
				if (in_template_decl) {
					/* Mark template parameter types */
					if (is_templ_depend (t)) res |= QUAL_TEMPL;
					if (is_templ_depend (s)) res |= QUAL_TEMPL;
				}
				if (ns == type_error_tag || nt == type_error_tag) {
					/* Mark error types */
					res |= QUAL_TEMPL;
				}
				res &= ~(QUAL_EXACT | QUAL_SIMILAR);
				return (res);
			}
		}
		j++;
    }
    return (res);
}


/*
 *    FIND THE TYPE FOR A POINTER OPERATION
 *
 *    This routine finds the common type for a pointer operation involving
 *    the pointer types t and s (as used, for example, in the relational
 *    operators).  Pointer conversions and qualification conversions are
 *    applied (including base class conversions if base is true), but the
 *    result must be a qualified version of one of the arguments, so only
 *    depth 1 qualification conversions are applied.  If t and s cannot be
 *    brought to a common type then the suspect flag is set to 2 and
 *    qualified 'void *' is returned.  suspect is set to 1 if precisely
 *    one of the types is 'void *'.  The routine also operates on reference
 *    types except that it returns a null type in the 'void *' case.
 */

TYPE
ptr_common_type(TYPE t, TYPE s, int base, int *suspect)
{
    CV_SPEC qt, qs;
    TYPE r = NULL_type;
    unsigned tag = TAG_type (t);
    TYPE pt = DEREF_type (type_ptr_etc_sub (t));
    TYPE ps = DEREF_type (type_ptr_etc_sub (s));
    unsigned nt = TAG_type (pt);
    unsigned ns = TAG_type (ps);
	
    /* Find the common type */
    if (nt == ns) {
		if (eq_type_unqual (pt, ps)) {
			/* Pointers to the same type */
			r = pt;
		} else if (nt == type_compound_tag && base) {
			/* Check for base class conversions */
			CLASS_TYPE ct = DEREF_ctype (type_compound_defn (pt));
			CLASS_TYPE cs = DEREF_ctype (type_compound_defn (ps));
			CLASS_TYPE cr = compare_base_class (ct, cs, 1);
			if (EQ_ctype (cr, ct)) {
				/* p is a base class of q */
				r = pt;
			} else if (EQ_ctype (cr, cs)) {
				/* q is a base class of p */
				r = ps;
			}
		}
    } else if (nt == type_top_tag || nt == type_bottom_tag) {
		/* One pointer is 'void *' */
		*suspect = 1;
		r = pt;
    } else if (ns == type_top_tag || ns == type_bottom_tag) {
		/* One pointer is 'void *' */
		*suspect = 1;
		r = ps;
    }
#if LANGUAGE_C
    if (IS_NULL_type (r)) {
		/* In C, compatible types are allowed */
		r = type_composite (pt, ps, 1, 0, KILL_err, 1);
    }
#endif
    if (IS_NULL_type (r)) {
		/* Can't bring to common pointer type */
		if (is_templ_type (t) || is_templ_type (s)) {
			*suspect = -1;
		} else {
			*suspect = 2;
		}
		if (tag == type_ref_tag) {
			/* There are no generic references */
			return (NULL_type);
		}
		r = type_void;
    }
	
    /* Qualify the common type appropriately */
    qt = find_cv_qual (pt);
    qs = find_cv_qual (ps);
    r = qualify_type (r, (qt | qs), 0);
	
    /* Form the result type */
    if (EQ_type (r, pt)) return (t);
    if (EQ_type (r, ps)) return (s);
    MAKE_type_ptr_etc (tag, cv_none, r, r);
    return (r);
}


/*
 *    FIND THE TYPE FOR A POINTER MEMBER OPERATION
 *
 *    This routine finds the common type for a pointer to member operation
 *    involving the pointer to member types t and s (as used, for example,
 *    in the equality operators).  If t and s cannot be brought to a common
 *    type then suspect is set to 2 and the error type is returned.  If
 *    the cv-qualifier of the common type is not equal to the cv-qualifier
 *    of either t or s then suspect is set to 1.
 */

TYPE
ptr_mem_common_type(TYPE t, TYPE s, int *suspect)
{
    /* Check for base class conversions */
    CLASS_TYPE ct = DEREF_ctype (type_ptr_mem_of (t));
    CLASS_TYPE cs = DEREF_ctype (type_ptr_mem_of (s));
    CLASS_TYPE cr = compare_base_class (ct, cs, 1);
    if (!IS_NULL_ctype (cr)) {
		TYPE pr;
		TYPE pt = DEREF_type (type_ptr_mem_sub (t));
		TYPE ps = DEREF_type (type_ptr_mem_sub (s));
		if (EQ_ctype (cr, ct)) {
			cr = cs;
			pr = ps;
		} else {
			cr = ct;
			pr = pt;
		}
		
		/* Check that underlying types are the same */
		if (eq_type_unqual (pt, ps)) {
			/* Form the result type */
			CV_SPEC qt = find_cv_qual (pt);
			CV_SPEC qs = find_cv_qual (ps);
			CV_SPEC qr = (qt | qs);
			pr = qualify_type (pr, qr, 0);
			if (qt != qs && qr != qs) *suspect = 1;
			if (EQ_ctype (cr, ct) && EQ_type (pr, pt)) return (t);
			if (EQ_ctype (cr, cs) && EQ_type (pr, ps)) return (s);
			MAKE_type_ptr_mem (cv_none, cr, pr, pr);
			return (pr);
		}
    }
	
    /* Can't bring to common pointer member type */
    if (is_templ_type (t) || is_templ_type (s)) {
		*suspect = -1;
    } else {
		*suspect = 2;
    }
    return (type_error);
}


/*
 *    FIND A COMMON TYPE
 *
 *    This routine finds the common type for the types t and s.  This is
 *    the other type if either type is null, the single type if they are
 *    equal, the arithmetic type if they are both arithmetic and the common
 *    pointer, reference or pointer-to-member type if these are appropriate.
 *    The null type is returned if the common type cannot be formed and
 *    suspect is set accordingly.  The rules are essentially the same as
 *    for the '?:' operation.
 */

TYPE
common_type(TYPE t, TYPE s, int *suspect)
{
    unsigned nt, ns;
    TYPE r = NULL_type;
    if (IS_NULL_type (t)) return (s);
    if (IS_NULL_type (s)) return (t);
    nt = TAG_type (t);
    ns = TAG_type (s);
    if (nt == ns) {
		switch (nt) {
	    case type_ptr_tag :
	    case type_ref_tag : {
			/* Common pointer or reference type */
			r = ptr_common_type (t, s, 1, suspect);
			if (*suspect != 2) return (r);
			r = NULL_type;
			break;
	    }
	    case type_ptr_mem_tag : {
			/* Common pointer to member type */
			r = ptr_mem_common_type (t, s, suspect);
			if (*suspect != 2) return (r);
			r = NULL_type;
			break;
	    }
	    default : {
			/* Other types */
			if (eq_type_unqual (t, s)) {
				CV_SPEC qt = find_cv_qual (t);
				CV_SPEC qs = find_cv_qual (s);
				if (qt != qs) {
					*suspect = 1;
					t = qualify_type (t, (qt | qs), 0);
				}
				return (t);
			}
			break;
	    }
		}
    }
    switch (nt) {
	case type_integer_tag :
	case type_enumerate_tag :
	case type_bitfield_tag :
	case type_floating_tag : {
	    switch (ns) {
		case type_integer_tag :
		case type_enumerate_tag :
		case type_bitfield_tag :
		case type_floating_tag : {
		    /* Common arithmetic type */
		    r = arith_type (t, s, NULL_exp, NULL_exp);
		    return (r);
		}
	    }
	}
    }
#if LANGUAGE_C
    if (IS_NULL_type (r)) {
		r = type_composite (t, s, 1, 0, KILL_err, 1);
		if (!IS_NULL_type (r)) return (r);
    }
#endif
    if (nt == type_error_tag) return (s);
    if (ns == type_error_tag) return (t);
    *suspect = 2;
    return (r);
}


/*
 *    CONVERT AN EXPRESSION TO ITS PROMOTED TYPE
 *
 *    This routine converts the expression e to its promoted type, t
 *    (previously calculated using promote_type).  Note that there is no
 *    effect unless t is an integral type.
 */

EXP
convert_promote(TYPE t, EXP e)
{
    if (IS_type_integer (t)) {
		TYPE s = DEREF_type (exp_type (e));
		if (!EQ_type (t, s)) {
			/* Perform non-trivial integral promotions */
			e = cast_int_int (t, e, KILL_err, CAST_IMPLICIT, 0);
		}
    }
    return (e);
}


/*
 *    CONVERT AN EXPRESSION TO ITS ARITHMETIC TYPE
 *
 *    This routine converts the expression e to an arithmetic result type, t,
 *    formed by arith_type using the type of e as its nth argument.  Note that
 *    there are three cases: integer->integer, integer->float and float->float.
 */

EXP
convert_arith(TYPE t, EXP e, int op, int n)
{
    TYPE s = DEREF_type (exp_type (e));
    if (!EQ_type (t, s)) {
		ERROR err = NULL_err;
		if (IS_type_floating (t)) {
			unsigned tag = TAG_type (s);
			if (tag == type_floating_tag) {
				e = cast_float_float (t, e, &err, CAST_IMPLICIT);
			} else {
				if (tag == type_bitfield_tag) {
					s = find_bitfield_type (s);
					e = cast_int_int (s, e, &err, CAST_IMPLICIT, -1);
				}
				e = cast_int_float (t, e, &err, CAST_IMPLICIT);
			}
		} else {
			e = cast_int_int (t, e, &err, CAST_IMPLICIT, -1);
		}
		if (!IS_NULL_err (err)) {
			unsigned m = (unsigned) n;
			err = concat_error (err, ERR_expr_convert_op (m, op));
			report (crt_loc, err);
		}
    }
    return (e);
}


/*
 *    CONVERT A POINTER TO A COMMON POINTER TYPE
 *
 *    This routine converts the pointer expression e to a common pointer
 *    type, t, formed by ptr_common_type using the type of e as its nth
 *    argument.
 */

EXP
convert_ptr_common(TYPE t, EXP e, int op, int n)
{
    TYPE s = DEREF_type (exp_type (e));
    if (!EQ_type (t, s)) {
		ERROR err = NULL_err;
		e = cast_ptr_ptr (t, e, &err, CAST_IMPLICIT, 1, 1);
		if (!IS_NULL_err (err)) {
			unsigned m = (unsigned) n;
			err = concat_error (err, ERR_expr_convert_op (m, op));
			report (crt_loc, err);
		}
    }
    return (e);
}


/*
 *    CONVERT A POINTER MEMBER TO A COMMON POINTER MEMBER TYPE
 *
 *    This routine converts the pointer member expression e to a common
 *    pointer to member type, t, formed by ptr_mem_common_type using the
 *    type of e as its nth argument.
 */

EXP
convert_ptr_mem_common(TYPE t, EXP e, int op, int n)
{
    TYPE s = DEREF_type (exp_type (e));
    if (!EQ_type (t, s)) {
		ERROR err = NULL_err;
		e = cast_ptr_mem_ptr_mem (t, e, &err, CAST_IMPLICIT, 1, 1);
		if (!IS_NULL_err (err)) {
			unsigned m = (unsigned) n;
			err = concat_error (err, ERR_expr_convert_op (m, op));
			report (crt_loc, err);
		}
    }
    return (e);
}


/*
 *    CHECK FOR ASSIGNMENT IN A BOOLEAN
 *
 *    This routine checks whether the expression a, which is to be converted
 *    to a boolean, is an assignment.  A warning is issued for 'x = y' and
 *    'x /= y' because of possible confusion with 'x == y' and 'x != y'
 *    respectively.  If the original expression was enclosed in brackets
 *    (as indicated by tag) then no warning is issued.
 */

static void
boolean_assign(EXP a, unsigned tag)
{
    if (tag != exp_paren_tag && !suppress_quality) {
		if (IS_exp_assign (a)) {
			report (crt_loc, ERR_conv_bool_assign ());
		} else if (IS_exp_preinc (a)) {
			int op = DEREF_int (exp_preinc_becomes (a));
			if (op == lex_assign || op == lex_div_Heq) {
				report (crt_loc, ERR_conv_bool_assign ());
			}
		}
    }
    return;
}


/*
 *    CONVERT AN EXPRESSION TO A BOOLEAN
 *
 *    This routine converts the expression a to a boolean if this is possible,
 *    returning the corresponding boolean expression.  Any error arising are
 *    added to the position indicated by the err argument.  User-defined
 *    conversions are handled elsewhere.
 */

EXP
convert_boolean(EXP a, unsigned tag, ERROR *err)
{
    EXP e;
    TYPE t = DEREF_type (exp_type (a));
    switch (TAG_exp (a)) {
	case exp_int_lit_tag : {
	    /* Check for integer literals */
	    e = make_test_nat (a);
	    return (e);
	}
	case exp_float_lit_tag : {
	    /* Check for floating-point literals */
	    FLOAT f = DEREF_flt (exp_float_lit_flt (a));
	    unsigned v = BOOL_VALUE (!is_zero_float (f));
	    e = make_bool_exp (v, exp_float_lit_tag);
	    return (e);
	}
	case exp_contents_tag : {
	    /* Check for assignment in boolean */
	    EXP b = DEREF_exp (exp_contents_ptr (a));
	    switch (TAG_exp (b)) {
		case exp_assign_tag :
		case exp_preinc_tag :
		case exp_postinc_tag : {
		    boolean_assign (b, tag);
		    break;
		}
	    }
	    break;
	}
	case exp_assign_tag :
	case exp_preinc_tag :
	case exp_postinc_tag : {
	    /* Check for assignment in boolean */
	    boolean_assign (a, tag);
	    break;
	}
    }
	
    /* Perform the conversion */
    switch (TAG_type (t)) {
	case type_integer_tag : {
	    /* Integral types are allowed */
	    if (check_int_type (t, btype_bool)) return (a);
	    break;
	}
	case type_bitfield_tag : {
	    /* Convert bitfields to integers */
	    a = convert_bitfield (a);
	    break;
	}
	case type_enumerate_tag :
	case type_floating_tag :
	case type_ptr_tag :
	case type_ptr_mem_tag : {
	    /* These types are allowed */
	    break;
	}
	case type_error_tag : {
	    /* Allow for error propagation */
	    break;
	}
	default : {
	    /* These types are not allowed */
	    add_error (err, ERR_conv_bool_cast (t));
	    break;
	}
    }
    MAKE_exp_test (type_bool, ntest_not_eq, a, e);
    return (e);
}


/*
 *    REPORT OVERLOADED FUNCTIONS
 *
 *    This routine prints an error and returns true if e represents an
 *    overloaded function.  If it represents a non-overloaded function which
 *    has not already resolved using resolve_cast then the function is
 *    marked as used.
 */

static int
is_overloaded(EXP e)
{
    if (!IS_NULL_exp (e) && IS_exp_identifier_etc (e)) {
		IDENTIFIER id = DEREF_id (exp_identifier_etc_id (e));
		if (IS_id_function_etc (id)) {
			QUALIFIER q = DEREF_qual (exp_identifier_etc_qual (e));
			if (!(q & qual_mark)) {
				/* Not already resolved */
				TYPE fn = DEREF_type (id_function_etc_type (id));
				IDENTIFIER over = DEREF_id (id_function_etc_over (id));
				if (!IS_NULL_id (over) || IS_type_templ (fn)) {
					/* Overloaded function */
					report (crt_loc, ERR_over_over_context (id));
					return (1);
				}
				use_id (id, suppress_usage);
			}
		}
    }
    return (0);
}


/*
 *    PERFORM QUALIFICATION CONVERSIONS ON A TYPE
 *
 *    This routine removes any type qualifiers from a rvalue, non-class
 *    type t.  Class types maintain their type qualifiers, lvalue types
 *    lose theirs in convert_lvalue.
 */

TYPE
convert_qual_type(TYPE t)
{
    CV_SPEC qual = DEREF_cv (type_qual (t));
    if (qual && !(qual & cv_lvalue)) {
#if LANGUAGE_CPP
		if (IS_type_compound (t)) return (t);
#endif
		t = qualify_type (t, cv_none, 0);
    }
    return (t);
}


/*
 *    EVALUATE A CONST VARIABLE
 *
 *    This routine evaluates the 'const' variable expression a, so that
 *    for example, if 'const int c = 5 ;' then 'c' is evaluated to '5'.
 */

EXP
convert_const(EXP a)
{
#if LANGUAGE_CPP
    IDENTIFIER id = DEREF_id (exp_identifier_id (a));
    EXP e = DEREF_exp (id_variable_etc_init (id));
    if (!IS_NULL_exp (e)) {
		switch (TAG_exp (e)) {
	    case exp_int_lit_tag : {
			/* Propagate simple constants */
			NAT n;
			TYPE t;
			unsigned tag;
			DECONS_exp_int_lit (t, n, tag, e);
			MAKE_exp_int_lit (t, n, tag, e);
			return (e);
	    }
	    case exp_null_tag : {
			/* Propagate null constants */
			TYPE t;
			int ptr_const;
			DECONS_exp_null (t, ptr_const, e);
			MAKE_exp_null (t, e);
			COPY_int (exp_null_ptr_const (e), ptr_const);
			return (e);
	    }
		}
    }
#endif
    return (a);
}


/*
 *    PERFORM ARRAY TO POINTER CONVERSION
 *
 *    This routine performs array to pointer conversion on the array
 *    expression a.  If a is a string literal and str is true then the
 *    const qualifiers are removed from the string.  A warning is also
 *    added to err if str is 2.
 */

EXP
convert_array(EXP a, int str, ERROR *err)
{
    TYPE t = DEREF_type (exp_type (a));
    TYPE s = DEREF_type (type_array_sub (t));
    if (str && IS_exp_string_lit (a)) {
		/* Remove const from string literals */
		CV_SPEC cv = DEREF_cv (type_qual (s));
		if (cv & cv_const) {
			cv &= ~cv_const;
			s = qualify_type (s, cv, 0);
			if (str == 2) add_error (err, ERR_conv_array_string ());
		}
    } else if (option (OPT_addr_register) && used_register) {
		/* Can't apply to a register variable in C */
		EXP b = NULL_exp;
		DECL_SPEC ds = find_exp_linkage (a, &b, 1);
		if ((ds & dspec_register) && !(ds & dspec_temp)) {
			if (IS_exp_identifier (b)) {
				IDENTIFIER id = DEREF_id (exp_identifier_id (b));
				add_error (err, ERR_expr_unary_op_ref_register (id));
			}
		}
    }
    MAKE_type_ptr (cv_none, s, t);
    MAKE_exp_address (t, a, a);
    return (a);
}


/*
 *    PERFORM LVALUE CONVERSIONS
 *
 *    This routine performs the lvalue conversions on the expression a.
 *    If e is an lvalue, the lvalue-to-rvalue, array-to-pointer and
 *    function-to-pointer conversions are applied to transform it into an
 *    rvalue.  Checks for overloaded functions are also applied at this
 *    stage to both lvalues and rvalues.
 */

EXP
convert_lvalue(EXP a)
{
    EXP e = a;
    TYPE t = DEREF_type (exp_type (a));
    CV_SPEC qual = DEREF_cv (type_qual (t));
    if (qual & cv_lvalue) {
		CV_SPEC cv = cv_none;
		switch (TAG_type (t)) {
	    case type_array_tag : {
			/* Array-to-pointer conversion */
			ERROR err = NULL_err;
			e = convert_array (a, 0, &err);
			if (!IS_NULL_err (err)) report (crt_loc, err);
			break;
	    }
	    case type_func_tag : {
			/* Function-to-pointer conversion */
			if (is_overloaded (a)) {
				e = make_error_exp (0);
				break;
			}
			if (IS_exp_member (a)) goto default_lab;
			MAKE_type_ptr (cv_none, t, t);
			MAKE_exp_address (t, a, e);
			break;
	    }
#if LANGUAGE_CPP
	    case type_compound_tag : {
			/* Classes preserve qualifiers in lvalue conversion */
			cv = (qual & cv_qual);
			goto default_lab;
	    }
#endif
	    case type_templ_tag : {
			/* Can't have template expressions */
			if (!is_overloaded (a)) {
				report (crt_loc, ERR_temp_local_not (t));
			}
			e = make_error_exp (0);
			break;
	    }
	    default :
			default_lab : {
				/* Lvalue-to-rvalue conversion */
				ERROR err;
				if (qual == (cv_const | cv_lvalue)) {
					/* Check for constants at this stage */
					if (IS_exp_identifier (a)) {
						e = convert_const (a);
						if (!EQ_exp (e, a)) return (e);
					}
				}
				t = qualify_type (t, cv, 0);
				err = check_incomplete (t);
				if (!IS_NULL_err (err)) {
					err = concat_error (err, ERR_conv_lval_incompl ());
					report (crt_loc, err);
				}
				MAKE_exp_contents (t, a, e);
				break;
			}
		}
		
    } else {
		/* Check rvalues for overloaded functions */
		switch (TAG_exp (e)) {
	    case exp_address_tag : {
			/* Address of object or function */
			EXP b = DEREF_exp (exp_address_arg (a));
			if (is_overloaded (b)) e = make_error_exp (0);
			break;
	    }
	    case exp_address_mem_tag : {
			/* Address of member or member function */
			EXP b = DEREF_exp (exp_address_mem_arg (a));
			if (is_overloaded (b)) e = make_error_exp (0);
			break;
	    }
	    case exp_token_tag : {
			/* Check for tokenised arrays */
			if (IS_type_array (t)) {
				ERROR err = NULL_err;
				e = convert_array (a, 0, &err);
				if (!IS_NULL_err (err)) report (crt_loc, err);
			}
			break;
	    }
		}
    }
    return (e);
}


/*
 *    CHECK AMBIGUOUS IDENTIFIERS
 *
 *    This routine checks whether the identifier id represents a non-member
 *    function or an ambiguous set of such functions.  It is required because
 *    overload resolution is used to distinguish between the ambiguous cases
 *    for non-member functions, whereas it is an error otherwise.
 */

int
is_ambiguous_func(IDENTIFIER id)
{
    switch (TAG_id (id)) {
	case id_ambig_tag : {
	    /* Deal with ambiguous identifiers */
	    LIST (IDENTIFIER) p = DEREF_list (id_ambig_ids (id));
	    while (!IS_NULL_list (p)) {
			id = DEREF_id (HEAD_list (p));
			if (!is_ambiguous_func (id)) return (0);
			p = TAIL_list (p);
	    }
	    return (1);
	}
	case id_function_tag : {
	    /* These are functions */
	    return (1);
	}
    }
    return (0);
}


/*
 *    PERFORM REFERENCE CONVERSIONS
 *
 *    This routine performs the reference conversions on the expression a.
 *    That is, if a has type reference to t, then it is transformed into an
 *    lvalue of type t.  Other checks are also applied to a - for example,
 *    parentheses are removed, undeclared variables are reported, and
 *    constants are evaluated.  The precise checks applied depend on context
 *    which can take one of the values from convert.h.
 */

EXP
convert_reference(EXP a, int context)
{
    /* Remove parentheses */
    TYPE t;
    unsigned etag = TAG_exp (a);
    if (etag == exp_paren_tag) {
		do {
			DESTROY_exp_paren (destroy, t, a, a);
			etag = TAG_exp (a);
		} while (etag == exp_paren_tag);
    } else {
		t = DEREF_type (exp_type (a));
    }
	
    /* Apply extra checks */
    switch (etag) {
		
	case exp_member_tag : {
	    /* Non-static data members and all function members */
	    if (context == REF_ADDRESS) {
			/* Suppress reference conversions */
			t = type_error;
	    } else {
			IDENTIFIER id = DEREF_id (exp_member_id (a));
			if (context == REF_NORMAL || IS_id_member (id)) {
				EXP b = make_this_field (id);
				if (IS_NULL_exp (b)) {
					report (crt_loc, ERR_expr_prim_mem (id));
					a = make_error_exp (0);
				} else {
					a = b;
					if (IS_exp_call (a)) goto call_lab;
				}
				t = DEREF_type (exp_type (a));
				etag = TAG_exp (a);
			}
	    }
	    break;
	}
		
	case exp_ambiguous_tag : {
	    /* Ambiguous identifiers */
	    IDENTIFIER id = DEREF_id (exp_ambiguous_id (a));
	    if (context == REF_NORMAL || !is_ambiguous_func (id)) {
			/* Report ambiguous identifier */
			IGNORE report_ambiguous (id, 0, 1, 0);
			a = make_error_exp (0);
			t = DEREF_type (exp_type (a));
	    } else {
			/* Allow ambiguous functions */
			t = type_func_void;
			t = lvalue_type (t);
			COPY_type (exp_type (a), t);
	    }
	    break;
	}
		
	case exp_undeclared_tag : {
	    /* Undeclared identifiers */
	    if (context == REF_FUNCTION || context == REF_ADDRESS) {
			/* Deal with undeclared functions later */
			t = type_func_void;
			t = lvalue_type (t);
			COPY_type (exp_type (a), t);
	    } else {
			/* Report undeclared identifiers */
			IDENTIFIER id = DEREF_id (exp_undeclared_id (a));
			crt_id_qualifier = DEREF_qual (exp_undeclared_qual (a));
			a = implicit_id_exp (id, 0);
			t = DEREF_type (exp_type (a));
	    }
	    break;
	}
		
	case exp_address_tag : {
	    /* Address of object */
	    EXP b = DEREF_exp (exp_address_arg (a));
	    unsigned btag = TAG_exp (b);
	    if (btag == exp_ambiguous_tag) {
			if (context != REF_FUNCTION && context != REF_ASSIGN) {
				/* Ambiguous function */
				b = convert_reference (b, REF_NORMAL);
				a = make_ref_exp (b, 1);
				t = DEREF_type (exp_type (a));
			}
	    } else if (btag == exp_undeclared_tag) {
			if (context != REF_FUNCTION) {
				/* Undeclared function */
				b = convert_reference (b, REF_NORMAL);
				a = make_ref_exp (b, 1);
				t = DEREF_type (exp_type (a));
			}
	    } else if (btag == exp_call_tag) {
			if (context != REF_ASSIGN) {
				b = DEREF_exp (exp_call_ptr (b));
				if (IS_exp_member (b)) {
					/* Member function selector */
					if (!is_overloaded (b)) {
						report (crt_loc, ERR_expr_ref_call ());
					}
					a = make_error_exp (0);
					t = DEREF_type (exp_type (a));
				}
			}
	    }
	    break;
	}
		
	case exp_call_tag :
		call_lab : {
			/* All member function calls */
			if (context != REF_FUNCTION) {
				EXP b = DEREF_exp (exp_call_ptr (a));
				unsigned btag = TAG_exp (b);
				if (btag == exp_identifier_tag) {
					/* Single static member function */
					IDENTIFIER id = DEREF_id (exp_identifier_id (b));
					use_id (id, suppress_usage);
					a = DEREF_exp (exp_call_arg (a));
					a = join_exp (a, b);
					t = DEREF_type (exp_type (a));
					break;
				}
				if (btag == exp_member_tag) {
					/* Other member functions */
					if (context != REF_NORMAL) break;
					if (!is_overloaded (b)) {
						report (crt_loc, ERR_expr_ref_call ());
					}
				} else {
					/* Pointer to member functions */
					report (crt_loc, ERR_expr_mptr_oper_call ());
				}
				a = make_error_exp (0);
				t = DEREF_type (exp_type (a));
			}
			break;
		}
    }
	
    /* Check for reference conversions */
    if (IS_type_ref (t)) {
		/* Reference to t becomes lvalue t */
		if (etag == exp_indir_tag) {
			/* Can't have two indirections in a row */
			MAKE_exp_contents (t, a, a);
		}
		t = DEREF_type (type_ref_sub (t));
		/* Note that t is already an lvalue */
		MAKE_exp_indir (t, a, a);
    }
    return (a);
}


/*
 *    PROMOTE BITFIELD EXPRESSIONS
 *
 *    In certain expressions, even though an integral operand is not subject
 *    to integer promotion, bitfield expressions need to be converted to
 *    integral expressions by promotion.  This routine performs this conversion
 *    for the expression a.
 */

EXP
convert_bitfield(EXP a)
{
    TYPE t = DEREF_type (exp_type (a));
    if (IS_type_bitfield (t)) {
		t = promote_type (t);
		a = convert_promote (t, a);
    }
    return (a);
}


/*
 *    CONVERT OPERAND WHERE NO CONTEXT IS GIVEN
 *
 *    This routine performs conversions on the operand a in contexts where
 *    there is no information to resolve overloaded functions etc.  It also
 *    introduces temporary variables for constructor call expressions.
 */

EXP
convert_none(EXP a)
{
    if (!IS_NULL_exp (a)) {
		ERROR err = NULL_err;
		if (IS_exp_constr (a)) {
			TYPE t = DEREF_type (exp_type (a));
			a = make_temporary (t, a, NULL_exp, 0, &err);
			a = convert_lvalue (a);
		} else {
			LIST (IDENTIFIER) pids = NULL_list (IDENTIFIER);
			a = resolve_cast (type_void, a, &err, 1, 0, pids);
		}
		if (!IS_NULL_err (err)) report (crt_loc, err);
    }
    return (a);
}


/*
 *    QUALIFICATION CONVERSIONS
 *
 *    The values cv_const and cv_volatile are used to represent qualification
 *    conversions which add the corresponding qualifiers at a single level.
 *    cv_strlit is used to represent the removal of const from a string
 *    literal.  cv_multi is used to represent qualifications which add
 *    qualifiers at more than one level.
 */

#define cv_strlit	((CV_SPEC) 0x10)
#define cv_multi	((CV_SPEC) 0x20)


/*
 *    CHECK FOR OVERLOADED FUNCTION CONVERSION SEQUENCES
 *
 *    This routine checks for conversion sequences between the overloaded
 *    function id and the pointer or pointer to member (of the correct class)
 *    type t.
 */

static unsigned
overload_convert_seq(TYPE t, IDENTIFIER id, CONVERSION *p)
{
    /* Check arguments */
    TYPE fn;
    int eq = 0;
    CV_SPEC cv;
    unsigned conv = CONV_EXACT;
    unsigned tag = TAG_type (t);
    if (tag == type_ptr_tag) {
		fn = DEREF_type (type_ptr_sub (t));
    } else {
		fn = DEREF_type (type_ptr_mem_sub (t));
    }
    if (!IS_type_func (fn)) return (CONV_NONE);
    cv = DEREF_cv (type_qual (fn));
    cv &= cv_qual;
    if (cv != cv_none) conv = CONV_QUAL;
    p->qual = cv;
	
    /* Check for matching overload function */
    id = resolve_func (id, fn, 1, 0, NULL_list (IDENTIFIER), &eq);
    if (!IS_NULL_id (id) && eq == 3) {
		switch (TAG_id (id)) {
	    case id_mem_func_tag : {
			/* A member function gives a pointer to member */
			if (tag == type_ptr_mem_tag) return (conv);
			break;
	    }
	    case id_function_tag :
	    case id_stat_mem_func_tag : {
			/* Other functions give pointers */
			if (tag == type_ptr_tag) return (conv);
			break;
	    }
		}
    }
    return (CONV_NONE);
}


/*
 *    CHECK FOR REFERENCE CONVERSION SEQUENCES
 *
 *    This routine checks the conversion sequence p, the destination type
 *    of which is a reference type.  If std is true then only standard
 *    conversions will be applied.  bind describes the form of reference
 *    binding to take place.  The normal value is 0, implements the normal
 *    reference binding rules.  A value of 1 is used to suppress all
 *    rvalue reference bindings.  Values of 2 and 3 allow rvalues of
 *    related types to be bound to any reference (not just const references),
 *    with 2 further regarding any base class conversions as exact matches.
 */

static unsigned
ref_convert_seq(CONVERSION *p, EXP e, int bind, int std)
{
    unsigned conv;
    TYPE t = DEREF_type (type_ref_sub (p->to));
    TYPE s = p->from;
    unsigned nt = TAG_type (t);
    unsigned ns = TAG_type (s);
    CV_SPEC qs = DEREF_cv (type_qual (s));
    if (qs & cv_lvalue) {
		CV_SPEC cv = cv_compare (t, s);
		if (cv == cv_none) {
			/* Qualifiers are alright */
			cv = cv_compare (s, t);
			p->qual = cv;
			if (eq_type_unqual (s, t)) {
				if (cv == cv_none) {
					conv = CONV_EXACT;
				} else {
					conv = CONV_QUAL;
				}
				return (conv);
			}
			if (ns == type_compound_tag && nt == type_compound_tag) {
				CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
				CLASS_TYPE cs = DEREF_ctype (type_compound_defn (s));
				if (eq_ctype (ct, cs)) {
					/* Classes match */
					if (cv == cv_none) {
						conv = CONV_EXACT;
					} else {
						conv = CONV_QUAL;
					}
					return (conv);
				} else {
					/* Check for base classes */
					GRAPH gr = find_base_class (cs, ct, 0);
					if (!IS_NULL_graph (gr)) {
						/* Base class conversion */
						p->base = gr;
						if (bind == 2) {
							/* Base class conversions match exactly */
							if (cv == cv_none) {
								conv = CONV_EXACT;
							} else {
								conv = CONV_QUAL;
							}
						} else {
							conv = CONV_BASE;
						}
						return (conv);
					}
				}
			}
		}
    }
    if (bind == 0) {
		/* Default - only const references allowed */
		CV_SPEC qt = find_cv_qual (t);
		if (qt != (cv_lvalue | cv_const)) return (CONV_NONE);
		qs = find_cv_qual (s);
		if (qs & cv_volatile) return (CONV_NONE);
    } else if (bind == 1) {
		/* No references allowed */
		return (CONV_NONE);
    } else {
		/* All references allowed */
		std = 1;
    }
    p->to = t;
    p->from = s;
    if (std) {
		conv = std_convert_seq (p, e, bind, 1);
    } else {
		conv = convert_seq (p, e, bind, 1);
    }
    if (bind == 2) {
		/* Base class conversions match exactly */
		if (conv == CONV_BASE) {
			if (p->qual == cv_none) {
				conv = CONV_EXACT;
			} else {
				conv = CONV_QUAL;
			}
		}
    }
    return (conv);
}


/*
 *    CHECK FOR STANDARD CONVERSION SEQUENCES
 *
 *    This routine checks whether there is a standard conversion sequence
 *    between the types given by p.  e gives the argument being converted
 *    (this is only used in identifying null pointer and null pointer member
 *    conversions).  The arguments bind and ref describe how reference bindings
 *    are to be treated (see above).  Note that conversion are applied in
 *    the canonical sequence, lvalue transformations, promotions, conversions
 *    and qualification adjustments.  The routine returns the value indicating
 *    the rank of this conversion.
 */

unsigned
std_convert_seq(CONVERSION *p, EXP e, int bind, int ref)
{
    CV_SPEC qs;
    int str = 0;
    unsigned etag;
    TYPE t = p->to;
    TYPE s = p->from;
    unsigned nt, ns;
    unsigned conv = CONV_NONE;
	
    /* Conversion to the null type counts as exact */
    if (IS_NULL_type (t)) return (CONV_EXACT);
	
    /* Conversion from the error type counts as ellipsis */
    ns = TAG_type (s);
    if (ns == type_error_tag) return (CONV_ELLIPSIS);
    qs = DEREF_cv (type_qual (s));
	
    /* Reference conversion */
    if (ns == type_ref_tag) {
		s = DEREF_type (type_ref_sub (s));
		p->from = s;
		ns = TAG_type (s);
		if (ns == type_error_tag) return (CONV_ELLIPSIS);
		qs = DEREF_cv (type_qual (s));
    }
	
    /* Deal with conversions to reference types */
    nt = TAG_type (t);
    if (nt == type_ref_tag) {
		conv = ref_convert_seq (p, e, bind, 1);
		return (conv);
    }
	
    /* Examine expression */
    etag = (IS_NULL_exp (e) ? null_tag : TAG_exp (e));
	
    /* Lvalue transformations */
    if (qs & cv_lvalue) {
		if (ns == type_func_tag) {
			/* Function to pointer conversion */
			if (etag != exp_member_tag) {
				TYPE ps = s;
				s = type_temp_star;
				COPY_type (type_ptr_sub (s), ps);
				ns = type_ptr_tag;
			}
		} else if (ns == type_array_tag) {
			/* Array to pointer conversion */
			TYPE ps = DEREF_type (type_array_sub (s));
			s = type_temp_star;
			COPY_type (type_ptr_sub (s), ps);
			ns = type_ptr_tag;
		} else {
			/* lvalue to rvalue conversion */
			if (etag == exp_identifier_tag) {
				if (qs == (cv_lvalue | cv_const)) {
					IDENTIFIER id = DEREF_id (exp_identifier_id (e));
					EXP d = DEREF_exp (id_variable_etc_init (id));
					if (is_zero_exp (d)) {
						/* Propagate zero constants */
						e = d;
					}
				}
			}
		}
    }
	
    /* Promotions and conversions */
    switch (ns) {
		
	case type_integer_tag :
	case type_enumerate_tag :
		integral_lab : {
			/* Integral and similar arguments */
			if (nt == ns && eq_type_unqual (t, s)) {
				/* Exact match */
				conv = CONV_EXACT;
			} else {
				TYPE ps = promote_type (s);
				if (!EQ_type (ps, s) && eq_type_unqual (t, ps)) {
					/* Integral promotion */
					conv = CONV_INT_PROM;
				} else if (nt == type_integer_tag) {
					/* Integral conversions (subsumes booleans) */
					conv = CONV_INT_INT;
				} else if (nt == type_floating_tag) {
					/* Floating-integer conversions */
					conv = CONV_INT_FLT;
				} else if (is_zero_exp (e)) {
					if (nt == type_ptr_tag) {
						/* Null pointers */
						conv = CONV_PTR_NULL;
					} else if (nt == type_ptr_mem_tag) {
						/* Null pointer members */
						conv = CONV_PTR_MEM_NULL;
					}
				}
			}
			break;
		}
		
	case type_bitfield_tag : {
	    /* Ignore any bitfield qualifiers */
	    s = find_bitfield_type (s);
	    ns = TAG_type (s);
	    goto integral_lab;
	}
		
	case type_floating_tag : {
	    /* Floating point arguments */
	    if (nt == type_floating_tag) {
			if (eq_type_unqual (t, s)) {
				/* Exact match */
				conv = CONV_EXACT;
			} else {
				TYPE ps = arg_promote_type (s, KILL_err);
				if (!EQ_type (ps, s) && eq_type_unqual (t, ps)) {
					/* Floating point promotion */
					conv = CONV_FLT_PROM;
				} else {
					/* Floating point conversions */
					conv = CONV_FLT_FLT;
				}
			}
	    } else if (nt == type_integer_tag) {
			/* Floating-integer conversions (subsumes booleans) */
			conv = CONV_FLT_INT;
	    }
	    break;
	}
		
	case type_ptr_tag :
		pointer_lab : {
			/* Pointer arguments */
			if (nt == type_ptr_tag) {
				/* Check for qualifier conversions */
				unsigned qual = check_qualifier (t, s, 0);
				if (qualifier_depth <= 1) {
					CV_SPEC cv = qualifier_diff;
					if (str) cv |= cv_strlit;
					p->qual = cv;
				} else {
					p->qual = cv_multi;
				}
				if (qual == QUAL_EQUAL || qual == QUAL_EQ_FUNC) {
					/* Exact match */
					conv = CONV_EXACT;
					if (str) conv = CONV_STRING;
				} else if (qual == QUAL_OK) {
					/* Qualification conversion */
					conv = CONV_QUAL;
					if (str) conv = CONV_STRING;
				} else if (qual == QUAL_CV) {
					/* Conversion preserves cv-qualifiers */
					TYPE pt = DEREF_type (type_ptr_sub (t));
					TYPE ps = DEREF_type (type_ptr_sub (s));
					nt = TAG_type (pt);
					ns = TAG_type (ps);
					if (nt == type_compound_tag && ns == nt) {
						/* Pointer base class conversions */
						GRAPH gr;
						CLASS_TYPE ct, cs;
						ct = DEREF_ctype (type_compound_defn (pt));
						cs = DEREF_ctype (type_compound_defn (ps));
						gr = find_base_class (cs, ct, 0);
						if (!IS_NULL_graph (gr)) {
							/* Don't worry about ambiguity */
							p->base = gr;
							conv = CONV_PTR_BASE;
						}
					} else if (nt == type_top_tag) {
						if (ns != type_func_tag) {
							/* Pointer to 'void *' conversions */
							conv = CONV_PTR_VOID;
						}
					} else if (nt == type_bottom_tag) {
						if (ns != type_func_tag) {
							/* Pointer to 'void *' conversions */
							conv = CONV_PTR_BOTTOM;
						}
					}
				}
				if (conv == CONV_NONE) {
					/* Check for string literals */
					if (etag == exp_string_lit_tag && !str) {
						if (!(qual & QUAL_CONST)) {
							TYPE ps = DEREF_type (type_ptr_sub (s));
							ps = qualify_type (ps, cv_none, 0);
							s = type_temp_star;
							COPY_type (type_ptr_sub (s), ps);
							str = 1;
							goto pointer_lab;
						}
					}
					
					/* Check for overloaded functions */
					if (etag == exp_address_tag) {
						e = DEREF_exp (exp_address_arg (e));
						etag = TAG_exp (e);
					}
					if (etag == exp_identifier_tag) {
						IDENTIFIER id = DEREF_id (exp_identifier_id (e));
						conv = overload_convert_seq (t, id, p);
					} else if (etag == exp_ambiguous_tag) {
						IDENTIFIER id = DEREF_id (exp_ambiguous_id (e));
						conv = overload_convert_seq (t, id, p);
					}
				}
			} else if (nt == type_integer_tag) {
				if (check_int_type (t, btype_bool)) {
					/* Boolean conversions */
					conv = CONV_BOOL;
				}
			}
			break;
		}
		
#if LANGUAGE_CPP
	case type_ptr_mem_tag : {
	    /* Pointer to member arguments */
	    if (nt == type_ptr_mem_tag) {
			unsigned qual;
			int ctype_match = 0;
			CLASS_TYPE ct = DEREF_ctype (type_ptr_mem_of (t));
			CLASS_TYPE cs = DEREF_ctype (type_ptr_mem_of (s));
			if (eq_ctype (ct, cs)) {
				ctype_match = 2;
			} else {
				GRAPH gr = find_base_class (ct, cs, 0);
				if (!IS_NULL_graph (gr)) {
					ctype_match = 1;
					p->base = gr;
				}
			}
			if (ctype_match) {
				if (etag == exp_address_mem_tag) {
					/* Check overloaded functions */
					IDENTIFIER id;
					e = DEREF_exp (exp_address_mem_arg (e));
					id = DEREF_id (exp_member_id (e));
					if (IS_id_function_etc (id)) {
						conv = overload_convert_seq (t, id, p);
						if (conv != CONV_NONE && ctype_match == 1) {
							conv = CONV_PTR_MEM_BASE;
						}
						break;
					}
				}
				/* Check other cases */
				qual = check_qualifier (t, s, 0);
				if (qualifier_depth <= 1) {
					p->qual = qualifier_diff;
				} else {
					p->qual = cv_multi;
				}
				if (qual == QUAL_EQUAL || qual == QUAL_EQ_FUNC) {
					/* Exact match */
					if (ctype_match == 2) {
						conv = CONV_EXACT;
					} else {
						conv = CONV_PTR_MEM_BASE;
					}
				} else if (qual == QUAL_OK) {
					/* Qualification conversion */
					if (ctype_match == 2) {
						conv = CONV_QUAL;
					} else {
						conv = CONV_PTR_MEM_BASE;
					}
				}
			}
	    } else if (nt == type_integer_tag) {
			if (check_int_type (t, btype_bool)) {
				/* Boolean conversions */
				conv = CONV_BOOL;
			}
	    } else if (nt == type_ptr_tag) {
			if (etag == exp_address_mem_tag) {
				/* Check overloaded functions */
				IDENTIFIER id;
				e = DEREF_exp (exp_address_mem_arg (e));
				id = DEREF_id (exp_member_id (e));
				conv = overload_convert_seq (t, id, p);
			}
	    }
	    break;
	}
#endif
		
	case type_compound_tag : {
	    /* Class arguments */
	    if (nt == type_compound_tag) {
			CV_SPEC cv = cv_compare (t, s);
			if (cv == cv_none || !ref) {
				CLASS_TYPE ct, cs;
				cv = cv_compare (s, t);
				p->qual = cv;
				ct = DEREF_ctype (type_compound_defn (t));
				cs = DEREF_ctype (type_compound_defn (s));
				if (eq_ctype (ct, cs)) {
					/* Class types match */
					if (cv == cv_none) {
						conv = CONV_EXACT;
					} else {
						conv = CONV_QUAL;
					}
				} else {
					/* Examine base classes */
					GRAPH gr = find_base_class (cs, ct, 0);
					if (!IS_NULL_graph (gr)) {
						/* Base class conversion */
						p->base = gr;
						conv = CONV_BASE;
					}
				}
			}
	    }
	    break;
	}
		
	case type_func_tag : {
	    /* Address of overloaded static member function */
	    if (nt == type_ptr_tag && etag == exp_member_tag) {
			IDENTIFIER id = DEREF_id (exp_member_id (e));
			conv = overload_convert_seq (t, id, p);
	    }
	    break;
	}
		
	case type_token_tag : {
	    /* Exact conversion on tokenised type */
	    if (nt == ns && eq_type_unqual (t, s)) {
			conv = CONV_EXACT;
	    }
	    break;
	}
    }
    return (conv);
}


/*
 *    CHECK FOR CONVERSION SEQUENCES
 *
 *    This routine checks whether there is an implicit conversion sequence
 *    corresponding to p.  e gives the argument being converted.  It returns
 *    the value indicating the rank of this conversion.  This is used in
 *    overload resolution to determine the best viable function.
 */

unsigned
convert_seq(CONVERSION *p, EXP e, int bind, int ref)
{
    int match = 0;
    unsigned conv;
    TYPE t = p->to;
    TYPE s = p->from;
    unsigned nt, ns;
    CONVERSION user, best;
    best.rank = CONV_NONE;
	
    /* Conversion to the null type counts as exact */
    if (IS_NULL_type (t)) return (CONV_EXACT);
    nt = TAG_type (t);
	
    /* Conversion from the error type counts as ellipsis */
    ns = TAG_type (s);
    if (ns == type_error_tag) return (CONV_ELLIPSIS);
	
    /* Reference conversion */
    if (ns == type_ref_tag) {
		s = DEREF_type (type_ref_sub (s));
		ns = TAG_type (s);
		if (ns == type_error_tag) return (CONV_ELLIPSIS);
    }
	
    /* Conversion to class type */
    if (nt == type_compound_tag && bind != 1) {
		IDENTIFIER id;
		CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
		complete_class (ct, 1);
		id = DEREF_id (ctype_constr (ct));
		if (ns == type_compound_tag) {
			/* Check for base class conversion */
			conv = std_convert_seq (p, e, bind, ref);
			if (conv != CONV_NONE) return (conv);
			p->from = s;
			p->to = t;
		}
		user.from = s;
		if (IS_id_function_etc (id)) {
			while (!IS_NULL_id (id)) {
				DECL_SPEC ds = DEREF_dspec (id_storage (id));
				if (!(ds & dspec_explicit)) {
					LIST (TYPE) q;
					TYPE fn = DEREF_type (id_function_etc_type (id));
					while (IS_type_templ (fn)) {
						fn = DEREF_type (type_templ_defn (fn));
					}
					q = DEREF_list (type_func_ptypes (fn));
					if (IS_NULL_list (q)) {
						/* Match with ellipsis */
						int ell = DEREF_int (type_func_ellipsis (fn));
						if (ell) {
							conv = CONV_ELLIPSIS;
						} else {
							conv = CONV_NONE;
						}
					} else {
						/* Match with parameter */
						user.to = DEREF_type (HEAD_list (q));
						if (min_no_args (fn) <= 2) {
							conv = std_convert_seq (&user, e, bind, 0);
						} else {
							conv = CONV_NONE;
						}
					}
					if (conv != CONV_NONE) {
						/* Compare against previous conversion */
						if (!match) {
							user.rank = conv;
							user.usr = id;
							user.std = conv;
							best = user;
						}
						match++;
					}
				}
				id = DEREF_id (id_function_etc_over (id));
			}
		}
    }
	
    /* Conversion from class type */
    if (ns == type_compound_tag && bind != 1) {
		/* Check for user-defined conversions */
		LIST (IDENTIFIER) convs;
		CLASS_TYPE cs = DEREF_ctype (type_compound_defn (s));
		complete_class (cs, 1);
		convs = DEREF_list (ctype_conv (cs));
		if (nt == type_ref_tag) {
			/* Check for base class conversion */
			TYPE pt = DEREF_type (type_ref_sub (t));
			if (IS_type_compound (pt)) {
				conv = ref_convert_seq (p, e, bind, 1);
				if (conv != CONV_NONE) return (conv);
				p->from = s;
				p->to = t;
			}
		}
		user.to = t;
		while (!IS_NULL_list (convs)) {
			IDENTIFIER id = DEREF_id (HEAD_list (convs));
			DECL_SPEC ds = DEREF_dspec (id_storage (id));
			if (!(ds & dspec_explicit)) {
				TYPE fn = DEREF_type (id_function_etc_type (id));
				if (IS_type_templ (fn)) {
					/* Allow for template functions */
					fn = deduce_conv (fn, t);
				}
				if (!IS_NULL_type (fn)) {
					TYPE r = DEREF_type (type_func_ret (fn));
					user.from = r;
					if (eq_type (r, t)) {
						conv = CONV_EXACT;
					} else {
						conv = std_convert_seq (&user, e, bind, 0);
					}
					if (conv != CONV_NONE) {
						/* Compare against previous conversion */
						if (!match) {
							user.rank = conv;
							user.usr = id;
							user.std = conv;
							best = user;
						}
						match++;
					}
				}
			}
			convs = TAIL_list (convs);
		}
    }
	
    /* User-defined conversion sequences */
    if (match) {
		*p = best;
		if (match == 1) return (CONV_USER);
		return (CONV_USER_MULTI);
    }
	
    /* Deal with conversions to reference types */
    if (nt == type_ref_tag) {
		conv = ref_convert_seq (p, e, bind, 0);
		return (conv);
    }
	
    /* Standard conversion sequences */
    conv = std_convert_seq (p, e, bind, ref);
    return (conv);
}


/*
 *    COMPARE TWO BASE CLASS CONVERSIONS
 *
 *    This routine compares the base classes given by p and q.  It returns 1
 *    if p is a proper subgraph of q, 2 if q is a proper subgraph of p and
 *    0 otherwise.
 */

static int
base_compare_seq(GRAPH p, GRAPH q)
{
    CLASS_TYPE ct;
    CLASS_TYPE pa, pb;
    CLASS_TYPE qa, qb;
	
    /* Decompose p into pa > pb */
    pb = DEREF_ctype (graph_head (p));
    p = DEREF_graph (graph_top (p));
    pa = DEREF_ctype (graph_head (p));
	
    /* Decompose q into qa > qb */
    qb = DEREF_ctype (graph_head (q));
    q = DEREF_graph (graph_top (q));
    qa = DEREF_ctype (graph_head (q));
	
    if (eq_ctype (pa, qa)) {
		/* Graph tops are equal, pa = qa */
		if (eq_ctype (pb, qb)) {
			/* Graphs are equal */
			return (0);
		}
		ct = compare_base_class (pb, qb, 0);
		if (EQ_ctype (ct, pb)) {
			/* pa = qa > qb > pb */
			return (2);
		}
		if (EQ_ctype (ct, qb)) {
			/* pa = qa > pb > qb */
			return (1);
		}
    } else if (eq_ctype (pb, qb)) {
		/* Graph bottoms are equal, pb = qb */
		ct = compare_base_class (pa, qa, 0);
		if (EQ_ctype (ct, pa)) {
			/* qa > pa > pb = qb */
			return (1);
		}
		if (EQ_ctype (ct, qa)) {
			/* pa > qa > pb = qb */
			return (2);
		}
    }
    return (0);
}


/*
 *    COMPARE TWO QUALIFICATION CONVERSIONS
 *
 *    This routine compares the qualification conversions given by p and q.
 *    It returns 3 if they are identical, 1 if p is better (in that every
 *    qualifier added by p is also added by q), 2 if q is better, and 0
 *    otherwise.  When qualifiers are added at only one level it is just
 *    a matter of comparing the added qualifiers.  If qualifiers are added
 *    at more than one level a trial conversion is carried out.
 */

static int
qual_compare_seq(CONVERSION *p, CONVERSION *q)
{
    CV_SPEC cp = p->qual;
    CV_SPEC cq = q->qual;
    if (cp == cv_multi || cq == cv_multi) {
		/* Qualifiers at more than one level */
		TYPE t;
		unsigned cmp;
		CONVERSION r;
		if (EQ_type (p->from, q->from)) {
			/* Compare to-types */
			r.from = p->to;
			r.to = q->to;
		} else if (EQ_type (p->to, q->to)) {
			/* Compare from-types */
			r.from = q->from;
			r.to = p->from;
		} else {
			/* This shouldn't happen */
			return (0);
		}
		cmp = std_convert_seq (&r, NULL_exp, 0, 0);
		if (cmp == CONV_EXACT) return (3);
		if (cmp != CONV_NONE) return (1);
		t = r.from;
		r.from = r.to;
		r.to = t;
		cmp = std_convert_seq (&r, NULL_exp, 0, 0);
		if (cmp != CONV_NONE) return (2);
    } else {
		/* Qualifiers at only one level */
		CV_SPEC cr;
		if (cp == cq) return (3);
		cr = (cp | cq);
		if (cr == cq) return (1);
		if (cr == cp) return (2);
    }
    return (0);
}


/*
 *    COMPARE TWO CONVERSION SEQUENCES
 *
 *    This routine compares the implicit conversion sequences given by
 *    p1 and p2.  In all cases either the from types of the two conversions
 *    or the to types will be equal.  The routine is used in determining
 *    the best viable function in overload resolution, it returns 1 if the
 *    first conversion is better, 2 if second is better, and some other
 *    value otherwise.
 */

int
compare_seq(CONVERSION *p1, CONVERSION *p2)
{
    /* Compare the ranks of the conversions */
    int cmp = 0;
    unsigned a1 = p1->rank;
    unsigned a2 = p2->rank;
    unsigned b1 = CONV_RANK (a1);
    unsigned b2 = CONV_RANK (a2);
    if (b1 > b2) return (1);
    if (b1 < b2) return (2);
	
    /* Check user-defined conversions */
    if (a1 == CONV_USER && a2 == CONV_USER) {
		if (!EQ_id (p1->usr, p2->usr)) return (0);
		a1 = p1->std;
		a2 = p2->std;
		b1 = CONV_RANK (a1);
		b2 = CONV_RANK (a2);
		if (b1 > b2) return (1);
		if (b1 < b2) return (2);
    }
	
    /* Compare standard conversions */
    switch (a1) {
	case CONV_PTR_BASE : {
	    /* Pointer conversions */
	    if (a2 == a1) {
			/* Compare base pointer conversions */
			GRAPH g1 = p1->base;
			GRAPH g2 = p2->base;
			if (eq_graph (g1, g2)) {
				cmp = qual_compare_seq (p1, p2);
			} else {
				cmp = base_compare_seq (g1, g2);
			}
	    } else if (a2 == CONV_PTR_VOID || a2 == CONV_PTR_BOTTOM) {
			/* Base pointer conversion is better than 'void *' */
			cmp = 1;
	    } else if (a2 == CONV_BOOL) {
			/* Base pointer conversion is better than 'bool' */
			cmp = 1;
	    }
	    break;
	}
	case CONV_PTR_VOID :
	case CONV_PTR_BOTTOM : {
	    /* Pointer to 'void *' conversions */
	    if (a2 == CONV_PTR_VOID || a2 == CONV_PTR_BOTTOM) {
			/* Compare pointer conversions */
			cmp = qual_compare_seq (p1, p2);
	    } else if (a2 == CONV_PTR_BASE) {
			/* Base pointer conversion is better than 'void *' */
			cmp = 2;
	    } else if (a2 == CONV_BOOL) {
			/* Pointer conversion is better than 'bool' */
			cmp = 1;
	    }
	    break;
	}
	case CONV_PTR_MEM_BASE : {
	    /* Pointer member conversions */
	    if (a2 == a1) {
			/* Compare base pointer member conversions */
			GRAPH g1 = p1->base;
			GRAPH g2 = p2->base;
			if (eq_graph (g1, g2)) {
				cmp = qual_compare_seq (p1, p2);
			} else {
				int bmp = base_compare_seq (g1, g2);
				if (bmp) {
					cmp = qual_compare_seq (p1, p2);
					switch (cmp) {
					case 1 : {
						if (bmp != 2) cmp = 0;
						break;
					}
					case 2 : {
						if (bmp != 1) cmp = 0;
						break;
					}
					case 3 : {
						cmp = bmp;
						break;
					}
					}
				}
			}
	    } else if (a2 == CONV_BOOL) {
			/* Pointer conversion is better than 'bool' */
			cmp = 1;
	    }
	    break;
	}
	case CONV_BASE : {
	    /* Base class conversions */
	    if (a2 == a1) {
			/* Compare base class conversions */
			GRAPH g1 = p1->base;
			GRAPH g2 = p2->base;
			if (eq_graph (g1, g2)) {
				cmp = qual_compare_seq (p1, p2);
			} else {
				cmp = base_compare_seq (g1, g2);
			}
	    }
	    break;
	}
	case CONV_BOOL : {
	    /* Boolean conversions */
	    if (a2 == CONV_PTR_BASE || a2 == CONV_PTR_MEM_BASE ||
			a2 == CONV_PTR_VOID || a2 == CONV_PTR_BOTTOM) {
			/* Pointer conversion is better than 'bool' */
			cmp = 2;
	    }
	    break;
	}
	case CONV_STRING : {
	    /* String literal conversions */
	    if (a2 == a1) {
			cmp = qual_compare_seq (p1, p2);
	    } else if (a2 == CONV_QUAL) {
			/* Qualification conversion is better than string */
			cmp = 2;
	    }
	    break;
	}
	case CONV_QUAL : {
	    /* Qualification conversions */
	    if (a2 == a1) {
			cmp = qual_compare_seq (p1, p2);
	    } else if (a2 == CONV_STRING) {
			/* Qualification conversion is better than string */
			cmp = 1;
	    }
	    break;
	}
    }
    return (cmp);
}
