diff options
author | YamaArashi <shadow962@live.com> | 2016-01-06 01:47:28 -0800 |
---|---|---|
committer | YamaArashi <shadow962@live.com> | 2016-01-06 01:47:28 -0800 |
commit | be8b04496302184c6e8f04d6179f9c3afc50aeb6 (patch) | |
tree | 726e2468c0c07add773c0dbd86ab6386844259ae /gcc/cp/typeck.c |
initial commit
Diffstat (limited to 'gcc/cp/typeck.c')
-rwxr-xr-x | gcc/cp/typeck.c | 7495 |
1 files changed, 7495 insertions, 0 deletions
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c new file mode 100755 index 0000000..58c19a4 --- /dev/null +++ b/gcc/cp/typeck.c @@ -0,0 +1,7495 @@ +/* Build expressions with type checking for C++ compiler. + Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc. + Hacked by Michael Tiemann (tiemann@cygnus.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 2, 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 and 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). */ + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "rtl.h" +#include "cp-tree.h" +#include "flags.h" +#include "output.h" +#include "expr.h" +#include "toplev.h" + +extern void compiler_error (); + +static tree convert_for_assignment PROTO((tree, tree, char*, tree, + int)); +static tree pointer_int_sum PROTO((enum tree_code, tree, tree)); +static tree rationalize_conditional_expr PROTO((enum tree_code, tree)); +static int comp_target_parms PROTO((tree, tree, int)); +static int comp_ptr_ttypes_real PROTO((tree, tree, int)); +static int comp_ptr_ttypes_const PROTO((tree, tree)); +static int comp_ptr_ttypes_reinterpret PROTO((tree, tree)); +static int comp_array_types PROTO((int (*) (tree, tree, int), tree, + tree, int)); +static tree build_ptrmemfunc1 PROTO((tree, tree, tree, tree, tree)); +static tree common_base_type PROTO((tree, tree)); +#if 0 +static tree convert_sequence PROTO((tree, tree)); +#endif +static tree lookup_anon_field PROTO((tree, tree)); +static tree pointer_diff PROTO((tree, tree, tree)); +static tree qualify_type PROTO((tree, tree)); +static tree get_delta_difference PROTO((tree, tree, int)); + +/* 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.) + Returns the error_mark_node if the VALUE does not have + complete type when this function returns. */ + +tree +require_complete_type (value) + tree value; +{ + tree type; + + if (processing_template_decl) + return value; + + if (TREE_CODE (value) == OVERLOAD) + type = unknown_type_node; + else + type = TREE_TYPE (value); + + /* First, detect a valid value with a complete type. */ + if (TYPE_SIZE (type) != 0 + && type != void_type_node + && ! (TYPE_LANG_SPECIFIC (type) + && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)) + && TYPE_SIZE (SIGNATURE_TYPE (type)) == 0)) + 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 + && current_class_ref != 0 + && TREE_OPERAND (value, 0) == current_class_ref) + { + tree base, member = TREE_OPERAND (value, 1); + tree basetype = TYPE_OFFSET_BASETYPE (type); + my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305); + base = convert_pointer_to (basetype, current_class_ptr); + value = build (COMPONENT_REF, TREE_TYPE (member), + build_indirect_ref (base, NULL_PTR), member); + return require_complete_type (value); + } + + if (complete_type_or_else (type)) + return value; + else + return error_mark_node; +} + +/* Try to complete TYPE, if it is incomplete. For example, if TYPE is + a template instantiation, do the instantiation. Returns TYPE, + whether or not it could be completed, unless something goes + horribly wrong, in which case the error_mark_node is returned. */ + +tree +complete_type (type) + tree type; +{ + if (type == NULL_TREE) + /* Rather than crash, we return something sure to cause an error + at some point. */ + return error_mark_node; + + if (type == error_mark_node || TYPE_SIZE (type) != NULL_TREE) + ; + else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type)) + { + tree t = complete_type (TREE_TYPE (type)); + if (TYPE_SIZE (t) != NULL_TREE && ! processing_template_decl) + layout_type (type); + TYPE_NEEDS_CONSTRUCTING (type) + = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t)); + TYPE_NEEDS_DESTRUCTOR (type) + = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t)); + } + else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type)) + instantiate_class_template (TYPE_MAIN_VARIANT (type)); + + return type; +} + +/* Like complete_type, but issue an error if the TYPE cannot be + completed. Returns NULL_TREE if the type cannot be made + complete. */ + +tree +complete_type_or_else (type) + tree type; +{ + type = complete_type (type); + if (type == error_mark_node) + /* We already issued an error. */ + return NULL_TREE; + else if (!TYPE_SIZE (type)) + { + incomplete_type_error (NULL_TREE, type); + return NULL_TREE; + } + else + return type; +} + +/* Return truthvalue of whether type of EXP is instantiated. */ + +int +type_unknown_p (exp) + tree exp; +{ + return (TREE_CODE (exp) == OVERLOAD + || TREE_CODE (exp) == TREE_LIST + || TREE_TYPE (exp) == unknown_type_node + || (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE + && TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node)); +} + +/* Return truthvalue of whether T is function (or pfn) type. */ + +int +fntype_p (t) + tree t; +{ + return (TREE_CODE (t) == FUNCTION_TYPE || TREE_CODE (t) == METHOD_TYPE + || (TREE_CODE (t) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE))); +} + +/* 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; +{ + /* @@ Must do member pointers here. */ + return cp_build_qualified_type (type, (CP_TYPE_QUALS (type) + | CP_TYPE_QUALS (like))); +} + +/* Return the common type of two parameter lists. + We assume that comptypes has already been done and returned 1; + if that isn't so, this may crash. + + 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 *) oballoc (0); + + len = list_length (p1); + newargs = tree_last (p1); + + if (newargs == void_list_node) + i = 1; + else + { + i = 0; + newargs = 0; + } + + for (; i < len; i++) + newargs = tree_cons (NULL_TREE, NULL_TREE, 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)) + { + TREE_PURPOSE (n) = TREE_PURPOSE (p1); + any_change = 1; + } + else if (! TREE_PURPOSE (p1)) + { + if (TREE_PURPOSE (p2)) + { + TREE_PURPOSE (n) = TREE_PURPOSE (p2); + any_change = 1; + } + } + else + { + if (1 != simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2))) + any_change = 1; + TREE_PURPOSE (n) = TREE_PURPOSE (p2); + } + if (TREE_VALUE (p1) != TREE_VALUE (p2)) + { + any_change = 1; + TREE_VALUE (n) = common_type (TREE_VALUE (p1), TREE_VALUE (p2)); + } + else + TREE_VALUE (n) = TREE_VALUE (p1); + } + if (! any_change) + { + obfree (first_obj); + return oldargs; + } + + return newargs; +} + +/* Given a type, perhaps copied for a typedef, + find the "original" version of it. */ +tree +original_type (t) + tree t; +{ + while (TYPE_NAME (t) != NULL_TREE) + { + tree x = TYPE_NAME (t); + if (TREE_CODE (x) != TYPE_DECL) + break; + x = DECL_ORIGINAL_TYPE (x); + if (x == NULL_TREE) + break; + t = x; + } + return t; +} + +/* 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 +common_type (t1, t2) + tree t1, t2; +{ + register enum tree_code code1; + register enum tree_code code2; + tree attributes; + + /* Save time if the two types are the same. */ + if (t1 == t2) + return t1; + t1 = original_type (t1); + t2 = original_type (t2); + if (t1 == t2) + return t1; + + /* If one type is nonsense, use the other. */ + if (t1 == error_mark_node) + return t2; + if (t2 == error_mark_node) + return t1; + + /* Merge the attributes. */ + attributes = merge_machine_type_attributes (t1, t2); + + { register tree a1, a2; + a1 = TYPE_ATTRIBUTES (t1); + a2 = TYPE_ATTRIBUTES (t2); + + /* Either one unset? Take the set one. */ + + if (!(attributes = a1)) + attributes = a2; + + /* One that completely contains the other? Take it. */ + + else if (a2 && !attribute_list_contained (a1, a2)) + { + if (attribute_list_contained (a2, a1)) + attributes = a2; + else + { + /* Pick the longest list, and hang on the other list. */ + /* ??? For the moment we punt on the issue of attrs with args. */ + + if (list_length (a1) < list_length (a2)) + attributes = a2, a2 = a1; + + for (; a2; a2 = TREE_CHAIN (a2)) + if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)), + attributes) == NULL_TREE) + { + a1 = copy_node (a2); + TREE_CHAIN (a1) = attributes; + attributes = a1; + } + } + } + } + + /* 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 (TYPE_PTRMEMFUNC_P (t1)) + t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1); + if (TYPE_PTRMEMFUNC_P (t2)) + t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2); + + code1 = TREE_CODE (t1); + code2 = TREE_CODE (t2); + + /* If one type is complex, form the common type of the non-complex + components, then make that complex. Use T1 or T2 if it is the + required type. */ + if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) + { + tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1; + tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2; + tree subtype = common_type (subtype1, subtype2); + + if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype) + return build_type_attribute_variant (t1, attributes); + else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype) + return build_type_attribute_variant (t2, attributes); + else + return build_type_attribute_variant (build_complex_type (subtype), + attributes); + } + + switch (code1) + { + case INTEGER_TYPE: + case REAL_TYPE: + /* If only one is real, use it as the result. */ + + if (code1 == REAL_TYPE && code2 != REAL_TYPE) + return build_type_attribute_variant (t1, attributes); + + if (code2 == REAL_TYPE && code1 != REAL_TYPE) + return build_type_attribute_variant (t2, attributes); + + /* Both real or both integers; use the one with greater precision. */ + + if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) + return build_type_attribute_variant (t1, attributes); + else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1)) + return build_type_attribute_variant (t2, attributes); + + /* Same precision. Prefer longs to ints even when same size. */ + + if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node + || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node) + return build_type_attribute_variant (long_unsigned_type_node, + attributes); + + if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node + || TYPE_MAIN_VARIANT (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)) + t1 = long_unsigned_type_node; + else + t1 = long_integer_type_node; + return build_type_attribute_variant (t1, attributes); + } + + if (TYPE_MAIN_VARIANT (t1) == long_double_type_node + || TYPE_MAIN_VARIANT (t2) == long_double_type_node) + return build_type_attribute_variant (long_double_type_node, + attributes); + + /* Otherwise prefer the unsigned one. */ + + if (TREE_UNSIGNED (t1)) + return build_type_attribute_variant (t1, attributes); + else + return build_type_attribute_variant (t2, attributes); + + 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. */ + /* This code was turned off; I don't know why. + But ANSI C++ specifies doing this with the qualifiers. + So I turned it on again. */ + { + tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (t1)); + tree tt2 = TYPE_MAIN_VARIANT (TREE_TYPE (t2)); + int type_quals = (CP_TYPE_QUALS (TREE_TYPE (t1)) + | CP_TYPE_QUALS (TREE_TYPE (t2))); + tree target; + + if (tt1 == tt2) + target = tt1; + else if (tt1 == void_type_node || tt2 == void_type_node) + target = void_type_node; + else if (tt1 == unknown_type_node) + target = tt2; + else if (tt2 == unknown_type_node) + target = tt1; + else + target = common_type (tt1, tt2); + + target = cp_build_qualified_type (target, type_quals); + if (code1 == POINTER_TYPE) + t1 = build_pointer_type (target); + else + t1 = build_reference_type (target); + t1 = build_type_attribute_variant (t1, attributes); + + if (TREE_CODE (target) == METHOD_TYPE) + t1 = build_ptrmemfunc_type (t1); + + return t1; + } + + case ARRAY_TYPE: + { + tree elt = common_type (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 build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2)) + return build_type_attribute_variant (t2, attributes); + /* Merge the element types, and have a size if either arg has one. */ + t1 = build_cplus_array_type + (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2)); + return build_type_attribute_variant (t1, attributes); + } + + 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 = common_type (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) && ! p2) + return build_type_attribute_variant (t1, attributes); + if (valtype == TREE_TYPE (t2) && ! p1) + return build_type_attribute_variant (t2, attributes); + + /* Simple way if one arg fails to specify argument types. */ + if (p1 == NULL_TREE || TREE_VALUE (p1) == void_type_node) + { + rval = build_function_type (valtype, p2); + if ((raises = TYPE_RAISES_EXCEPTIONS (t2))) + rval = build_exception_variant (rval, raises); + return build_type_attribute_variant (rval, attributes); + } + raises = TYPE_RAISES_EXCEPTIONS (t1); + if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node) + { + rval = build_function_type (valtype, p1); + if (raises) + rval = build_exception_variant (rval, raises); + return build_type_attribute_variant (rval, attributes); + } + + rval = build_function_type (valtype, commonparms (p1, p2)); + rval = build_exception_variant (rval, raises); + return build_type_attribute_variant (rval, attributes); + } + + case RECORD_TYPE: + case UNION_TYPE: + t1 = TYPE_MAIN_VARIANT (t1); + t2 = TYPE_MAIN_VARIANT (t2); + + if (DERIVED_FROM_P (t1, t2) && binfo_or_else (t1, t2)) + return build_type_attribute_variant (t1, attributes); + else if (binfo_or_else (t2, t1)) + return build_type_attribute_variant (t2, attributes); + else + { + compiler_error ("common_type called with uncommon aggregate types"); + return error_mark_node; + } + + case METHOD_TYPE: + if (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 raises, t3; + + tree b1 = TYPE_OFFSET_BASETYPE (t1); + tree b2 = TYPE_OFFSET_BASETYPE (t2); + + if (same_type_p (b1, b2) + || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))) + basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2))); + else + { + if (binfo_or_else (b2, b1) == NULL_TREE) + compiler_error ("common_type called with uncommon method types"); + basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1))); + } + + 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 = common_type (t1, t2); + t3 = build_cplus_method_type (basetype, TREE_TYPE (t3), + TYPE_ARG_TYPES (t3)); + t1 = build_exception_variant (t3, raises); + } + else + compiler_error ("common_type called with uncommon method types"); + + return build_type_attribute_variant (t1, attributes); + + case OFFSET_TYPE: + if (TREE_TYPE (t1) == TREE_TYPE (t2)) + { + tree b1 = TYPE_OFFSET_BASETYPE (t1); + tree b2 = TYPE_OFFSET_BASETYPE (t2); + + if (same_type_p (b1, b2) + || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))) + return build_type_attribute_variant (t2, attributes); + else if (binfo_or_else (b2, b1)) + return build_type_attribute_variant (t1, attributes); + } + compiler_error ("common_type called with uncommon member types"); + + default: + return build_type_attribute_variant (t1, attributes); + } +} + +/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */ + +int +compexcepttypes (t1, t2) + tree t1, t2; +{ + return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2); +} + +/* Compare the array types T1 and T2, using CMP as the type comparison + function for the element types. STRICT is as for comptypes. */ + +static int +comp_array_types (cmp, t1, t2, strict) + register int (*cmp) PROTO((tree, tree, int)); + tree t1, t2; + int strict; +{ + tree d1; + tree d2; + + if (t1 == t2) + return 1; + + /* The type of the array elements must be the same. */ + if (!(TREE_TYPE (t1) == TREE_TYPE (t2) + || (*cmp) (TREE_TYPE (t1), TREE_TYPE (t2), + strict & ~COMPARE_REDECLARATION))) + return 0; + + d1 = TYPE_DOMAIN (t1); + d2 = TYPE_DOMAIN (t2); + + if (d1 == d2) + return 1; + + /* If one of the arrays is dimensionless, and the other has a + dimension, they are of different types. However, it is legal to + write: + + extern int a[]; + int a[3]; + + by [basic.link]: + + declarations for an array object can specify + array types that differ by the presence or absence of a major + array bound (_dcl.array_). */ + if (!d1 || !d2) + return strict & COMPARE_REDECLARATION; + + /* Check that the dimensions are the same. */ + return (cp_tree_equal (TYPE_MIN_VALUE (d1), + TYPE_MIN_VALUE (d2)) + && cp_tree_equal (TYPE_MAX_VALUE (d1), + TYPE_MAX_VALUE (d2))); +} + +/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment + or various other operations. STRICT is a bitwise-or of the + COMPARE_* flags. */ + +int +comptypes (type1, type2, strict) + tree type1, type2; + int strict; +{ + register tree t1 = type1; + register tree t2 = type2; + int attrval, val; + int orig_strict = strict; + + /* The special exemption for redeclaring array types without an + array bound only applies at the top level: + + extern int (*i)[]; + int (*i)[8]; + + is not legal, for example. */ + strict &= ~COMPARE_REDECLARATION; + + /* Suppress errors caused by previously reported errors */ + if (t1 == t2) + return 1; + + /* This should never happen. */ + my_friendly_assert (t1 != error_mark_node, 307); + + if (t2 == error_mark_node) + return 0; + + if (strict & COMPARE_RELAXED) + { + /* 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; + } + + if (TYPE_PTRMEMFUNC_P (t1)) + t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1); + if (TYPE_PTRMEMFUNC_P (t2)) + t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2); + + /* Different classes of types can't be compatible. */ + if (TREE_CODE (t1) != TREE_CODE (t2)) + return 0; + + /* Qualifiers must match. */ + if (CP_TYPE_QUALS (t1) != CP_TYPE_QUALS (t2)) + return 0; + if (strict == COMPARE_STRICT + && TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2)) + return 0; + + /* Allow for two different type nodes which have essentially the same + definition. Note that we already checked for equality of the type + qualifiers (just above). */ + + if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) + return 1; + + /* ??? COMP_TYPE_ATTRIBUTES is currently useless for variables as each + attribute is its own main variant (`val' will remain 0). */ +#ifndef COMP_TYPE_ATTRIBUTES +#define COMP_TYPE_ATTRIBUTES(t1,t2) 1 +#endif + + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2))) + return 0; + + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + val = 0; + + switch (TREE_CODE (t1)) + { + case TEMPLATE_TEMPLATE_PARM: + if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2) + || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2)) + return 0; + if (! comp_template_parms (DECL_TEMPLATE_PARMS (TYPE_NAME (t1)), + DECL_TEMPLATE_PARMS (TYPE_NAME (t2)))) + return 0; + if (!TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t1) + && ! TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2)) + return 1; + /* Don't check inheritance. */ + strict = COMPARE_STRICT; + /* fall through */ + + case RECORD_TYPE: + case UNION_TYPE: + if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2) + && (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2) + || TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)) + val = comp_template_args (TYPE_TI_ARGS (t1), + TYPE_TI_ARGS (t2)); + look_hard: + if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2)) + { + val = 1; + break; + } + if ((strict & COMPARE_RELAXED) && DERIVED_FROM_P (t2, t1)) + { + val = 1; + break; + } + break; + + case OFFSET_TYPE: + val = (comptypes (build_pointer_type (TYPE_OFFSET_BASETYPE (t1)), + build_pointer_type (TYPE_OFFSET_BASETYPE (t2)), strict) + && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)); + break; + + case METHOD_TYPE: + if (! compexcepttypes (t1, t2)) + 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! */ + + val = (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict) + && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))); + break; + + case POINTER_TYPE: + case REFERENCE_TYPE: + t1 = TREE_TYPE (t1); + t2 = TREE_TYPE (t2); + /* first, check whether the referred types match with the + required level of strictness */ + val = comptypes (t1, t2, strict); + if (val) + break; + if (TREE_CODE (t1) == RECORD_TYPE + && TREE_CODE (t2) == RECORD_TYPE) + goto look_hard; + break; + + case FUNCTION_TYPE: + if (! compexcepttypes (t1, t2)) + return 0; + + val = ((TREE_TYPE (t1) == TREE_TYPE (t2) + || comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)) + && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))); + break; + + case ARRAY_TYPE: + /* Target types must match incl. qualifiers. We use ORIG_STRICT + here since this is the one place where + COMPARE_REDECLARATION should be used. */ + val = comp_array_types (comptypes, t1, t2, orig_strict); + break; + + case TEMPLATE_TYPE_PARM: + return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2) + && TEMPLATE_TYPE_LEVEL (t1) == TEMPLATE_TYPE_LEVEL (t2); + + case TYPENAME_TYPE: + if (TYPE_IDENTIFIER (t1) != TYPE_IDENTIFIER (t2)) + return 0; + return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)); + + default: + break; + } + return attrval == 2 && val == 1 ? 2 : val; +} + +/* Subroutine of comp_target-types. Make sure that the cv-quals change + only in the same direction as the target type. */ + +static int +comp_cv_target_types (ttl, ttr, nptrs) + tree ttl, ttr; + int nptrs; +{ + int t; + + if (!at_least_as_qualified_p (ttl, ttr) + && !at_least_as_qualified_p (ttr, ttl)) + /* The qualifications are incomparable. */ + return 0; + + if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr)) + return more_qualified_p (ttr, ttl) ? -1 : 1; + + t = comp_target_types (ttl, ttr, nptrs); + if ((t == 1 && at_least_as_qualified_p (ttl, ttr)) + || (t == -1 && at_least_as_qualified_p (ttr, ttl))) + return t; + + return 0; +} + +/* Return 1 or -1 if TTL and TTR are pointers to types that are equivalent, + ignoring their qualifiers, 0 if not. Return 1 means that TTR can be + converted to TTL. Return -1 means that TTL can be converted to TTR but + not vice versa. + + 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**. + + This should go away. Callers should use can_convert or something + similar instead. (jason 17 Apr 1997) */ + +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 + || TREE_CODE (ttr) == REFERENCE_TYPE) + /* If we get a pointer with nptrs == 0, we don't allow any tweaking + of the type pointed to. This is necessary for reference init + semantics. We won't get here from a previous call with nptrs == 1; + for multi-level pointers we end up in comp_ptr_ttypes. */ + && nptrs > 0) + { + int is_ptr = TREE_CODE (ttr) == POINTER_TYPE; + + ttl = TREE_TYPE (ttl); + ttr = TREE_TYPE (ttr); + + if (is_ptr) + { + if (TREE_CODE (ttl) == UNKNOWN_TYPE + || TREE_CODE (ttr) == UNKNOWN_TYPE) + return 1; + else if (TREE_CODE (ttl) == VOID_TYPE + && TREE_CODE (ttr) != FUNCTION_TYPE + && TREE_CODE (ttr) != METHOD_TYPE + && TREE_CODE (ttr) != OFFSET_TYPE) + return 1; + else if (TREE_CODE (ttr) == VOID_TYPE + && TREE_CODE (ttl) != FUNCTION_TYPE + && TREE_CODE (ttl) != METHOD_TYPE + && TREE_CODE (ttl) != OFFSET_TYPE) + return -1; + else if (TREE_CODE (ttl) == POINTER_TYPE + || TREE_CODE (ttl) == ARRAY_TYPE) + { + if (comp_ptr_ttypes (ttl, ttr)) + return 1; + else if (comp_ptr_ttypes (ttr, ttl)) + return -1; + return 0; + } + } + + /* Const and volatile mean something different for function types, + so the usual checks are not appropriate. */ + if (TREE_CODE (ttl) == FUNCTION_TYPE || TREE_CODE (ttl) == METHOD_TYPE) + return comp_target_types (ttl, ttr, nptrs - 1); + + return comp_cv_target_types (ttl, ttr, nptrs - 1); + } + + if (TREE_CODE (ttr) == ARRAY_TYPE) + return comp_array_types (comp_target_types, ttl, ttr, COMPARE_STRICT); + else if (TREE_CODE (ttr) == FUNCTION_TYPE || TREE_CODE (ttr) == METHOD_TYPE) + { + tree argsl, argsr; + int saw_contra = 0; + + if (pedantic) + { + if (!same_type_p (TREE_TYPE (ttl), TREE_TYPE (ttr))) + return 0; + } + else + { + switch (comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), -1)) + { + case 0: + return 0; + case -1: + saw_contra = 1; + } + } + + argsl = TYPE_ARG_TYPES (ttl); + argsr = TYPE_ARG_TYPES (ttr); + + /* Compare 'this' here, not in comp_target_parms. */ + if (TREE_CODE (ttr) == METHOD_TYPE) + { + tree tl = TYPE_METHOD_BASETYPE (ttl); + tree tr = TYPE_METHOD_BASETYPE (ttr); + + if (!same_or_base_type_p (tr, tl)) + { + if (same_or_base_type_p (tl, tr)) + saw_contra = 1; + else + return 0; + } + + argsl = TREE_CHAIN (argsl); + argsr = TREE_CHAIN (argsr); + } + + switch (comp_target_parms (argsl, argsr, 1)) + { + case 0: + return 0; + case -1: + saw_contra = 1; + } + + return saw_contra ? -1 : 1; + } + /* for C++ */ + else if (TREE_CODE (ttr) == OFFSET_TYPE) + { + int base; + + /* 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 (same_or_base_type_p (TYPE_OFFSET_BASETYPE (ttr), + TYPE_OFFSET_BASETYPE (ttl))) + base = 1; + else if (same_or_base_type_p (TYPE_OFFSET_BASETYPE (ttl), + TYPE_OFFSET_BASETYPE (ttr))) + { + tree tmp = ttl; + ttl = ttr; + ttr = tmp; + base = -1; + } + else + return 0; + + ttl = TREE_TYPE (ttl); + ttr = TREE_TYPE (ttr); + + if (TREE_CODE (ttl) == POINTER_TYPE + || TREE_CODE (ttl) == ARRAY_TYPE) + { + if (comp_ptr_ttypes (ttl, ttr)) + return base; + return 0; + } + else + { + if (comp_cv_target_types (ttl, ttr, nptrs) == 1) + return base; + return 0; + } + } + else if (IS_AGGR_TYPE (ttl)) + { + if (nptrs < 0) + return 0; + if (same_or_base_type_p (build_pointer_type (ttl), + build_pointer_type (ttr))) + return 1; + if (same_or_base_type_p (build_pointer_type (ttr), + build_pointer_type (ttl))) + return -1; + return 0; + } + + return 0; +} + +/* Returns 1 if TYPE1 is at least as qualified as TYPE2. */ + +int +at_least_as_qualified_p (type1, type2) + tree type1; + tree type2; +{ + /* All qualifiers for TYPE2 must also appear in TYPE1. */ + return ((CP_TYPE_QUALS (type1) & CP_TYPE_QUALS (type2)) + == CP_TYPE_QUALS (type2)); +} + +/* Returns 1 if TYPE1 is more qualified than TYPE2. */ + +int +more_qualified_p (type1, type2) + tree type1; + tree type2; +{ + return (CP_TYPE_QUALS (type1) != CP_TYPE_QUALS (type2) + && at_least_as_qualified_p (type1, type2)); +} + +/* Returns 1 if TYPE1 is more cv-qualified than TYPE2, -1 if TYPE2 is + more cv-qualified that TYPE1, and 0 otherwise. */ + +int +comp_cv_qualification (type1, type2) + tree type1; + tree type2; +{ + if (CP_TYPE_QUALS (type1) == CP_TYPE_QUALS (type2)) + return 0; + + if (at_least_as_qualified_p (type1, type2)) + return 1; + + else if (at_least_as_qualified_p (type2, type1)) + return -1; + + return 0; +} + +/* Returns 1 if the cv-qualification signature of TYPE1 is a proper + subset of the cv-qualification signature of TYPE2, and the types + are similar. Returns -1 if the other way 'round, and 0 otherwise. */ + +int +comp_cv_qual_signature (type1, type2) + tree type1; + tree type2; +{ + if (comp_ptr_ttypes_real (type2, type1, -1)) + return 1; + else if (comp_ptr_ttypes_real (type1, type2, -1)) + return -1; + else + return 0; +} + +/* If two types share a common base type, return that basetype. + If there is not a unique most-derived base type, this function + returns ERROR_MARK_NODE. */ + +static tree +common_base_type (tt1, tt2) + tree tt1, tt2; +{ + tree best = NULL_TREE; + int i; + + /* If one is a baseclass of another, that's good enough. */ + if (UNIQUELY_DERIVED_FROM_P (tt1, tt2)) + return tt1; + if (UNIQUELY_DERIVED_FROM_P (tt2, tt1)) + return tt2; + + /* Otherwise, try to find a unique baseclass of TT1 + that is shared by TT2, and follow that down. */ + for (i = CLASSTYPE_N_BASECLASSES (tt1)-1; i >= 0; i--) + { + tree basetype = TYPE_BINFO_BASETYPE (tt1, i); + tree trial = common_base_type (basetype, tt2); + if (trial) + { + if (trial == error_mark_node) + return trial; + if (best == NULL_TREE) + best = trial; + else if (best != trial) + return error_mark_node; + } + } + + /* Same for TT2. */ + for (i = CLASSTYPE_N_BASECLASSES (tt2)-1; i >= 0; i--) + { + tree basetype = TYPE_BINFO_BASETYPE (tt2, i); + tree trial = common_base_type (tt1, basetype); + if (trial) + { + if (trial == error_mark_node) + return trial; + if (best == NULL_TREE) + best = trial; + else if (best != trial) + return error_mark_node; + } + } + return best; +} + +/* 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 is no longer used. */ + +int +compparms (parms1, parms2) + tree parms1, parms2; +{ + register tree t1 = parms1, t2 = parms2; + + /* An unspecified parmlist matches any specified parmlist + whose argument types don't need default promotions. */ + + while (1) + { + if (t1 == 0 && t2 == 0) + return 1; + /* If one parmlist is shorter than the other, + they fail to match. */ + if (t1 == 0 || t2 == 0) + return 0; + if (!same_type_p (TREE_VALUE (t2), TREE_VALUE (t1))) + 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. + + The return value is like for comp_target_types. + + This should go away, possibly with the exception of the empty parmlist + conversion; there are no conversions between function types in C++. + (jason 17 Apr 1997) */ + +static int +comp_target_parms (parms1, parms2, strict) + tree parms1, parms2; + int strict; +{ + register tree t1 = parms1, t2 = parms2; + int warn_contravariance = 0; + + /* In C, an unspecified parmlist matches any specified parmlist + whose argument types don't need default promotions. This is not + true for C++, but let's do it anyway for unfixed headers. */ + + if (t1 == 0 && t2 != 0) + { + cp_pedwarn ("ANSI C++ prohibits conversion from `(%#T)' to `(...)'", + parms2); + return self_promoting_args_p (t2); + } + if (t2 == 0) + return self_promoting_args_p (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 (same_type_p (p1, p2)) + continue; + + if (pedantic) + return 0; + + if ((TREE_CODE (p1) == POINTER_TYPE && TREE_CODE (p2) == POINTER_TYPE) + || (TREE_CODE (p1) == REFERENCE_TYPE + && TREE_CODE (p2) == REFERENCE_TYPE)) + { + if (strict <= 0 + && (TYPE_MAIN_VARIANT (TREE_TYPE (p1)) + == TYPE_MAIN_VARIANT (TREE_TYPE (p2)))) + continue; + + /* The following is wrong for contravariance, + but many programs depend on it. */ + if (TREE_TYPE (p1) == void_type_node) + continue; + if (TREE_TYPE (p2) == void_type_node) + { + warn_contravariance = 1; + continue; + } + if (IS_AGGR_TYPE (TREE_TYPE (p1)) + && !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (p1)), + TYPE_MAIN_VARIANT (TREE_TYPE (p2)))) + return 0; + } + /* Note backwards order due to contravariance. */ + if (comp_target_types (p2, p1, 1) <= 0) + { + if (comp_target_types (p1, p2, 1) > 0) + { + warn_contravariance = 1; + continue; + } + if (strict != 0) + return 0; + } + } + return warn_contravariance ? -1 : 1; +} + +/* Return 1 if PARMS specifies a fixed number of parameters + and none of their types is affected by default promotions. */ + +int +self_promoting_args_p (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 == 0) + return 0; + + if (TYPE_MAIN_VARIANT (type) == float_type_node) + return 0; + + if (C_PROMOTING_INTEGER_TYPE_P (type)) + return 0; + } + return 1; +} + +/* 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; +{ + tree type1 = TYPE_MAIN_VARIANT (type); + if (type1 == signed_char_type_node || type1 == char_type_node) + return unsigned_char_type_node; + if (type1 == integer_type_node) + return unsigned_type_node; + if (type1 == short_integer_type_node) + return short_unsigned_type_node; + if (type1 == long_integer_type_node) + return long_unsigned_type_node; + if (type1 == long_long_integer_type_node) + return long_long_unsigned_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 + if (type1 == intTI_type_node) + return unsigned_intTI_type_node; +#endif + if (type1 == intDI_type_node) + return unsigned_intDI_type_node; + if (type1 == intSI_type_node) + return unsigned_intSI_type_node; + if (type1 == intHI_type_node) + return unsigned_intHI_type_node; + if (type1 == intQI_type_node) + return unsigned_intQI_type_node; + + return signed_or_unsigned_type (1, type); +} + +/* Return a signed type the same as TYPE in other respects. */ + +tree +signed_type (type) + tree type; +{ + tree type1 = TYPE_MAIN_VARIANT (type); + if (type1 == unsigned_char_type_node || type1 == char_type_node) + return signed_char_type_node; + if (type1 == unsigned_type_node) + return integer_type_node; + if (type1 == short_unsigned_type_node) + return short_integer_type_node; + if (type1 == long_unsigned_type_node) + return long_integer_type_node; + if (type1 == long_long_unsigned_type_node) + return long_long_integer_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 + if (type1 == unsigned_intTI_type_node) + return intTI_type_node; +#endif + if (type1 == unsigned_intDI_type_node) + return intDI_type_node; + if (type1 == unsigned_intSI_type_node) + return intSI_type_node; + if (type1 == unsigned_intHI_type_node) + return intHI_type_node; + if (type1 == unsigned_intQI_type_node) + return intQI_type_node; + + return signed_or_unsigned_type (0, 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 (! INTEGRAL_TYPE_P (type) + || TREE_UNSIGNED (type) == unsignedp) + 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; +} + +/* Compute the value of the `sizeof' operator. */ + +tree +c_sizeof (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + tree t; + + if (processing_template_decl) + return build_min (SIZEOF_EXPR, sizetype, type); + + if (code == FUNCTION_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("ANSI C++ forbids taking the sizeof a function type"); + return size_int (1); + } + if (code == METHOD_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("ANSI C++ forbids taking the sizeof a method type"); + return size_int (1); + } + if (code == VOID_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("ANSI C++ forbids taking the sizeof a void type"); + return size_int (1); + } + if (code == ERROR_MARK) + return size_int (1); + + /* ARM $5.3.2: ``When applied to a reference, the result is the size of the + referenced object.'' */ + if (code == REFERENCE_TYPE) + type = TREE_TYPE (type); + + /* We couldn't find anything in the ARM or the draft standard that says, + one way or the other, if doing sizeof on something that doesn't have + an object associated with it is correct or incorrect. For example, if + you declare `struct S { char str[16]; };', and in your program do + a `sizeof (S::str)', should we flag that as an error or should we give + the size of it? Since it seems like a reasonable thing to do, we'll go + with giving the value. */ + if (code == OFFSET_TYPE) + type = TREE_TYPE (type); + + /* @@ This also produces an error for a signature ref. + In that case we should be able to do better. */ + if (IS_SIGNATURE (type)) + { + error ("`sizeof' applied to a signature type"); + return size_int (0); + } + + if (TYPE_SIZE (complete_type (type)) == 0) + { + cp_error ("`sizeof' applied to incomplete type `%T'", type); + return size_int (0); + } + + /* Convert in case a char is more than one unit. */ + t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), + size_int (TYPE_PRECISION (char_type_node))); + t = convert (sizetype, t); + /* size_binop does not put the constant in range, so do it now. */ + if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0)) + TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) = 1; + return t; +} + +tree +expr_sizeof (e) + tree e; +{ + if (processing_template_decl) + return build_min (SIZEOF_EXPR, sizetype, e); + + if (TREE_CODE (e) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1))) + error ("sizeof applied to a bit-field"); + /* ANSI says arrays and functions are converted inside comma. + But we can't really convert them in build_compound_expr + because that would break commas in lvalues. + So do the conversion here if operand was a comma. */ + if (TREE_CODE (e) == COMPOUND_EXPR + && (TREE_CODE (TREE_TYPE (e)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (e)) == FUNCTION_TYPE)) + e = default_conversion (e); + else if (is_overloaded_fn (e)) + { + pedwarn ("ANSI C++ forbids taking the sizeof a function type"); + return size_int (1); + } + + return c_sizeof (TREE_TYPE (e)); +} + +tree +c_sizeof_nowarn (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + tree t; + + if (code == FUNCTION_TYPE + || code == METHOD_TYPE + || code == VOID_TYPE + || code == ERROR_MARK) + return size_int (1); + if (code == REFERENCE_TYPE) + type = TREE_TYPE (type); + + if (TYPE_SIZE (type) == 0) + return size_int (0); + + /* Convert in case a char is more than one unit. */ + t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), + size_int (TYPE_PRECISION (char_type_node))); + t = convert (sizetype, t); + force_fit_type (t, 0); + return t; +} + +/* 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); + tree t; + + if (processing_template_decl) + return build_min (ALIGNOF_EXPR, sizetype, type); + + if (code == FUNCTION_TYPE || code == METHOD_TYPE) + return size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT); + + if (code == VOID_TYPE || code == ERROR_MARK) + return size_int (1); + + /* C++: this is really correct! */ + if (code == REFERENCE_TYPE) + type = TREE_TYPE (type); + + /* @@ This also produces an error for a signature ref. + In that case we should be able to do better. */ + if (IS_SIGNATURE (type)) + { + error ("`__alignof' applied to a signature type"); + return size_int (1); + } + + t = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT); + force_fit_type (t, 0); + return t; +} + +/* 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 +decay_conversion (exp) + tree exp; +{ + register tree type = TREE_TYPE (exp); + register enum tree_code code = TREE_CODE (type); + + if (code == OFFSET_TYPE) + { + if (TREE_CODE (exp) == OFFSET_REF) + return decay_conversion (resolve_offset_ref (exp)); + + type = TREE_TYPE (type); + code = TREE_CODE (type); + + if (type == unknown_type_node) + { + cp_pedwarn ("assuming & on overloaded member function"); + return build_unary_op (ADDR_EXPR, exp, 0); + } + } + + if (code == REFERENCE_TYPE) + { + exp = convert_from_reference (exp); + type = TREE_TYPE (exp); + code = TREE_CODE (type); + } + + /* Constants can be used directly unless they're not loadable. */ + if (TREE_CODE (exp) == CONST_DECL) + exp = DECL_INITIAL (exp); + /* Replace a nonvolatile const static variable with its value. */ + else if (TREE_READONLY_DECL_P (exp)) + { + exp = decl_constant_value (exp); + type = TREE_TYPE (exp); + } + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Leave such NOP_EXPRs, since RHS is being used in non-lvalue context. */ + + if (code == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + if (code == METHOD_TYPE) + { + cp_pedwarn ("assuming & on `%E'", exp); + return build_unary_op (ADDR_EXPR, exp, 0); + } + if (code == FUNCTION_TYPE || is_overloaded_fn (exp)) + { + return build_unary_op (ADDR_EXPR, exp, 0); + } + if (code == ARRAY_TYPE) + { + register tree adr; + 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 (CONVERT_EXPR, + build_pointer_type (TREE_TYPE + (TREE_TYPE (inner))), + inner); + TREE_CONSTANT (inner) = TREE_CONSTANT (TREE_OPERAND (inner, 0)); + } + return cp_convert (build_pointer_type (TREE_TYPE (type)), inner); + } + + if (TREE_CODE (exp) == COMPOUND_EXPR) + { + tree op1 = decay_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; + } + + ptrtype = build_pointer_type (TREE_TYPE (type)); + + 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_CONSTANT (adr) = staticp (exp); + TREE_SIDE_EFFECTS (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 cp_convert (ptrtype, adr); + } + + return exp; +} + +tree +default_conversion (exp) + tree exp; +{ + tree type; + enum tree_code code; + + exp = decay_conversion (exp); + + type = TREE_TYPE (exp); + code = TREE_CODE (type); + + if (INTEGRAL_CODE_P (code)) + { + tree t = type_promotes_to (type); + if (t != type) + return cp_convert (t, exp); + } + + return exp; +} + +/* Take the address of an inline function without setting TREE_ADDRESSABLE + or TREE_USED. */ + +tree +inline_conversion (exp) + tree exp; +{ + if (TREE_CODE (exp) == FUNCTION_DECL) + exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp); + + return exp; +} + +/* Returns nonzero iff exp is a STRING_CST or the result of applying + decay_conversion to one. */ + +int +string_conv_p (totype, exp, warn) + tree totype, exp; + int warn; +{ + tree t; + + if (! flag_const_strings || TREE_CODE (totype) != POINTER_TYPE) + return 0; + + t = TREE_TYPE (totype); + if (!same_type_p (t, char_type_node) + && !same_type_p (t, wchar_type_node)) + return 0; + + if (TREE_CODE (exp) == STRING_CST) + { + /* Make sure that we don't try to convert between char and wchar_t. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (exp))) != t) + return 0; + } + else + { + /* Is this a string constant which has decayed to 'const char *'? */ + t = build_pointer_type (build_qualified_type (t, TYPE_QUAL_CONST)); + if (!same_type_p (TREE_TYPE (exp), t)) + return 0; + STRIP_NOPS (exp); + if (TREE_CODE (exp) != ADDR_EXPR + || TREE_CODE (TREE_OPERAND (exp, 0)) != STRING_CST) + return 0; + } + + /* This warning is not very useful, as it complains about printf. */ + if (warn && warn_write_strings) + cp_warning ("deprecated conversion from string constant to `%T'", totype); + + return 1; +} + +tree +build_object_ref (datum, basetype, field) + tree datum, basetype, field; +{ + tree dtype; + if (datum == error_mark_node) + return error_mark_node; + + dtype = TREE_TYPE (datum); + if (TREE_CODE (dtype) == REFERENCE_TYPE) + dtype = TREE_TYPE (dtype); + if (! IS_AGGR_TYPE_CODE (TREE_CODE (dtype))) + { + cp_error ("request for member `%T::%D' in expression of non-aggregate type `%T'", + basetype, field, dtype); + return error_mark_node; + } + else if (IS_SIGNATURE (basetype)) + { + warning ("signature name in scope resolution ignored"); + return build_component_ref (datum, field, NULL_TREE, 1); + } + else if (is_aggr_type (basetype, 1)) + { + tree binfo = binfo_or_else (basetype, dtype); + if (binfo) + return build_x_component_ref (build_scoped_ref (datum, basetype), + field, binfo, 1); + } + return error_mark_node; +} + +/* Like `build_component_ref, but uses an already found field, and converts + from a reference. Must compute access for current_class_ref. + Otherwise, ok. */ + +tree +build_component_ref_1 (datum, field, protect) + tree datum, field; + int protect; +{ + return convert_from_reference + (build_component_ref (datum, field, NULL_TREE, protect)); +} + +/* Given a COND_EXPR, MIN_EXPR, or MAX_EXPR in T, return it in a form that we + can, for example, use as an lvalue. This code used to be in + unary_complex_lvalue, but we needed it to deal with `a = (d == c) ? b : c' + expressions, where we're dealing with aggregates. But now it's again only + called from unary_complex_lvalue. The case (in particular) that led to + this was with CODE == ADDR_EXPR, since it's not an lvalue when we'd + get it there. */ + +static tree +rationalize_conditional_expr (code, t) + enum tree_code code; + tree t; +{ + /* For MIN_EXPR or MAX_EXPR, fold-const.c has arranged things so that + the first operand is always the one to be used if both operands + are equal, so we know what conditional expression this used to be. */ + if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR) + { + return + build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR + ? LE_EXPR : GE_EXPR), + TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1)), + build_unary_op (code, TREE_OPERAND (t, 0), 0), + build_unary_op (code, TREE_OPERAND (t, 1), 0)); + } + + return + build_conditional_expr (TREE_OPERAND (t, 0), + build_unary_op (code, TREE_OPERAND (t, 1), 0), + build_unary_op (code, TREE_OPERAND (t, 2), 0)); +} + +/* Given the TYPE of an anonymous union field inside T, return the + FIELD_DECL for the field. If not found return NULL_TREE. Because + anonymous unions can nest, we must also search all anonymous unions + that are directly reachable. */ + +static tree +lookup_anon_field (t, type) + tree t, type; +{ + tree field; + + for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field)) + { + if (TREE_STATIC (field)) + continue; + if (TREE_CODE (field) != FIELD_DECL) + continue; + + /* If we find it directly, return the field. */ + if (DECL_NAME (field) == NULL_TREE + && type == TREE_TYPE (field)) + { + return field; + } + + /* Otherwise, it could be nested, search harder. */ + if (DECL_NAME (field) == NULL_TREE + && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + { + tree subfield = lookup_anon_field (TREE_TYPE (field), type); + if (subfield) + return subfield; + } + } + return NULL_TREE; +} + +/* Build a COMPONENT_REF for a given DATUM, and it's member COMPONENT. + COMPONENT can be an IDENTIFIER_NODE that is the name of the member + that we are interested in, or it can be a FIELD_DECL. */ + +tree +build_component_ref (datum, component, basetype_path, protect) + tree datum, component, basetype_path; + int protect; +{ + register tree basetype; + register enum tree_code code; + register tree field = NULL; + register tree ref; + tree field_type; + int type_quals; + + if (processing_template_decl) + return build_min_nt (COMPONENT_REF, datum, component); + + if (datum == error_mark_node + || TREE_TYPE (datum) == error_mark_node) + return error_mark_node; + + /* BASETYPE holds the type of the class containing the COMPONENT. */ + basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum)); + + /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference + inside it. */ + switch (TREE_CODE (datum)) + { + case COMPOUND_EXPR: + { + tree value = build_component_ref (TREE_OPERAND (datum, 1), component, + basetype_path, protect); + return build (COMPOUND_EXPR, TREE_TYPE (value), + TREE_OPERAND (datum, 0), value); + } + case COND_EXPR: + return build_conditional_expr + (TREE_OPERAND (datum, 0), + build_component_ref (TREE_OPERAND (datum, 1), component, + basetype_path, protect), + build_component_ref (TREE_OPERAND (datum, 2), component, + basetype_path, protect)); + + case TEMPLATE_DECL: + cp_error ("invalid use of %D", datum); + datum = error_mark_node; + break; + + default: + break; + } + + code = TREE_CODE (basetype); + + if (code == REFERENCE_TYPE) + { + datum = convert_from_reference (datum); + basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum)); + code = TREE_CODE (basetype); + } + if (TREE_CODE (datum) == OFFSET_REF) + { + datum = resolve_offset_ref (datum); + basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum)); + code = TREE_CODE (basetype); + } + + /* First, see if there is a field or component with name COMPONENT. */ + if (TREE_CODE (component) == TREE_LIST) + { + /* I could not trigger this code. MvL */ + my_friendly_abort (980326); +#ifdef DEAD + my_friendly_assert (!(TREE_CHAIN (component) == NULL_TREE + && DECL_CHAIN (TREE_VALUE (component)) == NULL_TREE), 309); +#endif + return build (COMPONENT_REF, TREE_TYPE (component), datum, component); + } + + if (! IS_AGGR_TYPE_CODE (code)) + { + if (code != ERROR_MARK) + cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'", + component, datum, basetype); + return error_mark_node; + } + + if (!complete_type_or_else (basetype)) + return error_mark_node; + + if (TREE_CODE (component) == BIT_NOT_EXPR) + { + if (TYPE_IDENTIFIER (basetype) != TREE_OPERAND (component, 0)) + { + cp_error ("destructor specifier `%T::~%T' must have matching names", + basetype, TREE_OPERAND (component, 0)); + return error_mark_node; + } + if (! TYPE_HAS_DESTRUCTOR (basetype)) + { + cp_error ("type `%T' has no destructor", basetype); + return error_mark_node; + } + return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1); + } + + /* Look up component name in the structure type definition. */ + if (CLASSTYPE_VFIELD (basetype) + && DECL_NAME (CLASSTYPE_VFIELD (basetype)) == component) + /* Special-case this because if we use normal lookups in an ambiguous + hierarchy, the compiler will abort (because vptr lookups are + not supposed to be ambiguous. */ + field = CLASSTYPE_VFIELD (basetype); + else if (TREE_CODE (component) == FIELD_DECL) + field = component; + else if (TREE_CODE (component) == TYPE_DECL) + { + cp_error ("invalid use of type decl `%#D' as expression", component); + return error_mark_node; + } + else + { + tree name = component; + if (TREE_CODE (component) == VAR_DECL) + name = DECL_NAME (component); + if (basetype_path == NULL_TREE) + basetype_path = TYPE_BINFO (basetype); + field = lookup_field (basetype_path, name, + protect && !VFIELD_NAME_P (name), 0); + 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 fndecls = lookup_fnfields (basetype_path, name, 1); + if (fndecls == error_mark_node) + return error_mark_node; + if (fndecls) + { + /* If the function is unique and static, we can resolve it + now. Otherwise, we have to wait and see what context it is + used in; a component_ref involving a non-static member + function can only be used in a call (expr.ref). */ + + if (TREE_CHAIN (fndecls) == NULL_TREE + && TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL) + { + if (DECL_STATIC_FUNCTION_P (TREE_VALUE (fndecls))) + { + tree fndecl = TREE_VALUE (fndecls); + enforce_access (TREE_PURPOSE (fndecls), fndecl); + mark_used (fndecl); + return fndecl; + } + else + { + /* A unique non-static member function. Other parts + of the compiler expect something with + unknown_type_node to be really overloaded, so + let's oblige. */ + TREE_VALUE (fndecls) + = scratch_ovl_cons (TREE_VALUE (fndecls), NULL_TREE); + } + } + + ref = build (COMPONENT_REF, unknown_type_node, + datum, fndecls); + return ref; + } + + cp_error ("`%#T' has no member named `%D'", basetype, name); + return error_mark_node; + } + else if (TREE_TYPE (field) == error_mark_node) + return error_mark_node; + + if (TREE_CODE (field) != FIELD_DECL) + { + if (TREE_CODE (field) == TYPE_DECL) + cp_pedwarn ("invalid use of type decl `%#D' as expression", field); + else if (DECL_RTL (field) != 0) + mark_used (field); + else + TREE_USED (field) = 1; + return field; + } + } + + /* See if we have to do any conversions so that we pick up the field from the + right context. */ + if (DECL_FIELD_CONTEXT (field) != basetype) + { + tree context = DECL_FIELD_CONTEXT (field); + tree base = context; + while (!same_type_p (base, basetype) && TYPE_NAME (base) + && ANON_UNION_TYPE_P (base)) + { + base = TYPE_CONTEXT (base); + } + + /* Handle base classes here... */ + if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype)) + { + tree addr = build_unary_op (ADDR_EXPR, datum, 0); + if (integer_zerop (addr)) + { + error ("invalid reference to NULL ptr, use ptr-to-member instead"); + return error_mark_node; + } + if (VBASE_NAME_P (DECL_NAME (field))) + { + /* It doesn't matter which vbase pointer we grab, just + find one of them. */ + tree binfo = get_binfo (base, + TREE_TYPE (TREE_TYPE (addr)), 0); + addr = convert_pointer_to_real (binfo, addr); + } + else + addr = convert_pointer_to (base, addr); + datum = build_indirect_ref (addr, NULL_PTR); + my_friendly_assert (datum != error_mark_node, 311); + } + basetype = base; + + /* Handle things from anon unions here... */ + if (TYPE_NAME (context) && ANON_UNION_TYPE_P (context)) + { + tree subfield = lookup_anon_field (basetype, context); + tree subdatum = build_component_ref (datum, subfield, + basetype_path, protect); + return build_component_ref (subdatum, field, basetype_path, protect); + } + } + + /* Compute the type of the field, as described in [expr.ref]. */ + type_quals = TYPE_UNQUALIFIED; + field_type = TREE_TYPE (field); + if (TREE_CODE (field_type) == REFERENCE_TYPE) + /* The standard says that the type of the result should be the + type referred to by the reference. But for now, at least, we + do the conversion from reference type later. */ + ; + else + { + type_quals = (CP_TYPE_QUALS (field_type) + | CP_TYPE_QUALS (TREE_TYPE (datum))); + + /* A field is const (volatile) if the enclosing object, or the + field itself, is const (volatile). But, a mutable field is + not const, even within a const object. */ + if (DECL_LANG_SPECIFIC (field) && DECL_MUTABLE_P (field)) + type_quals &= ~TYPE_QUAL_CONST; + if (!IS_SIGNATURE (field_type)) + field_type = cp_build_qualified_type (field_type, type_quals); + } + + ref = fold (build (COMPONENT_REF, field_type, + break_out_cleanups (datum), field)); + + /* Mark the expression const or volatile, as appropriate. Even + though we've dealt with the type above, we still have to mark the + expression itself. */ + if (type_quals & TYPE_QUAL_CONST) + TREE_READONLY (ref) = 1; + else if (type_quals & TYPE_QUAL_VOLATILE) + TREE_THIS_VOLATILE (ref) = 1; + + return ref; +} + +/* Variant of build_component_ref for use in expressions, which should + never have REFERENCE_TYPE. */ + +tree +build_x_component_ref (datum, component, basetype_path, protect) + tree datum, component, basetype_path; + int protect; +{ + tree t = build_component_ref (datum, component, basetype_path, protect); + + if (! processing_template_decl) + t = convert_from_reference (t); + + return t; +} + +/* 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; + + if (processing_template_decl) + return build_min_nt (INDIRECT_REF, ptr); + + rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, + NULL_TREE); + if (rval) + return rval; + return build_indirect_ref (ptr, errorstring); +} + +tree +build_indirect_ref (ptr, errorstring) + tree ptr; + char *errorstring; +{ + register tree pointer, type; + + if (ptr == error_mark_node) + return error_mark_node; + + pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE + ? ptr : default_conversion (ptr)); + type = TREE_TYPE (pointer); + + if (ptr == current_class_ptr) + return current_class_ref; + + if (TYPE_PTR_P (type) || TREE_CODE (type) == REFERENCE_TYPE) + { + /* [expr.unary.op] + + If the type of the expression is "pointer to T," the type + of the result is "T." + + We must use the canonical variant because certain parts of + the back end, like fold, do pointer comparisons between + types. */ + tree t = canonical_type_variant (TREE_TYPE (type)); + + if (TREE_CODE (pointer) == ADDR_EXPR + && !flag_volatile + && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0)))) + /* The POINTER was something like `&x'. We simplify `*&x' to + `x'. */ + return TREE_OPERAND (pointer, 0); + else + { + tree ref = build1 (INDIRECT_REF, t, pointer); + + /* We *must* set TREE_READONLY when dereferencing a pointer to const, + so that we get the proper error message if the result is used + to assign to. Also, &* is supposed to be a no-op. */ + TREE_READONLY (ref) = CP_TYPE_CONST_P (t); + TREE_THIS_VOLATILE (ref) = CP_TYPE_VOLATILE_P (t); + TREE_SIDE_EFFECTS (ref) + = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer) + || flag_volatile); + return ref; + } + } + /* `pointer' won't be an error_mark_node if we were given a + pointer to member, so it's cool to check for this here. */ + else if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type)) + error ("invalid use of `%s' on pointer to member", errorstring); + else if (TREE_CODE (type) == RECORD_TYPE + && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))) + error ("cannot dereference signature pointer/reference"); + else if (pointer != error_mark_node) + { + if (errorstring) + error ("invalid type argument of `%s'", errorstring); + else + error ("invalid type argument"); + } + 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_array_ref (array, idx) + tree array, idx; +{ + if (idx == 0) + { + error ("subscript missing in array reference"); + return error_mark_node; + } + + if (TREE_TYPE (array) == error_mark_node + || TREE_TYPE (idx) == error_mark_node) + return error_mark_node; + + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE + && TREE_CODE (array) != INDIRECT_REF) + { + tree rval, type; + + /* Subscripting with type char is likely to lose + on a machine where chars are signed. + So warn on any machine, but optionally. + Don't warn for unsigned char since that type is safe. + Don't warn for signed char because anyone who uses that + must have done so deliberately. */ + if (warn_char_subscripts + && TYPE_MAIN_VARIANT (TREE_TYPE (idx)) == char_type_node) + warning ("array subscript has type `char'"); + + /* Apply default promotions *after* noticing character types. */ + idx = default_conversion (idx); + + if (TREE_CODE (TREE_TYPE (idx)) != 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 (idx) != 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; + } + /* An array that is indexed by a constant value which is not within + the array bounds cannot be stored in a register either; because we + would get a crash in store_bit_field/extract_bit_field when trying + to access a non-existent part of the register. */ + if (TREE_CODE (idx) == INTEGER_CST + && TYPE_VALUES (TREE_TYPE (array)) + && ! int_fits_type_p (idx, TYPE_VALUES (TREE_TYPE (array)))) + { + if (mark_addressable (array) == 0) + return error_mark_node; + } + + if (pedantic && !lvalue_p (array)) + pedwarn ("ANSI C++ forbids subscripting non-lvalue array"); + + /* Note in C++ it is valid to subscript a `register' array, since + it is valid to take the address of something with that + storage specification. */ + if (extra_warnings) + { + tree foo = array; + while (TREE_CODE (foo) == COMPONENT_REF) + foo = TREE_OPERAND (foo, 0); + if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo)) + warning ("subscripting array declared `register'"); + } + + type = TREE_TYPE (TREE_TYPE (array)); + rval = build (ARRAY_REF, type, array, idx); + /* Array ref is const/volatile if the array elements are + or if the array is.. */ + TREE_READONLY (rval) + |= (CP_TYPE_CONST_P (type) | TREE_READONLY (array)); + TREE_SIDE_EFFECTS (rval) + |= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array)); + TREE_THIS_VOLATILE (rval) + |= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array)); + return require_complete_type (fold (rval)); + } + + { + tree ar = default_conversion (array); + tree ind = default_conversion (idx); + + /* Put the integer in IND to simplify error checking. */ + if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE) + { + tree temp = ar; + ar = ind; + ind = temp; + } + + if (ar == error_mark_node) + return ar; + + if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE) + { + error ("subscripted value is neither array nor pointer"); + return error_mark_node; + } + if (TREE_CODE (TREE_TYPE (ind)) != 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"); + } +} + +/* 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. The PARAMS do + not include any object pointer that may be required. 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_REF. + + When calling a TEMPLATE_DECL, we don't require a complete return + type. */ + +tree +build_x_function_call (function, params, decl) + tree function, params, decl; +{ + tree type; + tree template_id = NULL_TREE; + int is_method; + + if (function == error_mark_node) + return error_mark_node; + + if (processing_template_decl) + return build_min_nt (CALL_EXPR, function, params, NULL_TREE); + + /* Save explicit template arguments if found */ + if (TREE_CODE (function) == TEMPLATE_ID_EXPR) + { + template_id = function; + function = TREE_OPERAND (function, 0); + } + + type = TREE_TYPE (function); + + if (TREE_CODE (type) == OFFSET_TYPE + && TREE_TYPE (type) == unknown_type_node + && TREE_CODE (function) == TREE_LIST + && TREE_CHAIN (function) == NULL_TREE) + { + /* Undo (Foo:bar)()... */ + type = TYPE_OFFSET_BASETYPE (type); + function = TREE_VALUE (function); + my_friendly_assert (TREE_CODE (function) == TREE_LIST, 999); + my_friendly_assert (TREE_CHAIN (function) == NULL_TREE, 999); + function = TREE_VALUE (function); + if (TREE_CODE (function) == OVERLOAD) + function = OVL_FUNCTION (function); + my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 999); + function = DECL_NAME (function); + return build_method_call (decl, function, params, + TYPE_BINFO (type), LOOKUP_NORMAL); + } + + is_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 + || TYPE_PTRMEMFUNC_P (type)); + + if ((TREE_CODE (function) == FUNCTION_DECL + && DECL_STATIC_FUNCTION_P (function)) + || (TREE_CODE (function) == TEMPLATE_DECL + && DECL_STATIC_FUNCTION_P (DECL_RESULT (function)))) + return build_member_call + (DECL_CONTEXT (function), DECL_NAME (function), params); + + /* A friend template. Make it look like a toplevel declaration. */ + if (! is_method && TREE_CODE (function) == TEMPLATE_DECL) + function = scratch_ovl_cons (function, NULL_TREE); + + /* Handle methods, friends, and overloaded functions, respectively. */ + if (is_method) + { + tree basetype = NULL_TREE; + + if (TREE_CODE (function) == FUNCTION_DECL + || DECL_FUNCTION_TEMPLATE_P (function)) + { + basetype = DECL_CLASS_CONTEXT (function); + + if (DECL_NAME (function)) + function = DECL_NAME (function); + else + function = TYPE_IDENTIFIER (DECL_CLASS_CONTEXT (function)); + } + else if (TREE_CODE (function) == TREE_LIST) + { + my_friendly_assert (TREE_CODE (TREE_VALUE (function)) + == FUNCTION_DECL, 312); + basetype = DECL_CLASS_CONTEXT (TREE_VALUE (function)); + function = TREE_PURPOSE (function); + } + else if (TREE_CODE (function) != IDENTIFIER_NODE) + { + if (TREE_CODE (function) == OFFSET_REF) + { + if (TREE_OPERAND (function, 0)) + decl = TREE_OPERAND (function, 0); + } + /* 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; + } + /* What other type of POINTER_TYPE could this be? */ + if (TREE_CODE (TREE_TYPE (function)) != POINTER_TYPE + && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (function)) + && TREE_CODE (function) != OFFSET_REF) + 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 (basetype && (! current_class_type + || ! DERIVED_FROM_P (basetype, current_class_type))) + return build_member_call (basetype, function, params); + + 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 = build_dummy_object (current_class_type); + } + + /* Put back explicit template arguments, if any. */ + if (template_id) + function = template_id; + return build_method_call (decl, function, params, + NULL_TREE, LOOKUP_NORMAL); + } + else if (TREE_CODE (function) == COMPONENT_REF + && type == unknown_type_node) + { + /* Undo what we did in build_component_ref. */ + decl = TREE_OPERAND (function, 0); + function = TREE_OPERAND (function, 1); + function = DECL_NAME (OVL_CURRENT (TREE_VALUE (function))); + return build_method_call (decl, function, params, + NULL_TREE, LOOKUP_NORMAL); + } + else if (really_overloaded_fn (function)) + { + if (OVL_FUNCTION (function) == NULL_TREE) + { + cp_error ("function `%D' declared overloaded, but no definitions appear with which to resolve it?!?", + TREE_PURPOSE (function)); + return error_mark_node; + } + else + { + /* Put back explicit template arguments, if any. */ + if (template_id) + function = template_id; + return build_new_function_call (function, params); + } + } + else + /* Remove a potential OVERLOAD around it */ + function = OVL_CURRENT (function); + + 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 = current_class_ref; + + decl_addr = build_unary_op (ADDR_EXPR, decl, 0); + + /* Sigh. OFFSET_REFs are being used for too many things. + They're being used both for -> and ->*, and we want to resolve + the -> cases here, but leave the ->*. We could use + resolve_offset_ref for those, too, but it would call + get_member_function_from_ptrfunc and decl_addr wouldn't get + updated properly. Nasty. */ + if (TREE_CODE (TREE_OPERAND (function, 1)) == FIELD_DECL) + function = resolve_offset_ref (function); + else + function = TREE_OPERAND (function, 1); + + function = get_member_function_from_ptrfunc (&decl_addr, function); + params = expr_tree_cons (NULL_TREE, decl_addr, params); + return build_function_call (function, params); + } + + type = TREE_TYPE (function); + if (type != error_mark_node) + { + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + + if (IS_AGGR_TYPE (type)) + return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE); + } + + if (is_method) + { + tree fntype = TREE_TYPE (function); + tree ctypeptr = NULL_TREE; + + /* Explicitly named method? */ + if (TREE_CODE (function) == FUNCTION_DECL) + ctypeptr = build_pointer_type (DECL_CLASS_CONTEXT (function)); + /* Expression with ptr-to-method type? It could either be a plain + usage, or it might be a case where the ptr-to-method is being + passed in as an argument. */ + else if (TYPE_PTRMEMFUNC_P (fntype)) + { + tree rec = TYPE_METHOD_BASETYPE (TREE_TYPE + (TYPE_PTRMEMFUNC_FN_TYPE (fntype))); + ctypeptr = build_pointer_type (rec); + } + /* Unexpected node type? */ + else + my_friendly_abort (116); + 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 + && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (decl))) + { + decl = build_unary_op (ADDR_EXPR, decl, 0); + decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl); + } + else + decl = build_c_cast (ctypeptr, decl); + params = expr_tree_cons (NULL_TREE, decl, params); + } + + return build_function_call (function, params); +} + +/* Resolve a pointer to member function. INSTANCE is the object + instance to use, if the member points to a virtual member. */ + +tree +get_member_function_from_ptrfunc (instance_ptrptr, function) + tree *instance_ptrptr; + tree function; +{ + if (TREE_CODE (function) == OFFSET_REF) + { + function = TREE_OPERAND (function, 1); + } + + if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function))) + { + tree fntype, idx, e1, delta, delta2, e2, e3, aref, vtbl; + tree instance, basetype; + + tree instance_ptr = *instance_ptrptr; + + if (TREE_SIDE_EFFECTS (instance_ptr)) + instance_ptr = save_expr (instance_ptr); + + if (TREE_SIDE_EFFECTS (function)) + function = save_expr (function); + + fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function)); + basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)); + + delta = cp_convert (ptrdiff_type_node, + build_component_ref (function, delta_identifier, + NULL_TREE, 0)); + e3 = PFN_FROM_PTRMEMFUNC (function); + + if (TYPE_SIZE (basetype) != NULL_TREE + && ! TYPE_VIRTUAL_P (basetype)) + /* If basetype doesn't have virtual functions, don't emit code to + handle that case. */ + e1 = e3; + else + { + /* Promoting idx before saving it improves performance on RISC + targets. Without promoting, the first compare used + load-with-sign-extend, while the second used normal load then + shift to sign-extend. An optimizer flaw, perhaps, but it's + easier to make this change. */ + idx = save_expr (default_conversion + (build_component_ref (function, + index_identifier, + NULL_TREE, 0))); + e1 = build_binary_op (GT_EXPR, idx, integer_zero_node, 1); + + /* Convert down to the right base, before using the instance. */ + instance = convert_pointer_to_real (basetype, instance_ptr); + if (instance == error_mark_node && instance_ptr != error_mark_node) + return instance; + + vtbl = convert_pointer_to (ptr_type_node, instance); + delta2 = DELTA2_FROM_PTRMEMFUNC (function); + vtbl = build + (PLUS_EXPR, + build_pointer_type (build_pointer_type (vtable_entry_type)), + vtbl, cp_convert (ptrdiff_type_node, delta2)); + vtbl = build_indirect_ref (vtbl, NULL_PTR); + aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR, + idx, + integer_one_node, 1)); + if (! flag_vtable_thunks) + { + aref = save_expr (aref); + + delta = build_binary_op + (PLUS_EXPR, + build_conditional_expr (e1, + build_component_ref (aref, + delta_identifier, + NULL_TREE, 0), + integer_zero_node), + delta, 1); + } + + if (flag_vtable_thunks) + e2 = aref; + else + e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0); + TREE_TYPE (e2) = TREE_TYPE (e3); + e1 = build_conditional_expr (e1, e2, e3); + + /* Make sure this doesn't get evaluated first inside one of the + branches of the COND_EXPR. */ + if (TREE_CODE (instance_ptr) == SAVE_EXPR) + e1 = build (COMPOUND_EXPR, TREE_TYPE (e1), + instance_ptr, e1); + } + + *instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr), + instance_ptr, delta); + + if (instance_ptr == error_mark_node + && TREE_CODE (e1) != ADDR_EXPR + && TREE_CODE (TREE_OPERAND (e1, 0)) != FUNCTION_DECL) + cp_error ("object missing in `%E'", function); + + function = e1; + } + return function; +} + +tree +build_function_call_real (function, params, require_complete, flags) + tree function, params; + int require_complete, flags; +{ + register tree fntype, fndecl; + register tree value_type; + register tree coerced_params; + tree name = NULL_TREE, assembler_name = NULL_TREE; + int is_method; + + /* 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) + { + name = DECL_NAME (function); + assembler_name = DECL_ASSEMBLER_NAME (function); + + GNU_xref_call (current_function_decl, + IDENTIFIER_POINTER (name ? name + : TYPE_IDENTIFIER (DECL_CLASS_CONTEXT + (function)))); + mark_used (function); + fndecl = function; + + /* Convert anything with function type to a pointer-to-function. */ + if (pedantic && DECL_MAIN_P (function)) + pedwarn ("ANSI C++ forbids calling `main' from within program"); + + /* 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 (DECL_INLINE (function)) + function = inline_conversion (function); + else + function = build_addr_func (function); + } + else + { + fndecl = NULL_TREE; + + function = build_addr_func (function); + } + + if (function == error_mark_node) + return error_mark_node; + + fntype = TREE_TYPE (function); + + if (TYPE_PTRMEMFUNC_P (fntype)) + { + cp_error ("must use .* or ->* to call pointer-to-member function in `%E (...)'", + function); + return error_mark_node; + } + + 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 + || TREE_CODE (function) == TEMPLATE_ID_EXPR)) + { + cp_error ("`%E' cannot be used as a function", 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. */ + + if (flags & LOOKUP_COMPLAIN) + coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype), + params, fndecl, LOOKUP_NORMAL); + else + coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype), + params, fndecl, 0); + + if (coerced_params == error_mark_node) + { + if (flags & LOOKUP_SPECULATIVELY) + return NULL_TREE; + else + return error_mark_node; + } + + /* Check for errors in format strings. */ + + if (warn_format && (name || assembler_name)) + check_function_format (name, assembler_name, coerced_params); + + /* 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 + && DECL_BUILT_IN (TREE_OPERAND (function, 0))) + 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); + + default: + break; + } + + /* C++ */ + value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node; + { + register tree result + = build_call (function, value_type, coerced_params); + + if (require_complete) + { + if (value_type == void_type_node) + return result; + result = require_complete_type (result); + } + if (IS_AGGR_TYPE (value_type)) + result = build_cplus_new (value_type, result); + return convert_from_reference (result); + } +} + +tree +build_function_call (function, params) + tree function, params; +{ + return build_function_call_real (function, params, 1, LOOKUP_NORMAL); +} + +/* 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. + + 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 +convert_arguments (typelist, values, fndecl, flags) + tree typelist, values, fndecl; + int flags; +{ + register tree typetail, valtail; + register tree result = NULL_TREE; + char *called_thing = 0; + int i = 0; + + /* Argument passing is always copy-initialization. */ + flags |= LOOKUP_ONLYCONVERTING; + + if (fndecl) + { + if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE) + { + if (DECL_NAME (fndecl) == NULL_TREE + || IDENTIFIER_HAS_TYPE_VALUE (DECL_NAME (fndecl))) + called_thing = "constructor"; + else + called_thing = "member function"; + } + else + called_thing = "function"; + } + + for (valtail = values, typetail = typelist; + valtail; + valtail = TREE_CHAIN (valtail), i++) + { + register tree type = typetail ? TREE_VALUE (typetail) : 0; + register tree val = TREE_VALUE (valtail); + + if (val == error_mark_node) + return error_mark_node; + + if (type == void_type_node) + { + if (fndecl) + { + cp_error_at ("too many arguments to %s `%+D'", called_thing, + fndecl); + 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 (tree_last (result)) = error_mark_node; + break; + } + + if (TREE_CODE (val) == OFFSET_REF) + val = resolve_offset_ref (val); + + /* 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)) + && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE)) + val = TREE_OPERAND (val, 0); + + if (type == 0 || TREE_CODE (type) != REFERENCE_TYPE) + { + if (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); + } + + if (val == error_mark_node) + return error_mark_node; + + if (type != 0) + { + /* Formal parm type is specified by a function prototype. */ + tree parmval; + + if (TYPE_SIZE (complete_type (type)) == 0) + { + error ("parameter type of called function is incomplete"); + parmval = val; + } + else + { + parmval = convert_for_initialization + (NULL_TREE, type, val, flags, + "argument passing", fndecl, i); +#ifdef PROMOTE_PROTOTYPES + if ((TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && (TYPE_PRECISION (type) + < TYPE_PRECISION (integer_type_node))) + parmval = default_conversion (parmval); +#endif + } + + if (parmval == error_mark_node) + return error_mark_node; + + result = expr_tree_cons (NULL_TREE, parmval, result); + } + else + { + if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE) + val = convert_from_reference (val); + + result = expr_tree_cons (NULL_TREE, + convert_arg_to_ellipsis (val), + result); + } + + 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)) + { + for (; typetail != void_list_node; ++i) + { + tree parmval + = convert_default_arg (TREE_VALUE (typetail), + TREE_PURPOSE (typetail), + fndecl); + + if (parmval == error_mark_node) + return error_mark_node; + + result = expr_tree_cons (0, parmval, result); + 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 `%%#D'", called_thing); + cp_error_at (buf, fndecl); + error ("at this point in file"); + } + else + error ("too few arguments to function"); + return error_mark_list; + } + } + + return nreverse (result); +} + +/* 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; +{ + if (processing_template_decl) + return build_min_nt (code, arg1, arg2); + + return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE); +} + +tree +build_binary_op (code, arg1, arg2, convert_p) + enum tree_code code; + tree arg1, arg2; + int convert_p ATTRIBUTE_UNUSED; +{ + return build_binary_op_nodefault (code, arg1, arg2, 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, and deal with pointer to member functions. */ + +tree +build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) + enum tree_code code; + tree orig_op0, orig_op1; + enum tree_code error_code; +{ + tree op0, op1; + register enum tree_code code0, code1; + tree type0, type1; + + /* 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 create the expression with this type, rather than + RESULT_TYPE. */ + tree build_type = 0; + + /* Nonzero means after finally constructing the expression + convert it to this 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; + + /* Apply default conversions. */ + if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR + || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR + || code == TRUTH_XOR_EXPR) + { + op0 = decay_conversion (orig_op0); + op1 = decay_conversion (orig_op1); + } + else + { + op0 = default_conversion (orig_op0); + op1 = default_conversion (orig_op1); + } + + type0 = TREE_TYPE (op0); + type1 = TREE_TYPE (op1); + + /* The expression codes of the data types of the arguments tell us + whether the arguments are integers, floating, pointers, etc. */ + code0 = TREE_CODE (type0); + code1 = TREE_CODE (type1); + + /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (op0); + STRIP_TYPE_NOPS (op1); + + /* 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 (type0, type1, 1)) + return pointer_diff (op0, op1, common_type (type0, type1)); + /* 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 + || code0 == COMPLEX_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == COMPLEX_TYPE)) + { + if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1)) + cp_warning ("division by zero in `%E / 0'", op0); + else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1)) + cp_warning ("division by zero in `%E / 0.'", op0); + + if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)) + resultcode = RDIV_EXPR; + else + /* When dividing two signed integers, we have to promote to int. + unless we divide by a constant != -1. Note that default + conversion will have been performed on the operands at this + point, so we have to dig out the original type to find out if + it was unsigned. */ + shorten = ((TREE_CODE (op0) == NOP_EXPR + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0)))) + || (TREE_CODE (op1) == INTEGER_CST + && (TREE_INT_CST_LOW (op1) != -1 + || TREE_INT_CST_HIGH (op1) != -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 (type1) + > 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 (type0) + > 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: + case FLOOR_MOD_EXPR: + if (code1 == INTEGER_TYPE && integer_zerop (op1)) + cp_warning ("division by zero in `%E %% 0'", op0); + else if (code1 == REAL_TYPE && real_zerop (op1)) + cp_warning ("division by zero in `%E %% 0.'", op0); + + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + /* Although it would be tempting to shorten always here, that loses + on some targets, since the modulo instruction is undefined if the + quotient can't be represented in the computation mode. We shorten + only if unsigned or if dividing by something we know != -1. */ + shorten = ((TREE_CODE (op0) == NOP_EXPR + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0)))) + || (TREE_CODE (op1) == INTEGER_CST + && (TREE_INT_CST_LOW (op1) != -1 + || TREE_INT_CST_HIGH (op1) != -1))); + common = 1; + } + break; + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + result_type = boolean_type_node; + 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 = type0; + if (TREE_CODE (op1) == INTEGER_CST) + { + if (tree_int_cst_lt (op1, integer_zero_node)) + warning ("right shift count is negative"); + else + { + if (TREE_INT_CST_LOW (op1) | TREE_INT_CST_HIGH (op1)) + short_shift = 1; + if (TREE_INT_CST_HIGH (op1) != 0 + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1) + >= TYPE_PRECISION (type0))) + warning ("right shift count >= width of type"); + } + } + /* Convert the shift-count to an integer, regardless of + size of value being shifted. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node) + op1 = cp_convert (integer_type_node, op1); + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + break; + + case LSHIFT_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + if (TREE_CODE (op1) == INTEGER_CST) + { + if (tree_int_cst_lt (op1, integer_zero_node)) + warning ("left shift count is negative"); + else if (TREE_INT_CST_HIGH (op1) != 0 + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1) + >= TYPE_PRECISION (type0))) + warning ("left shift count >= width of type"); + } + /* Convert the shift-count to an integer, regardless of + size of value being shifted. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node) + op1 = cp_convert (integer_type_node, op1); + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + break; + + case RROTATE_EXPR: + case LROTATE_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + if (TREE_CODE (op1) == INTEGER_CST) + { + if (tree_int_cst_lt (op1, integer_zero_node)) + warning ("%s rotate count is negative", + (code == LROTATE_EXPR) ? "left" : "right"); + else if (TREE_INT_CST_HIGH (op1) != 0 + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1) + >= TYPE_PRECISION (type0))) + warning ("%s rotate count >= width of type", + (code == LROTATE_EXPR) ? "left" : "right"); + } + /* Convert the shift-count to an integer, regardless of + size of value being shifted. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node) + op1 = cp_convert (integer_type_node, op1); + } + break; + + case EQ_EXPR: + case NE_EXPR: + build_type = boolean_type_node; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == COMPLEX_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == COMPLEX_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + register tree tt0 = TYPE_MAIN_VARIANT (TREE_TYPE (type0)); + register tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (type1)); + + if (comp_target_types (type0, type1, 1)) + result_type = common_type (type0, type1); + else if (tt0 == void_type_node) + { + if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE + && tree_int_cst_lt (TYPE_SIZE (type0), TYPE_SIZE (type1))) + pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer"); + else if (TREE_CODE (tt1) == OFFSET_TYPE) + pedwarn ("ANSI C++ forbids conversion of a pointer to member to `void *'"); + } + else if (tt1 == void_type_node) + { + if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE + && tree_int_cst_lt (TYPE_SIZE (type1), TYPE_SIZE (type0))) + pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer"); + } + else + cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast", + type0, type1); + + if (result_type == NULL_TREE) + result_type = ptr_type_node; + } + else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST + && integer_zerop (op1)) + result_type = type0; + else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST + && integer_zerop (op0)) + result_type = type1; + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + error ("ANSI C++ forbids comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + error ("ANSI C++ forbids comparison between pointer and integer"); + } + else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST + && integer_zerop (op1)) + { + op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0); + op1 = integer_zero_node; + result_type = TREE_TYPE (op0); + } + else if (TYPE_PTRMEMFUNC_P (type1) && TREE_CODE (op0) == INTEGER_CST + && integer_zerop (op0)) + { + op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0); + op1 = integer_zero_node; + result_type = TREE_TYPE (op0); + } + else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1) + && (TYPE_PTRMEMFUNC_FN_TYPE (type0) + == TYPE_PTRMEMFUNC_FN_TYPE (type1))) + { + /* The code we generate for the test is: + + (op0.index == op1.index + && ((op1.index != -1 && op0.delta2 == op1.delta2) + || op0.pfn == op1.pfn)) */ + + tree index0 = build_component_ref (op0, index_identifier, + NULL_TREE, 0); + tree index1 = save_expr (build_component_ref (op1, index_identifier, + NULL_TREE, 0)); + tree pfn0 = PFN_FROM_PTRMEMFUNC (op0); + tree pfn1 = PFN_FROM_PTRMEMFUNC (op1); + tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0); + tree delta21 = DELTA2_FROM_PTRMEMFUNC (op1); + tree e1, e2, e3; + tree integer_neg_one_node + = build_binary_op (MINUS_EXPR, integer_zero_node, + integer_one_node, 1); + e1 = build_binary_op (EQ_EXPR, index0, index1, 1); + e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node, 1); + e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2, + build_binary_op (EQ_EXPR, delta20, delta21, 1), + 1); + e3 = build_binary_op (EQ_EXPR, pfn0, pfn1, 1); + e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3, 1); + e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2, 1); + if (code == EQ_EXPR) + return e2; + return build_binary_op (EQ_EXPR, e2, integer_zero_node, 1); + } + else if (TYPE_PTRMEMFUNC_P (type0) + && TYPE_PTRMEMFUNC_FN_TYPE (type0) == type1) + { + tree index0 = build_component_ref (op0, index_identifier, + NULL_TREE, 0); + tree index1; + tree pfn0 = PFN_FROM_PTRMEMFUNC (op0); + tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0); + tree delta21 = integer_zero_node; + tree e1, e2, e3; + tree integer_neg_one_node + = build_binary_op (MINUS_EXPR, integer_zero_node, integer_one_node, 1); + if (TREE_CODE (TREE_OPERAND (op1, 0)) == FUNCTION_DECL + && DECL_VINDEX (TREE_OPERAND (op1, 0))) + { + /* Map everything down one to make room for + the null pointer to member. */ + index1 = size_binop (PLUS_EXPR, + DECL_VINDEX (TREE_OPERAND (op1, 0)), + integer_one_node); + op1 = integer_zero_node; + delta21 = CLASSTYPE_VFIELD (TYPE_METHOD_BASETYPE + (TREE_TYPE (type1))); + delta21 = DECL_FIELD_BITPOS (delta21); + delta21 = size_binop (FLOOR_DIV_EXPR, delta21, + size_int (BITS_PER_UNIT)); + delta21 = convert (sizetype, delta21); + } + else + index1 = integer_neg_one_node; + { + tree nop1 = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type0), + op1); + TREE_CONSTANT (nop1) = TREE_CONSTANT (op1); + op1 = nop1; + } + e1 = build_binary_op (EQ_EXPR, index0, index1, 1); + e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node, 1); + e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2, + build_binary_op (EQ_EXPR, delta20, delta21, 1), + 1); + e3 = build_binary_op (EQ_EXPR, pfn0, op1, 1); + e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3, 1); + e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2, 1); + if (code == EQ_EXPR) + return e2; + return build_binary_op (EQ_EXPR, e2, integer_zero_node, 1); + } + else if (TYPE_PTRMEMFUNC_P (type1) + && TYPE_PTRMEMFUNC_FN_TYPE (type1) == type0) + { + return build_binary_op (code, op1, op0, 1); + } + 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 (type0, type1, 1)) + result_type = common_type (type0, type1); + else + { + cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast", + type0, type1); + result_type = ptr_type_node; + } + } + break; + + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + build_type = boolean_type_node; + 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 (type0, type1, 1)) + result_type = common_type (type0, type1); + else + { + cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast", + type0, type1); + result_type = ptr_type_node; + } + } + else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST + && integer_zerop (op1)) + result_type = type0; + else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST + && integer_zerop (op0)) + result_type = type1; + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + pedwarn ("ANSI C++ forbids comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + pedwarn ("ANSI C++ forbids comparison between pointer and integer"); + } + break; + + default: + break; + } + + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE) + && + (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE)) + { + int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE); + + if (shorten || common || short_compare) + result_type = common_type (type0, type1); + + /* 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 && none_complex) + { + 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, + common_type (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) + /* We can shorten only if the shift count is less than the + number of bits in the smaller type size. */ + && TREE_INT_CST_HIGH (op1) == 0 + && TYPE_PRECISION (TREE_TYPE (arg0)) > TREE_INT_CST_LOW (op1) + /* 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 + || (((unsigned) 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 = cp_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 cp_convert (boolean_type_node, val); + op0 = xop0, op1 = xop1; + converted = 1; + resultcode = xresultcode; + } + + if (short_compare && warn_sign_compare) + { + int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0)); + int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1)); + + int unsignedp0, unsignedp1; + tree primop0 = get_narrower (op0, &unsignedp0); + tree primop1 = get_narrower (op1, &unsignedp1); + + /* Check for comparison of different enum types. */ + if (TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0)) + != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1))) + { + cp_warning ("comparison between `%#T' and `%#T'", + TREE_TYPE (orig_op0), TREE_TYPE (orig_op1)); + } + + /* Give warnings for comparisons between signed and unsigned + quantities that may fail. */ + /* Do the checking based on the original operand trees, so that + casts will be considered, but default promotions won't be. */ + + /* Do not warn if the comparison is being done in a signed type, + since the signed type will only be chosen if it can represent + all the values of the unsigned type. */ + if (! TREE_UNSIGNED (result_type)) + /* OK */; + /* Do not warn if both operands are unsigned. */ + else if (op0_signed == op1_signed) + /* OK */; + /* Do not warn if the signed quantity is an unsuffixed + integer literal (or some static constant expression + involving such literals) and it is non-negative. */ + else if ((op0_signed && TREE_CODE (orig_op0) == INTEGER_CST + && tree_int_cst_sgn (orig_op0) >= 0) + || (op1_signed && TREE_CODE (orig_op1) == INTEGER_CST + && tree_int_cst_sgn (orig_op1) >= 0)) + /* OK */; + /* Do not warn if the comparison is an equality operation, + the unsigned quantity is an integral constant and it does + not use the most significant bit of result_type. */ + else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR) + && ((op0_signed && TREE_CODE (orig_op1) == INTEGER_CST + && int_fits_type_p (orig_op1, + signed_type (result_type))) + || (op1_signed && TREE_CODE (orig_op0) == INTEGER_CST + && int_fits_type_p (orig_op0, + signed_type (result_type))))) + /* OK */; + else + warning ("comparison between signed and unsigned"); + + /* Warn if two unsigned values are being compared in a size + larger than their original size, and one (and only one) is the + result of a `~' operator. This comparison will always fail. + + Also warn if one operand is a constant, and the constant does not + have all bits set that are set in the ~ operand when it is + extended. */ + + if ((TREE_CODE (primop0) == BIT_NOT_EXPR) + ^ (TREE_CODE (primop1) == BIT_NOT_EXPR)) + { + if (TREE_CODE (primop0) == BIT_NOT_EXPR) + primop0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0); + if (TREE_CODE (primop1) == BIT_NOT_EXPR) + primop1 = get_narrower (TREE_OPERAND (op1, 0), &unsignedp1); + + if (TREE_CODE (primop0) == INTEGER_CST + || TREE_CODE (primop1) == INTEGER_CST) + { + tree primop; + HOST_WIDE_INT constant, mask; + int unsignedp; + unsigned bits; + + if (TREE_CODE (primop0) == INTEGER_CST) + { + primop = primop1; + unsignedp = unsignedp1; + constant = TREE_INT_CST_LOW (primop0); + } + else + { + primop = primop0; + unsignedp = unsignedp0; + constant = TREE_INT_CST_LOW (primop1); + } + + bits = TYPE_PRECISION (TREE_TYPE (primop)); + if (bits < TYPE_PRECISION (result_type) + && bits < HOST_BITS_PER_LONG && unsignedp) + { + mask = (~ (HOST_WIDE_INT) 0) << bits; + if ((mask & constant) != mask) + warning ("comparison of promoted ~unsigned with constant"); + } + } + else if (unsignedp0 && unsignedp1 + && (TYPE_PRECISION (TREE_TYPE (primop0)) + < TYPE_PRECISION (result_type)) + && (TYPE_PRECISION (TREE_TYPE (primop1)) + < TYPE_PRECISION (result_type))) + warning ("comparison of promoted ~unsigned with unsigned"); + } + } + } + + /* 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) + { + cp_error ("invalid operands `%T' and `%T' to binary `%O'", + TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), error_code); + return error_mark_node; + } + + /* Issue warnings about peculiar, but legal, uses of NULL. */ + if (/* It's reasonable to use pointer values as operands of && + and ||, so NULL is no exception. */ + !(code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR) + && (/* If OP0 is NULL and OP1 is not a pointer, or vice versa. */ + (orig_op0 == null_node + && TREE_CODE (TREE_TYPE (op1)) != POINTER_TYPE) + /* Or vice versa. */ + || (orig_op1 == null_node + && TREE_CODE (TREE_TYPE (op0)) != POINTER_TYPE) + /* Or, both are NULL and the operation was not a comparison. */ + || (orig_op0 == null_node && orig_op1 == null_node + && code != EQ_EXPR && code != NE_EXPR))) + /* Some sort of arithmetic operation involving NULL was + performed. Note that pointer-difference and pointer-addition + have already been handled above, and so we don't end up here in + that case. */ + cp_warning ("NULL used in arithmetic"); + + if (! converted) + { + if (TREE_TYPE (op0) != result_type) + op0 = cp_convert (result_type, op0); + if (TREE_TYPE (op1) != result_type) + op1 = cp_convert (result_type, op1); + + if (op0 == error_mark_node || op1 == error_mark_node) + return error_mark_node; + } + + if (build_type == NULL_TREE) + build_type = result_type; + + { + register tree result = build (resultcode, build_type, op0, op1); + register tree folded; + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); + if (final_type != 0) + return cp_convert (final_type, folded); + return folded; + } +} + +/* 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 = TREE_TYPE (ptrop); + + if (!complete_type_or_else (result_type)) + return error_mark_node; + + if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("ANSI C++ forbids using pointer of type `void *' in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("ANSI C++ forbids using pointer to a function in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("ANSI C++ forbids using pointer to a method in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("ANSI C++ forbids using pointer to a member in arithmetic"); + size_exp = integer_one_node; + } + else + size_exp = size_in_bytes (complete_type (TREE_TYPE (result_type))); + + /* 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 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_CONSTANT (intop) + && TREE_CONSTANT (TREE_OPERAND (intop, 1)) + && TREE_CONSTANT (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), 1); + intop = TREE_OPERAND (intop, 0); + } + + /* Convert the integer argument to a type the same size as sizetype + so the multiply won't overflow spuriously. */ + + if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)) + intop = cp_convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop); + + /* Replace the integer argument with a suitable product by the object size. + Do this multiplication as signed, then convert to the appropriate + pointer type (actually unsigned integral). */ + + intop = cp_convert (result_type, + build_binary_op (MULT_EXPR, intop, + cp_convert (TREE_TYPE (intop), + size_exp), + 1)); + + /* Create the sum or difference. */ + + result = build (resultcode, result_type, ptrop, intop); + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (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, ptrtype) + register tree op0, op1; + register tree ptrtype; +{ + register tree result, folded; + tree restype = ptrdiff_type_node; + tree target_type = TREE_TYPE (ptrtype); + + if (!complete_type_or_else (target_type)) + return error_mark_node; + + if (pedantic || warn_pointer_arith) + { + if (TREE_CODE (target_type) == VOID_TYPE) + pedwarn ("ANSI C++ forbids using pointer of type `void *' in subtraction"); + if (TREE_CODE (target_type) == FUNCTION_TYPE) + pedwarn ("ANSI C++ forbids using pointer to a function in subtraction"); + if (TREE_CODE (target_type) == METHOD_TYPE) + pedwarn ("ANSI C++ forbids using pointer to a method in subtraction"); + if (TREE_CODE (target_type) == OFFSET_TYPE) + pedwarn ("ANSI C++ forbids using pointer to a member in subtraction"); + } + + /* First do the subtraction as integers; + then drop through to build the divide operator. */ + + op0 = build_binary_op (MINUS_EXPR, cp_convert (restype, op0), + cp_convert (restype, op1), 1); + + /* This generates an error if op1 is a pointer to an incomplete type. */ + if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0) + error ("arithmetic on pointer to an incomplete type"); + + op1 = ((TREE_CODE (target_type) == VOID_TYPE + || TREE_CODE (target_type) == FUNCTION_TYPE + || TREE_CODE (target_type) == METHOD_TYPE + || TREE_CODE (target_type) == OFFSET_TYPE) + ? integer_one_node + : size_in_bytes (target_type)); + + /* Do the division. */ + + result = build (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1)); + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); + return folded; +} + +/* 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); + + my_friendly_assert (TREE_CODE (field) == FIELD_DECL, 981018); + + if (DECL_C_BIT_FIELD (field)) + { + error (msg, IDENTIFIER_POINTER (DECL_NAME (field))); + return error_mark_node; + } + + if (TREE_CODE (field) == FIELD_DECL + && TYPE_USES_COMPLEX_INHERITANCE (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)); + TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0)); + } + else + /* This conversion is harmless. */ + rval = convert_force (argtype, rval, 0); + + if (! integer_zerop (DECL_FIELD_BITPOS (field))) + { + tree offset = size_binop (EASY_DIV_EXPR, DECL_FIELD_BITPOS (field), + size_int (BITS_PER_UNIT)); + int flag = TREE_CONSTANT (rval); + offset = convert (sizetype, offset); + rval = fold (build (PLUS_EXPR, argtype, + rval, cp_convert (argtype, offset))); + TREE_CONSTANT (rval) = flag; + } + 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; +{ + if (processing_template_decl) + return build_min_nt (code, xarg, NULL_TREE); + + /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an + error message. */ + if (code == ADDR_EXPR + && TREE_CODE (xarg) != TEMPLATE_ID_EXPR + && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg))) + && TYPE_SIZE (TREE_TYPE (xarg)) == NULL_TREE) + || (TREE_CODE (xarg) == OFFSET_REF))) + /* don't look for a function */; + else + { + tree rval; + + rval = build_new_op (code, LOOKUP_NORMAL, xarg, + NULL_TREE, NULL_TREE); + if (rval || code != ADDR_EXPR) + return rval; + } + + if (code == ADDR_EXPR) + { + if (TREE_CODE (xarg) == TARGET_EXPR) + warning ("taking address of temporary"); + } + + return build_unary_op (code, xarg, 0); +} + +/* Just like truthvalue_conversion, but we want a CLEANUP_POINT_EXPR. */ + +tree +condition_conversion (expr) + tree expr; +{ + tree t; + if (processing_template_decl) + return expr; + t = cp_convert (boolean_type_node, expr); + t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t)); + return t; +} + +/* 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; + char *errstring = NULL; + tree val; + + if (arg == error_mark_node) + return error_mark_node; + + 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 (!(arg = build_expr_type_conversion + (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, 1))) + errstring = "wrong type argument to unary plus"; + else + { + if (!noconvert) + arg = default_conversion (arg); + arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg); + TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0)); + } + break; + + case NEGATE_EXPR: + if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1))) + errstring = "wrong type argument to unary minus"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case BIT_NOT_EXPR: + if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE) + { + code = CONJ_EXPR; + if (!noconvert) + arg = default_conversion (arg); + } + else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM, + arg, 1))) + errstring = "wrong type argument to bit-complement"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case ABS_EXPR: + if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1))) + errstring = "wrong type argument to abs"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case CONJ_EXPR: + /* Conjugating a real value is a no-op, but allow it anyway. */ + if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1))) + errstring = "wrong type argument to conjugation"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case TRUTH_NOT_EXPR: + arg = cp_convert (boolean_type_node, arg); + val = invert_truthvalue (arg); + if (arg != error_mark_node) + return val; + errstring = "in argument to unary !"; + break; + + case NOP_EXPR: + break; + + case REALPART_EXPR: + if (TREE_CODE (arg) == COMPLEX_CST) + return TREE_REALPART (arg); + else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE) + return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg)); + else + return arg; + + case IMAGPART_EXPR: + if (TREE_CODE (arg) == COMPLEX_CST) + return TREE_IMAGPART (arg); + else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE) + return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg)); + else + return cp_convert (TREE_TYPE (arg), integer_zero_node); + + 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; + + /* Increment or decrement the real part of the value, + and don't change the imaginary part. */ + if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE) + { + tree real, imag; + + arg = stabilize_reference (arg); + real = build_unary_op (REALPART_EXPR, arg, 1); + imag = build_unary_op (IMAGPART_EXPR, arg, 1); + return build (COMPLEX_EXPR, TREE_TYPE (arg), + build_unary_op (code, real, 1), imag); + } + + /* Report invalid types. */ + + if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER, + arg, 1))) + { + if (code == PREINCREMENT_EXPR) + errstring ="no pre-increment operator for type"; + else if (code == POSTINCREMENT_EXPR) + errstring ="no post-increment operator for type"; + else if (code == PREDECREMENT_EXPR) + errstring ="no pre-decrement operator for type"; + else + errstring ="no post-decrement operator for type"; + break; + } + + /* Report something read-only. */ + + if (CP_TYPE_CONST_P (TREE_TYPE (arg)) + || TREE_READONLY (arg)) + readonly_error (arg, ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement"), + 0); + + { + register tree inc; + tree result_type = TREE_TYPE (arg); + + arg = get_unwidened (arg, 0); + argtype = TREE_TYPE (arg); + + /* ARM $5.2.5 last annotation says this should be forbidden. */ + if (TREE_CODE (argtype) == ENUMERAL_TYPE) + pedwarn ("ANSI C++ forbids %sing an enum", + (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement"); + + /* Compute the increment. */ + + if (TREE_CODE (argtype) == POINTER_TYPE) + { + enum tree_code tmp = TREE_CODE (TREE_TYPE (argtype)); + if (TYPE_SIZE (complete_type (TREE_TYPE (argtype))) == 0) + cp_error ("cannot %s a pointer to incomplete type `%T'", + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement"), TREE_TYPE (argtype)); + else if ((pedantic || warn_pointer_arith) + && (tmp == FUNCTION_TYPE || tmp == METHOD_TYPE + || tmp == VOID_TYPE || tmp == OFFSET_TYPE)) + cp_pedwarn ("ANSI C++ forbids %sing a pointer of type `%T'", + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement"), argtype); + inc = c_sizeof_nowarn (TREE_TYPE (argtype)); + } + else + inc = integer_one_node; + + inc = cp_convert (argtype, inc); + + /* Handle incrementing a cast-expression. */ + + 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, compound; + if (! lvalue_p (arg) && pedantic) + pedwarn ("cast to non-reference type used as lvalue"); + 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_SIDE_EFFECTS (incremented) = 1; + + modify = build_modify_expr (arg, NOP_EXPR, incremented); + compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value); + + /* Eliminate warning about unused result of + or -. */ + TREE_NO_UNUSED_WARNING (compound) = 1; + return compound; + } + + default: + break; + } + + /* 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; + + /* Forbid using -- on `bool'. */ + if (TREE_TYPE (arg) == boolean_type_node) + { + if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR) + { + cp_error ("invalid use of `--' on bool variable `%D'", arg); + return error_mark_node; + } +#if 0 + /* This will only work if someone can convince Kenner to accept + my patch to expand_increment. (jason) */ + val = build (code, TREE_TYPE (arg), arg, inc); +#else + if (code == POSTINCREMENT_EXPR) + { + arg = stabilize_reference (arg); + val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, + boolean_true_node); + TREE_SIDE_EFFECTS (val) = 1; + arg = save_expr (arg); + val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg); + val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val); + } + else + val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, + boolean_true_node); +#endif + } + else + val = build (code, TREE_TYPE (arg), arg, inc); + + TREE_SIDE_EFFECTS (val) = 1; + return cp_convert (result_type, val); + } + + case ADDR_EXPR: + /* Note that this operation never does default_conversion + regardless of NOCONVERT. */ + + argtype = lvalue_type (arg); + if (TREE_CODE (argtype) == REFERENCE_TYPE) + { + arg = build1 + (CONVERT_EXPR, + build_pointer_type (TREE_TYPE (argtype)), arg); + TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0)); + return arg; + } + else if (pedantic && DECL_MAIN_P (arg)) + /* ARM $3.4 */ + pedwarn ("taking address of function `main'"); + + /* Let &* cancel out to simplify resulting code. */ + if (TREE_CODE (arg) == INDIRECT_REF) + { + /* We don't need to have `current_class_ptr' wrapped in a + NON_LVALUE_EXPR node. */ + if (arg == current_class_ref) + return current_class_ptr; + + arg = TREE_OPERAND (arg, 0); + if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE) + { + arg = build1 + (CONVERT_EXPR, + build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg); + TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0)); + } + else if (lvalue_p (arg)) + /* Don't let this be an lvalue. */ + return non_lvalue (arg); + 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), 1); + } + + /* Uninstantiated types are all functions. Taking the + address of a function is a no-op, so just return the + argument. */ + + if (TREE_CODE (arg) == IDENTIFIER_NODE + && IDENTIFIER_OPNAME_P (arg)) + { + my_friendly_abort (117); + /* 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) == TEMPLATE_ID_EXPR) + { + tree targs; + tree fn; + + /* We don't require a match here; it's possible that the + context (like a cast to a particular type) will resolve + the particular choice of template. */ + fn = determine_specialization (arg, + NULL_TREE, + &targs, + 0, + 0); + + if (fn) + { + fn = instantiate_template (fn, targs); + mark_addressable (fn); + return build_unary_op (ADDR_EXPR, fn, 0); + } + + return build1 (ADDR_EXPR, unknown_type_node, arg); + } + else if (type_unknown_p (arg)) + 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; + + 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 (! lvalue_p (arg) && pedantic) + pedwarn ("taking the address of a cast to non-reference type"); + break; + + default: + break; + } + + /* Allow the address of a constructor if all the elements + are constant. */ + if (TREE_CODE (arg) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (arg) + && TREE_CONSTANT (arg)) + ; + /* Anything not already handled and not a true memory reference + is an error. */ + else if (TREE_CODE (argtype) != FUNCTION_TYPE + && TREE_CODE (argtype) != METHOD_TYPE + && !lvalue_or_else (arg, "unary `&'")) + return error_mark_node; + + if (argtype != error_mark_node) + 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 */ + if (staticp (arg)) + TREE_CONSTANT (addr) = 1; + + if (TREE_CODE (argtype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE) + { + build_ptrmemfunc_type (argtype); + addr = build_ptrmemfunc (argtype, addr, 0); + } + + return addr; + } + + default: + break; + } + + if (!errstring) + { + if (argtype == 0) + argtype = TREE_TYPE (arg); + return fold (build1 (code, argtype, arg)); + } + + error (errstring); + return error_mark_node; +} + +#if 0 +/* 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 cp_convert (TREE_TYPE (conversions), + convert_sequence (TREE_OPERAND (conversions, 0), + arg)); + + default: + return arg; + } +} +#endif + +/* 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 + || TREE_CODE (arg) == MIN_EXPR || TREE_CODE (arg) == MAX_EXPR) + return rationalize_conditional_expr (code, arg); + + if (TREE_CODE (arg) == MODIFY_EXPR + || TREE_CODE (arg) == PREINCREMENT_EXPR + || TREE_CODE (arg) == PREDECREMENT_EXPR) + return unary_complex_lvalue + (code, build (COMPOUND_EXPR, TREE_TYPE (TREE_OPERAND (arg, 0)), + arg, TREE_OPERAND (arg, 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); + arg = build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result); + TREE_NO_UNUSED_WARNING (arg) = 1; + return arg; + } + + 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; + + my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313); + + if (TREE_CODE (arg) != OFFSET_REF) + return 0; + + t = TREE_OPERAND (arg, 1); + + /* Check all this code for right semantics. */ + if (TREE_CODE (t) == FUNCTION_DECL) + { + if (DECL_DESTRUCTOR_P (t)) + cp_error ("taking address of destructor"); + return build_unary_op (ADDR_EXPR, t, 0); + } + if (TREE_CODE (t) == VAR_DECL) + return build_unary_op (ADDR_EXPR, t, 0); + else + { + tree type; + + if (TREE_OPERAND (arg, 0) + && ! is_dummy_object (TREE_OPERAND (arg, 0)) + && TREE_CODE (t) != FIELD_DECL) + { + cp_error ("taking address of bound pointer-to-member expression"); + return error_mark_node; + } + + type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t)); + type = build_pointer_type (type); + + t = make_node (PTRMEM_CST); + TREE_TYPE (t) = type; + PTRMEM_CST_MEMBER (t) = TREE_OPERAND (arg, 1); + return t; + } + } + + + /* We permit compiler to make function calls returning + objects of aggregate type look like lvalues. */ + { + tree targ = arg; + + if (TREE_CODE (targ) == SAVE_EXPR) + targ = TREE_OPERAND (targ, 0); + + if (TREE_CODE (targ) == CALL_EXPR && IS_AGGR_TYPE (TREE_TYPE (targ))) + { + if (TREE_CODE (arg) == SAVE_EXPR) + targ = arg; + else + targ = build_cplus_new (TREE_TYPE (arg), arg); + return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), targ); + } + + if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == INDIRECT_REF) + return build (SAVE_EXPR, build_pointer_type (TREE_TYPE (arg)), + TREE_OPERAND (targ, 0), current_function_decl, NULL); + } + + /* Don't let anything else be handled specially. */ + 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. + Value is 1 if successful. + + C++: we do not allow `current_class_ptr' 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: + case REALPART_EXPR: + case IMAGPART_EXPR: + x = TREE_OPERAND (x, 0); + break; + + case PARM_DECL: + if (x == current_class_ptr) + { + if (! flag_this_is_variable) + 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 + && ! DECL_IN_MEMORY_P (x)) + { + /* We thought this would make a good constant variable, + but we were wrong. */ + push_obstacks_nochange (); + end_temporary_allocation (); + + TREE_ASM_WRITTEN (x) = 0; + DECL_RTL (x) = 0; + rest_of_decl_compilation (x, 0, + !DECL_FUNCTION_SCOPE_P (x), + 0); + TREE_ADDRESSABLE (x) = 1; + + pop_obstacks (); + + return 1; + } + /* Caller should not be trying to mark initialized + constant fields addressable. */ + my_friendly_assert (DECL_LANG_SPECIFIC (x) == 0 + || DECL_IN_AGGR_P (x) == 0 + || TREE_STATIC (x) + || DECL_EXTERNAL (x), 314); + + case CONST_DECL: + case RESULT_DECL: + if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x) + && !DECL_ARTIFICIAL (x) && extra_warnings) + cp_warning ("address requested for `%D', which is declared `register'", + x); + put_var_into_stack (x); + TREE_ADDRESSABLE (x) = 1; + return 1; + + case FUNCTION_DECL: + if (DECL_LANG_SPECIFIC (x) != 0) + { + x = DECL_MAIN_VARIANT (x); + /* We have to test both conditions here. The first may be + non-zero in the case of processing a default function. The + second may be non-zero in the case of a template function. */ + if (DECL_TEMPLATE_INFO (x) && !DECL_TEMPLATE_SPECIALIZATION (x)) + mark_used (x); + } + TREE_ADDRESSABLE (x) = 1; + TREE_USED (x) = 1; + TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1; + return 1; + + case CONSTRUCTOR: + TREE_ADDRESSABLE (x) = 1; + return 1; + + case TARGET_EXPR: + TREE_ADDRESSABLE (x) = 1; + mark_addressable (TREE_OPERAND (x, 0)); + return 1; + + default: + return 1; + } +} + +/* Build and return a conditional expression IFEXP ? OP1 : OP2. */ + +tree +build_x_conditional_expr (ifexp, op1, op2) + tree ifexp, op1, op2; +{ + if (processing_template_decl) + return build_min_nt (COND_EXPR, ifexp, op1, op2); + + return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2); +} + +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) + pedwarn ("ANSI C++ forbids omitting the middle term of a ?: expression"); + ifexp = op1 = save_expr (ifexp); + } + + ifexp = cp_convert (boolean_type_node, ifexp); + + if (TREE_CODE (ifexp) == ERROR_MARK) + 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 + && code2 != FUNCTION_TYPE + && code2 != METHOD_TYPE) + { + tree result; + + if (TREE_CONSTANT (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) + type1 = cp_build_qualified_type + (type1, (CP_TYPE_QUALS (TREE_TYPE (op1)) + | CP_TYPE_QUALS (TREE_TYPE (op2)))); + /* ??? This is a kludge to deal with the fact that + we don't sort out integers and enums properly, yet. */ + result = fold (build (COND_EXPR, type1, ifexp, op1, op2)); + if (TREE_TYPE (result) != type1) + result = build1 (NOP_EXPR, type1, result); + /* Expand both sides into the same slot, + hopefully the target of the ?: expression. */ + if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR) + { + tree slot = build (VAR_DECL, TREE_TYPE (result)); + layout_decl (slot, 0); + result = build (TARGET_EXPR, TREE_TYPE (result), + slot, result, NULL_TREE, NULL_TREE); + } + return result; + } + + /* 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) + { + cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'", + type1, type2); + return error_mark_node; + } + else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2) + && type2 != type_promotes_to (type1)) + warning ("enumeral and non-enumeral type in conditional expression"); + } + else if (extra_warnings + && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1) + && type1 != type_promotes_to (type2)) + warning ("enumeral and non-enumeral type in conditional expression"); + + if (code1 != VOID_TYPE) + { + op1 = default_conversion (op1); + type1 = TREE_TYPE (op1); + if (TYPE_PTRMEMFUNC_P (type1)) + type1 = TYPE_PTRMEMFUNC_FN_TYPE (type1); + code1 = TREE_CODE (type1); + } + if (code2 != VOID_TYPE) + { + op2 = default_conversion (op2); + type2 = TREE_TYPE (op2); + if (TYPE_PTRMEMFUNC_P (type2)) + type2 = TYPE_PTRMEMFUNC_FN_TYPE (type2); + code2 = TREE_CODE (type2); + } + + if (code1 == RECORD_TYPE && code2 == RECORD_TYPE + && real_lvalue_p (op1) && real_lvalue_p (op2) + && comptypes (type1, type2, COMPARE_BASE | COMPARE_RELAXED)) + { + type1 = build_reference_type (type1); + type2 = build_reference_type (type2); + result_type = common_type (type1, type2); + op1 = convert_to_reference (result_type, op1, CONV_IMPLICIT, + LOOKUP_NORMAL, NULL_TREE); + op2 = convert_to_reference (result_type, op2, CONV_IMPLICIT, + LOOKUP_NORMAL, NULL_TREE); + } + /* Quickly detect the usual case where op1 and op2 have the same type + after promotion. */ + else if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)) + { + if (type1 == type2) + result_type = type1; + else + result_type = + cp_build_qualified_type (type1, + CP_TYPE_QUALS (TREE_TYPE (op1)) + | CP_TYPE_QUALS (TREE_TYPE (op2))); + } + else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE) + && (code2 == INTEGER_TYPE || code2 == REAL_TYPE)) + { + result_type = common_type (type1, type2); + } + else if (code1 == VOID_TYPE || code2 == VOID_TYPE) + { + if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE)) + pedwarn ("ANSI C++ forbids conditional expr with only one void side"); + result_type = void_type_node; + } + else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2)) + result_type = qualify_type (type1, type2); + else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1)) + result_type = qualify_type (type2, type1); + else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) + { + if (comp_target_types (type1, type2, 1)) + result_type = common_type (type1, type2); + else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node) + { + if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE) + pedwarn ("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) + pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer"); + result_type = qualify_type (type2, type1); + } + /* C++ */ + else if (same_or_base_type_p (type2, type1)) + result_type = type2; + else if (IS_AGGR_TYPE (TREE_TYPE (type1)) + && IS_AGGR_TYPE (TREE_TYPE (type2)) + && (result_type = common_base_type (TREE_TYPE (type1), + TREE_TYPE (type2)))) + { + if (result_type == error_mark_node) + { + cp_error ("common base type of types `%T' and `%T' is ambiguous", + TREE_TYPE (type1), TREE_TYPE (type2)); + result_type = ptr_type_node; + } + else + { + if (pedantic + && result_type != TREE_TYPE (type1) + && result_type != TREE_TYPE (type2)) + cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression", + type1, type2, result_type); + + result_type = build_pointer_type (result_type); + } + } + else + { + pedwarn ("pointer type mismatch in conditional expression"); + result_type = ptr_type_node; + } + } + else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) + { + pedwarn ("pointer/integer type mismatch in conditional expression"); + result_type = type1; + } + else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + pedwarn ("pointer/integer type mismatch in conditional expression"); + result_type = type2; + } + if (type2 == unknown_type_node) + result_type = type1; + else if (type1 == unknown_type_node) + result_type = type2; + + 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) + { + cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'", + type1, type2); + return error_mark_node; + } + /* Warning: this code assumes that conversion between cv-variants of + a type is done using NOP_EXPRs. */ + if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1)) + { + /* There are other types besides pointers and records. */ + tree tmp; + if (code2 == POINTER_TYPE) + tmp = build_pointer_type + (cp_build_qualified_type (TREE_TYPE (type2), + TYPE_QUAL_CONST + | TYPE_QUAL_VOLATILE + | TYPE_QUAL_RESTRICT)); + else + tmp = type2; + tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0); + if (tmp == NULL_TREE) + { + cp_error ("incompatible types `%T' and `%T' in `?:'", + type1, type2); + return error_mark_node; + } + if (tmp == error_mark_node) + error ("ambiguous pointer conversion"); + else + STRIP_NOPS (tmp); + result_type = common_type (type2, TREE_TYPE (tmp)); + op1 = tmp; + } + else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2)) + { + tree tmp; + if (code1 == POINTER_TYPE) + tmp = build_pointer_type + (cp_build_qualified_type (TREE_TYPE (type1), + TYPE_QUAL_CONST + | TYPE_QUAL_VOLATILE + | TYPE_QUAL_RESTRICT)); + else + tmp = type1; + + tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0); + if (tmp == NULL_TREE) + { + cp_error ("incompatible types `%T' and `%T' in `?:'", + type1, type2); + return error_mark_node; + } + if (tmp == error_mark_node) + error ("ambiguous pointer conversion"); + else + STRIP_NOPS (tmp); + result_type = common_type (type1, TREE_TYPE (tmp)); + op2 = tmp; + } + else if (flag_cond_mismatch) + result_type = void_type_node; + else + { + error ("type mismatch in conditional expression"); + return error_mark_node; + } + } + + if (TREE_CODE (result_type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE) + result_type = build_ptrmemfunc_type (result_type); + + if (result_type != TREE_TYPE (op1)) + op1 = convert_for_initialization + (NULL_TREE, result_type, op1, LOOKUP_NORMAL, "converting", NULL_TREE, 0); + if (result_type != TREE_TYPE (op2)) + op2 = convert_for_initialization + (NULL_TREE, result_type, op2, LOOKUP_NORMAL, "converting", NULL_TREE, 0); + + if (TREE_CODE (ifexp) == INTEGER_CST) + return integer_zerop (ifexp) ? op2 : op1; + + return convert_from_reference + (fold (build (COND_EXPR, result_type, ifexp, op1, op2))); +} + +/* Handle overloading of the ',' operator when needed. Otherwise, + this function just builds an expression list. */ + +tree +build_x_compound_expr (list) + tree list; +{ + tree rest = TREE_CHAIN (list); + tree result; + + if (processing_template_decl) + return build_min_nt (COMPOUND_EXPR, list, NULL_TREE); + + if (rest == NULL_TREE) + return build_compound_expr (list); + + result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL, + TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE); + if (result) + return build_x_compound_expr (expr_tree_cons (NULL_TREE, result, + TREE_CHAIN (rest))); + + if (! TREE_SIDE_EFFECTS (TREE_VALUE (list))) + { + /* the left-hand operand of a comma expression is like an expression + statement: we should warn if it doesn't have any side-effects, + unless it was explicitly cast to (void). */ + if ((extra_warnings || warn_unused) + && !(TREE_CODE (TREE_VALUE(list)) == CONVERT_EXPR + && TREE_TYPE (TREE_VALUE(list)) == void_type_node)) + warning("left-hand operand of comma expression has no effect"); + } +#if 0 /* this requires a gcc backend patch to export warn_if_unused_value */ + else if (warn_unused) + warn_if_unused_value (TREE_VALUE(list)); +#endif + + return build_compound_expr + (expr_tree_cons (NULL_TREE, TREE_VALUE (list), + build_expr_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_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); + + /* Convert arrays to pointers. */ + if (TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE) + return default_conversion (TREE_VALUE (list)); + else + return TREE_VALUE (list); + } + + rest = build_compound_expr (TREE_CHAIN (list)); + + /* When pedantic, a compound expression cannot be a constant expression. */ + if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)) && ! pedantic) + return rest; + + return build (COMPOUND_EXPR, TREE_TYPE (rest), + break_out_cleanups (TREE_VALUE (list)), rest); +} + +tree +build_static_cast (type, expr) + tree type, expr; +{ + tree intype, binfo; + int ok; + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; + + if (TREE_CODE (expr) == OFFSET_REF) + expr = resolve_offset_ref (expr); + + if (processing_template_decl) + { + tree t = build_min (STATIC_CAST_EXPR, copy_to_permanent (type), + expr); + return t; + } + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */ + if (TREE_CODE (type) != REFERENCE_TYPE + && TREE_CODE (expr) == NOP_EXPR + && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0))) + expr = TREE_OPERAND (expr, 0); + + if (TREE_CODE (type) == VOID_TYPE) + return build1 (CONVERT_EXPR, type, expr); + + if (TREE_CODE (type) == REFERENCE_TYPE) + return (convert_from_reference + (convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT, + LOOKUP_COMPLAIN, NULL_TREE))); + + if (IS_AGGR_TYPE (type)) + return build_cplus_new + (type, (build_method_call + (NULL_TREE, ctor_identifier, build_expr_list (NULL_TREE, expr), + TYPE_BINFO (type), LOOKUP_NORMAL))); + + expr = decay_conversion (expr); + intype = TREE_TYPE (expr); + + /* FIXME handle casting to array type. */ + + ok = 0; + if (can_convert_arg (type, intype, expr)) + ok = 1; + else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype)) + { + tree binfo; + if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)) + && at_least_as_qualified_p (TREE_TYPE (type), + TREE_TYPE (intype)) + && (binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 0)) + && ! TREE_VIA_VIRTUAL (binfo)) + ok = 1; + } + else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) + { + if (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))), + TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (intype)))) + && at_least_as_qualified_p (TREE_TYPE (TREE_TYPE (type)), + TREE_TYPE (TREE_TYPE (intype))) + && (binfo = get_binfo (TYPE_OFFSET_BASETYPE (TREE_TYPE (type)), + TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)), 0)) + && ! TREE_VIA_VIRTUAL (binfo)) + ok = 1; + } + else if (TREE_CODE (intype) != BOOLEAN_TYPE + && TREE_CODE (type) != ARRAY_TYPE + && TREE_CODE (type) != FUNCTION_TYPE + && can_convert (intype, type)) + ok = 1; + + if (ok) + return build_c_cast (type, expr); + + cp_error ("static_cast from `%T' to `%T'", intype, type); + return error_mark_node; +} + +tree +build_reinterpret_cast (type, expr) + tree type, expr; +{ + tree intype; + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; + + if (TREE_CODE (expr) == OFFSET_REF) + expr = resolve_offset_ref (expr); + + if (processing_template_decl) + { + tree t = build_min (REINTERPRET_CAST_EXPR, + copy_to_permanent (type), expr); + return t; + } + + if (TREE_CODE (type) != REFERENCE_TYPE) + { + expr = decay_conversion (expr); + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs if VALUE 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); + } + + intype = TREE_TYPE (expr); + + if (TREE_CODE (type) == REFERENCE_TYPE) + { + if (! real_lvalue_p (expr)) + { + cp_error ("reinterpret_cast from `%T' rvalue to `%T'", intype, type); + return error_mark_node; + } + expr = build_unary_op (ADDR_EXPR, expr, 0); + if (expr != error_mark_node) + expr = build_reinterpret_cast + (build_pointer_type (TREE_TYPE (type)), expr); + if (expr != error_mark_node) + expr = build_indirect_ref (expr, 0); + return expr; + } + else if (same_type_p (TYPE_MAIN_VARIANT (intype), + TYPE_MAIN_VARIANT (type))) + return build_static_cast (type, expr); + + if (TYPE_PTR_P (type) && (TREE_CODE (intype) == INTEGER_TYPE + || TREE_CODE (intype) == ENUMERAL_TYPE)) + /* OK */; + else if (TREE_CODE (type) == INTEGER_TYPE && TYPE_PTR_P (intype)) + { + if (TYPE_PRECISION (type) < TYPE_PRECISION (intype)) + cp_pedwarn ("reinterpret_cast from `%T' to `%T' loses precision", + intype, type); + } + else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype)) + || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))) + { + if (TREE_READONLY_DECL_P (expr)) + expr = decl_constant_value (expr); + return fold (build1 (NOP_EXPR, type, expr)); + } + else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) + || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype))) + { + if (! comp_ptr_ttypes_reinterpret (TREE_TYPE (type), TREE_TYPE (intype))) + cp_pedwarn ("reinterpret_cast from `%T' to `%T' casts away const (or volatile)", + intype, type); + + if (TREE_READONLY_DECL_P (expr)) + expr = decl_constant_value (expr); + return fold (build1 (NOP_EXPR, type, expr)); + } + else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype)) + || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type))) + { + pedwarn ("ANSI C++ forbids casting between pointers to functions and objects"); + if (TREE_READONLY_DECL_P (expr)) + expr = decl_constant_value (expr); + return fold (build1 (NOP_EXPR, type, expr)); + } + else + { + cp_error ("reinterpret_cast from `%T' to `%T'", intype, type); + return error_mark_node; + } + + return cp_convert (type, expr); +} + +tree +build_const_cast (type, expr) + tree type, expr; +{ + tree intype; + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; + + if (TREE_CODE (expr) == OFFSET_REF) + expr = resolve_offset_ref (expr); + + if (processing_template_decl) + { + tree t = build_min (CONST_CAST_EXPR, copy_to_permanent (type), + expr); + return t; + } + + if (TREE_CODE (type) != REFERENCE_TYPE) + { + expr = decay_conversion (expr); + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs if VALUE 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); + } + + intype = TREE_TYPE (expr); + + if (same_type_p (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type))) + return build_static_cast (type, expr); + else if (TREE_CODE (type) == REFERENCE_TYPE) + { + if (! real_lvalue_p (expr)) + { + cp_error ("const_cast from `%T' rvalue to `%T'", intype, type); + return error_mark_node; + } + + if (comp_ptr_ttypes_const (TREE_TYPE (type), intype)) + { + expr = build_unary_op (ADDR_EXPR, expr, 0); + expr = build1 (NOP_EXPR, type, expr); + return convert_from_reference (expr); + } + } + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (intype) == POINTER_TYPE + && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype))) + return cp_convert (type, expr); + + cp_error ("const_cast from `%T' to `%T'", intype, type); + return error_mark_node; +} + +/* Build an expression representing a cast to type TYPE of expression EXPR. + + ALLOW_NONCONVERTING is true if we should allow non-converting constructors + when doing the cast. */ + +tree +build_c_cast (type, expr) + tree type, expr; +{ + register tree value = expr; + tree otype; + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */ + if (TREE_CODE (type) != REFERENCE_TYPE + && TREE_CODE (value) == NOP_EXPR + && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0))) + value = TREE_OPERAND (value, 0); + + if (TREE_TYPE (expr) + && TREE_CODE (TREE_TYPE (expr)) == OFFSET_TYPE + && TREE_CODE (type) != OFFSET_TYPE) + value = resolve_offset_ref (value); + + if (TREE_CODE (type) == ARRAY_TYPE) + { + /* Allow casting from T1* to T2[] because Cfront allows it. + NIHCL uses it. It is not valid ANSI C however, and hence, not + valid ANSI C++. */ + if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) + { + if (pedantic) + pedwarn ("ANSI C++ forbids casting to an array type"); + type = build_pointer_type (TREE_TYPE (type)); + } + else + { + error ("ANSI C++ forbids casting to an array type"); + return error_mark_node; + } + } + + if (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE) + { + cp_error ("casting to function type `%T'", type); + return error_mark_node; + } + + if (IS_SIGNATURE (type)) + { + error ("cast specifies signature type"); + return error_mark_node; + } + + if (processing_template_decl) + { + tree t = build_min (CAST_EXPR, type, + min_tree_cons (NULL_TREE, value, NULL_TREE)); + return t; + } + + /* Convert functions and arrays to pointers and + convert references to their expanded types, + but don't convert any other types. If, however, we are + casting to a class type, there's no reason to do this: the + cast will only succeed if there is a converting constructor, + and the default conversions will be done at that point. In + fact, doing the default conversion here is actually harmful + in cases like this: + + typedef int A[2]; + struct S { S(const A&); }; + + since we don't want the array-to-pointer conversion done. */ + if (!IS_AGGR_TYPE (type)) + { + if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE + || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE + /* Don't do the default conversion on a ->* expression. */ + && ! (TREE_CODE (type) == POINTER_TYPE + && bound_pmf_p (value))) + || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE) + value = default_conversion (value); + } + else if (TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE) + /* However, even for class types, we still need to strip away + the reference type, since the call to convert_force below + does not expect the input expression to be of reference + type. */ + value = convert_from_reference (value); + + otype = TREE_TYPE (value); + + /* Optionally warn about potentially worrisome casts. */ + + if (warn_cast_qual + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && !at_least_as_qualified_p (TREE_TYPE (type), + TREE_TYPE (otype))) + cp_warning ("cast discards qualifiers from pointer target type"); + + /* Warn about possible alignment problems. */ + if (STRICT_ALIGNMENT && warn_cast_align + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE + && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE + && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype))) + warning ("cast increases required alignment of target type"); + +#if 0 + /* We should see about re-enabling these, they seem useful to + me. */ + if (TREE_CODE (type) == INTEGER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype)) + warning ("cast from pointer to integer of different size"); + + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == INTEGER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype) + /* Don't warn about converting 0 to pointer, + provided the 0 was explicit--not cast or made by folding. */ + && !(TREE_CODE (value) == INTEGER_CST && integer_zerop (value))) + warning ("cast to pointer from integer of different size"); +#endif + + if (TREE_CODE (type) == REFERENCE_TYPE) + value = (convert_from_reference + (convert_to_reference (type, value, CONV_C_CAST, + LOOKUP_COMPLAIN, NULL_TREE))); + else + { + tree ovalue; + + if (TREE_READONLY_DECL_P (value)) + value = decl_constant_value (value); + + ovalue = value; + value = convert_force (type, value, CONV_C_CAST); + + /* Ignore any integer overflow caused by the cast. */ + if (TREE_CODE (value) == INTEGER_CST) + { + TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue); + TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue); + } + } + + /* Always produce some operator for an explicit cast, + so we can tell (for -pedantic) that the cast is no lvalue. */ + if (TREE_CODE (type) != REFERENCE_TYPE && value == expr + && real_lvalue_p (value)) + value = non_lvalue (value); + + return value; +} + +/* 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. */ + +tree +build_modify_expr (lhs, modifycode, rhs) + tree lhs; + enum tree_code modifycode; + tree rhs; +{ + register tree result; + tree newrhs = rhs; + tree lhstype = TREE_TYPE (lhs); + tree olhstype = lhstype; + tree olhs = lhs; + + /* Avoid duplicate error messages from operands that had errors. */ + if (lhs == error_mark_node || rhs == error_mark_node) + return error_mark_node; + + /* Types that aren't fully specified cannot be used in assignments. */ + lhs = require_complete_type (lhs); + + newrhs = rhs; + + /* Handle assignment to signature pointers/refs. */ + + if (TYPE_LANG_SPECIFIC (lhstype) + && (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype))) + { + return build_signature_pointer_constructor (lhs, rhs); + } + + /* Handle control structure constructs used as "lvalues". */ + + switch (TREE_CODE (lhs)) + { + /* Handle --foo = 5; as these are valid constructs in C++ */ + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))) + lhs = build (TREE_CODE (lhs), TREE_TYPE (lhs), + stabilize_reference (TREE_OPERAND (lhs, 0)), + TREE_OPERAND (lhs, 1)); + return build (COMPOUND_EXPR, lhstype, + lhs, + build_modify_expr (TREE_OPERAND (lhs, 0), + modifycode, rhs)); + + /* Handle (a, b) used as an "lvalue". */ + case COMPOUND_EXPR: + newrhs = build_modify_expr (TREE_OPERAND (lhs, 1), + modifycode, rhs); + if (newrhs == error_mark_node) + return error_mark_node; + return build (COMPOUND_EXPR, lhstype, + TREE_OPERAND (lhs, 0), newrhs); + + case MODIFY_EXPR: + newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs); + if (newrhs == error_mark_node) + return error_mark_node; + return build (COMPOUND_EXPR, lhstype, lhs, newrhs); + + /* 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 (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)), + modifycode, rhs), + build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)), + modifycode, rhs)); + if (cond == error_mark_node) + return cond; + /* 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. */ + cp_convert (void_type_node, rhs), cond); + } + + default: + break; + } + + 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 + lhs = resolve_offset_ref (lhs); + + olhstype = lhstype = TREE_TYPE (lhs); + } + + if (TREE_CODE (lhstype) == REFERENCE_TYPE + && modifycode != INIT_EXPR) + { + lhs = convert_from_reference (lhs); + olhstype = lhstype = TREE_TYPE (lhs); + } + + /* 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) + { + if (! IS_AGGR_TYPE (lhstype)) + /* Do the default thing */; + else + { + result = build_method_call (lhs, ctor_identifier, + build_expr_list (NULL_TREE, rhs), + TYPE_BINFO (lhstype), LOOKUP_NORMAL); + if (result == NULL_TREE) + return error_mark_node; + return result; + } + } + else if (modifycode == NOP_EXPR) + { + /* `operator=' is not an inheritable operator. */ + if (! IS_AGGR_TYPE (lhstype)) + /* Do the default thing */; + else + { + result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, + lhs, rhs, make_node (NOP_EXPR)); + if (result == NULL_TREE) + return error_mark_node; + return result; + } + lhstype = olhstype; + } + else if (PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE)) + { + my_friendly_abort (978652); + } + else + { + lhs = stabilize_reference (lhs); + newrhs = build_binary_op (modifycode, lhs, rhs, 1); + if (newrhs == error_mark_node) + { + cp_error (" in evaluation of `%Q(%#T, %#T)'", modifycode, + TREE_TYPE (lhs), TREE_TYPE (rhs)); + return error_mark_node; + } + } + + /* 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 cast type of the lhs, + and then true type of the lhs and store it there; + then convert result back to the cast type to be the value + of the assignment. */ + + 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; + + /* WP 5.4.1: The result is an lvalue if T is a reference type, + otherwise the result is an rvalue. */ + if (! lvalue_p (lhs)) + pedwarn ("ANSI C++ forbids cast to non-reference type used as lvalue"); + + result = build_modify_expr (inner_lhs, NOP_EXPR, + cp_convert (TREE_TYPE (inner_lhs), + cp_convert (lhstype, newrhs))); + if (result == error_mark_node) + return result; + return cp_convert (TREE_TYPE (lhs), result); + } + + default: + break; + } + + /* 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; + + GNU_xref_assign (lhs); + + /* Warn about storing in something that is `const'. */ + /* For C++, don't warn if this is initialization. */ + if (modifycode != INIT_EXPR + /* For assignment to `const' signature pointer/reference fields, + don't warn either, we already printed a better message before. */ + && ! (TREE_CODE (lhs) == COMPONENT_REF + && (IS_SIGNATURE_POINTER (TREE_TYPE (TREE_OPERAND (lhs, 0))) + || IS_SIGNATURE_REFERENCE (TREE_TYPE (TREE_OPERAND (lhs, 0))))) + && (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype) + /* Functions are not modifiable, even though they are + lvalues. */ + || TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE + || ((TREE_CODE (lhstype) == RECORD_TYPE + || TREE_CODE (lhstype) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (lhstype)) + || (TREE_CODE (lhstype) == REFERENCE_TYPE + && CP_TYPE_CONST_P (TREE_TYPE (lhstype))))) + readonly_error (lhs, "assignment", 0); + + /* 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)); + + /* 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; + } + } + + /* check to see if there is an assignment to `this' */ + if (lhs == current_class_ptr) + { + if (flag_this_is_variable > 0 + && DECL_NAME (current_function_decl) != NULL_TREE + && (DECL_NAME (current_function_decl) + != constructor_name (current_class_type))) + warning ("assignment to `this' not in constructor or destructor"); + current_function_just_assigned_this = 1; + } + + 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_SIDE_EFFECTS (lhs)) + lhs = stabilize_reference (lhs); + if (TREE_SIDE_EFFECTS (newrhs)) + newrhs = stabilize_reference (newrhs); + + /* Convert new value to destination type. */ + + if (TREE_CODE (lhstype) == ARRAY_TYPE) + { + int from_array; + + if (!same_or_base_type_p (lhstype, TREE_TYPE (rhs))) + { + cp_error ("incompatible types in assignment of `%T' to `%T'", + TREE_TYPE (rhs), lhstype); + return error_mark_node; + } + + /* Allow array assignment in compiler-generated code. */ + if (pedantic && ! DECL_ARTIFICIAL (current_function_decl)) + pedwarn ("ANSI C++ forbids assignment of arrays"); + + /* 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. */ + + result = make_node (RTL_EXPR); + + TREE_TYPE (result) = void_type_node; + do_pending_stack_adjust (); + start_sequence_for_rtl_expr (result); + + /* As a matter of principle, `start_sequence' should do this. */ + emit_note (0, -1); + + from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE + ? 1 + (modifycode != INIT_EXPR): 0; + expand_vec_init (lhs, lhs, array_type_nelts (lhstype), newrhs, + from_array); + + do_pending_stack_adjust (); + + TREE_SIDE_EFFECTS (result) = 1; + RTL_EXPR_SEQUENCE (result) = get_insns (); + RTL_EXPR_RTL (result) = const0_rtx; + end_sequence (); + return result; + } + + if (modifycode == INIT_EXPR) + { + newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL, + "assignment", NULL_TREE, 0); + if (lhs == DECL_RESULT (current_function_decl)) + { + if (DECL_INITIAL (lhs)) + warning ("return value from function receives multiple initializations"); + DECL_INITIAL (lhs) = newrhs; + } + } + else + { + /* Avoid warnings on enum bit fields. */ + if (TREE_CODE (olhstype) == ENUMERAL_TYPE + && TREE_CODE (lhstype) == INTEGER_TYPE) + { + newrhs = convert_for_assignment (olhstype, newrhs, "assignment", + NULL_TREE, 0); + newrhs = convert_force (lhstype, newrhs, 0); + } + else + newrhs = convert_for_assignment (lhstype, newrhs, "assignment", + NULL_TREE, 0); + if (TREE_CODE (newrhs) == CALL_EXPR + && TYPE_NEEDS_CONSTRUCTING (lhstype)) + newrhs = build_cplus_new (lhstype, newrhs); + + /* Can't initialize directly from a TARGET_EXPR, since that would + cause the lhs to be constructed twice, and possibly result in + accidental self-initialization. So we force the TARGET_EXPR to be + expanded without a target. */ + if (TREE_CODE (newrhs) == TARGET_EXPR) + newrhs = build (COMPOUND_EXPR, TREE_TYPE (newrhs), newrhs, + TREE_OPERAND (newrhs, 0)); + } + + if (newrhs == error_mark_node) + return error_mark_node; + + if (TREE_CODE (newrhs) == COND_EXPR) + { + tree lhs1; + tree cond = TREE_OPERAND (newrhs, 0); + + if (TREE_SIDE_EFFECTS (lhs)) + cond = build_compound_expr (tree_cons + (NULL_TREE, lhs, + build_expr_list (NULL_TREE, cond))); + + /* Cannot have two identical lhs on this one tree (result) as preexpand + calls will rip them out and fill in RTL for them, but when the + rtl is generated, the calls will only be in the first side of the + condition, not on both, or before the conditional jump! (mrs) */ + lhs1 = break_out_calls (lhs); + + if (lhs == lhs1) + /* If there's no change, the COND_EXPR behaves like any other rhs. */ + result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, + lhstype, lhs, newrhs); + else + { + tree result_type = TREE_TYPE (newrhs); + /* We have to convert each arm to the proper type because the + types may have been munged by constant folding. */ + result + = build (COND_EXPR, result_type, cond, + build_modify_expr (lhs, modifycode, + cp_convert (result_type, + TREE_OPERAND (newrhs, 1))), + build_modify_expr (lhs1, modifycode, + cp_convert (result_type, + TREE_OPERAND (newrhs, 2)))); + } + } + else + result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, + lhstype, lhs, newrhs); + + TREE_SIDE_EFFECTS (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; + /* Avoid warnings converting integral types back into enums + for enum bit fields. */ + if (TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE + && TREE_CODE (olhstype) == ENUMERAL_TYPE) + { + result = build (COMPOUND_EXPR, olhstype, result, olhs); + TREE_NO_UNUSED_WARNING (result) = 1; + return result; + } + return convert_for_assignment (olhstype, result, "assignment", + NULL_TREE, 0); +} + +tree +build_x_modify_expr (lhs, modifycode, rhs) + tree lhs; + enum tree_code modifycode; + tree rhs; +{ + if (processing_template_decl) + return build_min_nt (MODOP_EXPR, lhs, + build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs); + + if (modifycode != NOP_EXPR) + { + tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, + make_node (modifycode)); + if (rval) + return rval; + } + return build_modify_expr (lhs, modifycode, rhs); +} + + +/* Get difference in deltas for different pointer to member function + types. Return integer_zero_node, if FROM cannot be converted to a + TO type. If FORCE is true, then allow reverse conversions as well. */ + +static tree +get_delta_difference (from, to, force) + tree from, to; + int force; +{ + tree delta = integer_zero_node; + tree binfo; + + if (to == from) + return delta; + + /* Should get_base_distance here, so we can check if any thing along the + path is virtual, and we need to make sure we stay + inside the real binfos when going through virtual bases. + Maybe we should replace virtual bases with + binfo_member (...CLASSTYPE_VBASECLASSES...)... (mrs) */ + binfo = get_binfo (from, to, 1); + if (binfo == error_mark_node) + { + error (" in pointer to member function conversion"); + return delta; + } + if (binfo == 0) + { + if (!force) + { + error_not_base_type (from, to); + error (" in pointer to member conversion"); + return delta; + } + binfo = get_binfo (to, from, 1); + if (binfo == 0 || binfo == error_mark_node) + return delta; + if (TREE_VIA_VIRTUAL (binfo)) + { + binfo = binfo_member (BINFO_TYPE (binfo), + CLASSTYPE_VBASECLASSES (from)); + cp_warning ("pointer to member cast to virtual base `%T'", + BINFO_TYPE (binfo)); + warning (" will only work if you are very careful"); + } + delta = BINFO_OFFSET (binfo); + delta = cp_convert (ptrdiff_type_node, delta); + + return build_binary_op (MINUS_EXPR, + integer_zero_node, + delta, 1); + } + + if (TREE_VIA_VIRTUAL (binfo)) + { + if (force) + { + cp_warning ("pointer to member cast from virtual base `%T'", + BINFO_TYPE (binfo)); + warning (" will only work if you are very careful"); + } + else + cp_error ("pointer to member conversion from virtual base `%T'", + BINFO_TYPE (binfo)); + } + + return BINFO_OFFSET (binfo); +} + +static tree +build_ptrmemfunc1 (type, delta, idx, pfn, delta2) + tree type, delta, idx, pfn, delta2; +{ + tree u; + +#if 0 + /* This is the old way we did it. We want to avoid calling + digest_init, so that it can give an error if we use { } when + initializing a pointer to member function. */ + + if (pfn) + { + u = build_nt (CONSTRUCTOR, NULL_TREE, + expr_tree_cons (pfn_identifier, pfn, NULL_TREE)); + } + else + { + u = build_nt (CONSTRUCTOR, NULL_TREE, + expr_tree_cons (delta2_identifier, delta2, NULL_TREE)); + } + + u = build_nt (CONSTRUCTOR, NULL_TREE, + expr_tree_cons (NULL_TREE, delta, + expr_tree_cons (NULL_TREE, idx, + expr_tree_cons (NULL_TREE, u, NULL_TREE)))); + + return digest_init (type, u, (tree*)0); +#else + tree delta_field, idx_field, pfn_or_delta2_field, pfn_field, delta2_field; + tree subtype; + int allconstant, allsimple; + + delta_field = TYPE_FIELDS (type); + idx_field = TREE_CHAIN (delta_field); + pfn_or_delta2_field = TREE_CHAIN (idx_field); + subtype = TREE_TYPE (pfn_or_delta2_field); + pfn_field = TYPE_FIELDS (subtype); + delta2_field = TREE_CHAIN (pfn_field); + + if (pfn) + { + allconstant = TREE_CONSTANT (pfn); + allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn)); + u = expr_tree_cons (pfn_field, pfn, NULL_TREE); + } + else + { + delta2 = convert_and_check (delta_type_node, delta2); + allconstant = TREE_CONSTANT (delta2); + allsimple = !! initializer_constant_valid_p (delta2, TREE_TYPE (delta2)); + u = expr_tree_cons (delta2_field, delta2, NULL_TREE); + } + + delta = convert_and_check (delta_type_node, delta); + idx = convert_and_check (delta_type_node, idx); + + allconstant = allconstant && TREE_CONSTANT (delta) && TREE_CONSTANT (idx); + allsimple = allsimple + && initializer_constant_valid_p (delta, TREE_TYPE (delta)) + && initializer_constant_valid_p (idx, TREE_TYPE (idx)); + + u = build (CONSTRUCTOR, subtype, NULL_TREE, u); + u = expr_tree_cons (delta_field, delta, + expr_tree_cons (idx_field, idx, + expr_tree_cons (pfn_or_delta2_field, u, NULL_TREE))); + u = build (CONSTRUCTOR, type, NULL_TREE, u); + TREE_CONSTANT (u) = allconstant; + TREE_STATIC (u) = allconstant && allsimple; + return u; +#endif +} + +/* Build a constructor for a pointer to member function. It can be + used to initialize global variables, local variable, or used + as a value in expressions. TYPE is the POINTER to METHOD_TYPE we + want to be. + + If FORCE is non-zero, then force this conversion, even if + we would rather not do it. Usually set when using an explicit + cast. + + Return error_mark_node, if something goes wrong. */ + +tree +build_ptrmemfunc (type, pfn, force) + tree type, pfn; + int force; +{ + tree idx = integer_zero_node; + tree delta = integer_zero_node; + tree delta2 = integer_zero_node; + tree vfield_offset; + tree npfn = NULL_TREE; + + /* Handle multiple conversions of pointer to member functions. */ + if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn))) + { + tree ndelta, ndelta2; + tree e1, e2, e3, n; + tree pfn_type; + + /* Is is already the right type? */ + if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn))) + return pfn; + + pfn_type = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)); + if (!force + && comp_target_types (type, pfn_type, 1) != 1) + cp_error ("conversion to `%T' from `%T'", type, pfn_type); + + ndelta = cp_convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0)); + ndelta2 = cp_convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn)); + idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0); + + n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (pfn_type)), + TYPE_METHOD_BASETYPE (TREE_TYPE (type)), + force); + + delta = build_binary_op (PLUS_EXPR, ndelta, n, 1); + delta2 = build_binary_op (PLUS_EXPR, ndelta2, n, 1); + e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node)); + + e2 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, + NULL_TREE, delta2); + + pfn = PFN_FROM_PTRMEMFUNC (pfn); + npfn = build1 (NOP_EXPR, type, pfn); + TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn); + + e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, + NULL_TREE); + return build_conditional_expr (e1, e2, e3); + } + + /* Handle null pointer to member function conversions. */ + if (integer_zerop (pfn)) + { + pfn = build_c_cast (type, integer_zero_node); + return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), + integer_zero_node, integer_zero_node, + pfn, NULL_TREE); + } + + if (type_unknown_p (pfn)) + return instantiate_type (type, pfn, 1); + + if (!force + && comp_target_types (type, TREE_TYPE (pfn), 0) != 1) + cp_error ("conversion to `%T' from `%T'", type, TREE_TYPE (pfn)); + + /* Allow pointer to member conversions here. */ + delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))), + TYPE_METHOD_BASETYPE (TREE_TYPE (type)), + force); + delta2 = build_binary_op (PLUS_EXPR, delta2, delta, 1); + + if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL) + warning ("assuming pointer to member function is non-virtual"); + + if (TREE_CODE (TREE_OPERAND (pfn, 0)) == FUNCTION_DECL + && DECL_VINDEX (TREE_OPERAND (pfn, 0))) + { + /* Find the offset to the vfield pointer in the object. */ + vfield_offset = get_binfo (DECL_CONTEXT (TREE_OPERAND (pfn, 0)), + DECL_CLASS_CONTEXT (TREE_OPERAND (pfn, 0)), + 0); + vfield_offset = get_vfield_offset (vfield_offset); + delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2); + + /* Map everything down one to make room for the null pointer to member. */ + idx = size_binop (PLUS_EXPR, + DECL_VINDEX (TREE_OPERAND (pfn, 0)), + integer_one_node); + } + else + { + idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node); + + if (type == TREE_TYPE (pfn)) + { + npfn = pfn; + } + else + { + npfn = build1 (NOP_EXPR, type, pfn); + TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn); + } + } + + return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2); +} + +/* 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, fndecl, parmnum) + tree type, rhs; + char *errtype; + tree fndecl; + int parmnum; +{ + register enum tree_code codel = TREE_CODE (type); + register tree rhstype; + register enum tree_code coder = TREE_CODE (TREE_TYPE (rhs)); + + /* Issue warnings about peculiar, but legal, uses of NULL. */ + if (ARITHMETIC_TYPE_P (type) && rhs == null_node) + cp_warning ("converting NULL to non-pointer type"); + + if (coder == ERROR_MARK) + return error_mark_node; + + if (codel == OFFSET_TYPE) + { + type = TREE_TYPE (type); + codel = TREE_CODE (type); + } + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + if (TREE_CODE (rhs) == NON_LVALUE_EXPR) + rhs = TREE_OPERAND (rhs, 0); + + if (rhs == error_mark_node) + return error_mark_node; + + if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node) + return error_mark_node; + + 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 + || is_overloaded_fn (rhs)) + rhs = default_conversion (rhs); + else if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE) + rhs = convert_from_reference (rhs); + + /* If rhs is some sort of overloaded function, ocp_convert will either + do the right thing or complain; we don't need to check anything else. + So just hand off. */ + if (type_unknown_p (rhs)) + return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL); + + 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 (same_type_p (type, rhstype)) + { + overflow_warning (rhs); + 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 || codel == BOOLEAN_TYPE + || codel == COMPLEX_TYPE) + && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE + || coder == COMPLEX_TYPE)) + { + /* But we should warn if assigning REAL_TYPE to INTEGER_TYPE. */ + if (coder == REAL_TYPE && codel == INTEGER_TYPE) + { + if (fndecl) + cp_warning ("`%T' used for argument %P of `%D'", + rhstype, parmnum, fndecl); + else + cp_warning ("%s to `%T' from `%T'", errtype, type, rhstype); + } + /* And we should warn if assigning a negative value to + an unsigned variable. */ + else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE) + { + if (TREE_CODE (rhs) == INTEGER_CST + && TREE_NEGATED_INT (rhs)) + { + if (fndecl) + cp_warning ("negative value `%E' passed as argument %P of `%D'", + rhs, parmnum, fndecl); + else + cp_warning ("%s of negative value `%E' to `%T'", + errtype, rhs, type); + } + overflow_warning (rhs); + if (TREE_CONSTANT (rhs)) + rhs = fold (rhs); + } + + return convert_and_check (type, rhs); + } + /* Conversions involving enums. */ + else if ((codel == ENUMERAL_TYPE + && (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE)) + || (coder == ENUMERAL_TYPE + && (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE))) + { + return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL); + } + /* Conversions among pointers */ + else if (codel == POINTER_TYPE + && (coder == POINTER_TYPE + || (coder == RECORD_TYPE + && (IS_SIGNATURE_POINTER (rhstype) + || IS_SIGNATURE_REFERENCE (rhstype))))) + { + register tree ttl = TREE_TYPE (type); + register tree ttr; + int ctt = 0; + + if (coder == RECORD_TYPE) + { + rhs = build_optr_ref (rhs); + rhstype = TREE_TYPE (rhs); + } + 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 (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE) + { + tree binfo; + + if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr) + || type == class_star_type_node + || rhstype == class_star_type_node) + binfo = TYPE_BINFO (ttl); + else + binfo = get_binfo (ttl, ttr, 1); + + if (binfo == error_mark_node) + return error_mark_node; + if (binfo == 0) + return error_not_base_type (ttl, ttr); + + if (!at_least_as_qualified_p (ttl, ttr)) + { + if (fndecl) + cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers", + rhstype, parmnum, fndecl); + else + cp_pedwarn ("%s to `%T' from `%T' discards qualifiers", + errtype, type, rhstype); + } + } + + /* 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 + || (ctt = comp_target_types (type, rhstype, 1)) + || (unsigned_type (TYPE_MAIN_VARIANT (ttl)) + == unsigned_type (TYPE_MAIN_VARIANT (ttr)))) + { + /* ARM $4.8, commentary on p39. */ + if (TYPE_MAIN_VARIANT (ttl) == void_type_node + && TREE_CODE (ttr) == OFFSET_TYPE) + { + cp_error ("no standard conversion from `%T' to `void *'", ttr); + return error_mark_node; + } + + if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr)) + cp_pedwarn ("converting `%T' to `%T' is a contravariance violation", + rhstype, type); + + if (TYPE_MAIN_VARIANT (ttl) != void_type_node + && TYPE_MAIN_VARIANT (ttr) == void_type_node + && ! null_ptr_cst_p (rhs)) + { + if (coder == RECORD_TYPE) + cp_pedwarn ("implicit conversion of signature pointer to type `%T'", + type); + else + pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s", + errtype); + } + /* Const and volatile mean something different for function types, + so the usual warnings are not appropriate. */ + else if ((TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttr) != METHOD_TYPE) + || (TREE_CODE (ttl) != FUNCTION_TYPE && TREE_CODE (ttl) != METHOD_TYPE)) + { + if (TREE_CODE (ttl) == OFFSET_TYPE + && binfo_member (TYPE_OFFSET_BASETYPE (ttr), + CLASSTYPE_VBASECLASSES (TYPE_OFFSET_BASETYPE (ttl)))) + { + error ("%s between pointer to members converting across virtual baseclasses", errtype); + return error_mark_node; + } + else if (!at_least_as_qualified_p (ttl, ttr)) + { + if (string_conv_p (type, rhs, 1)) + /* converting from string constant to char *, OK. */; + else if (fndecl) + cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers", + rhstype, parmnum, fndecl); + else + cp_pedwarn ("%s to `%T' from `%T' discards qualifiers", + errtype, type, rhstype); + } + else if (TREE_CODE (ttl) == TREE_CODE (ttr) + && ! comp_target_types (type, rhstype, 1)) + { + if (fndecl) + cp_pedwarn ("passing `%T' as argument %P of `%D' changes signedness", + rhstype, parmnum, fndecl); + else + cp_pedwarn ("%s to `%T' from `%T' changes signedness", + errtype, type, rhstype); + } + } + } + else + { + int add_quals = 0; + int drops_quals = 0; + int left_const = 1; + int unsigned_parity; + int nptrs = 0; + + /* This code is basically a duplicate of comp_ptr_ttypes_real. */ + for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr)) + { + nptrs -= 1; + drops_quals |= !at_least_as_qualified_p (ttl, ttr); + + if (! left_const + && !at_least_as_qualified_p (ttr, ttl)) + add_quals = 1; + left_const &= TYPE_READONLY (ttl); + + if (TREE_CODE (ttl) != POINTER_TYPE + || TREE_CODE (ttr) != POINTER_TYPE) + break; + } + 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) > 0) + { + if (add_quals) + { + if (fndecl) + cp_pedwarn ("passing `%T' as argument %P of `%D' adds cv-quals without intervening `const'", + rhstype, parmnum, fndecl); + else + cp_pedwarn ("%s to `%T' from `%T' adds cv-quals without intervening `const'", + errtype, type, rhstype); + } + if (drops_quals) + { + if (fndecl) + cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers", + rhstype, parmnum, fndecl); + else + cp_pedwarn ("%s to `%T' from `%T' discards qualifiers", + errtype, type, rhstype); + } + if (unsigned_parity > 0) + { + if (fndecl) + cp_pedwarn ("passing `%T' as argument %P of `%D' changes signed to unsigned", + rhstype, parmnum, fndecl); + else + cp_pedwarn ("%s to `%T' from `%T' changes signed to unsigned", + errtype, type, rhstype); + } + else if (unsigned_parity < 0) + { + if (fndecl) + cp_pedwarn ("passing `%T' as argument %P of `%D' changes unsigned to signed", + rhstype, parmnum, fndecl); + else + cp_pedwarn ("%s to `%T' from `%T' changes unsigned to signed", + errtype, type, rhstype); + } + + /* 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 (!same_or_base_type_p (ttl, ttr)) + { + warning ("conflicting function types in %s:", errtype); + cp_warning ("\t`%T' != `%T'", type, rhstype); + } + } + else + { + if (fndecl) + cp_error ("passing `%T' as argument %P of `%D'", + rhstype, parmnum, fndecl); + else + cp_error ("%s to `%T' from `%T'", errtype, type, rhstype); + return error_mark_node; + } + } + return cp_convert (type, rhs); + } + else if (codel == POINTER_TYPE && coder == INTEGER_TYPE) + { + /* An explicit constant 0 can convert to a pointer, + but not a 0 that results from casting or folding. */ + if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))) + { + if (fndecl) + cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast", + rhstype, parmnum, fndecl); + else + cp_pedwarn ("%s to `%T' from `%T' lacks a cast", + errtype, type, rhstype); + } + return cp_convert (type, rhs); + } + else if (codel == INTEGER_TYPE + && (coder == POINTER_TYPE + || (coder == RECORD_TYPE + && (IS_SIGNATURE_POINTER (rhstype) + || TYPE_PTRMEMFUNC_FLAG (rhstype) + || IS_SIGNATURE_REFERENCE (rhstype))))) + { + if (fndecl) + cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast", + rhstype, parmnum, fndecl); + else + cp_pedwarn ("%s to `%T' from `%T' lacks a cast", + errtype, type, rhstype); + return cp_convert (type, rhs); + } + else if (codel == BOOLEAN_TYPE + && (coder == POINTER_TYPE + || (coder == RECORD_TYPE + && (IS_SIGNATURE_POINTER (rhstype) + || TYPE_PTRMEMFUNC_FLAG (rhstype) + || IS_SIGNATURE_REFERENCE (rhstype))))) + return cp_convert (type, rhs); + + /* C++ */ + else if (((coder == POINTER_TYPE + && TREE_CODE (TREE_TYPE (rhstype)) == METHOD_TYPE) + || integer_zerop (rhs) + || TYPE_PTRMEMFUNC_P (rhstype)) + && TYPE_PTRMEMFUNC_P (type)) + { + tree ttl = TYPE_PTRMEMFUNC_FN_TYPE (type); + tree ttr = (TYPE_PTRMEMFUNC_P (rhstype) + ? TYPE_PTRMEMFUNC_FN_TYPE (rhstype) + : rhstype); + int ctt = (TREE_CODE (rhstype) == INTEGER_TYPE ? 1 + : comp_target_types (ttl, ttr, 1)); + + if (ctt < 0) + cp_pedwarn ("converting `%T' to `%T' is a contravariance violation", + ttr, ttl); + else if (ctt == 0) + cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr); + + /* compatible pointer to member functions. */ + return build_ptrmemfunc (ttl, rhs, 0); + } + else if (codel == ERROR_MARK || coder == ERROR_MARK) + return error_mark_node; + + /* This should no longer happen. References are initialized via + `convert_for_initialization'. They should otherwise be + bashed before coming here. */ + else if (codel == REFERENCE_TYPE) + my_friendly_abort (317); + else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (rhs))) + { + tree nrhs = build1 (NOP_EXPR, type, rhs); + TREE_CONSTANT (nrhs) = TREE_CONSTANT (rhs); + return nrhs; + } + else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs))) + return cp_convert (type, rhs); + /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */ + else if (TREE_CODE (type) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE + || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node) + && TREE_TYPE (rhs) + && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs))) + return cp_convert (type, rhs); + + cp_error ("%s to `%T' from `%T'", errtype, type, rhstype); + 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&)). + + If using constructor make sure no conversion operator exists, if one does + exist, an ambiguity exists. + + If flags doesn't include LOOKUP_COMPLAIN, don't complain about anything. */ + +tree +convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum) + tree exp, type, rhs; + int flags; + char *errtype; + tree fndecl; + int parmnum; +{ + 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)) + && codel != REFERENCE_TYPE) + rhs = TREE_OPERAND (rhs, 0); + + if (rhs == error_mark_node + || (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)) + return error_mark_node; + + if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE) + { + rhs = resolve_offset_ref (rhs); + if (rhs == error_mark_node) + return error_mark_node; + } + + if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE) + rhs = convert_from_reference (rhs); + + if ((TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE + && TREE_CODE (type) != ARRAY_TYPE + && (TREE_CODE (type) != REFERENCE_TYPE + || TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE)) + || (TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE + && (TREE_CODE (type) != REFERENCE_TYPE + || TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)) + || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE) + rhs = default_conversion (rhs); + + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + + if (coder == ERROR_MARK) + return error_mark_node; + + /* We accept references to incomplete types, so we can + return here before checking if RHS is of complete type. */ + + if (codel == REFERENCE_TYPE) + { + /* This should eventually happen in convert_arguments. */ + extern int warningcount, errorcount; + int savew = 0, savee = 0; + + if (fndecl) + savew = warningcount, savee = errorcount; + rhs = convert_to_reference (type, rhs, CONV_IMPLICIT, flags, + exp ? exp : error_mark_node); + if (fndecl) + { + if (warningcount > savew) + cp_warning_at ("in passing argument %P of `%+D'", parmnum, fndecl); + else if (errorcount > savee) + cp_error_at ("in passing argument %P of `%+D'", parmnum, fndecl); + } + return rhs; + } + + 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); + + type = complete_type (type); + + if (TYPE_LANG_SPECIFIC (type) + && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))) + return build_signature_pointer_constructor (type, rhs); + + if (IS_AGGR_TYPE (type)) + return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags); + + if (type == TREE_TYPE (rhs)) + { + /* Issue warnings about peculiar, but legal, uses of NULL. We + do this *before* the call to decl_constant_value so as to + avoid duplicate warnings on code like `const int I = NULL; + f(I);'. */ + if (ARITHMETIC_TYPE_P (type) && rhs == null_node) + cp_warning ("converting NULL to non-pointer type"); + + if (TREE_READONLY_DECL_P (rhs)) + rhs = decl_constant_value (rhs); + + return rhs; + } + + return convert_for_assignment (type, rhs, errtype, fndecl, parmnum); +} + +/* 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. + + We don't do default conversions on all inputs, because it can screw + up operands that are expected to be in memory. */ + +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 modified. */ + for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) + o[i] = TREE_VALUE (tail); + + /* 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++) + { + if (o[i] != TREE_VALUE (tail)) + { + expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)), + const0_rtx, VOIDmode, EXPAND_NORMAL); + free_temp_slots (); + } + /* Detect modification of read-only values. + (Otherwise done by build_modify_expr.) */ + else + { + tree type = TREE_TYPE (o[i]); + if (CP_TYPE_CONST_P (type) + || ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (type))) + readonly_error (o[i], "modification by `asm'", 1); + } + } + + /* Those MODIFY_EXPRs could do autoincrements. */ + emit_queue (); +} + +/* 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 nesting *cond_stack, *loop_stack, *case_stack; + extern tree dtor_label, ctor_label; + tree result = DECL_RESULT (current_function_decl); + tree valtype = TREE_TYPE (result); + + if (TREE_THIS_VOLATILE (current_function_decl)) + warning ("function declared `noreturn' has a `return' statement"); + + if (retval == error_mark_node) + { + current_function_returns_null = 1; + return; + } + + if (processing_template_decl) + { + add_tree (build_min_nt (RETURN_STMT, retval)); + return; + } + + if (dtor_label) + { + if (retval) + error ("returning a value from a destructor"); + + /* Can't just return from a destructor. */ + expand_goto (dtor_label); + return; + } + + if (retval == NULL_TREE) + { + /* A non-named return value does not count. */ + + if (DECL_CONSTRUCTOR_P (current_function_decl)) + retval = current_class_ptr; + else if (DECL_NAME (result) != NULL_TREE + && TREE_CODE (valtype) != VOID_TYPE) + retval = result; + else + { + current_function_returns_null = 1; + + if (valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE) + { + if (DECL_NAME (DECL_RESULT (current_function_decl)) == NULL_TREE) + { + pedwarn ("`return' with no value, in function returning non-void"); + /* Clear this, so finish_function won't say that we + reach the end of a non-void function (which we don't, + we gave a return!). */ + current_function_returns_null = 0; + } + } + + expand_null_return (); + return; + } + } + else if (DECL_CONSTRUCTOR_P (current_function_decl)) + { + if (flag_this_is_variable) + error ("return from a constructor: use `this = ...' instead"); + else + error ("returning a value from a constructor"); + retval = current_class_ptr; + } + + /* Effective C++ rule 15. See also start_function. */ + if (warn_ecpp + && DECL_NAME (current_function_decl) == ansi_opname[(int) MODIFY_EXPR] + && retval != current_class_ref) + cp_warning ("`operator=' should return a reference to `*this'"); + + if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE) + { + current_function_returns_null = 1; + if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) + pedwarn ("`return' with a value, in function returning void"); + expand_return (retval); + return; + } + + /* 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. */ + + if (retval == result + || DECL_CONSTRUCTOR_P (current_function_decl)) + /* It's already done for us. */; + else if (TREE_TYPE (retval) == void_type_node) + { + pedwarn ("return of void value in function returning non-void"); + expand_expr_stmt (retval); + retval = 0; + } + else + { + tree functype = TREE_TYPE (TREE_TYPE (current_function_decl)); + + /* First convert the value to the function's return type, then + to the type of return value's location to handle the + case that functype is thiner than the valtype. */ + + retval = convert_for_initialization + (NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING, + "return", NULL_TREE, 0); + + retval = convert (valtype, retval); + + if (retval == error_mark_node) + { + /* Avoid warning about control reaching end of function. */ + expand_null_return (); + return; + } + + /* We can't initialize a register from a AGGR_INIT_EXPR. */ + else if (! current_function_returns_struct + && TREE_CODE (retval) == TARGET_EXPR + && TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR) + retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval, + TREE_OPERAND (retval, 0)); + + /* Add some useful error checking for C++. */ + else if (TREE_CODE (valtype) == REFERENCE_TYPE) + { + tree whats_returned; + + /* Sort through common things to see what it is + we are returning. */ + whats_returned = retval; + if (TREE_CODE (whats_returned) == COMPOUND_EXPR) + { + whats_returned = TREE_OPERAND (whats_returned, 1); + if (TREE_CODE (whats_returned) == ADDR_EXPR) + whats_returned = TREE_OPERAND (whats_returned, 0); + } + while (TREE_CODE (whats_returned) == CONVERT_EXPR + || TREE_CODE (whats_returned) == NOP_EXPR) + whats_returned = TREE_OPERAND (whats_returned, 0); + if (TREE_CODE (whats_returned) == ADDR_EXPR) + { + whats_returned = TREE_OPERAND (whats_returned, 0); + while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR + || TREE_CODE (whats_returned) == TARGET_EXPR) + { + /* Get the target. */ + whats_returned = TREE_OPERAND (whats_returned, 0); + warning ("returning reference to temporary"); + } + } + + if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned)) + { + if (TEMP_NAME_P (DECL_NAME (whats_returned))) + warning ("reference to non-lvalue returned"); + else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE + && DECL_FUNCTION_SCOPE_P (whats_returned) + && !(TREE_STATIC (whats_returned) + || TREE_PUBLIC (whats_returned))) + cp_warning_at ("reference to local variable `%D' returned", whats_returned); + } + } + else if (TREE_CODE (retval) == ADDR_EXPR) + { + tree whats_returned = TREE_OPERAND (retval, 0); + + if (TREE_CODE (whats_returned) == VAR_DECL + && DECL_NAME (whats_returned) + && DECL_FUNCTION_SCOPE_P (whats_returned) + && !(TREE_STATIC (whats_returned) + || TREE_PUBLIC (whats_returned))) + cp_warning_at ("address of local variable `%D' returned", whats_returned); + } + } + + if (retval != NULL_TREE + && TREE_CODE_CLASS (TREE_CODE (retval)) == 'd' + && cond_stack == 0 && loop_stack == 0 && case_stack == 0) + current_function_return_value = retval; + + if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK) + { + /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do. */ + expand_goto (ctor_label); + } + + if (retval && retval != result) + { + result = build (INIT_EXPR, TREE_TYPE (result), result, retval); + TREE_SIDE_EFFECTS (result) = 1; + } + + expand_start_target_temps (); + + expand_return (result); + + expand_end_target_temps (); + + current_function_returns_value = 1; +} + +/* 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, idx; + + exp = build_expr_type_conversion (WANT_INT | WANT_ENUM, exp, 1); + if (exp == NULL_TREE) + { + error ("switch quantity not an integer"); + exp = error_mark_node; + } + if (exp == error_mark_node) + return error_mark_node; + + exp = default_conversion (exp); + type = TREE_TYPE (exp); + idx = 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 (idx))) + exp = idx; + + expand_start_case + (1, fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp)), + type, "switch statement"); + + return exp; +} + +/* Returns non-zero if the pointer-type FROM can be converted to the + pointer-type TO via a qualification conversion. If CONSTP is -1, + then we return non-zero if the pointers are similar, and the + cv-qualification signature of FROM is a proper subset of that of TO. + + If CONSTP is positive, then all outer pointers have been + const-qualified. */ + +static int +comp_ptr_ttypes_real (to, from, constp) + tree to, from; + int constp; +{ + int to_more_cv_qualified = 0; + + for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from)) + { + if (TREE_CODE (to) != TREE_CODE (from)) + return 0; + + if (TREE_CODE (from) == OFFSET_TYPE + && same_type_p (TYPE_OFFSET_BASETYPE (from), + TYPE_OFFSET_BASETYPE (to))) + continue; + + /* Const and volatile mean something different for function types, + so the usual checks are not appropriate. */ + if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE) + { + if (!at_least_as_qualified_p (to, from)) + return 0; + + if (!at_least_as_qualified_p (from, to)) + { + if (constp == 0) + return 0; + else + ++to_more_cv_qualified; + } + + if (constp > 0) + constp &= TYPE_READONLY (to); + } + + if (TREE_CODE (to) != POINTER_TYPE) + return + same_type_p (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from)) + && (constp >= 0 || to_more_cv_qualified); + } +} + +/* When comparing, say, char ** to char const **, this function takes the + 'char *' and 'char const *'. Do not pass non-pointer types to this + function. */ + +int +comp_ptr_ttypes (to, from) + tree to, from; +{ + return comp_ptr_ttypes_real (to, from, 1); +} + +/* Returns 1 if to and from are (possibly multi-level) pointers to the same + type or inheritance-related types, regardless of cv-quals. */ + +int +ptr_reasonably_similar (to, from) + tree to, from; +{ + for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from)) + { + if (TREE_CODE (to) != TREE_CODE (from)) + return 0; + + if (TREE_CODE (from) == OFFSET_TYPE + && comptypes (TYPE_OFFSET_BASETYPE (to), + TYPE_OFFSET_BASETYPE (from), + COMPARE_BASE | COMPARE_RELAXED)) + continue; + + if (TREE_CODE (to) != POINTER_TYPE) + return comptypes + (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), + COMPARE_BASE | COMPARE_RELAXED); + } +} + +/* Like comp_ptr_ttypes, for const_cast. */ + +static int +comp_ptr_ttypes_const (to, from) + tree to, from; +{ + for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from)) + { + if (TREE_CODE (to) != TREE_CODE (from)) + return 0; + + if (TREE_CODE (from) == OFFSET_TYPE + && same_type_p (TYPE_OFFSET_BASETYPE (from), + TYPE_OFFSET_BASETYPE (to))) + continue; + + if (TREE_CODE (to) != POINTER_TYPE) + return same_type_p (TYPE_MAIN_VARIANT (to), + TYPE_MAIN_VARIANT (from)); + } +} + +/* Like comp_ptr_ttypes, for reinterpret_cast. */ + +static int +comp_ptr_ttypes_reinterpret (to, from) + tree to, from; +{ + int constp = 1; + + for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from)) + { + if (TREE_CODE (from) == OFFSET_TYPE) + from = TREE_TYPE (from); + if (TREE_CODE (to) == OFFSET_TYPE) + to = TREE_TYPE (to); + + /* Const and volatile mean something different for function types, + so the usual checks are not appropriate. */ + if (TREE_CODE (from) != FUNCTION_TYPE && TREE_CODE (from) != METHOD_TYPE + && TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE) + { + if (!at_least_as_qualified_p (to, from)) + return 0; + + if (! constp + && !at_least_as_qualified_p (from, to)) + return 0; + constp &= TYPE_READONLY (to); + } + + if (TREE_CODE (from) != POINTER_TYPE + || TREE_CODE (to) != POINTER_TYPE) + return 1; + } +} + +/* Returns the type-qualifier set corresponding to TYPE. */ + +int +cp_type_quals (type) + tree type; +{ + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + + return TYPE_QUALS (type); +} + +/* Returns non-zero if the TYPE contains a mutable member */ + +int +cp_has_mutable_p (type) + tree type; +{ + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + + return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type); +} |