/* * 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/operator.c,v 1.8 2004/08/15 11:13:35 bp Exp $ */ #include "config.h" #include "producer.h" #include "msgcat.h" #include "c_types.h" #include "ctype_ops.h" #include "etype_ops.h" #include "exp_ops.h" #include "hashid_ops.h" #include "id_ops.h" #include "member_ops.h" #include "nat_ops.h" #include "type_ops.h" #include "error.h" #include "catalog.h" #include "allocate.h" #include "assign.h" #include "basetype.h" #include "cast.h" #include "chktype.h" #include "class.h" #include "constant.h" #include "construct.h" #include "convert.h" #include "copy.h" #include "derive.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 "inttype.h" #include "member.h" #include "namespace.h" #include "operator.h" #include "overload.h" #include "quality.h" #include "statement.h" #include "syntax.h" #include "template.h" #include "typeid.h" /* * FIND AN EXPRESSION RELATION * * This routine returns the lexical token number of associated with * the test ntst. The default value returned is lex. */ int ntest_token(NTEST ntst, int lex) { switch (ntst) { case ntest_eq : lex = lex_eq ; break; case ntest_not_eq : lex = lex_not_Heq_H1 ; break; case ntest_less : lex = lex_less ; break; case ntest_less_eq : lex = lex_less_Heq ; break; case ntest_greater : lex = lex_greater ; break; case ntest_greater_eq : lex = lex_greater_Heq ; break; } return (lex); } /* * FIND THE TOKEN NUMBER FOR AN OPERATION * * This routine returns the lexical token number associated with the * expression e. The default value returned is lex. */ int op_token(EXP e, int lex) { if (!IS_NULL_exp (e)) { switch (TAG_exp (e)) { case exp_negate_tag : lex = lex_minus ; break; case exp_compl_tag : lex = lex_compl_H1 ; break; case exp_not_tag : lex = lex_not_H1 ; break; case exp_abs_tag : lex = lex_abs ; break; case exp_plus_tag : lex = lex_plus ; break; case exp_minus_tag : lex = lex_minus ; break; case exp_mult_tag : lex = lex_star ; break; case exp_div_tag : lex = lex_div ; break; case exp_rem_tag : lex = lex_rem ; break; case exp_and_tag : lex = lex_and_H1 ; break; case exp_or_tag : lex = lex_or_H1 ; break; case exp_xor_tag : lex = lex_xor_H1 ; break; case exp_log_and_tag : lex = lex_logical_Hand_H1 ; break; case exp_log_or_tag : lex = lex_logical_Hor_H1 ; break; case exp_lshift_tag : lex = lex_lshift ; break; case exp_rshift_tag : lex = lex_rshift ; break; case exp_max_tag : lex = lex_max ; break; case exp_min_tag : lex = lex_min ; break; case exp_test_tag : { NTEST ntst = DEREF_ntest (exp_test_tst (e)); lex = ntest_token (ntst, lex); break; } case exp_compare_tag : { NTEST ntst = DEREF_ntest (exp_compare_tst (e)); lex = ntest_token (ntst, lex); break; } case exp_paren_tag : { EXP a = DEREF_exp (exp_paren_arg (e)); lex = op_token (a, lex); break; } case exp_copy_tag : { EXP a = DEREF_exp (exp_copy_arg (e)); lex = op_token (a, lex); break; } } } return (lex); } /* * APPLY A UNARY OPERATOR * * This routine applies the unary operator op to the argument a. The * type t2 gives the destination for any cast operator. */ EXP apply_unary(int op, EXP a, TYPE t1, TYPE t2, int cpy) { EXP e; if (cpy) { /* Copy argument if necessary */ switch (op) { case lex_function : { a = copy_func_exp (a, t1, t2); break; } case lex_sizeof : case lex_alignof : case lex_typeid : case lex_vtable : { suppress_usage++; a = copy_exp (a, t1, t2); suppress_usage--; break; } default : { a = copy_exp (a, t1, t2); break; } } } suppress_quality++; switch (op) { case lex_and_H1 : { /* Construct '&a' */ e = make_ref_exp (a, 0); break; } case lex_abs : case lex_plus : case lex_minus : case lex_compl_H1 : { /* Construct '+a', '-a', '~a' and 'abs a' */ e = make_uminus_exp (op, a); break; } case lex_not_H1 : { /* Construct '!a' */ e = make_not_exp (a); break; } case lex_plus_Hplus : case lex_minus_Hminus : { /* Construct '++a' and '--a' */ e = make_prefix_exp (op, a); break; } case lex_star : { /* Construct '*a' */ e = make_indir_exp (a); break; } case lex_pointer : { /* Construct null pointer constant */ e = make_null_ptr (a, t2); if (IS_NULL_exp (e)) { /* Force conversion error */ e = apply_unary (lex_implicit, a, t1, t2, 0); } break; } case lex_sizeof : case lex_alignof : { /* Construct 'sizeof (a)' */ TYPE s; EXP b = a; suppress_usage++; s = typeof_exp (&b, 0, op); e = make_sizeof_exp (s, b, 0, op); suppress_usage--; break; } case lex_function : { /* Dummy function resolution operator */ ERROR err = NULL_err; LIST (IDENTIFIER) pids = NULL_list (IDENTIFIER); a = resolve_cast (t2, a, &err, 1, 1, pids); e = cast_exp (t2, a, &err, CAST_IMPLICIT); if (!IS_NULL_err (err)) report (crt_loc, err); break; } case lex_implicit : { /* Dummy implicit cast operator */ ERROR err = NULL_err; if (IS_exp_initialiser (a)) { LIST (EXP) args; args = DEREF_list (exp_initialiser_args (a)); e = init_constr (t2, args, &err); } else { a = convert_reference (a, REF_ASSIGN); e = cast_exp (t2, a, &err, CAST_IMPLICIT); } if (!IS_NULL_err (err)) report (crt_loc, err); break; } case lex_cast : { /* Construct '(t2) a' */ if (IS_NULL_exp (a)) { ERROR err = NULL_err; e = init_empty (t2, cv_none, 1, &err); if (!IS_NULL_err (err)) report (crt_loc, err); } else { e = make_cast_exp (t2, a, 0); } break; } case lex_if : case lex_do : case lex_for : case lex_while : case lex_cond_Hop : { /* Dummy conditional operators */ EXP b = NULL_exp; e = check_cond (a, &b, op); break; } case lex_switch : { /* Dummy control operator */ EXP b = NULL_exp; EXP c = NULL_exp; e = check_control (a, &b, &c); break; } case lex_fall : case lex_return : { /* Dummy return operator */ IDENTIFIER lab = NULL_id; e = find_return_exp (a, &lab, op); break; } case lex_discard : { /* Dummy expression statement operator */ e = make_exp_stmt (a); break; } case lex_void : { /* Dummy discard operator */ e = make_discard_exp (a); break; } case lex_question : { /* Dummy identity operator */ e = a; break; } #if LANGUAGE_CPP case lex_delete : { /* Construct 'delete a' */ e = make_delete_exp (lex_delete, 0, a); break; } case lex_delete_Hfull : { /* Construct '::delete a' */ e = make_delete_exp (lex_delete, 1, a); break; } case lex_delete_Harray : { /* Construct 'delete [] a' */ e = make_delete_exp (lex_delete_Harray, 0, a); break; } case lex_delete_Harray_Hfull : { /* Construct '::delete [] a' */ e = make_delete_exp (lex_delete_Harray, 1, a); break; } case lex_compute : { /* Construct empty new-initialiser */ e = make_new_init (t2, NULL_list (EXP), 0); break; } case lex_typeid : case lex_vtable : { /* Construct 'typeid (a)' */ suppress_usage++; e = make_typeid_exp (op, a, 0); suppress_usage--; break; } case lex_static_Hcast : case lex_reinterpret_Hcast : case lex_const_Hcast : case lex_dynamic_Hcast : { /* Construct 'op < t2 > (a)' */ e = make_new_cast_exp (op, t2, a, 0); break; } #endif default : { /* Illegal operations */ FAIL (Unexpected unary operation); e = make_error_exp (0); break; } } suppress_quality--; return (e); } /* * APPLY A BINARY OPERATOR * * This routine applies the binary operator op to the arguments a and b. */ EXP apply_binary(int op, EXP a, EXP b, TYPE t1, TYPE t2, int cpy) { EXP e; if (cpy) { /* Copy arguments if necessary */ a = copy_exp (a, t1, t2); b = copy_exp (b, t1, t2); } suppress_quality++; switch (op) { case lex_and_H1 : { /* Construct 'a & b' */ e = make_and_exp (a, b); break; } case lex_and_Heq_H1 : case lex_div_Heq : case lex_lshift_Heq : case lex_minus_Heq : case lex_or_Heq_H1 : case lex_plus_Heq : case lex_rem_Heq : case lex_rshift_Heq : case lex_star_Heq : case lex_xor_Heq_H1 : { /* Construct 'a &= b', 'a /= b' etc. */ e = make_become_exp (op, a, b); break; } case lex_array_Hop : { /* Construct 'a [b]' */ e = make_index_exp (a, b); break; } case lex_arrow : case lex_dot : { /* Construct 'a->b' and 'a.b' */ e = make_field_exp (op, a, b); break; } case lex_assign : { /* Construct 'a = b' */ e = make_assign_exp (a, b, LANGUAGE_C); break; } case lex_comma : { /* Construct 'a, b' */ LIST (EXP) p = NULL_list (EXP); CONS_exp (b, p, p); CONS_exp (a, p, p); e = make_comma_exp (p); break; } case lex_eq : case lex_not_Heq_H1 : { /* Construct 'a == b' and 'a != b' */ e = make_equality_exp (op, a, b); break; } case lex_greater : case lex_greater_Heq : case lex_less : case lex_less_Heq : { /* Construct 'a > b', 'a >= b', 'a < b' and 'a <= b' */ e = make_relation_exp (op, a, b); break; } case lex_logical_Hand_H1 : { /* Construct 'a && b' */ e = make_log_and_exp (a, b); break; } case lex_logical_Hor_H1 : { /* Construct 'a || b' */ e = make_log_or_exp (a, b); break; } case lex_lshift : case lex_rshift : { /* Construct 'a << b' and 'a >> b' */ e = make_shift_exp (op, a, b); break; } case lex_minus : { /* Construct 'a - b' */ e = make_minus_exp (a, b); break; } case lex_plus : { /* Construct 'a + b' */ e = make_plus_exp (a, b); break; } case lex_plus_Hplus : case lex_minus_Hminus : { /* Construct 'a++' and 'a--' */ e = make_postfix_exp (op, a); break; } case lex_or_H1 : { /* Construct 'a | b' */ e = make_or_exp (a, b); break; } case lex_rem : { /* Construct 'a % b' */ e = make_rem_exp (a, b); break; } case lex_star : case lex_div : case lex_max : case lex_min : { /* Construct 'a * b' and 'a / b' */ e = make_mult_exp (op, a, b); break; } case lex_xor_H1 : { /* Construct 'a ^ b' */ e = make_xor_exp (a, b); break; } case lex_colon : { /* Construct 'NULL_exp ? a : b' */ e = make_cond_exp (NULL_exp, a, b); break; } #if LANGUAGE_CPP case lex_arrow_Hstar : case lex_dot_Hstar : { /* Construct 'a->*b' and 'a.*b' */ e = make_member_exp (op, a, b); break; } #endif default : { /* Illegal operations */ FAIL (Unexpected binary operation); e = make_error_exp (0); break; } } suppress_quality--; return (e); } /* * APPLY AN N-ARY OPERATOR * * This routine applies the n-ary operator op to the arguments p. The * type t2 gives the destination for any cast operator. */ EXP apply_nary(int op, LIST (EXP) p, TYPE t1, TYPE t2, int cpy) { EXP e; suppress_quality++; switch (op) { case lex_comma : { /* Construct 'p0, p1, ..., pn' */ if (cpy) p = copy_exp_list (p, t1, t2); e = make_comma_exp (p); break; } case lex_cond_Hop : { /* Construct 'p0 ? p1 : p2' */ EXP c, a, b; c = DEREF_exp (HEAD_list (p)); p = TAIL_list (p); a = DEREF_exp (HEAD_list (p)); p = TAIL_list (p); b = DEREF_exp (HEAD_list (p)); if (cpy) { c = copy_exp (c, type_bool, type_bool); a = copy_exp (a, t1, t2); b = copy_exp (b, t1, t2); } e = make_cond_exp (c, a, b); break; } case lex_func_Hop : { /* Construct 'p0 (p1, ..., pn)' */ EXP a = DEREF_exp (HEAD_list (p)); p = TAIL_list (p); if (cpy) { a = copy_func_exp (a, t1, t2); p = copy_exp_list (p, t1, t2); } e = make_func_exp (a, p, 1); break; } case lex_cast : { /* Construct 't2 (p0, ..., pn)' */ if (cpy) p = copy_exp_list (p, t1, t2); e = make_func_cast_exp (t2, p); break; } case lex_static_Hcast : { /* Construct 't2 (p0, ..., pn)' */ ERROR err = NULL_err; if (cpy) p = copy_exp_list (p, t1, t2); p = convert_args (p); e = convert_constr (t2, p, &err, CAST_STATIC); if (!IS_NULL_err (err)) report (crt_loc, err); break; } #if LANGUAGE_CPP case lex_new : case lex_new_Hfull : { /* Construct 'new (p3, ..., pn) (t0 [ p1 ]) (p2)' */ EXP a; TYPE s; int b = 0; if (op == lex_new_Hfull) b = 1; if (cpy) p = copy_exp_list (p, t1, t2); a = DEREF_exp (HEAD_list (p)); p = TAIL_list (p); s = DEREF_type (exp_type (a)); a = DEREF_exp (HEAD_list (p)); p = TAIL_list (p); if (!IS_NULL_exp (a)) { /* Array dimension */ NAT n; MAKE_nat_calc (a, n); MAKE_type_array (cv_none, s, n, s); } a = DEREF_exp (HEAD_list (p)); p = TAIL_list (p); e = make_new_exp (s, 0, b, p, a); break; } case lex_compute : { /* Construct new-initialiser, '(p0, ..., pn)' */ if (cpy) p = copy_exp_list (p, t1, t2); e = make_new_init (t2, p, 1); break; } #endif default : { /* Illegal operations */ FAIL (Unexpected nary operation); e = make_error_exp (0); break; } } suppress_quality--; return (e); } /* * CONVERT AN OPERAND TO A BUILT-IN OPERATOR * * This routine converts the nth operand a to the built-in operator op * to type t. */ static EXP convert_builtin(TYPE t, EXP a, int op, unsigned n) { ERROR err = NULL_err; if (IS_type_compound (t)) { a = convert_class (t, a, &err); } else { a = init_assign (t, cv_none, a, &err); } if (!IS_NULL_err (err)) { err = init_error (err, 0); err = concat_error (err, ERR_expr_convert_op (n, op)); report (crt_loc, err); } return (a); } /* * APPLY A BUILT-IN OPERATOR * * This routine applies the built-in operator id to the arguments args. */ EXP apply_builtin(IDENTIFIER id, LIST (EXP) args) { EXP e; TYPE t; int op; EXP a, b; HASHID nm = DEREF_hashid (id_name (id)); LIST (TYPE) ts = DEREF_list (id_builtin_ptypes (id)); /* Find operator */ if (IS_hashid_op (nm)) { op = DEREF_int (hashid_op_lex (nm)); } else { op = lex_func_Hop; } /* Shouldn't have no arguments */ if (IS_NULL_list (args)) { e = make_error_exp (0); return (e); } /* Convert first argument */ DESTROY_CONS_exp (destroy, a, args, args); t = DEREF_type (HEAD_list (ts)); a = convert_builtin (t, a, op, (unsigned) 1); /* Allow for 'operator ()' */ if (op == lex_func_Hop) { overload_depth++; e = make_func_exp (a, args, 0); overload_depth--; return (e); } /* Allow for unary operators */ if (IS_NULL_list (args)) { overload_depth++; e = apply_unary (op, a, NULL_type, NULL_type, 0); overload_depth--; return (e); } /* Convert second argument */ DESTROY_CONS_exp (destroy, b, args, args); t = DEREF_type (HEAD_list (TAIL_list (ts))); b = convert_builtin (t, b, op, (unsigned) 1); /* Allow for binary operators */ if (IS_NULL_list (args)) { overload_depth++; e = apply_binary (op, a, b, NULL_type, NULL_type, 0); overload_depth--; return (e); } /* Shouldn't have more than two arguments */ DESTROY_list (args, SIZE_exp); e = make_error_exp (0); return (e); } /* * OVERLOAD DEPTH FLAG * * This flag is used to keep track of the depth of overloaded operator * resolutions. */ int overload_depth = 0; int overload_warn = 1; /* * OPERATOR OVERLOADING ROUTINES * * The operator overloading routines are only included in the C++ * producer. */ #if LANGUAGE_CPP /* * CHECK AN OVERLOADED OPERATOR TYPE * * This routine checks the function type t for the overloaded operator id. * The argument mem is true if id represents a non-static member function. * Most operators have restrictions on the number and types of their * parameters, others must be member functions. Note that this routine * only covers genuine overloading operators such as 'operator +', the * allocation operators such as 'operator new' are handled by the routine * check_allocator and alloc is set accordingly. */ TYPE check_operator(TYPE t, IDENTIFIER id, int mem, int *alloc) { int op; int ell; HASHID nm; int dargs = 0; unsigned n, m; unsigned npars; LIST (TYPE) ptypes; /* Allow for template types */ if (IS_type_templ (t)) { TYPE s = DEREF_type (type_templ_defn (t)); s = check_operator (s, id, mem, alloc); COPY_type (type_templ_defn (t), s); return (t); } /* Find the operator */ nm = DEREF_hashid (id_name (id)); op = DEREF_int (hashid_op_lex (nm)); switch (op) { case lex_new : case lex_new_Harray : { /* Check for allocation operators */ *alloc = 1; t = check_allocator (t, id, mem, 0); return (t); } case lex_delete : case lex_delete_Harray : { /* Check for deallocation operators */ *alloc = 2; t = check_allocator (t, id, mem, 0); return (t); } default : { *alloc = 0; break; } } /* Decompose function type */ ptypes = DEREF_list (type_func_ptypes (t)); npars = LENGTH_list (ptypes); ell = DEREF_int (type_func_ellipsis (t)); if (ell) { /* Set number of parameters to dummy large value */ npars = 10000; } /* Check function arguments */ if (mem) { /* Member functions have implicit extra parameter */ npars++; n = 0; m = 1; } else { /* Should have an overloadable parameter */ LIST (TYPE) p = ptypes; while (!IS_NULL_list (p)) { TYPE a = DEREF_type (HEAD_list (p)); unsigned ca = type_category (&a); if (IS_TYPE_OVERLOAD (ca)) break; p = TAIL_list (p); } if (IS_NULL_list (p)) { report (crt_loc, ERR_over_oper_type (nm)); } n = 1; m = 2; } /* Check number of arguments */ switch (op) { case lex_compl_H1 : case lex_not_H1 : case lex_abs : case lex_alignof : case lex_sizeof : case lex_typeid : case lex_vtable : { /* Unary operators */ if (npars != 1) { ERROR err = ERR_over_unary_pars (nm, n, n); report (crt_loc, err); } break; } case lex_plus : case lex_minus : case lex_star : case lex_and_H1 : { /* Either unary or binary operators */ if (npars != 1 && npars != 2) { ERROR err = ERR_over_binary_pars_p1 (nm, n, m, m); report (crt_loc, err); } break; } default : { /* Binary operators */ if (npars != 2) { ERROR err = ERR_over_binary_pars_p2 (nm, m, m); report (crt_loc, err); } break; } case lex_assign : { /* Assignment */ if (!mem) report (crt_loc, ERR_over_ass_mem (nm)); if (npars != 2) { ERROR err = ERR_over_ass_pars (nm, m, m); report (crt_loc, err); } break; } case lex_func_Hop : { /* Function call (can have default arguments) */ if (!mem) report (crt_loc, ERR_over_call_mem (nm)); dargs = 1; break; } case lex_array_Hop : { /* Subscripting */ if (!mem) report (crt_loc, ERR_over_sub_mem (nm)); if (npars != 2) { ERROR err = ERR_over_sub_pars (nm, m, m); report (crt_loc, err); } break; } case lex_arrow : { /* Class member access */ if (!mem) report (crt_loc, ERR_over_ref_mem (nm)); if (npars != 1) { ERROR err = ERR_over_ref_pars (nm, n, n); report (crt_loc, err); } break; } case lex_plus_Hplus : case lex_minus_Hminus : { /* Increment and decrement */ if (npars == 1) { /* One argument form is fine */ /* EMPTY */ } else if (npars == 2) { /* Two argument form needs checking */ TYPE a; TYPE b = type_sint; LIST (TYPE) p = ptypes; if (!mem) p = TAIL_list (p); a = DEREF_type (HEAD_list (p)); if (!eq_type_unqual (a, b) && !is_templ_type (a)) { /* Second argument should be 'int' */ report (crt_loc, ERR_over_inc_pars_p2 (nm, b)); } } else { /* Anything else is illegal */ ERROR err = ERR_over_inc_pars (nm, n, m, m); report (crt_loc, err); } break; } case lex_cond_Hop : { /* Tertiary operators */ if (npars != 3) { unsigned p = n + 2; ERROR err = ERR_over_binary_pars_p2 (nm, p, p); report (crt_loc, err); } break; } } /* Check for default arguments */ if (!dargs && check_func_dargs (t, 0, 0)) { report (crt_loc, ERR_over_oper_default (nm)); } return (t); } /* * LISTS OF BUILT-IN OPERATORS * * These values are used in the allocation and deallocation of built-in * operators. */ static IDENTIFIER unary_free = NULL_id; static IDENTIFIER unary_all = NULL_id; static IDENTIFIER binary_free = NULL_id; static IDENTIFIER binary_all = NULL_id; static IDENTIFIER nary_free = NULL_id; static IDENTIFIER nary_all = NULL_id; /* * CONSTRUCT A BUILT-IN UNARY OPERATOR * * This routine constructs the built-in unary operator 'r nm (a)'. */ static IDENTIFIER unary_builtin(HASHID nm, TYPE a, TYPE r) { LIST (TYPE) p; IDENTIFIER id = unary_free; if (IS_NULL_id (id)) { /* Allocate new identifier */ NAMESPACE ns = NULL_nspace; CONS_type (a, NULL_list (TYPE), p); MAKE_id_builtin (nm, dspec_none, ns, builtin_loc, r, p, id); COPY_id (id_alias (id), unary_all); unary_all = id; } else { /* Use existing identifier */ COPY_hashid (id_name (id), nm); COPY_ulong (id_dump (id), LINK_NONE); COPY_type (id_builtin_ret (id), r); p = DEREF_list (id_builtin_ptypes (id)); COPY_type (HEAD_list (p), a); unary_free = DEREF_id (id_alias (id)); } return (id); } /* * CONSTRUCT A BUILT-IN BINARY OPERATOR * * This routine constructs the built-in binary operator 'r nm (a, b)'. */ static IDENTIFIER binary_builtin(HASHID nm, TYPE a, TYPE b, TYPE r) { LIST (TYPE) p; IDENTIFIER id = binary_free; if (IS_NULL_id (id)) { /* Allocate new identifier */ NAMESPACE ns = NULL_nspace; CONS_type (b, NULL_list (TYPE), p); CONS_type (a, p, p); MAKE_id_builtin (nm, dspec_none, ns, builtin_loc, r, p, id); COPY_id (id_alias (id), binary_all); binary_all = id; } else { /* Use existing identifier */ COPY_hashid (id_name (id), nm); COPY_ulong (id_dump (id), LINK_NONE); COPY_type (id_builtin_ret (id), r); p = DEREF_list (id_builtin_ptypes (id)); COPY_type (HEAD_list (p), a); p = TAIL_list (p); COPY_type (HEAD_list (p), b); binary_free = DEREF_id (id_alias (id)); } return (id); } /* * CONSTRUCT A BUILT-IN N-ARY OPERATOR * * This routine constructs the built-in n-ary operator 'r nm (a, p)'. */ static IDENTIFIER nary_builtin(HASHID nm, TYPE a, LIST (TYPE) p, TYPE r) { IDENTIFIER id = nary_free; if (IS_NULL_id (id)) { /* Allocate new identifier */ NAMESPACE ns = NULL_nspace; CONS_type (a, p, p); MAKE_id_builtin (nm, dspec_none, ns, builtin_loc, r, p, id); COPY_id (id_alias (id), nary_all); nary_all = id; } else { /* Use existing identifier */ LIST (TYPE) q; COPY_hashid (id_name (id), nm); COPY_ulong (id_dump (id), LINK_NONE); COPY_type (id_builtin_ret (id), r); q = DEREF_list (id_builtin_ptypes (id)); COPY_type (HEAD_list (q), a); COPY_list (PTR_TAIL_list (q), p); nary_free = DEREF_id (id_alias (id)); } return (id); } /* * CONSTRUCT OVERLOADED OPERATION CANDIDATE LIST * * This routine constructs the candidate list for the overloaded n-ary * operation op, adding the result to p. The candidates come from the * current namespace and the type t, if this is a class. The routine * returns the hash table entry for 'operator op'. */ static HASHID overload_candidates(CANDIDATE_LIST *p, int op, TYPE t, TYPE s) { /* Look up 'operator op' (non-standard) */ HASHID nm = lookup_op (op); switch (op) { case lex_assign : case lex_func_Hop : case lex_array_Hop : case lex_arrow : { /* These can only be member functions */ break; } default : { /* These can be non-member functions */ IDENTIFIER id = find_op_id (nm); if (!IS_NULL_type (s)) { IGNORE koenig_candidates (p, id, s, KIND_OP); } IGNORE koenig_candidates (p, id, t, KIND_OP); if (!IS_id_dummy (id)) { /* Function declared */ add_candidates (p, id, 1, KIND_OP); } break; } } /* Look up 't::operator op' */ if (IS_type_compound (t)) { CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); NAMESPACE ns = DEREF_nspace (ctype_member (ct)); IDENTIFIER id = search_field (ns, nm, 0, 0); if (!IS_NULL_id (id)) { if (IS_id_ambig (id)) { /* Ambiguous look-up */ IGNORE report_ambiguous (id, 0, 1, 0); } add_candidates (p, id, 1, KIND_MEM_OP); } } return (nm); } /* * CONSTRUCT LIST OF INTEGRAL TYPES * * This routine adds all the promoted integral types to the list res. */ static LIST (TYPE) add_int_types(LIST (TYPE) res) { if (basetype_info [ ntype_sllong ].key) { res = cons_type_set (res, type_ullong); res = cons_type_set (res, type_sllong); } res = cons_type_set (res, type_ulong); res = cons_type_set (res, type_slong); res = cons_type_set (res, type_uint); res = cons_type_set (res, type_sint); return (res); } /* * CONSTRUCT LIST OF FLOATING POINT TYPES * * This routine adds all the floating point types to the list res. */ static LIST (TYPE) add_float_types(LIST (TYPE) res) { res = cons_type_set (res, type_ldouble); res = cons_type_set (res, type_double); res = cons_type_set (res, type_float); return (res); } /* * CONSTRUCT A LIST OF CONVERSION TYPES * * This routine constructs a list of types consisting of all the types * of a certain kind to which the type t can be converted. Conversions * which are worse that existing conversions are omitted. The type kind * is indicated by the CTYPE macros defined in chktype.h, except that * CTYPE_INTEGER refers to promoted integer types unless qualified using * CTYPE_LVALUE. */ static LIST (TYPE) find_type_convs(TYPE t, EXP a, unsigned kind) { LIST (TYPE) res = NULL_list (TYPE); unsigned nt = TAG_type (t); switch (nt) { case type_compound_tag : { /* Class types */ LIST (IDENTIFIER) conv; CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); complete_class (ct, 1); conv = DEREF_list (ctype_conv (ct)); for (; !IS_NULL_list (conv) ; conv = TAIL_list (conv)) { /* Scan through conversion operations */ TYPE r; HASHID nm; unsigned nr; IDENTIFIER id = DEREF_id (HEAD_list (conv)); DECL_SPEC ds = DEREF_dspec (id_storage (id)); if (ds & dspec_explicit) continue; /* Check for reference types */ nm = DEREF_hashid (id_name (id)); r = DEREF_type (hashid_conv_type (nm)); if (kind == CTYPE_NONE) { /* Include all types in this case */ res = cons_type_set (res, r); continue; } nr = TAG_type (r); if (nr == type_ref_tag) { /* Allow for reference bindings */ if (IS_TYPE_LVALUE (kind)) { TYPE s = DEREF_type (type_ref_sub (r)); CV_SPEC cv = find_cv_qual (s); if (!(cv & cv_const)) { /* Don't include const references */ unsigned ns = TAG_type (s); switch (ns) { case type_integer_tag : case type_bitfield_tag : case type_enumerate_tag : { if (IS_TYPE_INTEGER (kind)) { res = cons_type_set (res, r); } break; } case type_floating_tag : { if (IS_TYPE_FLOAT (kind)) { res = cons_type_set (res, r); } break; } case type_ptr_tag : { if (IS_TYPE_PTR (kind)) { res = cons_type_set (res, r); } break; } case type_ptr_mem_tag : { if (IS_TYPE_PTR_MEM (kind)) { res = cons_type_set (res, r); } break; } } } } else { /* Allow for reference conversions */ r = DEREF_type (type_ref_sub (r)); nr = TAG_type (r); } } /* Check return type */ switch (nr) { case type_integer_tag : case type_bitfield_tag : case type_enumerate_tag : { /* Integral types */ if (IS_TYPE_INTEGER (kind)) { /* Means promoted integer type */ TYPE s = promote_type (r); res = cons_type_set (res, s); } else if (IS_TYPE_FLOAT (kind)) { /* Can convert to any floating type */ res = add_float_types (res); } break; } case type_floating_tag : { /* Floating point types */ if (IS_TYPE_FLOAT (kind)) { res = cons_type_set (res, r); } else if (IS_TYPE_INTEGER (kind)) { /* Can convert to any promoted integer type */ res = add_int_types (res); } break; } case type_ptr_tag : { /* Pointer types */ if (IS_TYPE_PTR (kind)) { res = cons_type_set (res, r); } break; } case type_ptr_mem_tag : { /* Pointer to member types */ if (IS_TYPE_PTR_MEM (kind)) { res = cons_type_set (res, r); } break; } } } res = REVERSE_list (res); break; } case type_integer_tag : case type_bitfield_tag : case type_enumerate_tag : { /* Integral types */ if (IS_TYPE_LVALUE (kind)) { /* Lvalue of integral type */ if (IS_TYPE_INTEGER (kind)) { if (nt == type_integer_tag) { t = lvalue_type (t); MAKE_type_ref (cv_none, t, t); CONS_type (t, res, res); } } } else if (IS_TYPE_INTEGER (kind)) { /* Means promoted integer type */ TYPE s = promote_type (t); CONS_type (s, res, res); } else if (IS_TYPE_FLOAT (kind)) { /* Can convert to any floating type */ res = add_float_types (res); } break; } case type_floating_tag : { /* Floating point types */ if (IS_TYPE_LVALUE (kind)) { /* Lvalue of floating point type */ if (IS_TYPE_FLOAT (kind)) { t = lvalue_type (t); MAKE_type_ref (cv_none, t, t); CONS_type (t, res, res); } } else if (IS_TYPE_FLOAT (kind)) { /* Floating point type */ CONS_type (t, res, res); } else if (IS_TYPE_INTEGER (kind)) { /* Can convert to any promoted integer type */ if (basetype_info [ ntype_sllong ].key) { CONS_type (type_ullong, res, res); CONS_type (type_sllong, res, res); } CONS_type (type_ulong, res, res); CONS_type (type_slong, res, res); CONS_type (type_uint, res, res); CONS_type (type_sint, res, res); } break; } case type_ptr_tag : { /* Pointer types */ if (IS_TYPE_PTR (kind)) { if (IS_TYPE_LVALUE (kind)) { t = lvalue_type (t); MAKE_type_ref (cv_none, t, t); } CONS_type (t, res, res); } break; } case type_ptr_mem_tag : { /* Pointer to member types */ if (IS_TYPE_PTR_MEM (kind)) { if (IS_TYPE_LVALUE (kind)) { t = lvalue_type (t); MAKE_type_ref (cv_none, t, t); } CONS_type (t, res, res); } break; } case type_array_tag : { /* Allow for array-to-pointer conversion */ if (IS_TYPE_PTR (kind) && !IS_TYPE_LVALUE (kind)) { TYPE s = DEREF_type (type_array_sub (t)); MAKE_type_ptr (cv_none, s, s); CONS_type (s, res, res); } if (kind == CTYPE_NONE) { TYPE s = DEREF_type (type_array_sub (t)); MAKE_type_ptr (cv_none, s, t); } break; } case type_func_tag : { /* Allow for function-to-pointer conversion */ if (IS_TYPE_PTR (kind) && !IS_TYPE_LVALUE (kind)) { TYPE s; MAKE_type_ptr (cv_none, t, s); CONS_type (s, res, res); } if (kind == CTYPE_NONE) { MAKE_type_ptr (cv_none, t, t); } break; } } if (kind == CTYPE_NONE) { /* Include all types in this case */ CV_SPEC cv = DEREF_cv (type_qual (t)); if (cv & cv_lvalue) { /* Turn lvalues into references */ MAKE_type_ref (cv_none, t, t); } res = cons_type_set (res, t); } UNUSED (a); return (res); } /* * FILTER A LIST OF POINTER TYPES * * This routine scans through the list of pointer or pointer to member * types pa replacing any types which are not pointers to complete object * types by the null type. If fn is true pointer to function types are * also allowed. */ static void filter_ptr(LIST (TYPE) pa, int fn) { while (!IS_NULL_list (pa)) { TYPE ta = DEREF_type (HEAD_list (pa)); TYPE sa = ta; if (IS_type_ref (sa)) { sa = DEREF_type (type_ref_sub (sa)); } if (IS_type_ptr (sa)) { sa = DEREF_type (type_ptr_sub (sa)); } else { sa = DEREF_type (type_ptr_mem_sub (sa)); } switch (TAG_type (sa)) { case type_array_tag : { /* Check for incomplete arrays */ NAT n = DEREF_nat (type_array_size (sa)); if (IS_NULL_nat (n)) ta = NULL_type; break; } case type_compound_tag : { /* Check for incomplete classes */ CLASS_TYPE cs = DEREF_ctype (type_compound_defn (sa)); CLASS_INFO ci = DEREF_cinfo (ctype_info (cs)); if (!(ci & cinfo_complete)) ta = NULL_type; break; } case type_enumerate_tag : { /* Check for incomplete enumerations */ ENUM_TYPE es = DEREF_etype (type_enumerate_defn (sa)); CLASS_INFO ei = DEREF_cinfo (etype_info (es)); if (!(ei & cinfo_complete)) ta = NULL_type; break; } case type_top_tag : case type_bottom_tag : { /* These are always incomplete */ ta = NULL_type; break; } case type_func_tag : { /* Deal with function types */ if (!fn) ta = NULL_type; break; } } COPY_type (HEAD_list (pa), ta); pa = TAIL_list (pa); } return; } /* * BUILT-IN OPERATOR TYPES * * The following macros are used to describe the return types and the * constraints on the operand types of the built-in operators. */ #define RTYPE_ARG_1 0 #define RTYPE_ARG_2 1 #define RTYPE_CONT_1 2 #define RTYPE_CONT_2 3 #define RTYPE_ARITH 4 #define RTYPE_BOOL 5 #define RTYPE_PTRDIFF 6 #define RTYPE_OP 7 #define OTYPE_NONE 0 #define OTYPE_PTR 1 #define OTYPE_PTR_MEM 2 #define OTYPE_REF_PTR 3 #define OTYPE_REF_MEM 4 #define OTYPE_SELECT 5 #define OTYPE_COND 6 /* * FIND RETURN TYPE OF BUILT-IN OPERATOR * * This routine finds the return type for a built-in operator with * operand types ta and tb and return descriptor rtype. tc gives the * default return type. The return type is not used in overload * resolution but is included for error reporting purposes. */ static TYPE find_builtin_ret(TYPE ta, TYPE tb, int rtype, TYPE tc) { switch (rtype) { case RTYPE_ARG_1 : { tc = ta; break; } case RTYPE_ARG_2 : { tc = tb; break; } case RTYPE_CONT_1 : { if (IS_type_ptr_etc (ta)) { tc = DEREF_type (type_ptr_etc_sub (ta)); } break; } case RTYPE_CONT_2 : { if (IS_type_ptr_etc (tb)) { tc = DEREF_type (type_ptr_etc_sub (tb)); } break; } case RTYPE_ARITH : { tc = arith_type (ta, tb, NULL_exp, NULL_exp); break; } case RTYPE_BOOL : { tc = type_bool; break; } case RTYPE_PTRDIFF : { tc = type_ptrdiff_t; break; } } return (tc); } /* * CHECK BUILT-IN OPERAND TYPES * * This routine checks whether the operand types ta and tb are valid for * a built-in operator with operand constraints otype. In some cases * the return type is returned via pt. */ static int check_builtin_args(TYPE ta, TYPE tb, int otype, TYPE *pt) { int ok = 1; switch (otype) { case OTYPE_PTR : { /* Allow equal pointer types */ TYPE sa = DEREF_type (type_ptr_sub (ta)); TYPE sb = DEREF_type (type_ptr_sub (tb)); ok = eq_type_unqual (sa, sb); break; } case OTYPE_PTR_MEM : { /* Allow equal pointer member types */ CLASS_TYPE ca = DEREF_ctype (type_ptr_mem_of (ta)); CLASS_TYPE cb = DEREF_ctype (type_ptr_mem_of (tb)); if (eq_ctype (ca, cb)) { TYPE sa = DEREF_type (type_ptr_mem_sub (ta)); TYPE sb = DEREF_type (type_ptr_mem_sub (tb)); ok = eq_type_unqual (sa, sb); } else { ok = 0; } break; } case OTYPE_REF_PTR : { /* Allow equal pointer types */ if (IS_type_ref (ta)) { ta = DEREF_type (type_ref_sub (ta)); } return (check_builtin_args (ta, tb, OTYPE_PTR, pt)); } case OTYPE_REF_MEM : { /* Allow equal pointer member types */ if (IS_type_ref (ta)) { ta = DEREF_type (type_ref_sub (ta)); } return (check_builtin_args (ta, tb, OTYPE_PTR_MEM, pt)); } case OTYPE_SELECT : { /* Allow pointer member selection */ TYPE sa = DEREF_type (type_ptr_sub (ta)); if (IS_type_compound (sa)) { CLASS_TYPE ca = DEREF_ctype (type_compound_defn (sa)); CLASS_TYPE cb = DEREF_ctype (type_ptr_mem_of (tb)); GRAPH gr = find_base_class (ca, cb, 0); if (IS_NULL_graph (gr)) ok = 0; *pt = DEREF_type (type_ptr_mem_sub (tb)); } else { ok = 0; } break; } case OTYPE_COND : { /* Allow for conditional expressions */ int suspect = 0; TYPE r = common_type (ta, tb, &suspect); if (IS_NULL_type (r)) { ok = 0; if (IS_type_ref (ta)) { ta = DEREF_type (type_ref_sub (ta)); ok = 1; } if (IS_type_ref (tb)) { tb = DEREF_type (type_ref_sub (tb)); ok = 1; } if (ok) { suspect = 0; r = common_type (ta, tb, &suspect); if (IS_NULL_type (r)) { ok = 0; } else { *pt = r; } } } else { *pt = r; } break; } } return (ok); } /* * ADD A LIST OF BUILT-IN UNARY CANDIDATES * * This routine adds a series of built-in unary candidates for the * operator nm to the list p. The possible operand types are given by pa. * rtype describes how to form the return type from the operand type. */ static void add_unary_builtin(CANDIDATE_LIST *p, HASHID nm, LIST (TYPE) pa, int rtype) { while (!IS_NULL_list (pa)) { TYPE ta = DEREF_type (HEAD_list (pa)); if (!IS_NULL_type (ta)) { TYPE tb = find_builtin_ret (ta, ta, rtype, type_error); IDENTIFIER id = unary_builtin (nm, ta, tb); add_candidates (p, id, 1, KIND_BUILTIN); } pa = TAIL_list (pa); } DESTROY_list (pa, SIZE_type); return; } /* * ADD A LIST OF BUILT-IN BINARY CANDIDATES * * This routine adds a series of built-in binary candidates for the * operator nm to the list p. The possible first and second operand types * are given by pa and pb. rtype describes how to form the return type * from the operand types, otype describes any restrictions on the operand * types. */ static void add_binary_builtin(CANDIDATE_LIST *p, HASHID nm, LIST (TYPE) pa, LIST (TYPE) pb, int rtype, int otype) { while (!IS_NULL_list (pa)) { TYPE ta = DEREF_type (HEAD_list (pa)); if (!IS_NULL_type (ta)) { LIST (TYPE) pc = pb; while (!IS_NULL_list (pc)) { TYPE tb = DEREF_type (HEAD_list (pc)); if (!IS_NULL_type (tb)) { /* Check operand types */ TYPE tc = type_error; if (check_builtin_args (ta, tb, otype, &tc)) { IDENTIFIER id; tc = find_builtin_ret (ta, tb, rtype, tc); if (otype == OTYPE_COND) { ta = tc; tb = tc; } id = binary_builtin (nm, ta, tb, tc); add_candidates (p, id, 1, KIND_BUILTIN); } } pc = TAIL_list (pc); } } pa = TAIL_list (pa); } if (!EQ_list (pa, pb)) DESTROY_list (pa, SIZE_type); DESTROY_list (pb, SIZE_type); return; } /* * OVERLOAD A UNARY OPERATOR * * This routine calculates the unary overload operator 'op a'. This can * be 'a.operator op ()', 'operator op (a)' or 'op t (a)' for some * type t. Note that '->' is a special case for op, with 'a->b' being * expanded as '(a.operator -> ())->b'. This expansion is done in * begin_field_exp, this routine returning the null expression to indicate * that '->' is not overloaded. */ EXP unary_overload(int op, EXP a) { EXP e; HASHID nm; IDENTIFIER id; LIST (TYPE) pa; CANDIDATE_LIST *p = &candidates; /* Check for template parameters */ TYPE t = DEREF_type (exp_type (a)); if (is_templ_type (t)) { MAKE_exp_op (t, op, a, NULL_exp, e); return (e); } /* Construct candidate list */ p->size = 0; nm = overload_candidates (p, op, t, NULL_type); /* Construct built-in candidates */ switch (op) { case lex_plus : { /* Built-in candidates for '+a' */ pa = find_type_convs (t, a, CTYPE_SCALAR); add_unary_builtin (p, nm, pa, RTYPE_ARG_1); break; } case lex_minus : case lex_abs : { /* Built-in candidates for '-a' */ pa = find_type_convs (t, a, CTYPE_ARITH); add_unary_builtin (p, nm, pa, RTYPE_ARG_1); break; } case lex_compl_H1 : { /* Built-in candidates for '~a' */ pa = find_type_convs (t, a, CTYPE_INT); add_unary_builtin (p, nm, pa, RTYPE_ARG_1); break; } case lex_not_H1 : { /* Built-in candidate for '!a' */ id = unary_builtin (nm, type_bool, type_bool); add_candidates (p, id, 1, KIND_BUILTIN); break; } case lex_star : { /* Built-in candidates for '*a' */ pa = find_type_convs (t, a, CTYPE_PTR); filter_ptr (pa, 1); add_unary_builtin (p, nm, pa, RTYPE_CONT_1); break; } case lex_plus_Hplus : case lex_minus_Hminus : { /* Built-in candidates for '++a' and '--a' */ pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_PTR)); filter_ptr (pa, 0); add_unary_builtin (p, nm, pa, RTYPE_ARG_1); pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_ARITH)); add_unary_builtin (p, nm, pa, RTYPE_ARG_1); break; } case lex_and_H1 : { /* No built-in candidates for '&a' */ break; } case lex_arrow : { /* No built-in candidates for 'a->' */ break; } } /* Search for overload operator */ if (p->size) { CANDIDATE *q; unsigned rank; LIST (EXP) args; CONS_exp (a, NULL_list (EXP), args); q = resolve_overload (p, args, NULL_type, 0); unary_free = unary_all; rank = q->rank; if (rank >= RANK_VIABLE) { /* Only allow viable resolutions */ int kind = q->kind; IDENTIFIER qid = q->func; int ow = overload_warn; if (rank == RANK_BEST) { /* Unambiguous resolution */ if (match_no_viable > 1 && ow) { if (do_dump) dump_builtin (qid); report (crt_loc, ERR_over_match_oper_ok (qid)); } } else { /* Ambiguous resolution */ q = resolve_ambiguous (p, args, NULL_type, 0); qid = q->func; rank = q->rank; if (rank == RANK_TARGET) { ERROR err2 = ERR_over_match_oper_target (op); qid = make_ambig_func (p, qid, args, qual_none, &err2); kind = KIND_OP; if (do_dump) dump_builtin (qid); report (crt_loc, err2); } else if (rank == RANK_VIABLE) { ERROR err2 = ERR_over_match_oper_ambig (op); err2 = list_candidates (err2, p, RANK_VIABLE); report (crt_loc, err2); } overload_warn = 0; } if (kind == KIND_BUILTIN) { /* Built-in resolution */ if (op == lex_arrow) { /* For 'a->' return the null expression */ DESTROY_list (args, SIZE_exp); e = NULL_exp; } else { e = apply_builtin (qid, args); } } else { /* Function resolution */ use_func_id (qid, 0, suppress_usage); e = apply_func_id (qid, qual_none, NULL_graph, args); } overload_warn = ow; return (e); } DESTROY_list (args, SIZE_exp); } /* Try operation again */ if (op == lex_arrow) { /* For 'a->' return the null expression */ e = NULL_exp; } else { overload_depth++; e = apply_unary (op, a, NULL_type, NULL_type, 0); overload_depth--; } return (e); } /* * OVERLOAD A BINARY OPERATOR * * This routine calculates the binary overload operator 'a op b'. This can * be 'a.operator op (b)', 'operator op (a, b)' or 't (a) op s (b)' * for some types t and s. Note that postfix '++' and '--' are special * cases for op in which b is a dummy zero operand. */ EXP binary_overload(int op, EXP a, EXP b) { EXP e; HASHID nm; LIST (TYPE) pa, pb; CANDIDATE_LIST *p = &candidates; /* Check for template parameters */ TYPE t = DEREF_type (exp_type (a)); TYPE s = DEREF_type (exp_type (b)); if (is_templ_type (t)) { MAKE_exp_op (t, op, a, b, e); return (e); } if (is_templ_type (s)) { MAKE_exp_op (s, op, a, b, e); return (e); } /* Construct candidate list */ p->size = 0; nm = overload_candidates (p, op, t, s); /* Construct built-in candidates */ /* QUERY - overloaded function operands */ switch (op) { case lex_logical_Hand_H1 : case lex_logical_Hor_H1 : { /* Built-in candidates for 'a && b' and 'a || b' */ IDENTIFIER id; id = binary_builtin (nm, type_bool, type_bool, type_bool); add_candidates (p, id, 1, KIND_BUILTIN); break; } case lex_and_H1 : case lex_or_H1 : case lex_rem : case lex_xor_H1 : { /* Built-in candidates for 'a & b' etc. */ pa = find_type_convs (t, a, CTYPE_INT); pb = find_type_convs (s, b, CTYPE_INT); add_binary_builtin (p, nm, pa, pb, RTYPE_ARITH, OTYPE_NONE); break; } case lex_lshift : case lex_rshift : { /* Built-in candidates for 'a << b' and 'a >> b' */ pa = find_type_convs (t, a, CTYPE_INT); pb = find_type_convs (s, b, CTYPE_INT); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_NONE); break; } case lex_minus : { /* Built-in candidates for 'a - b' */ pa = find_type_convs (t, a, CTYPE_PTR); pb = find_type_convs (s, b, CTYPE_PTR); filter_ptr (pa, 0); add_binary_builtin (p, nm, pa, pb, RTYPE_PTRDIFF, OTYPE_PTR); pa = find_type_convs (t, a, CTYPE_PTR); CONS_type (type_ptrdiff_t, NULL_list (TYPE), pb); filter_ptr (pa, 0); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_NONE); goto arith_op_lab; } case lex_plus : { /* Built-in candidates for 'a + b' */ pa = find_type_convs (t, a, CTYPE_PTR); CONS_type (type_ptrdiff_t, NULL_list (TYPE), pb); filter_ptr (pa, 0); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_NONE); CONS_type (type_ptrdiff_t, NULL_list (TYPE), pa); pb = find_type_convs (s, b, CTYPE_PTR); filter_ptr (pb, 0); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_2, OTYPE_NONE); goto arith_op_lab; } case lex_array_Hop : { /* Built-in candidates for 'a [b]' */ pa = find_type_convs (t, a, CTYPE_PTR); CONS_type (type_ptrdiff_t, NULL_list (TYPE), pb); filter_ptr (pa, 0); add_binary_builtin (p, nm, pa, pb, RTYPE_CONT_1, OTYPE_NONE); CONS_type (type_ptrdiff_t, NULL_list (TYPE), pa); pb = find_type_convs (s, b, CTYPE_PTR); filter_ptr (pb, 0); add_binary_builtin (p, nm, pa, pb, RTYPE_CONT_2, OTYPE_NONE); break; } case lex_star : case lex_div : case lex_max : case lex_min : arith_op_lab : { /* Built-in candidates for 'a * b' and 'a / b' */ pa = find_type_convs (t, a, CTYPE_ARITH); pb = find_type_convs (s, b, CTYPE_ARITH); add_binary_builtin (p, nm, pa, pb, RTYPE_ARITH, OTYPE_NONE); break; } case lex_eq : case lex_not_Heq_H1 : { /* Built-in candidates for 'a == b' and 'a != b' */ pa = find_type_convs (t, a, CTYPE_PTR_MEM); pb = find_type_convs (s, b, CTYPE_PTR_MEM); if (is_zero_exp (a)) pa = pb; if (is_zero_exp (b)) pb = pa; add_binary_builtin (p, nm, pa, pb, RTYPE_BOOL, OTYPE_PTR_MEM); goto relation_op_lab; } case lex_greater : case lex_greater_Heq : case lex_less : case lex_less_Heq : relation_op_lab : { /* Built-in candidates for 'a > b' etc. */ pa = find_type_convs (t, a, CTYPE_PTR); pb = find_type_convs (s, b, CTYPE_PTR); if (is_zero_exp (a)) pa = pb; if (is_zero_exp (b)) pb = pa; add_binary_builtin (p, nm, pa, pb, RTYPE_BOOL, OTYPE_PTR); pa = find_type_convs (t, a, CTYPE_ARITH); pb = find_type_convs (s, b, CTYPE_ARITH); add_binary_builtin (p, nm, pa, pb, RTYPE_BOOL, OTYPE_NONE); break; } case lex_arrow_Hstar : { /* Built-in candidates for 'a->*b' */ pa = find_type_convs (t, a, CTYPE_PTR); pb = find_type_convs (s, b, CTYPE_PTR_MEM); filter_ptr (pb, 1); add_binary_builtin (p, nm, pa, pb, RTYPE_OP, OTYPE_SELECT); break; } case lex_plus_Hplus : case lex_minus_Hminus : { /* Built-in candidates for 'a++' and 'a--' */ pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_PTR)); CONS_type (type_sint, NULL_list (TYPE), pb); filter_ptr (pa, 0); add_binary_builtin (p, nm, pa, pb, RTYPE_CONT_1, OTYPE_NONE); pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_ARITH)); CONS_type (type_sint, NULL_list (TYPE), pb); add_binary_builtin (p, nm, pa, pb, RTYPE_CONT_1, OTYPE_NONE); break; } case lex_and_Heq_H1 : case lex_lshift_Heq : case lex_or_Heq_H1 : case lex_rem_Heq : case lex_rshift_Heq : case lex_xor_Heq_H1 : { /* Built-in candidates for 'a &= b' etc. */ pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_INT)); pb = find_type_convs (s, b, CTYPE_INT); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_NONE); break; } case lex_div_Heq : case lex_star_Heq : { /* Built-in candidates for 'a /= b' and 'a *= b' */ pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_ARITH)); pb = find_type_convs (s, b, CTYPE_ARITH); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_NONE); break; } case lex_plus_Heq : case lex_minus_Heq : { /* Built-in candidates for 'a += b' and 'a -= b' */ pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_PTR)); CONS_type (type_ptrdiff_t, NULL_list (TYPE), pb); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_NONE); pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_ARITH)); pb = find_type_convs (s, b, CTYPE_ARITH); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_NONE); break; } case lex_assign : { /* Built-in candidates for 'a = b' */ pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_PTR_MEM)); pb = find_type_convs (s, b, CTYPE_PTR_MEM); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_REF_MEM); pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_PTR)); pb = find_type_convs (s, b, CTYPE_PTR); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_REF_PTR); pa = find_type_convs (t, a, (CTYPE_LVALUE | CTYPE_ARITH)); pb = find_type_convs (s, b, CTYPE_ARITH); add_binary_builtin (p, nm, pa, pb, RTYPE_ARG_1, OTYPE_NONE); break; } case lex_comma : { /* No built-in candidates for 'a, b' */ break; } case lex_colon : { /* Built-in candidates for ' ? a : b' */ LIST (TYPE) pc; pa = find_type_convs (t, a, CTYPE_NONE); pb = find_type_convs (s, b, CTYPE_NONE); if (is_zero_exp (a)) { /* Allow for null pointers */ pc = find_type_convs (s, b, (CTYPE_PTR | CTYPE_PTR_MEM)); pa = APPEND_list (pa, pc); } if (is_zero_exp (b)) { /* Allow for null pointers */ pc = find_type_convs (t, a, (CTYPE_PTR | CTYPE_PTR_MEM)); pb = APPEND_list (pb, pc); } add_binary_builtin (p, nm, pa, pb, RTYPE_OP, OTYPE_COND); break; } } /* Search for overload operator */ if (p->size) { CANDIDATE *q; unsigned rank; LIST (EXP) args; CONS_exp (b, NULL_list (EXP), args); CONS_exp (a, args, args); q = resolve_overload (p, args, NULL_type, 0); binary_free = binary_all; rank = q->rank; if (rank >= RANK_VIABLE) { /* Only allow viable resolutions */ int kind = q->kind; IDENTIFIER qid = q->func; int ow = overload_warn; if (rank == RANK_BEST) { /* Unambiguous resolution */ if (match_no_viable > 1 && ow) { if (do_dump) dump_builtin (qid); report (crt_loc, ERR_over_match_oper_ok (qid)); } } else { /* Ambiguous resolution */ q = resolve_ambiguous (p, args, NULL_type, 0); qid = q->func; rank = q->rank; if (rank == RANK_TARGET) { ERROR err2 = ERR_over_match_oper_target (op); qid = make_ambig_func (p, qid, args, qual_none, &err2); kind = KIND_OP; if (do_dump) dump_builtin (qid); report (crt_loc, err2); } else if (rank == RANK_VIABLE) { ERROR err2 = ERR_over_match_oper_ambig (op); err2 = list_candidates (err2, p, RANK_VIABLE); report (crt_loc, err2); } overload_warn = 0; } if (kind == KIND_BUILTIN) { /* Built-in resolution */ if (op == lex_comma) { /* Return null expression for 'a, b' */ DESTROY_list (args, SIZE_exp); e = NULL_exp; } else { e = apply_builtin (qid, args); } } else { /* Function resolution */ use_func_id (qid, 0, suppress_usage); e = apply_func_id (qid, qual_none, NULL_graph, args); } overload_warn = ow; return (e); } DESTROY_list (args, SIZE_exp); } /* Try operation again */ if (op == lex_comma) { /* Return null expression for 'a, b' */ e = NULL_exp; } else { overload_depth++; e = apply_binary (op, a, b, NULL_type, NULL_type, 0); overload_depth--; } return (e); } /* * OVERLOAD A FUNCTION OPERATOR * * This routine calculates the function overload operator 'a (args)'. * This is expanded as 'a.operator () (args)'. */ EXP function_overload(EXP a, LIST (EXP) args) { EXP e; int op = lex_func_Hop; /* Construct candidate list */ TYPE t = DEREF_type (exp_type (a)); CANDIDATE_LIST *p = &candidates; p->size = 0; IGNORE overload_candidates (p, op, t, NULL_type); if (IS_type_compound (t)) { LIST (IDENTIFIER) conv; HASHID nm = KEYWORD (lex_zzzz); CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t)); complete_class (ct, 1); conv = DEREF_list (ctype_conv (ct)); while (!IS_NULL_list (conv)) { /* Scan through conversion operations */ IDENTIFIER cid = DEREF_id (HEAD_list (conv)); DECL_SPEC ds = DEREF_dspec (id_storage (cid)); if (!(ds & dspec_explicit)) { HASHID cnm = DEREF_hashid (id_name (cid)); TYPE r = DEREF_type (hashid_conv_type (cnm)); unsigned nr = TAG_type (r); /* Search for pointer or reference to functions */ if (nr == type_ptr_tag || nr == type_ref_tag) { TYPE s = DEREF_type (type_ptr_etc_sub (r)); if (IS_type_func (s)) { LOCATION loc; LIST (TYPE) ptypes; TYPE ret = DEREF_type (type_func_ret (s)); ptypes = DEREF_list (type_func_ptypes (s)); DEREF_loc (id_loc (cid), loc); cid = nary_builtin (nm, r, ptypes, ret); COPY_loc (id_loc (cid), loc); add_candidates (p, cid, 1, KIND_BUILTIN); } } } conv = TAIL_list (conv); } } /* Search for overload operator */ if (p->size) { CANDIDATE *q; unsigned rank; CONS_exp (a, args, args); q = resolve_overload (p, args, NULL_type, 0); nary_free = nary_all; rank = q->rank; if (rank >= RANK_VIABLE) { /* Only allow viable resolutions */ int kind = q->kind; IDENTIFIER qid = q->func; int ow = overload_warn; if (rank == RANK_BEST) { /* Unambiguous resolution */ if (match_no_viable > 1 && ow) { if (do_dump) dump_builtin (qid); report (crt_loc, ERR_over_match_oper_ok (qid)); } } else { /* Ambiguous resolution */ q = resolve_ambiguous (p, args, NULL_type, 0); qid = q->func; rank = q->rank; if (rank == RANK_TARGET) { ERROR err = ERR_over_match_oper_target (op); qid = make_ambig_func (p, qid, args, qual_none, &err); kind = KIND_OP; if (do_dump) dump_builtin (qid); report (crt_loc, err); } else if (rank == RANK_VIABLE) { ERROR err = ERR_over_match_oper_ambig (op); err = list_candidates (err, p, RANK_VIABLE); report (crt_loc, err); } overload_warn = 0; } if (kind == KIND_BUILTIN) { /* Built-in resolution */ e = apply_builtin (qid, args); } else { /* Function resolution */ use_func_id (qid, 0, suppress_usage); e = apply_func_id (qid, qual_none, NULL_graph, args); } overload_warn = ow; return (e); } DESTROY_CONS_exp (destroy, a, args, args); } /* Try operation again with increased overload depth */ overload_depth++; e = make_func_exp (a, args, 0); overload_depth--; return (e); } #endif /* LANGUAGE_CPP */