diff options
Diffstat (limited to 'gcc/cp/typeck.c')
-rwxr-xr-x | gcc/cp/typeck.c | 7495 |
1 files changed, 0 insertions, 7495 deletions
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c deleted file mode 100755 index 58c19a4..0000000 --- a/gcc/cp/typeck.c +++ /dev/null @@ -1,7495 +0,0 @@ -/* 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); -} |