/*
* 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 */