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


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

#include "msgcat.h"

#include "c_types.h"
#include "ctype_ops.h"
#include "exp_ops.h"
#include "id_ops.h"
#include "graph_ops.h"
#include "nat_ops.h"
#include "nspace_ops.h"
#include "member_ops.h"
#include "off_ops.h"
#include "tok_ops.h"
#include "type_ops.h"
#include "error.h"
#include "catalog.h"
#include "allocate.h"
#include "basetype.h"
#include "capsule.h"
#include "cast.h"
#include "check.h"
#include "chktype.h"
#include "class.h"
#include "compile.h"
#include "constant.h"
#include "construct.h"
#include "convert.h"
#include "copy.h"
#include "declare.h"
#include "derive.h"
#include "destroy.h"
#include "dump.h"
#include "exception.h"
#include "expression.h"
#include "function.h"
#include "hash.h"
#include "identifier.h"
#include "initialise.h"
#include "instance.h"
#include "label.h"
#include "literal.h"
#include "namespace.h"
#include "operator.h"
#include "predict.h"
#include "redeclare.h"
#include "rewrite.h"
#include "statement.h"
#include "syntax.h"
#include "template.h"
#include "token.h"


/*
 *    IS AN EXPRESSION AN UNRESOLVED IMPLICIT CAST?
 *
 *    This routine checks whether the expression e denotes an unresolved
 *    implicit cast expression.  If so it returns the expression being
 *    cast.  Otherwise the null expression is returned.  The copying
 *    routines work perfectly well for such implicit casts however
 *    spotting them early can help to give a context to any error message.
 */

EXP
implicit_cast_exp(EXP e)
{
	if (!IS_NULL_exp (e)) {
		unsigned tag = TAG_exp (e);
		if (tag == exp_op_tag) {
			/* Check for implicit conversions */
			int op = DEREF_int (exp_op_lex (e));
			if (op == lex_implicit) {
				EXP a = DEREF_exp (exp_op_arg1 (e));
				return (a);
			}
		}
		if (tag == exp_aggregate_tag || tag == exp_nof_tag) {
			/* Check for aggregate initialisers */
			return (e);
		}
	}
	return (NULL_exp);
}


/*
 *    COPY A VARIABLE DEFINITION
 *
 *    This routine defines the variable or static data member id to be e.
 */

static void
copy_variable(IDENTIFIER id, EXP e)
{
	EXP d;
	TYPE t1 = DEREF_type (id_variable_etc_type (id));
	TYPE t2 = expand_type (t1, 1);
	if (IS_NULL_exp (e)) {
		/* Empty initialiser */
		DECL_SPEC ds = DEREF_dspec (id_storage (id));
		if ((ds & dspec_temp) && (ds & dspec_explicit)) {
			/* Explicitly initialised temporary */
			/* EMPTY */
		} else {
			e = init_general (t2, e, id, LANGUAGE_C);
		}
	} else {
		EXP a = implicit_cast_exp (e);
		if (!IS_NULL_exp (a)) {
			/* Implicit cast initialiser */
			a = copy_exp (a, t1, t2);
			e = init_general (t2, a, id, 0);
		} else {
			/* Simple initialiser */
			e = copy_exp (e, t1, t2);
			e = dynamic_init (id, NULL_string, e);
		}
		e = check_init (e);
	}
	d = destroy_general (t2, id);
	COPY_exp (id_variable_etc_term (id), d);
	COPY_exp (id_variable_etc_init (id), e);
	return;
}


/*
 *    COPY A LOCAL VARIABLE
 *
 *    This routine copies the local variable id.
 */

static IDENTIFIER
copy_local(IDENTIFIER id)
{
	IDENTIFIER cid = copy_id (id, 2);
	COPY_id (id_alias (id), cid);
	DEREF_loc (id_loc (id), crt_loc);
	decl_loc = crt_loc;
	if (IS_id_variable (cid)) {
		EXP e = DEREF_exp (id_variable_init (cid));
		copy_variable (cid, e);
	}
	return (cid);
}


/*
 *    COPY A TYPE OFFSET
 *
 *    This routine copies the offset for the type t.  The result must be a
 *    complete object type.
 */

static TYPE
copy_type_offset(TYPE t, int op)
{
	TYPE s = expand_type (t, 1);
	if (!EQ_type (s, t)) {
		ERROR err = check_complete (s);
		if (!IS_NULL_err (err)) {
			err = concat_error (err, ERR_expr_add_incompl (op));
			report (crt_loc, err);
		}
	}
	return (s);
}


/*
 *    COPY AN OFFSET
 *
 *    This routine copies the offset off.
 */

OFFSET
copy_offset(OFFSET off, int op)
{
	if (IS_NULL_off (off)) return (NULL_off);
	ASSERT (ORDER_off == 13);
	switch (TAG_off (off)) {
	case off_zero_tag : {
		/* Zero offsets */
		TYPE t = DEREF_type (off_zero_type (off));
		t = copy_type_offset (t, op);
		MAKE_off_zero (t, off);
		break;
	}
	case off_type_tag : {
		/* Type offsets */
		TYPE t = DEREF_type (off_type_type (off));
		t = copy_type_offset (t, op);
		MAKE_off_type (t, off);
		break;
	}
	case off_array_tag : {
		/* Array type offsets */
		TYPE t = DEREF_type (off_array_type (off));
		unsigned n = DEREF_unsigned (off_array_arg (off));
		t = copy_type_offset (t, op);
		MAKE_off_array (t, n, off);
		break;
	}
	case off_extra_tag : {
		/* Extra allocation offsets */
		TYPE t = DEREF_type (off_extra_type (off));
		int n = DEREF_int (off_extra_scale (off));
		t = expand_type (t, 1);
		MAKE_off_extra (t, n, off);
		break;
	}
	case off_base_tag : {
		/* Direct base class offsets */
		GRAPH gr = DEREF_graph (off_base_graph (off));
		gr = expand_graph (gr, 1);
		if (!IS_NULL_graph (gr)) {
			off = DEREF_off (graph_off (gr));
		}
		break;
	}
	case off_deriv_tag : {
		/* Indirect base class offsets */
		GRAPH gr = DEREF_graph (off_deriv_graph (off));
		gr = expand_graph (gr, 1);
		if (!IS_NULL_graph (gr)) {
			off = DEREF_off (graph_off (gr));
		}
		break;
	}
	case off_member_tag : {
		/* Member offsets */
		IDENTIFIER id = DEREF_id (off_member_id (off));
		id = rescan_id (id, qual_nested, 0);
		if (IS_id_member (id)) {
			off = DEREF_off (id_member_off (id));
		}
		break;
	}
	case off_ptr_mem_tag : {
		/* Pointer to member offsets */
		EXP a = DEREF_exp (off_ptr_mem_arg (off));
		a = copy_exp (a, NULL_type, NULL_type);
		MAKE_off_ptr_mem (a, off);
		break;
	}
	case off_negate_tag : {
		/* Negated offsets */
		OFFSET a = DEREF_off (off_negate_arg (off));
		op = (lex_plus + lex_minus) - op;
		a = copy_offset (a, op);
		MAKE_off_negate (a, off);
		break;
	}
	case off_plus_tag : {
		/* Offset additions */
		OFFSET a = DEREF_off (off_plus_arg1 (off));
		OFFSET b = DEREF_off (off_plus_arg2 (off));
		a = copy_offset (a, op);
		b = copy_offset (b, op);
		MAKE_off_plus (a, b, off);
		break;
	}
	case off_mult_tag : {
		/* Offset multiplications */
		OFFSET a = DEREF_off (off_mult_arg1 (off));
		EXP b = DEREF_exp (off_mult_arg2 (off));
		a = copy_offset (a, op);
		b = copy_exp (b, NULL_type, NULL_type);
		MAKE_off_mult (a, b, off);
		break;
	}
	case off_ptr_diff_tag : {
		/* Pointer differences */
		EXP a = DEREF_exp (off_ptr_diff_ptr1 (off));
		EXP b = DEREF_exp (off_ptr_diff_ptr2 (off));
		TYPE s1 = DEREF_type (exp_type (a));
		TYPE s2 = expand_type (s1, 1);
		a = copy_exp (a, s1, s2);
		b = copy_exp (b, s1, s2);
		MAKE_off_ptr_diff (a, b, off);
		break;
	}
	case off_token_tag : {
		/* Offset tokens */
		IDENTIFIER tok = DEREF_id (off_token_tok (off));
		LIST (TOKEN) args = DEREF_list (off_token_args (off));
		tok = DEREF_id (id_alias (tok));
		args = expand_args (args, 1, 1);
		off = apply_mem_token (tok, args);
		break;
	}
	}
	return (off);
}


/*
 *    COPY A LIST OF OFFSETS
 *
 *    This routine copies the list of offsets p.
 */

static LIST (OFFSET)
copy_off_list(LIST (OFFSET) p)
{
	LIST (OFFSET) q = NULL_list (OFFSET);
	while (!IS_NULL_list (p)) {
		OFFSET off = DEREF_off (HEAD_list (p));
		off = copy_offset (off, lex_plus);
		CONS_off (off, q, q);
		p = TAIL_list (p);
	}
	return (REVERSE_list (q));
}


/*
 *    COPY A LIST OF EXPRESSIONS
 *
 *    This routine copies the list of expressions p.
 */

LIST (EXP)
copy_exp_list(LIST (EXP) p, TYPE t1, TYPE t2)
{
	LIST (EXP) q = NULL_list (EXP);
	while (!IS_NULL_list (p)) {
		EXP e = DEREF_exp (HEAD_list (p));
		e = copy_exp (e, t1, t2);
		CONS_exp (e, q, q);
		p = TAIL_list (p);
	}
	return (REVERSE_list (q));
}


/*
 *    COPY A FUNCTION EXPRESSION
 *
 *    This routine copies the function expression e.  Any name look-ups
 *    are postponed until make_func_exp.
 */

EXP
copy_func_exp(EXP e, TYPE t1, TYPE t2)
{
	if (!IS_NULL_exp (e)) {
		unsigned tag = TAG_exp (e);
		TYPE t = DEREF_type (exp_type (e));
		if (!EQ_type (t, t1)) {
			/* Expand type if necessary */
			t1 = t;
			t2 = expand_type (t, 1);
		}
		switch (tag) {
		case exp_identifier_tag :
		case exp_member_tag :
		case exp_ambiguous_tag : {
			/* Identifier expressions */
			IDENTIFIER id;
			QUALIFIER qual;
			id = DEREF_id (exp_identifier_etc_id (e));
			qual = DEREF_qual (exp_identifier_etc_qual (e));
			MAKE_exp_identifier_etc (tag, t2, id, qual, e);
			break;
		}
		case exp_undeclared_tag : {
			/* Undeclared identifiers */
			IDENTIFIER id;
			QUALIFIER qual;
			id = DEREF_id (exp_undeclared_id (e));
			qual = DEREF_qual (exp_undeclared_qual (e));
			MAKE_exp_identifier (type_func_void, id, qual, e);
			break;
		}
		case exp_paren_tag : {
			/* Parenthesised expressions */
			EXP a = DEREF_exp (exp_paren_arg (e));
			a = copy_func_exp (a, t1, t2);
			if (!IS_NULL_exp (a)) {
				t2 = DEREF_type (exp_type (a));
			}
			MAKE_exp_paren (t2, a, e);
			break;
		}
		case exp_address_tag : {
			/* Address expressions */
			EXP a = DEREF_exp (exp_address_arg (e));
			a = copy_func_exp (a, t1, t2);
			MAKE_exp_address (t2, a, e);
			break;
		}
		case exp_address_mem_tag : {
			/* Member address expressions */
			EXP a = DEREF_exp (exp_address_mem_arg (e));
			int paren = DEREF_int (exp_address_mem_paren (e));
			a = copy_func_exp (a, t1, t2);
			MAKE_exp_address_mem (t2, a, paren, e);
			break;
		}
		case exp_op_tag : {
			/* Check for undetermined address expressions */
			int op = DEREF_int (exp_op_lex (e));
			EXP a = DEREF_exp (exp_op_arg1 (e));
			EXP b = DEREF_exp (exp_op_arg2 (e));
			if (op == lex_and_H1 && IS_NULL_exp (b)) {
				a = copy_func_exp (a, t1, t2);
				e = make_ref_exp (a, 0);
				break;
			}
			e = copy_exp (e, t1, t2);
			break;
		}
		default : {
			/* Other expressions */
			e = copy_exp (e, t1, t2);
			break;
		}
		}
	}
	return (e);
}


/*
 *    COPY A LIST OF FUNCTION ARGUMENTS
 *
 *    This routine copies the list of function arguments p.  id gives the
 *    function name (for error reporting purposes).
 */

static LIST (EXP)
copy_func_args(LIST (EXP) p, IDENTIFIER id)
{
	unsigned n = 1;
	LIST (EXP) q = NULL_list (EXP);
	while (!IS_NULL_list (p)) {
		EXP e = DEREF_exp (HEAD_list (p));
		EXP a = implicit_cast_exp (e);
		if (!IS_NULL_exp (a)) {
			/* Do implicit argument conversion */
			TYPE t;
			ERROR err = NULL_err;
			a = copy_exp (a, NULL_type, NULL_type);
			t = DEREF_type (exp_type (a));
			e = init_assign (t, cv_none, a, &err);
			if (!IS_NULL_err (err)) {
				err = init_error (err, 0);
				err = concat_error (err, ERR_expr_call_arg (n));
				if (!IS_NULL_id (id)) {
					err = concat_error (ERR_expr_call_func (id), err);
				}
				report (crt_loc, err);
			}
		} else {
			/* Simple argument copy */
			e = copy_exp (e, NULL_type, NULL_type);
		}
		CONS_exp (e, q, q);
		n++;
		p = TAIL_list (p);
	}
	return (REVERSE_list (q));
}


/*
 *    COPY A LABEL
 *
 *    This routine finds the copy of the label lab in the current label
 *    namespace, copying it if necessary.  If def is true then the labelled
 *    statement is also copied.
 */

static IDENTIFIER
copy_label(IDENTIFIER lab, int def)
{
	IDENTIFIER nlab = lab;
	if (!IS_NULL_id (nlab)) {
		NAMESPACE ns = label_namespace;
		if (!IS_NULL_nspace (ns)) {
			/* Look up name in label namespace */
			HASHID nm = DEREF_hashid (id_name (lab));
			MEMBER mem = search_member (ns, nm, 1);
			nlab = DEREF_id (member_id (mem));
			if (IS_NULL_id (nlab)) {
				/* Create new label */
				int op = DEREF_int (id_label_op (lab));
				IDENTIFIER alab = DEREF_id (id_alias (lab));
				DECL_SPEC ds = DEREF_dspec (id_storage (lab));
				DEREF_loc (id_loc (lab), crt_loc);
				ds &= ~dspec_temp;
				MAKE_id_label (nm, ds, ns, crt_loc, op, nlab);
				if (!EQ_id (lab, alab)) {
					alab = copy_label (alab, 0);
					COPY_id (id_alias (nlab), alab);
				}
				COPY_id (member_id (mem), nlab);
			}
		}
		if (def) {
			EXP e = DEREF_exp (id_label_stmt (lab));
			if (!IS_NULL_exp (e)) {
				/* Copy labelled statement */
				TYPE t = DEREF_type (exp_type (e));
				EXP a = DEREF_exp (exp_label_stmt_body (e));
				IDENTIFIER elab = DEREF_id (exp_label_stmt_next (e));
				elab = copy_label (elab, 0);
				a = copy_exp (a, type_void, type_void);
				MAKE_exp_label_stmt (t, nlab, a, e);
				COPY_id (exp_label_stmt_next (e), elab);
				COPY_exp (id_label_stmt (nlab), e);
				set_parent_stmt (a, e);
			}
			DEREF_loc (id_loc (lab), crt_loc);
		}
	}
	return (nlab);
}


/*
 *    SET JUMP JOIN STATEMENTS
 *
 *    This routine sets the join field for all jumps to the label lab to
 *    be e.
 */

static void
set_jump_joins(IDENTIFIER lab, EXP e)
{
	EXP a = DEREF_exp (id_label_gotos (lab));
	while (!IS_NULL_exp (a) && IS_exp_goto_stmt (a)) {
		COPY_exp (exp_goto_stmt_join (a), e);
		a = DEREF_exp (exp_goto_stmt_next (a));
	}
	return;
}


/*
 *    COPY A SWITCH STATEMENT
 *
 *    This routine copies the switch statement e.
 */

static EXP
copy_switch_stmt(EXP e, TYPE t1, TYPE t2)
{
	/* Decompose switch statement */
	int changed = 0;
	LIST (NAT) an = NULL_list (NAT);
	LIST (IDENTIFIER) al = NULL_list (IDENTIFIER);
	EXP c = DEREF_exp (exp_switch_stmt_control (e));
	EXP a = DEREF_exp (exp_switch_stmt_body (e));
	int exhaust = DEREF_int (exp_switch_stmt_exhaust (e));
	IDENTIFIER blab = DEREF_id (exp_switch_stmt_break_lab (e));
	IDENTIFIER dlab = DEREF_id (exp_switch_stmt_default_lab (e));
	LIST (NAT) cn = DEREF_list (exp_switch_stmt_cases (e));
	LIST (IDENTIFIER) cl = DEREF_list (exp_switch_stmt_case_labs (e));
	
	/* Copy basic components */
	c = copy_exp (c, type_sint, type_sint);
	blab = copy_label (blab, 1);
	a = copy_exp (a, t1, t2);
	MAKE_exp_switch_stmt (t2, c, a, exhaust, blab, e);
	set_jump_joins (blab, e);
	set_parent_stmt (a, e);
	
	/* Copy cases */
	while (!IS_NULL_list (cn)) {
		ERROR err = NULL_err;
		NAT n = DEREF_nat (HEAD_list (cn));
		IDENTIFIER clab = DEREF_id (HEAD_list (cl));
		NAT m = expand_nat (n, 1, 0, &err);
		if (!EQ_nat (n, m)) {
			if (!IS_NULL_err (err)) {
				err = concat_error (err, ERR_stmt_switch_case_const ());
				report (crt_loc, err);
			}
			changed = 1;
		}
		clab = copy_label (clab, 0);
		COPY_exp (id_label_gotos (clab), e);
		if (changed) {
			IDENTIFIER plab = find_case (an, al, m);
			if (!IS_NULL_id (plab) && !is_error_nat (m)) {
				/* New duplicate case created */
				LOCATION loc;
				PTR (LOCATION) ploc = id_loc (plab);
				DEREF_loc (id_loc (clab), loc);
				report (loc, ERR_stmt_switch_case_dup (m, ploc));
			}
		}
		CONS_id (clab, al, al);
		CONS_nat (m, an, an);
		cl = TAIL_list (cl);
		cn = TAIL_list (cn);
	}
	an = REVERSE_list (an);
	al = REVERSE_list (al);
	COPY_list (exp_switch_stmt_cases (e), an);
	COPY_list (exp_switch_stmt_case_labs (e), al);
	if (!IS_NULL_id (dlab)) {
		dlab = copy_label (dlab, 0);
		COPY_exp (id_label_gotos (dlab), e);
		COPY_id (exp_switch_stmt_default_lab (e), dlab);
	}
	e = solve_switch (e);
	return (e);
}


/*
 *    COPY A TRY BLOCK
 *
 *    This routine copies the try block e.
 */

#if LANGUAGE_CPP

static EXP
copy_try_stmt(EXP e, TYPE t1, TYPE t2)
{
	int empty = 1;
	int changed = 0;
	EXP a = DEREF_exp (exp_try_block_body (e));
	LIST (EXP) h = DEREF_list (exp_try_block_handlers (e));
	LIST (TYPE) s = DEREF_list (exp_try_block_htypes (e));
	LIST (TYPE) t = DEREF_list (exp_try_block_ttypes (e));
	LIST (LOCATION) tl = DEREF_list (exp_try_block_tlocs (e));
	LIST (LOCATION) sl = NULL_list (LOCATION);
	EXP b = DEREF_exp (exp_try_block_ellipsis (e));
	int func = DEREF_int (exp_try_block_func (e));
	e = begin_try_stmt (func);
	t = expand_exceptions (t, 1, &changed);
	while (!IS_NULL_list (tl)) {
		LOCATION loc;
		DEREF_loc (HEAD_list (tl), loc);
		CONS_loc (loc, sl, sl);
		tl = TAIL_list (tl);
	}
	sl = REVERSE_list (sl);
	COPY_list (exp_try_block_ttypes (e), t);
	COPY_list (exp_try_block_tlocs (e), sl);
	a = copy_exp (a, t1, t2);
	e = cont_try_stmt (e, a);
	h = copy_exp_list (h, t1, t2);
	s = expand_exceptions (s, 1, &changed);
	b = copy_exp (b, t1, t2);
	COPY_list (exp_try_block_handlers (e), h);
	COPY_list (exp_try_block_htypes (e), s);
	COPY_exp (exp_try_block_ellipsis (e), b);
	while (!IS_NULL_list (h)) {
		EXP c = DEREF_exp (HEAD_list (h));
		set_parent_stmt (c, e);
		empty = 0;
		h = TAIL_list (h);
	}
	set_parent_stmt (b, e);
	if (!IS_NULL_exp (b) && IS_exp_handler (b)) empty = 0;
	e = end_try_stmt (e, empty);
	return (e);
}

#endif


/*
 *    COPY A BLOCK DECLARATION
 *
 *    This routine copies the object id declared in block scope.  This is
 *    primarily to handle local classes and the like, local variables being
 *    handled by copy_local when their declaration is encountered.
 */

static void
copy_local_decl(IDENTIFIER id)
{
	switch (TAG_id (id)) {
	case id_variable_tag : {
		/* Local variable declaration */
		DECL_SPEC ds = DEREF_dspec (id_storage (id));
		if (ds & dspec_linkage) {
			IDENTIFIER pid;
			TYPE t = DEREF_type (id_variable_type (id));
			t = expand_type (t, 1);
			pid = make_object_decl (dspec_extern, t, id, 0);
			pid = DEREF_id (id_alias (pid));
			COPY_id (id_alias (id), pid);
		}
		break;
	}
	case id_function_tag : {
		/* Local function declaration */
		IDENTIFIER pid;
		TYPE t = DEREF_type (id_function_type (id));
		IDENTIFIER over = DEREF_id (id_function_over (id));
		if (!IS_NULL_id (over)) {
			copy_local_decl (over);
		}
		t = expand_type (t, 1);
		pid = make_func_decl (dspec_extern, t, id, 0);
		pid = DEREF_id (id_alias (pid));
		COPY_id (id_alias (id), pid);
		break;
	}
	case id_class_name_tag : {
		/* Local class */
		TYPE t = DEREF_type (id_class_name_defn (id));
		if (IS_type_compound (t)) {
			/* Can't be a template class */
			CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
			CLASS_INFO ci = DEREF_cinfo (ctype_info (ct));
			if (ci & cinfo_force_copy) {
				TYPE s;
				CLASS_TYPE cs;
				COPY_type (ctype_form (ct), NULL_type);
				s = copy_class (t, dspec_none);
				cs = DEREF_ctype (type_compound_defn (s));
				COPY_type (ctype_form (ct), s);
				copy_members (cs, ct, cinfo_none, 1);
			}
		}
		break;
	}
	case id_enumerator_tag : {
		/* Check enumerator values */
		IGNORE copy_id (id, 2);
		break;
	}
	}
	return;
}


/*
 *    COPY A COMPOUND STATEMENT
 *
 *    This routine copies the compound statement e.
 */

static EXP
copy_compound_stmt(EXP e, TYPE t1, TYPE t2)
{
	int block = DEREF_int (exp_sequence_block (e));
	NAMESPACE pns = DEREF_nspace (exp_sequence_decl (e));
	LIST (EXP) p = DEREF_list (exp_sequence_first (e));
	
	/* Copy the dummy first statement */
	LIST (EXP) q;
	EXP a = DEREF_exp (HEAD_list (p));
	if (!IS_NULL_exp (a)) a = copy_exp (a, t1, t2);
	CONS_exp (a, NULL_list (EXP), q);
	p = TAIL_list (p);
	
	/* Create the compound statement */
	MAKE_exp_sequence (t2, q, q, NULL_nspace, block, e);
	if (!IS_NULL_list (p)) {
		/* Construct namespace for copied block */
		MEMBER mem = NULL_member;
		NAMESPACE ns = make_namespace (crt_func_id, nspace_block_tag, 0);
		COPY_nspace (exp_sequence_decl (e), ns);
		push_namespace (ns);
		
		/* Copy members of block namespace */
		if (!IS_NULL_nspace (pns)) {
			MEMBER mem2 = DEREF_member (nspace_last (pns));
			while (!IS_NULL_member (mem2)) {
				IDENTIFIER id = DEREF_id (member_id (mem2));
				IDENTIFIER alt = DEREF_id (member_alt (mem2));
				if (!IS_NULL_id (id)) {
					copy_local_decl (id);
				}
				if (!IS_NULL_id (alt) && !EQ_id (id, alt)) {
					copy_local_decl (alt);
				}
				mem2 = DEREF_member (member_next (mem2));
			}
		}
		
		/* Copy list of components */
		while (!IS_NULL_list (p)) {
			MEMBER mem2;
			LIST (EXP) r;
			a = DEREF_exp (HEAD_list (p));
			a = copy_exp (a, t1, t2);
			mem2 = DEREF_member (nspace_last (ns));
			if (!EQ_member (mem2, mem)) {
				/* Introduced new temporary variables */
				a = make_temp_decl (mem2, mem, a);
				mem = mem2;
			}
			set_parent_stmt (a, e);
			CONS_exp (a, NULL_list (EXP), r);
			COPY_list (PTR_TAIL_list (q), r);
			q = r;
			p = TAIL_list (p);
		}
		
		/* Update compound statement */
		IGNORE pop_namespace ();
		COPY_member (nspace_prev (ns), mem);
		COPY_list (exp_sequence_last (e), q);
	}
	return (e);
}


/*
 *    LISTS OF DUMMY EXPRESSIONS
 *
 *    Dummy expressions are used to point to a component of a complex
 *    expression.  These lists are used to hold all the dummy expressions to
 *    be copied by copy_exp.  They are updated as they are copied.
 */

static LIST (EXP) input_dummy_exps = NULL_list (EXP);
static LIST (EXP) output_dummy_exps = NULL_list (EXP);


/*
 *    ADD A DUMMY EXPRESSION TO THE LIST
 *
 *    This routine adds the expression e to the lists of dummy expressions.
 */

static void
save_dummy_exp(EXP e)
{
	CONS_exp (e, input_dummy_exps, input_dummy_exps);
	CONS_exp (NULL_exp, output_dummy_exps, output_dummy_exps);
	return;
}


/*
 *    REMOVE A DUMMY EXPRESSION FROM THE LIST
 *
 *    This routine removes an expression from the lists of dummy expressions.
 *    It returns the copied values.
 */

static EXP
restore_dummy_exp(void)
{
	EXP a, b;
	DESTROY_CONS_exp (destroy, a, input_dummy_exps, input_dummy_exps);
	DESTROY_CONS_exp (destroy, b, output_dummy_exps, output_dummy_exps);
	if (IS_NULL_exp (b) && !IS_NULL_exp (a)) {
		/* Do a straight copy if not copied already */
		b = copy_exp (a, NULL_type, NULL_type);
	}
	return (b);
}


/*
 *    COPY A DUMMY EXPRESSION
 *
 *    This routine copies the dummy expression e, including updating the lists
 *    of dummy expressions.
 */

static EXP
copy_dummy_exp(EXP e, TYPE t1, TYPE t2)
{
	EXP f;
	LIST (EXP) p = input_dummy_exps;
	LIST (EXP) q = output_dummy_exps;
	EXP a = DEREF_exp (exp_dummy_value (e));
	ulong_type no = DEREF_ulong (exp_dummy_no (e));
	OFFSET off = DEREF_off (exp_dummy_off (e));
	int virt = DEREF_int (exp_dummy_virt (e));
	int cont = DEREF_int (exp_dummy_cont (e));
	a = copy_exp (a, t1, t2);
	off = copy_offset (off, lex_plus);
	MAKE_exp_dummy (t2, a, no, off, cont, f);
	COPY_int (exp_dummy_virt (f), virt);
	while (!IS_NULL_list (p)) {
		EXP b = DEREF_exp (HEAD_list (p));
		if (EQ_exp (b, e)) {
			/* Update output lists */
			COPY_exp (HEAD_list (q), f);
		}
		q = TAIL_list (q);
		p = TAIL_list (p);
	}
	return (f);
}


/*
 *    COPY AN EXPRESSION
 *
 *    This routine copies the expression e, expanding any template parameters
 *    and tokens.  It is used in the instantiation of template functions.
 *    t1 and t2 are used to prevent repeated type expansions.  t1 gives the
 *    previous expression type and t2 gives its expanded form.
 */

EXP
copy_exp(EXP e, TYPE t1, TYPE t2)
{
	TYPE t;
	unsigned tag;
	if (IS_NULL_exp (e)) return (NULL_exp);
	t = DEREF_type (exp_type (e));
	if (!EQ_type (t, t1)) {
		/* Expand type if necessary */
		t1 = t;
		t2 = expand_type (t, 1);
	}
	ASSERT (ORDER_exp == 88);
	tag = TAG_exp (e);
	switch (tag) {
	case exp_identifier_tag :
	case exp_member_tag :
	case exp_ambiguous_tag : {
		/* Identifier expressions */
		IDENTIFIER id = DEREF_id (exp_identifier_etc_id (e));
		QUALIFIER qual = DEREF_qual (exp_identifier_etc_qual (e));
		id = DEREF_id (id_alias (id));
		id = rescan_member (id);
		MAKE_exp_identifier_etc (tag, t2, id, qual, e);
		break;
	}
	case exp_undeclared_tag : {
		/* Undeclared identifier expressions */
		IDENTIFIER id = DEREF_id (exp_undeclared_id (e));
		QUALIFIER qual = DEREF_qual (exp_undeclared_qual (e));
		id = rescan_id (id, qual, 0);
		crt_id_qualifier = qual;
		e = make_id_exp (id);
		break;
	}
	case exp_int_lit_tag : {
		/* Integer literals */
		ERROR err = NULL_err;
		NAT n = DEREF_nat (exp_int_lit_nat (e));
		unsigned etag = DEREF_unsigned (exp_int_lit_etag (e));
		n = expand_nat (n, 1, 0, &err);
		if (!IS_NULL_err (err)) report (crt_loc, err);
		MAKE_exp_int_lit (t2, n, etag, e);
		break;
	}
	case exp_float_lit_tag : {
		/* Floating point literals */
		FLOAT flt = DEREF_flt (exp_float_lit_flt (e));
		MAKE_exp_float_lit (t2, flt, e);
		break;
	}
	case exp_char_lit_tag : {
		/* Character literals */
		STRING str = DEREF_str (exp_char_lit_str (e));
		int digit = DEREF_int (exp_char_lit_digit (e));
		MAKE_exp_char_lit (t2, str, digit, e);
		break;
	}
	case exp_string_lit_tag : {
		/* String literals */
		STRING str = DEREF_str (exp_string_lit_str (e));
		MAKE_exp_string_lit (t2, str, e);
		break;
	}
	case exp_value_tag : {
		/* Uninitiated expressions */
		MAKE_exp_value (t2, e);
		break;
	}
	case exp_null_tag : {
		/* Null expressions */
		int ptr_const = DEREF_int (exp_null_ptr_const (e));
		MAKE_exp_null (t2, e);
		COPY_int (exp_null_ptr_const (e), ptr_const);
		break;
	}
	case exp_zero_tag : {
		/* Zero expressions */
		MAKE_exp_zero (t2, e);
		break;
	}
	case exp_paren_tag : {
		/* Parenthesised expressions */
		EXP a = DEREF_exp (exp_paren_arg (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_paren (t2, a, e);
		break;
	}
	case exp_copy_tag : {
		/* Copy expressions */
		EXP a = DEREF_exp (exp_copy_arg (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_copy (t2, a, e);
		break;
	}
	case exp_assign_tag : {
		/* Assignment expressions */
		EXP a = DEREF_exp (exp_assign_ref (e));
		EXP b = DEREF_exp (exp_assign_arg (e));
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		MAKE_exp_assign (t2, a, b, e);
		break;
	}
	case exp_init_tag : {
		/* Initialisation expressions */
		IDENTIFIER id = DEREF_id (exp_init_id (e));
		EXP a = DEREF_exp (exp_init_arg (e));
		id = DEREF_id (id_alias (id));
		a = copy_exp (a, t1, t2);
		MAKE_exp_init (t2, id, a, e);
		break;
	}
	case exp_preinc_tag : {
		/* Pre-increment expressions */
		EXP a = DEREF_exp (exp_preinc_ref (e));
		EXP b = DEREF_exp (exp_preinc_op (e));
		int becomes = DEREF_int (exp_preinc_becomes (e));
		save_dummy_exp (a);
		b = copy_exp (b, t1, t2);
		a = restore_dummy_exp ();
		MAKE_exp_preinc (t2, a, b, becomes, e);
		break;
	}
	case exp_postinc_tag : {
		/* Post-increment expressions */
		EXP a = DEREF_exp (exp_postinc_ref (e));
		EXP b = DEREF_exp (exp_postinc_value (e));
		EXP c = DEREF_exp (exp_postinc_op (e));
		save_dummy_exp (a);
		if (!IS_NULL_exp (b)) {
			save_dummy_exp (b);
			c = copy_exp (c, t1, t2);
			b = restore_dummy_exp ();
		} else {
			c = copy_exp (c, t1, t2);
		}
		a = restore_dummy_exp ();
		MAKE_exp_postinc (t2, a, b, c, e);
		break;
	}
	case exp_indir_tag : {
		/* Indirection expressions */
		EXP a = DEREF_exp (exp_indir_ptr (e));
		int i = DEREF_int (exp_indir_index (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_indir (t2, a, e);
		COPY_int (exp_indir_index (e), i);
		break;
	}
	case exp_contents_tag : {
		/* Contents expressions */
		EXP a = DEREF_exp (exp_contents_ptr (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_contents (t2, a, e);
		break;
	}
	case exp_address_tag : {
		/* Address expressions */
		EXP a = DEREF_exp (exp_address_arg (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_address (t2, a, e);
		break;
	}
	case exp_address_mem_tag : {
		/* Member address expressions */
		EXP a = DEREF_exp (exp_address_mem_arg (e));
		int paren = DEREF_int (exp_address_mem_paren (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_address_mem (t2, a, paren, e);
		break;
	}
	case exp_func_tag : {
		/* Function expressions */
		EXP a = DEREF_exp (exp_func_fn (e));
		LIST (EXP) args = DEREF_list (exp_func_args (e));
		unsigned extra = DEREF_unsigned (exp_func_extra (e));
		a = copy_exp (a, t1, t2);
		args = copy_func_args (args, NULL_id);
		MAKE_exp_func (t2, a, args, e);
		COPY_unsigned (exp_func_extra (e), extra);
		break;
	}
	case exp_func_id_tag : {
		/* Function expressions */
		IDENTIFIER id = DEREF_id (exp_func_id_id (e));
		LIST (EXP) args = DEREF_list (exp_func_id_args (e));
		EXP a = DEREF_exp (exp_func_id_virt (e));
		unsigned extra = DEREF_unsigned (exp_func_id_extra (e));
		id = DEREF_id (id_alias (id));
		id = rescan_member (id);
		save_dummy_exp (a);
		args = copy_func_args (args, id);
		a = restore_dummy_exp ();
		MAKE_exp_func_id (t2, id, args, a, e);
		COPY_unsigned (exp_func_id_extra (e), extra);
		break;
	}
	case exp_call_tag : {
		/* Member call expressions */
		EXP a = DEREF_exp (exp_call_ptr (e));
		EXP b = DEREF_exp (exp_call_arg (e));
		GRAPH gr = DEREF_graph (exp_call_base (e));
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		gr = expand_graph (gr, 1);
		MAKE_exp_call (t2, a, b, gr, e);
		break;
	}
	case exp_negate_tag :
	case exp_compl_tag :
	case exp_not_tag :
	case exp_abs_tag : {
		/* Unary operations */
		EXP a = DEREF_exp (exp_negate_etc_arg (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_negate_etc (tag, t2, a, e);
		break;
	}
	case exp_plus_tag :
	case exp_minus_tag :
	case exp_mult_tag :
	case exp_div_tag :
	case exp_rem_tag :
	case exp_and_tag :
	case exp_or_tag :
	case exp_xor_tag :
	case exp_log_and_tag :
	case exp_log_or_tag :
	case exp_lshift_tag :
	case exp_rshift_tag :
	case exp_max_tag :
	case exp_min_tag : {
		/* Binary operations */
		EXP a = DEREF_exp (exp_plus_etc_arg1 (e));
		EXP b = DEREF_exp (exp_plus_etc_arg2 (e));
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		MAKE_exp_plus_etc (tag, t2, a, b, e);
		break;
	}
	case exp_test_tag : {
		/* Test expressions */
		NTEST tst = DEREF_ntest (exp_test_tst (e));
		EXP a = DEREF_exp (exp_test_arg (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_test (t2, tst, a, e);
		break;
	}
	case exp_compare_tag : {
		/* Comparison expressions */
		NTEST tst = DEREF_ntest (exp_compare_tst (e));
		EXP a = DEREF_exp (exp_compare_arg1 (e));
		EXP b = DEREF_exp (exp_compare_arg2 (e));
		TYPE s1 = DEREF_type (exp_type (a));
		TYPE s2 = expand_type (s1, 1);
		a = copy_exp (a, s1, s2);
		b = copy_exp (b, s1, s2);
		MAKE_exp_compare (t2, tst, a, b, e);
		break;
	}
	case exp_cast_tag : {
		/* Cast expressions */
		unsigned conv = DEREF_unsigned (exp_cast_conv (e));
		EXP a = DEREF_exp (exp_cast_arg (e));
		a = copy_exp (a, t1, t2);
		if (conv == CONV_EXACT && IS_exp_cast (a)) {
			/* Exact casts are idempotent */
			unsigned conv2 = DEREF_unsigned (exp_cast_conv (a));
			if (conv2 == CONV_EXACT) {
				a = DEREF_exp (exp_cast_arg (a));
			}
		}
		MAKE_exp_cast (t2, conv, a, e);
		break;
	}
	case exp_base_cast_tag : {
		/* Base cast expressions */
		unsigned conv = DEREF_unsigned (exp_base_cast_conv (e));
		EXP a = DEREF_exp (exp_base_cast_arg (e));
		OFFSET off = DEREF_off (exp_base_cast_off (e));
		a = copy_exp (a, t1, t2);
		off = copy_offset (off, lex_plus);
		MAKE_exp_base_cast (t2, conv, a, off, e);
		break;
	}
	case exp_dyn_cast_tag : {
		/* Dynamic cast expressions */
		EXP a = DEREF_exp (exp_dyn_cast_arg (e));
		EXP b = DEREF_exp (exp_dyn_cast_except (e));
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		MAKE_exp_dyn_cast (t2, a, b, e);
		break;
	}
	case exp_add_ptr_tag : {
		/* Pointer addition expressions */
		EXP a = DEREF_exp (exp_add_ptr_ptr (e));
		OFFSET off = DEREF_off (exp_add_ptr_off (e));
		int virt = DEREF_int (exp_add_ptr_virt (e));
		a = copy_exp (a, t1, t2);
		off = copy_offset (off, lex_plus);
		MAKE_exp_add_ptr (t2, a, off, virt, e);
		break;
	}
	case exp_offset_size_tag : {
		/* Offset division expressions */
		OFFSET off = DEREF_off (exp_offset_size_off (e));
		TYPE s = DEREF_type (exp_offset_size_step (e));
		int pad = DEREF_int (exp_offset_size_pad (e));
		off = copy_offset (off, lex_minus);
		s = copy_type_offset (s, lex_minus);
		MAKE_exp_offset_size (t2, off, s, pad, e);
		break;
	}
	case exp_constr_tag : {
		/* Constructor call expressions */
		EXP a = DEREF_exp (exp_constr_call (e));
		EXP b = DEREF_exp (exp_constr_obj (e));
		EXP c = DEREF_exp (exp_constr_alt (e));
		int info = DEREF_int (exp_constr_info (e));
		save_dummy_exp (b);
		save_dummy_exp (c);
		a = copy_exp (a, t1, t2);
		c = restore_dummy_exp ();
		b = restore_dummy_exp ();
		MAKE_exp_constr (t2, a, b, c, info, e);
		break;
	}
	case exp_destr_tag : {
		/* Destructor call expressions */
		EXP a = DEREF_exp (exp_destr_call (e));
		EXP b = DEREF_exp (exp_destr_obj (e));
		save_dummy_exp (b);
		a = copy_exp (a, t1, t2);
		b = restore_dummy_exp ();
		MAKE_exp_destr (t2, a, b, e);
		break;
	}
	case exp_alloc_tag : {
		/* Allocation call expressions */
		EXP a = DEREF_exp (exp_alloc_call (e));
		EXP b = DEREF_exp (exp_alloc_init (e));
		EXP c = DEREF_exp (exp_alloc_garbage (e));
		EXP d = DEREF_exp (exp_alloc_size (e));
		save_dummy_exp (d);
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		c = copy_exp (c, t1, t2);
		d = restore_dummy_exp ();
		MAKE_exp_alloc (t2, a, b, c, d, e);
		break;
	}
	case exp_dealloc_tag : {
		/* Deallocation call expressions */
		EXP a = DEREF_exp (exp_dealloc_term (e));
		EXP b = DEREF_exp (exp_dealloc_call (e));
		EXP c = DEREF_exp (exp_dealloc_arg (e));
		EXP d = DEREF_exp (exp_dealloc_size (e));
		save_dummy_exp (c);
		save_dummy_exp (d);
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		d = restore_dummy_exp ();
		c = restore_dummy_exp ();
		MAKE_exp_dealloc (t2, a, b, c, d, e);
		break;
	}
	case exp_rtti_tag : {
		/* Run-time type information expressions */
		EXP a = DEREF_exp (exp_rtti_arg (e));
		EXP b = DEREF_exp (exp_rtti_except (e));
		int op = DEREF_int (exp_rtti_op (e));
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		MAKE_exp_rtti (t2, a, b, op, e);
		break;
	}
	case exp_rtti_type_tag : {
		/* Run-time type information expressions */
		TYPE s = DEREF_type (exp_rtti_type_arg (e));
		int op = DEREF_int (exp_rtti_type_op (e));
		s = expand_type (s, 1);
		MAKE_exp_rtti_type (t2, s, op, e);
		break;
	}
	case exp_rtti_no_tag : {
		/* Run-time type information expressions */
		TYPE s = DEREF_type (exp_rtti_no_arg (e));
		s = expand_type (s, 1);
		MAKE_exp_rtti_no (t2, s, e);
		break;
	}
	case exp_dynamic_tag : {
		/* Dynamic initialiser expressions */
		EXP a = DEREF_exp (exp_dynamic_arg (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_dynamic (t2, a, e);
		break;
	}
	case exp_aggregate_tag : {
		/* Aggregate initialisers */
		LIST (EXP) args = DEREF_list (exp_aggregate_args (e));
		LIST (OFFSET) offs = DEREF_list (exp_aggregate_offs (e));
		args = copy_exp_list (args, t1, t2);
		offs = copy_off_list (offs);
		MAKE_exp_aggregate (t2, args, offs, e);
		break;
	}
	case exp_initialiser_tag : {
		/* Constructor initialisers */
		int kind = DEREF_int (exp_initialiser_kind (e));
		if (kind) {
			/* Copy ctor-initialiser */
			e = copy_ctor (e, kind);
		} else {
			unsigned nv, nb;
			LIST (EXP) args;
			LIST (OFFSET) offs;
			args = DEREF_list (exp_initialiser_args (e));
			offs = DEREF_list (exp_initialiser_offs (e));
			nv = DEREF_unsigned (exp_initialiser_virt (e));
			nb = DEREF_unsigned (exp_initialiser_base (e));
			args = copy_exp_list (args, t1, t2);
			offs = copy_off_list (offs);
			MAKE_exp_initialiser (t2, args, offs, kind, nv, nb, e);
		}
		break;
	}
	case exp_nof_tag : {
		/* Array initialisers */
		ERROR err = NULL_err;
		EXP a = DEREF_exp (exp_nof_start (e));
		EXP b = DEREF_exp (exp_nof_pad (e));
		EXP c = DEREF_exp (exp_nof_end (e));
		NAT n = DEREF_nat (exp_nof_size (e));
		NAT m = expand_nat (n, 1, 0, &err);
		a = copy_exp (a, t1, t2);
		if (!EQ_nat (n, m)) {
			if (!IS_NULL_err (err)) report (crt_loc, err);
			if (is_zero_nat (m)) {
				/* No extra elements */
				e = a;
				break;
			}
			if (is_negative_nat (m)) {
				/* Number of extra elements has gone negative */
				report (crt_loc, ERR_dcl_init_aggr_excess (t2));
				e = a;
				break;
			}
		}
		b = copy_exp (b, t1, t2);
		c = copy_exp (c, t1, t2);
		MAKE_exp_nof (t2, a, m, b, c, e);
		break;
	}
	case exp_comma_tag : {
		/* Comma expressions */
		LIST (EXP) args = DEREF_list (exp_comma_args (e));
		args = copy_exp_list (args, t1, t2);
		MAKE_exp_comma (t2, args, e);
		break;
	}
	case exp_set_tag : {
		/* Variable set expressions */
		EXP a = DEREF_exp (exp_set_arg (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_set (t2, a, e);
		break;
	}
	case exp_unused_tag : {
		/* Variable unset expressions */
		EXP a = DEREF_exp (exp_unused_arg (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_unused (t2, a, e);
		break;
	}
	case exp_reach_tag : {
		/* Reached statements */
		EXP a = DEREF_exp (exp_reach_body (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_reach (t2, a, e);
		set_parent_stmt (a, e);
		break;
	}
	case exp_unreach_tag : {
		/* Unreached statements */
		EXP a = DEREF_exp (exp_unreach_body (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_unreach (t2, a, e);
		set_parent_stmt (a, e);
		break;
	}
	case exp_sequence_tag : {
		/* Block statements */
		e = copy_compound_stmt (e, t1, t2);
		break;
	}
	case exp_solve_stmt_tag : {
		/* Solve statements */
		EXP a = DEREF_exp (exp_solve_stmt_body (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_solve_stmt (t2, a, e);
		CONS_exp (e, all_solve_stmts, all_solve_stmts);
		set_parent_stmt (a, e);
		break;
	}
	case exp_decl_stmt_tag : {
		/* Declaration statements */
		IDENTIFIER id = DEREF_id (exp_decl_stmt_id (e));
		IDENTIFIER aid = DEREF_id (id_alias (id));
		IDENTIFIER cid = copy_local (id);
		EXP a = DEREF_exp (exp_decl_stmt_body (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_decl_stmt (t2, cid, a, e);
		set_parent_stmt (a, e);
		COPY_id (id_alias (id), aid);
		break;
	}
	case exp_if_stmt_tag : {
		/* Conditional statements */
		EXP c = DEREF_exp (exp_if_stmt_cond (e));
		EXP a = DEREF_exp (exp_if_stmt_true_code (e));
		EXP b = DEREF_exp (exp_if_stmt_false_code (e));
		IDENTIFIER lab = DEREF_id (exp_if_stmt_label (e));
		c = copy_exp (c, type_bool, type_bool);
		lab = copy_label (lab, 1);
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		MAKE_exp_if_stmt (t2, c, a, b, lab, e);
		set_parent_stmt (a, e);
		set_parent_stmt (b, e);
		break;
	}
	case exp_while_stmt_tag : {
		/* While statements */
		LIST (IDENTIFIER) pids;
		EXP c = DEREF_exp (exp_while_stmt_cond (e));
		EXP a = DEREF_exp (exp_while_stmt_body (e));
		IDENTIFIER blab = DEREF_id (exp_while_stmt_break_lab (e));
		IDENTIFIER clab = DEREF_id (exp_while_stmt_cont_lab (e));
		IDENTIFIER llab = DEREF_id (exp_while_stmt_loop_lab (e));
		c = copy_exp (c, type_bool, type_bool);
		blab = copy_label (blab, 1);
		clab = copy_label (clab, 1);
		llab = copy_label (llab, 1);
		pids = DEREF_list (exp_while_stmt_cond_id (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_while_stmt (t2, c, blab, clab, llab, e);
		COPY_exp (exp_while_stmt_body (e), a);
		set_jump_joins (blab, e);
		set_jump_joins (clab, e);
		set_parent_stmt (a, e);
		if (!IS_NULL_list (pids)) {
			LIST (IDENTIFIER) qids = NULL_list (IDENTIFIER);
			while (!IS_NULL_list (pids)) {
				IDENTIFIER id = DEREF_id (HEAD_list (pids));
				id = DEREF_id (id_alias (id));
				CONS_id (id, qids, qids);
				pids = TAIL_list (pids);
			}
			qids = REVERSE_list (qids);
			COPY_list (exp_while_stmt_cond_id (e), qids);
		}
		break;
	}
	case exp_do_stmt_tag : {
		/* Do statements */
		EXP c = DEREF_exp (exp_do_stmt_cond (e));
		EXP a = DEREF_exp (exp_do_stmt_body (e));
		IDENTIFIER blab = DEREF_id (exp_do_stmt_break_lab (e));
		IDENTIFIER clab = DEREF_id (exp_do_stmt_cont_lab (e));
		IDENTIFIER llab = DEREF_id (exp_do_stmt_loop_lab (e));
		blab = copy_label (blab, 1);
		clab = copy_label (clab, 1);
		llab = copy_label (llab, 1);
		a = copy_exp (a, t1, t2);
		c = copy_exp (c, type_bool, type_bool);
		MAKE_exp_do_stmt (t2, c, blab, clab, llab, e);
		COPY_exp (exp_do_stmt_body (e), a);
		set_jump_joins (blab, e);
		set_jump_joins (clab, e);
		set_parent_stmt (a, e);
		break;
	}
	case exp_switch_stmt_tag : {
		/* Switch statements */
		e = copy_switch_stmt (e, t1, t2);
		break;
	}
	case exp_hash_if_tag : {
		/* Target dependent conditional statements */
		EXP c = DEREF_exp (exp_hash_if_cond (e));
		EXP a = DEREF_exp (exp_hash_if_true_code (e));
		EXP b = DEREF_exp (exp_hash_if_false_code (e));
		c = copy_exp (c, type_bool, type_bool);
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		MAKE_exp_hash_if (t2, c, a, b, e);
		set_parent_stmt (a, e);
		set_parent_stmt (b, e);
		break;
	}
	case exp_return_stmt_tag : {
		/* Return statements */
		EXP a = DEREF_exp (exp_return_stmt_value (e));
		EXP b = implicit_cast_exp (a);
		if (!IS_NULL_exp (b)) {
			IDENTIFIER lab = NULL_id;
			b = copy_exp (b, t1, t2);
			a = find_return_exp (b, &lab, lex_return);
		} else {
			a = copy_exp (a, t1, t2);
		}
		MAKE_exp_return_stmt (t2, a, e);
		break;
	}
	case exp_goto_stmt_tag : {
		/* Goto statements */
		IDENTIFIER lab = DEREF_id (exp_goto_stmt_label (e));
		lab = copy_label (lab, 0);
		e = make_jump_stmt (lab, NULL_exp);
		break;
	}
	case exp_label_stmt_tag : {
		/* Labelled statements */
		IDENTIFIER lab = DEREF_id (exp_label_stmt_label (e));
		lab = copy_label (lab, 1);
		e = DEREF_exp (id_label_stmt (lab));
		break;
	}
#if LANGUAGE_CPP
	case exp_try_block_tag : {
		/* Try blocks */
		e = copy_try_stmt (e, t1, t2);
		break;
	}
	case exp_handler_tag : {
		/* Exception handlers */
		IDENTIFIER id = DEREF_id (exp_handler_except (e));
		IDENTIFIER aid = DEREF_id (id_alias (id));
		IDENTIFIER cid = copy_local (id);
		EXP a = DEREF_exp (exp_handler_body (e));
		a = copy_exp (a, t1, t2);
		MAKE_exp_handler (t2, cid, a, e);
		set_parent_stmt (a, e);
		COPY_id (id_alias (id), aid);
		break;
	}
	case exp_exception_tag : {
		/* Exception expressions */
		EXP a = DEREF_exp (exp_exception_arg (e));
		EXP b = DEREF_exp (exp_exception_size (e));
		EXP c = DEREF_exp (exp_exception_destr (e));
		int expl = DEREF_int (exp_exception_expl (e));
		a = copy_exp (a, t1, t2);
		b = copy_exp (b, t1, t2);
		c = copy_exp (c, t1, t2);
		MAKE_exp_exception (t2, a, b, c, expl, e);
		break;
	}
	case exp_thrown_tag : {
		/* Thrown expressions */
		int d = DEREF_int (exp_thrown_done (e));
		MAKE_exp_thrown (t2, d, e);
		break;
	}
#endif
	case exp_op_tag : {
		/* Undetermined expressions */
		int op = DEREF_int (exp_op_lex (e));
		EXP a = DEREF_exp (exp_op_arg1 (e));
		EXP b = DEREF_exp (exp_op_arg2 (e));
		if (IS_NULL_exp (b)) {
			e = apply_unary (op, a, t1, t2, 1);
		} else {
			e = apply_binary (op, a, b, t1, t2, 1);
		}
		break;
	}
	case exp_opn_tag : {
		/* Undetermined expressions */
		int op = DEREF_int (exp_opn_lex (e));
		LIST (EXP) args = DEREF_list (exp_opn_args (e));
		e = apply_nary (op, args, t1, t2, 1);
		break;
	}
	case exp_assembler_tag : {
		/* Assembler expressions */
		STRING op = DEREF_str (exp_assembler_op (e));
		LIST (EXP) args = DEREF_list (exp_assembler_args (e));
		args = copy_exp_list (args, t1, t2);
		MAKE_exp_assembler (t2, op, args, e);
		break;
	}
	case exp_uncompiled_tag : {
		/* Uncompiled expressions */
		PPTOKEN *p = DEREF_pptok (exp_uncompiled_defn (e));
		DEREF_loc (exp_uncompiled_start (e), crt_loc);
		MAKE_exp_uncompiled (t2, crt_loc, p, e);
		break;
	}
	case exp_location_tag : {
		/* Location expressions */
		EXP a = DEREF_exp (exp_location_arg (e));
		a = copy_exp (a, t1, t2);
		DEREF_loc (exp_location_end (e), crt_loc);
		MAKE_exp_location (t2, crt_loc, a, e);
		break;
	}
	case exp_fail_tag : {
		/* Installer error expressions */
		string msg = DEREF_string (exp_fail_msg (e));
		MAKE_exp_fail (t2, msg, e);
		break;
	}
	case exp_dummy_tag : {
		/* Dummy expressions */
		e = copy_dummy_exp (e, t1, t2);
		break;
	}
	case exp_token_tag : {
		/* Expression tokens */
		e = expand_exp (e, 1, 0);
		break;
	}
	}
	return (e);
}


/*
 *    EVALUATE A CONSTANT EXPRESSION
 *
 *    This routine evaluates the integer constant expression e, expanding
 *    any template parameters and tokens.  If ch is true then any character
 *    literals are replaced by their ASCII values.
 */

EXP
eval_exp(EXP e, int ch)
{
	unsigned tag;
	if (IS_NULL_exp (e)) return (NULL_exp);
	ASSERT (ORDER_exp == 88);
	tag = TAG_exp (e);
	switch (tag) {
	case exp_int_lit_tag : {
		/* Integer literals */
		ERROR err = NULL_err;
		NAT n1 = DEREF_nat (exp_int_lit_nat (e));
		NAT n2 = expand_nat (n1, 1, ch, &err);
		if (!EQ_nat (n1, n2)) {
			TYPE t;
			unsigned etag = DEREF_unsigned (exp_int_lit_etag (e));
			if (!IS_NULL_err (err)) report (crt_loc, err);
			if (IS_nat_calc (n2)) {
				if (etag == exp_identifier_tag) break;
				e = DEREF_exp (nat_calc_value (n2));
				if (IS_exp_int_lit (e)) break;
			}
			t = DEREF_type (exp_type (e));
			t = expand_type (t, 1);
			MAKE_exp_int_lit (t, n2, etag, e);
		}
		break;
	}
	case exp_char_lit_tag : {
		/* Character literals */
		if (ch) {
			TYPE t = DEREF_type (exp_type (e));
			STRING s = DEREF_str (exp_char_lit_str (e));
			NAT n = eval_char_lit (s);
			if (check_nat_range (t, n) != NAT_FIT) {
				/* n may not fit into t */
				TYPE u = find_char_type (n);
				MAKE_exp_int_lit (u, n, tag, e);
				MAKE_exp_cast (t, CONV_INT_INT, e, e);
				MAKE_nat_calc (e, n);
				tag = exp_cast_tag;
			}
			MAKE_exp_int_lit (t, n, tag, e);
		} else {
			e = copy_exp (e, NULL_type, NULL_type);
		}
		break;
	}
	case exp_paren_tag : {
		/* Parenthesised expressions */
		EXP a = DEREF_exp (exp_paren_arg (e));
		e = eval_exp (a, ch);
		break;
	}
	case exp_negate_tag :
	case exp_compl_tag :
	case exp_not_tag :
	case exp_abs_tag : {
		/* Unary operations */
		EXP a1 = DEREF_exp (exp_negate_etc_arg (e));
		EXP a2 = eval_exp (a1, ch);
		if (!EQ_exp (a1, a2)) {
			int op = op_token (e, lex_unknown);
			e = apply_unary (op, a2, NULL_type, NULL_type, 0);
		}
		break;
	}
	case exp_plus_tag :
	case exp_minus_tag :
	case exp_mult_tag :
	case exp_div_tag :
	case exp_rem_tag :
	case exp_and_tag :
	case exp_or_tag :
	case exp_xor_tag :
	case exp_log_and_tag :
	case exp_log_or_tag :
	case exp_lshift_tag :
	case exp_rshift_tag :
	case exp_max_tag :
	case exp_min_tag : {
		/* Binary operations */
		EXP a1 = DEREF_exp (exp_plus_etc_arg1 (e));
		EXP b1 = DEREF_exp (exp_plus_etc_arg2 (e));
		EXP a2 = eval_exp (a1, ch);
		EXP b2 = eval_exp (b1, ch);
		if (!EQ_exp (a1, a2) || !EQ_exp (b1, b2)) {
			int op = op_token (e, lex_unknown);
			e = apply_binary (op, a2, b2, NULL_type, NULL_type, 0);
		}
		break;
	}
	case exp_test_tag : {
		/* Test expressions */
		EXP a1 = DEREF_exp (exp_test_arg (e));
		EXP a2 = eval_exp (a1, ch);
		if (!EQ_exp (a1, a2)) {
			int op = op_token (e, lex_unknown);
			TYPE t2 = DEREF_type (exp_type (a2));
			EXP b2 = make_null_exp (t2);
			e = apply_binary (op, a2, b2, NULL_type, NULL_type, 0);
		}
		break;
	}
	case exp_compare_tag : {
		/* Comparison expressions */
		EXP a1 = DEREF_exp (exp_compare_arg1 (e));
		EXP b1 = DEREF_exp (exp_compare_arg2 (e));
		EXP a2 = eval_exp (a1, ch);
		EXP b2 = eval_exp (b1, ch);
		if (!EQ_exp (a1, a2) || !EQ_exp (b1, b2)) {
			int op = op_token (e, lex_unknown);
			e = apply_binary (op, a2, b2, NULL_type, NULL_type, 0);
		}
		break;
	}
	case exp_cast_tag : {
		/* Cast expressions */
		unsigned conv = DEREF_unsigned (exp_cast_conv (e));
		EXP a1 = DEREF_exp (exp_cast_arg (e));
		EXP a2 = eval_exp (a1, ch);
		if (!EQ_exp (a1, a2) || conv == CONV_ENUM) {
			ERROR err = NULL_err;
			TYPE t = DEREF_type (exp_type (e));
			t = expand_type (t, 1);
			a2 = convert_reference (a2, REF_ASSIGN);
			e = cast_exp (t, a2, &err, CAST_STATIC);
			if (!IS_NULL_err (err)) {
				err = concat_warning (err, ERR_expr_cast_expl_bad ());
				report (crt_loc, err);
			}
		}
		break;
	}
	case exp_offset_size_tag : {
		/* Offset division expressions */
		OFFSET off = DEREF_off (exp_offset_size_off (e));
		TYPE s = DEREF_type (exp_offset_size_step (e));
		if (IS_off_type (off) && EQ_type (s, type_char)) {
			TYPE t1 = DEREF_type (off_type_type (off));
			TYPE t2 = expand_type (t1, 1);
			if (!EQ_type (t1, t2)) {
				/* Evaluate sizeof expressions */
				e = make_sizeof_exp (t2, NULL_exp, 0, lex_sizeof);
			}
		}
		break;
	}
	case exp_if_stmt_tag : {
		/* Conditional statements */
		EXP c1 = DEREF_exp (exp_if_stmt_cond (e));
		EXP a1 = DEREF_exp (exp_if_stmt_true_code (e));
		EXP b1 = DEREF_exp (exp_if_stmt_false_code (e));
		EXP c2 = eval_exp (c1, ch);
		EXP a2 = eval_exp (a1, ch);
		EXP b2 = eval_exp (b1, ch);
		if (!EQ_exp (c1, c2) ||
			!EQ_exp (a1, a2) || !EQ_exp (b1, b2)) {
			e = make_cond_exp (c2, a2, b2);
		}
		break;
	}
	default : {
		/* Other expressions */
		EXP f = copy_exp (e, NULL_type, NULL_type);
		if (!EQ_exp (f, e) && !eq_exp_exact (f, e)) e = f;
		break;
	}
	}
	return (e);
}


/*
 *    COPY AN OBJECT FUNCTION DEFINITION
 *
 *    This defines the object id to be a copy of the expression e.  It
 *    is used in the instantiation of template functions and static data
 *    members of template classes.
 */

void
copy_object(IDENTIFIER id, EXP e)
{
	if (!IS_NULL_exp (e)) {
		int r = record_location;
		record_location = 0;
		begin_declarator (id, qual_none, NULL_nspace, 0);
		switch (TAG_id (id)) {
		case id_function_tag :
		case id_mem_func_tag :
		case id_stat_mem_func_tag : {
			/* Functions */
			TYPE fn = DEREF_type (id_function_etc_type (id));
			in_function_defn++;
			really_in_function_defn++;
			IGNORE begin_templ_scope (fn);
			begin_function (id);
			e = copy_exp (e, type_bottom, type_bottom);
			IGNORE pop_namespace ();
			unreached_code = 1;
			IGNORE end_function (id, e);
			end_templ_scope (fn);
			really_in_function_defn--;
			in_function_defn--;
			break;
		}
		case id_stat_member_tag : {
			/* Static data members */
			copy_variable (id, e);
			if (!in_template_decl) {
				compile_variable (id, 0);
			}
			if (do_dump) dump_declare (id, &crt_loc, 1);
			break;
		}
		case id_class_name_tag : {
			/* Nested template classes */
			CLASS_TYPE ct, cs;
			TYPE t = DEREF_type (id_class_name_defn (id));
			TYPE s = DEREF_type (exp_type (e));
			while (IS_type_templ (t)) {
				t = DEREF_type (type_templ_defn (t));
			}
			ct = DEREF_ctype (type_compound_defn (t));
			while (IS_type_templ (s)) {
				s = DEREF_type (type_templ_defn (s));
			}
			cs = DEREF_ctype (type_compound_defn (s));
			copy_members (ct, cs, cinfo_none, 1);
			break;
		}
		}
		end_declarator (id, 0);
		record_location = r;
	}
	return;
}


/*
 *    CHECK FOR NON-CLASS NAMESPACES
 *
 *    Qualifiers of the form 'T::' where T is a template parameter can lead
 *    to repeated errors if T is bound to a non-class type.  This routine
 *    is used to keep track of those instances which have been reported
 *    to avoid duplication.
 */

static int
reported_nspace(NAMESPACE ns, TYPE t)
{
	static LIST (TYPE) types = NULL_list (TYPE);
	static LIST (NAMESPACE) nspaces = NULL_list (NAMESPACE);
	LIST (TYPE) p = types;
	LIST (NAMESPACE) q = nspaces;
	while (!IS_NULL_list (q)) {
		NAMESPACE pns = DEREF_nspace (HEAD_list (q));
		if (EQ_nspace (pns, ns)) {
			TYPE pt = DEREF_type (HEAD_list (p));
			if (eq_type (pt, t)) return (1);
		}
		p = TAIL_list (p);
		q = TAIL_list (q);
	}
	CONS_type (t, types, types);
	CONS_nspace (ns, nspaces, nspaces);
	return (0);
}


/*
 *    EXPAND A NAMESPACE
 *
 *    This routine expands the namespace ns by replacing any class namespace
 *    by the namespace of the expanded class.
 */

NAMESPACE
rescan_nspace(NAMESPACE ns)
{
	if (!IS_NULL_nspace (ns) && IS_nspace_ctype (ns)) {
		TYPE s;
		IDENTIFIER tid = DEREF_id (nspace_name (ns));
		TYPE t = DEREF_type (id_class_name_etc_defn (tid));
		while (IS_type_templ (t)) {
			t = DEREF_type (type_templ_defn (t));
		}
		s = expand_type (t, 1);
		if (!EQ_type (t, s)) {
			unsigned tag = TAG_type (s);
			while (tag == type_templ_tag) {
				s = DEREF_type (type_templ_defn (s));
				tag = TAG_type (s);
			}
			if (tag == type_compound_tag) {
				/* Expands to class type */
				CLASS_TYPE cs = DEREF_ctype (type_compound_defn (s));
				complete_class (cs, 1);
				ns = DEREF_nspace (ctype_member (cs));
			} else if (tag == type_token_tag && is_templ_type (s)) {
				/* Allow template parameters */
				IDENTIFIER id = DEREF_id (type_token_tok (s));
				CLASS_TYPE cs = find_class (id);
				if (!IS_NULL_ctype (cs)) {
					ns = DEREF_nspace (ctype_member (cs));
				}
			} else {
				if (tag != type_error_tag && !reported_nspace (ns, s)) {
					/* Other types are not allowed */
					report (crt_loc, ERR_temp_res_nspace (ns, s));
				}
			}
		}
	}
	return (ns);
}


/*
 *    RESCAN AN IDENTIFIER NAME
 *
 *    This routine looks up the identifier id again in the current context.
 *    The name is looked up as a type-name if type is true.  The routine is
 *    used in the resolution of dependent names in template instantiations.
 */

IDENTIFIER
rescan_id(IDENTIFIER id, QUALIFIER qual, int type)
{
	DECL_SPEC ds;
	int member = 0;
	IDENTIFIER rid = NULL_id;
	HASHID nm = DEREF_hashid (id_name (id));
	NAMESPACE ns = DEREF_nspace (id_parent (id));
	
	/* Allow for pseudo-template instances */
	if (IS_id_undef (id)) {
		TYPE form = DEREF_type (id_undef_form (id));
		if (!IS_NULL_type (form) && IS_type_token (form)) {
			int force = 0;
			IDENTIFIER tid = DEREF_id (type_token_tok (form));
			LIST (TOKEN) args = DEREF_list (type_token_args (form));
			tid = rescan_id (tid, qual, type);
			if (IS_id_undef (tid)) force = 1;
			args = expand_args (args, 1, 1);
			rid = apply_template (tid, args, 0, force);
			return (rid);
		}
	}
	
	/* Allow for template instances */
	ds = DEREF_dspec (id_storage (id));
	if (ds & dspec_instance) {
		if (IS_id_function_etc (id)) {
			/* Template functions */
			TYPE form = DEREF_type (id_function_etc_form (id));
			if (!IS_NULL_type (form) && IS_type_token (form)) {
				IDENTIFIER tid = DEREF_id (type_token_tok (form));
				if (IS_id_function_etc (tid)) {
					LIST (TOKEN) args;
					tid = rescan_id (tid, qual, type);
					args = DEREF_list (type_token_args (form));
					args = expand_args (args, 1, 1);
					rid = apply_template (tid, args, 0, 0);
					return (rid);
				}
			}
		}
	}
	
	/* Look up identifier */
	nm = expand_name (nm, NULL_ctype);
	if (!IS_NULL_nspace (ns)) {
		if (qual != qual_none) {
			member = 1;
		} else if (IS_nspace_ctype (ns) && !IS_id_undef (id)) {
			member = 1;
		}
	}
	if (member) {
		/* Expand namespace */
		NAMESPACE cns = rescan_nspace (ns);
		if (IS_nspace_ctype (cns)) {
			rid = search_field (cns, nm, 0, type);
		} else {
			MEMBER mem = search_member (cns, nm, 0);
			if (!IS_NULL_member (mem)) {
				if (type) {
					rid = type_member (mem, type);
				} else {
					rid = DEREF_id (member_id (mem));
				}
			}
		}
		
		/* Check for undeclared identifiers */
		if (IS_NULL_id (rid)) {
			MAKE_id_undef (nm, dspec_none, cns, crt_loc, rid);
		}
		
	} else {
		/* Simple name look-up */
		rid = find_id (nm);
	}
	return (rid);
}


/*
 *    RESCAN A FUNCTION IDENTIFIER NAME
 *
 *    This routine is a special case of rescan_id which is used to look up
 *    the names of functions in template instantiations.  If the look-ups
 *    in the contexts of both the template definition and the template
 *    instantiation are both functions then the result is an ambiguous
 *    identifier consisting of both sets of overloaded functions.
 *    Overload resolution is then used to select within these two sets.
 */

IDENTIFIER
rescan_func_id(IDENTIFIER id, QUALIFIER qual)
{
	IDENTIFIER pid = rescan_id (id, qual, 0);
	IDENTIFIER qid = rescan_member (id);
	NAMESPACE qns = DEREF_nspace (id_parent (qid));
	if (!IS_NULL_nspace (qns) && IS_nspace_block (qns)) {
		qid = pid;
	}
	/* QUERY: should qid be rescanned in context? */
	if (!EQ_id (pid, qid) && !IS_id_undef (qid)) {
		int eq = 0;
		if (IS_id_function_etc (pid) && IS_id_function_etc (qid)) {
			/* Check for overloaded functions */
			IDENTIFIER rid = pid;
			while (!IS_NULL_id (rid)) {
				if (EQ_id (rid, qid)) {
					eq = 1;
					break;
				}
				rid = DEREF_id (id_function_etc_over (rid));
			}
		}
		if (!eq) {
			/* Create ambiguous identifier */
			DECL_SPEC ds;
			LOCATION loc;
			LIST (IDENTIFIER) pids;
			HASHID nm = DEREF_hashid (id_name (pid));
			NAMESPACE ns = DEREF_nspace (id_parent (pid));
			DEREF_loc (id_loc (pid), loc);
			CONS_id (pid, NULL_list (IDENTIFIER), pids);
			CONS_id (qid, pids, pids);
			ds = find_ambig_dspec (pids);
			MAKE_id_ambig (nm, ds, ns, loc, pids, 1, pid);
		}
	}
	return (pid);
}


/*
 *    RESCAN A MEMBER NAME
 *
 *    This routine rescans the identifier id.  If id is a member of a template
 *    class then the corresponding member of the expanded class is returned.
 *    id is also marked as having been used and is instantiated if necessary.
 */

IDENTIFIER
rescan_member(IDENTIFIER id)
{
	IDENTIFIER lid;
	NAMESPACE ns = DEREF_nspace (id_parent (id));
	DECL_SPEC ds = DEREF_dspec (id_storage (id));
	
	/* Check for template functions */
	if (ds & dspec_instance) {
		if (IS_id_function_etc (id)) {
			/* Template functions */
			TYPE form = DEREF_type (id_function_etc_form (id));
			if (!IS_NULL_type (form) && IS_type_token (form)) {
				IDENTIFIER tid = DEREF_id (type_token_tok (form));
				if (IS_id_function_etc (tid)) {
					LIST (TOKEN) args;
					tid = rescan_member (tid);
					args = DEREF_list (type_token_args (form));
					args = expand_args (args, 1, 1);
					id = apply_template (tid, args, 0, 0);
					ns = NULL_nspace;
				}
			}
		}
	}
	
	/* Check for template class members */
	if (!IS_NULL_nspace (ns) && IS_nspace_ctype (ns)) {
		NAMESPACE pns = rescan_nspace (ns);
		if (!EQ_nspace (ns, pns)) {
			IDENTIFIER pid = DEREF_id (nspace_name (pns));
			lid = find_copied (pid, id, 1);
			if (!EQ_id (lid, id)) {
				define_template (lid, 0);
				id = lid;
				ds = DEREF_dspec (id_storage (id));
			}
		}
	}
	
	/* Handle implicitly declared parameters */
	if ((ds & dspec_implicit) && (ds & dspec_auto)) {
		HASHID nm = DEREF_hashid (id_name (id));
		id = find_id (nm);
		ds = DEREF_dspec (id_storage (id));
	}
	
	/* Mark as used */
	ds |= dspec_used;
	COPY_dspec (id_storage (id), ds);
	lid = DEREF_id (id_alias (id));
	if (!EQ_id (lid, id)) {
		ds = DEREF_dspec (id_storage (lid));
		ds |= dspec_used;
		COPY_dspec (id_storage (lid), ds);
	}
	return (id);
}


syntax highlighted by Code2HTML, v. 0.9.1