/* * 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/check.c,v 1.8 2005/08/04 20:22:16 stefanf Exp $ */ #include "config.h" #include "producer.h" #include "msgcat.h" #include "c_types.h" #include "exp_ops.h" #include "graph_ops.h" #include "hashid_ops.h" #include "id_ops.h" #include "nat_ops.h" #include "nspace_ops.h" #include "off_ops.h" #include "tok_ops.h" #include "type_ops.h" #include "error.h" #include "catalog.h" #include "option.h" #include "basetype.h" #include "check.h" #include "chktype.h" #include "constant.h" #include "convert.h" #include "derive.h" #include "function.h" #include "hash.h" #include "literal.h" #include "merge.h" #include "namespace.h" #include "syntax.h" #include "tokdef.h" /* * ARE TWO OFFSETS EQUAL? * * This routine checks whether the offsets a and b are equal. The co * argument is passed through to eq_exp. */ int eq_offset(OFFSET a, OFFSET b, int co) { unsigned taga, tagb; /* Check for obvious equality */ if (EQ_off (a, b)) return (1); if (IS_NULL_off (a)) return (0); if (IS_NULL_off (b)) return (0); /* Check tags */ taga = TAG_off (a); tagb = TAG_off (b); if (taga != tagb) return (0); /* Check individual cases */ ASSERT (ORDER_off == 13); switch (TAG_off (a)) { case off_zero_tag : { /* Zero offsets */ TYPE ta = DEREF_type (off_zero_type (a)); TYPE tb = DEREF_type (off_zero_type (b)); return (eq_type_offset (ta, tb)); } case off_type_tag : { /* Type offsets */ TYPE ta = DEREF_type (off_type_type (a)); TYPE tb = DEREF_type (off_type_type (b)); return (eq_type_offset (ta, tb)); } case off_extra_tag : { /* Extra allocator offsets */ TYPE ta = DEREF_type (off_extra_type (a)); TYPE tb = DEREF_type (off_extra_type (b)); int na = DEREF_int (off_extra_scale (a)); int nb = DEREF_int (off_extra_scale (b)); return (na == nb && eq_type_offset (ta, tb)); } case off_array_tag : { /* Array offsets */ TYPE ta = DEREF_type (off_array_type (a)); TYPE tb = DEREF_type (off_array_type (b)); unsigned na = DEREF_unsigned (off_array_arg (a)); unsigned nb = DEREF_unsigned (off_array_arg (b)); return (na == nb && eq_type_offset (ta, tb)); } case off_base_tag : { /* Base class offsets */ GRAPH ga = DEREF_graph (off_base_graph (a)); GRAPH gb = DEREF_graph (off_base_graph (b)); return (eq_graph (ga, gb)); } case off_deriv_tag : { /* Derived class offsets */ GRAPH ga = DEREF_graph (off_deriv_graph (a)); GRAPH gb = DEREF_graph (off_deriv_graph (b)); return (eq_graph (ga, gb)); } case off_member_tag : { /* Member offsets */ IDENTIFIER ia = DEREF_id (off_member_id (a)); IDENTIFIER ib = DEREF_id (off_member_id (b)); return (EQ_id (ia, ib)); } case off_ptr_mem_tag : { /* Pointer member offsets */ EXP xa = DEREF_exp (off_ptr_mem_arg (a)); EXP xb = DEREF_exp (off_ptr_mem_arg (b)); return (eq_exp (xa, xb, co)); } case off_negate_tag : { /* Offset negation */ OFFSET sa = DEREF_off (off_negate_arg (a)); OFFSET sb = DEREF_off (off_negate_arg (b)); return (eq_offset (sa, sb, co)); } case off_plus_tag : { /* Offset addition */ OFFSET sa = DEREF_off (off_plus_arg1 (a)); OFFSET sb = DEREF_off (off_plus_arg1 (b)); OFFSET ta = DEREF_off (off_plus_arg2 (a)); OFFSET tb = DEREF_off (off_plus_arg2 (b)); if (eq_offset (sa, sb, co) && eq_offset (ta, tb, co)) { return (1); } if (co && eq_offset (sa, tb, 1) && eq_offset (ta, sb, 1)) { return (1); } return (0); } case off_mult_tag : { /* Offset multiplication */ OFFSET sa = DEREF_off (off_mult_arg1 (a)); OFFSET sb = DEREF_off (off_mult_arg1 (b)); EXP za = DEREF_exp (off_mult_arg2 (a)); EXP zb = DEREF_exp (off_mult_arg2 (b)); return (eq_offset (sa, sb, co) && eq_exp (za, zb, co)); } case off_ptr_diff_tag : { /* Pointer difference */ EXP xa = DEREF_exp (off_ptr_diff_ptr1 (a)); EXP xb = DEREF_exp (off_ptr_diff_ptr1 (b)); EXP za = DEREF_exp (off_ptr_diff_ptr2 (a)); EXP zb = DEREF_exp (off_ptr_diff_ptr2 (b)); return (eq_exp (xa, xb, co) && eq_exp (za, zb, co)); } case off_token_tag : { /* Token application */ IDENTIFIER ia = DEREF_id (off_token_tok (a)); IDENTIFIER ib = DEREF_id (off_token_tok (b)); LIST (TOKEN) pa = DEREF_list (off_token_args (a)); LIST (TOKEN) pb = DEREF_list (off_token_args (b)); return (eq_token_args (ia, ib, pa, pb)); } } return (0); } /* * ARE TWO LISTS OF EXPRESSIONS EQUAL? * * This routine checks whether the expression lists p and q are equal, * in the sense that each of their components is equal. The co argument * is passed through to eq_exp. */ static int eq_exp_list(LIST (EXP) p, LIST (EXP) q, int co) { unsigned np = LENGTH_list (p); unsigned nq = LENGTH_list (q); if (np != nq) return (0); while (!IS_NULL_list (p)) { EXP a = DEREF_exp (HEAD_list (p)); EXP b = DEREF_exp (HEAD_list (q)); if (!eq_exp (a, b, co)) return (0); p = TAIL_list (p); q = TAIL_list (q); } return (1); } /* * CHECK EXPRESSION EQUALITY * * This is an auxiliary routine for eq_exp which checks whether the * expressions a and b, which have the same tag value, are equal. */ static int eq_exp_aux(EXP a, EXP b, int co) { /* Check expressions */ ASSERT (ORDER_exp == 88); switch (TAG_exp (a)) { case exp_identifier_tag : case exp_member_tag : case exp_ambiguous_tag : case exp_undeclared_tag : { /* Identifier expressions */ IDENTIFIER ia = DEREF_id (exp_identifier_etc_id (a)); IDENTIFIER ib = DEREF_id (exp_identifier_etc_id (b)); return (EQ_id (ia, ib)); } case exp_int_lit_tag : { /* Integer literal expressions */ TYPE ta = DEREF_type (exp_type (a)); TYPE tb = DEREF_type (exp_type (b)); NAT na = DEREF_nat (exp_int_lit_nat (a)); NAT nb = DEREF_nat (exp_int_lit_nat (b)); if (!eq_type (ta, tb)) return (0); if (EQ_nat (na, nb) || eq_nat (na, nb)) return (1); return (0); } case exp_float_lit_tag : { /* Floating literal expressions */ TYPE ta = DEREF_type (exp_type (a)); TYPE tb = DEREF_type (exp_type (b)); FLOAT fa = DEREF_flt (exp_float_lit_flt (a)); FLOAT fb = DEREF_flt (exp_float_lit_flt (b)); if (!eq_type (ta, tb)) return (0); if (EQ_flt (fa, fb)) return (1); return (eq_float_lit (fa, fb)); } case exp_char_lit_tag : { /* Character literal expressions */ TYPE ta = DEREF_type (exp_type (a)); TYPE tb = DEREF_type (exp_type (b)); STRING ca = DEREF_str (exp_char_lit_str (a)); STRING cb = DEREF_str (exp_char_lit_str (b)); if (!eq_type (ta, tb)) return (0); if (EQ_str (ca, cb)) return (1); return (eq_string_lit (ca, cb)); } case exp_string_lit_tag : { /* String literal expressions */ TYPE ta = DEREF_type (exp_type (a)); TYPE tb = DEREF_type (exp_type (b)); STRING ca = DEREF_str (exp_string_lit_str (a)); STRING cb = DEREF_str (exp_string_lit_str (b)); if (!eq_type (ta, tb)) return (0); if (EQ_str (ca, cb)) return (1); return (eq_string_lit (ca, cb)); } case exp_null_tag : case exp_zero_tag : case exp_value_tag : { /* Null expressions */ TYPE ta = DEREF_type (exp_type (a)); TYPE tb = DEREF_type (exp_type (b)); if (eq_type (ta, tb) == 1) return (1); return (0); } case exp_paren_tag : case exp_copy_tag : { /* Parenthesised expressions */ EXP sa = DEREF_exp (exp_paren_etc_arg (a)); EXP sb = DEREF_exp (exp_paren_etc_arg (b)); return (eq_exp (sa, sb, co)); } case exp_assign_tag : { /* Assignment expressions */ EXP ra = DEREF_exp (exp_assign_ref (a)); EXP rb = DEREF_exp (exp_assign_ref (b)); EXP sa = DEREF_exp (exp_assign_arg (a)); EXP sb = DEREF_exp (exp_assign_arg (b)); return (eq_exp (ra, rb, co) && eq_exp (sa, sb, co)); } case exp_init_tag : { /* Initialisation expressions */ IDENTIFIER ia = DEREF_id (exp_init_id (a)); IDENTIFIER ib = DEREF_id (exp_init_id (b)); EXP sa = DEREF_exp (exp_init_arg (a)); EXP sb = DEREF_exp (exp_init_arg (b)); return (EQ_id (ia, ib) && eq_exp (sa, sb, co)); } case exp_preinc_tag : { /* Pre-increment expressions */ EXP sa = DEREF_exp (exp_preinc_op (a)); EXP sb = DEREF_exp (exp_preinc_op (b)); return (eq_exp (sa, sb, co)); } case exp_postinc_tag : { /* Post-increment expressions */ EXP sa = DEREF_exp (exp_postinc_op (a)); EXP sb = DEREF_exp (exp_postinc_op (b)); return (eq_exp (sa, sb, co)); } case exp_indir_tag : { /* Indirection expressions */ EXP sa = DEREF_exp (exp_indir_ptr (a)); EXP sb = DEREF_exp (exp_indir_ptr (b)); return (eq_exp (sa, sb, co)); } case exp_contents_tag : { /* Contents expressions */ EXP sa = DEREF_exp (exp_contents_ptr (a)); EXP sb = DEREF_exp (exp_contents_ptr (b)); return (eq_exp (sa, sb, co)); } case exp_address_tag : { /* Address expressions */ EXP sa = DEREF_exp (exp_address_arg (a)); EXP sb = DEREF_exp (exp_address_arg (b)); return (eq_exp (sa, sb, co)); } case exp_address_mem_tag : { /* Address expressions */ EXP sa = DEREF_exp (exp_address_mem_arg (a)); EXP sb = DEREF_exp (exp_address_mem_arg (b)); return (eq_exp (sa, sb, co)); } case exp_func_tag : { /* Function expressions */ EXP sa = DEREF_exp (exp_func_fn (a)); EXP sb = DEREF_exp (exp_func_fn (b)); LIST (EXP) pa = DEREF_list (exp_func_args (a)); LIST (EXP) pb = DEREF_list (exp_func_args (b)); return (eq_exp (sa, sb, co) && eq_exp_list (pa, pb, co)); } case exp_func_id_tag : { /* Function expressions */ IDENTIFIER ia = DEREF_id (exp_func_id_id (a)); IDENTIFIER ib = DEREF_id (exp_func_id_id (b)); LIST (EXP) pa = DEREF_list (exp_func_id_args (a)); LIST (EXP) pb = DEREF_list (exp_func_id_args (b)); return (EQ_id (ia, ib) && eq_exp_list (pa, pb, co)); } case exp_call_tag : { /* Member function call expressions */ EXP ra = DEREF_exp (exp_call_ptr (a)); EXP rb = DEREF_exp (exp_call_ptr (b)); EXP sa = DEREF_exp (exp_call_arg (a)); EXP sb = DEREF_exp (exp_call_arg (b)); return (eq_exp (ra, rb, co) && eq_exp (sa, sb, co)); } case exp_negate_tag : case exp_compl_tag : case exp_not_tag : case exp_abs_tag : { /* Unary expressions */ EXP sa = DEREF_exp (exp_negate_etc_arg (a)); EXP sb = DEREF_exp (exp_negate_etc_arg (b)); return (eq_exp (sa, sb, co)); } case exp_plus_tag : case exp_mult_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_max_tag : case exp_min_tag : { /* Commutative binary expressions */ EXP ra = DEREF_exp (exp_plus_etc_arg1 (a)); EXP rb = DEREF_exp (exp_plus_etc_arg1 (b)); EXP sa = DEREF_exp (exp_plus_etc_arg2 (a)); EXP sb = DEREF_exp (exp_plus_etc_arg2 (b)); if (eq_exp (ra, rb, co) && eq_exp (sa, sb, co)) { return (1); } if (co && eq_exp (ra, sb, 1) && eq_exp (sa, rb, 1)) { return (1); } return (0); } case exp_minus_tag : case exp_div_tag : case exp_rem_tag : case exp_lshift_tag : case exp_rshift_tag : { /* Non-commutative binary expressions */ EXP ra = DEREF_exp (exp_plus_etc_arg1 (a)); EXP rb = DEREF_exp (exp_plus_etc_arg1 (b)); EXP sa = DEREF_exp (exp_plus_etc_arg2 (a)); EXP sb = DEREF_exp (exp_plus_etc_arg2 (b)); return (eq_exp (ra, rb, co) && eq_exp (sa, sb, co)); } case exp_test_tag : { /* Test expressions */ NTEST ca = DEREF_ntest (exp_test_tst (a)); NTEST cb = DEREF_ntest (exp_test_tst (b)); EXP sa = DEREF_exp (exp_test_arg (a)); EXP sb = DEREF_exp (exp_test_arg (b)); if (ca != cb) return (0); return (eq_exp (sa, sb, co)); } case exp_compare_tag : { /* Comparison expressions */ NTEST ca = DEREF_ntest (exp_compare_tst (a)); NTEST cb = DEREF_ntest (exp_compare_tst (b)); EXP ra = DEREF_exp (exp_compare_arg1 (a)); EXP rb = DEREF_exp (exp_compare_arg1 (b)); EXP sa = DEREF_exp (exp_compare_arg2 (a)); EXP sb = DEREF_exp (exp_compare_arg2 (b)); if (ca != cb) return (0); if (eq_exp (ra, rb, co) && eq_exp (sa, sb, co)) { return (1); } if (co && (ca == ntest_eq || ca == ntest_not_eq)) { /* Commutative comparisons */ if (eq_exp (ra, sb, 1) && eq_exp (sa, rb, 1)) { return (1); } } return (0); } case exp_cast_tag : { /* Cast expressions */ EXP sa = DEREF_exp (exp_cast_arg (a)); EXP sb = DEREF_exp (exp_cast_arg (b)); unsigned va = DEREF_unsigned (exp_cast_conv (a)); unsigned vb = DEREF_unsigned (exp_cast_conv (b)); return (va == vb && eq_exp (sa, sb, co)); } case exp_base_cast_tag : { /* Base cast expressions */ EXP ra = DEREF_exp (exp_base_cast_arg (a)); EXP rb = DEREF_exp (exp_base_cast_arg (b)); OFFSET za = DEREF_off (exp_base_cast_off (a)); OFFSET zb = DEREF_off (exp_base_cast_off (b)); unsigned va = DEREF_unsigned (exp_base_cast_conv (a)); unsigned vb = DEREF_unsigned (exp_base_cast_conv (b)); if (va != vb) return (0); return (eq_exp (ra, rb, co) && eq_offset (za, zb, co)); } case exp_dyn_cast_tag : { /* Dynamic cast expressions */ EXP sa = DEREF_exp (exp_dyn_cast_arg (a)); EXP sb = DEREF_exp (exp_dyn_cast_arg (b)); EXP ra = DEREF_exp (exp_dyn_cast_except (a)); EXP rb = DEREF_exp (exp_dyn_cast_except (b)); return (eq_exp (sa, sb, co) && eq_exp (ra, rb, co)); } case exp_add_ptr_tag : { /* Pointer addition expressions */ EXP ra = DEREF_exp (exp_add_ptr_ptr (a)); EXP rb = DEREF_exp (exp_add_ptr_ptr (b)); OFFSET za = DEREF_off (exp_add_ptr_off (a)); OFFSET zb = DEREF_off (exp_add_ptr_off (b)); return (eq_exp (ra, rb, co) && eq_offset (za, zb, co)); } case exp_offset_size_tag : { /* Offset size expressions */ OFFSET xa = DEREF_off (exp_offset_size_off (a)); OFFSET xb = DEREF_off (exp_offset_size_off (b)); TYPE sa = DEREF_type (exp_offset_size_step (a)); TYPE sb = DEREF_type (exp_offset_size_step (b)); return (eq_offset (xa, xb, co) && eq_type_offset (sa, sb)); } case exp_constr_tag : { /* Constructors */ EXP sa = DEREF_exp (exp_constr_call (a)); EXP sb = DEREF_exp (exp_constr_call (b)); return (eq_exp (sa, sb, co)); } case exp_destr_tag : { /* Destructors */ EXP sa = DEREF_exp (exp_destr_call (a)); EXP sb = DEREF_exp (exp_destr_call (b)); return (eq_exp (sa, sb, co)); } case exp_alloc_tag : { /* Allocators */ EXP sa = DEREF_exp (exp_alloc_call (a)); EXP sb = DEREF_exp (exp_alloc_call (b)); EXP ra = DEREF_exp (exp_alloc_init (a)); EXP rb = DEREF_exp (exp_alloc_init (b)); return (eq_exp (sa, sb, co) && eq_exp (ra, rb, co)); } case exp_dealloc_tag : { /* Deallocators */ EXP sa = DEREF_exp (exp_dealloc_call (a)); EXP sb = DEREF_exp (exp_dealloc_call (b)); EXP ra = DEREF_exp (exp_dealloc_term (a)); EXP rb = DEREF_exp (exp_dealloc_term (b)); return (eq_exp (sa, sb, co) && eq_exp (ra, rb, co)); } case exp_rtti_tag : { /* Run-time type information */ EXP sa = DEREF_exp (exp_rtti_arg (a)); EXP sb = DEREF_exp (exp_rtti_arg (b)); EXP ra = DEREF_exp (exp_rtti_except (a)); EXP rb = DEREF_exp (exp_rtti_except (b)); int ia = DEREF_int (exp_rtti_op (a)); int ib = DEREF_int (exp_rtti_op (b)); if (ia != ib) return (0); return (eq_exp (sa, sb, co) && eq_exp (ra, rb, co)); } case exp_rtti_type_tag : { /* Run-time type information */ TYPE sa = DEREF_type (exp_rtti_type_arg (a)); TYPE sb = DEREF_type (exp_rtti_type_arg (b)); int ia = DEREF_int (exp_rtti_type_op (a)); int ib = DEREF_int (exp_rtti_type_op (b)); if (ia != ib) return (0); if (eq_type (sa, sb) == 1) return (1); return (0); } case exp_rtti_no_tag : { /* Link-time type information */ TYPE sa = DEREF_type (exp_rtti_no_arg (a)); TYPE sb = DEREF_type (exp_rtti_no_arg (b)); if (eq_type (sa, sb) == 1) return (1); return (0); } case exp_dynamic_tag : { /* Dynamic initialisers */ EXP sa = DEREF_exp (exp_dynamic_arg (a)); EXP sb = DEREF_exp (exp_dynamic_arg (b)); return (eq_exp (sa, sb, co)); } case exp_aggregate_tag : { /* Aggregate initialisers */ LIST (EXP) pa = DEREF_list (exp_aggregate_args (a)); LIST (EXP) pb = DEREF_list (exp_aggregate_args (b)); return (eq_exp_list (pa, pb, co)); } case exp_initialiser_tag : { /* Function style initialisers */ LIST (EXP) pa = DEREF_list (exp_initialiser_args (a)); LIST (EXP) pb = DEREF_list (exp_initialiser_args (b)); return (eq_exp_list (pa, pb, co)); } case exp_nof_tag : { /* Array initialisers */ EXP ra = DEREF_exp (exp_nof_start (a)); EXP rb = DEREF_exp (exp_nof_start (b)); EXP sa = DEREF_exp (exp_nof_pad (a)); EXP sb = DEREF_exp (exp_nof_pad (b)); NAT na = DEREF_nat (exp_nof_size (a)); NAT nb = DEREF_nat (exp_nof_size (b)); EXP ua = DEREF_exp (exp_nof_end (a)); EXP ub = DEREF_exp (exp_nof_end (b)); if (!EQ_nat (na, nb)) { if (!eq_nat (na, nb)) return (0); } if (!eq_exp (sa, sb, co)) return (0); return (eq_exp (ra, rb, co) && eq_exp (ua, ub, co)); } case exp_comma_tag : { /* Comma expressions */ LIST (EXP) pa = DEREF_list (exp_comma_args (a)); LIST (EXP) pb = DEREF_list (exp_comma_args (b)); return (eq_exp_list (pa, pb, co)); } case exp_set_tag : case exp_unused_tag : { /* Flow analysis expressions */ EXP sa = DEREF_exp (exp_set_etc_arg (a)); EXP sb = DEREF_exp (exp_set_etc_arg (b)); return (eq_exp (sa, sb, co)); } case exp_if_stmt_tag : { /* Conditional expressions */ EXP ca = DEREF_exp (exp_if_stmt_cond (a)); EXP cb = DEREF_exp (exp_if_stmt_cond (b)); EXP ra = DEREF_exp (exp_if_stmt_true_code (a)); EXP rb = DEREF_exp (exp_if_stmt_true_code (b)); EXP sa = DEREF_exp (exp_if_stmt_false_code (a)); EXP sb = DEREF_exp (exp_if_stmt_false_code (b)); if (!eq_exp (ca, cb, co)) return (0); return (eq_exp (ra, rb, co) && eq_exp (sa, sb, co)); } case exp_exception_tag : { /* Throw expressions */ EXP sa = DEREF_exp (exp_exception_arg (a)); EXP sb = DEREF_exp (exp_exception_arg (b)); return (eq_exp (sa, sb, co)); } case exp_thrown_tag : { /* Thrown expressions */ TYPE ta = DEREF_type (exp_type (a)); TYPE tb = DEREF_type (exp_type (b)); if (eq_type (ta, tb) == 1) return (1); return (0); } case exp_op_tag : { /* Undetermined expressions */ int ca = DEREF_int (exp_op_lex (a)); int cb = DEREF_int (exp_op_lex (b)); EXP ra = DEREF_exp (exp_op_arg1 (a)); EXP rb = DEREF_exp (exp_op_arg1 (b)); EXP sa = DEREF_exp (exp_op_arg2 (a)); EXP sb = DEREF_exp (exp_op_arg2 (b)); if (ca != cb) return (0); return (eq_exp (ra, rb, co) && eq_exp (sa, sb, co)); } case exp_opn_tag : { /* Undetermined expressions */ int ca = DEREF_int (exp_opn_lex (a)); int cb = DEREF_int (exp_opn_lex (b)); LIST (EXP) pa = DEREF_list (exp_opn_args (a)); LIST (EXP) pb = DEREF_list (exp_opn_args (b)); if (ca != cb) return (0); return (eq_exp_list (pa, pb, co)); } case exp_assembler_tag : { /* Assembler expressions */ STRING ca = DEREF_str (exp_assembler_op (a)); STRING cb = DEREF_str (exp_assembler_op (b)); if (EQ_str (ca, cb) || eq_string_lit (ca, cb)) { LIST (EXP) pa = DEREF_list (exp_assembler_args (a)); LIST (EXP) pb = DEREF_list (exp_assembler_args (b)); return (eq_exp_list (pa, pb, co)); } break; } case exp_location_tag : { /* Location expressions */ EXP sa = DEREF_exp (exp_location_arg (a)); EXP sb = DEREF_exp (exp_location_arg (b)); return (eq_exp (sa, sb, co)); } case exp_token_tag : { /* Token application */ IDENTIFIER ia = DEREF_id (exp_token_tok (a)); IDENTIFIER ib = DEREF_id (exp_token_tok (b)); LIST (TOKEN) pa = DEREF_list (exp_token_args (a)); LIST (TOKEN) pb = DEREF_list (exp_token_args (b)); return (eq_token_args (ia, ib, pa, pb)); } case exp_dummy_tag : { /* Dummy expressions */ EXP sa = DEREF_exp (exp_dummy_value (a)); EXP sb = DEREF_exp (exp_dummy_value (b)); return (eq_exp (sa, sb, co)); } case exp_reach_tag : case exp_unreach_tag : case exp_sequence_tag : case exp_solve_stmt_tag : case exp_decl_stmt_tag : case exp_while_stmt_tag : case exp_do_stmt_tag : case exp_switch_stmt_tag : case exp_hash_if_tag : case exp_return_stmt_tag : case exp_goto_stmt_tag : case exp_label_stmt_tag : case exp_try_block_tag : case exp_handler_tag : case exp_uncompiled_tag : case exp_fail_tag : { /* Statements are never equal */ return (0); } } return (0); } /* * UNIFY TWO EXPRESSIONS * * This routine unifies the expressions a and b by defining tokens as * necessary. It returns true if a value is assigned to a token. Note * that it is necessary to consider integer constant tokens as well as * expression tokens. */ static int unify_exp(EXP a, EXP b) { IDENTIFIER id; LIST (TOKEN) args; switch (TAG_exp (a)) { case exp_token_tag : { id = DEREF_id (exp_token_tok (a)); args = DEREF_list (exp_token_args (a)); break; } case exp_int_lit_tag : { NAT n = DEREF_nat (exp_int_lit_nat (a)); if (!IS_nat_token (n)) return (0); id = DEREF_id (nat_token_tok (n)); args = DEREF_list (nat_token_args (n)); break; } default : { return (0); } } if (IS_NULL_list (args) && defining_token (id)) { return (define_exp_token (id, b, 1)); } return (0); } /* * ARE TWO EXPRESSIONS EQUAL? * * This routine checks whether the expressions a and b are equal. If * co is true then commutativity and other such relations are taken * into account. */ int eq_exp(EXP a, EXP b, int co) { /* Check for obvious equality */ unsigned ta, tb; if (EQ_exp (a, b)) return (1); if (IS_NULL_exp (a)) return (0); if (IS_NULL_exp (b)) return (0); /* Allow for parentheses */ ta = TAG_exp (a); while (ta == exp_paren_tag || ta == exp_copy_tag) { a = DEREF_exp (exp_paren_etc_arg (a)); ta = TAG_exp (a); } tb = TAG_exp (b); while (tb == exp_paren_tag || tb == exp_copy_tag) { b = DEREF_exp (exp_paren_etc_arg (b)); tb = TAG_exp (b); } /* Check equality of expressions */ if (ta == tb && eq_exp_aux (a, b, co)) return (1); if (force_tokdef || force_template || expand_tokdef) { TYPE sa = DEREF_type (exp_type (a)); TYPE sb = DEREF_type (exp_type (b)); if (eq_type (sa, sb) == 1) { if (unify_exp (a, b)) return (1); if (unify_exp (b, a)) return (1); } } return (0); } /* * ARE TWO EXPRESSIONS PRECISELY EQUAL? * * This routine is similar to eq_exp, but it disallows token and template * unification and does not allow for commutativity relations. */ int eq_exp_exact(EXP a, EXP b) { int eq; int tok = force_tokdef; int templ = force_template; force_tokdef = 0; force_template = 0; eq = eq_exp (a, b, 0); force_template = templ; force_tokdef = tok; return (eq); } /* * ARE TWO TOKENS EQUAL? * * This routine checks whether the tokens a and b are equal. */ int eq_token(TOKEN a, TOKEN b) { unsigned na, nb; if (EQ_tok (a, b)) return (1); if (IS_NULL_tok (a)) return (0); if (IS_NULL_tok (b)) return (0); na = TAG_tok (a); nb = TAG_tok (b); if (na != nb) return (0); switch (na) { case tok_exp_tag : { EXP va = DEREF_exp (tok_exp_value (a)); EXP vb = DEREF_exp (tok_exp_value (b)); return (eq_exp (va, vb, 0)); } case tok_stmt_tag : { EXP va = DEREF_exp (tok_stmt_value (a)); EXP vb = DEREF_exp (tok_stmt_value (b)); return (eq_exp (va, vb, 0)); } case tok_nat_tag : case tok_snat_tag : { NAT va = DEREF_nat (tok_nat_etc_value (a)); NAT vb = DEREF_nat (tok_nat_etc_value (b)); if (compare_nat (va, vb) == 0) return (1); break; } case tok_type_tag : { TYPE va = DEREF_type (tok_type_value (a)); TYPE vb = DEREF_type (tok_type_value (b)); if (eq_type (va, vb) == 1) return (1); return (0); } case tok_member_tag : { OFFSET va = DEREF_off (tok_member_value (a)); OFFSET vb = DEREF_off (tok_member_value (b)); return (eq_offset (va, vb, 0)); } case tok_class_tag : { IDENTIFIER ia = DEREF_id (tok_class_value (a)); IDENTIFIER ib = DEREF_id (tok_class_value (b)); return (EQ_id (ia, ib)); } } return (0); } /* * ARE TWO TOKEN APPLICATIONS EQUAL? * * This routine checks whether the token applications ia (pa) and * ib (pb) are equal. */ int eq_token_args(IDENTIFIER ia, IDENTIFIER ib, LIST (TOKEN) pa, LIST (TOKEN) pb) { if (!EQ_id (ia, ib)) { /* Check that tokens are the same */ ia = DEREF_id (id_alias (ia)); ib = DEREF_id (id_alias (ib)); if (!EQ_id (ia, ib)) { if (!force_merge || !merge_type (ia, ib)) { return (0); } } } if (EQ_list (pa, pb)) return (1); if (LENGTH_list (pa) != LENGTH_list (pb)) return (0); while (!IS_NULL_list (pa)) { TOKEN a, b; if (EQ_list (pa, pb)) return (1); a = DEREF_tok (HEAD_list (pa)); b = DEREF_tok (HEAD_list (pb)); if (!eq_token (a, b)) return (0); pb = TAIL_list (pb); pa = TAIL_list (pa); } return (1); } /* * IS A TOKEN APPLICATION A CONSTANT? * * This routine checks whether the token id applied to the arguments args * is a constant. */ static int is_const_token(IDENTIFIER id, LIST (TOKEN) args, int c) { TOKEN tok = DEREF_tok (id_token_sort (id)); if (IS_tok_proc (tok)) { /* Allow for procedure tokens */ tok = DEREF_tok (tok_proc_res (tok)); } switch (TAG_tok (tok)) { case tok_exp_tag : { /* Check for constant expression tokens */ int cn = DEREF_int (tok_exp_constant (tok)); if (cn) { /* Constant token */ return (1); } if (c >= 0) { /* Constant expression expected */ report (crt_loc, ERR_token_const (id)); } if (option (OPT_token_const) == OPTION_DISALLOW) { /* Non-constant tokens not allowed */ return (0); } break; } case tok_nat_tag : { /* Integer constants */ return (1); } case tok_stmt_tag : { /* Statements are not constant */ return (0); } } /* Check all token arguments */ while (!IS_NULL_list (args)) { TOKEN a = DEREF_tok (HEAD_list (args)); if (!IS_NULL_tok (a)) { switch (TAG_tok (a)) { case tok_exp_tag : { EXP e = DEREF_exp (tok_exp_value (a)); if (!is_const_exp (e, c)) return (0); break; } case tok_stmt_tag : { EXP e = DEREF_exp (tok_stmt_value (a)); if (!is_const_exp (e, c)) return (0); break; } case tok_member_tag : { OFFSET off = DEREF_off (tok_member_value (a)); if (!is_const_offset (off, c, 1)) return (0); break; } } } args = TAIL_list (args); } return (1); } /* * IS AN OFFSET A CONSTANT? * * This routine checks whether the offset off is a constant offset. virt * is true if virtual base classes are to be taken into account. */ int is_const_offset(OFFSET off, int c, int virt) { ASSERT (ORDER_off == 13); switch (TAG_off (off)) { case off_zero_tag : case off_type_tag : case off_extra_tag : case off_array_tag : case off_member_tag : { /* Constant offsets */ return (1); } case off_base_tag : { /* Base class offsets */ if (virt) { GRAPH gr = DEREF_graph (off_base_graph (off)); DECL_SPEC acc = DEREF_dspec (graph_access (gr)); if (!(acc & dspec_mutable)) return (1); } else { return (1); } break; } case off_deriv_tag : { /* Derived class offsets */ if (virt) { GRAPH gr = DEREF_graph (off_deriv_graph (off)); DECL_SPEC acc = DEREF_dspec (graph_access (gr)); if (!(acc & dspec_mutable)) return (1); } else { return (1); } break; } case off_ptr_mem_tag : { /* Pointer member offsets */ EXP a = DEREF_exp (off_ptr_mem_arg (off)); return (is_const_exp (a, c)); } case off_negate_tag : { /* Offset negation */ OFFSET off1 = DEREF_off (off_negate_arg (off)); return (is_const_offset (off1, c, 1)); } case off_plus_tag : { /* Offset addition */ OFFSET off1 = DEREF_off (off_plus_arg1 (off)); OFFSET off2 = DEREF_off (off_plus_arg2 (off)); if (!is_const_offset (off1, c, 1)) return (0); return (is_const_offset (off2, c, 1)); } case off_mult_tag : { /* Offset multiplication */ OFFSET off1 = DEREF_off (off_mult_arg1 (off)); EXP a = DEREF_exp (off_mult_arg2 (off)); if (!is_const_offset (off1, c, 1)) return (0); return (is_const_exp (a, c)); } case off_ptr_diff_tag : { /* Pointer difference */ EXP a = DEREF_exp (off_ptr_diff_ptr1 (off)); EXP b = DEREF_exp (off_ptr_diff_ptr2 (off)); if (is_const_exp (a, c) && is_const_exp (b, c)) { /* Only allow pointers from same array */ EXP pa = NULL_exp; EXP pb = NULL_exp; IGNORE find_exp_linkage (a, &pa, 1); IGNORE find_exp_linkage (b, &pb, 1); if (!IS_NULL_exp (pa) && !IS_exp_string_lit (pa)) { return (eq_exp (pa, pb, 0)); } } break; } case off_token_tag : { /* All member tokens are constant */ IDENTIFIER id = DEREF_id (off_token_tok (off)); LIST (TOKEN) args = DEREF_list (off_token_args (off)); return (is_const_token (id, args, c)); } } return (0); } /* * IS AN EXPRESSION AN ADDRESS CONSTANT? * * This routine checks whether the address of e is a constant expression. * c will be nonzero. */ static int is_const_addr(EXP e, int c) { if (IS_NULL_exp (e)) return (1); switch (TAG_exp (e)) { case exp_identifier_tag : { /* Identifier expressions */ IDENTIFIER id = DEREF_id (exp_identifier_id (e)); DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (!(ds & dspec_auto)) { TYPE t = DEREF_type (exp_type (e)); if (!IS_type_ref (t)) return (1); } break; } case exp_indir_tag : { /* Indirection expressions */ EXP a = DEREF_exp (exp_indir_ptr (e)); return (is_const_exp (a, c)); } case exp_member_tag : case exp_string_lit_tag : case exp_rtti_type_tag : { /* lvalue expressions */ return (1); } case exp_token_tag : { /* Tokenised expressions */ return (is_const_exp (e, c)); } case exp_comma_tag : { /* Comma expressions (not allowed) */ if (c < 0) { LIST (EXP) p = DEREF_list (exp_comma_args (e)); while (!IS_NULL_list (p)) { EXP a = DEREF_exp (HEAD_list (p)); p = TAIL_list (p); if (IS_NULL_list (p)) { return (is_const_addr (a, c)); } if (!is_const_exp (a, c)) break; } } break; } case exp_if_stmt_tag : { /* Conditional expressions */ EXP d = 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)); if (!is_const_exp (d, c)) break; if (!is_const_addr (a, c)) break; return (is_const_addr (b, c)); } } return (0); } /* * IS AN EXPRESSION CONSTANT? * * This routine checks whether e is a constant expression. Note that * most integer constant expressions are dealt with in a bottom-up * fashion by means of the constant evaluation routines. Other * constants are dealt with in a top-down fashion by this routine. If * c is 0 then only valid integer constant expressions are allowed; c * is -1 then only a check is intended. */ int is_const_exp(EXP e, int c) { TYPE t; if (IS_NULL_exp (e)) return (1); ASSERT (ORDER_exp == 88); switch (TAG_exp (e)) { case exp_int_lit_tag : case exp_char_lit_tag : { /* Integer literals */ return (1); } case exp_identifier_tag : { /* Identifiers */ if (c) { IDENTIFIER id = DEREF_id (exp_identifier_id (e)); DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (!(ds & dspec_auto)) { t = DEREF_type (exp_type (e)); if (!IS_type_ref (t)) return (1); } } break; } case exp_string_lit_tag : case exp_float_lit_tag : case exp_null_tag : case exp_zero_tag : case exp_value_tag : case exp_rtti_type_tag : case exp_rtti_no_tag : case exp_set_tag : case exp_unused_tag : { /* Floating literals, null pointers etc. */ if (c) return (1); break; } case exp_paren_tag : case exp_copy_tag : { /* Parenthesised expressions */ EXP a = DEREF_exp (exp_paren_etc_arg (e)); return (is_const_exp (a, c)); } case exp_indir_tag : { /* Indirection expressions */ if (c) { EXP a = DEREF_exp (exp_indir_ptr (e)); return (is_const_exp (a, c)); } break; } case exp_address_tag : { /* Address expressions */ if (c) { EXP a = DEREF_exp (exp_address_arg (e)); return (is_const_addr (a, c)); } break; } case exp_address_mem_tag : { /* Address expressions */ if (c) { EXP a = DEREF_exp (exp_address_mem_arg (e)); if (IS_exp_member (a)) return (1); } break; } case exp_negate_tag : case exp_compl_tag : case exp_not_tag : case exp_abs_tag : { /* Unary expressions */ EXP a = DEREF_exp (exp_negate_etc_arg (e)); return (is_const_exp (a, c)); } case exp_plus_tag : case exp_minus_tag : case exp_mult_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 expressions */ EXP a = DEREF_exp (exp_plus_etc_arg1 (e)); EXP b = DEREF_exp (exp_plus_etc_arg2 (e)); return (is_const_exp (a, c) && is_const_exp (b, c)); } case exp_div_tag : case exp_rem_tag : { /* Division expressions */ EXP a = DEREF_exp (exp_plus_etc_arg1 (e)); EXP b = DEREF_exp (exp_plus_etc_arg2 (e)); if (c == 0 && is_zero_exp (b)) { /* Division by zero doesn't count */ break; } return (is_const_exp (a, c) && is_const_exp (b, c)); } case exp_test_tag : { /* Test expressions */ EXP a = DEREF_exp (exp_test_arg (e)); return (is_const_exp (a, c)); } case exp_compare_tag : { /* Comparison expressions */ EXP a = DEREF_exp (exp_compare_arg1 (e)); EXP b = DEREF_exp (exp_compare_arg2 (e)); return (is_const_exp (a, c) && is_const_exp (b, c)); } case exp_cast_tag : { /* Cast expressions */ EXP a = DEREF_exp (exp_cast_arg (e)); if (!c) { unsigned tc; t = DEREF_type (exp_type (a)); tc = type_category (&t); if (!IS_TYPE_INT (tc)) break; } return (is_const_exp (a, c)); } case exp_base_cast_tag : { /* Base cast expressions */ if (c) { EXP a = DEREF_exp (exp_base_cast_arg (e)); OFFSET off = DEREF_off (exp_base_cast_off (e)); unsigned conv = DEREF_unsigned (exp_base_cast_conv (e)); if (conv & CONV_PTR_MEM_BASE) { /* Pointer to member conversions */ if (conv & CONV_REVERSE) return (0); } else { /* Pointer conversions */ if (!is_zero_offset (off)) return (0); } return (is_const_exp (a, c)); } break; } case exp_add_ptr_tag : { /* Pointer addition */ if (c) { t = DEREF_type (exp_type (e)); if (!IS_type_ref (t)) { EXP a = DEREF_exp (exp_add_ptr_ptr (e)); OFFSET b = DEREF_off (exp_add_ptr_off (e)); int v = DEREF_int (exp_add_ptr_virt (e)); if (!is_const_exp (a, c)) return (0); return (is_const_offset (b, c, v)); } } break; } case exp_offset_size_tag : { /* Offset size */ OFFSET a = DEREF_off (exp_offset_size_off (e)); if (IS_off_type (a)) { /* Allow for sizeof expressions */ TYPE s = DEREF_type (exp_offset_size_step (e)); if (EQ_type (s, type_char)) return (1); } if (c) return (is_const_offset (a, c, c)); break; } case exp_aggregate_tag : { /* Aggregate initialisers */ if (c) { LIST (EXP) p = DEREF_list (exp_aggregate_args (e)); while (!IS_NULL_list (p)) { EXP a = DEREF_exp (HEAD_list (p)); if (!is_const_exp (a, c)) return (0); p = TAIL_list (p); } return (1); } break; } case exp_nof_tag : { /* Array initialisers */ if (c) { EXP a = DEREF_exp (exp_nof_start (e)); EXP b = DEREF_exp (exp_nof_pad (e)); EXP d = DEREF_exp (exp_nof_end (e)); if (!is_const_exp (a, c)) return (0); if (!is_const_exp (b, c)) return (0); return (is_const_exp (d, c)); } break; } case exp_comma_tag : { /* Comma expressions (not allowed) */ if (c < 0) { LIST (EXP) p = DEREF_list (exp_comma_args (e)); while (!IS_NULL_list (p)) { EXP a = DEREF_exp (HEAD_list (p)); if (!is_const_exp (a, c)) return (0); p = TAIL_list (p); } return (1); } break; } case exp_if_stmt_tag : { /* Conditional expressions */ if (c) { EXP d = 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)); if (!is_const_exp (d, c)) break; if (!is_const_exp (a, c)) break; return (is_const_exp (b, c)); } break; } case exp_op_tag : { /* Undetermined expressions */ EXP a = DEREF_exp (exp_op_arg1 (e)); EXP b = DEREF_exp (exp_op_arg2 (e)); return (is_const_exp (a, c) && is_const_exp (b, c)); } case exp_opn_tag : { /* Undetermined nary expressions */ LIST (EXP) p = DEREF_list (exp_opn_args (e)); while (!IS_NULL_list (p)) { EXP a = DEREF_exp (HEAD_list (p)); if (!is_const_exp (a, c)) return (0); p = TAIL_list (p); } return (1); } case exp_token_tag : { /* Tokenised expressions (C compatibility) */ IDENTIFIER id = DEREF_id (exp_token_tok (e)); LIST (TOKEN) args = DEREF_list (exp_token_args (e)); if (!c) { unsigned tc; t = DEREF_type (exp_type (e)); tc = type_category (&t); if (!IS_TYPE_INT (tc)) break; } return (is_const_token (id, args, c)); } case exp_location_tag : { /* Location expressions */ EXP a = DEREF_exp (exp_location_arg (e)); return (is_const_exp (a, c)); } case exp_dummy_tag : { /* Dummy expressions */ EXP a = DEREF_exp (exp_dummy_value (e)); return (is_const_exp (a, c)); } } /* Allow for errors */ t = DEREF_type (exp_type (e)); if (IS_type_error (t)) return (1); return (0); } /* * DOES AN EXPRESSION CONTAIN AN OVERFLOW? * * Certain evaluations on integer constant expressions are only valid * if it can be shown that the operands cannot raise an exception. * For example, 'a - a' can only safely be replaced by zero if the * evaluation of a does not overflow. This routine returns true if * the evaluation of the expression a may raise an overflow exception * or contains some other side effect. */ int overflow_exp(EXP a) { if (IS_NULL_exp (a)) return (0); switch (TAG_exp (a)) { case exp_int_lit_tag : { /* Check integer constant expressions */ NAT n = DEREF_nat (exp_int_lit_nat (a)); unsigned etag = DEREF_unsigned (exp_int_lit_etag (a)); switch (etag) { case exp_char_lit_tag : case exp_offset_size_tag : { /* These never overflow */ return (0); } } return (is_calc_nat (n)); } case exp_identifier_tag : case exp_member_tag : case exp_char_lit_tag : case exp_value_tag : case exp_null_tag : case exp_zero_tag : { return (0); } case exp_string_lit_tag : { /* String literals deliberately excluded */ return (1); } case exp_paren_tag : case exp_copy_tag : { EXP b = DEREF_exp (exp_paren_etc_arg (a)); return (overflow_exp (b)); } case exp_address_tag : { EXP b = DEREF_exp (exp_address_arg (a)); return (overflow_exp (b)); } case exp_address_mem_tag : { EXP b = DEREF_exp (exp_address_mem_arg (a)); return (overflow_exp (b)); } case exp_cast_tag : { /* Cast expressions */ unsigned c = DEREF_unsigned (exp_cast_conv (a)); if (c == CONV_ELLIPSIS) { EXP b = DEREF_exp (exp_cast_arg (a)); return (overflow_exp (b)); } break; } case exp_comma_tag : { LIST (EXP) p = DEREF_list (exp_comma_args (a)); while (!IS_NULL_list (p)) { EXP b = DEREF_exp (HEAD_list (p)); if (overflow_exp (b)) return (1); p = TAIL_list (p); } return (0); } case exp_aggregate_tag : { LIST (EXP) p = DEREF_list (exp_aggregate_args (a)); while (!IS_NULL_list (p)) { EXP b = DEREF_exp (HEAD_list (p)); if (overflow_exp (b)) return (1); p = TAIL_list (p); } return (0); } case exp_nof_tag : { EXP b = DEREF_exp (exp_nof_start (a)); EXP c = DEREF_exp (exp_nof_pad (a)); EXP d = DEREF_exp (exp_nof_end (a)); NAT n = DEREF_nat (exp_nof_size (a)); if (overflow_exp (b)) return (1); if (overflow_exp (c)) return (1); if (overflow_exp (d)) return (1); return (is_calc_nat (n)); } } return (1); } /* * FIND THE LINKAGE OF AN EXPRESSION * * This routine checks the linkage of the expression a. If vol is true * then the result is or-ed with dspec_implicit if a is derived from * an implicitly volatile external identifier and or-ed with dspec_pure * if a is derived from an implicitly const string literal. The * component of a which determines the linkage is returned via pa. */ DECL_SPEC find_exp_linkage(EXP e, EXP *pa, int vol) { if (!IS_NULL_exp (e)) { ASSERT (ORDER_exp == 88); switch (TAG_exp (e)) { case exp_identifier_tag : case exp_member_tag : { /* Identifier expressions */ IDENTIFIER id = DEREF_id (exp_identifier_etc_id (e)); DECL_SPEC ds = DEREF_dspec (id_storage (id)); ds &= (dspec_storage | dspec_temp); if (vol && IS_id_variable_etc (id)) { TYPE t = DEREF_type (id_variable_etc_type (id)); CV_SPEC cv = find_cv_qual (t); if (!(cv & cv_volatile)) ds |= dspec_implicit; } *pa = e; return (ds); } case exp_string_lit_tag : { /* String literals have internal linkage */ *pa = e; return (dspec_static | dspec_pure); } case exp_paren_tag : case exp_copy_tag : { /* Parenthesised expressions */ EXP a = DEREF_exp (exp_paren_etc_arg (e)); return (find_exp_linkage (a, pa, vol)); } case exp_indir_tag : { /* Indirection expressions */ EXP a = DEREF_exp (exp_indir_ptr (e)); return (find_exp_linkage (a, pa, vol)); } case exp_address_tag : { /* Address expressions */ EXP a = DEREF_exp (exp_address_arg (e)); return (find_exp_linkage (a, pa, vol)); } case exp_address_mem_tag : { /* Address expressions */ EXP a = DEREF_exp (exp_address_mem_arg (e)); if (IS_exp_member (a)) { return (find_exp_linkage (a, pa, vol)); } break; } case exp_cast_tag : { /* Cast expressions */ EXP a = DEREF_exp (exp_cast_arg (e)); DECL_SPEC ds = find_exp_linkage (a, pa, vol); ds &= ~(dspec_implicit | dspec_pure); return (ds); } case exp_add_ptr_tag : { /* Pointer offset expressions */ EXP a = DEREF_exp (exp_add_ptr_ptr (e)); DECL_SPEC ds = find_exp_linkage (a, pa, vol); OFFSET off = DEREF_off (exp_add_ptr_off (e)); if (vol) { /* Check for volatile members */ while (IS_off_plus (off)) { off = DEREF_off (off_plus_arg2 (off)); } if (IS_off_member (off)) { TYPE t; CV_SPEC cv; IDENTIFIER id; id = DEREF_id (off_member_id (off)); t = DEREF_type (id_member_type (id)); cv = find_cv_qual (t); if (cv & cv_volatile) ds &= ~dspec_implicit; } } else { /* Only base class conversions allowed */ if (!IS_off_base (off) && !IS_off_deriv (off)) { ds = dspec_none; } } return (ds); } case exp_base_cast_tag : { /* Base cast expressions */ EXP a = DEREF_exp (exp_base_cast_arg (e)); return (find_exp_linkage (a, pa, vol)); } case exp_location_tag : { /* Location expressions */ EXP a = DEREF_exp (exp_location_arg (e)); return (find_exp_linkage (a, pa, vol)); } case exp_int_lit_tag : case exp_char_lit_tag : case exp_null_tag : case exp_zero_tag : case exp_value_tag : case exp_token_tag : { /* These count as external linkage */ *pa = e; return (dspec_extern); } } } return (dspec_none); } /* * IS AN OFFSET ZERO? * * This routine checks whether the offset off is zero. The only * non-trivial case is for base class offsets where the single * inheritance (zero offset) cases are marked using dspec_ignore. */ int is_zero_offset(OFFSET off) { if (IS_NULL_off (off)) return (1); ASSERT (ORDER_off == 13); switch (TAG_off (off)) { case off_zero_tag : { /* Zero offsets */ return (1); } case off_array_tag : { /* Array offsets */ unsigned n = DEREF_unsigned (off_array_arg (off)); if (n == 0) return (1); break; } case off_base_tag : { /* Base class offsets */ GRAPH gr = DEREF_graph (off_base_graph (off)); DECL_SPEC acc = DEREF_dspec (graph_access (gr)); if (acc & dspec_ignore) return (1); break; } case off_deriv_tag : { /* Derived class offsets */ GRAPH gr = DEREF_graph (off_deriv_graph (off)); DECL_SPEC acc = DEREF_dspec (graph_access (gr)); if (acc & dspec_ignore) return (1); break; } case off_negate_tag : { /* Offset negations */ OFFSET a = DEREF_off (off_negate_arg (off)); return (is_zero_offset (a)); } case off_plus_tag : { /* Offset additions */ OFFSET a = DEREF_off (off_plus_arg1 (off)); OFFSET b = DEREF_off (off_plus_arg2 (off)); return (is_zero_offset (a) && is_zero_offset (b)); } case off_mult_tag : { /* Offset multiplications */ OFFSET a = DEREF_off (off_mult_arg1 (off)); return (is_zero_offset (a)); } } return (0); } /* * IS THE TYPE OF AN OFFSET STATICALLY DETERMINED? * * This routine checks whether the type of a pointer plus the offset off * can be statically determined. It returns 2 if the type is known * independent of the value of the pointer, 1 if it is known if the * type of the pointer is known, and 0 otherwise. */ static int know_offset(OFFSET off) { if (!IS_NULL_off (off)) { switch (TAG_off (off)) { case off_base_tag : case off_deriv_tag : case off_ptr_mem_tag : { /* Base class offsets */ return (0); } case off_member_tag : { /* Member offsets */ return (2); } case off_plus_tag : { /* Check for derived member offsets */ off = DEREF_off (off_plus_arg2 (off)); if (IS_off_member (off)) return (2); break; } } } return (1); } /* * IS THE TYPE OF AN EXPRESSION STATICALLY DETERMINED? * * This routine checks whether the expression of class type or pointer to * class type, e, is derived from an object so that its type can be * statically determined. It is used to check whether the virtual call * mechanism and virtual base class conversions can be bypassed for e. * A value of 2 is returned for non-obvious known types. */ int know_type(EXP e) { if (!IS_NULL_exp (e)) { unsigned tag = TAG_exp (e); switch (tag) { case exp_address_tag : { EXP a = DEREF_exp (exp_address_arg (e)); tag = TAG_exp (a); if (tag == exp_identifier_tag) { return (1); } if (tag == exp_indir_tag) { EXP b = DEREF_exp (exp_indir_ptr (a)); return (know_type (b)); } if (tag == exp_dummy_tag) { EXP b = DEREF_exp (exp_dummy_value (a)); if (IS_NULL_exp (b)) { int v = DEREF_int (exp_dummy_virt (a)); if (!v) return (1); } } break; } case exp_indir_tag : { EXP a = DEREF_exp (exp_indir_ptr (e)); return (know_type (a)); } case exp_add_ptr_tag : { OFFSET off = DEREF_off (exp_add_ptr_off (e)); int k = know_offset (off); if (k == 2) { return (1); } if (k == 1) { EXP a = DEREF_exp (exp_add_ptr_ptr (e)); return (know_type (a)); } break; } case exp_contents_tag : { e = DEREF_exp (exp_contents_ptr (e)); if (IS_exp_identifier (e)) goto identifier_lab; break; } case exp_identifier_tag : identifier_lab : { IDENTIFIER id = DEREF_id (exp_identifier_id (e)); HASHID nm = DEREF_hashid (id_name (id)); if (EQ_KEYWORD (nm, lex_this_Hname)) { /* A 'this' expression */ NAMESPACE ns = DEREF_nspace (id_parent (id)); id = DEREF_id (nspace_name (ns)); nm = DEREF_hashid (id_name (id)); if (IS_hashid_constr (nm)) { /* Function is a constructor */ return (2); } if (IS_hashid_destr (nm)) { /* Function is a destructor */ return (2); } } break; } } } return (0); }