+/* Build expressions with type checking for C compiler.
+ Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
+ Hacked by Michael Tiemann (tiemann@mcc.com)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of the C front end.
+ It contains routines to build C expressions given their operands,
+ including computing the types of the result, C-specific error checks,
+ and some optimization.
+
+ There are also routines to build RETURN_STMT nodes and CASE_STMT nodes,
+ and to process initializations in declarations (since they work
+ like a strange sort of assignment). */
+
+extern void error ();
+extern void warning ();
+
+#include "config.h"
+#include <stdio.h>
+#include "tree.h"
+#include "cplus-tree.h"
+#include "flags.h"
+#include "assert.h"
+
+#include "obstack.h"
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+extern int xmalloc ();
+extern void free ();
+
+extern struct obstack *current_obstack;
+
+int mark_addressable ();
+static tree convert_for_assignment ();
+/* static */ tree convert_for_initialization ();
+int compparms ();
+int compparms1 ();
+int comp_target_types ();
+static tree shorten_compare ();
+static void binary_op_error ();
+static tree pointer_int_sum ();
+static tree pointer_diff ();
+static tree convert_sequence ();
+/* static */ tree unary_complex_lvalue ();
+tree truthvalue_conversion ();
+static tree invert_truthvalue ();
+extern void readonly_warning_or_error ();
+
+static void
+message_2_types (pfn, s, type1, type2)
+ void (*pfn) ();
+ char *s;
+ tree type1, type2;
+{
+ tree name1 = TYPE_NAME (type1);
+ tree name2 = TYPE_NAME (type2);
+ if (TREE_CODE (name1) == TYPE_DECL)
+ name1 = DECL_NAME (name1);
+ if (TREE_CODE (name2) == TYPE_DECL)
+ name2 = DECL_NAME (name2);
+ (*pfn) (s, IDENTIFIER_POINTER (name1), IDENTIFIER_POINTER (name2));
+}
+
+/* Return the _TYPE node describing the data type
+ of the data which NODE represents as a C expression.
+ Arrays and functions are converted to pointers
+ just as they are when they appear as C expressions.
+
+ C++: Member types are converted to the data
+ type of the member they are. */
+
+tree
+datatype (node)
+ tree node;
+{
+ register tree type = TREE_TYPE (node);
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return TYPE_POINTER_TO (TREE_TYPE (type));
+ if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
+ return build_pointer_type (type);
+ if (TREE_CODE (type) == OFFSET_TYPE)
+ return datatype (type);
+ return type;
+}
+
+/* Return the target type of TYPE, which meas return T for:
+ T*, T&, T[], T (...), and otherwise, just T. */
+tree
+target_type (type)
+ tree type;
+{
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ while (TREE_CODE (type) == POINTER_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE
+ || TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE
+ || TREE_CODE (type) == OFFSET_TYPE)
+ type = TREE_TYPE (type);
+ return type;
+}
+
+/* Do `exp = require_complete_type (exp);' to make sure exp
+ does not have an incomplete type. (That includes void types.) */
+
+tree
+require_complete_type (value)
+ tree value;
+{
+ tree type = TREE_TYPE (value);
+
+ /* First, detect a valid value with a complete type. */
+ if (TYPE_SIZE (type) != 0
+ && type != void_type_node)
+ return value;
+
+ /* If we see X::Y, we build an OFFSET_TYPE which has
+ not been laid out. Try to avoid an error by interpreting
+ it as this->X::Y, if reasonable. */
+ if (TREE_CODE (value) == OFFSET_REF
+ && C_C_D != 0
+ && TREE_OPERAND (value, 0) == C_C_D)
+ {
+ tree base, member = TREE_OPERAND (value, 1);
+ tree basetype = TYPE_OFFSET_BASETYPE (type);
+ assert (TREE_CODE (member) == FIELD_DECL);
+ base = convert_pointer_to (basetype, current_class_decl);
+ value = build (COMPONENT_REF, TREE_TYPE (TREE_OPERAND (value, 1)),
+ build_indirect_ref (base, 0),
+ TREE_OPERAND (value, 1));
+ return require_complete_type (value);
+ }
+
+ incomplete_type_error (value, type);
+ return error_mark_node;
+}
+
+/* Return truthvalue of whether type of EXP is instantiated. */
+int
+type_unknown_p (exp)
+ tree exp;
+{
+ return (TREE_TYPE (exp) == unknown_type_node
+ || (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE
+ && TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node));
+}
+
+/* Do `exp = require_instantiated_type (type, exp);' to make sure EXP
+ does not have an uninstantiated type.
+ TYPE is type to instantiate with, if uninstantiated. */
+tree
+require_instantiated_type (type, exp, errval)
+ tree type, exp, errval;
+{
+ if (TREE_TYPE (exp) == unknown_type_node
+ || (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE
+ && TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node))
+ {
+ exp = instantiate_type (type, exp, 1);
+ if (TREE_TYPE (exp) == error_mark_node)
+ return errval;
+ }
+ return exp;
+}
+
+/* Return a variant of TYPE which has all the type qualifiers of LIKE
+ as well as those of TYPE. */
+
+static tree
+qualify_type (type, like)
+ tree type, like;
+{
+ int constflag = TREE_READONLY (type) || TREE_READONLY (like);
+ int volflag = TREE_VOLATILE (type) || TREE_VOLATILE (like);
+ /* @@ Must do member pointers here. */
+ return build_type_variant (type, constflag, volflag);
+}
+\f
+/* Return the common type of two parameter lists.
+
+ As an optimization, free the space we allocate if the parameter
+ lists are already common. */
+
+tree
+commonparms (p1, p2)
+ tree p1, p2;
+{
+ tree oldargs = p1, newargs, n;
+ int i, len;
+ int any_change = 0;
+ char *first_obj = (char *)obstack_alloc (current_obstack, 0);
+
+ len = list_length (p1);
+ newargs = 0;
+
+ for (i = 0; i < len; i++)
+ newargs = tree_cons (0, 0, newargs);
+
+ n = newargs;
+
+ for (i = 0; p1;
+ p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n), i++)
+ {
+ if (TREE_PURPOSE (p1) && !TREE_PURPOSE (p2))
+ {
+#if 0
+ if (! any_warning)
+ {
+ warning ("default argument given in prototype and not in declaration of function");
+ any_warning++;
+ }
+#endif
+ TREE_PURPOSE (p2) = TREE_PURPOSE (p1);
+ any_change = 1;
+ }
+ else if (! TREE_PURPOSE (p1))
+ {
+ if (TREE_PURPOSE (p2))
+ any_change = 1;
+ }
+ else
+ {
+ int cmp = simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2));
+ if (cmp < 0)
+ abort ();
+ if (cmp == 0)
+ {
+ error ("redeclaration of default argument %d", i);
+ any_change = 1;
+ }
+ }
+ TREE_PURPOSE (n) = TREE_PURPOSE (p2);
+ if (TREE_VALUE (p1) != TREE_VALUE (p2))
+ {
+ any_change = 1;
+ TREE_VALUE (n) = commontype (TREE_VALUE (p1), TREE_VALUE (p2));
+ }
+ else
+ TREE_VALUE (n) = TREE_VALUE (p1);
+ }
+ if (! any_change)
+ {
+ obstack_free (current_obstack, first_obj);
+ return oldargs;
+ }
+
+ return newargs;
+}
+
+/* Return the common type of two types.
+ We assume that comptypes has already been done and returned 1;
+ if that isn't so, this may crash.
+
+ This is the type for the result of most arithmetic operations
+ if the operands have the given two types.
+
+ We do not deal with enumeral types here because they have already been
+ converted to integer types. */
+
+tree
+commontype (t1, t2)
+ tree t1, t2;
+{
+ register enum tree_code form1;
+ register enum tree_code form2;
+
+ /* Save time if the two types are the same. */
+
+ if (t1 == t2) return t1;
+
+ /* Treat an enum type as the unsigned integer type of the same width. */
+
+ if (TREE_CODE (t1) == ENUMERAL_TYPE)
+ t1 = type_for_size (TYPE_PRECISION (t1), 1);
+ if (TREE_CODE (t2) == ENUMERAL_TYPE)
+ t2 = type_for_size (TYPE_PRECISION (t2), 1);
+
+ form1 = TREE_CODE (t1);
+ form2 = TREE_CODE (t2);
+
+ switch (form1)
+ {
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ /* If only one is real, use it as the result. */
+
+ if (form1 == REAL_TYPE && form2 != REAL_TYPE)
+ return t1;
+
+ if (form2 == REAL_TYPE && form1 != REAL_TYPE)
+ return t2;
+
+ /* Both real or both integers; use the one with greater precision. */
+
+ if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
+ return t1;
+ else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
+ return t2;
+
+ /* Same precision. Prefer longs to ints even when same size. */
+
+ if (t1 == long_unsigned_type_node
+ || t2 == long_unsigned_type_node)
+ return long_unsigned_type_node;
+
+ if (t1 == long_integer_type_node
+ || t2 == long_integer_type_node)
+ {
+ /* But preserve unsignedness from the other type,
+ since long cannot hold all the values of an unsigned int. */
+ if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+ return long_unsigned_type_node;
+ return long_integer_type_node;
+ }
+
+ /* Otherwise prefer the unsigned one. */
+
+ if (TREE_UNSIGNED (t1))
+ return t1;
+ else return t2;
+
+#if 1
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ /* For two pointers, do this recursively on the target type,
+ and combine the qualifiers of the two types' targets. */
+ {
+ tree target = commontype (TYPE_MAIN_VARIANT (TREE_TYPE (t1)),
+ TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
+ int constp
+ = TREE_READONLY (TREE_TYPE (t1)) || TREE_READONLY (TREE_TYPE (t2));
+ int volatilep
+ = TREE_VOLATILE (TREE_TYPE (t1)) || TREE_VOLATILE (TREE_TYPE (t2));
+ target = build_type_variant (target, constp, volatilep);
+ if (form1 == POINTER_TYPE)
+ return build_pointer_type (target);
+ else
+ return build_reference_type (target);
+ }
+#else
+ case POINTER_TYPE:
+ return build_pointer_type (commontype (TREE_TYPE (t1), TREE_TYPE (t2)));
+
+ case REFERENCE_TYPE:
+ return build_reference_type (commontype (TREE_TYPE (t1), TREE_TYPE (t2)));
+#endif
+
+ case ARRAY_TYPE:
+ {
+ tree elt = commontype (TREE_TYPE (t1), TREE_TYPE (t2));
+ /* Save space: see if the result is identical to one of the args. */
+ if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
+ return t1;
+ if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
+ return t2;
+ /* Merge the element types, and have a size if either arg has one. */
+ return build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ }
+
+ case FUNCTION_TYPE:
+ /* Function types: prefer the one that specified arg types.
+ If both do, merge the arg types. Also merge the return types. */
+ {
+ tree valtype = commontype (TREE_TYPE (t1), TREE_TYPE (t2));
+ tree p1 = TYPE_ARG_TYPES (t1);
+ tree p2 = TYPE_ARG_TYPES (t2);
+ tree rval, raises;
+
+ /* Save space: see if the result is identical to one of the args. */
+ if (valtype == TREE_TYPE (t1) && ! TYPE_ARG_TYPES (t2))
+ return t1;
+ if (valtype == TREE_TYPE (t2) && ! TYPE_ARG_TYPES (t1))
+ return t2;
+
+ /* Simple way if one arg fails to specify argument types. */
+ if (TYPE_ARG_TYPES (t1) == 0)
+ {
+ rval = build_function_type (valtype, TYPE_ARG_TYPES (t2));
+ if (raises = TYPE_RAISES_EXCEPTIONS (t2))
+ rval = build_exception_variant (NULL_TREE, rval, raises);
+ return rval;
+ }
+ raises = TYPE_RAISES_EXCEPTIONS (t1);
+ if (TYPE_ARG_TYPES (t2) == 0)
+ {
+ rval = build_function_type (valtype, TYPE_ARG_TYPES (t1));
+ if (raises)
+ rval = build_exception_variant (NULL_TREE, rval, raises);
+ return rval;
+ }
+
+ /* If both args specify argument types, we must merge the two
+ lists, argument by argument. */
+ rval = build_function_type (valtype, commonparms (p1, p2));
+ return build_exception_variant (NULL_TREE, rval, raises);
+ }
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ assert (TYPE_MAIN_VARIANT (t1) == t1 && TYPE_MAIN_VARIANT (t2) == t2);
+
+ if (basetype_or_else (t1, t2))
+ return t1;
+ compiler_error ("commontype called with uncommon aggregate types");
+ return t1;
+
+ case METHOD_TYPE:
+ if (TYPE_METHOD_BASETYPE (t1) == TYPE_METHOD_BASETYPE (t2)
+ && TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
+ {
+ /* Get this value the long way, since TYPE_METHOD_BASETYPE
+ is just the main variant of this. */
+ tree basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1)));
+ tree raises, t3;
+
+ raises = TYPE_RAISES_EXCEPTIONS (t1);
+
+ /* If this was a member function type, get back to the
+ original type of type member function (i.e., without
+ the class instance variable up front. */
+ t1 = build_function_type (TREE_TYPE (t1), TREE_CHAIN (TYPE_ARG_TYPES (t1)));
+ t2 = build_function_type (TREE_TYPE (t2), TREE_CHAIN (TYPE_ARG_TYPES (t2)));
+ t3 = commontype (t1, t2);
+ t3 = build_cplus_method_type (basetype, TREE_TYPE (t3), TYPE_ARG_TYPES (t3));
+ return build_exception_variant (basetype, t3, raises);
+ }
+ compiler_error ("commontype called with uncommon method types");
+ return t1;
+
+ case OFFSET_TYPE:
+ if (TYPE_OFFSET_BASETYPE (t1) == TYPE_OFFSET_BASETYPE (t2)
+ && TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
+ {
+ tree basetype = TYPE_OFFSET_BASETYPE (t1);
+ return build_member_type (basetype,
+ commontype (TREE_TYPE (t1), TREE_TYPE (t2)));
+ }
+ compiler_error ("commontype called with uncommon member types");
+ return t1;
+
+ default:
+ return t1;
+ }
+}
+\f
+/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */
+int
+compexcepttypes (t1, t2, strict)
+ tree t1, t2;
+ int strict;
+{
+ return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
+}
+
+static int
+comp_array_types (cmp, t1, t2, strict)
+ register int (*cmp)();
+ tree t1, t2;
+{
+ tree d1 = TYPE_DOMAIN (t1);
+ tree d2 = TYPE_DOMAIN (t2);
+
+ if (!(TREE_TYPE (t1) == TREE_TYPE (t2)
+ || (*cmp) (TREE_TYPE (t1), TREE_TYPE (t2), strict)))
+ return 0;
+
+ /* Sizes must match unless one is missing or variable. */
+ if (d1 == 0 || d2 == 0 || d1 == d2
+ || TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST
+ || TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
+ || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST
+ || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)
+ return 1;
+
+ return ((TREE_INT_CST_LOW (TYPE_MIN_VALUE (d1))
+ == TREE_INT_CST_LOW (TYPE_MIN_VALUE (d2)))
+ && (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d1))
+ == TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d2)))
+ && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (d1))
+ == TREE_INT_CST_LOW (TYPE_MAX_VALUE (d2)))
+ && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d1))
+ == TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d2))));
+}
+
+/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
+ or various other operations. This is what ANSI C speaks of as
+ "being the same".
+
+ For C++: argument STRICT says we should be strict about this
+ comparison:
+
+ 1 : strict (compared according to ANSI C)
+ 0 : <= (compared according to C++)
+ -1: <= or >= (relaxed)
+
+ Otherwise, pointers involving base classes and derived classes
+ can be mixed as legal: i.e. a pointer to a base class may be assigned
+ to a pointer to one of its derived classes, as per C++. A pointer to
+ a derived class may be passed as a paramter to a function expecting a
+ pointer to a base classes. These allowances do not commute. In this
+ case, TYPE1 is assumed to be the base class, and TYPE2 is assumed to
+ be the derived class. */
+int
+comptypes (type1, type2, strict)
+ tree type1, type2;
+ int strict;
+{
+ register tree t1 = type1;
+ register tree t2 = type2;
+
+ /* Suppress errors caused by previously reported errors */
+
+ if (t1 == t2)
+ return 1;
+ /* This should never happen. */
+ assert (t1 != error_mark_node);
+
+ /* We don't want this to happen. */
+ if (t2 == error_mark_node)
+ {
+ warning ("t2 == error_mark_node in `comptypes'");
+ return 0;
+ }
+
+ /* Treat an enum type as the unsigned integer type of the same width. */
+
+ if (TREE_CODE (t1) == ENUMERAL_TYPE)
+ t1 = type_for_size (TYPE_PRECISION (t1), 1);
+ if (TREE_CODE (t2) == ENUMERAL_TYPE)
+ t2 = type_for_size (TYPE_PRECISION (t2), 1);
+
+ if (t1 == t2)
+ return 1;
+
+ /* Different classes of types can't be compatible. */
+
+ if (TREE_CODE (t1) != TREE_CODE (t2)) return 0;
+
+ /* Qualifiers must match. */
+
+ if (TREE_READONLY (t1) != TREE_READONLY (t2))
+ return 0;
+ if (TREE_THIS_VOLATILE (t1) != TREE_THIS_VOLATILE (t2))
+ return 0;
+
+ switch (TREE_CODE (t1))
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ if (t1 == t2)
+ return 1;
+ if (strict <= 0)
+ goto look_hard;
+ return 0;
+
+ case OFFSET_TYPE:
+ return (comptypes (TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t1)),
+ TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t2)), strict)
+ && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict));
+
+ case METHOD_TYPE:
+ if (! compexcepttypes (t1, t2, strict))
+ return 0;
+
+ /* This case is anti-symmetrical!
+ One can pass a base member (or member function)
+ to something expecting a derived member (or member function),
+ but not vice-versa! */
+
+ return (comptypes (TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t2)),
+ TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t1)), strict)
+ && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
+ && compparms (TREE_CHAIN (TYPE_ARG_TYPES (t1)),
+ TREE_CHAIN (TYPE_ARG_TYPES(t2)), strict));
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ t1 = TREE_TYPE (t1);
+ t2 = TREE_TYPE (t2);
+ if (t1 == t2)
+ return 1;
+ if (strict <= 0)
+ {
+ if (IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2))
+ {
+ int rval;
+ look_hard:
+ rval = t1 == t2 || get_base_distance (t1, t2, 0, 0) >= 0;
+
+ if (rval)
+ return 1;
+ if (strict < 0)
+ return (get_base_type (t2, t1, 0) != 0);
+ }
+ return 0;
+ }
+ else
+ return comptypes (t1, t2, strict);
+
+ case FUNCTION_TYPE:
+ if (! compexcepttypes (t1, t2, strict))
+ return 0;
+
+ return ((TREE_TYPE (t1) == TREE_TYPE (t2)
+ || comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
+ && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2), strict));
+
+ case ARRAY_TYPE:
+ /* Target types must match incl. qualifiers. */
+ return comp_array_types (&comptypes, t1, t2, strict);
+
+ }
+ return 0;
+}
+
+/* Return 1 if TTL and TTR are pointers to types that are equivalent,
+ ignoring their qualifiers.
+
+ NPTRS is the number of pointers we can strip off and keep cool.
+ This is used to permit (for aggr A, aggr B) A, B* to convert to A*,
+ but to not permit B** to convert to A**. */
+
+int
+comp_target_types (ttl, ttr, nptrs)
+ tree ttl, ttr;
+ int nptrs;
+{
+ ttl = TYPE_MAIN_VARIANT (ttl);
+ ttr = TYPE_MAIN_VARIANT (ttr);
+ if (ttl == ttr)
+ return 1;
+
+ if (TREE_CODE (ttr) != TREE_CODE (ttl))
+ return 0;
+
+ if (TREE_CODE (ttr) == POINTER_TYPE)
+ return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs - 1);
+
+ if (TREE_CODE (ttr) == REFERENCE_TYPE)
+ return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs);
+ if (TREE_CODE (ttr) == ARRAY_TYPE)
+ return comp_array_types (&comp_target_types, ttl, ttr, 0);
+ else if (TREE_CODE (ttr) == FUNCTION_TYPE || TREE_CODE (ttr) == METHOD_TYPE)
+ if (comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs))
+ switch (comp_target_parms (TYPE_ARG_TYPES (ttl), TYPE_ARG_TYPES (ttr), -1))
+ {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ warning ("contravariance violation for method types ignored");
+ return 1;
+ default:
+ abort ();
+ }
+ else
+ return 0;
+
+ /* for C++ */
+ else if (TREE_CODE (ttr) == OFFSET_TYPE)
+ {
+ /* Contravariance: we can assign a pointer to base member to a pointer
+ to derived member. Note difference from simple pointer case, where
+ we can pass a pointer to derived to a pointer to base. */
+ if (comptypes (TYPE_OFFSET_BASETYPE (ttr), TYPE_OFFSET_BASETYPE (ttl), 0))
+ return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs);
+ else if (comptypes (TYPE_OFFSET_BASETYPE (ttl), TYPE_OFFSET_BASETYPE (ttr), 0)
+ && comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs))
+ {
+ warning ("contravariance violation for member types ignored");
+ return 1;
+ }
+ }
+ else if (IS_AGGR_TYPE (ttl))
+ {
+ if (nptrs < 0)
+ return 0;
+ return comptypes (TYPE_POINTER_TO (ttl), TYPE_POINTER_TO (ttr), 0);
+ }
+
+ return 0;
+}
+
+/* If two types share a common base type, return that basetype.
+ There is not a unique most-derived base type, this function
+ returns ERROR_MARK_NODE. */
+tree
+common_base_type (tt1, tt2)
+ tree tt1, tt2;
+{
+ tree first = NULL_TREE, second = NULL_TREE, tmp;
+ int i;
+
+ for (i = CLASSTYPE_N_BASECLASSES (tt1); i > 0; i--)
+ {
+ tree basetype = CLASSTYPE_BASECLASS (tt1, i);
+ switch (get_base_distance (basetype, tt2, 0, 0))
+ {
+ case -1:
+ tmp = common_base_type (basetype, tt2);
+ if (tmp == NULL_TREE)
+ break;
+ if (tmp == error_mark_node)
+ return error_mark_node;
+ if (first != NULL_TREE)
+ return error_mark_node;
+ first = tmp;
+ break;
+
+ case -2:
+ first = error_mark_node;
+ break;
+
+ default:
+ if (first != NULL_TREE)
+ return error_mark_node;
+ first = CLASSTYPE_BASECLASS (tt1, i);
+ break;
+ }
+ }
+
+ for (i = CLASSTYPE_N_BASECLASSES (tt2); i > 0; i--)
+ {
+ tree basetype = CLASSTYPE_BASECLASS (tt2, i);
+ switch (get_base_distance (basetype, tt1, 0, 0))
+ {
+ case -1:
+ tmp = common_base_type (basetype, tt1);
+ if (tmp == NULL_TREE)
+ break;
+ if (tmp == error_mark_node)
+ return error_mark_node;
+ if (second != NULL_TREE)
+ return error_mark_node;
+ second = tmp;
+ break;
+
+ case -2:
+ second = error_mark_node;
+ break;
+
+ default:
+ if (second != NULL_TREE)
+ return error_mark_node;
+ second = CLASSTYPE_BASECLASS (tt2, i);
+ break;
+ }
+ }
+
+ if (first != NULL_TREE
+ && second != NULL_TREE
+ && TYPE_MAIN_VARIANT (first) == TYPE_MAIN_VARIANT (second))
+ return first;
+ if (first)
+ return first;
+ if (second)
+ return second;
+
+ return NULL_TREE;
+}
+\f
+/* Subroutines of `comptypes'. */
+
+/* Return 1 if two parameter type lists PARMS1 and PARMS2
+ are equivalent in the sense that functions with those parameter types
+ can have equivalent types.
+ If either list is empty, we win.
+ Otherwise, the two lists must be equivalent, element by element.
+
+ C++: See comment above about TYPE1, TYPE2, STRICT. */
+int
+compparms (parms1, parms2, strict)
+ tree parms1, parms2;
+ int strict;
+{
+ register tree t1 = parms1, t2 = parms2;
+
+ /* An unspecified parmlist matches any specified parmlist
+ whose argument types don't need default promotions. */
+
+ if (t1 == 0)
+ return compparms1 (t2);
+ if (t2 == 0)
+ return compparms1 (t1);
+
+ while (1)
+ {
+ if (t1 == 0 && t2 == 0)
+ return 1;
+ /* If one parmlist is shorter than the other,
+ they fail to match, unless STRICT is <= 0. */
+ if (t1 == 0 || t2 == 0)
+ {
+ if (strict > 0)
+ return 0;
+ if (strict < 0)
+ return 1;
+ if (strict == 0)
+ return t1 && TREE_PURPOSE (t1);
+ return ((t1 && TREE_PURPOSE (t1)) || TREE_PURPOSE (t2));
+ }
+ if (! comptypes (TREE_VALUE (t2), TREE_VALUE (t1), strict))
+ {
+ if (strict > 0)
+ return 0;
+ if (strict == 0)
+ return t2 == void_list_node && TREE_PURPOSE (t1);
+ return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
+ }
+ if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
+ {
+ int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
+ if (cmp < 0)
+ abort ();
+ if (cmp == 0)
+ return 0;
+ }
+
+ t1 = TREE_CHAIN (t1);
+ t2 = TREE_CHAIN (t2);
+ }
+}
+
+/* This really wants return whether or not parameter type lists
+ would make their owning functions assignment compatible or not. */
+int
+comp_target_parms (parms1, parms2, strict)
+ tree parms1, parms2;
+ int strict;
+{
+ register tree t1 = parms1, t2 = parms2;
+ int warn_contravariance = 0;
+
+ /* An unspecified parmlist matches any specified parmlist
+ whose argument types don't need default promotions. */
+
+ if (t1 == 0)
+ return compparms1 (t2);
+ if (t2 == 0)
+ return compparms1 (t1);
+
+ for (; t1 || t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+ {
+ tree p1, p2;
+
+ /* If one parmlist is shorter than the other,
+ they fail to match, unless STRICT is <= 0. */
+ if (t1 == 0 || t2 == 0)
+ {
+ if (strict > 0)
+ return 0;
+ if (strict < 0)
+ return 1 + warn_contravariance;
+ return ((t1 && TREE_PURPOSE (t1)) + warn_contravariance);
+ }
+ p1 = TREE_VALUE (t1);
+ p2 = TREE_VALUE (t2);
+ if (p1 == p2)
+ continue;
+ if ((TREE_CODE (p1) == POINTER_TYPE && TREE_CODE (p2) == POINTER_TYPE)
+ || (TREE_CODE (p1) == REFERENCE_TYPE && TREE_CODE (p2) == REFERENCE_TYPE))
+ {
+ /* The following is wrong for contravariance,
+ but many programs depend on it. */
+ if (TREE_TYPE (p1) == void_type_node)
+ {
+ warn_contravariance = 1;
+ continue;
+ }
+ if (TREE_TYPE (p2) == void_type_node)
+ continue;
+ if (IS_AGGR_TYPE (TREE_TYPE (p1)))
+ {
+ if (comptypes (p2, p1, 0) == 0)
+ {
+ if (comptypes (p1, p2, 0) != 0)
+ warn_contravariance = 1;
+ else
+ return 0;
+ }
+ continue;
+ }
+ }
+ /* Note backwards order due to contravariance. */
+ if (comp_target_types (p2, p1, 1) == 0)
+ {
+ if (comp_target_types (p1, p2, 1))
+ {
+ warn_contravariance = 1;
+ continue;
+ }
+ if (strict > 0)
+ return 0;
+#if 0
+ /* What good do these cases do? */
+ if (strict == 0)
+ return p2 == void_type_node && TREE_PURPOSE (t1);
+ return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
+#endif
+ }
+ /* Target types are compatible--just make sure that if
+ we use parameter lists, that they are ok as well. */
+ if (TREE_CODE (p1) == FUNCTION_TYPE || TREE_CODE (p1) == METHOD_TYPE)
+ switch (comp_target_parms (TYPE_ARG_TYPES (p1), TYPE_ARG_TYPES (p2), strict))
+ {
+ case 0:
+ return 0;
+ case 1:
+ break;
+ case 2:
+ warn_contravariance = 1;
+ }
+
+ if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
+ {
+ int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
+ if (cmp < 0)
+ abort ();
+ if (cmp == 0)
+ return 0;
+ }
+ }
+ return 1 + warn_contravariance;
+}
+
+/* Return 1 if PARMS specifies a fixed number of parameters
+ and none of their types is affected by default promotions. */
+
+int
+compparms1 (parms)
+ tree parms;
+{
+ register tree t;
+ for (t = parms; t; t = TREE_CHAIN (t))
+ {
+ register tree type = TREE_VALUE (t);
+
+ if (TREE_CHAIN (t) == 0 && type != void_type_node)
+ return 0;
+
+ if (type == float_type_node)
+ return 0;
+
+ if (TREE_CODE (type) == INTEGER_TYPE
+ && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
+ return 0;
+ }
+ return 1;
+}
+\f
+/* Return an unsigned type the same as TYPE in other respects.
+
+ C++: must make these work for type variants as well. */
+
+tree
+unsigned_type (type)
+ tree type;
+{
+ type = TYPE_MAIN_VARIANT (type);
+
+ if (type == signed_char_type_node || type == char_type_node)
+ return unsigned_char_type_node;
+ if (type == integer_type_node)
+ return unsigned_type_node;
+ if (type == short_integer_type_node)
+ return short_unsigned_type_node;
+ if (type == long_integer_type_node)
+ return long_unsigned_type_node;
+ if (type == long_long_integer_type_node)
+ return long_long_unsigned_type_node;
+ return type;
+}
+
+/* Return a signed type the same as TYPE in other respects. */
+
+tree
+signed_type (type)
+ tree type;
+{
+ if (type == unsigned_char_type_node || type == char_type_node)
+ return signed_char_type_node;
+ if (type == unsigned_type_node)
+ return integer_type_node;
+ if (type == short_unsigned_type_node)
+ return short_integer_type_node;
+ if (type == long_unsigned_type_node)
+ return long_integer_type_node;
+ if (type == long_long_unsigned_type_node)
+ return long_long_integer_type_node;
+ return type;
+}
+
+/* Return a type the same as TYPE except unsigned or
+ signed according to UNSIGNEDP. */
+
+tree
+signed_or_unsigned_type (unsignedp, type)
+ int unsignedp;
+ tree type;
+{
+ if (TREE_CODE (type) != INTEGER_TYPE)
+ return type;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
+ return (unsignedp ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+ return type;
+}
+
+/* Return an integer type with BITS bits of precision,
+ that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
+
+tree
+type_for_size (bits, unsignedp)
+ int bits;
+ int unsignedp;
+{
+ if (bits <= TYPE_PRECISION (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+ if (bits <= TYPE_PRECISION (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+ if (bits <= TYPE_PRECISION (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+
+ if (bits <= TYPE_PRECISION (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+ if (bits <= TYPE_PRECISION (long_long_integer_type_node))
+ return (unsignedp ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+
+ return 0;
+}
+
+tree
+get_floating_type (mode)
+ enum machine_mode mode;
+{
+ if (mode == TYPE_MODE (float_type_node))
+ return float_type_node;
+ if (mode == TYPE_MODE (double_type_node))
+ return double_type_node;
+ if (mode == TYPE_MODE (long_double_type_node))
+ return long_double_type_node;
+ abort ();
+}
+
+tree
+c_sizeof (type)
+ tree type;
+{
+ enum tree_code code = TREE_CODE (type);
+
+ if (code == FUNCTION_TYPE)
+ {
+ if (pedantic || warn_pointer_arith)
+ warning ("sizeof applied to a function type");
+ return build_int (1);
+ }
+ if (code == METHOD_TYPE)
+ {
+ if (pedantic || warn_pointer_arith)
+ warning ("sizeof applied to a method type");
+ return build_int (1);
+ }
+ if (code == VOID_TYPE)
+ {
+ if (pedantic || warn_pointer_arith)
+ warning ("sizeof applied to a void type");
+ return build_int (1);
+ }
+
+ /* C++: this is really correct! */
+ if (code == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+
+ return size_in_bytes (type);
+}
+
+tree
+c_sizeof_nowarn (type)
+ tree type;
+{
+ enum tree_code code = TREE_CODE (type);
+
+ if (code == FUNCTION_TYPE
+ || code == METHOD_TYPE
+ || code == VOID_TYPE)
+ return build_int (1);
+ if (code == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+
+ return size_in_bytes (type);
+}
+
+/* Implement the __alignof keyword: Return the minimum required
+ alignment of TYPE, measured in bytes. */
+
+tree
+c_alignof (type)
+ tree type;
+{
+ enum tree_code code = TREE_CODE (type);
+
+ if (code == FUNCTION_TYPE || code == METHOD_TYPE)
+ return build_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+
+ if (code == VOID_TYPE)
+ return build_int (1);
+
+ /* C++: this is really correct! */
+ if (code == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+
+ return build_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
+}
+\f
+/* Perform default promotions for C data used in expressions.
+ Arrays and functions are converted to pointers;
+ enumeral types or short or char, to int.
+ In addition, manifest constants symbols are replaced by their values.
+
+ C++: this will automatically bash references to their target type. */
+
+tree
+default_conversion (exp)
+ tree exp;
+{
+ register tree dt = TREE_TYPE (exp);
+ register enum tree_code form = TREE_CODE (dt);
+
+ if (form == OFFSET_TYPE)
+ {
+#if 0
+ warning ("conversion from member type");
+#endif
+ if (TREE_CODE (exp) == OFFSET_REF)
+ return default_conversion (resolve_offset_ref (exp));
+
+ dt = TREE_TYPE (dt);
+ form = TREE_CODE (dt);
+ }
+
+ if (form == REFERENCE_TYPE)
+ {
+ exp = convert_from_reference (exp);
+ dt = TREE_TYPE (exp);
+ form = TREE_CODE (dt);
+ }
+
+ if (TREE_CODE (exp) == CONST_DECL)
+ exp = DECL_INITIAL (exp);
+ else if (TREE_READONLY_DECL_P (exp))
+ {
+ exp = decl_constant_value (exp);
+ dt = TREE_TYPE (exp);
+ }
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs, since EXP is being used in non-lvalue context. */
+ if (TREE_CODE (exp) == NOP_EXPR
+ && TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0)))
+ exp = TREE_OPERAND (exp, 0);
+
+ if (form == ENUMERAL_TYPE
+ || (form == INTEGER_TYPE
+ && (TYPE_PRECISION (dt)
+ < TYPE_PRECISION (integer_type_node))))
+ {
+ /* Traditionally, unsignedness is preserved in default promotions. */
+ if (flag_traditional && TREE_UNSIGNED (dt))
+ return convert (unsigned_type_node, exp);
+ return convert (integer_type_node, exp);
+ }
+ if (flag_traditional && dt == float_type_node)
+ return convert (double_type_node, exp);
+ if (form == VOID_TYPE)
+ {
+ error ("void value not ignored as it ought to be");
+ return error_mark_node;
+ }
+ if (form == FUNCTION_TYPE || form == METHOD_TYPE)
+ {
+ return build_unary_op (ADDR_EXPR, exp, 0);
+ }
+ if (form == ARRAY_TYPE)
+ {
+ register tree adr;
+ tree restype = TREE_TYPE (dt);
+ tree ptrtype;
+
+ if (TREE_CODE (exp) == INDIRECT_REF)
+ {
+ /* Stripping away the INDIRECT_REF is not the right
+ thing to do for references... */
+ tree inner = TREE_OPERAND (exp, 0);
+ if (TREE_CODE (TREE_TYPE (inner)) == REFERENCE_TYPE)
+ inner = build1 (REFERENCE_EXPR,
+ build_pointer_type (TREE_TYPE (TREE_TYPE (inner))),
+ inner);
+ return convert (TYPE_POINTER_TO (TREE_TYPE (dt)), inner);
+ }
+
+ if (TREE_CODE (exp) == COMPOUND_EXPR)
+ {
+ tree op1 = default_conversion (TREE_OPERAND (exp, 1));
+ return build (COMPOUND_EXPR, TREE_TYPE (op1),
+ TREE_OPERAND (exp, 0), op1);
+ }
+
+ if (!lvalue_p (exp)
+ && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
+ {
+ error ("invalid use of non-lvalue array");
+ return error_mark_node;
+ }
+
+ if (TREE_READONLY (exp) || TREE_THIS_VOLATILE (exp))
+ restype = build_type_variant (restype, TREE_READONLY (exp),
+ TREE_THIS_VOLATILE (exp));
+
+ ptrtype = build_pointer_type (restype);
+
+ if (TREE_CODE (exp) == VAR_DECL)
+ {
+ /* ??? This is not really quite correct
+ in that the type of the operand of ADDR_EXPR
+ is not the target type of the type of the ADDR_EXPR itself.
+ Question is, can this lossage be avoided? */
+ adr = build1 (ADDR_EXPR, ptrtype, exp);
+ if (mark_addressable (exp) == 0)
+ return error_mark_node;
+ TREE_LITERAL (adr) = staticp (exp);
+ TREE_VOLATILE (adr) = 0; /* Default would be, same as EXP. */
+ return adr;
+ }
+ /* This way is better for a COMPONENT_REF since it can
+ simplify the offset for a component. */
+ adr = build_unary_op (ADDR_EXPR, exp, 1);
+ return convert (ptrtype, adr);
+ }
+ return exp;
+}
+\f
+/* Like `build_component_ref, but uses an already found field.
+ Must compute visibility for C_C_D. Otherwise, ok. */
+tree
+build_component_ref_1 (datum, field, protect)
+ tree datum, field;
+ int protect;
+{
+ register tree basetype = TREE_TYPE (datum);
+ register enum tree_code form = TREE_CODE (basetype);
+ register tree ref;
+
+ if (form == REFERENCE_TYPE)
+ {
+ datum = convert_from_reference (datum);
+ basetype = TREE_TYPE (datum);
+ form = TREE_CODE (basetype);
+ }
+
+ if (! IS_AGGR_TYPE_CODE (form))
+ {
+ if (form != ERROR_MARK)
+ error_with_decl (field, "request for member `%s' in something not a class, structure or union");
+ return error_mark_node;
+ }
+
+ if (TYPE_SIZE (basetype) == 0)
+ {
+ incomplete_type_error (0, basetype);
+ return error_mark_node;
+ }
+
+ /* Look up component name in the structure type definition. */
+
+ if (field == error_mark_node)
+ abort ();
+
+ if (TREE_STATIC (field))
+ return field;
+
+ if (datum == C_C_D && ! TREE_FIELD_PUBLIC (field))
+ {
+ enum visibility_type visibility
+ = compute_visibility (build_tree_list (NULL_TREE, current_class_type),
+ field);
+
+ if (visibility == visibility_private)
+ {
+ error_with_decl (field, "field `%s' is private");
+ return error_mark_node;
+ }
+ else if (visibility == visibility_protected)
+ {
+ error_with_decl (field, "field `%s' is protected");
+ return error_mark_node;
+ }
+ }
+
+ ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
+
+ if (TREE_READONLY (datum) || TREE_READONLY (field))
+ TREE_READONLY (ref) = 1;
+ if (TREE_THIS_VOLATILE (datum) || TREE_VOLATILE (field))
+ TREE_THIS_VOLATILE (ref) = 1;
+
+ return ref;
+}
+
+tree
+build_component_ref (datum, component, basetype_path, protect)
+ tree datum, component, basetype_path;
+ int protect;
+{
+ tree basetypes;
+ register tree basetype = TREE_TYPE (datum);
+ register enum tree_code form = TREE_CODE (basetype);
+ register tree field = NULL;
+ register tree ref;
+
+ if (form == REFERENCE_TYPE)
+ {
+#if 0
+ /* REFERENCE_EXPRs are not converted by `convert_from_reference'.
+ @@ Maybe that is not right. */
+ if (TREE_CODE (datum) == REFERENCE_EXPR)
+ datum = build1 (INDIRECT_REF, TREE_TYPE (basetype), datum);
+ else
+#endif
+ datum = convert_from_reference (datum);
+ basetype = TREE_TYPE (datum);
+ form = TREE_CODE (basetype);
+ }
+
+ /* First, see if there is a field or component with name COMPONENT. */
+ if (TREE_CODE (component) == TREE_LIST)
+ {
+ assert (!(TREE_CHAIN (component) == NULL_TREE
+ && TREE_CHAIN (TREE_VALUE (component)) == NULL_TREE));
+ return build (COMPONENT_REF, TREE_TYPE (component), datum, component);
+ }
+ if (TREE_CODE (component) == TYPE_EXPR)
+ return build_component_type_expr (datum, component, NULL_TREE, protect);
+
+ if (! IS_AGGR_TYPE_CODE (form))
+ {
+ if (form != ERROR_MARK)
+ error ("request for member `%s' in something not a class, structure or union",
+ IDENTIFIER_POINTER (component));
+ return error_mark_node;
+ }
+
+ if (TYPE_SIZE (basetype) == 0)
+ {
+ incomplete_type_error (0, basetype);
+ return error_mark_node;
+ }
+
+ /* Look up component name in the structure type definition. */
+ if (basetype_path == NULL_TREE)
+ basetype_path = CLASSTYPE_AS_LIST (basetype);
+ basetypes = basetype_path;
+ field = lookup_field (basetypes, component,
+ protect && ! VFIELD_NAME_P (component));
+
+ if (field == error_mark_node)
+ return error_mark_node;
+
+ if (field == NULL_TREE)
+ {
+ /* Not found as a data field, look for it as a method. If found,
+ then if this is the only possible one, return it, else
+ report ambiguity error. */
+ tree fields = lookup_fnfields (basetype_path, component, 1);
+ tree basename = TYPE_NAME (basetype);
+ if (fields)
+ {
+ if (TREE_CHAIN (fields) == NULL_TREE
+ && TREE_CHAIN (TREE_VALUE (fields)) == NULL_TREE)
+ {
+ enum visibility_type visibility;
+
+ /* Unique, so use this one now. */
+ basetype = TREE_PURPOSE (fields);
+ field = TREE_VALUE (fields);
+ visibility = compute_visibility (TREE_PURPOSE (fields), field);
+ if (visibility == visibility_public)
+ {
+ if (DECL_VIRTUAL_P (field)
+ && ! resolves_to_fixed_type_p (datum))
+ {
+ tree addr = build_unary_op (ADDR_EXPR, datum, 0);
+ addr = convert_pointer_to (DECL_VCONTEXT (field), addr);
+ datum = build_indirect_ref (addr);
+ assert (datum != error_mark_node);
+ field = build_vfn_ref (&addr, datum, DECL_VINDEX (field));
+ }
+ return field;
+ }
+ if (visibility == visibility_protected)
+ error_with_decl (field, "member function `%s' is protected");
+ else
+ error_with_decl (field, "member function `%s' is private");
+ return error_mark_node;
+ }
+ else
+ return build (COMPONENT_REF, unknown_type_node, datum, fields);
+ }
+ if (TREE_CODE (basename) == TYPE_DECL)
+ basename = DECL_NAME (basename);
+
+ if (OPERATOR_TYPENAME_P (component))
+ error ("%s `%s' has no such type conversion operator",
+ form == RECORD_TYPE ? "structure" : "union",
+ IDENTIFIER_POINTER (basename));
+ else
+ error (form == RECORD_TYPE
+ ? "structure `%s' has no member named `%s'"
+ : "union `%s' has no member named `%s'",
+ IDENTIFIER_POINTER (basename),
+ IDENTIFIER_POINTER (component));
+ return error_mark_node;
+ }
+ else if (TREE_TYPE (field) == error_mark_node)
+ return error_mark_node;
+
+ if (TREE_CODE (field) == VAR_DECL || TREE_CODE (field) == CONST_DECL)
+ {
+ TREE_USED (field) = 1;
+ return field;
+ }
+
+ if (DECL_FIELD_CONTEXT (field) != basetype
+ && (TYPE_USES_MULTIPLE_INHERITANCE (basetype)
+ || TYPE_USES_VIRTUAL_BASECLASSES (basetype)))
+ {
+ tree addr = build_unary_op (ADDR_EXPR, datum, 0);
+ addr = convert_pointer_to (DECL_FIELD_CONTEXT (field), addr);
+ datum = build_indirect_ref (addr);
+ assert (datum != error_mark_node);
+ }
+ ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
+
+ if (TREE_READONLY (datum) || TREE_READONLY (field))
+ TREE_READONLY (ref) = 1;
+ if (TREE_THIS_VOLATILE (datum) || TREE_VOLATILE (field))
+ TREE_THIS_VOLATILE (ref) = 1;
+ return ref;
+}
+\f
+/* Given an expression PTR for a pointer, return an expression
+ for the value pointed to.
+ ERRORSTRING is the name of the operator to appear in error messages.
+
+ This function may need to overload OPERATOR_FNNAME.
+ Must also handle REFERENCE_TYPEs for C++. */
+
+tree
+build_x_indirect_ref (ptr, errorstring)
+ tree ptr;
+ char *errorstring;
+{
+ tree rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr);
+
+ if (rval) return rval;
+ return build_indirect_ref (ptr, errorstring);
+}
+
+tree
+build_indirect_ref (ptr, errorstring)
+ tree ptr;
+ char *errorstring;
+{
+ register tree pointer = default_conversion (ptr);
+ register tree dt = TREE_TYPE (pointer);
+
+ if (ptr == current_class_decl)
+ return C_C_D;
+
+ if (TREE_CODE (dt) == POINTER_TYPE || TREE_CODE (dt) == REFERENCE_TYPE)
+ if (TREE_CODE (pointer) == ADDR_EXPR
+ && (TREE_TYPE (TREE_OPERAND (pointer, 0))
+ == TREE_TYPE (dt)))
+ return TREE_OPERAND (pointer, 0);
+ else
+ {
+ tree t = TREE_TYPE (dt);
+ register tree ref = build1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (t), pointer);
+
+ TREE_READONLY (ref) = TREE_READONLY (t);
+ TREE_VOLATILE (ref) = TREE_VOLATILE (t) || TREE_VOLATILE (pointer);
+ TREE_THIS_VOLATILE (ref) = TREE_VOLATILE (t);
+ return ref;
+ }
+ else if (pointer != error_mark_node)
+ error ("invalid type argument of `%s'", errorstring);
+ return error_mark_node;
+}
+
+/* This handles expressions of the form "a[i]", which denotes
+ an array reference.
+
+ This is logically equivalent in C to *(a+i), but we may do it differently.
+ If A is a variable or a member, we generate a primitive ARRAY_REF.
+ This avoids forcing the array out of registers, and can work on
+ arrays that are not lvalues (for example, members of structures returned
+ by functions).
+
+ If INDEX is of some user-defined type, it must be converted to
+ integer type. Otherwise, to make a compatible PLUS_EXPR, it
+ will inherit the type of the array, which will be some pointer type. */
+
+tree
+build_x_array_ref (array, index)
+ tree array, index;
+{
+ tree rval;
+
+ rval = build_opfncall (ARRAY_REF, LOOKUP_NORMAL, array, index);
+ if (rval)
+ return rval;
+ return build_array_ref (array, index);
+}
+
+tree
+build_array_ref (array, index)
+ tree array, index;
+{
+ tree itype;
+ tree rval;
+
+ if (index == 0)
+ {
+ error ("subscript missing in array reference");
+ return error_mark_node;
+ }
+
+ itype = TREE_TYPE (index);
+ if (TREE_CODE (itype) == REFERENCE_TYPE)
+ {
+ index = convert_from_reference (index);
+ itype = TREE_TYPE (index);
+ }
+
+ if (IS_AGGR_TYPE (itype))
+ if (TYPE_HAS_INT_CONVERSION (itype))
+ index = build_type_conversion (CONVERT_EXPR, integer_type_node, index, 1);
+ else
+ {
+ error_with_aggr_type (itype, "type `%s' requires integer conversion for array indexing");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
+ && TREE_CODE (array) != INDIRECT_REF)
+ {
+ index = default_conversion (index);
+ if (index != error_mark_node
+ && TREE_CODE (TREE_TYPE (index)) != INTEGER_TYPE)
+ {
+ error ("array subscript is not an integer");
+ return error_mark_node;
+ }
+
+ /* An array that is indexed by a non-constant
+ cannot be stored in a register; we must be able to do
+ address arithmetic on its address.
+ Likewise an array of elements of variable size. */
+ if (TREE_CODE (index) != INTEGER_CST
+ || (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST))
+ {
+ if (mark_addressable (array) == 0)
+ return error_mark_node;
+ }
+
+ if (pedantic && !lvalue_p (array))
+ warning ("ANSI C forbids subscripting non-lvalue array");
+
+ if (pedantic)
+ {
+ tree foo = array;
+ while (TREE_CODE (foo) == COMPONENT_REF)
+ foo = TREE_OPERAND (foo, 0);
+ if (TREE_CODE (foo) == VAR_DECL && TREE_REGDECL (foo))
+ warning ("ANSI C forbids subscripting non-lvalue array");
+ }
+
+ rval = build (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)), array, index);
+ /* Array ref is const/volatile if the array elements are. */
+ TREE_READONLY (rval) |= TREE_READONLY (TREE_TYPE (TREE_TYPE (array)));
+ TREE_VOLATILE (rval) |= TREE_VOLATILE (TREE_TYPE (TREE_TYPE (array)));
+ TREE_THIS_VOLATILE (rval) |= TREE_VOLATILE (TREE_TYPE (TREE_TYPE (array)));
+ return require_complete_type (fold (rval));
+ }
+
+ {
+ tree ar = default_conversion (array);
+ tree ind = default_conversion (index);
+
+ if ((TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE)
+ || (TREE_CODE (TREE_TYPE (ind)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (ar)) != INTEGER_TYPE))
+ {
+ error ("array subscript is not an integer");
+ return error_mark_node;
+ }
+
+ return build_indirect_ref (build_binary_op_nodefault (PLUS_EXPR, ar, ind, PLUS_EXPR),
+ "array indexing");
+ }
+}
+\f
+/* Build a function call to function FUNCTION with parameters PARAMS.
+ PARAMS is a list--a chain of TREE_LIST nodes--in which the
+ TREE_VALUE of each node is a parameter-expression.
+ FUNCTION's data type may be a function type or a pointer-to-function.
+
+ For C++: If FUNCTION's data type is a TREE_LIST, then the tree list
+ is the list of possible methods that FUNCTION could conceivably
+ be. If the list of methods comes from a class, then it will be
+ a list of lists (where each element is associated with the class
+ that produced it), otherwise it will be a simple list (for
+ functions overloaded in global scope).
+
+ In the first case, TREE_VALUE (function) is the head of one of those
+ lists, and TREE_PURPOSE is the name of the function.
+
+ In the second case, TREE_PURPOSE (function) is the function's
+ name directly.
+
+ DECL is the class instance variable, usually CURRENT_CLASS_DECL. */
+
+tree
+build_x_function_call (function, params, decl)
+ tree function, params, decl;
+{
+ tree type = TREE_TYPE (function);
+ int may_be_method
+ = ((TREE_CODE (function) == TREE_LIST
+ && current_class_type != NULL_TREE
+ && IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function)) == function)
+ || TREE_CODE (function) == IDENTIFIER_NODE
+ || TREE_CODE (type) == METHOD_TYPE);
+
+ /* Handle methods, friends, and overloaded functions, respectively. */
+ if (may_be_method)
+ {
+ if (TREE_CODE (function) == FUNCTION_DECL)
+ function = DECL_ORIGINAL_NAME (function);
+ else if (TREE_CODE (function) == TREE_LIST)
+ {
+#if 0
+ if (TREE_CODE (TREE_VALUE (function)) == TREE_LIST)
+ function = TREE_PURPOSE (TREE_VALUE (function));
+ else
+ function = TREE_PURPOSE (function);
+#else
+ assert (TREE_CODE (TREE_VALUE (function)) == FUNCTION_DECL);
+ function = TREE_PURPOSE (function);
+#endif
+ }
+ else if (TREE_CODE (function) != IDENTIFIER_NODE)
+ {
+ /* Call via a pointer to member function. */
+ if (decl == NULL_TREE)
+ {
+ error ("pointer to member function called, but not in class scope");
+ return error_mark_node;
+ }
+ function = build (OFFSET_REF, TREE_TYPE (type), NULL_TREE, function);
+ goto do_x_function;
+ }
+
+ /* this is an abbreviated method call.
+ must go through here in case it is a virtual function.
+ @@ Perhaps this could be optimized. */
+
+ if (decl == NULL_TREE)
+ {
+ if (current_class_type == NULL_TREE)
+ {
+ error ("object missing in call to method `%s'",
+ IDENTIFIER_POINTER (function));
+ return error_mark_node;
+ }
+ /* Yow: call from a static member function. */
+ decl = build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type), error_mark_node);
+ }
+
+ return build_method_call (decl, function, params, NULL_TREE, LOOKUP_NORMAL);
+ }
+ else if (TREE_CODE (function) == COMPONENT_REF
+ && type == unknown_type_node)
+ {
+ function = TREE_PURPOSE (TREE_OPERAND (function, 1));
+ return build_method_call (decl, function, params, NULL_TREE, LOOKUP_NORMAL);
+ }
+ else if (TREE_CODE (function) == TREE_LIST)
+ {
+ if (TREE_CHAIN (function) != NULL_TREE)
+ return build_overload_call (TREE_PURPOSE (function), params, 1, 0);
+ else if (TREE_VALUE (function) != NULL_TREE)
+ function = TREE_VALUE (function);
+ else
+ {
+ error ("function `%s' declared overloaded, but no definitions appear with which to resolve it",
+ IDENTIFIER_POINTER (TREE_PURPOSE (function)));
+ return error_mark_node;
+ }
+ }
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
+ && (TREE_CODE (function) == VAR_DECL
+ || TREE_CODE (function) == PARM_DECL
+ || TREE_CODE (function) == FIELD_DECL))
+ {
+ error_with_decl (function, "call via pointer-to-member-function `%s' must be composed with object");
+ return error_mark_node;
+ }
+
+ do_x_function:
+ if (TREE_CODE (function) == OFFSET_REF)
+ {
+ /* If the component is a data element (or a virtual function), we play
+ games here to make things work. */
+ tree decl_addr;
+
+ if (TREE_OPERAND (function, 0))
+ decl = TREE_OPERAND (function, 0);
+ else
+ decl = C_C_D;
+
+ decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
+ function = get_member_function (&decl_addr, decl, TREE_OPERAND (function, 1));
+ params = tree_cons (NULL_TREE, decl_addr, params);
+ return build_function_call (function, params);
+ }
+
+ type = TREE_TYPE (function);
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+
+ if (TYPE_LANG_SPECIFIC (type) && TYPE_OVERLOADS_CALL_EXPR (type))
+ return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params);
+
+ if (may_be_method)
+ {
+ tree ctypeptr = TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (TREE_TYPE (function)));
+ if (decl == NULL_TREE)
+ {
+ if (current_function_decl
+ && DECL_STATIC_FUNCTION_P (current_function_decl))
+ error ("invalid call to member function needing `this' in static member function scope");
+ else
+ error ("pointer to member function called, but not in class scope");
+ return error_mark_node;
+ }
+ if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE)
+ {
+ decl = build_unary_op (ADDR_EXPR, decl, 0);
+ decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
+ }
+ else
+ decl = build_c_cast (ctypeptr, decl);
+ params = tree_cons (NULL_TREE, decl, params);
+ }
+
+ return build_function_call (function, params);
+}
+
+tree
+build_function_call (function, params)
+ tree function, params;
+{
+ register tree fntype, fndecl;
+ register tree value_type;
+ register tree coerced_params;
+ tree actualparameterlist ();
+ int is_method;
+
+#ifdef FIELD_XREF
+ if (TREE_CODE(function) == FUNCTION_DECL)
+ FIELD_xref_call(current_function_decl,
+ IDENTIFIER_POINTER(DECL_NAME(function)));
+#endif
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs, since FUNCTION is used in non-lvalue context. */
+ if (TREE_CODE (function) == NOP_EXPR
+ && TREE_TYPE (function) == TREE_TYPE (TREE_OPERAND (function, 0)))
+ function = TREE_OPERAND (function, 0);
+
+ if (TREE_CODE (function) == FUNCTION_DECL)
+ fndecl = function;
+ else
+ fndecl = NULL_TREE;
+
+ /* Convert anything with function type to a pointer-to-function. */
+ if (TREE_CODE (function) == FUNCTION_DECL)
+ {
+ if (pedantic
+ && IDENTIFIER_LENGTH (DECL_NAME (function)) == 4
+ && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (function)), "main"))
+ {
+ error ("cannot call `main' from within program");
+ return error_mark_node;
+ }
+
+ /* Differs from default_conversion by not setting TREE_ADDRESSABLE
+ (because calling an inline function does not mean the function
+ needs to be separately compiled). */
+
+ if (! TREE_INLINE (function))
+ TREE_USED (function) = 1;
+
+ function = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (function)),
+ function);
+ }
+ else
+ {
+ if (function == error_mark_node)
+ return error_mark_node;
+ function = default_conversion (function);
+ }
+
+ fntype = TREE_TYPE (function);
+
+ is_method = (TREE_CODE (fntype) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (fntype)) == METHOD_TYPE);
+
+ if (!(TREE_CODE (fntype) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE || is_method)))
+ {
+ error ("called object is not a function");
+ return error_mark_node;
+ }
+
+ /* fntype now gets the type of function pointed to. */
+ fntype = TREE_TYPE (fntype);
+
+ /* Convert the parameters to the types declared in the
+ function prototype, or apply default promotions. */
+
+ coerced_params = actualparameterlist (NULL_TREE, TYPE_ARG_TYPES (fntype), params, fndecl, LOOKUP_NORMAL);
+
+ /* Recognize certain built-in functions so we can make tree-codes
+ other than CALL_EXPR. We do this when it enables fold-const.c
+ to do something useful. */
+
+ if (TREE_CODE (function) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+ switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0)))
+ {
+ case BUILT_IN_ABS:
+ case BUILT_IN_LABS:
+ case BUILT_IN_FABS:
+ if (coerced_params == 0)
+ return integer_zero_node;
+ return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
+ }
+
+ value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
+
+ if (is_method)
+ {
+ tree parm = TREE_VALUE (coerced_params);
+ tree parmtype = TREE_TYPE (parm);
+ if (parmtype == error_mark_node)
+ return error_mark_node;
+
+ parmtype = TREE_TYPE (parmtype);
+ if (TYPE_NEEDS_WRAPPER (parmtype))
+ {
+ if (fndecl == NULL_TREE || ! WRAPPER_NAME_P (DECL_NAME (fndecl)))
+ {
+ int bytecount = get_arglist_len_in_bytes (coerced_params);
+
+ params = tree_cons (NULL_TREE, build_int_2 (bytecount, 0),
+ tree_cons (NULL_TREE, function, TREE_CHAIN (coerced_params)));
+
+ return build_method_call (TREE_VALUE (coerced_params),
+ wrapper_name, params,
+ NULL_TREE, LOOKUP_NORMAL);
+ }
+ }
+ }
+ {
+ register tree result =
+ build (CALL_EXPR, value_type, function, coerced_params, NULL_TREE);
+
+ TREE_VOLATILE (result) = 1;
+ TREE_RAISES (result) |= !! TYPE_RAISES_EXCEPTIONS (fntype);
+ if (value_type == void_type_node)
+ return result;
+ return require_complete_type (result);
+ }
+}
+\f
+/* Convert the actual parameter expressions in the list VALUES
+ to the types in the list TYPELIST.
+ If parmdecls is exhausted, or when an element has NULL as its type,
+ perform the default conversions.
+
+ RETURN_LOC is the location of the return value, if known, NULL_TREE
+ otherwise. This is useful in the case where we can avoid creating
+ a temporary variable in the case where we can initialize the return
+ value directly. If we are not eliding constructors, then we set this
+ to NULL_TREE to avoid this avoidance.
+
+ NAME is an IDENTIFIER_NODE or 0. It is used only for error messages.
+
+ This is also where warnings about wrong number of args are generated.
+
+ Return a list of expressions for the parameters as converted.
+
+ Both VALUES and the returned value are chains of TREE_LIST nodes
+ with the elements of the list in the TREE_VALUE slots of those nodes.
+
+ In C++, unspecified trailing parameters can be filled in with their
+ default arguments, if such were specified. Do so here. */
+
+tree
+actualparameterlist (return_loc, typelist, values, fndecl, flags)
+ tree return_loc, typelist, values, fndecl;
+ int flags;
+{
+ register tree typetail, valtail;
+ register tree result = NULL_TREE;
+ char *called_thing;
+ int maybe_raises = 0;
+
+ if (! flag_elide_constructors)
+ return_loc = 0;
+
+ if (fndecl)
+ if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
+ if (TREE_TYPE (DECL_ORIGINAL_NAME (fndecl)))
+ called_thing = "constructor";
+ else
+ called_thing = "member function";
+ else
+ called_thing = "function";
+
+ for (valtail = values, typetail = typelist;
+ valtail;
+ valtail = TREE_CHAIN (valtail))
+ {
+ register tree type = typetail ? TREE_VALUE (typetail) : 0;
+ register tree val = TREE_VALUE (valtail);
+ register tree parm;
+
+ if (type == void_type_node)
+ {
+ if (fndecl)
+ {
+ char *buf = (char *)alloca (80);
+ sprintf (buf, "too many arguments to %s `%%s'", called_thing);
+ error_with_decl (fndecl, buf);
+ error ("at this point in file");
+ }
+ else
+ error ("too many arguments to function");
+ /* In case anybody wants to know if this argument
+ list is valid. */
+ if (result)
+ TREE_TYPE (result) = error_mark_node;
+ break;
+ }
+
+ /* The tree type of the parameter being passed may not yet be
+ known. In this case, its type is TYPE_UNKNOWN, and will
+ be instantiated by the type given by TYPE. If TYPE
+ is also NULL, the tree type of VAL is ERROR_MARK_NODE. */
+ if (type && type_unknown_p (val))
+ val = require_instantiated_type (type, val, integer_zero_node);
+ else if (type_unknown_p (val))
+ {
+
+ if (TREE_CODE (val) == TREE_LIST
+ && TREE_CHAIN (val) == NULL_TREE
+ && (TREE_TYPE (val) == unknown_type_node
+ || TREE_CHAIN (TREE_VALUE (val)) == NULL_TREE))
+ /* Instantiates automatically. */
+ val = TREE_VALUE (val);
+ else
+ {
+ error ("insufficient type information in parameter list");
+ val = integer_zero_node;
+ }
+ }
+
+ {
+ /* Convert FUNCTION_DECLs for virtual functions
+ to proper representation. */
+ tree basetype = NULL_TREE;
+ tree ttype = TREE_TYPE (val);
+
+ if (TREE_CODE (ttype) == METHOD_TYPE)
+ basetype = TYPE_METHOD_BASETYPE (ttype);
+ else if (TREE_CODE (ttype) == OFFSET_TYPE)
+ basetype = TYPE_OFFSET_BASETYPE (ttype);
+
+ /* If BASETYPE is set here, default_conversion will do the
+ actual conversion for us. */
+ if (basetype && TREE_CODE (val) != OFFSET_REF)
+ {
+ val = build (OFFSET_REF, ttype,
+ build1 (NOP_EXPR, basetype, error_mark_node), val);
+ type = build_pointer_type (ttype);
+ }
+ else if (TREE_CODE (ttype) == FUNCTION_TYPE)
+ type = build_pointer_type (ttype);
+ }
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs, since VAL is used in non-lvalue context. */
+ if (TREE_CODE (val) == NOP_EXPR
+ && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0)))
+ val = TREE_OPERAND (val, 0);
+
+ if ((type == 0 || TREE_CODE (type) != REFERENCE_TYPE)
+ && (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE))
+ val = default_conversion (val);
+
+ val = require_complete_type (val);
+
+ maybe_raises |= TREE_RAISES (val);
+
+ if (type != 0)
+ {
+ /* Formal parm type is specified by a function prototype. */
+ tree parmval;
+
+ if (TYPE_SIZE (type) == 0)
+ {
+ error ("parameter type of called function is incomplete");
+ parmval = val;
+ }
+ else
+ {
+#ifdef PROMOTE_PROTOTYPES
+ /* Rather than truncating and then reextending,
+ convert directly to int, if that's the type we will want. */
+ if (! flag_traditional
+ && TREE_CODE (type) == INTEGER_TYPE
+ && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+ type = integer_type_node;
+#endif
+ parmval = convert_for_initialization (return_loc, type, val,
+ "argument passing", flags);
+#ifdef PROMOTE_PROTOTYPES
+ if (TREE_CODE (type) == INTEGER_TYPE
+ && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+ parmval = default_conversion (parmval);
+#endif
+ }
+ parm = build_tree_list (0, parmval);
+ }
+ else
+ {
+ if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
+ val = convert_from_reference (val);
+
+ if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
+ && (TYPE_PRECISION (TREE_TYPE (val))
+ < TYPE_PRECISION (double_type_node)))
+ /* Convert `float' to `double'. */
+ parm = build_tree_list (NULL_TREE, convert (double_type_node, val));
+ else if (TYPE_LANG_SPECIFIC (TREE_TYPE (val))
+ && (TYPE_GETS_INIT_REF (TREE_TYPE (val))
+ || TYPE_GETS_ASSIGN_REF (TREE_TYPE (val))))
+ {
+ if (pedantic)
+ error_with_aggr_type (TREE_TYPE (val), "cannot pass objects of type `%s' through `...'");
+ else
+ warning ("cannot pass objects of type `%s' through `...'",
+ TYPE_NAME_STRING (TREE_TYPE (val)));
+ parm = build_tree_list (NULL_TREE, val);
+ }
+ else
+ /* Convert `short' and `char' to full-size `int'. */
+ parm = build_tree_list (NULL_TREE, default_conversion (val));
+ }
+
+ result = chainon (result, parm);
+ if (typetail)
+ typetail = TREE_CHAIN (typetail);
+ }
+
+ if (typetail != 0 && typetail != void_list_node)
+ {
+ /* See if there are default arguments that can be used */
+ if (TREE_PURPOSE (typetail))
+ {
+ while (typetail != void_list_node)
+ {
+ tree type = TREE_VALUE (typetail);
+ tree val = TREE_PURPOSE (typetail);
+ tree parm, parmval;
+
+ if (val == NULL_TREE)
+ parmval = error_mark_node;
+ else if (TREE_CODE (val) == CONSTRUCTOR)
+ {
+ parmval = digest_init (type, val, NULL_TREE);
+ parmval = convert_for_initialization (return_loc, type, parmval, "default constructor", flags);
+ }
+ else
+ {
+ parmval = convert_for_initialization (return_loc, type, val,
+ "default argument", flags);
+#ifdef PROMOTE_PROTOTYPES
+ if (TREE_CODE (type) == INTEGER_TYPE
+ && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+ parmval = default_conversion (parmval);
+#endif
+ }
+ maybe_raises |= TREE_RAISES (parmval);
+ parm = build_tree_list (0, parmval);
+ result = chainon (result, parm);
+ typetail = TREE_CHAIN (typetail);
+ /* ends with `...'. */
+ if (typetail == NULL_TREE)
+ break;
+ }
+ }
+ else
+ {
+ if (fndecl)
+ {
+ char *buf = (char *)alloca (32 + strlen (called_thing));
+ sprintf (buf, "too few arguments to %s `%%s'", called_thing);
+ error_with_decl (fndecl, buf);
+ error ("at this point in file");
+ }
+ else
+ error ("too few arguments to function");
+ return error_mark_list;
+ }
+ }
+ if (result)
+ TREE_RAISES (result) = maybe_raises;
+
+ return result;
+}
+\f
+/* Build a binary-operation expression, after performing default
+ conversions on the operands. CODE is the kind of expression to build. */
+
+tree
+build_x_binary_op (code, arg1, arg2)
+ enum tree_code code;
+ tree arg1, arg2;
+{
+ tree rval;
+
+ if (rval = build_opfncall (code, LOOKUP_PROTECT, arg1, arg2))
+ return rval;
+ rval = build_binary_op (code, arg1, arg2);
+ if (rval == error_mark_node)
+ build_opfncall (code, LOOKUP_NORMAL, arg1, arg2);
+ return rval;
+}
+
+tree
+build_binary_op (code, arg1, arg2)
+ enum tree_code code;
+ tree arg1, arg2;
+{
+ tree type1, type2;
+ tree args[2];
+ arg1 = default_conversion (arg1);
+ arg2 = default_conversion (arg2);
+
+ if (type_unknown_p (arg1))
+ {
+ arg1 = instantiate_type (TREE_TYPE (arg2), arg1, 1);
+ arg1 = default_conversion (arg1);
+ }
+ else
+ {
+ arg2 = require_instantiated_type (TREE_TYPE (arg1), arg2, error_mark_node);
+ arg2 = default_conversion (arg2);
+ }
+
+ type1 = TREE_TYPE (arg1);
+ type2 = TREE_TYPE (arg2);
+
+ args[0] = arg1;
+ args[1] = arg2;
+
+ if (IS_AGGR_TYPE (type1) && IS_AGGR_TYPE (type2))
+ {
+ /* Try to convert this to something reasonable. */
+ if (! build_default_binary_type_conversion (code, &args[0], &args[1]))
+ return error_mark_node;
+ }
+ else if (IS_AGGR_TYPE (type1) || IS_AGGR_TYPE (type2))
+ {
+ int convert_index = IS_AGGR_TYPE (type2);
+ /* Avoid being tripped up by things like (ARG1 != 0). */
+ tree types[2], try;
+
+ types[0] = type1; types[1] = type2;
+ try = build_type_conversion (code, types[convert_index ^ 1],
+ args[convert_index], 1);
+
+ if (try == 0
+ && arg2 == integer_zero_node
+ && (code == NE_EXPR || code == EQ_EXPR))
+ try = build_type_conversion (code, ptr_type_node,
+ args[convert_index], 1);
+ if (try == 0)
+ {
+ error_with_aggr_type (types[convert_index], "type conversion required for type `%s'");
+ return error_mark_node;
+ }
+ if (try == error_mark_node)
+ error ("ambiguous pointer conversion");
+ args[convert_index] = try;
+ }
+
+ return build_binary_op_nodefault (code, args[0], args[1], code);
+}
+
+/* Build a binary-operation expression without default conversions.
+ CODE is the kind of expression to build.
+ This function differs from `build' in several ways:
+ the data type of the result is computed and recorded in it,
+ warnings are generated if arg data types are invalid,
+ special handling for addition and subtraction of pointers is known,
+ and some optimization is done (operations on narrow ints
+ are done in the narrower type when that gives the same result).
+ Constant folding is also done before the result is returned.
+
+ ERROR_CODE is the code that determines what to say in error messages.
+ It is usually, but not always, the same as CODE.
+
+ Note that the operands will never have enumeral types
+ because either they have just had the default conversions performed
+ or they have both just been converted to some other type in which
+ the arithmetic is to be done.
+
+ C++: must do special pointer arithmetic when implementing
+ multiple inheritance. */
+
+tree
+build_binary_op_nodefault (code, op0, op1, error_code)
+ enum tree_code code;
+ tree op0, op1;
+ enum tree_code error_code;
+{
+ tree dt0 = datatype (op0), dt1 = datatype (op1);
+
+ /* The expression codes of the data types of the arguments tell us
+ whether the arguments are integers, floating, pointers, etc. */
+ register enum tree_code code0 = TREE_CODE (dt0);
+ register enum tree_code code1 = TREE_CODE (dt1);
+
+ /* Expression code to give to the expression when it is built.
+ Normally this is CODE, which is what the caller asked for,
+ but in some special cases we change it. */
+ register enum tree_code resultcode = code;
+
+ /* Data type in which the computation is to be performed.
+ In the simplest cases this is the common type of the arguments. */
+ register tree result_type = NULL;
+
+ /* Nonzero means operands have already been type-converted
+ in whatever way is necessary.
+ Zero means they need to be converted to RESULT_TYPE. */
+ int converted = 0;
+
+ /* Nonzero means after finally constructing the expression
+ give it this type. Otherwise, give it type RESULT_TYPE. */
+ tree final_type = 0;
+
+ /* Nonzero if this is an operation like MIN or MAX which can
+ safely be computed in short if both args are promoted shorts.
+ Also implies COMMON.
+ -1 indicates a bitwise operation; this makes a difference
+ in the exact conditions for when it is safe to do the operation
+ in a narrower mode. */
+ int shorten = 0;
+
+ /* Nonzero if this is a comparison operation;
+ if both args are promoted shorts, compare the original shorts.
+ Also implies COMMON. */
+ int short_compare = 0;
+
+ /* Nonzero if this is a right-shift operation, which can be computed on the
+ original short and then promoted if the operand is a promoted short. */
+ int short_shift = 0;
+
+ /* Nonzero means set RESULT_TYPE to the common type of the args. */
+ int common = 0;
+
+ /* If an error was already reported for one of the arguments,
+ avoid reporting another error. */
+
+ if (code0 == ERROR_MARK || code1 == ERROR_MARK)
+ return error_mark_node;
+
+ switch (code)
+ {
+ case PLUS_EXPR:
+ /* Handle the pointer + int case. */
+ if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+ return pointer_int_sum (PLUS_EXPR, op0, op1);
+ else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
+ return pointer_int_sum (PLUS_EXPR, op1, op0);
+ else
+ common = 1;
+ break;
+
+ case MINUS_EXPR:
+ /* Subtraction of two similar pointers.
+ We must subtract them as integers, then divide by object size. */
+ if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
+ && comp_target_types (dt0, dt1, 1))
+ return pointer_diff (op0, op1);
+ /* Handle pointer minus int. Just like pointer plus int. */
+ else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+ return pointer_int_sum (MINUS_EXPR, op0, op1);
+ else
+ common = 1;
+ break;
+
+ case MULT_EXPR:
+ common = 1;
+ break;
+
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ {
+ if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
+ resultcode = RDIV_EXPR;
+ else
+ shorten = 1;
+ common = 1;
+ }
+ break;
+
+ case BIT_AND_EXPR:
+ case BIT_ANDTC_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+ shorten = -1;
+ /* If one operand is a constant, and the other is a short type
+ that has been converted to an int,
+ really do the work in the short type and then convert the
+ result to int. If we are lucky, the constant will be 0 or 1
+ in the short type, making the entire operation go away. */
+ if (TREE_CODE (op0) == INTEGER_CST
+ && TREE_CODE (op1) == NOP_EXPR
+ && TYPE_PRECISION (dt1) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0)))
+ && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0))))
+ {
+ final_type = result_type;
+ op1 = TREE_OPERAND (op1, 0);
+ result_type = TREE_TYPE (op1);
+ }
+ if (TREE_CODE (op1) == INTEGER_CST
+ && TREE_CODE (op0) == NOP_EXPR
+ && TYPE_PRECISION (dt0) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0)))
+ && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
+ {
+ final_type = result_type;
+ op0 = TREE_OPERAND (op0, 0);
+ result_type = TREE_TYPE (op0);
+ }
+ break;
+
+ case TRUNC_MOD_EXPR:
+ if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+ shorten = 1;
+ break;
+
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE || code0 == REAL_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE || code1 == REAL_TYPE))
+ {
+ /* Result of these operations is always an int,
+ but that does not mean the operands should be
+ converted to ints! */
+ result_type = integer_type_node;
+ op0 = truthvalue_conversion (op0);
+ op1 = truthvalue_conversion (op1);
+ converted = 1;
+
+ /* If these two expressions perform the same operation
+ on what are (or could be given alignment constraints) parts of
+ the same word, try chaining the operations. */
+ if (optimize)
+ {
+ tree rval;
+
+ if (TREE_CODE (op0) == TREE_CODE (op1))
+ {
+ /* Do they look like (x.p == y.p && x.q == y.q)
+ or (x.p != y.p || x.q != y.q). */
+ if (((code == TRUTH_ANDIF_EXPR && TREE_CODE (op0) == EQ_EXPR)
+ || (code == TRUTH_ORIF_EXPR && TREE_CODE (op0) == NE_EXPR))
+ && (rval = merge_component_comparisons (code, op0, op1)))
+ return rval;
+ }
+ if (TREE_CODE (op0) == code
+ && TREE_CODE (TREE_OPERAND (op0, 1)) == TREE_CODE (op1))
+ /* Associate the operation. */
+ {
+ /* Now try to simplify right-hand term. */
+ if (((code == TRUTH_ANDIF_EXPR && TREE_CODE (op1) == EQ_EXPR)
+ || (code == TRUTH_ORIF_EXPR && TREE_CODE (op1) == NE_EXPR))
+ && (rval = merge_component_comparisons (code, TREE_OPERAND (op0, 1), op1)))
+ {
+ TREE_OPERAND (op0, 1) = rval;
+ return op0;
+ }
+ }
+ }
+ }
+ break;
+
+ /* Shift operations: result has same type as first operand;
+ always convert second operand to int.
+ Also set SHORT_SHIFT if shifting rightward. */
+
+ case RSHIFT_EXPR:
+ if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+ {
+ result_type = dt0;
+ if (TREE_CODE (op1) == INTEGER_CST
+ && TREE_INT_CST_LOW (op1) > 0)
+ short_shift = 1;
+ /* Convert the shift-count to an integer, regardless of
+ size of value being shifted. */
+ if (TREE_TYPE (op1) != integer_type_node)
+ op1 = convert (integer_type_node, op1);
+ }
+ break;
+
+ case LSHIFT_EXPR:
+ if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+ {
+ result_type = dt0;
+ if (TREE_CODE (op1) == INTEGER_CST
+ && TREE_INT_CST_LOW (op1) < 0)
+ short_shift = 1;
+ /* Convert the shift-count to an integer, regardless of
+ size of value being shifted. */
+ if (TREE_TYPE (op1) != integer_type_node)
+ op1 = convert (integer_type_node, op1);
+ }
+ break;
+
+ case RROTATE_EXPR:
+ case LROTATE_EXPR:
+ if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+ {
+ result_type = dt0;
+ /* Convert the shift-count to an integer, regardless of
+ size of value being shifted. */
+ if (TREE_TYPE (op1) != integer_type_node)
+ op1 = convert (integer_type_node, op1);
+ }
+ break;
+
+ case EQ_EXPR:
+ case NE_EXPR:
+ /* Result of comparison is always int,
+ but don't convert the args to int! */
+ result_type = integer_type_node;
+ converted = 1;
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ short_compare = 1;
+ else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
+ {
+ register tree tt0 = TYPE_MAIN_VARIANT (TREE_TYPE (dt0));
+ register tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (dt1));
+ /* Anything compares with void *. void * compares with anything.
+ Otherwise, the targets must be the same. */
+ if (tt0 != tt1 && IS_AGGR_TYPE (tt0) && IS_AGGR_TYPE (tt1))
+ {
+ tree base = common_base_type (tt0, tt1);
+ if (base == NULL_TREE)
+ warning ("comparison of distinct object pointer types");
+ else if (base == error_mark_node)
+ {
+ message_2_types (error, "comparison of pointer types `%s*' and `%s*' requires conversion to ambiguous supertype", tt0, tt1);
+ return error_mark_node;
+ }
+ op0 = convert (TYPE_POINTER_TO (base), op0);
+ op1 = convert (TYPE_POINTER_TO (base), op1);
+ }
+ else if (comp_target_types (dt0, dt1, 1))
+ ;
+ else if (tt0 == void_type_node)
+ {
+ if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
+ warning ("ANSI C forbids comparison of `void *' with function pointer");
+ }
+ else if (tt1 == void_type_node)
+ {
+ if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
+ warning ("ANSI C forbids comparison of `void *' with function pointer");
+ }
+ else
+ warning ("comparison of distinct pointer types lacks a cast");
+ }
+ else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
+ && integer_zerop (op1))
+ op1 = null_pointer_node;
+ else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
+ && integer_zerop (op0))
+ op0 = null_pointer_node;
+ else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+ {
+ error ("comparison between pointer and integer");
+ op1 = convert (TREE_TYPE (op0), op1);
+ }
+ else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
+ {
+ error ("comparison between pointer and integer");
+ op0 = convert (TREE_TYPE (op1), op0);
+ }
+ else
+ /* If args are not valid, clear out RESULT_TYPE
+ to cause an error message later. */
+ result_type = 0;
+ break;
+
+ case MAX_EXPR:
+ case MIN_EXPR:
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ shorten = 1;
+ else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
+ {
+ if (! comp_target_types (dt0, dt1, 1))
+ warning ("comparison of distinct pointer types lacks a cast");
+ else if (pedantic
+ && TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE)
+ warning ("ANSI C forbids ordered comparisons of pointers to functions");
+ result_type = commontype (dt0, dt1);
+ }
+ break;
+
+ case LE_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case GT_EXPR:
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ short_compare = 1;
+ else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
+ {
+ if (! comp_target_types (dt0, dt1, 1))
+ warning ("comparison of distinct pointer types lacks a cast");
+ else if (pedantic
+ && TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE)
+ warning ("ANSI C forbids ordered comparisons of pointers to functions");
+ result_type = integer_type_node;
+ }
+ else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
+ && integer_zerop (op1))
+ {
+ result_type = integer_type_node;
+ op1 = null_pointer_node;
+ if (! flag_traditional)
+ warning ("ordered comparison of pointer with integer zero");
+ }
+ else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
+ && integer_zerop (op0))
+ {
+ result_type = integer_type_node;
+ op0 = null_pointer_node;
+ if (pedantic)
+ warning ("ordered comparison of pointer with integer zero");
+ }
+ else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+ {
+ result_type = integer_type_node;
+ if (! flag_traditional)
+ warning ("comparison between pointer and integer");
+ op1 = convert (TREE_TYPE (op0), op1);
+ }
+ else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
+ {
+ result_type = integer_type_node;
+ if (! flag_traditional)
+ warning ("comparison between pointer and integer");
+ op0 = convert (TREE_TYPE (op1), op0);
+ }
+ converted = 1;
+ break;
+ }
+
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ {
+ if (shorten || common || short_compare)
+ result_type = commontype (dt0, dt1);
+
+ /* For certain operations (which identify themselves by shorten != 0)
+ if both args were extended from the same smaller type,
+ do the arithmetic in that type and then extend.
+
+ shorten !=0 and !=1 indicates a bitwise operation.
+ For them, this optimization is safe only if
+ both args are zero-extended or both are sign-extended.
+ Otherwise, we might change the result.
+ Eg, (short)-1 | (unsigned short)-1 is (int)-1
+ but calculated in (unsigned short) it would be (unsigned short)-1. */
+
+ if (shorten)
+ {
+ int unsigned0, unsigned1;
+ tree arg0 = get_narrower (op0, &unsigned0);
+ tree arg1 = get_narrower (op1, &unsigned1);
+ /* UNS is 1 if the operation to be done is an unsigned one. */
+ int uns = TREE_UNSIGNED (result_type);
+ tree type;
+
+ final_type = result_type;
+
+ /* Handle the case that OP0 does not *contain* a conversion
+ but it *requires* conversion to FINAL_TYPE. */
+
+ if (op0 == arg0 && TREE_TYPE (op0) != final_type)
+ unsigned0 = TREE_UNSIGNED (TREE_TYPE (op0));
+ if (op1 == arg1 && TREE_TYPE (op1) != final_type)
+ unsigned1 = TREE_UNSIGNED (TREE_TYPE (op1));
+
+ /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */
+
+ /* For bitwise operations, signedness of nominal type
+ does not matter. Consider only how operands were extended. */
+ if (shorten == -1)
+ uns = unsigned0;
+
+ /* Note that in all three cases below we refrain from optimizing
+ an unsigned operation on sign-extended args.
+ That would not be valid. */
+
+ /* Both args variable: if both extended in same way
+ from same width, do it in that width.
+ Do it unsigned if args were zero-extended. */
+ if ((TYPE_PRECISION (TREE_TYPE (arg0))
+ < TYPE_PRECISION (result_type))
+ && (TYPE_PRECISION (TREE_TYPE (arg1))
+ == TYPE_PRECISION (TREE_TYPE (arg0)))
+ && unsigned0 == unsigned1
+ && (unsigned0 || !uns))
+ result_type
+ = signed_or_unsigned_type (unsigned0,
+ commontype (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+ else if (TREE_CODE (arg0) == INTEGER_CST
+ && (unsigned1 || !uns)
+ && (TYPE_PRECISION (TREE_TYPE (arg1))
+ < TYPE_PRECISION (result_type))
+ && (type = signed_or_unsigned_type (unsigned1,
+ TREE_TYPE (arg1)),
+ int_fits_type_p (arg0, type)))
+ result_type = type;
+ else if (TREE_CODE (arg1) == INTEGER_CST
+ && (unsigned0 || !uns)
+ && (TYPE_PRECISION (TREE_TYPE (arg0))
+ < TYPE_PRECISION (result_type))
+ && (type = signed_or_unsigned_type (unsigned0,
+ TREE_TYPE (arg0)),
+ int_fits_type_p (arg1, type)))
+ result_type = type;
+ }
+
+ /* Shifts can be shortened if shifting right. */
+
+ if (short_shift)
+ {
+ int unsigned_arg;
+ tree arg0 = get_narrower (op0, &unsigned_arg);
+
+ final_type = result_type;
+
+ if (arg0 == op0 && final_type == TREE_TYPE (op0))
+ unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0));
+
+ if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
+ /* If arg is sign-extended and then unsigned-shifted,
+ we can simulate this with a signed shift in arg's type
+ only if the extended result is at least twice as wide
+ as the arg. Otherwise, the shift could use up all the
+ ones made by sign-extension and bring in zeros.
+ We can't optimize that case at all, but in most machines
+ it never happens because available widths are 2**N. */
+ && (!TREE_UNSIGNED (final_type)
+ || unsigned_arg
+ || 2 * TYPE_PRECISION (TREE_TYPE (arg0)) <= TYPE_PRECISION (result_type)))
+ {
+ /* Do an unsigned shift if the operand was zero-extended. */
+ result_type
+ = signed_or_unsigned_type (unsigned_arg,
+ TREE_TYPE (arg0));
+ /* Convert value-to-be-shifted to that type. */
+ if (TREE_TYPE (op0) != result_type)
+ op0 = convert (result_type, op0);
+ converted = 1;
+ }
+ }
+
+ /* Comparison operations are shortened too but differently.
+ They identify themselves by setting short_compare = 1. */
+
+ if (short_compare)
+ {
+ /* Don't write &op0, etc., because that would prevent op0
+ from being kept in a register.
+ Instead, make copies of the our local variables and
+ pass the copies by reference, then copy them back afterward. */
+ tree xop0 = op0, xop1 = op1, xresult_type = result_type;
+ enum tree_code xresultcode = resultcode;
+ tree val
+ = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
+ if (val != 0)
+ return val;
+ op0 = xop0, op1 = xop1, result_type = xresult_type;
+ resultcode = xresultcode;
+ }
+ }
+
+ /* At this point, RESULT_TYPE must be nonzero to avoid an error message.
+ If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
+ Then the expression will be built.
+ It will be given type FINAL_TYPE if that is nonzero;
+ otherwise, it will be given type RESULT_TYPE. */
+
+ if (!result_type)
+ {
+ binary_op_error (error_code);
+ return error_mark_node;
+ }
+
+ if (! converted)
+ {
+ if (TREE_TYPE (op0) != result_type)
+ op0 = convert (result_type, op0);
+ if (TREE_TYPE (op1) != result_type)
+ op1 = convert (result_type, op1);
+ }
+
+ {
+ register tree result = build (resultcode, result_type, op0, op1);
+ register tree folded;
+
+ folded = fold (result);
+ if (folded == result)
+ TREE_LITERAL (folded) = TREE_LITERAL (op0) & TREE_LITERAL (op1);
+ if (final_type != 0)
+ return convert (final_type, folded);
+ return folded;
+ }
+}
+\f
+/* Return a tree for the sum or difference (RESULTCODE says which)
+ of pointer PTROP and integer INTOP. */
+
+static tree
+pointer_int_sum (resultcode, ptrop, intop)
+ enum tree_code resultcode;
+ register tree ptrop, intop;
+{
+ tree size_exp;
+
+ register tree result;
+ register tree folded = fold (intop);
+
+ /* The result is a pointer of the same type that is being added. */
+
+ register tree result_type = datatype (ptrop);
+
+ /* Needed to make OOPS V2R3 work. */
+ intop = folded;
+ if (TREE_CODE (intop) == INTEGER_CST
+ && TREE_INT_CST_LOW (intop) == 0
+ && TREE_INT_CST_HIGH (intop) == 0)
+ return ptrop;
+
+ if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
+ {
+ if (pedantic || warn_pointer_arith)
+ warning ("pointer of type `void *' used in arithmetic");
+ size_exp = integer_one_node;
+ }
+ else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
+ {
+ if (pedantic || warn_pointer_arith)
+ warning ("pointer to a function used in arithmetic");
+ size_exp = integer_one_node;
+ }
+ else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
+ {
+ if (pedantic)
+ warning ("pointer to a method used in arithmetic");
+ size_exp = integer_one_node;
+ }
+ else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
+ {
+ if (pedantic)
+ warning ("pointer to a member used in arithmetic");
+ size_exp = integer_one_node;
+ }
+ else
+ size_exp = size_in_bytes (TREE_TYPE (result_type));
+
+ /* If what we are about to multiply by the size of the elements
+ contains a constant term, apply distributive law
+ and multiply that constant term separately.
+ This helps produce common subexpressions. */
+
+ if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
+ && ! TREE_LITERAL (intop)
+ && TREE_LITERAL (TREE_OPERAND (intop, 1))
+ && TREE_LITERAL (size_exp))
+ {
+ enum tree_code subcode = resultcode;
+ if (TREE_CODE (intop) == MINUS_EXPR)
+ subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
+ ptrop = build_binary_op (subcode, ptrop, TREE_OPERAND (intop, 1));
+ intop = TREE_OPERAND (intop, 0);
+ }
+
+ /* Convert the integer argument to a type the same size as a pointer
+ so the multiply won't overflow spuriously. */
+
+ if (TYPE_PRECISION (TREE_TYPE (intop)) != POINTER_SIZE)
+ intop = convert (type_for_size (POINTER_SIZE, 0), intop);
+
+ /* Replace the integer argument
+ with a suitable product by the object size. */
+
+ intop = build_binary_op (MULT_EXPR, intop, size_exp);
+
+ /* Create the sum or difference. */
+
+ result = build (resultcode, result_type, ptrop, intop);
+
+ folded = fold (result);
+ if (folded == result)
+ TREE_LITERAL (folded) = TREE_LITERAL (ptrop) & TREE_LITERAL (intop);
+ return folded;
+}
+
+/* Return a tree for the difference of pointers OP0 and OP1.
+ The resulting tree has type int. */
+
+static tree
+pointer_diff (op0, op1)
+ register tree op0, op1;
+{
+ tree dt0 = datatype (op0);
+ register tree result, folded;
+ tree restype = type_for_size (POINTER_SIZE, 0);
+
+ if (pedantic)
+ {
+ if (TREE_CODE (TREE_TYPE (dt0)) == VOID_TYPE)
+ warning ("pointer of type `void *' used in subtraction");
+ if (TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE)
+ warning ("pointer to a function used in subtraction");
+ if (TREE_CODE (TREE_TYPE (dt0)) == METHOD_TYPE)
+ warning ("pointer to a method used in subtraction");
+ if (TREE_CODE (TREE_TYPE (dt0)) == OFFSET_TYPE)
+ warning ("pointer to a member used in subtraction");
+ }
+
+ /* First do the subtraction as integers;
+ then drop through to build the divide operator. */
+
+ op0 = build_binary_op (MINUS_EXPR,
+ convert (restype, op0), convert (restype, op1));
+ op1 = ((TREE_CODE (TREE_TYPE (dt0)) == VOID_TYPE
+ || TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (dt0)) == METHOD_TYPE
+ || TREE_CODE (TREE_TYPE (dt0)) == OFFSET_TYPE)
+ ? integer_one_node
+ : size_in_bytes (TREE_TYPE (dt0)));
+
+ /* Create the sum or difference. */
+
+ result = build (EXACT_DIV_EXPR, restype, op0, op1);
+
+ folded = fold (result);
+ if (folded == result)
+ TREE_LITERAL (folded) = TREE_LITERAL (op0) & TREE_LITERAL (op1);
+ return folded;
+}
+\f
+/* Print an error message for invalid operands to arith operation CODE.
+ NOP_EXPR is used as a special case (see truthvalue_conversion). */
+
+static void
+binary_op_error (code)
+ enum tree_code code;
+{
+ register char *opname;
+ switch (code)
+ {
+ case NOP_EXPR:
+ error ("invalid truth-value expression");
+ return;
+
+ case PLUS_EXPR:
+ opname = "+"; break;
+ case MINUS_EXPR:
+ opname = "-"; break;
+ case MULT_EXPR:
+ opname = "*"; break;
+ case MAX_EXPR:
+ opname = "max"; break;
+ case MIN_EXPR:
+ opname = "min"; break;
+ case EQ_EXPR:
+ opname = "=="; break;
+ case NE_EXPR:
+ opname = "!="; break;
+ case LE_EXPR:
+ opname = "<="; break;
+ case GE_EXPR:
+ opname = ">="; break;
+ case LT_EXPR:
+ opname = "<"; break;
+ case GT_EXPR:
+ opname = ">"; break;
+ case LSHIFT_EXPR:
+ opname = "<<"; break;
+ case RSHIFT_EXPR:
+ opname = ">>"; break;
+ case TRUNC_MOD_EXPR:
+ opname = "%"; break;
+ case TRUNC_DIV_EXPR:
+ opname = "/"; break;
+ case BIT_AND_EXPR:
+ opname = "&"; break;
+ case BIT_IOR_EXPR:
+ opname = "|"; break;
+ case TRUTH_ANDIF_EXPR:
+ opname = "&&"; break;
+ case TRUTH_ORIF_EXPR:
+ opname = "||"; break;
+ case BIT_XOR_EXPR:
+ opname = "^"; break;
+ }
+ error ("invalid operands to binary %s", opname);
+}
+\f
+/* Subroutine of build_binary_op_nodefault, used for comparison operations.
+ See if the operands have both been converted from subword integer types
+ and, if so, perhaps change them both back to their original type.
+
+ The arguments of this function are all pointers to local variables
+ of build_binary_op_nodefault: OP0_PTR is &OP0, OP1_PTR is &OP1,
+ RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE.
+
+ If this function returns nonzero, it means that the comparison has
+ a constant value. What this function returns is an expression for
+ that value. */
+
+static tree
+shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
+ tree *op0_ptr, *op1_ptr;
+ tree *restype_ptr;
+ enum tree_code *rescode_ptr;
+{
+ register tree type;
+ tree op0 = *op0_ptr;
+ tree op1 = *op1_ptr;
+ int unsignedp0, unsignedp1;
+ int real1, real2;
+ tree primop0, primop1;
+ enum tree_code code = *rescode_ptr;
+
+ /* Throw away any conversions to wider types
+ already present in the operands. */
+
+ primop0 = get_narrower (op0, &unsignedp0);
+ primop1 = get_narrower (op1, &unsignedp1);
+
+ /* Handle the case that OP0 does not *contain* a conversion
+ but it *requires* conversion to FINAL_TYPE. */
+
+ if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr)
+ unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0));
+ if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr)
+ unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1));
+
+ /* If one of the operands must be floated, we cannot optimize. */
+ real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE;
+ real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE;
+
+ /* If first arg is constant, swap the args (changing operation
+ so value is preserved), for canonicalization. */
+
+ if (TREE_LITERAL (primop0))
+ {
+ register tree tem = primop0;
+ register int temi = unsignedp0;
+ primop0 = primop1;
+ primop1 = tem;
+ tem = op0;
+ op0 = op1;
+ op1 = tem;
+ *op0_ptr = op0;
+ *op1_ptr = op1;
+ unsignedp0 = unsignedp1;
+ unsignedp1 = temi;
+ temi = real1;
+ real1 = real2;
+ real2 = temi;
+
+ switch (code)
+ {
+ case LT_EXPR:
+ code = GT_EXPR;
+ break;
+ case GT_EXPR:
+ code = LT_EXPR;
+ break;
+ case LE_EXPR:
+ code = GE_EXPR;
+ break;
+ case GE_EXPR:
+ code = LE_EXPR;
+ break;
+ }
+ *rescode_ptr = code;
+ }
+
+ /* If comparing an integer against a constant more bits wide,
+ maybe we can deduce a value of 1 or 0 independent of the data.
+ Or else truncate the constant now
+ rather than extend the variable at run time.
+
+ This is only interesting if the constant is the wider arg.
+ Also, it is not safe if the constant is unsigned and the
+ variable arg is signed, since in this case the variable
+ would be sign-extended and then regarded as unsigned.
+ Our technique fails in this case because the lowest/highest
+ possible unsigned results don't follow naturally from the
+ lowest/highest possible values of the variable operand.
+ For just EQ_EXPR and NE_EXPR there is another technique that
+ could be used: see if the constant can be faithfully represented
+ in the other operand's type, by truncating it and reextending it
+ and see if that preserves the constant's value. */
+
+ if (!real1 && !real2
+ && TREE_CODE (primop1) == INTEGER_CST
+ && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr))
+ {
+ int min_gt, max_gt, min_lt, max_lt;
+ tree maxval, minval;
+ /* 1 if comparison is nominally unsigned. */
+ int unsignedp = TREE_UNSIGNED (*restype_ptr);
+ tree val;
+
+ type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
+
+ maxval = TYPE_MAX_VALUE (type);
+ minval = TYPE_MIN_VALUE (type);
+
+ if (unsignedp && !unsignedp0)
+ *restype_ptr = signed_type (*restype_ptr);
+
+ if (TREE_TYPE (primop1) != *restype_ptr)
+ primop1 = convert (*restype_ptr, primop1);
+ if (type != *restype_ptr)
+ {
+ minval = convert (*restype_ptr, minval);
+ maxval = convert (*restype_ptr, maxval);
+ }
+
+ if (unsignedp && unsignedp0)
+ {
+ min_gt = INT_CST_LT_UNSIGNED (primop1, minval);
+ max_gt = INT_CST_LT_UNSIGNED (primop1, maxval);
+ min_lt = INT_CST_LT_UNSIGNED (minval, primop1);
+ max_lt = INT_CST_LT_UNSIGNED (maxval, primop1);
+ }
+ else
+ {
+ min_gt = INT_CST_LT (primop1, minval);
+ max_gt = INT_CST_LT (primop1, maxval);
+ min_lt = INT_CST_LT (minval, primop1);
+ max_lt = INT_CST_LT (maxval, primop1);
+ }
+
+ val = 0;
+ switch (code)
+ {
+ case NE_EXPR:
+ if (max_lt || min_gt)
+ val = integer_one_node;
+ break;
+
+ case EQ_EXPR:
+ if (max_lt || min_gt)
+ val = integer_zero_node;
+ break;
+
+ case LT_EXPR:
+ if (max_lt)
+ val = integer_one_node;
+ if (!min_lt)
+ val = integer_zero_node;
+ break;
+
+ case GT_EXPR:
+ if (min_gt)
+ val = integer_one_node;
+ if (!max_gt)
+ val = integer_zero_node;
+ break;
+
+ case LE_EXPR:
+ if (!max_gt)
+ val = integer_one_node;
+ if (min_gt)
+ val = integer_zero_node;
+ break;
+
+ case GE_EXPR:
+ if (!min_lt)
+ val = integer_one_node;
+ if (max_lt)
+ val = integer_zero_node;
+ break;
+ }
+
+ /* If primop0 was sign-extended and unsigned comparison specd,
+ we did a signed comparison above using the signed type bounds.
+ But the comparison we output must be unsigned.
+
+ Also, for inequalities, VAL is no good; but if the signed
+ comparison had *any* fixed result, it follows that the
+ unsigned comparison just tests the sign in reverse
+ (positive values are LE, negative ones GE).
+ So we can generate an unsigned comparison
+ against an extreme value of the signed type. */
+
+ if (unsignedp && !unsignedp0)
+ {
+ if (val != 0)
+ switch (code)
+ {
+ case LT_EXPR:
+ case GE_EXPR:
+ primop1 = TYPE_MIN_VALUE (type);
+ val = 0;
+ break;
+
+ case LE_EXPR:
+ case GT_EXPR:
+ primop1 = TYPE_MAX_VALUE (type);
+ val = 0;
+ break;
+ }
+ type = unsigned_type (type);
+ }
+
+ if (max_lt && !unsignedp0)
+ {
+ /* This is the case of (char)x >?< 0x80, which people used to use
+ expecting old C compilers to change the 0x80 into -0x80. */
+ if (val == integer_zero_node)
+ warning ("comparison is always 0 due to limited range of data type");
+ if (val == integer_one_node)
+ warning ("comparison is always 1 due to limited range of data type");
+ }
+
+ if (val != 0)
+ {
+ /* Don't forget to evaluate PRIMOP0 if it has side effects. */
+ if (TREE_VOLATILE (primop0))
+ return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
+ return val;
+ }
+
+ /* Value is not predetermined, but do the comparison
+ in the type of the operand that is not constant.
+ TYPE is already properly set. */
+ }
+ else if (real1 && real2
+ && TYPE_PRECISION (TREE_TYPE (primop0)) == TYPE_PRECISION (TREE_TYPE (primop1)))
+ type = TREE_TYPE (primop0);
+
+ /* If args' natural types are both narrower than nominal type
+ and both extend in the same manner, compare them
+ in the type of the wider arg.
+ Otherwise must actually extend both to the nominal
+ common type lest different ways of extending
+ alter the result.
+ (eg, (short)-1 == (unsigned short)-1 should be 0.) */
+
+ else if (unsignedp0 == unsignedp1 && real1 == real2
+ && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
+ && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
+ {
+ type = commontype (TREE_TYPE (primop0), TREE_TYPE (primop1));
+ type = signed_or_unsigned_type (unsignedp0
+ || TREE_UNSIGNED (*restype_ptr),
+ type);
+ /* Make sure shorter operand is extended the right way
+ to match the longer operand. */
+ primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)),
+ primop0);
+ primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)),
+ primop1);
+ }
+ else
+ {
+ /* Here we must do the comparison on the nominal type
+ using the args exactly as we received them. */
+ type = *restype_ptr;
+ primop0 = op0;
+ primop1 = op1;
+ }
+
+ *op0_ptr = convert (type, primop0);
+ *op1_ptr = convert (type, primop1);
+
+ *restype_ptr = integer_type_node;
+
+ return 0;
+}
+\f
+/* Handle the case of taking the address of a COMPONENT_REF.
+ Called by `build_unary_op' and `build_up_reference'.
+
+ ARG is the COMPONENT_REF whose address we want.
+ ARGTYPE is the pointer type that this address should have.
+ MSG is an error message to print if this COMPONENT_REF is not
+ addressable (such as a bitfield). */
+
+tree
+build_component_addr (arg, argtype, msg)
+ tree arg, argtype;
+ char *msg;
+{
+ tree field = TREE_OPERAND (arg, 1);
+ tree basetype = decl_type_context (field);
+ tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
+
+ if (TREE_PACKED (field))
+ {
+ error (msg, IDENTIFIER_POINTER (DECL_NAME (field)));
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (field) == FIELD_DECL
+ && (TYPE_USES_MULTIPLE_INHERITANCE (basetype)
+ || TYPE_USES_VIRTUAL_BASECLASSES (basetype)))
+ /* Can't convert directly to ARGTYPE, since that
+ may have the same pointer type as one of our
+ baseclasses. */
+ rval = build1 (NOP_EXPR, argtype,
+ convert_pointer_to (basetype, rval));
+ else
+ /* This conversion is harmless. */
+ rval = convert (argtype, rval);
+
+ if (DECL_OFFSET (field) != 0)
+ {
+ tree offset = build_int_2 ((DECL_OFFSET (field) / BITS_PER_UNIT), 0);
+ TREE_TYPE (offset) = argtype;
+ rval = fold (build (PLUS_EXPR, argtype, rval, offset));
+ }
+ return rval;
+}
+
+/* Construct and perhaps optimize a tree representation
+ for a unary operation. CODE, a tree_code, specifies the operation
+ and XARG is the operand. */
+
+tree
+build_x_unary_op (code, xarg)
+ enum tree_code code;
+ tree xarg;
+{
+ tree rval;
+
+ if (rval = build_opfncall (code, LOOKUP_PROTECT, xarg))
+ return rval;
+ rval = build_unary_op (code, xarg, 0);
+ if (rval == error_mark_node)
+ build_opfncall (code, LOOKUP_NORMAL, xarg);
+ return rval;
+}
+
+/* C++: Must handle pointers to members.
+
+ Perhaps type instantiation should be extended to handle conversion
+ from aggregates to types we don't yet know we want? (Or are those
+ cases typically errors which should be reported?)
+
+ NOCONVERT nonzero suppresses the default promotions
+ (such as from short to int). */
+tree
+build_unary_op (code, xarg, noconvert)
+ enum tree_code code;
+ tree xarg;
+ int noconvert;
+{
+ /* No default_conversion here. It causes trouble for ADDR_EXPR. */
+ register tree arg = xarg;
+ register tree argtype = 0;
+ register enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
+ char *errstring = NULL;
+ tree val;
+ int isaggrtype;
+
+ if (typecode == ERROR_MARK)
+ return error_mark_node;
+
+ if (typecode == REFERENCE_TYPE && code != ADDR_EXPR && ! noconvert)
+ {
+ arg = convert_from_reference (arg);
+ typecode = TREE_CODE (TREE_TYPE (arg));
+ }
+
+ if (typecode == ENUMERAL_TYPE)
+ typecode = INTEGER_TYPE;
+
+ isaggrtype = IS_AGGR_TYPE_CODE (typecode);
+
+ switch (code)
+ {
+ case CONVERT_EXPR:
+ /* This is used for unary plus, because a CONVERT_EXPR
+ is enough to prevent anybody from looking inside for
+ associativity, but won't generate any code. */
+ if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
+ errstring = "wrong type argument to unary plus";
+ else if (!noconvert)
+ arg = default_conversion (arg);
+ break;
+
+ case NEGATE_EXPR:
+ if (isaggrtype)
+ {
+ if (!noconvert)
+ arg = default_conversion (arg);
+ else
+ {
+ error_with_aggr_type (TREE_TYPE (arg), "type conversion for type `%s' not allowed");
+ return error_mark_node;
+ }
+ typecode = TREE_CODE (TREE_TYPE (arg));
+ noconvert = 1;
+ }
+
+ if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
+ errstring = "wrong type argument to unary minus";
+ else if (!noconvert)
+ arg = default_conversion (arg);
+ break;
+
+ case BIT_NOT_EXPR:
+ if (isaggrtype)
+ {
+ if (!noconvert)
+ arg = default_conversion (arg);
+ else
+ {
+ error_with_aggr_type (TREE_TYPE (arg), "type conversion for type `%s' not allowed");
+ return error_mark_node;
+ }
+ typecode = TREE_CODE (TREE_TYPE (arg));
+ noconvert = 1;
+ }
+
+ if (typecode != INTEGER_TYPE)
+ errstring = "wrong type argument to bit-complement";
+ else if (!noconvert)
+ arg = default_conversion (arg);
+ break;
+
+ case ABS_EXPR:
+ if (isaggrtype)
+ {
+ if (!noconvert)
+ arg = default_conversion (arg);
+ else
+ {
+ error_with_aggr_type (TREE_TYPE (arg), "type conversion for type `%s' not allowed");
+ return error_mark_node;
+ }
+ typecode = TREE_CODE (TREE_TYPE (arg));
+ noconvert = 1;
+ }
+
+ if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
+ errstring = "wrong type argument to abs";
+ else if (!noconvert)
+ arg = default_conversion (arg);
+ break;
+
+ case TRUTH_NOT_EXPR:
+ if (isaggrtype)
+ {
+ arg = truthvalue_conversion (arg);
+ typecode = TREE_CODE (TREE_TYPE (arg));
+ }
+
+ if (typecode != INTEGER_TYPE
+ && typecode != REAL_TYPE && typecode != POINTER_TYPE
+ /* These will convert to a pointer. */
+ && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE)
+ {
+ errstring = "wrong type argument to unary exclamation mark";
+ break;
+ }
+ arg = truthvalue_conversion (arg);
+ val = invert_truthvalue (arg);
+ if (val) return val;
+ break;
+
+ case NOP_EXPR:
+ break;
+
+ case PREINCREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ /* Handle complex lvalues (when permitted)
+ by reduction to simpler cases. */
+
+ val = unary_complex_lvalue (code, arg);
+ if (val != 0)
+ return val;
+
+ /* Report invalid types. */
+
+ if (isaggrtype)
+ {
+ arg = default_conversion (arg);
+ typecode = TREE_CODE (TREE_TYPE (arg));
+ }
+
+ if (typecode != POINTER_TYPE
+ && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
+ {
+ if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+ errstring ="wrong type argument to increment";
+ else
+ errstring ="wrong type argument to decrement";
+ break;
+ }
+
+ /* Report something read-only. */
+
+ if (TREE_READONLY (arg))
+ readonly_warning_or_error (arg,
+ ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? "increment" : "decrement"));
+
+ {
+ register tree inc;
+ tree result_type = TREE_TYPE (arg);
+
+ arg = get_unwidened (arg, 0);
+ argtype = TREE_TYPE (arg);
+
+ /* Compute the increment. */
+
+ if (typecode == POINTER_TYPE)
+ {
+ if (pedantic && (TREE_CODE (argtype) == FUNCTION_TYPE
+ || TREE_CODE (argtype) == METHOD_TYPE
+ || TREE_CODE (argtype) == VOID_TYPE
+ || TREE_CODE (argtype) == OFFSET_TYPE))
+ warning ("wrong type argument to %s",
+ ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? "increment" : "decrement"));
+ inc = c_sizeof_nowarn (TREE_TYPE (argtype));
+ }
+ else
+ inc = integer_one_node;
+
+ inc = convert (argtype, inc);
+
+ /* Handle incrementing a cast-expression. */
+
+ if (!pedantic)
+ switch (TREE_CODE (arg))
+ {
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ case FIX_CEIL_EXPR:
+ {
+ tree incremented, modify, value;
+ arg = stabilize_reference (arg);
+ if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
+ value = arg;
+ else
+ value = save_expr (arg);
+ incremented = build (((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? PLUS_EXPR : MINUS_EXPR),
+ argtype, value, inc);
+ TREE_VOLATILE (incremented) = 1;
+ modify = build_modify_expr (arg, NOP_EXPR, incremented);
+ return build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+ }
+ }
+
+ if (TREE_CODE (arg) == OFFSET_REF)
+ arg = resolve_offset_ref (arg);
+
+ /* Complain about anything else that is not a true lvalue. */
+ if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? "increment" : "decrement")))
+ return error_mark_node;
+
+ val = build (code, TREE_TYPE (arg), arg, inc);
+ TREE_VOLATILE (val) = 1;
+ return convert (result_type, val);
+ }
+
+ case ADDR_EXPR:
+ /* Note that this operation never does default_conversion
+ regardless of NOCONVERT. */
+
+ if (TREE_CODE (arg) == REFERENCE_EXPR)
+ {
+ error ("references are not lvalues");
+ return error_mark_node;
+ }
+ else if (typecode == REFERENCE_TYPE)
+ return build1 (REFERENCE_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
+
+ /* Let &* cancel out to simplify resulting code. */
+ if (TREE_CODE (arg) == INDIRECT_REF)
+ {
+ /* Keep `default_conversion' from converting if
+ ARG is of REFERENCE_TYPE. */
+ arg = TREE_OPERAND (arg, 0);
+ if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
+ {
+ if (TREE_CODE (arg) == VAR_DECL && DECL_INITIAL (arg))
+ arg = DECL_INITIAL (arg);
+ arg = build1 (REFERENCE_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
+ TREE_LITERAL (arg) = TREE_LITERAL (TREE_OPERAND (arg, 0));
+ }
+ return arg;
+ }
+
+ /* For &x[y], return x+y */
+ if (TREE_CODE (arg) == ARRAY_REF)
+ {
+ if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
+ return error_mark_node;
+ return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
+ TREE_OPERAND (arg, 1));
+ }
+
+ /* Uninstantiated types are all functions. Taking the
+ address of a function is a no-op, so just return the
+ arguemnt. */
+
+ if (TREE_CODE (arg) == OP_IDENTIFIER)
+ /* We don't know the type yet, so just work around the problem.
+ We know that this will resolve to an lvalue. */
+ return build1 (ADDR_EXPR, unknown_type_node, arg);
+
+ if (TREE_CODE (arg) == TREE_LIST)
+ {
+ /* Look at methods with only this name. */
+ if (TREE_CODE (TREE_VALUE (arg)) == FUNCTION_DECL)
+ {
+ tree targ = TREE_VALUE (arg);
+
+ /* If this function is unique, or it is a unique
+ constructor, we can takes its address easily. */
+ if (TREE_CHAIN (targ) == NULL_TREE
+ || (DESTRUCTOR_NAME_P (DECL_NAME (targ))
+ && TREE_CHAIN (TREE_CHAIN (targ)) == NULL_TREE))
+ {
+ if (TREE_CHAIN (targ))
+ targ = TREE_CHAIN (targ);
+ targ = build (OFFSET_REF, TREE_TYPE (targ), C_C_D, targ);
+
+ val = unary_complex_lvalue (ADDR_EXPR, targ);
+ if (val)
+ return val;
+ }
+ return build1 (ADDR_EXPR, unknown_type_node, arg);
+ }
+ if (TREE_CHAIN (arg) == NULL_TREE
+ && TREE_CHAIN (TREE_VALUE (TREE_VALUE (arg))) == NULL_TREE)
+ {
+ /* Unique overloaded member function. */
+ return build_unary_op (ADDR_EXPR, TREE_VALUE (TREE_VALUE (arg)), 0);
+ }
+ return build1 (ADDR_EXPR, unknown_type_node, arg);
+ }
+
+ /* Handle complex lvalues (when permitted)
+ by reduction to simpler cases. */
+ val = unary_complex_lvalue (code, arg);
+ if (val != 0)
+ return val;
+
+ /* Address of a cast is just a cast of the address
+ of the operand of the cast. */
+ switch (TREE_CODE (arg))
+ {
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ case FIX_CEIL_EXPR:
+ if (pedantic)
+ warning ("ANSI C forbids the address of a cast expression");
+ return convert (build_pointer_type (TREE_TYPE (arg)),
+ build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0));
+ }
+
+ /* Allow the address of a constructor if all the elements
+ are constant. */
+ if (TREE_CODE (arg) == CONSTRUCTOR && TREE_LITERAL (arg))
+ ;
+ /* Anything not already handled and not a true memory reference
+ is an error. */
+ else if (typecode != FUNCTION_TYPE
+ && typecode != METHOD_TYPE
+ && !lvalue_or_else (arg, "unary `&'"))
+ return error_mark_node;
+
+ /* Ordinary case; arg is a COMPONENT_REF or a decl. */
+ argtype = TREE_TYPE (arg);
+ if (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg))
+ argtype = build_type_variant (argtype,
+ TREE_READONLY (arg),
+ TREE_THIS_VOLATILE (arg));
+
+ argtype = build_pointer_type (argtype);
+
+ if (mark_addressable (arg) == 0)
+ return error_mark_node;
+
+ {
+ tree addr;
+
+ if (TREE_CODE (arg) == COMPONENT_REF)
+ addr = build_component_addr (arg, argtype,
+ "attempt to take address of bit-field structure member `%s'");
+ else
+ addr = build1 (code, argtype, arg);
+
+ /* Address of a static or external variable or
+ function counts as a constant */
+ TREE_LITERAL (addr) = staticp (arg);
+ return addr;
+ }
+ }
+
+ if (!errstring)
+ {
+ if (argtype == 0)
+ argtype = TREE_TYPE (arg);
+ return fold (build1 (code, argtype, arg));
+ }
+
+ error (errstring);
+ return error_mark_node;
+}
+
+/* If CONVERSIONS is a conversion expression or a nested sequence of such,
+ convert ARG with the same conversions in the same order
+ and return the result. */
+
+static tree
+convert_sequence (conversions, arg)
+ tree conversions;
+ tree arg;
+{
+ switch (TREE_CODE (conversions))
+ {
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ case FIX_CEIL_EXPR:
+ return convert (TREE_TYPE (conversions),
+ convert_sequence (TREE_OPERAND (conversions, 0),
+ arg));
+
+ default:
+ return arg;
+ }
+}
+
+/* Apply unary lvalue-demanding operator CODE to the expression ARG
+ for certain kinds of expressions which are not really lvalues
+ but which we can accept as lvalues.
+
+ If ARG is not a kind of expression we can handle, return zero. */
+
+tree
+unary_complex_lvalue (code, arg)
+ enum tree_code code;
+ tree arg;
+{
+ /* Handle (a, b) used as an "lvalue". */
+ if (TREE_CODE (arg) == COMPOUND_EXPR)
+ {
+ tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
+ return build (COMPOUND_EXPR, TREE_TYPE (real_result),
+ TREE_OPERAND (arg, 0), real_result);
+ }
+
+ /* Handle (a ? b : c) used as an "lvalue". */
+ if (TREE_CODE (arg) == COND_EXPR)
+ return (build_conditional_expr
+ (TREE_OPERAND (arg, 0),
+ build_unary_op (code, TREE_OPERAND (arg, 1), 0),
+ build_unary_op (code, TREE_OPERAND (arg, 2), 0)));
+
+ if (code != ADDR_EXPR)
+ return 0;
+
+ /* Handle (a = b) used as an "lvalue" for `&'. */
+ if (TREE_CODE (arg) == MODIFY_EXPR
+ || TREE_CODE (arg) == INIT_EXPR)
+ {
+ tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
+ return build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
+ }
+
+ if (TREE_CODE (arg) == WITH_CLEANUP_EXPR)
+ {
+ tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
+ real_result = build (WITH_CLEANUP_EXPR, TREE_TYPE (real_result),
+ real_result, 0, TREE_OPERAND (arg, 2));
+ return real_result;
+ }
+
+ if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
+ || TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
+ {
+ /* The representation of something of type OFFSET_TYPE
+ is really the representation of a pointer to it.
+ Here give the representation its true type. */
+ tree t;
+ tree offset;
+
+ assert (TREE_CODE (arg) != SCOPE_REF);
+
+ if (TREE_CODE (arg) != OFFSET_REF)
+ return 0;
+
+ t = TREE_OPERAND (arg, 1);
+ if (TREE_OPERAND (arg, 0)
+ && (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR
+ || TREE_OPERAND (TREE_OPERAND (arg, 0), 0) != error_mark_node))
+ {
+ /* Don't know if this should return address to just
+ _DECL, or actual address resolved in this expression. */
+ sorry ("address of bound pointer-to-member expression");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (t) == FUNCTION_DECL)
+ {
+ tree context = NULL_TREE;
+
+ if (DECL_VIRTUAL_P (t)
+#ifdef SOS
+ || flag_all_virtual == 2
+#endif
+ || (flag_all_virtual == 1
+ && ((context = decl_type_context (t))
+ && (TYPE_OVERLOADS_METHOD_CALL_EXPR (context)
+ || TYPE_NEEDS_WRAPPER (context))
+ && ! DECL_CONSTRUCTOR_P (t))))
+ {
+ offset = copy_node (DECL_VINDEX (t));
+ TREE_TYPE (offset) = build_pointer_type (TREE_TYPE (arg));
+ }
+ else
+ offset = build_unary_op (ADDR_EXPR, t, 0);
+
+ return offset;
+ }
+ if (TREE_CODE (t) == VAR_DECL)
+ {
+ if (TREE_STATIC (t))
+ offset = build_unary_op (ADDR_EXPR, t, 0);
+ else
+ return 0;
+ }
+ else
+ {
+ /* Can't build a pointer to member if the member must
+ go through virtual base classes. */
+ if (virtual_member (DECL_FIELD_CONTEXT (t),
+ CLASSTYPE_VBASECLASSES (TREE_TYPE (TREE_OPERAND (arg, 0)))))
+ {
+ sorry ("pointer to member via virtual baseclass");
+ return error_mark_node;
+ }
+ /* @@ What is the correct machine-independent way to do this? */
+ offset = build_int_2 (DECL_OFFSET (t) / DECL_SIZE_UNIT (t), 0);
+ TREE_TYPE (offset) = build_pointer_type (TREE_TYPE (arg));
+ return offset;
+ }
+ }
+
+ if (TREE_CODE (arg) == OFFSET_REF)
+ {
+ tree left = TREE_OPERAND (arg, 0), left_addr;
+ tree right_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 1), 0);
+
+ if (left == 0)
+ if (current_class_decl)
+ left_addr = current_class_decl;
+ else
+ {
+ error ("no `this' for pointer to member");
+ return error_mark_node;
+ }
+ else
+ left_addr = build_unary_op (ADDR_EXPR, left, 0);
+
+ return build (PLUS_EXPR, build_pointer_type (TREE_TYPE (arg)),
+ build1 (NOP_EXPR, integer_type_node, left_addr),
+ build1 (NOP_EXPR, integer_type_node, right_addr));
+ }
+
+
+ /* We permit compiler to make function calls returning
+ objects of aggregate type look like lvalues. */
+ if (TREE_CODE (arg) == CALL_EXPR && IS_AGGR_TYPE (TREE_TYPE (arg)))
+ {
+ tree temp = build_cplus_new (TREE_TYPE (arg), arg);
+ return build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (arg)), temp);
+ }
+
+ /* Don't let anything else be handled specially. */
+ return 0;
+}
+\f
+/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
+ or validate its data type for an `if' or `while' statement or ?..: exp.
+
+ This preparation consists of taking the ordinary
+ representation of an expression expr and producing a valid tree
+ boolean expression describing whether expr is nonzero. We could
+ simply always do build_binary_op (NE_EXPR, expr, integer_zero_node),
+ but we optimize comparisons, &&, ||, and ! */
+
+tree
+truthvalue_conversion (expr)
+ tree expr;
+{
+ register enum tree_code form;
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs, since EXPR is being used in non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
+
+ form = TREE_CODE (expr);
+
+ if (form == EQ_EXPR && integer_zerop (TREE_OPERAND (expr, 1)))
+ return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0);
+
+ /* A one-bit unsigned bit-field is already acceptable. */
+ if (form == COMPONENT_REF
+ && 1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1)))
+ && 1 == DECL_SIZE_UNIT (TREE_OPERAND (expr, 1))
+ && TREE_UNSIGNED (TREE_OPERAND (expr, 1)))
+ return expr;
+
+ if (form == TRUTH_ANDIF_EXPR || form == TRUTH_ORIF_EXPR
+ || form == TRUTH_AND_EXPR || form == TRUTH_OR_EXPR
+ || form == TRUTH_NOT_EXPR
+ || form == EQ_EXPR || form == NE_EXPR
+ || form == LE_EXPR || form == GE_EXPR
+ || form == LT_EXPR || form == GT_EXPR
+ || form == ERROR_MARK)
+ return expr;
+
+ /* Unary minus has no effect on whether its argument is nonzero. */
+ if (form == NEGATE_EXPR)
+ return truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+ /* Distribute the conversion into the arms of a COND_EXPR. */
+ if (form == COND_EXPR)
+ return build (COND_EXPR, TREE_TYPE (expr),
+ TREE_OPERAND (expr, 0),
+ truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ truthvalue_conversion (TREE_OPERAND (expr, 2)));
+
+ /* Sign-extension and zero-extension has no effect. */
+ if (form == NOP_EXPR
+ && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+ && (TYPE_PRECISION (TREE_TYPE (expr))
+ > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))))
+ return truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+ return build_binary_op (NE_EXPR, expr, integer_zero_node);
+}
+
+/* Return a simplified tree node for the truth-negation of ARG
+ (perhaps by altering ARG).
+ If it can't be simplified, return 0. */
+
+static tree
+invert_truthvalue (arg)
+ tree arg;
+{
+ switch (TREE_CODE (arg))
+ {
+ case NE_EXPR:
+ TREE_SET_CODE (arg, EQ_EXPR);
+ return arg;
+
+ case EQ_EXPR:
+ TREE_SET_CODE (arg, NE_EXPR);
+ return arg;
+
+ case GE_EXPR:
+ TREE_SET_CODE (arg, LT_EXPR);
+ return arg;
+
+ case GT_EXPR:
+ TREE_SET_CODE (arg, LE_EXPR);
+ return arg;
+
+ case LE_EXPR:
+ TREE_SET_CODE (arg, GT_EXPR);
+ return arg;
+
+ case LT_EXPR:
+ TREE_SET_CODE (arg, GE_EXPR);
+ return arg;
+
+#if 0
+ case TRUTH_AND_EXPR:
+ return build (TRUTH_OR_EXPR, TREE_TYPE (arg),
+ build_unary_op (TRUTH_NOT_EXPR,
+ TREE_OPERAND (arg, 0), 0),
+ build_unary_op (TRUTH_NOT_EXPR,
+ TREE_OPERAND (arg, 1), 0));
+
+ case TRUTH_OR_EXPR:
+ return build (TRUTH_AND_EXPR, TREE_TYPE (arg),
+ build_unary_op (TRUTH_NOT_EXPR,
+ TREE_OPERAND (arg, 0), 0),
+ build_unary_op (TRUTH_NOT_EXPR,
+ TREE_OPERAND (arg, 1), 0));
+#endif
+
+ case TRUTH_ANDIF_EXPR:
+ return build (TRUTH_ORIF_EXPR, TREE_TYPE (arg),
+ build_unary_op (TRUTH_NOT_EXPR,
+ TREE_OPERAND (arg, 0), 0),
+ build_unary_op (TRUTH_NOT_EXPR,
+ TREE_OPERAND (arg, 1), 0));
+
+ case TRUTH_ORIF_EXPR:
+ return build (TRUTH_ANDIF_EXPR, TREE_TYPE (arg),
+ build_unary_op (TRUTH_NOT_EXPR,
+ TREE_OPERAND (arg, 0), 0),
+ build_unary_op (TRUTH_NOT_EXPR,
+ TREE_OPERAND (arg, 1), 0));
+
+ case TRUTH_NOT_EXPR:
+ return TREE_OPERAND (arg, 0);
+ }
+ return 0;
+}
+
+/* Mark EXP saying that we need to be able to take the
+ address of it; it should not be allocated in a register.
+
+ Return 1 if taking address of this expression is ok.
+ Return 0 otherwise.
+
+ C++: we do not allow `current_class_decl' to be addressable. */
+
+int
+mark_addressable (exp)
+ tree exp;
+{
+ register tree x = exp;
+
+ if (TREE_ADDRESSABLE (x) == 1)
+ return 1;
+
+ while (1)
+ switch (TREE_CODE (x))
+ {
+ case ADDR_EXPR:
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ x = TREE_OPERAND (x, 0);
+ break;
+
+ case PARM_DECL:
+ if (x == current_class_decl)
+ {
+ error ("address of `this' not available");
+ TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
+ put_var_into_stack (x);
+ return 1;
+ }
+ case VAR_DECL:
+ if (TREE_STATIC (x)
+ && TREE_READONLY (x)
+ && DECL_RTL (x) != 0
+ && ! memory_operand (DECL_RTL (x), DECL_MODE (x)))
+ {
+ /* We thought this would make a good constant variable,
+ but we were wrong. */
+ TREE_ASM_WRITTEN (x) = 0;
+ DECL_RTL (x) = 0;
+ rest_of_decl_compilation (x, 0, IDENTIFIER_LOCAL_VALUE (x) == 0, 0);
+ TREE_ADDRESSABLE (x) = 1;
+ return 1;
+ }
+ /* Caller should not be trying to mark initialized
+ constant fields addressable. */
+ assert (DECL_LANG_SPECIFIC (x) == 0 || DECL_IN_AGGR_P (x) == 0 || TREE_STATIC (x));
+
+ case CONST_DECL:
+ if (TREE_REGDECL (x))
+ {
+ if (TREE_PUBLIC (x))
+ {
+ error ("address of global register variable `%s' requested",
+ IDENTIFIER_POINTER (DECL_NAME (x)));
+ return 0;
+ }
+ warning ("address requested for `%s', which is declared `register'",
+ IDENTIFIER_POINTER (DECL_NAME (x)));
+ }
+ put_var_into_stack (x);
+ TREE_ADDRESSABLE (x) = 1;
+ return 1;
+
+ case RESULT_DECL:
+ put_var_into_stack (x);
+ TREE_ADDRESSABLE (x) = 1;
+ return 1;
+
+ case FUNCTION_DECL:
+ if (TREE_INLINE (x))
+ mark_inline_for_output (x);
+ TREE_ADDRESSABLE (x) = 1;
+ TREE_USED (x) = 1;
+ TREE_ADDRESSABLE (DECL_NAME (x)) = 1;
+ return 1;
+
+ default:
+ return 1;
+ }
+}
+\f
+/* Build and return a conditional expression IFEXP ? OP1 : OP2. */
+
+tree
+build_x_conditional_expr (ifexp, op1, op2)
+ tree ifexp, op1, op2;
+{
+ tree rval;
+
+ if (op1 != 0 && (rval = build_opfncall (COND_EXPR, LOOKUP_PROTECT, ifexp, op1, op2)))
+ return rval;
+ rval = build_conditional_expr (ifexp, op1, op2);
+ if (op1 != 0 && rval == error_mark_node)
+ build_opfncall (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
+ return rval;
+}
+
+tree
+build_conditional_expr (ifexp, op1, op2)
+ tree ifexp, op1, op2;
+{
+ register tree type1;
+ register tree type2;
+ register enum tree_code code1;
+ register enum tree_code code2;
+ register tree result_type = NULL_TREE;
+
+ /* If second operand is omitted, it is the same as the first one;
+ make sure it is calculated only once. */
+ if (op1 == 0)
+ {
+ if (pedantic)
+ warning ("ANSI C forbids omitting the middle term of a ?: expression");
+ ifexp = op1 = save_expr (ifexp);
+ }
+
+ ifexp = truthvalue_conversion (default_conversion (ifexp));
+
+ if (TREE_CODE (ifexp) == ERROR_MARK)
+ return error_mark_node;
+
+ op1 = require_instantiated_type (TREE_TYPE (op2), op1, error_mark_node);
+ if (op1 == error_mark_node)
+ return error_mark_node;
+ op2 = require_instantiated_type (TREE_TYPE (op1), op2, error_mark_node);
+ if (op2 == error_mark_node)
+ return error_mark_node;
+
+ /* C++: REFERENCE_TYPES must be dereferenced. */
+ type1 = TREE_TYPE (op1);
+ code1 = TREE_CODE (type1);
+ type2 = TREE_TYPE (op2);
+ code2 = TREE_CODE (type2);
+
+ if (code1 == REFERENCE_TYPE)
+ {
+ op1 = convert_from_reference (op1);
+ type1 = TREE_TYPE (op1);
+ code1 = TREE_CODE (type1);
+ }
+ if (code2 == REFERENCE_TYPE)
+ {
+ op2 = convert_from_reference (op2);
+ type2 = TREE_TYPE (op2);
+ code2 = TREE_CODE (type2);
+ }
+
+ /* Don't promote the operands separately if they promote
+ the same way. Return the unpromoted type and let the combined
+ value get promoted if necessary. */
+
+ if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
+ && code2 != ARRAY_TYPE
+#if 0
+ /* For C++, let the enumeral type come through. */
+ && code2 != ENUMERAL_TYPE
+#endif
+ && code2 != FUNCTION_TYPE
+ && code2 != METHOD_TYPE)
+ {
+ if (TREE_LITERAL (ifexp)
+ && (TREE_CODE (ifexp) == INTEGER_CST
+ || TREE_CODE (ifexp) == ADDR_EXPR))
+ return (integer_zerop (ifexp) ? op2 : op1);
+
+ if (TREE_CODE (op1) == CONST_DECL)
+ op1 = DECL_INITIAL (op1);
+ else if (TREE_READONLY_DECL_P (op1))
+ op1 = decl_constant_value (op1);
+ if (TREE_CODE (op2) == CONST_DECL)
+ op2 = DECL_INITIAL (op2);
+ else if (TREE_READONLY_DECL_P (op2))
+ op2 = decl_constant_value (op2);
+ if (type1 != type2)
+ {
+ int constp = TREE_READONLY (type1) || TREE_READONLY (type2);
+ int volatilep = TREE_VOLATILE (type1) || TREE_VOLATILE (type2);
+ type1 = build_type_variant (type1, constp, volatilep);
+ }
+ return build (COND_EXPR, type1, ifexp, op1, op2);
+ }
+
+ /* They don't match; promote them both and then try to reconcile them.
+ But don't permit mismatching enum types. */
+ if (code1 == ENUMERAL_TYPE)
+ {
+ if (code2 == ENUMERAL_TYPE)
+ {
+ message_2_types (error, "enumeral mismatch in conditional expression: `%s' vs `%s'", type1, type2);
+ return error_mark_node;
+ }
+ else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2))
+ warning ("enumeral and non-enumeral type in conditional expression");
+ }
+ else if (extra_warnings
+ && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1))
+ warning ("enumeral and non-enumeral type in conditional expression");
+
+ if (code1 != VOID_TYPE)
+ {
+ op1 = default_conversion (op1);
+ type1 = TREE_TYPE (op1);
+ code1 = TREE_CODE (type1);
+ }
+ if (code2 != VOID_TYPE)
+ {
+ op2 = default_conversion (op2);
+ type2 = TREE_TYPE (op2);
+ code2 = TREE_CODE (type2);
+ }
+
+ /* Quickly detect the usual case where op1 and op2 have the same type
+ after promotion. */
+ if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
+ {
+ if (type1 != type2)
+ {
+ int constp = TREE_READONLY (type1) || TREE_READONLY (type2);
+ int volatilep = TREE_VOLATILE (type1) || TREE_VOLATILE (type2);
+ type1 = build_type_variant (type1, constp, volatilep);
+ }
+ result_type = type1;
+ }
+ else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE)
+ && (code2 == INTEGER_TYPE || code2 == REAL_TYPE))
+ {
+ result_type = commontype (type1, type2);
+ }
+ else if (code1 == VOID_TYPE || code2 == VOID_TYPE)
+ {
+ if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE))
+ warning ("ANSI C forbids conditional expr with only one void side");
+ result_type = void_type_node;
+ }
+ else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
+ {
+ if (comp_target_types (type1, type2, 1))
+ result_type = commontype (type1, type2);
+ else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
+ {
+ if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
+ warning ("ANSI C forbids conditional expr between `void *' and function pointer");
+ result_type = qualify_type (type1, type2);
+ }
+ else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node)
+ {
+ if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
+ warning ("ANSI C forbids conditional expr between `void *' and function pointer");
+ result_type = qualify_type (type2, type1);
+ }
+ /* C++ */
+ else if (comptypes (type2, type1, 0))
+ result_type = type2;
+ else if (result_type = common_base_type (TREE_TYPE (type1), TREE_TYPE (type2)))
+ {
+ if (result_type == error_mark_node)
+ {
+ message_2_types (error, "common base type of types `%s' and `%s' is ambiguous",
+ TREE_TYPE (type1), TREE_TYPE (type2));
+ result_type = ptr_type_node;
+ }
+ else result_type = TYPE_POINTER_TO (result_type);
+ }
+ else
+ {
+ warning ("pointer type mismatch in conditional expression");
+ result_type = ptr_type_node;
+ }
+ }
+ else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
+ {
+ if (!integer_zerop (op2))
+ warning ("pointer/integer type mismatch in conditional expression");
+ else
+ {
+ op2 = null_pointer_node;
+ if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
+ warning ("ANSI C forbids conditional expr between 0 and function pointer");
+ }
+ result_type = type1;
+ }
+ else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
+ {
+ if (!integer_zerop (op1))
+ warning ("pointer/integer type mismatch in conditional expression");
+ else
+ {
+ op1 = null_pointer_node;
+ if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
+ warning ("ANSI C forbids conditional expr between 0 and function pointer");
+ }
+ result_type = type2;
+ op1 = null_pointer_node;
+ }
+
+ if (!result_type)
+ {
+ /* The match does not look good. If either is
+ an aggregate value, try converting to a scalar type. */
+ if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
+ {
+ message_2_types (error, "aggregate mismatch in conditional expression: `%s' vs `%s'", type1, type2);
+ return error_mark_node;
+ }
+ if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
+ {
+ tree tmp = build_type_conversion (CONVERT_EXPR, type2, op1, 0);
+ if (tmp == NULL_TREE)
+ {
+ error_with_aggr_type (type1, "aggregate type `%s' could not convert on lhs of `:'");
+ return error_mark_node;
+ }
+ if (tmp == error_mark_node)
+ error ("ambiguous pointer conversion");
+ result_type = type2;
+ op1 = tmp;
+ }
+ else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
+ {
+ tree tmp = build_type_conversion (CONVERT_EXPR, type1, op2, 0);
+ if (tmp == NULL_TREE)
+ {
+ error_with_aggr_type (type2, "aggregate type `%s' could not convert on rhs of `:'");
+ return error_mark_node;
+ }
+ if (tmp == error_mark_node)
+ error ("ambiguous pointer conversion");
+ result_type = type1;
+ op2 = tmp;
+ }
+ else if (flag_cond_mismatch)
+ result_type = void_type_node;
+ else
+ {
+ error ("type mismatch in conditional expression");
+ return error_mark_node;
+ }
+ }
+
+ if (result_type != TREE_TYPE (op1))
+ op1 = convert (result_type, op1);
+ if (result_type != TREE_TYPE (op2))
+ op2 = convert (result_type, op2);
+
+#if 0
+ if (IS_AGGR_TYPE_CODE (code1))
+ {
+ result_type = TREE_TYPE (op1);
+ if (TREE_LITERAL (ifexp))
+ return (integer_zerop (ifexp) ? op2 : op1);
+
+ if (TYPE_MODE (result_type) == BLKmode)
+ {
+ register tree tempvar
+ = build_decl (VAR_DECL, NULL_TREE, result_type);
+ register tree xop1 = build_modify_expr (tempvar, NOP_EXPR, op1);
+ register tree xop2 = build_modify_expr (tempvar, NOP_EXPR, op2);
+ register tree result = build (COND_EXPR, result_type,
+ ifexp, xop1, xop2);
+
+ layout_decl (tempvar);
+ /* No way to handle variable-sized objects here.
+ I fear that the entire handling of BLKmode conditional exprs
+ needs to be redone. */
+ assert (TREE_LITERAL (DECL_SIZE (tempvar)));
+ DECL_RTL (tempvar)
+ = assign_stack_local (DECL_MODE (tempvar),
+ (TREE_INT_CST_LOW (DECL_SIZE (tempvar))
+ * DECL_SIZE_UNIT (tempvar)
+ + BITS_PER_UNIT - 1)
+ / BITS_PER_UNIT);
+
+ TREE_VOLATILE (result)
+ = TREE_VOLATILE (ifexp) | TREE_VOLATILE (op1)
+ | TREE_VOLATILE (op2);
+ return build (COMPOUND_EXPR, result_type, result, tempvar);
+ }
+ }
+#endif /* 0 */
+
+ if (TREE_LITERAL (ifexp))
+ return (integer_zerop (ifexp) ? op2 : op1);
+
+ return build (COND_EXPR, result_type, ifexp, op1, op2);
+}
+\f
+/* Handle overloading of the ',' operator when needed. Otherwise,
+ this function just builds an expression list. */
+tree
+build_x_compound_expr (list)
+ tree list;
+{
+ tree type, rest = TREE_CHAIN (list);
+ tree result;
+
+ if (rest == NULL_TREE)
+ return build_compound_expr (list);
+
+ result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
+ TREE_VALUE (list), TREE_VALUE (rest));
+ if (result)
+ return build_x_compound_expr (tree_cons (NULL_TREE, result, TREE_CHAIN (rest)));
+ else
+ return build_compound_expr (tree_cons (NULL_TREE, TREE_VALUE (list),
+ build_tree_list (NULL_TREE, build_x_compound_expr (rest))));
+}
+
+/* Given a list of expressions, return a compound expression
+ that performs them all and returns the value of the last of them. */
+
+tree
+build_compound_expr (list)
+ tree list;
+{
+ register tree rest;
+
+ if (TREE_CODE (TREE_VALUE (list)) == CALL_EXPR
+ && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (TREE_VALUE (list))))
+ TREE_VALUE (list) = cleanup_after_call (TREE_VALUE (list));
+ else if (TREE_READONLY_DECL_P (TREE_VALUE (list)))
+ TREE_VALUE (list) = decl_constant_value (TREE_VALUE (list));
+
+ if (TREE_CHAIN (list) == 0)
+ {
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs, since LIST is used in non-lvalue context. */
+ if (TREE_CODE (list) == NOP_EXPR
+ && TREE_TYPE (list) == TREE_TYPE (TREE_OPERAND (list, 0)))
+ list = TREE_OPERAND (list, 0);
+
+ return TREE_VALUE (list);
+ }
+
+ rest = build_compound_expr (TREE_CHAIN (list));
+
+ /* This is patched out so that sizeof (0, array) is distinguishable from
+ sizeof array. */
+#if 0
+ if (! TREE_VOLATILE (TREE_VALUE (list)))
+ return rest;
+#endif
+
+ if (! TREE_VOLATILE (TREE_VALUE (list)))
+ return rest;
+
+ return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
+}
+
+/* Build an expression representing a cast to type TYPE of expression EXPR. */
+
+tree
+build_c_cast (type, expr)
+ register tree type;
+ tree expr;
+{
+ register tree value = expr;
+
+ if (type == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
+ type = TYPE_MAIN_VARIANT (type);
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs, since VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (value) == NOP_EXPR
+ && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
+ value = TREE_OPERAND (value, 0);
+
+ if (type == TREE_TYPE (value))
+ {
+ if (pedantic)
+ {
+ if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ warning ("ANSI C forbids casting nonscalar to the same type");
+ }
+ return value;
+ }
+
+ /* If there's only one function in the overloaded space,
+ just take it. */
+ if (TREE_CODE (value) == TREE_LIST
+ && TREE_CHAIN (value) == NULL_TREE)
+ value = TREE_VALUE (value);
+
+ if (TREE_TYPE (value) == NULL_TREE
+ || type_unknown_p (value))
+ {
+ value = instantiate_type (type, value, 1);
+ /* Did we lose? */
+ if (value == error_mark_node)
+ return error_mark_node;
+ }
+ else if (TREE_CODE (type) == REFERENCE_TYPE
+ && TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
+ {
+ /* Reference-to-reference conversion is special. */
+ value = build_unary_op (ADDR_EXPR, value, 0);
+ if (value != error_mark_node)
+ value = convert_force (build_pointer_type (TREE_TYPE (type)), value);
+ if (value == error_mark_node)
+ return error_mark_node;
+ return build1 (NOP_EXPR, type, value);
+ }
+ else
+ {
+ tree otype;
+ value = default_conversion (value);
+ otype = TREE_TYPE (value);
+
+ /* Optionally warn about potentially worrysome casts. */
+
+ if (warn_cast_qual
+ && TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE)
+ {
+ if (TREE_VOLATILE (TREE_TYPE (otype))
+ && ! TREE_VOLATILE (TREE_TYPE (type)))
+ warning ("cast discards `volatile' from pointer target type");
+ if (TREE_READONLY (TREE_TYPE (otype))
+ && ! TREE_READONLY (TREE_TYPE (type)))
+ warning ("cast discards `const' from pointer target type");
+ }
+ value = convert_force (type, value);
+ }
+ if (value == expr)
+ /* Always produce some operator for an explicit cast,
+ so we can tell (for -pedantic) that the cast is no lvalue. */
+ {
+ tree nvalue = build1 (NOP_EXPR, type, value);
+ TREE_LITERAL (nvalue) = TREE_LITERAL (value);
+ return nvalue;
+ }
+
+ if (TREE_CODE (value) == CALL_EXPR
+ && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (value)))
+ value = cleanup_after_call (value);
+
+ return value;
+}
+\f
+/* Build an assignment expression of lvalue LHS from value RHS.
+
+ In C++, if the left hand side of the assignment is a REFERENCE_TYPE,
+ that reference becomes deferenced down to it base type. */
+
+/* Return a reference to the BASE_INDEX part of EXPR. TYPE is
+ the type to which BASE_INDEX applies. */
+static tree
+get_base_ref (type, base_index, expr)
+ tree type;
+ int base_index;
+ tree expr;
+{
+ tree basetype = CLASSTYPE_BASECLASS (type, base_index);
+ tree ref;
+
+ if (TREE_CODE (expr) == ARRAY_REF
+ || CLASSTYPE_OFFSET (basetype) != integer_zero_node
+ || CLASSTYPE_VIA_VIRTUAL (type, base_index)
+ || TYPE_MODE (type) != TYPE_MODE (basetype))
+ {
+ tree addr = build_unary_op (ADDR_EXPR, expr, 0);
+ ref = build_indirect_ref (convert_pointer_to (basetype, addr), 0);
+ }
+ else
+ {
+ ref = copy_node (expr);
+ TREE_TYPE (ref) = basetype;
+ }
+ return ref;
+}
+
+/* Build an assignment expression of lvalue LHS from value RHS.
+ MODIFYCODE is the code for a binary operator that we use
+ to combine the old value of LHS with RHS to get the new value.
+ Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
+
+ C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.
+
+ `build_modify_expr_1' implements recursive part of memberwise
+ assignment operation. */
+static tree
+build_modify_expr_1 (lhs, modifycode, rhs, basetype_path)
+ tree lhs, rhs;
+ enum tree_code modifycode;
+ tree basetype_path;
+{
+ register tree result;
+ tree newrhs = rhs;
+ tree lhstype = TREE_TYPE (lhs);
+ tree olhstype = lhstype;
+
+ /* Avoid duplicate error messages from operands that had errors. */
+ if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
+ return error_mark_node;
+
+ /* If a binary op has been requested, combine the old LHS value with the RHS
+ producing the value we should actually store into the LHS. */
+
+ if (modifycode == INIT_EXPR)
+ ;
+ else if (modifycode == NOP_EXPR)
+ {
+ /* must deal with overloading of `operator=' here. */
+ if (TREE_CODE (lhstype) == REFERENCE_TYPE)
+ lhstype = TREE_TYPE (lhstype);
+ lhstype = olhstype;
+ }
+ else
+ {
+ lhs = stabilize_reference (lhs);
+ newrhs = build_binary_op (modifycode, lhs, rhs);
+ modifycode = NOP_EXPR;
+ }
+
+ /* If storing into a structure or union member,
+ it has probably been given type `int'.
+ Compute the type that would go with
+ the actual amount of storage the member occupies. */
+
+ if (TREE_CODE (lhs) == COMPONENT_REF
+ && (TREE_CODE (lhstype) == INTEGER_TYPE
+ || TREE_CODE (lhstype) == REAL_TYPE
+ || TREE_CODE (lhstype) == ENUMERAL_TYPE))
+ lhstype = TREE_TYPE (get_unwidened (lhs, 0));
+
+ /* C++: The semantics of C++ differ from those of C when an
+ assignment of an aggregate is desired. Assignment in C++ is
+ now defined as memberwise assignment of non-static members
+ and base class objects. This rule applies recursively
+ until a member of a built-in type is found.
+
+ Also, we cannot do a bit-wise copy of aggregates which
+ contain virtual function table pointers. Those
+ pointer values must be preserved through the copy.
+ However, this is handled in expand_expr, and not here.
+ This is because much better code can be generated at
+ that stage than this one. */
+ if (TREE_CODE (lhstype) == RECORD_TYPE
+ && TYPE_LANG_SPECIFIC (lhstype)
+ && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
+ {
+ register tree elt;
+ int i;
+
+ /* Perform operation on object. */
+ if (modifycode == INIT_EXPR && TYPE_HAS_INIT_REF (lhstype))
+ {
+ result = build_method_call (lhs, DECL_NAME (TYPE_NAME (lhstype)),
+ build_tree_list (NULL_TREE, rhs),
+ basetype_path, LOOKUP_NORMAL);
+ return build_indirect_ref (result, 0);
+ }
+ else if (modifycode == NOP_EXPR)
+ {
+ /* `operator=' is not an inheritable operator. */
+ if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_ASSIGNMENT (lhstype))
+ {
+ result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, (tree)NOP_EXPR);
+ if (result == NULL_TREE)
+ return error_mark_node;
+ return result;
+ }
+ }
+
+ if (TYPE_USES_VIRTUAL_BASECLASSES (lhstype)
+ || (modifycode == NOP_EXPR && TYPE_GETS_ASSIGNMENT (lhstype))
+ || (modifycode == INIT_EXPR && TYPE_GETS_INIT_REF (lhstype)))
+ {
+ result = NULL_TREE;
+
+ /* Perform operation on each member, depth-first, left-right. */
+ for (i = 1; i <= CLASSTYPE_N_BASECLASSES (lhstype); i++)
+ {
+ tree base_lhs, base_rhs;
+ tree new_result;
+
+ /* Assignments from virtual baseclasses handled elsewhere. */
+ if (CLASSTYPE_VIA_VIRTUAL (lhstype, i))
+ continue;
+
+ base_lhs = get_base_ref (lhstype, i, lhs);
+ base_rhs = get_base_ref (lhstype, i, newrhs);
+
+ new_result
+ = build_modify_expr_1 (base_lhs, modifycode, base_rhs,
+ tree_cons (NULL_TREE,
+ TREE_TYPE (base_lhs),
+ basetype_path));
+
+ /* We either get back a compound stmt, or a simple one. */
+ if (new_result && TREE_CODE (new_result) == TREE_LIST)
+ new_result = build_compound_expr (new_result);
+ result = tree_cons (NULL_TREE, new_result, result);
+ }
+
+ for (elt = TYPE_FIELDS (lhstype); elt; elt = TREE_CHAIN (elt))
+ {
+ tree vbases = NULL_TREE;
+ tree elt_lhs, elt_rhs;
+
+ if (TREE_CODE (elt) == VAR_DECL || TREE_CODE (elt) == CONST_DECL)
+ continue;
+ if (DECL_NAME (elt)
+ && (VFIELD_NAME_P (DECL_NAME (elt))
+ || VBASE_NAME_P (DECL_NAME (elt))))
+ continue;
+
+ if (IS_AGGR_TYPE (TREE_TYPE (elt))
+ && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
+ vbases = CLASSTYPE_VBASECLASSES (TREE_TYPE (elt));
+
+ elt_lhs = build (COMPONENT_REF, TREE_TYPE (elt), lhs, elt);
+ elt_rhs = build (COMPONENT_REF, TREE_TYPE (elt), newrhs, elt);
+ /* It is not always safe to go through `build_modify_expr_1'
+ when performing element-wise copying. This is because
+ an element may be of ARRAY_TYPE, which will not
+ be properly copied as a naked element. */
+ if (TREE_CODE (TREE_TYPE (elt)) == RECORD_TYPE
+ && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
+ basetype_path = CLASSTYPE_AS_LIST (TREE_TYPE (elt));
+
+ while (vbases)
+ {
+ tree elt_lhs_addr = build_unary_op (ADDR_EXPR, elt_lhs);
+ tree elt_rhs_addr = build_unary_op (ADDR_EXPR, elt_rhs);
+
+ elt_lhs_addr = convert_pointer_to (TREE_TYPE (vbases), elt_lhs_addr);
+ elt_rhs_addr = convert_pointer_to (TREE_TYPE (vbases), elt_rhs_addr);
+ result = tree_cons (NULL_TREE, build_modify_expr_1 (build_indirect_ref (elt_lhs_addr, 0), modifycode, build_indirect_ref (elt_rhs_addr, 0), basetype_path), result);
+ if (TREE_VALUE (result) == error_mark_node)
+ return error_mark_node;
+ vbases = TREE_CHAIN (vbases);
+ }
+ elt_lhs = build_modify_expr_1 (elt_lhs, modifycode, elt_rhs,
+ basetype_path);
+ result = tree_cons (NULL_TREE, elt_lhs, result);
+ }
+
+ if (result)
+ return build_compound_expr (result);
+ /* No fields to move. */
+ return integer_zero_node;
+ }
+ else
+ {
+ result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
+ void_type_node, lhs, rhs);
+ TREE_VOLATILE (result) = 1;
+ return result;
+ }
+ }
+
+ return build_modify_expr (lhs, modifycode, newrhs);
+}
+
+tree
+build_modify_expr (lhs, modifycode, rhs)
+ tree lhs, rhs;
+ enum tree_code modifycode;
+{
+ register tree result;
+ tree newrhs = rhs;
+ tree lhstype = TREE_TYPE (lhs);
+ tree olhstype = lhstype;
+
+ /* Types that aren't fully specified cannot be used in assignments. */
+ lhs = require_complete_type (lhs);
+
+ /* Avoid duplicate error messages from operands that had errors. */
+ if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
+ return error_mark_node;
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs, since RHS is being used in non-lvalue context. */
+ if (TREE_CODE (rhs) == NOP_EXPR
+ && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0)))
+ rhs = TREE_OPERAND (rhs, 0);
+
+ newrhs = rhs;
+
+ /* Handle control structure constructs used as "lvalues". */
+
+ if (!pedantic)
+ switch (TREE_CODE (lhs))
+ {
+ /* Handle (a, b) used as an "lvalue". */
+ case COMPOUND_EXPR:
+ return build (COMPOUND_EXPR, lhstype,
+ TREE_OPERAND (lhs, 0),
+ build_modify_expr (TREE_OPERAND (lhs, 1),
+ modifycode, rhs));
+
+ /* Handle (a ? b : c) used as an "lvalue". */
+ case COND_EXPR:
+ rhs = save_expr (rhs);
+ {
+ /* Produce (a ? (b = rhs) : (c = rhs))
+ except that the RHS goes through a save-expr
+ so the code to compute it is only emitted once. */
+ tree cond
+ = build_conditional_expr
+ (TREE_OPERAND (lhs, 0),
+ build_modify_expr (TREE_OPERAND (lhs, 1),
+ modifycode, rhs),
+ build_modify_expr (TREE_OPERAND (lhs, 2),
+ modifycode, rhs));
+ /* Make sure the code to compute the rhs comes out
+ before the split. */
+ return build (COMPOUND_EXPR, TREE_TYPE (lhs),
+ /* Case to void to suppress warning
+ from warn_if_unused_value. */
+ convert (void_type_node, rhs),
+ cond);
+ }
+ }
+
+ /* If a binary op has been requested, combine the old LHS value with the RHS
+ producing the value we should actually store into the LHS. */
+
+ if (modifycode == INIT_EXPR)
+ ;
+ else if (modifycode == NOP_EXPR)
+ {
+ /* must deal with overloading of `operator=' here. */
+ if (TREE_CODE (lhstype) == REFERENCE_TYPE)
+ lhstype = TREE_TYPE (lhstype);
+#if 1
+ /* `operator=' is not an inheritable operator. */
+ if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_ASSIGNMENT (lhstype))
+ {
+ result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, (tree)NOP_EXPR);
+ if (result == NULL_TREE)
+ return error_mark_node;
+ return result;
+ }
+#else
+ /* Treat `operator=' as an inheritable operator. */
+ if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_GETS_ASSIGNMENT (lhstype))
+ {
+ tree orig_lhstype = lhstype;
+ while (! TYPE_HAS_ASSIGNMENT (lhstype))
+ {
+ int i;
+ tree basetype = NULL_TREE;
+ for (i = 1; i <= CLASSTYPE_N_BASECLASSES (lhstype); i++)
+ if (TYPE_GETS_ASSIGNMENT (CLASSTYPE_BASECLASS (lhstype, i)))
+ {
+ if (basetype != NULL_TREE)
+ {
+ message_2_types (error, "base classes `%s' and `%s' both have operator ='",
+ basetype,
+ CLASSTYPE_BASECLASS (lhstype, i));
+ return error_mark_node;
+ }
+ basetype = CLASSTYPE_BASECLASS (lhstype, i);
+ }
+ lhstype = basetype;
+ }
+ if (orig_lhstype != lhstype)
+ {
+ lhs = build_indirect_ref (convert_pointer_to (lhstype,
+ build_unary_op (ADDR_EXPR, lhs, 0)), 0);
+ if (lhs == error_mark_node)
+ {
+ error_with_aggr_type (lhstype, "conversion to private basetype `%s'");
+ return error_mark_node;
+ }
+ }
+ result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, (tree)NOP_EXPR);
+ if (result == NULL_TREE)
+ return error_mark_node;
+ return result;
+ }
+#endif
+ lhstype = olhstype;
+ }
+ else if (IS_AGGR_TYPE (lhstype)
+ || (TREE_CODE (lhstype) == REFERENCE_TYPE
+ && IS_AGGR_TYPE (TREE_TYPE (lhstype))))
+ {
+ /* This case must convert to some sort of lvalue that
+ can participate in a op= operation. */
+ tree lhs_tmp = lhs;
+ tree rhs_tmp = rhs;
+ if (build_default_binary_type_conversion (modifycode, &lhs_tmp, &rhs_tmp))
+ {
+ lhs = stabilize_reference (lhs_tmp);
+ /* Forget is was ever anything else. */
+ olhstype = lhstype = TREE_TYPE (lhs);
+ newrhs = build_binary_op (modifycode, lhs, rhs_tmp);
+ }
+ else
+ return error_mark_node;
+ }
+ else
+ {
+ lhs = stabilize_reference (lhs);
+ newrhs = build_binary_op (modifycode, lhs, rhs);
+ }
+
+ /* Handle a cast used as an "lvalue".
+ We have already performed any binary operator using the value as cast.
+ Now convert the result to the true type of the lhs and store there;
+ then cast the result back to the specified type to be the value
+ of the assignment. */
+
+ if (!pedantic)
+ switch (TREE_CODE (lhs))
+ {
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ case FIX_CEIL_EXPR:
+ if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
+ || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
+ newrhs = default_conversion (newrhs);
+ {
+ tree inner_lhs = TREE_OPERAND (lhs, 0);
+ tree result = build_modify_expr (inner_lhs, NOP_EXPR,
+ convert (TREE_TYPE (inner_lhs),
+ newrhs));
+ return convert (TREE_TYPE (lhs), result);
+ }
+ }
+
+ if (TREE_CODE (lhs) == OFFSET_REF)
+ if (TREE_OPERAND (lhs, 0) == NULL_TREE)
+ {
+ /* Static class member? */
+ tree member = TREE_OPERAND (lhs, 1);
+ if (TREE_CODE (member) == VAR_DECL)
+ lhs = member;
+ else
+ {
+ compiler_error ("invalid static class member");
+ return error_mark_node;
+ }
+ }
+ else
+ {
+ tree base = build_unary_op (ADDR_EXPR, TREE_OPERAND (lhs, 0), 0);
+ tree member = build_unary_op (ADDR_EXPR, TREE_OPERAND (lhs, 1), 0);
+
+ if (TREE_CODE (base) == ERROR_MARK
+ || TREE_CODE (member) == ERROR_MARK)
+ return error_mark_node;
+ lhs = build_indirect_ref (build (PLUS_EXPR, build_pointer_type (TREE_TYPE (lhs)),
+ base, member));
+ }
+
+ /* Now we have handled acceptable kinds of LHS that are not truly lvalues.
+ Reject anything strange now. */
+
+ if (!lvalue_or_else (lhs, "assignment"))
+ return error_mark_node;
+
+#ifdef FIELD_XREF
+ FIELD_xref_assign(lhs);
+#endif
+
+ /* Warn about storing in something that is `const'. */
+ /* For C++, don't warn if this is initialization. */
+ if (modifycode != INIT_EXPR
+ && (TREE_READONLY (lhs)
+ || ((TREE_CODE (lhstype) == RECORD_TYPE
+ || TREE_CODE (lhstype) == UNION_TYPE)
+ && C_TYPE_FIELDS_READONLY (lhstype))
+ || (TREE_CODE (lhstype) == REFERENCE_TYPE
+ && TREE_READONLY (TREE_TYPE (lhstype)))))
+ readonly_warning_or_error (lhs, "assignment");
+
+ /* If storing into a structure or union member,
+ it has probably been given type `int'.
+ Compute the type that would go with
+ the actual amount of storage the member occupies. */
+
+ if (TREE_CODE (lhs) == COMPONENT_REF
+ && (TREE_CODE (lhstype) == INTEGER_TYPE
+ || TREE_CODE (lhstype) == REAL_TYPE
+ || TREE_CODE (lhstype) == ENUMERAL_TYPE))
+ lhstype = TREE_TYPE (get_unwidened (lhs, 0));
+
+ /* check to see if there is an assignment to `this' */
+ if (lhs == current_class_decl)
+ {
+ if (flag_this_is_variable
+ && current_class_name != DECL_ORIGINAL_NAME (current_function_decl))
+ warning ("assignment to `this' not in constructor or destructor");
+ current_function_just_assigned_this = 1;
+ }
+
+ /* The TREE_TYPE of RHS may be TYPE_UNKNOWN. This can happen
+ when the type of RHS is not yet known, i.e. its type
+ is inherited from LHS. */
+ rhs = require_instantiated_type (lhstype, newrhs, error_mark_node);
+ if (rhs == error_mark_node)
+ return error_mark_node;
+ newrhs = rhs;
+
+ if (modifycode != INIT_EXPR)
+ {
+ /* Make modifycode now either a NOP_EXPR or an INIT_EXPR. */
+ modifycode = NOP_EXPR;
+ /* Reference-bashing */
+ if (TREE_CODE (lhstype) == REFERENCE_TYPE)
+ {
+ tree tmp = convert_from_reference (lhs);
+ lhstype = TREE_TYPE (tmp);
+ if (TYPE_SIZE (lhstype) == 0)
+ {
+ incomplete_type_error (lhs, lhstype);
+ return error_mark_node;
+ }
+ lhs = tmp;
+ olhstype = lhstype;
+ }
+ if (TREE_CODE (TREE_TYPE (newrhs)) == REFERENCE_TYPE)
+ {
+ tree tmp = convert_from_reference (newrhs);
+ if (TYPE_SIZE (TREE_TYPE (tmp)) == 0)
+ {
+ incomplete_type_error (newrhs, TREE_TYPE (tmp));
+ return error_mark_node;
+ }
+ newrhs = tmp;
+ }
+ }
+
+ if (TREE_VOLATILE (lhs))
+ lhs = stabilize_reference (lhs);
+ if (TREE_VOLATILE (newrhs))
+ newrhs = stabilize_reference (newrhs);
+
+ /* C++: The semantics of C++ differ from those of C when an
+ assignment of an aggregate is desired. Assignment in C++ is
+ now defined as memberwise assignment of non-static members
+ and base class objects. This rule applies recursively
+ until a member of a built-in type is found.
+
+ Also, we cannot do a bit-wise copy of aggregates which
+ contain virtual function table pointers. Those
+ pointer values must be preserved through the copy.
+ However, this is handled in expand_expr, and not here.
+ This is because much better code can be generated at
+ that stage than this one. */
+ if (TREE_CODE (lhstype) == RECORD_TYPE
+ && ((TYPE_USES_VIRTUAL_BASECLASSES (lhstype)
+ || (modifycode != INIT_EXPR && TYPE_GETS_ASSIGNMENT (lhstype))
+ || (modifycode == INIT_EXPR && TYPE_GETS_INIT_REF (lhstype)))
+ && (TYPE_MAIN_VARIANT (lhstype)
+ == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs))
+ || (TREE_CODE (TREE_TYPE (newrhs)) == RECORD_TYPE
+ && get_base_type (lhstype, TREE_TYPE (newrhs), 0)))))
+ {
+ tree vbases = CLASSTYPE_VBASECLASSES (lhstype);
+ tree lhs_addr = build_unary_op (ADDR_EXPR, lhs);
+ tree rhs_addr = build_unary_op (ADDR_EXPR, newrhs);
+ result = NULL_TREE;
+ if (! comptypes (TREE_TYPE (lhs_addr), TREE_TYPE (rhs_addr), 1))
+ {
+ rhs_addr = convert_pointer_to (TREE_TYPE (TREE_TYPE (lhs_addr)), rhs_addr);
+ newrhs = build_indirect_ref (rhs_addr, 0);
+ }
+
+ while (vbases)
+ {
+ tree elt_lhs = convert_pointer_to (TREE_TYPE (vbases), lhs_addr);
+ tree elt_rhs = convert_pointer_to (TREE_TYPE (vbases), rhs_addr);
+ result = tree_cons (NULL_TREE, build_modify_expr_1 (build_indirect_ref (elt_lhs, 0), modifycode, build_indirect_ref (elt_rhs, 0), CLASSTYPE_AS_LIST (lhstype)), result);
+ if (TREE_VALUE (result) == error_mark_node)
+ return error_mark_node;
+ vbases = TREE_CHAIN (vbases);
+ }
+ result = tree_cons (NULL_TREE,
+ build_modify_expr_1 (lhs, modifycode, newrhs, CLASSTYPE_AS_LIST (lhstype)),
+ result);
+ return build_compound_expr (result);
+ }
+
+ /* If storing in a field that is in actuality a short or narrower than one,
+ we must store in the field in its actual type. */
+
+ if (lhstype != TREE_TYPE (lhs))
+ {
+ lhs = copy_node (lhs);
+ TREE_TYPE (lhs) = lhstype;
+ }
+
+ /* Convert new value to destination type. */
+
+ if (modifycode == INIT_EXPR)
+ {
+ newrhs = convert_for_initialization (lhs, lhstype, newrhs, "assignment", LOOKUP_NORMAL);
+ if (lhs == DECL_RESULT (current_function_decl))
+ {
+ if (DECL_INITIAL (lhs))
+ warning ("return value from function receives multiple initializations");
+ DECL_INITIAL (lhs) = newrhs;
+ }
+ }
+ else
+ {
+ if (IS_AGGR_TYPE (lhstype))
+ {
+ if (TYPE_GETS_ASSIGNMENT (lhstype)
+ && ! TYPE_HAS_ASSIGNMENT (lhstype))
+ {
+ error_with_aggr_type (lhstype, "assignment not defined for type `%s'");
+ return error_mark_node;
+ }
+ if (result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, newrhs, NOP_EXPR))
+ return result;
+ }
+ else if (TREE_CODE (lhstype) == ARRAY_TYPE)
+ {
+ /* Have to wrap this in RTL_EXPR for two cases:
+ in base or member initialization and if we
+ are a branch of a ?: operator. Since we
+ can't easily know the latter, just do it always. */
+
+ extern struct rtx_def *get_insns (), *const0_rtx;
+ result = make_node (RTL_EXPR);
+
+ TREE_TYPE (result) = void_type_node;
+ do_pending_stack_adjust ();
+ start_sequence ();
+
+ /* As a matter of principle, `start_sequence' should do this. */
+ emit_note (0, -1);
+
+ expand_vec_init (lhs, lhs, array_type_nelts (lhstype), newrhs, 2);
+
+ do_pending_stack_adjust ();
+
+ TREE_VOLATILE (result) = 1;
+ RTL_EXPR_SEQUENCE (result) = get_insns ();
+ RTL_EXPR_RTL (result) = const0_rtx;
+ end_sequence ();
+ return result;
+ }
+ newrhs = convert_for_assignment (lhstype, newrhs, "assignment");
+ if (flag_elide_constructors == 0
+ && TREE_CODE (newrhs) == CALL_EXPR
+ && TREE_ADDRESSABLE (lhstype))
+ {
+ /* Can't initialized directly from a CALL_EXPR, since
+ we don't know about what doesn't alias what. */
+
+ if (TYPE_NEEDS_DESTRUCTOR (lhstype))
+ newrhs = cleanup_after_call (newrhs);
+ else
+ {
+ tree temp = get_temp_name (lhstype, 0);
+ newrhs = build (COMPOUND_EXPR, lhstype,
+ build_modify_expr (temp, INIT_EXPR, newrhs),
+ temp);
+ }
+ }
+ }
+
+ if (TREE_CODE (newrhs) == ERROR_MARK)
+ return error_mark_node;
+
+ result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
+ lhstype, lhs, newrhs);
+ TREE_VOLATILE (result) = 1;
+
+ /* If we got the LHS in a different type for storing in,
+ convert the result back to the nominal type of LHS
+ so that the value we return always has the same type
+ as the LHS argument. */
+
+ if (olhstype == TREE_TYPE (result))
+ return result;
+ return convert_for_assignment (olhstype, result, "assignment");
+}
+
+
+/* Return 0 if EXP is not a valid lvalue in this language
+ even though `lvalue_or_else' would accept it. */
+
+int
+language_lvalue_valid (exp)
+ tree exp;
+{
+ return 1;
+}
+\f
+/* Convert value RHS to type TYPE as preparation for an assignment
+ to an lvalue of type TYPE.
+ The real work of conversion is done by `convert'.
+ The purpose of this function is to generate error messages
+ for assignments that are not allowed in C.
+ ERRTYPE is a string to use in error messages:
+ "assignment", "return", etc.
+
+ C++: attempts to allow `convert' to find conversions involving
+ implicit type conversion between aggregate and scalar types
+ as per 8.5.6 of C++ manual. Does not randomly dereference
+ pointers to aggregates! */
+
+static tree
+convert_for_assignment (type, rhs, errtype)
+ tree type, rhs;
+ char *errtype;
+{
+ register enum tree_code codel = TREE_CODE (type);
+ register tree rhstype = datatype (rhs);
+ register enum tree_code coder = TREE_CODE (rhstype);
+
+ if (coder == UNKNOWN_TYPE)
+ {
+ rhs = instantiate_type (type, rhs, 1);
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+ }
+
+ if (coder == ERROR_MARK)
+ return error_mark_node;
+
+ if (codel == OFFSET_TYPE)
+ {
+ type = TREE_TYPE (type);
+ codel = TREE_CODE (type);
+ }
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs, since RHS is used in non-lvalue context. */
+ if (TREE_CODE (rhs) == NOP_EXPR
+ && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0)))
+ rhs = TREE_OPERAND (rhs, 0);
+
+ if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
+ {
+ rhs = resolve_offset_ref (rhs);
+ if (rhs == error_mark_node)
+ return error_mark_node;
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+ }
+
+ if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
+ {
+ rhs = default_conversion (rhs);
+ if (rhs == error_mark_node)
+ return rhs;
+ }
+ else if (coder == REFERENCE_TYPE)
+ {
+ rhs = convert_from_reference (rhs);
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+ }
+
+ /* This should no longer change types on us. */
+ if (TREE_CODE (rhs) == CONST_DECL)
+ rhs = DECL_INITIAL (rhs);
+ else if (TREE_READONLY_DECL_P (rhs))
+ rhs = decl_constant_value (rhs);
+
+ if (type == rhstype)
+ return rhs;
+
+ if (coder == VOID_TYPE)
+ {
+ error ("void value not ignored as it ought to be");
+ return error_mark_node;
+ }
+ /* Arithmetic types all interconvert. */
+ if ((codel == INTEGER_TYPE || codel == REAL_TYPE)
+ && (coder == INTEGER_TYPE || coder == REAL_TYPE))
+ {
+ /* But we should warn if assigning REAL_TYPE to INTEGER_TYPE. */
+ if (coder == REAL_TYPE && codel == INTEGER_TYPE)
+ warning ("float or double assigned to integer data type");
+ /* And we should warn if assigning a negative value to
+ an unsigned variable. */
+ else if (TREE_UNSIGNED (type))
+ {
+ if (TREE_CODE (rhs) == INTEGER_CST
+ && TREE_NEGATED_INT (rhs))
+ warning ("negative value assigned to unsigned quantity");
+ if (TREE_LITERAL (rhs))
+ rhs = fold (rhs);
+ }
+
+ return convert (type, rhs);
+ }
+ /* Conversions involving enums. */
+ else if ((codel == ENUMERAL_TYPE
+ && (coder == ENUMERAL_TYPE || coder == INTEGER_TYPE || coder == REAL_TYPE))
+ || (coder == ENUMERAL_TYPE
+ && (codel == ENUMERAL_TYPE || codel == INTEGER_TYPE || codel == REAL_TYPE)))
+ {
+ extern int warn_enum_clash;
+
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
+ return convert (type, rhs);
+ if (warn_enum_clash)
+ {
+ if (codel == ENUMERAL_TYPE && coder == ENUMERAL_TYPE)
+ message_2_types (warning, "conversion between incompatible enumeral types `%s' and `%s'",
+ type, rhstype);
+ else if (coder == REAL_TYPE)
+ warning ("float or double assigned to enumeral data type");
+ else if (codel == REAL_TYPE)
+ warning ("enumeral value assigned to real data type");
+ else if (coder == INTEGER_TYPE)
+ warning ("assignment of integer to enumeral data type");
+ }
+ return convert (type, rhs);
+ }
+ /* Conversions among pointers */
+ else if (codel == POINTER_TYPE && coder == POINTER_TYPE)
+ {
+ register tree ttl = TREE_TYPE (type);
+ register tree ttr = TREE_TYPE (rhstype);
+
+ /* If both pointers are of aggregate type, then we
+ can give better error messages, and save some work
+ as well. */
+ if (IS_AGGR_TYPE (ttl) && IS_AGGR_TYPE (ttr))
+ {
+ tree basetype;
+
+ if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr))
+ basetype = ttl;
+ else
+ basetype = get_base_type (ttl, ttr, 1);
+
+ if (basetype == error_mark_node)
+ return error_mark_node;
+ if (basetype == 0)
+ {
+ error_not_base_type (ttl, ttr);
+ return error_mark_node;
+ }
+ if (! TREE_READONLY (ttl) && TREE_READONLY (ttr))
+ warning ("%s of non-const * pointer from const *", errtype);
+ if (! TREE_VOLATILE (ttl) && TREE_VOLATILE (ttr))
+ warning ("%s of non-volatile * pointer from volatile *", errtype);
+ }
+ /* Any non-function converts to a [const][volatile] void *
+ and vice versa; otherwise, targets must be the same.
+ Meanwhile, the lhs target must have all the qualifiers of the rhs. */
+ else if (TYPE_MAIN_VARIANT (ttl) == void_type_node
+ || TYPE_MAIN_VARIANT (ttr) == void_type_node
+ || comp_target_types (type, rhstype, 1))
+ {
+ if (pedantic
+ && ((TYPE_MAIN_VARIANT (ttl) == void_type_node
+ && (TREE_CODE (ttr) == FUNCTION_TYPE
+ || TREE_CODE (ttr) == METHOD_TYPE))
+ ||
+ (TYPE_MAIN_VARIANT (ttr) == void_type_node
+ && (TREE_CODE (ttl) == FUNCTION_TYPE
+ || TREE_CODE (ttl) == METHOD_TYPE))))
+ warning ("%s between incompatible pointer types", errtype);
+ else
+ {
+ if (TREE_CODE (ttl) == OFFSET_TYPE
+ && virtual_member (TYPE_OFFSET_BASETYPE (ttr),
+ CLASSTYPE_VBASECLASSES (TYPE_OFFSET_BASETYPE (ttl))))
+ {
+ sorry ("%s between pointer to members converting across virtual baseclasses", errtype);
+ return error_mark_node;
+ }
+ if (! TREE_READONLY (ttl) && TREE_READONLY (ttr))
+ warning ("%s of non-const * pointer from const *", errtype);
+ if (! TREE_VOLATILE (ttl) && TREE_VOLATILE (ttr))
+ warning ("%s of non-volatile * pointer from volatile *", errtype);
+ }
+ }
+ else if (TREE_CODE (ttr) == OFFSET_TYPE
+ && TREE_CODE (ttl) != OFFSET_TYPE)
+ {
+ /* Normally, pointers to different type codes (other
+ than void) are not compatible, but we perform
+ some type instantiation if that resolves the
+ ambiguity of (X Y::*) and (X *). */
+
+ if (current_class_decl)
+ {
+ if (TREE_CODE (rhs) == INTEGER_CST)
+ {
+ rhs = build (PLUS_EXPR, build_pointer_type (TREE_TYPE (ttr)),
+ current_class_decl, rhs);
+ return convert_for_assignment (type, rhs, errtype);
+ }
+ }
+ if (TREE_CODE (ttl) == METHOD_TYPE)
+ error ("%s between pointer-to-method and pointer-to-member types", errtype);
+ else
+ error ("%s between pointer and pointer-to-member types", errtype);
+ return error_mark_node;
+ }
+ else
+ {
+ int const_parity = TREE_READONLY (type) ^ TREE_READONLY (rhstype);
+ int volatile_parity = TREE_VOLATILE (type) ^ TREE_VOLATILE (rhstype);
+ int unsigned_parity;
+ int nptrs = 0;
+
+ while (TREE_CODE (ttl) == POINTER_TYPE
+ && TREE_CODE (ttr) == POINTER_TYPE)
+ {
+ nptrs -= 1;
+ const_parity |= TREE_READONLY (ttl) ^ TREE_READONLY (ttr);
+ volatile_parity |= TREE_VOLATILE (ttl) ^ TREE_VOLATILE (ttr);
+ ttl = TREE_TYPE (ttl);
+ ttr = TREE_TYPE (ttr);
+ }
+ unsigned_parity = TREE_UNSIGNED (ttl) - TREE_UNSIGNED (ttr);
+ if (unsigned_parity)
+ if (TREE_UNSIGNED (ttl))
+ ttr = unsigned_type (ttr);
+ else
+ ttl = unsigned_type (ttl);
+
+ if (comp_target_types (ttl, ttr, nptrs))
+ {
+ if (const_parity)
+ warning ("%s of non-const * pointer from const *", errtype);
+ if (volatile_parity)
+ warning ("%s of non-volatile * pointer from volatile *", errtype);
+ if (unsigned_parity > 0)
+ warning ("%s of unsigned pointer from signed pointer", errtype);
+ else if (unsigned_parity < 0)
+ warning ("%s of signed pointer from unsigned pointer", errtype);
+
+ /* C++ is not so friendly about converting function and
+ member function pointers as C. Emit warnings here. */
+ if (TREE_CODE (ttl) == FUNCTION_TYPE
+ || TREE_CODE (ttl) == METHOD_TYPE)
+ if (! comptypes (ttl, ttr, 0))
+ {
+ char lhsbuf[2048];
+ char rhsbuf[2048];
+ tree null_name = get_identifier ("");
+ tree lhs = build_decl (FUNCTION_DECL, null_name, ttl);
+ tree rhs = build_decl (FUNCTION_DECL, null_name, ttr);
+ fndecl_as_string (lhsbuf, 0, lhs, 1);
+ fndecl_as_string (rhsbuf, 0, rhs, 1);
+ warning ("conflicting function types in %s:", errtype);
+ warning ("\t`%s' != `%s'", lhsbuf, rhsbuf);
+ }
+ }
+ else if (TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
+ {
+ /* When does this happen? */
+ abort ();
+ /* Conversion of a pointer-to-member type to void *. */
+ rhs = build_unary_op (ADDR_EXPR, rhs, 0);
+ TREE_TYPE (rhs) = type;
+ return rhs;
+ }
+ else if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
+ {
+ /* When does this happen? */
+ abort ();
+ /* Conversion of a pointer-to-member type to void *. */
+ rhs = build_unary_op (ADDR_EXPR, rhs, 0);
+ TREE_TYPE (rhs) = type;
+ return rhs;
+ }
+ else
+ {
+ error ("%s between incompatible pointer types", errtype);
+ return error_mark_node;
+ }
+ }
+ return convert (type, rhs);
+ }
+ else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
+ {
+ if (! integer_zerop (rhs))
+ {
+ warning ("%s of pointer from integer lacks a cast", errtype);
+ return convert (type, rhs);
+ }
+ return null_pointer_node;
+ }
+ else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
+ {
+ warning ("%s of integer from pointer lacks a cast", errtype);
+ return convert (type, rhs);
+ }
+
+ /* C++ */
+ else if (codel == ERROR_MARK || coder == ERROR_MARK)
+ return error_mark_node;
+
+ /* This should no longer happen. References are initialzed via
+ `convert_for_initialization'. They should otherwise be
+ bashed before coming here. */
+ else if (codel == REFERENCE_TYPE)
+ assert (codel != REFERENCE_TYPE);
+ else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (rhs)))
+ return build1 (NOP_EXPR, type, rhs);
+ else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
+ return convert (type, rhs);
+
+ error ("incompatible types in %s", errtype);
+ return error_mark_node;
+}
+
+/* Convert RHS to be of type TYPE. If EXP is non-zero,
+ it is the target of the initialization.
+ ERRTYPE is a string to use in error messages.
+
+ Two major differences between the behavior of
+ `convert_for_assignment' and `convert_for_initialization'
+ are that references are bashed in the former, while
+ copied in the latter, and aggregates are assigned in
+ the former (operator=) while initialized in the
+ latter (X(X&)). */
+tree
+convert_for_initialization (exp, type, rhs, errtype, flags)
+ tree exp, type, rhs;
+ char *errtype;
+ int flags;
+{
+ register enum tree_code codel = TREE_CODE (type);
+ register tree rhstype;
+ register enum tree_code coder;
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs, since RHS is used in non-lvalue context. */
+ if (TREE_CODE (rhs) == NOP_EXPR
+ && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0)))
+ rhs = TREE_OPERAND (rhs, 0);
+
+ if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
+ {
+ rhs = resolve_offset_ref (rhs);
+ if (rhs == error_mark_node)
+ return error_mark_node;
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+ }
+
+ if ((TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
+ && TREE_CODE (type) != ARRAY_TYPE && TREE_CODE (type) != REFERENCE_TYPE)
+ || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
+ rhs = default_conversion (rhs);
+
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+
+ if (coder == UNKNOWN_TYPE)
+ {
+ rhs = instantiate_type (type, rhs, 1);
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+ }
+
+ if (coder == ERROR_MARK)
+ return error_mark_node;
+
+#if 0
+ /* This is *not* the quick way out! It is the way to disaster. */
+ if (type == rhstype)
+ goto converted;
+#endif
+
+ /* We accept references to incomplete types, so we can
+ return here before checking if RHS is of complete type. */
+
+ if (codel == REFERENCE_TYPE)
+ return convert_to_reference ((exp ? exp : error_mark_node), type, rhs, 0, flags);
+
+ rhs = require_complete_type (rhs);
+ if (rhs == error_mark_node)
+ return error_mark_node;
+
+ if (exp != 0) exp = require_complete_type (exp);
+ if (exp == error_mark_node)
+ return error_mark_node;
+
+ if (TREE_CODE (rhstype) == REFERENCE_TYPE)
+ rhstype = TREE_TYPE (rhstype);
+
+ if (IS_AGGR_TYPE (type) && TYPE_NEEDS_CONSTRUCTOR (type))
+ {
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
+ {
+ /* This is sufficient to perform initialization. No need, apparently,
+ to go through X(X&) to do first-cut initialization. Return through
+ a NEW_EXPR so that we get cleanups if it is used. */
+ if (TREE_CODE (rhs) == CALL_EXPR)
+ {
+ rhs = build_cplus_new (type, rhs);
+ return rhs;
+ }
+ }
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)
+ || (IS_AGGR_TYPE (rhstype) && get_base_type (type, rhstype, 0)))
+ {
+ if (TYPE_HAS_INIT_REF (type))
+ {
+ tree init = build_method_call (exp, DECL_NAME (TYPE_NAME (type)),
+ build_tree_list (NULL_TREE, rhs),
+ NULL_TREE, LOOKUP_NORMAL);
+
+ if (init == error_mark_node)
+ return error_mark_node;
+
+ if (exp == 0)
+ {
+ exp = build_cplus_new (type, init);
+ return exp;
+ }
+
+ return build (COMPOUND_EXPR, type, init, exp);
+ }
+
+ if (TYPE_GETS_ASSIGNMENT (type))
+ warning ("bitwise copy: `%s' defines operator=()",
+ TYPE_NAME_STRING (type));
+
+ if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
+ rhs = convert_from_reference (rhs);
+ if (type != rhstype)
+ return build1 (NOP_EXPR, type, rhs);
+ return rhs;
+ }
+
+ return convert (type, rhs);
+ }
+ if (TYPE_LANG_SPECIFIC (type) && TYPE_GETS_ASSIGNMENT (type))
+ warning ("bitwise copy: `%s' defines operator=()",
+ TYPE_NAME_STRING (type));
+
+ converted:
+ if (type == TREE_TYPE (rhs))
+ {
+ if (TREE_READONLY_DECL_P (rhs))
+ rhs = decl_constant_value (rhs);
+ return rhs;
+ }
+
+ return convert_for_assignment (type, rhs, errtype);
+}
+\f
+/* Expand an ASM statement with operands, handling output operands
+ that are not variables or INDIRECT_REFS by transforming such
+ cases into cases that expand_asm_operands can handle.
+
+ Arguments are same as for expand_asm_operands. */
+
+void
+c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
+ tree string, outputs, inputs, clobbers;
+ int vol;
+ char *filename;
+ int line;
+{
+ int noutputs = list_length (outputs);
+ register int i;
+ /* o[I] is the place that output number I should be written. */
+ register tree *o = (tree *) alloca (noutputs * sizeof (tree));
+ register tree tail;
+
+ /* Record the contents of OUTPUTS before it is modifed. */
+ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+ o[i] = TREE_VALUE (tail);
+
+#if 0 /* Don't do this--it screws up operands expected to be in memory. */
+ /* Perform default conversions on all inputs. */
+ for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++)
+ TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
+#endif
+
+ /* Generate the ASM_OPERANDS insn;
+ store into the TREE_VALUEs of OUTPUTS some trees for
+ where the values were actually stored. */
+ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line);
+
+ /* Copy all the intermediate outputs into the specified outputs. */
+ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+ {
+ extern struct rtx_def *const0_rtx;
+
+ if (o[i] != TREE_VALUE (tail))
+ expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
+ const0_rtx, VOIDmode, 0);
+ /* Detect modification of read-only values.
+ (Otherwise done by build_modify_expr.) */
+ else
+ {
+ tree type = TREE_TYPE (o[i]);
+ if (TREE_READONLY (o[i])
+ || ((TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ && C_TYPE_FIELDS_READONLY (type)))
+ readonly_warning_or_error (o[i], "modification by `asm'");
+ }
+ }
+
+ /* Those MODIFY_EXPRs could do autoincrements. */
+ emit_queue ();
+}
+\f
+/* Expand a C `return' statement.
+ RETVAL is the expression for what to return,
+ or a null pointer for `return;' with no value.
+
+ C++: upon seeing a `return', we must call destructors on all
+ variables in scope which had constructors called on them.
+ This means that if in a destructor, the base class destructors
+ must be called before returning.
+
+ The RETURN statement in C++ has initialization semantics. */
+
+void
+c_expand_return (retval)
+ tree retval;
+{
+ extern struct rtx_def *original_result_rtx;
+ extern tree dtor_label, ctor_label;
+ tree result = DECL_RESULT (current_function_decl);
+ tree valtype = TREE_TYPE (result);
+ tree save_from_destructor = NULL_TREE;
+
+ if (TREE_THIS_VOLATILE (current_function_decl))
+ warning ("function declared `volatile' has a `return' statement");
+
+ if (retval == error_mark_node)
+ {
+ current_function_returns_null = 1;
+ return;
+ }
+
+ if (retval == NULL_TREE)
+ {
+ /* A non-named return value does not count. */
+ extern tree value_identifier;
+
+ /* Can't just return from a destructor. */
+ if (dtor_label)
+ {
+ expand_goto (dtor_label);
+ return;
+ }
+
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ retval = current_class_decl;
+ else if (result != NULL_TREE
+ && DECL_NAME (result) != value_identifier
+ && TREE_CODE (valtype) != VOID_TYPE)
+ retval = result;
+ else
+ {
+ current_function_returns_null = 1;
+ if (valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
+ {
+ extern tree value_identifier;
+ if (DECL_NAME (DECL_RESULT (current_function_decl)) == value_identifier)
+ warning ("`return' with no value, in function returning non-void");
+ }
+
+ expand_null_return ();
+ return;
+ }
+ }
+
+ if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
+ {
+ current_function_returns_null = 1;
+ if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
+ warning ("`return' with a value, in function returning void");
+ expand_return (retval);
+ }
+ else
+ {
+ register tree t;
+ register int use_temp = 0;
+
+ if (retval == result)
+ ;
+ else if (IS_AGGR_TYPE (valtype) && TYPE_NEEDS_CONSTRUCTOR (valtype))
+ {
+ expand_aggr_init (result, retval, 0);
+ save_from_destructor = DECL_INITIAL (result);
+ DECL_INITIAL (result) = NULL_TREE;
+ retval = 0;
+ }
+ else
+ {
+ /* Watch out for constructors, which "return" aggregates
+ via initialization, but which otherwise "return" a pointer. */
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ {
+ if (retval != current_class_decl)
+ {
+ error ("return from a constructor: use `this = ...' instead");
+ retval = current_class_decl;
+ }
+ }
+ else
+ {
+ retval = convert_for_initialization (result, valtype, retval, "return", LOOKUP_NORMAL);
+ if (retval == error_mark_node)
+ return;
+ save_from_destructor = DECL_INITIAL (result);
+ DECL_INITIAL (result) = NULL_TREE;
+ }
+
+ /* Add some useful error checking for C++. */
+ if (TREE_CODE (valtype) == REFERENCE_TYPE)
+ {
+ tree whats_returned = retval;
+
+ /* Sort through common things to see what it is
+ we are returning. */
+ if (TREE_CODE (retval) == COMPOUND_EXPR)
+ {
+ whats_returned = TREE_OPERAND (retval, 1);
+ if (TREE_CODE (whats_returned) == ADDR_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ }
+ if (TREE_CODE (retval) == VAR_DECL)
+ whats_returned = retval;
+ else if (TREE_CODE (retval) == ADDR_EXPR)
+ {
+ whats_returned = TREE_OPERAND (retval, 0);
+ if (TREE_CODE (whats_returned) == NEW_EXPR)
+ /* Get the target. */
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ }
+
+ if (TREE_CODE (whats_returned) == VAR_DECL)
+ if (DECL_NAME (whats_returned) == NULL_TREE
+ || TEMP_NAME_P (DECL_NAME (whats_returned)))
+ warning ("reference to non-lvalue returned");
+ else if (! TREE_STATIC (whats_returned)
+ && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned)))
+ warning_with_decl (whats_returned, "reference to local variable `%s' returned");
+ }
+ }
+
+ /* Now deal with possible C++ hair:
+ (1) Compute the return value.
+ (2) If there are aggregate values with destructors which
+ must be cleaned up, clean them (taking care
+ not to clobber the return value).
+ (3) If an X(X&) constructor is defined, the return
+ value must be returned via that. */
+
+ /* Keep anybody from thinking that our return value
+ is up for grabs (i.e., later inline function expansion).
+ We cannot use a `save_expr' here, because the
+ return value must be calculated _now_,
+ and wrapping it in a SAVE_EXPR just make it
+ be calculated _once_.
+
+ We look up the binding contours to see whether there are
+ any cleanups to perform to avoid, where possible, the need
+ to pass the value through a temporary. This is needed to make
+ tail-recursion work in GCC. */
+ /* use_variable (DECL_RTL (result)); */
+
+ if (retval && TYPE_MODE (valtype) != BLKmode
+ && any_pending_cleanups ())
+ {
+ t = get_temp_regvar (valtype, retval);
+ use_temp = obey_regdecls;
+ }
+ else
+ t = retval;
+
+ emit_queue ();
+
+ if (t == result)
+ {
+ if (original_result_rtx)
+ store_expr (result, original_result_rtx, 0);
+ use_variable (DECL_RTL (t));
+ if (ctor_label)
+ expand_goto (ctor_label);
+ else
+ expand_null_return ();
+ }
+ else
+ {
+ if (original_result_rtx)
+ {
+ if (t)
+ expand_assignment (result, t, 0, 0);
+ else
+ store_expr (result, original_result_rtx, 0);
+ result = build (SAVE_EXPR, TREE_TYPE (result),
+ error_mark_node, original_result_rtx);
+ }
+
+ if (ctor_label)
+ {
+ result = build (INIT_EXPR, TREE_TYPE (result), result, t);
+ TREE_VOLATILE (result) = 1;
+ expand_expr_stmt (result);
+ expand_goto (ctor_label);
+ }
+ else if (t)
+ {
+ result = build (INIT_EXPR, TREE_TYPE (result), result, t);
+ TREE_VOLATILE (result) = 1;
+ expand_return (result);
+ }
+ else
+ expand_return (result);
+ }
+
+ current_function_returns_value = 1;
+ if (original_result_rtx)
+ use_variable (original_result_rtx);
+ if (use_temp)
+ use_variable (DECL_RTL (t));
+ }
+ /* One way to clear out cleanups that EXPR might
+ generate. Note that this code will really be
+ dead code, but that is ok--cleanups that were
+ needed were handled by the magic of `return'. */
+ expand_cleanups_to (NULL_TREE);
+}
+\f
+/* Start a C switch statement, testing expression EXP.
+ Return EXP if it is valid, an error node otherwise. */
+
+tree
+c_expand_start_case (exp)
+ tree exp;
+{
+ tree type = TREE_TYPE (exp);
+ register enum tree_code code = TREE_CODE (type);
+
+ if (IS_AGGR_TYPE_CODE (code))
+ exp = build_type_conversion (CONVERT_EXPR, integer_type_node, exp, 1);
+ else
+ exp = default_conversion (exp);
+ type = TREE_TYPE (exp);
+ code = TREE_CODE (type);
+
+ if (code != INTEGER_TYPE && code != ENUMERAL_TYPE && code != ERROR_MARK)
+ {
+ error ("switch quantity not an integer");
+ exp = error_mark_node;
+ }
+ else
+ {
+ tree index;
+
+ index = get_unwidened (exp, 0);
+ /* We can't strip a conversion from a signed type to an unsigned,
+ because if we did, int_fits_type_p would do the wrong thing
+ when checking case values for being in range,
+ and it's too hard to do the right thing. */
+ if (TREE_UNSIGNED (TREE_TYPE (exp))
+ == TREE_UNSIGNED (TREE_TYPE (index)))
+ exp = index;
+ }
+
+ expand_start_case (1, exp, type);
+
+ return exp;
+}