Subversion Repositories tendra.SVN

Rev

Rev 2 | 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 "err_ops.h"
#include "exp_ops.h"
#include "ftype_ops.h"
#include "graph_ops.h"
#include "id_ops.h"
#include "itype_ops.h"
#include "nat_ops.h"
#include "tok_ops.h"
#include "type_ops.h"
#include "error.h"
#include "catalog.h"
#include "option.h"
#include "access.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 "exception.h"
#include "expression.h"
#include "function.h"
#include "identifier.h"
#include "initialise.h"
#include "inttype.h"
#include "literal.h"
#include "overload.h"
#include "predict.h"
#include "statement.h"
#include "syntax.h"
#include "template.h"
#include "tok.h"
#include "tokdef.h"
#include "token.h"
#include "typeid.h"


/*
    CREATE AN EXACT CAST EXPRESSION

    This routine introduces a dummy cast expression which converts the
    expression a to its own type t.  This is needed in a couple of places
    where it is necessary to recognise cast expressions.
*/

static EXP
cast_exact(TYPE t, EXP a)
{
        EXP e;
        if (IS_exp_cast(a)) {
                /* Exact casts are idempotent */
                unsigned conv = DEREF_unsigned(exp_cast_conv(a));
                if (conv == CONV_EXACT) {
                        a = DEREF_exp(exp_cast_arg(a));
                }
        }
        MAKE_exp_cast(t, CONV_EXACT, a, e);
        return (e);
}


/*
    FIND THE RANK OF AN INTEGER-INTEGER CONVERSION

    This routine finds the rank of a conversion to the integral type t
    from the integral type s.  For basic types this is given by the
    table builtin_casts.
*/

static int
rank_int_int(TYPE t, TYPE s)
{
        int ct = 100, cr = 100;
        INT_TYPE is = DEREF_itype(type_integer_sem(s));
        INT_TYPE it = DEREF_itype(type_integer_sem(t));
        INT_TYPE ir = DEREF_itype(type_integer_rep(t));

        /* Find the semantic conversion */
        if (!EQ_itype(it, ir)) {
                if (eq_itype(it, is)) {
                        return (0);
                }
                if (IS_itype_basic(ir) && IS_itype_basic(is)) {
                        BUILTIN_TYPE bt = DEREF_ntype(itype_basic_no(it));
                        BUILTIN_TYPE bs = DEREF_ntype(itype_basic_no(is));
                        ct = builtin_cast(bs, bt);
                }
        }

        /* Find the representational conversion */
        while (IS_itype_promote(ir)) {
                /* Allow for integer promotion conversions */
                ir = DEREF_itype(itype_promote_arg(ir));
        }
        if (eq_itype(ir, is)) {
                return (0);
        }
        if (IS_itype_basic(ir) && IS_itype_basic(is)) {
                BUILTIN_TYPE br = DEREF_ntype(itype_basic_no(ir));
                BUILTIN_TYPE bs = DEREF_ntype(itype_basic_no(is));
                cr = builtin_cast(bs, br);
        } else {
                TYPE ps = promote_type(s);
                if (eq_type(ps, t)) {
                        return (0);
                }
        }

        /* Return the better conversion */
        return (cr < ct ? cr : ct);
}


/*
    FIND THE RANK OF A FLOATING-FLOATING CONVERSION

    This routine finds the rank of a conversion to the floating-point
    type t from the floating-point type s.
*/

static int
rank_float_float(TYPE t, TYPE s)
{
        int ct = 0;
        FLOAT_TYPE fs = DEREF_ftype(type_floating_rep(s));
        FLOAT_TYPE ft = DEREF_ftype(type_floating_rep(t));
        while (IS_ftype_arg_promote(ft)) {
                /* Allow for floating promotion conversions */
                ft = DEREF_ftype(ftype_arg_promote_arg(ft));
        }
        if (!eq_ftype(ft, fs)) {
                if (IS_ftype_basic(ft) && IS_ftype_basic(fs)) {
                        BUILTIN_TYPE nt = DEREF_ntype(ftype_basic_no(ft));
                        BUILTIN_TYPE ns = DEREF_ntype(ftype_basic_no(fs));
                        ct = builtin_cast(ns, nt);
                } else {
                        TYPE ps = promote_type(s);
                        if (eq_type(ps, t)) {
                                return (0);
                        }
                }
        }
        return (ct);
}


/*
    PERFORM AN INTEGER-INTEGER CONVERSION

    This, and the following routines, are used to perform the basic type
    conversions allowed within the language.  Each takes a destination
    type t and an argument expression a.  In this case both t and the type
    of a are integral (including enumeration and bitfield) types.  The case
    where t is bool is dealt with separately by convert_boolean, however a
    may have type bool.  rank gives the rank of the conversion, or -1 if
    the rank needs to be calculated using rank_int_int.
*/

EXP
cast_int_int(TYPE t, EXP a, ERROR *err, unsigned cast, int rank)
{
        EXP e;
        int opt;
        TYPE s = DEREF_type(exp_type(a));
        unsigned nt = TAG_type(t);
        unsigned ns = TAG_type(s);

        /* Don't force unnecessary token definitions */
        if (force_tokdef) {
                TYPE t0 = t;
                TYPE s0 = s;
                t = expand_type(t0, 1);
                if (!EQ_type(t, t0)) {
                        nt = TAG_type(t);
                        if (nt == type_floating_tag || nt == type_ptr_tag) {
                                t = t0;
                                nt = TAG_type(t);
                        }
                }
                s = expand_type(s0, 1);
                if (!EQ_type(s, s0)) {
                        ns = TAG_type(s);
                        if (ns == type_floating_tag || ns == type_ptr_tag) {
                                s = s0;
                                ns = TAG_type(s);
                        }
                }
        }

        /* Deal with bitfields */
        if (ns == type_bitfield_tag) {
                TYPE r = find_bitfield_type(s);
                MAKE_exp_cast(r, CONV_BITFIELD, a, a);
                /* NOT YET IMPLEMENTED: find rank */
                rank = 0;
                e = cast_int_int(t, a, err, cast, rank);
                if (EQ_exp(e, a)) {
                        MAKE_exp_cast(t, CONV_INT_INT, e, e);
                }
                return (e);
        }
        if (nt == type_bitfield_tag) {
                TYPE r = find_bitfield_type(t);
                /* NOT YET IMPLEMENTED: find rank */
                rank = 0;
                e = cast_int_int(r, a, err, cast, rank);
                if (EQ_exp(e, a)) {
                        MAKE_exp_cast(r, CONV_INT_INT, e, e);
                }
                MAKE_exp_cast(t,(CONV_BITFIELD | CONV_REVERSE), e, e);
                return (e);
        }

        /* Deal with identity casts */
        if (nt == ns) {
                if (EQ_type(t, s)) {
                        if (IS_exp_int_lit(a) && cast != CAST_IMPLICIT) {
                                NAT n = DEREF_nat(exp_int_lit_nat(a));
                                MAKE_exp_int_lit(t, n, exp_cast_tag, a);
                        }
                        return (a);
                }
                if (eq_type(t, s)) {
                        if (cast == CAST_IMPLICIT) {
                                /* Preserve semantics for implicit casts */
                                return (a);
                        }
                        if (cast != CAST_REINTERP) {
                                /* Override semantics for other casts */
                                if (IS_exp_int_lit(a)) {
                                        NAT n = DEREF_nat(exp_int_lit_nat(a));
                                        MAKE_exp_int_lit(t, n, exp_cast_tag, e);
                                } else {
                                        MAKE_exp_cast(t, CONV_INT_INT, a, e);
                                }
                                return (e);
                        }
                }
        }

        /* Find error severity level */
        if (cast == CAST_IMPLICIT) {
                opt = OPT_conv_int_int_impl;
        } else if (cast & CAST_STATIC) {
                opt = OPT_conv_int_int_expl;
        } else {
                opt = OPT_error;
        }

        /* Can't cast implicitly to enumeration type */
        if (nt == type_enumerate_tag) {
                ERROR err2;
#if LANGUAGE_C
                if (IS_exp_int_lit(a)) {
                        /* Allow for C enumerators */
                        unsigned tag = DEREF_unsigned(exp_int_lit_etag(a));
                        if (tag == exp_identifier_tag) {
                                e = make_cast_nat(t, a, err, cast);
                                return (e);
                        }
                }
#endif
                if (cast == CAST_IMPLICIT) {
                        if (option(OPT_conv_int_enum) > option(opt)) {
                                opt = OPT_conv_int_enum;
                        }
                }
                if (ns == type_enumerate_tag) {
                        err2 = ERR_expr_cast_stat_enum_enum(s, t);
                } else {
                        err2 = ERR_expr_cast_stat_int_enum(s, t);
                }
                err2 = set_severity(err2, opt, 0);
                if (!IS_NULL_err(err2)) {
                        e = cast_token(t, a, err, err2, cast);
                        if (!IS_NULL_exp(e)) {
                                return (e);
                        }
                }
        } else if (opt == OPT_error) {
                ERROR err2 = ERR_conv_integral_cast(s, t);
                err2 = set_severity(err2, opt, 0);
                if (!IS_NULL_err(err2)) {
                        e = cast_token(t, a, err, err2, cast);
                        if (!IS_NULL_exp(e)) {
                                return (e);
                        }
                }
                opt = OPT_none;
        }

        /* Deal with integral constants */
        if (IS_exp_int_lit(a)) {
                e = make_cast_nat(t, a, err, cast);
                return (e);
        }

        /* Check integer to integer conversions */
        if (rank != 0 && option(opt)) {
                if (nt == type_integer_tag && ns == type_integer_tag) {
                        if (rank < 0) {
                                rank = rank_int_int(t, s);
                        }
                        if (rank >= max_builtin_cast) {
                                ERROR err2 = ERR_conv_integral_cast(s, t);
                                err2 = set_severity(err2, opt, 0);
                                if (!IS_NULL_err(err2)) {
                                        e = cast_token(t, a, err, err2, cast);
                                        if (!IS_NULL_exp(e)) {
                                                return (e);
                                        }
                                }
                        }
                }
        }

        /* Construct the result */
        MAKE_exp_cast(t, CONV_INT_INT, a, e);
        return (e);
}


/*
    PERFORM A INTEGER-FLOAT CONVERSION

    This routine converts the integral expression a to the floating point
    type t.
*/

EXP
cast_int_float(TYPE t, EXP a, ERROR *err, unsigned cast)
{
        EXP e;
        int opt;
        TYPE s = DEREF_type(exp_type(a));

        /* Find error severity level */
        if (cast == CAST_IMPLICIT) {
                opt = OPT_conv_int_int_impl;
        } else if (cast & CAST_STATIC) {
                opt = OPT_conv_int_int_expl;
        } else {
                opt = OPT_error;
        }
        if (option(opt)) {
                ERROR err2 = ERR_conv_fpint_float(s, t);
                err2 = set_severity(err2, opt, 0);
                if (!IS_NULL_err(err2)) {
                        e = cast_token(t, a, err, err2, cast);
                        if (!IS_NULL_exp(e)) {
                                return (e);
                        }
                }
        }

        /* Construct the result */
        MAKE_exp_cast(t, CONV_INT_FLT, a, e);
        return (e);
}


/*
    PERFORM A FLOAT-INTEGER CONVERSION

    This routine converts the floating point expression a to the integral
    type t (which will not be bool).  Note that a floating point literal
    cast to an integral type is an integral constant expression.
*/

static EXP
cast_float_int(TYPE t, EXP a, ERROR *err, unsigned cast)
{
        EXP e;
        int opt;
        TYPE s = DEREF_type(exp_type(a));

        /* Find error severity level */
        if (cast == CAST_IMPLICIT) {
                opt = OPT_conv_int_int_impl;
                if (IS_type_enumerate(t)) {
                        /* Can't have enumeration type */
                        if (option(OPT_conv_int_enum) > option(opt)) {
                                opt = OPT_conv_int_enum;
                        }
                }
        } else if (cast & CAST_STATIC) {
                opt = OPT_conv_int_int_expl;
        } else {
                opt = OPT_error;
        }
        if (option(opt)) {
                ERROR err2 = ERR_conv_fpint_trunc(s, t);
                err2 = set_severity(err2, opt, 0);
                if (!IS_NULL_err(err2)) {
                        e = cast_token(t, a, err, err2, cast);
                        if (!IS_NULL_exp(e)) {
                                return (e);
                        }
                }
        }

        /* Construct the result */
        MAKE_exp_cast(t, CONV_FLT_INT, a, e);

        /* Deal with floating point literals */
        if (IS_exp_float_lit(a)) {
                FLOAT f = DEREF_flt(exp_float_lit_flt(a));
                NAT n = round_float_lit(f, crt_round_mode);
                if (!IS_NULL_nat(n)) {
                        EXP c = make_int_exp(t, exp_cast_tag, n);
                        if (!IS_NULL_exp(c)) {
                                return (c);
                        }
                }
                MAKE_nat_calc(e, n);
                MAKE_exp_int_lit(t, n, exp_cast_tag, e);
        }
        return (e);
}


/*
    PERFORM A FLOAT-FLOAT CONVERSION

    This routine converts the floating point expression a to the floating
    point type t.
*/

EXP
cast_float_float(TYPE t, EXP a, ERROR *err, unsigned cast)
{
        EXP e;
        int opt;
        TYPE s = DEREF_type(exp_type(a));

        /* Don't force unnecessary token definitions */
        if (force_tokdef) {
                TYPE t0 = t;
                TYPE s0 = s;
                t = expand_type(t0, 1);
                s = expand_type(s0, 1);
                if (!IS_type_floating(t)) {
                        t = t0;
                }
                if (!IS_type_floating(s)) {
                        s = s0;
                }
        }

        /* Deal with identity casts */
        if (eq_type(t, s)) {
                if (cast != CAST_REINTERP) {
                        return (a);
                }
        }

        /* Find error severity level */
        if (cast == CAST_IMPLICIT) {
                opt = OPT_conv_int_int_impl;
        } else if (cast & CAST_STATIC) {
                opt = OPT_conv_int_int_expl;
        } else {
                opt = OPT_error;
        }
        if (option(opt)) {
                int c = rank_float_float(t, s);
                if (c >= max_builtin_cast || opt == OPT_error) {
                        ERROR err2 = ERR_conv_double_cast(s, t);
                        err2 = set_severity(err2, opt, 0);
                        if (!IS_NULL_err(err2)) {
                                e = cast_token(t, a, err, err2, cast);
                                if (!IS_NULL_exp(e)) {
                                        return (e);
                                }
                        }
                }
        }

        /* Construct the result */
        MAKE_exp_cast(t, CONV_FLT_FLT, a, e);
        return (e);
}


/*
    CONSTRUCT AN UNRESOLVED CAST EXPRESSION

    This routine creates an expression for casting the expression a to
    type t using cast where either t or the type of a depends on a
    template parameter type.
*/

EXP
cast_templ_type(TYPE t, EXP a, unsigned cast)
{
        EXP e;
        int op;
        switch (cast) {
        case CAST_IMPLICIT:
                op = lex_implicit;
                break;
        case CAST_STATIC:
                op = lex_static_Hcast;
                break;
        case CAST_REINTERP:
                op = lex_reinterpret_Hcast;
                break;
        case CAST_CONST:
                op = lex_const_Hcast;
                break;
        default:
                op = lex_cast;
                break;
        }
        t = rvalue_type(t);
        MAKE_exp_op(t, op, a, NULL_exp, e);
        return (e);
}


/*
    REPORT CASTING AWAY CONST-NESS

    This routine adds an error to the end of err if the value qual returned
    by check_qualifier indicates that a particular conversion casts away
    const-ness (or volatile-ness).
*/

void
cast_away_const(unsigned qual, ERROR *err, unsigned cast)
{
        if (!(cast & CAST_CONST)) {
                CV_SPEC cv = cv_none;
                if (!(qual & QUAL_CONST)) {
                        cv |= cv_const;
                }
                if (!(qual & QUAL_VOLATILE)) {
                        cv |= cv_volatile;
                }
                if (cv == cv_none) {
                        if (!(qual & QUAL_ALL_CONST)) {
                                add_error(err, ERR_conv_qual_multi());
                        }
                } else {
                        add_error(err, ERR_conv_qual_cast(cv));
                }
        }
        return;
}


/*
    CREATE A BASE CAST EXPRESSION

    This routine creates a base cast expression for converting the
    expression a to type t using the offset off.  If off is a zero offset
    (indicating single inheritance) or the type of a can be statically
    determined then this is a simple add_ptr operation.  Otherwise a
    base_cast expression is used.  Note that a dummy expression is
    introduced to represent the argument.
*/

EXP
make_base_cast(TYPE t, EXP a, OFFSET off)
{
        EXP e;
        if (is_zero_offset(off) || know_type(a) == 1) {
                MAKE_exp_add_ptr(t, a, off, 0, e);
        } else {
                TYPE s = DEREF_type(exp_type(a));
                if (!IS_type_ptr(s)) {
                        s = t;
                }
                MAKE_exp_dummy(s, a, LINK_NONE, NULL_off, 1, a);
                MAKE_exp_base_cast(t, CONV_PTR_BASE, a, off, e);
        }
        return (e);
}


/*
    PERFORM A POINTER-POINTER CONVERSION

    This routine converts the pointer expression a to the pointer type t.
    Pointers can be partitioned into pointer to object, pointer to function
    and void * for the purposes of pointer casts.  Note that even identity
    function casts are always performed.  This is to prevent further function
    overload resolution and to inherit any default arguments from t.  Also
    if force is true then an identity explicit cast is inserted after any
    base pointer cast.  This is to allow for TDF operations such as
    pointer_test which require exact equality of alignments.
*/

EXP
cast_ptr_ptr(TYPE t, EXP a, ERROR *err, unsigned cast, int safe, int force)
{
        EXP e;
        int opt;
        unsigned qual;
        OFFSET off = NULL_off;
        unsigned conv = CONV_NONE;
        TYPE s = DEREF_type(exp_type(a));
        TYPE pt = DEREF_type(type_ptr_sub(t));
        TYPE ps = DEREF_type(type_ptr_sub(s));
        unsigned nt = TAG_type(pt);
        unsigned ns = TAG_type(ps);

        /* Allow for tokenised types */
        if (nt == type_token_tag) {
                t = expand_type(t, 1);
                pt = DEREF_type(type_ptr_sub(t));
                nt = TAG_type(pt);
        }
        if (ns == type_token_tag) {
                s = expand_type(s, 1);
                ps = DEREF_type(type_ptr_sub(s));
                ns = TAG_type(ps);
        }

        /* Check for qualifier conversions */
        qual = check_qualifier(t, s, safe);
        if (qual == QUAL_EQUAL) {
                /* Allow for type equality */
                if (cast != CAST_IMPLICIT) {
                        a = cast_exact(t, a);
                }
                return (a);
        }
        if (qual == QUAL_EQ_FUNC) {
                /* Allow for equality of function types */
                if (!(cast & CAST_REINTERP) && !eq_except(ps, pt)) {
                        add_error(err, ERR_except_spec_assign());
                }
                e = cast_exact(t, a);
                return (e);
        }
        if (qual & QUAL_TEMPL) {
                /* Conversion depends on template parameter */
                e = cast_templ_type(t, a, cast);
                return (e);
        }
        if (!(qual & QUAL_CONST)) {
                /* Check for string literal conversions */
                if (IS_exp_address(a) && ns == type_integer_tag) {
                        EXP b = DEREF_exp(exp_address_arg(a));
                        if (IS_exp_string_lit(b)) {
                                /* Remove const and try again */
                                int str = 1;
                                if (!(cast & CAST_CONST)) {
                                        str = 2;
                                }
                                a = convert_array(b, str, err);
                                e = cast_ptr_ptr(t, a, err, cast, safe, force);
                                return (e);
                        }
                }
        }
        if (!(qual & QUAL_VOLATILE) && used_extern_volatile) {
                /* Check for implicitly volatile external objects */
                EXP pa = NULL_exp;
                DECL_SPEC ds = find_exp_linkage(a, &pa, 1);
                if (ds & dspec_implicit) {
                        qual |= QUAL_VOLATILE;
                }
        }

        /* Check conversion */
        if (qual & QUAL_SIMILAR) {
                /* Simple qualification conversions */
                opt = OPT_none;
                conv = CONV_QUAL;
        } else {
                /* Other pointer conversions */
                ERROR ferr = NULL_err;
                switch (nt) {
                case type_top_tag:
                case type_bottom_tag:
generic_lab:
                        if (ns == type_func_tag) {
                                /* Conversion from 'function *' to 'void *' */
                                ERROR err2 = ERR_expr_cast_reint_func_ptr(s, t);
                                if (!IS_NULL_err(err2)) {
                                        e = cast_token(t, a, err, err2, cast);
                                        if (!IS_NULL_exp(e)) {
                                                return (e);
                                        }
                                }
                        }
                        if (ns == type_top_tag || ns == type_bottom_tag) {
                                /* Conversion from 'void *' to 'void *' */
                                opt = OPT_none;
                                if (nt == type_integer_tag) {
                                        conv = (CONV_PTR_VOID | CONV_REVERSE);
                                } else {
                                        conv = CONV_EXACT;
                                }
                        } else {
                                /* Conversion from 'object *' to 'void *' */
                                TYPE r = NULL_type;
                                if (ns == type_integer_tag) {
                                        /* Check for generic pointers */
                                        r = type_void_star;
                                        r = type_composite(s, r, 1, 0, &ferr,
                                                           0);
                                }
                                if (!IS_NULL_type(r)) {
                                        opt = OPT_none;
                                } else if (cast == CAST_IMPLICIT) {
                                        opt = OPT_conv_ptr_ptr_void;
                                } else if (cast == CAST_CONST) {
                                        opt = OPT_error;
                                } else {
                                        opt = OPT_none;
                                }
                                if (nt != type_integer_tag)conv = CONV_PTR_VOID;
                        }
                        break;
                case type_compound_tag: {
                        if (cast == CAST_CONST || cast == CAST_REINTERP) {
                                goto default_lab;
                        }
                        if (ns == type_compound_tag) {
                                /* Conversion from 'class *' to 'class *' */
                                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, 1);
                                if (!IS_NULL_graph(gr)) {
                                        /* Base class conversion */
                                        ERROR err2 = check_ambig_base(gr);
                                        if (!IS_NULL_err(err2)) {
                                                /* Can't be ambiguous */
                                                e = cast_token(t, a, err, err2,
                                                               cast);
                                                if (!IS_NULL_exp(e)) {
                                                        return (e);
                                                }
                                                add_error(err, ERR_conv_ptr_ambiguous());
                                        }
                                        if (!(cast & CAST_BAD)) {
                                                /* Check base access */
                                                check_base_access(gr);
                                        }
                                        off = DEREF_off(graph_off(gr));
                                        conv = CONV_PTR_BASE;
                                        opt = OPT_none;
                                        break;
                                }
                                if (cast & CAST_STATIC) {
                                        gr = find_base_class(ct, cs, 1);
                                        if (!IS_NULL_graph(gr)) {
                                                /* Reverse base class
                                                 * conversion */
                                                ERROR err2 =
                                                    check_ambig_base(gr);
                                                if (!IS_NULL_err(err2)) {
                                                        /* Can't be ambiguous */
                                                        e = cast_token(t, a, err, err2, cast);
                                                        if (!IS_NULL_exp(e)) {
                                                                return (e);
                                                        }
                                                        add_error(err, ERR_conv_ptr_ambiguous());
                                                }
                                                err2 = check_virt_base(gr);
                                                if (!IS_NULL_err(err2)) {
                                                        /* Can't be virtual */
                                                        e = cast_token(t, a, err, err2, cast);
                                                        if (!IS_NULL_exp(e)) {
                                                                return (e);
                                                        }
                                                        add_error(err, ERR_expr_cast_stat_virt());
                                                }
                                                if (!(cast & CAST_BAD)) {
                                                        /* Check base access */
                                                        check_base_access(gr);
                                                }
                                                off = DEREF_off(graph_off(gr));
                                                conv = (CONV_PTR_BASE |
                                                        CONV_REVERSE);
                                                opt = OPT_none;
                                                break;
                                        }
                                }
                        }
                        goto default_lab;
                }
                case type_func_tag: {
                        if (ns != type_func_tag) {
                                /* Conversion from 'function *' to 'object *' */
                                ERROR err2 = ERR_expr_cast_reint_func_ptr(s, t);
                                if (!IS_NULL_err(err2)) {
                                        e = cast_token(t, a, err, err2, cast);
                                        if (!IS_NULL_exp(e)) {
                                                return (e);
                                        }
                                }
                                goto object_lab;
                        }
                        /* Conversion from 'function *' to 'function *' */
                        if (cast & CAST_REINTERP) {
                                opt = OPT_conv_ptr_ptr_expl;
                        } else {
                                opt = OPT_conv_ptr_ptr_impl;
                        }
                        conv = CONV_FUNC;
                        break;
                }
                case type_integer_tag: {
                        /* Check for generic pointers */
                        TYPE r = type_void_star;
                        r = type_composite(t, r, 1, 0, &ferr, 0);
                        if (!IS_NULL_type(r)) {
                                goto generic_lab;
                        }
                        goto default_lab;
                }
                default:
default_lab:
                        if (ns == type_func_tag) {
                                /* Conversion from 'function *' to 'object *' */
                                ERROR err2 = ERR_expr_cast_reint_func_ptr(s, t);
                                if (!IS_NULL_err(err2)) {
                                        e = cast_token(t, a, err, err2, cast);
                                        if (!IS_NULL_exp(e)) {
                                                return (e);
                                        }
                                }
                        }
                        goto object_lab;
object_lab: {
                        TYPE r = NULL_type;
                        if (ns == type_integer_tag) {
                                /* Check for generic pointers */
                                r = type_void_star;
                                r = type_composite(s, r, 1, 0, &ferr, 0);
                        }
                        if (IS_NULL_type(r)) {
                                if (ns != type_top_tag &&
                                    ns != type_bottom_tag) {
                                        /* Conversion from 'object *' to
                                         * 'object *' */
                                        if (cast & CAST_REINTERP) {
                                                opt = OPT_conv_ptr_ptr_expl;
                                        } else {
                                                opt = OPT_conv_ptr_ptr_impl;
                                        }
                                        break;
                                }
                        }
                        /* Conversion from 'void *' to 'object *' */
                        if (cast == CAST_IMPLICIT) {
                                opt = OPT_conv_ptr_void_ptr;
                        } else if (cast == CAST_CONST) {
                                opt = OPT_error;
                        } else {
                                opt = OPT_none;
                        }
                        if (IS_NULL_type(r)) {
                                conv = (CONV_PTR_VOID | CONV_REVERSE);
                        }
                        break;
            }
                }

                /* Add generic pointer errors */
                if (!IS_NULL_err(ferr)) {
                        if (opt == OPT_none) {
                                destroy_error(ferr, 1);
                        } else {
                                add_error(err, ferr);
                        }
                }

                /* Check for function linkage conversions */
                if ((qual & QUAL_FUNC) && opt == OPT_conv_ptr_ptr_impl) {
                        opt = OPT_func_linkage;
                }
        }

        /* Report any conversion errors */
        if (option(opt)) {
                ERROR err2;
                switch (opt) {
                case OPT_func_linkage: {
                        err2 = ERR_dcl_link_conv();
                        break;
                }
                case OPT_conv_ptr_ptr_expl:
                case OPT_conv_ptr_ptr_impl: {
                        err2 = ERR_basic_link_incompat(ps, pt);
                        err2 = concat_error(err2, ERR_conv_ptr_incompat());
                        break;
                }
                default : {
                        err2 = ERR_conv_ptr_cast(s, t);
                        break;
                }
                }
                err2 = set_severity(err2, opt, 0);
                if (!IS_NULL_err(err2)) {
                        e = cast_token(t, a, err, err2, cast);
                        if (!IS_NULL_exp(e)) {
                                return (e);
                        }
                }
        }
        if (qual != QUAL_OK) {
                cast_away_const(qual, err, cast);
        }

        /* Construct the result */
        if (IS_exp_null(a)) {
                /* Deal with null pointers */
                e = make_null_exp(t);
        } else if (conv == CONV_PTR_BASE) {
                /* Deal with base class conversions */
                e = make_base_cast(t, a, off);
                if (force) {
                        /* Force pointer cast */
                        conv = (CONV_PTR_PTR | CONV_REVERSE);
                        MAKE_exp_cast(t, conv, e, e);
                }
        } else if (conv == (CONV_PTR_BASE | CONV_REVERSE)) {
                /* Deal with reverse base class conversions */
                MAKE_exp_cast(t, CONV_PTR_PTR, a, a);
                if (is_zero_offset(off)) {
                        e = a;
                } else {
                        MAKE_exp_dummy(t, a, LINK_NONE, NULL_off, 1, a);
                        MAKE_exp_base_cast(t, conv, a, off, e);
                        if (force) {
                                /* Force pointer cast */
                                conv = (CONV_PTR_PTR | CONV_REVERSE);
                                MAKE_exp_cast(t, conv, e, e);
                        }
                }
        } else {
                if (conv == CONV_NONE) {
                        if (eq_type_offset(pt, ps)) {
                                conv = CONV_PTR_PTR_ALIGN;
                        } else {
                                conv = CONV_PTR_PTR;
                        }
                }
                MAKE_exp_cast(t, conv, a, e);
        }
        return (e);
}


/*
    PERFORM A INTEGER-POINTER CONVERSION

    This routine converts the integral expression a to the pointer type t.
    There are two cases, depending on whether a represents a null pointer.
*/

static EXP
cast_int_ptr(TYPE t, EXP a, ERROR *err, unsigned cast, int nptr)
{
        EXP e;
        int opt;
        if (nptr && (cast == CAST_IMPLICIT || (cast & CAST_STATIC))) {
                /* Deal with null pointers */
                EXP b = make_null_ptr(a, t);
                if (!IS_NULL_exp(b)) {
                        return (b);
                }
        }
        if (cast & CAST_REINTERP) {
                opt = OPT_conv_int_ptr_expl;
        } else {
                opt = OPT_conv_int_ptr_impl;
        }
        if (option(opt)) {
                TYPE s = DEREF_type(exp_type(a));
                ERROR err2 = ERR_conv_ptr_nonzero(s, t);
                err2 = set_severity(err2, opt, 0);
                if (!IS_NULL_err(err2)) {
                        e = cast_token(t, a, err, err2, cast);
                        if (!IS_NULL_exp(e)) {
                                return (e);
                        }
                }
        }
        MAKE_exp_cast(t, CONV_INT_PTR, a, e);
        return (e);
}


/*
    PERFORM A POINTER-INTEGER CONVERSION

    This routine converts the pointer expression a to the integral type t
    (which will not be bool).
*/

static EXP
cast_ptr_int(TYPE t, EXP a, ERROR *err, unsigned cast)
{
        EXP e;
        int opt;
        if (IS_exp_null(a)) {
                if (cast & CAST_STATIC) {
                        MAKE_exp_cast(t, CONV_NULL, a, e);
                        return (e);
                }
        }
        if (cast & CAST_REINTERP) {
                opt = OPT_conv_int_ptr_expl;
        } else {
                opt = OPT_conv_int_ptr_impl;
        }
        if (option(opt)) {
                TYPE s = DEREF_type(exp_type(a));
                ERROR err2 = ERR_expr_cast_reint_ptr_int(s, t);
                if (!IS_NULL_err(err2)) {
                        e = cast_token(t, a, err, err2, cast);
                        if (!IS_NULL_exp(e)) {
                                return (e);
                        }
                }
        }
        MAKE_exp_cast(t, CONV_PTR_INT, a, e);
        return (e);
}


/*
    PERFORM A POINTER MEMBER-POINTER MEMBER CONVERSION

    This routine converts the pointer to member expression a to the pointer
    to member type t.  force is as in cast_ptr_ptr.
*/

EXP
cast_ptr_mem_ptr_mem(TYPE t, EXP a, ERROR *err, unsigned cast, int safe,
                     int force)
{
        EXP e;
        int ok = 2;
        unsigned conv = CONV_EXACT;
        TYPE s = DEREF_type(exp_type(a));

        if (cast != CAST_REINTERP) {
                /* Check for base class conversions */
                OFFSET off = NULL_off;
                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)) {
                        GRAPH gr = find_base_class(ct, cs, 1);
                        if (!IS_NULL_graph(gr)) {
                                /* cs is a base class of ct */
                                ERROR err2 = check_ambig_base(gr);
                                if (!IS_NULL_err(err2)) {
                                        /* Can't be ambiguous */
                                        e = cast_token(t, a, err, err2, cast);
                                        if (!IS_NULL_exp(e)) {
                                                return (e);
                                        }
                                        add_error(err, ERR_conv_mem_ambiguous());
                                }
                                err2 = check_virt_base(gr);
                                if (!IS_NULL_err(err2)) {
                                        /* Can't be virtual */
                                        e = cast_token(t, a, err, err2, cast);
                                        if (!IS_NULL_exp(e)) {
                                                return (e);
                                        }
                                        add_error(err, ERR_conv_mem_virtual());
                                }
                                if (!(cast & CAST_BAD)) {
                                        /* Check base access */
                                        check_base_access(gr);
                                }
                                off = DEREF_off(graph_off(gr));
                                conv = CONV_PTR_MEM_BASE;
                                ok = 1;
                        } else {
                                /* cs is not a base class of ct */
                                if (cast & CAST_STATIC) {
                                        gr = find_base_class(cs, ct, 1);
                                        if (!IS_NULL_graph(gr)) {
                                                /* ct is a base class of cs */
                                                ERROR err2 = check_ambig_base(gr);
                                                if (!IS_NULL_err(err2)) {
                                                        /* Can't be ambiguous */
                                                        e = cast_token(t, a, err, err2, cast);
                                                        if (!IS_NULL_exp(e)) {
                                                                return (e);
                                                        }
                                                        add_error(err, ERR_conv_mem_ambiguous());
                                                }
                                                err2 = check_virt_base(gr);
                                                if (!IS_NULL_err(err2)) {
                                                        /* Can't be virtual */
                                                        e = cast_token(t, a, err, err2, cast);
                                                        if (!IS_NULL_exp(e)) {
                                                                return (e);
                                                        }
                                                        add_error(err, ERR_conv_mem_virtual());
                                                }
                                                if (!(cast & CAST_BAD)) {
                                                        /* Check base access */
                                                        check_base_access(gr);
                                                }
                                                off = DEREF_off(graph_off(gr));
                                                conv = (CONV_PTR_MEM_BASE | CONV_REVERSE);
                                                ok = 1;
                                        } else {
                                                ok = 0;
                                        }
                                } else {
                                        ok = 0;
                                }
                        }

                        if (ok == 0 && in_template_decl) {
                                /* Allow for template parameter types */
                                TYPE ft = DEREF_type(ctype_form(ct));
                                TYPE fs = DEREF_type(ctype_form(cs));
                                if (is_templ_depend(ft) ||
                                    is_templ_depend(fs)) {
                                        /* Check further */
                                        ok = -1;
                                }
                        }
                }

                /* Check for qualification conversions */
                if (ok) {
                        unsigned qual;
                        TYPE pt = DEREF_type(type_ptr_mem_sub(t));
                        TYPE ps = DEREF_type(type_ptr_mem_sub(s));
                        if (IS_type_token(pt)) {
                                t = expand_type(t, 1);
                        }
                        if (IS_type_token(ps)) {
                                s = expand_type(s, 1);
                        }
                        qual = check_qualifier(t, s, safe);
                        if (qual == QUAL_EQUAL) {
                                /* Type equality */
                                if (ok == 2) {
                                        if (cast != CAST_IMPLICIT) {
                                                a = cast_exact(t, a);
                                        }
                                        return (a);
                                }
                                qual = QUAL_OK;
                        } else if (qual == QUAL_EQ_FUNC) {
                                /* Function type equality */
                                if (!(cast & CAST_REINTERP) &&
                                    !eq_except(ps, pt)) {
                                        /* Exception specifications don't
                                         * match */
                                        add_error(err, ERR_except_spec_assign());
                                }
                                if (ok == 2) {
                                        e = cast_exact(t, a);
                                        return (e);
                                }
                                qual = QUAL_OK;
                        }
                        if ((qual & QUAL_TEMPL) || ok == -1) {
                                /* Conversion depends on template parameter */
                                e = cast_templ_type(t, a, cast);
                                return (e);
                        }
                        if (qual & QUAL_SIMILAR) {
                                /* Check for casting away const-ness */
                                if (qual != QUAL_OK) {
                                        cast_away_const(qual, err, cast);
                                }
                                if (ok == 2) {
                                        MAKE_exp_cast(t, CONV_QUAL, a, e);
                                } else {
                                        MAKE_exp_dummy(s, a, LINK_NONE, NULL_off, 1, a);
                                        MAKE_exp_base_cast(t, conv, a, off, e);
                                        UNUSED(force);
                                }
                                return (e);
                        }
                        ok = 0;
                }
        }

        /* Check for reinterpret conversions */
        conv = CONV_NONE;
        if (cast & CAST_REINTERP) {
                unsigned nt = TAG_type(t);
                unsigned ns = TAG_type(s);
                if (nt == type_func_tag) {
                        ok = (ns == type_func_tag ? 1 : 0);
                } else {
                        ok = (ns == type_func_tag ? 0 : 1);
                }
                if (ok) {
                        unsigned qual = check_qualifier(t, s, safe);
                        if (qual != QUAL_OK) {
                                cast_away_const(qual, err, cast);
                        }
                        conv = CONV_PTR_MEM_PTR_MEM;
                }
        }

        /* Invalid cast expression */
        if (!ok) {
                ERROR err2 = ERR_conv_mem_cast(s, t);
                if (!IS_NULL_err(err2)) {
                        e = cast_token(t, a, err, err2, cast);
                        if (!IS_NULL_exp(e)) {
                                return (e);
                        }
                }
        }
        MAKE_exp_cast(t, conv, a, e);
        return (e);
}


/*
    PERFORM A INTEGER-POINTER MEMBER CONVERSION

    This routine converts the integral expression a to the pointer to
    member type t.  The only valid case is when a is zero.
*/

static EXP
cast_int_ptr_mem(TYPE t, EXP a, ERROR *err, unsigned cast, int nptr)
{
        EXP e;
        TYPE s;
        ERROR err2;
        if (nptr && (cast == CAST_IMPLICIT || (cast & CAST_STATIC))) {
                /* Deal with null pointers */
                EXP b = make_null_ptr(a, t);
                if (!IS_NULL_exp(b)) {
                        return (b);
                }
        }
        s = DEREF_type(exp_type(a));
        err2 = ERR_conv_mem_nonzero(s, t);
        if (!IS_NULL_err(err2)) {
                e = cast_token(t, a, err, err2, cast);
                if (!IS_NULL_exp(e)) {
                        return (e);
                }
        }
        MAKE_exp_cast(t, CONV_NONE, a, e);
        return (e);
}


/*
    PERFORM A POINTER MEMBER-INTEGER CONVERSION

    This routine converts the pointer to member expression a to the
    integral type t.  The only valid case is when a is a null pointer.
    In all other cases the null expression is returned.
*/

static EXP
cast_ptr_mem_int(TYPE t, EXP a, ERROR *err, unsigned cast)
{
        if (IS_exp_null(a)) {
                if (cast & CAST_STATIC) {
                        EXP e;
                        MAKE_exp_cast(t, CONV_NULL, a, e);
                        return (e);
                }
        }
        UNUSED(err);
        return (NULL_exp);
}


/*
    PERFORM A POINTER MEMBER-POINTER CONVERSION

    This routine converts the pointer to member expression a to the
    pointer type t.  The only potentially valid case is casting a pointer
    to member function to a pointer to function.  In all other cases the
    null expression is returned.
*/

static EXP
cast_ptr_mem_ptr(TYPE t, EXP a, ERROR *err, unsigned cast)
{
        TYPE s = DEREF_type(exp_type(a));
        TYPE p = DEREF_type(type_ptr_mem_sub(s));
        TYPE q = DEREF_type(type_ptr_sub(t));
        if (IS_type_func(p) && IS_type_func(q)) {
                if (cast & CAST_REINTERP) {
                        EXP e;
                        ERROR err2 = ERR_expr_cast_reint_mem_func(s, t);
                        if (!IS_NULL_err(err2)) {
                                e = cast_token(t, a, err, err2, cast);
                                if (!IS_NULL_exp(e)) {
                                        return (e);
                                }
                        }
                        MAKE_exp_cast(t, CONV_PTR_MEM_FUNC, a, e);
                        return (e);
                }
        }
        return (NULL_exp);
}


/*
    PERFORM A CLASS-CLASS CONVERSION

    This routine performs any base class conversion of the class object
    a to the class t.  ref is true if this is a reference binding.  The
    null expression is returned if no such conversion is possible.
*/

EXP
cast_class_class(TYPE t, EXP a, ERROR *err, unsigned cast, int ref)
{
        EXP e = NULL_exp;
        TYPE s = DEREF_type(exp_type(a));
        CLASS_TYPE ct = DEREF_ctype(type_compound_defn(t));
        CLASS_TYPE cs = DEREF_ctype(type_compound_defn(s));
        if (eq_ctype(cs, ct)) {
                e = a;
        } else {
                GRAPH gr = find_base_class(cs, ct, 1);
                if (!IS_NULL_graph(gr)) {
                        /* Allow for base class conversions */
                        TYPE p;
                        CV_SPEC cv = DEREF_cv(type_qual(s));
                        OFFSET off = DEREF_off(graph_off(gr));
                        ERROR err2 = check_ambig_base(gr);
                        if (!IS_NULL_err(err2)) {
                                e = cast_token(t, a, err, err2, cast);
                                if (!IS_NULL_exp(e)) {
                                        return (e);
                                }
                                add_error(err, ERR_dcl_init_ref_ambig());
                        }
                        check_base_access(gr);
                        p = rvalue_type(t);
                        MAKE_type_ptr(cv_none, p, p);
                        if (!(cv & cv_lvalue)) {
                                /* Introduce temporary if necessary */
                                a = make_temporary(s, a, NULL_exp, 0, err);
                        }
                        MAKE_exp_address(p, a, e);
                        e = make_base_cast(p, e, off);
                        t = lvalue_type(t);
                        MAKE_exp_indir(t, e, e);
                }
        }
        if (!IS_NULL_exp(e)) {
                if (ref) {
                        /* Check cv-qualifiers */
                        CV_SPEC cv = cv_compare(t, s);
                        if (cv) {
                                add_error(err, ERR_dcl_init_ref_qual(cv));
                        }
                } else {
                        e = convert_lvalue(e);
                }
                if (cast != CAST_IMPLICIT && err != KILL_err) {
                        /* Can't have explicit cast in C */
                        *err = concat_error(ERR_expr_cast_expl_scalar(t), *err);
                }
        }
        return (e);
}


/*
    CONSTRUCT A CAST EXPRESSION

    This routine constructs a cast expression for converting the expression
    a to the type t.  Any errors are added to the end of the position given
    by err.
*/

EXP
cast_exp(TYPE t, EXP a, ERROR *err, unsigned cast)
{
        TYPE s;
        CV_SPEC cv;
        unsigned ns;
        EXP e = NULL_exp;
        int usr = LANGUAGE_CPP;
        unsigned nt = TAG_type(t);

        /* Deal with tokenised types */
        if (nt == type_token_tag) {
                if (is_templ_type(t)) {
                        e = cast_templ_type(t, a, cast);
                        return (e);
                }
                t = expand_type(t, 0);
                nt = TAG_type(t);
        }

        /* Deal with reference conversions */
        if (nt == type_ref_tag) {
                /* Transform 'cast <t&> (a)' to '*cast <t*> (&a)' */
                ERROR err2 = NULL_err;
                TYPE p = DEREF_type(type_ref_sub(t));
                if (is_templ_type(p)) {
                        e = cast_templ_type(t, a, cast);
                        return (e);
                }
                p = rvalue_type(p);
                MAKE_type_ptr(cv_none, p, p);

                /* Construct the result */
                a = make_ref_object(a, &err2);
                s = DEREF_type(exp_type(a));
                if (IS_type_error(s)) {
                        e = cast_exact(p, a);
                } else {
                        e = cast_exp(p, a, &err2, cast);
                }
                if (!IS_NULL_err(err2)) {
                        add_error(err, err2);
                        add_error(err, ERR_expr_cast_ref(t, p));
                }
                e = cast_exact(t, e);
                return (e);
        }

        /* Check user-defined conversion status */
        if (cast & CAST_STANDARD) {
                cast &= ~CAST_STANDARD;
                usr = 0;
        }

        /* Deal with function overloading */
        a = resolve_cast(t, a, err, 1, 0, NULL_list(IDENTIFIER));

        /* Deal with casting to void */
        if (nt == type_top_tag || nt == type_bottom_tag) {
                if (cast & CAST_STATIC) {
                        a = make_discard_exp(a);
                        MAKE_exp_cast(t, CONV_ELLIPSIS, a, e);
                        return (e);
                }
        }

        /* Find the operand type */
        s = DEREF_type(exp_type(a));
        ns = TAG_type(s);

        /* Check for template types */
        if (ns == type_token_tag && is_templ_type(s)) {
                e = cast_templ_type(t, a, cast);
                return (e);
        }

        /* Deal with user-defined conversions */
        if (usr) {
                if (nt == type_compound_tag) {
                        if (cast == CAST_IMPLICIT || (cast & CAST_STATIC)) {
                                ERROR err2 = check_incomplete(t);
                                if (!IS_NULL_err(err2)) {
                                        /* Can't have incomplete type */
                                        add_error(err, err2);
                                        add_error(err, ERR_expr_cast_invalid(s, t));
                                        e = make_null_exp(t);
                                        return (e);
                                }
                                if (cast != CAST_IMPLICIT) {
                                        err2 = check_abstract(t);
                                        if (!IS_NULL_err(err2)) {
                                                /* Can't have abstract type */
                                                add_error(err, err2);
                                                add_error(err, ERR_class_abstract_cast());
                                        }
                                }
                                e = init_direct(t, a, err);
                                return (e);
                        }
                }
                if (ns == type_compound_tag) {
                        if (cast == CAST_IMPLICIT || (cast & CAST_STATIC)) {
                                e = convert_conv(t, a, err, cast);
                                return (e);
                        }
                }
        }

        /* Check for function casts */
#if LANGUAGE_CPP
        if (nt == type_func_tag && ns == type_func_tag) {
                if (cast & CAST_STATIC) {
                        if (eq_type(t, s)) {
                                add_error(err, ERR_expr_cast_stat_func(t));
                                t = lvalue_type(t);
                                MAKE_exp_cast(t, CONV_FUNC, a, e);
                                return (e);
                        }
                }
        }
#endif

        /* Do lvalue conversion on conversion */
        a = convert_lvalue(a);
        s = DEREF_type(exp_type(a));
        ns = TAG_type(s);

        /* Deal with tokenised types */
        if (ns == type_token_tag) {
                s = expand_type(s, 0);
                ns = TAG_type(s);
        }

        /* Ignore any qualifiers for destination type */
        cv = DEREF_cv(type_qual(t));
        if (cv != cv_none) {
#if LANGUAGE_CPP
                if (nt != type_compound_tag) {
                        cv = cv_none;
                }
                t = qualify_type(t, cv, 0);
#else
                t = qualify_type(t, cv_none, 0);
#endif
        }

        /* Deal with casting to bool */
        if (nt == type_integer_tag && check_int_type(t, btype_bool)) {
                if (ns == type_compound_tag) {
                        /* User-defined conversions already handled */
                        /* EMPTY */
                } else {
                        if (cast == CAST_IMPLICIT || (cast & CAST_STATIC)) {
                                e = convert_boolean(a, exp_paren_tag, err);
                                return (e);
                        }
                        if (cast == CAST_CONST && eq_type(s, t)) {
                                return (a);
                        }
                        ns = null_tag;
                }
        }

        /* Check simple conversions */
        switch (ns) {
        case type_integer_tag:
        case type_enumerate_tag:
integer_label:
                /* Conversion from integer */
                switch (nt) {
                case type_integer_tag:
                case type_bitfield_tag:
                case type_enumerate_tag: {
                        e = cast_int_int(t, a, err, cast, -1);
                        break;
                }
                case type_floating_tag: {
                        e = cast_int_float(t, a, err, cast);
                        break;
                }
                case type_ptr_tag: {
                        e = cast_int_ptr(t, a, err, cast, 1);
                        break;
                }
                case type_ptr_mem_tag: {
                        e = cast_int_ptr_mem(t, a, err, cast, 1);
                        break;
                }
                }
                break;
        case type_bitfield_tag: {
                /* Conversion from bitfield */
                switch (nt) {
                case type_integer_tag:
                case type_bitfield_tag:
                case type_enumerate_tag: {
                        e = cast_int_int(t, a, err, cast, -1);
                        break;
                }
                default : {
                        TYPE r = find_bitfield_type(s);
                        a = cast_int_int(r, a, err, cast, -1);
                        goto integer_label;
                }
                }
                break;
        }
        case type_floating_tag: {
                /* Conversion from floating */
                switch (nt) {
                case type_integer_tag:
                case type_enumerate_tag: {
                        e = cast_float_int(t, a, err, cast);
                        break;
                }
                case type_bitfield_tag: {
                        TYPE r = find_bitfield_type(t);
                        a = cast_float_int(r, a, err, cast);
                        e = cast_int_int(t, a, err, cast, -1);
                        break;
                }
                case type_floating_tag: {
                        e = cast_float_float(t, a, err, cast);
                        break;
                }
                }
                break;
        }
        case type_ptr_tag: {
                /* Conversion from pointer */
                switch (nt) {
                case type_integer_tag:
                case type_enumerate_tag: {
                        e = cast_ptr_int(t, a, err, cast);
                        break;
                }
                case type_bitfield_tag: {
                        TYPE r = find_bitfield_type(t);
                        a = cast_ptr_int(r, a, err, cast);
                        e = cast_int_int(t, a, err, cast, -1);
                        break;
                }
                case type_ptr_tag: {
                        e = cast_ptr_ptr(t, a, err, cast, 0, 0);
                        break;
                }
                }
                break;
        }
        case type_ptr_mem_tag: {
                /* Conversion from pointer to member */
                switch (nt) {
                case type_integer_tag:
                case type_enumerate_tag: {
                        e = cast_ptr_mem_int(t, a, err, cast);
                        break;
                }
                case type_bitfield_tag: {
                        TYPE r = find_bitfield_type(t);
                        e = cast_ptr_mem_int(r, a, err, cast);
                        a = cast_int_int(t, a, err, cast, -1);
                        break;
                }
                case type_ptr_tag: {
                        e = cast_ptr_mem_ptr(t, a, err, cast);
                        break;
                }
                case type_ptr_mem_tag: {
                        e = cast_ptr_mem_ptr_mem(t, a, err, cast, 0, 0);
                        break;
                }
                }
                break;
        }
        case type_compound_tag: {
                if (nt == type_compound_tag && !usr) {
                        e = cast_class_class(t, a, err, cast, 0);
                }
                break;
        }
        }

        if (IS_NULL_exp(e)) {
                if (cast != CAST_IMPLICIT) {
                        switch (nt) {
                        case type_func_tag:
                        case type_array_tag:
                        case type_token_tag:
                        case type_compound_tag: {
                                /* Cast to non-scalar type */
                                add_error(err, ERR_expr_cast_expl_scalar(t));
                                break;
                        }
                        }
                }
                if (ns == type_token_tag || nt == type_token_tag) {
                        /* Allow for tokenised types */
                        int ft = force_tokdef;
                        int fs = force_template;
                        if (cast != CAST_IMPLICIT) {
                                force_tokdef = 0;
                                force_template = 0;
                        }
                        if (eq_type_unqual(s, t)) {
                                e = a;
                        }
                        force_template = fs;
                        force_tokdef = ft;
                }
                if (IS_NULL_exp(e)) {
                        /* No other conversions are allowed */
                        if (ns == type_error_tag || nt == type_error_tag) {
                                e = cast_exact(t, a);
                        } else {
                                ERROR err2 = check_incomplete(t);
                                err2 = concat_error(err2, ERR_expr_cast_invalid(s, t));
                                if (!IS_NULL_err(err2)) {
                                        e = cast_token(t, a, err, err2, cast);
                                        if (!IS_NULL_exp(e)) {
                                                return (e);
                                        }
                                }
                                MAKE_exp_cast(t, CONV_NONE, a, e);
                        }
                }
        }
        return (e);
}


/*
    CONSTRUCT A SIMPLE CAST EXPRESSION

    This routine constructs the simple cast expression '( t ) a'.  n gives
    the number of types defined in t.
*/

EXP
make_cast_exp(TYPE t, EXP a, int n)
{
        EXP e;
        ERROR err = NULL_err;
        unsigned conv = (unsigned)option_value(OPT_VAL_cast_explicit);
        report(crt_loc, ERR_expr_cast_expl_used());
        if (n) {
                report(crt_loc, ERR_expr_cast_expl_typedef());
        }
        a = convert_reference(a, REF_ASSIGN);
        e = cast_exp(t, a, &err, conv);
        if (!IS_NULL_err(err)) {
                err = concat_warning(err, ERR_expr_cast_expl_bad());
                report(crt_loc, err);
        }
        return (e);
}


/*
    CONSTRUCT A STATIC CAST EXPRESSION

    This routine constructs the static cast expression 'static_cast < t >
    ( a )'.  n gives the number of types defined in t.
*/

EXP
make_static_cast_exp(TYPE t, EXP a, int n)
{
        EXP e;
        ERROR err = NULL_err;
        if (n) {
                report(crt_loc, ERR_expr_cast_stat_typedef());
        }
        a = convert_reference(a, REF_ASSIGN);
        e = cast_exp(t, a, &err, CAST_STATIC);
        if (!IS_NULL_err(err)) {
                err = concat_warning(err, ERR_expr_cast_stat_bad());
                report(crt_loc, err);
        }
        return (e);
}


/*
    CONSTRUCT A REINTERPRET CAST EXPRESSION

    This routine constructs the reinterpret cast expression 'reinterpret_cast
    < t > ( a )'.  n gives the number of types defined in t.
*/

EXP
make_reinterp_cast_exp(TYPE t, EXP a, int n)
{
        EXP e;
        ERROR err = NULL_err;
        if (n) {
                report(crt_loc, ERR_expr_cast_reint_typedef());
        }
        a = convert_reference(a, REF_ASSIGN);
        e = cast_exp(t, a, &err, CAST_REINTERP);
        if (!IS_NULL_err(err)) {
                err = concat_warning(err, ERR_expr_cast_reint_bad());
                report(crt_loc, err);
        }
        return (e);
}


/*
    CONSTRUCT A CONST CAST EXPRESSION

    This routine constructs the const cast expression 'const_cast < t >
    ( a )'.  n gives the number of types defined in t.
*/

EXP
make_const_cast_exp(TYPE t, EXP a, int n)
{
        EXP e;
        ERROR err = NULL_err;
        if (n) {
                report(crt_loc, ERR_expr_cast_const_typedef());
        }
        a = convert_reference(a, REF_ASSIGN);
        e = cast_exp(t, a, &err, CAST_CONST);
        if (!IS_NULL_err(err)) {
                err = concat_warning(err, ERR_expr_cast_const_bad());
                report(crt_loc, err);
        }
        return (e);
}


/*
    CONSTRUCT A NEW-STYLE CAST EXPRESSION

    This routine constructs the new-style cast expression 'op < t > ( a )'.
    n gives the number of types defined in t.
*/

#if LANGUAGE_CPP

EXP
make_new_cast_exp(int op, TYPE t, EXP a, int n)
{
        EXP e;
        switch (op) {
        case lex_static_Hcast: {
                e = make_static_cast_exp(t, a, n);
                break;
        }
        case lex_reinterpret_Hcast: {
                e = make_reinterp_cast_exp(t, a, n);
                break;
        }
        case lex_const_Hcast: {
                e = make_const_cast_exp(t, a, n);
                break;
        }
        case lex_dynamic_Hcast: {
                e = make_dynamic_cast_exp(t, a, n);
                break;
        }
        default: {
                e = make_cast_exp(t, a, n);
                break;
        }
        }
        return (e);
}

#endif


/*
    CONSTRUCT A FUNCTION-STYLE CAST EXPRESSION

    This routine constructs the function-style cast expression 't ( args )'.
    If args is a single argument, a, then this is identical to '( t ) a'.
    The expression 't ()' can be formed for any type, otherwise t must be
    a class type with a suitable constructor.
*/

EXP
make_func_cast_exp(TYPE t, LIST(EXP)args)
{
        EXP e;
        ERROR err = NULL_err;
        unsigned tag = TAG_type(t);
        unsigned len = LENGTH_list(args);

        /* Do reference conversions on arguments */
        args = convert_args(args);

        /* Check for template types */
        if (tag == type_token_tag && is_templ_type(t)) {
                MAKE_exp_opn(t, lex_cast, args, e);
                return (e);
        }

        /* Check for class type with more than one argument */
        if (len > 1 && tag != type_compound_tag) {
                report(crt_loc, ERR_expr_type_conv_many(t));
                len = 1;
        }

        if (len == 1) {
                /* A single argument is the same as a normal cast */
                unsigned conv = (unsigned)option_value(OPT_VAL_cast_explicit);
                EXP a = DEREF_exp(HEAD_list(args));
                DESTROY_list(args, SIZE_exp);
                if (tag != type_compound_tag) {
                        report(crt_loc, ERR_expr_cast_expl_used());
                }
                e = cast_exp(t, a, &err, conv);
                if (!IS_NULL_err(err)) {
                        err = concat_warning(err, ERR_expr_type_conv_bad());
                        report(crt_loc, err);
                }
                return (e);
        }

        if (len == 0) {
                /* No arguments give a zero value */
                if (IS_type_top_etc(t)) {
                        MAKE_exp_value(t, e);
                } else {
                        err = check_complete(t);
                        if (!IS_NULL_err(err)) {
                                /* Can't cast to an incomplete type */
                                err = concat_error(err, ERR_expr_type_conv_incompl());
                                report(crt_loc, err);
                        }
                        if (IS_type_array(t)) {
                                /* Can't use an array type */
                                report(crt_loc, ERR_expr_type_conv_array(t));
                        }
                        err = check_abstract(t);
                        if (!IS_NULL_err(err)) {
                                /* Can't cast to an abstract type */
                                err = concat_error(err, ERR_class_abstract_cast());
                                report(crt_loc, err);
                                err = NULL_err;
                        }
                        e = init_empty(t, cv_none, 1, &err);
                        if (!IS_NULL_err(err)) {
                                report(crt_loc, err);
                        }
                }
                return (e);
        }

        /* Now check constructor conversions */
        e = convert_constr(t, args, &err, CAST_STATIC);
        if (!IS_NULL_err(err)) {
                report(crt_loc, err);
        }
        return (e);
}


/*
    LIST OF ALL CONVERSION TOKENS

    Whenever a type conversion would raise an error this list of tokens
    is consulted to see if one of them could perform the conversion.
*/

static LIST(IDENTIFIER) conv_tokens = NULL_list(IDENTIFIER);


/*
    ALLOW A TOKEN AS A CONVERSION

    This routine enables the token id as a conversion token.
*/

void
allow_conversion(IDENTIFIER id)
{
        IDENTIFIER tid = resolve_token(id, "EE", 1);
        if (!IS_NULL_id(tid)) {
                CONS_id(tid, conv_tokens, conv_tokens);
        }
        return;
}


/*
    CHECK FOR TOKENISED CONVERSIONS

    This routine checks whether the expression a can be converted to the
    type t using a conversion token.  If so it returns the appropriate
    token application.  Otherwise it returns the null expression.
*/

EXP
cast_token(TYPE t, EXP a, ERROR *err, ERROR err2, unsigned cast)
{
        EXP e = NULL_exp;
        int sev = ERROR_NONE;
        if (!IS_NULL_err(err2)) {
                sev = DEREF_int(err_severity(err2));
        }
        if (sev == ERROR_SERIOUS) {
                /* Only check illegal conversions */
                force_tokdef++;
                if (cast == CAST_IMPLICIT || (cast & CAST_STATIC)) {
                        /* Scan through conversion tokens */
                        TYPE s = DEREF_type(exp_type(a));
                        LIST(IDENTIFIER)convs = conv_tokens;
                        while (!IS_NULL_list(convs)) {
                                IDENTIFIER id = DEREF_id(HEAD_list(convs));
                                TOKEN tok = DEREF_tok(id_token_sort(id));
                                if (IS_tok_func(tok)) {
                                        /* Function tokens */
                                        tok = func_proc_token(tok);
                                }
                                if (IS_tok_proc(tok)) {
                                        /* Procedure tokens */
                                        int d;
                                        TYPE p;
                                        TOKEN par;
                                        IDENTIFIER pid;
                                        LIST(IDENTIFIER)bids;
                                        LIST(IDENTIFIER)pids;

                                        /* Find result type */
                                        TOKEN res = DEREF_tok(tok_proc_res(tok));
                                        TYPE r = DEREF_type(tok_exp_type(res));

                                        /* Find parameter type */
                                        pids = DEREF_list(tok_proc_pids(tok));
                                        pid = DEREF_id(HEAD_list(pids));
                                        par = DEREF_tok(id_token_sort(pid));
                                        p = DEREF_type(tok_exp_type(par));

                                        /* Check conversion */
                                        bids = DEREF_list(tok_proc_bids(tok));
                                        d = save_token_args(bids, NULL_list(TOKEN));
                                        if (eq_type(s, p) && eq_type(t, r)) {
                                                LIST(TOKEN)args;
                                                ERROR err1 = ERR_token_conv(id, s, t);
                                                IGNORE define_exp_token(pid, a, 1);
                                                args = make_token_args(id, bids, &err1);
                                                e = apply_exp_token(id, args, 0);
                                                if (!IS_NULL_exp(e)) {
                                                        IDENTIFIER fid;
                                                        fid = DEREF_id(id_token_alt(id));
                                                        use_func_id(fid, 0, 0);
                                                        restore_token_args(bids, d);
                                                        destroy_error(err2, 1);
                                                        err2 = err1;
                                                        break;
                                                }
                                                destroy_error(err1, 1);
                                        }
                                        restore_token_args(bids, d);
                                }
                                convs = TAIL_list(convs);
                        }
                }
                force_tokdef--;
        }
        add_error(err, err2);
        return (e);
}