Subversion Repositories tendra.SVN

Rev

Rev 5 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (c) 2002-2006 The TenDRA Project <http://www.tendra.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,
 *    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.
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific, prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 COPYRIGHT HOLDERS OR
 * CONTRIBUTORS 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.
 *
 * $Id$
 */
/*
                 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.
*/


#include "config.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));
                NAT n = round_float_lit(f, crt_round_mode);
                if (!IS_NULL_nat(n) && IS_nat_small(n)) {
                        unsigned v = DEREF_unsigned(nat_small_value(n));
                        if (v < 2) {
                                v = BOOL_VALUE(v);
                                e = make_bool_exp(v, exp_float_lit_tag);
                                return (e);
                        }
                }
                MAKE_exp_test(type_bool, ntest_not_eq, a, e);
                MAKE_nat_calc(e, n);
                MAKE_exp_int_lit(type_bool, n, exp_test_tag, e);
                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;
                        DECONS_exp_null(t, e);
                        MAKE_exp_null(t, e);
                        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);
}