/* * Copyright (c) 2002, The Tendra Project * 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); }