X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fcp%2Ftypeck.c;h=97b6fbad8340897dd4e5f16d1e404bdad8a03288;hp=71846dabd82ff77e6eee731e43b4d16c07f63211;hb=c9db32f5526e45b333790bde9f0327c911f9d88d;hpb=3f7d79e4582e972e104146dcdb336a0a79eadbae diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 71846dabd82..97b6fbad834 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1,5 +1,5 @@ /* Build expressions with type checking for C++ compiler. - Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc. + Copyright (C) 1987, 88, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GNU CC. @@ -16,7 +16,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* This file is part of the C++ front end. @@ -39,19 +40,21 @@ extern void warning (); #include "flags.h" #include "output.h" -int mark_addressable (); -static tree convert_for_assignment (); -/* static */ tree convert_for_initialization (); +int mark_addressable PROTO((tree)); +static tree convert_for_assignment PROTO((tree, tree, char*, tree, int)); +/* static */ tree convert_for_initialization PROTO((tree, tree, tree, int, char*, tree, int)); extern tree shorten_compare (); -extern void binary_op_error (); -static tree pointer_int_sum (); -static tree pointer_diff (); +static tree pointer_int_sum PROTO((enum tree_code, register tree, register tree)); +static tree pointer_diff PROTO((register tree, register tree)); +static int comp_target_parms PROTO((tree, tree, int)); +static int comp_ptr_ttypes_const PROTO((tree, tree)); +static int comp_ptr_ttypes_reinterpret PROTO((tree, tree)); +#if 0 static tree convert_sequence (); -/* static */ tree unary_complex_lvalue (); +#endif +/* static */ tree unary_complex_lvalue PROTO((enum tree_code, tree)); static tree get_delta_difference PROTO((tree, tree, int)); -extern rtx original_result_rtx; - /* Return the target type of TYPE, which meas return T for: T*, T&, T[], T (...), and otherwise, just T. */ @@ -77,7 +80,12 @@ tree require_complete_type (value) tree value; { - tree type = TREE_TYPE (value); + tree type; + + if (processing_template_decl) + return value; + + type = TREE_TYPE (value); /* First, detect a valid value with a complete type. */ if (TYPE_SIZE (type) != 0 @@ -91,23 +99,53 @@ require_complete_type (value) not been laid out. Try to avoid an error by interpreting it as this->X::Y, if reasonable. */ if (TREE_CODE (value) == OFFSET_REF - && C_C_D != 0 - && TREE_OPERAND (value, 0) == C_C_D) + && 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_decl); + 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 (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type)) + { + instantiate_class_template (TYPE_MAIN_VARIANT (type)); + if (TYPE_SIZE (type) != 0) + return value; + } + incomplete_type_error (value, type); return error_mark_node; } +tree +complete_type (type) + tree type; +{ + 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 (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type)) + instantiate_class_template (TYPE_MAIN_VARIANT (type)); + + return type; +} + /* Return truthvalue of whether type of EXP is instantiated. */ + int type_unknown_p (exp) tree exp; @@ -119,6 +157,7 @@ type_unknown_p (exp) } /* Return truthvalue of whether T is function (or pfn) type. */ + int fntype_p (t) tree t; @@ -132,6 +171,7 @@ fntype_p (t) /* Do `exp = require_instantiated_type (type, exp);' to make sure EXP does not have an uninstantiated type. TYPE is type to instantiate with, if uninstantiated. */ + tree require_instantiated_type (type, exp, errval) tree type, exp, errval; @@ -216,10 +256,7 @@ commonparms (p1, p2) } else { - int cmp = simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2)); - if (cmp < 0) - my_friendly_abort (111); - if (cmp == 0) + if (1 != simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2))) any_change = 1; TREE_PURPOSE (n) = TREE_PURPOSE (p2); } @@ -286,14 +323,15 @@ common_type (t1, t2) attributes = a2; else { - /* Pick the longest list, and hang on the other - list. */ + /* 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 (!value_member (attributes, a2)) + if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)), + attributes) == NULL_TREE) { a1 = copy_node (a2); TREE_CHAIN (a1) = attributes; @@ -309,6 +347,11 @@ common_type (t1, t2) 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); @@ -397,15 +440,6 @@ common_type (t1, t2) return t1; } -#if 0 - case POINTER_TYPE: - t1 = build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2))); - return build_type_attribute_variant (t1, attributes); - - case REFERENCE_TYPE: - t1 = build_reference_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2))); - return build_type_attribute_variant (t1, attributes); -#endif case ARRAY_TYPE: { @@ -416,7 +450,8 @@ common_type (t1, t2) 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_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2)); + t1 = build_cplus_array_type + (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2)); return build_type_attribute_variant (t1, attributes); } @@ -440,7 +475,7 @@ common_type (t1, t2) { rval = build_function_type (valtype, p2); if ((raises = TYPE_RAISES_EXCEPTIONS (t2))) - rval = build_exception_variant (NULL_TREE, rval, raises); + rval = build_exception_variant (rval, raises); return build_type_attribute_variant (rval, attributes); } raises = TYPE_RAISES_EXCEPTIONS (t1); @@ -448,12 +483,12 @@ common_type (t1, t2) { rval = build_function_type (valtype, p1); if (raises) - rval = build_exception_variant (NULL_TREE, rval, 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 (NULL_TREE, rval, raises); + rval = build_exception_variant (rval, raises); return build_type_attribute_variant (rval, attributes); } @@ -480,7 +515,8 @@ common_type (t1, t2) tree b1 = TYPE_OFFSET_BASETYPE (t1); tree b2 = TYPE_OFFSET_BASETYPE (t2); - if (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)) + if (comptypes (b1, b2, 1) + || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))) basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2))); else { @@ -498,7 +534,7 @@ common_type (t1, t2) 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 (basetype, t3, raises); + t1 = build_exception_variant (t3, raises); } else compiler_error ("common_type called with uncommon method types"); @@ -511,7 +547,8 @@ common_type (t1, t2) tree b1 = TYPE_OFFSET_BASETYPE (t1); tree b2 = TYPE_OFFSET_BASETYPE (t2); - if (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)) + if (comptypes (b1, b2, 1) + || (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); @@ -524,10 +561,10 @@ common_type (t1, t2) } /* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */ + int -compexcepttypes (t1, t2, strict) +compexcepttypes (t1, t2) tree t1, t2; - int strict; { return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2); } @@ -587,6 +624,7 @@ comp_array_types (cmp, t1, t2, strict) pointer to a base classes. These allowances do not commute. In this case, TYPE1 is assumed to be the base class, and TYPE2 is assumed to be the derived class. */ + int comptypes (type1, type2, strict) tree type1, type2; @@ -620,6 +658,11 @@ comptypes (type1, type2, strict) 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)) @@ -652,13 +695,15 @@ comptypes (type1, type2, strict) if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) return 1; -#ifdef COMP_TYPE_ATTRIBUTES + /* ??? 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; -#else - /* 1 if no need for warning yet, 2 if warning cause has been seen. */ - attrval = 1; -#endif /* 1 if no need for warning yet, 2 if warning cause has been seen. */ val = 0; @@ -667,18 +712,40 @@ comptypes (type1, type2, strict) { case RECORD_TYPE: case UNION_TYPE: + if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2) + && CLASSTYPE_TI_TEMPLATE (t1) == CLASSTYPE_TI_TEMPLATE (t2)) + { + int i = TREE_VEC_LENGTH (CLASSTYPE_TI_ARGS (t1)); + tree *p1 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t1), 0); + tree *p2 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t2), 0); + + while (i--) + { + if (TREE_CODE_CLASS (TREE_CODE (p1[i])) == 't') + { + if (! comptypes (p1[i], p2[i], 1)) + return 0; + } + else + { + if (simple_cst_equal (p1[i], p2[i]) <= 0) + return 0; + } + } + return 1; + } if (strict <= 0) goto look_hard; return 0; case OFFSET_TYPE: - val = (comptypes (TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t1)), - TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t2)), strict) - && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)); + 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, strict)) + if (! compexcepttypes (t1, t2)) return 0; /* This case is anti-symmetrical! @@ -686,11 +753,9 @@ comptypes (type1, type2, strict) to something expecting a derived member (or member function), but not vice-versa! */ - val = (comptypes (TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t2)), - TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t1)), strict) - && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict) - && compparms (TREE_CHAIN (TYPE_ARG_TYPES (t1)), - TREE_CHAIN (TYPE_ARG_TYPES (t2)), strict)); + val = (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict) + && compparms (TYPE_ARG_TYPES (t1), + TYPE_ARG_TYPES (t2), strict)); break; case POINTER_TYPE: @@ -708,7 +773,7 @@ comptypes (type1, type2, strict) { int rval; look_hard: - rval = t1 == t2 || UNIQUELY_DERIVED_FROM_P (t1, t2); + rval = t1 == t2 || DERIVED_FROM_P (t1, t2); if (rval) { @@ -717,7 +782,7 @@ comptypes (type1, type2, strict) } if (strict < 0) { - val = UNIQUELY_DERIVED_FROM_P (t2, t1); + val = DERIVED_FROM_P (t2, t1); break; } } @@ -728,7 +793,7 @@ comptypes (type1, type2, strict) break; case FUNCTION_TYPE: - if (! compexcepttypes (t1, t2, strict)) + if (! compexcepttypes (t1, t2)) return 0; val = ((TREE_TYPE (t1) == TREE_TYPE (t2) @@ -742,31 +807,12 @@ comptypes (type1, type2, strict) break; case TEMPLATE_TYPE_PARM: - return 1; + return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2); - case UNINSTANTIATED_P_TYPE: - if (UPT_TEMPLATE (t1) != UPT_TEMPLATE (t2)) + case TYPENAME_TYPE: + if (TYPE_IDENTIFIER (t1) != TYPE_IDENTIFIER (t2)) return 0; - { - int i = TREE_VEC_LENGTH (UPT_PARMS (t1)); - tree *p1 = &TREE_VEC_ELT (UPT_PARMS (t1), 0); - tree *p2 = &TREE_VEC_ELT (UPT_PARMS (t2), 0); - - while (i--) - { - if (TREE_CODE_CLASS (TREE_CODE (p1[i])) == 't') - { - if (! comptypes (p1[i], p2[i], 1)) - return 0; - } - else - { - if (simple_cst_equal (p1[i], p2[i]) <= 0) - return 0; - } - } - } - return 1; + return comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), 1); } return attrval == 2 && val == 1 ? 2 : val; } @@ -810,10 +856,39 @@ comp_target_types (ttl, ttr, nptrs) return -1; else if (TREE_CODE (ttl) == POINTER_TYPE || TREE_CODE (ttl) == ARRAY_TYPE) - return comp_ptr_ttypes (ttl, ttr); + { + if (comp_ptr_ttypes (ttl, ttr)) + return 1; + else if (comp_ptr_ttypes (ttr, ttl)) + return -1; + return 0; + } } - return comp_target_types (ttl, ttr, nptrs - 1); + /* 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); + + /* Make sure that the cv-quals change only in the same direction as + the target type. */ + { + int t; + int c = TYPE_READONLY (ttl) - TYPE_READONLY (ttr); + int v = TYPE_VOLATILE (ttl) - TYPE_VOLATILE (ttr); + + if ((c > 0 && v < 0) || (c < 0 && v > 0)) + return 0; + + if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr)) + return (c + v < 0) ? -1 : 1; + + t = comp_target_types (ttl, ttr, nptrs - 1); + if ((t == 1 && c + v >= 0) || (t == -1 && c + v <= 0)) + return t; + + return 0; + } } if (TREE_CODE (ttr) == REFERENCE_TYPE) @@ -852,9 +927,9 @@ comp_target_types (ttl, ttr, nptrs) { if (nptrs < 0) return 0; - if (comptypes (TYPE_POINTER_TO (ttl), TYPE_POINTER_TO (ttr), 0)) + if (comptypes (build_pointer_type (ttl), build_pointer_type (ttr), 0)) return 1; - if (comptypes (TYPE_POINTER_TO (ttr), TYPE_POINTER_TO (ttl), 0)) + if (comptypes (build_pointer_type (ttr), build_pointer_type (ttl), 0)) return -1; return 0; } @@ -865,11 +940,12 @@ comp_target_types (ttl, ttr, nptrs) /* 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. */ -tree + +static tree common_base_type (tt1, tt2) tree tt1, tt2; { - tree best = NULL_TREE, tmp; + tree best = NULL_TREE; int i; /* If one is a baseclass of another, that's good enough. */ @@ -878,15 +954,6 @@ common_base_type (tt1, tt2) if (UNIQUELY_DERIVED_FROM_P (tt2, tt1)) return tt2; -#if 0 - /* If they share a virtual baseclass, that's good enough. */ - for (tmp = CLASSTYPE_VBASECLASSES (tt1); tmp; tmp = TREE_CHAIN (tmp)) - { - if (binfo_member (BINFO_TYPE (tmp), CLASSTYPE_VBASECLASSES (tt2))) - return BINFO_TYPE (tmp); - } -#endif - /* 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--) @@ -933,6 +1000,7 @@ common_base_type (tt1, tt2) C++: See comment above about TYPE1, TYPE2, STRICT. If STRICT == 3, it means checking is strict, but do not compare default parameter values. */ + int compparms (parms1, parms2, strict) tree parms1, parms2; @@ -971,17 +1039,6 @@ compparms (parms1, parms2, strict) return t2 == void_list_node && TREE_PURPOSE (t1); return TREE_PURPOSE (t1) || TREE_PURPOSE (t2); } -#if 0 - /* Default parms are not part of the type of a function. */ - if (strict != 3 && TREE_PURPOSE (t1) && TREE_PURPOSE (t2)) - { - int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)); - if (cmp < 0) - my_friendly_abort (113); - if (cmp == 0) - return 0; - } -#endif t1 = TREE_CHAIN (t1); t2 = TREE_CHAIN (t2); @@ -990,7 +1047,8 @@ compparms (parms1, parms2, strict) /* This really wants return whether or not parameter type lists would make their owning functions assignment compatible or not. */ -int + +static int comp_target_parms (parms1, parms2, strict) tree parms1, parms2; int strict; @@ -1069,12 +1127,6 @@ comp_target_parms (parms1, parms2, strict) } if (strict != 0) return 0; -#if 0 - /* What good do these cases do? */ - if (strict == 0) - return p2 == void_type_node && TREE_PURPOSE (t1); - return TREE_PURPOSE (t1) || TREE_PURPOSE (t2); -#endif } /* Target types are compatible--just make sure that if we use parameter lists, that they are ok as well. */ @@ -1118,10 +1170,10 @@ self_promoting_args_p (parms) if (TREE_CHAIN (t) == 0 && type != void_type_node) return 0; - if (TYPE_MAIN_VARIANT (type) == float_type_node) + if (type == 0) return 0; - if (type == 0) + if (TYPE_MAIN_VARIANT (type) == float_type_node) return 0; if (C_PROMOTING_INTEGER_TYPE_P (type)) @@ -1149,7 +1201,16 @@ unsigned_type (type) return long_unsigned_type_node; if (type1 == long_long_integer_type_node) return long_long_unsigned_type_node; - return type; + 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. */ @@ -1169,7 +1230,16 @@ signed_type (type) return long_integer_type_node; if (type1 == long_long_unsigned_type_node) return long_long_integer_type_node; - return type; + 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 @@ -1180,8 +1250,10 @@ signed_or_unsigned_type (unsignedp, type) int unsignedp; tree type; { - if (! INTEGRAL_TYPE_P (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)) @@ -1196,6 +1268,8 @@ signed_or_unsigned_type (unsignedp, type) return type; } +/* Compute the value of the `sizeof' operator. */ + tree c_sizeof (type) tree type; @@ -1203,6 +1277,9 @@ c_sizeof (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) @@ -1247,9 +1324,9 @@ c_sizeof (type) return size_int (0); } - if (TYPE_SIZE (type) == 0) + if (TYPE_SIZE (complete_type (type)) == 0) { - error ("`sizeof' applied to an incomplete type"); + cp_error ("`sizeof' applied to incomplete type `%T'", type); return size_int (0); } @@ -1263,6 +1340,36 @@ c_sizeof (type) } tree +expr_sizeof (e) + tree e; +{ + if (processing_template_decl) + return build_min (SIZEOF_EXPR, sizetype, e); + + if (TREE_CODE (e) == COMPONENT_REF + && DECL_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 (TREE_CODE (e) == TREE_LIST) + { + tree t = TREE_VALUE (e); + if (t != NULL_TREE + && ((TREE_TYPE (t) + && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) + || is_overloaded_fn (t))) + pedwarn ("ANSI C++ forbids taking the sizeof a function type"); + } + return c_sizeof (TREE_TYPE (e)); +} + +tree c_sizeof_nowarn (type) tree type; { @@ -1278,14 +1385,7 @@ c_sizeof_nowarn (type) type = TREE_TYPE (type); if (TYPE_SIZE (type) == 0) - { -#if 0 - /* ??? Tiemann, why have any diagnostic here? - There is none in the corresponding function for C. */ - warning ("sizeof applied to an incomplete type"); -#endif - return size_int (0); - } + return size_int (0); /* Convert in case a char is more than one unit. */ t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), @@ -1335,19 +1435,25 @@ c_alignof (type) C++: this will automatically bash references to their target type. */ tree -default_conversion (exp) +decay_conversion (exp) tree exp; { register tree type = TREE_TYPE (exp); register enum tree_code code = TREE_CODE (type); - if (code == OFFSET_TYPE /* || TREE_CODE (exp) == OFFSET_REF */ ) + if (code == OFFSET_TYPE) { if (TREE_CODE (exp) == OFFSET_REF) - return default_conversion (resolve_offset_ref (exp)); + 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) @@ -1361,7 +1467,7 @@ default_conversion (exp) 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) && DECL_MODE (exp) != BLKmode) + else if (TREE_READONLY_DECL_P (exp)) { exp = decl_constant_value (exp); type = TREE_TYPE (exp); @@ -1370,15 +1476,6 @@ default_conversion (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 (INTEGRAL_CODE_P (code)) - { - tree t = type_promotes_to (type); - if (t != type) - return convert (t, exp); - } - if (flag_traditional - && TYPE_MAIN_VARIANT (type) == float_type_node) - return convert (double_type_node, exp); if (code == VOID_TYPE) { error ("void value not ignored as it ought to be"); @@ -1390,12 +1487,7 @@ default_conversion (exp) } if (code == METHOD_TYPE) { - if (TREE_CODE (exp) == OFFSET_REF) - { - my_friendly_assert (TREE_CODE (TREE_OPERAND (exp, 1)) == FUNCTION_DECL, - 308); - return build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0); - } + cp_pedwarn ("assuming & on `%E'", exp); return build_unary_op (ADDR_EXPR, exp, 0); } if (code == ARRAY_TYPE) @@ -1415,14 +1507,14 @@ default_conversion (exp) inner = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (inner))), inner); - TREE_REFERENCE_EXPR (inner) = 1; + TREE_CONSTANT (inner) = TREE_CONSTANT (TREE_OPERAND (inner, 0)); } - return convert (TYPE_POINTER_TO (TREE_TYPE (type)), inner); + return convert (build_pointer_type (TREE_TYPE (type)), inner); } if (TREE_CODE (exp) == COMPOUND_EXPR) { - tree op1 = default_conversion (TREE_OPERAND (exp, 1)); + tree op1 = decay_conversion (TREE_OPERAND (exp, 1)); return build (COMPOUND_EXPR, TREE_TYPE (op1), TREE_OPERAND (exp, 0), op1); } @@ -1468,6 +1560,45 @@ default_conversion (exp) adr = build_unary_op (ADDR_EXPR, exp, 1); return 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 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) + { + tree type = build_type_variant + (TREE_TYPE (exp), TREE_READONLY (exp), TREE_THIS_VOLATILE (exp)); + exp = build1 (ADDR_EXPR, build_pointer_type (type), exp); + } return exp; } @@ -1488,89 +1619,30 @@ build_object_ref (datum, basetype, field) basetype, field, dtype); return error_mark_node; } - else if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (basetype))) + 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_typedef (basetype, 1)) + else if (is_aggr_type (basetype, 1)) { - tree real_basetype = IDENTIFIER_TYPE_VALUE (basetype); - tree binfo = binfo_or_else (real_basetype, TREE_TYPE (datum)); + tree binfo = binfo_or_else (basetype, dtype); if (binfo) - return build_component_ref (build_scoped_ref (datum, basetype), - field, binfo, 1); + 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. - Must compute access for C_C_D. Otherwise, ok. */ + Must compute access for current_class_ref. Otherwise, ok. */ + tree build_component_ref_1 (datum, field, protect) tree datum, field; int protect; { - register tree basetype = TREE_TYPE (datum); - register enum tree_code code = TREE_CODE (basetype); - register tree ref; - - if (code == REFERENCE_TYPE) - { - datum = convert_from_reference (datum); - basetype = TREE_TYPE (datum); - code = TREE_CODE (basetype); - } - - 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'", - field, datum, basetype); - return error_mark_node; - } - - if (TYPE_SIZE (basetype) == 0) - { - incomplete_type_error (0, basetype); - return error_mark_node; - } - - /* Look up component name in the structure type definition. */ - - if (field == error_mark_node) - my_friendly_abort (115); - - if (TREE_STATIC (field)) - return field; - - if (datum == C_C_D) - { - enum access_type access - = compute_access (TYPE_BINFO (current_class_type), field); - - if (access == access_private) - { - cp_error ("field `%D' is private", field); - return error_mark_node; - } - else if (access == access_protected) - { - cp_error ("field `%D' is protected", field); - return error_mark_node; - } - } - - ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field); - - if (TREE_READONLY (datum) || TREE_READONLY (field)) - TREE_READONLY (ref) = 1; - if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field)) - TREE_THIS_VOLATILE (ref) = 1; - if (DECL_MUTABLE_P (field)) - TREE_READONLY (ref) = 0; - - return ref; + return build_component_ref (datum, field, NULL_TREE, protect); } /* Given a COND_EXPR in T, return it in a form that we can, for @@ -1579,6 +1651,7 @@ build_component_ref_1 (datum, field, protect) we're dealing with aggregates. So, we now call this in unary_complex_lvalue, and in build_modify_expr. 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; @@ -1590,17 +1663,62 @@ rationalize_conditional_expr (code, t) 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 = TREE_TYPE (datum); - register enum tree_code code = TREE_CODE (basetype); + register enum tree_code code; register tree field = NULL; register tree ref; - /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it. */ + if (processing_template_decl) + return build_min_nt (COMPONENT_REF, datum, component); + + /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference + inside it. */ switch (TREE_CODE (datum)) { case COMPOUND_EXPR: @@ -1619,31 +1737,28 @@ build_component_ref (datum, component, basetype_path, protect) basetype_path, protect)); } + code = TREE_CODE (basetype); + if (code == REFERENCE_TYPE) { -#if 0 - /* TREE_REFERENCE_EXPRs are not converted by `convert_from_reference'. - @@ Maybe that is not right. */ - if (TREE_REFERENCE_EXPR (datum)) - datum = build1 (INDIRECT_REF, TREE_TYPE (basetype), datum); - else -#endif - datum = convert_from_reference (datum); + datum = convert_from_reference (datum); + basetype = TREE_TYPE (datum); + code = TREE_CODE (basetype); + } + if (TREE_CODE (datum) == OFFSET_REF) + { + datum = resolve_offset_ref (datum); basetype = TREE_TYPE (datum); code = TREE_CODE (basetype); } - /* First, see if there is a field or component with name COMPONENT. */ + /* First, see if there is a field or component with name COMPONENT. */ if (TREE_CODE (component) == TREE_LIST) { my_friendly_assert (!(TREE_CHAIN (component) == NULL_TREE && DECL_CHAIN (TREE_VALUE (component)) == NULL_TREE), 309); return build (COMPONENT_REF, TREE_TYPE (component), datum, component); } -#if 0 - if (TREE_CODE (component) == TYPE_EXPR) - return build_component_type_expr (datum, component, NULL_TREE, protect); -#endif if (! IS_AGGR_TYPE_CODE (code)) { @@ -1653,7 +1768,7 @@ build_component_ref (datum, component, basetype_path, protect) return error_mark_node; } - if (TYPE_SIZE (basetype) == 0) + if (TYPE_SIZE (complete_type (basetype)) == 0) { incomplete_type_error (0, basetype); return error_mark_node; @@ -1672,7 +1787,7 @@ build_component_ref (datum, component, basetype_path, protect) cp_error ("type `%T' has no destructor", basetype); return error_mark_node; } - return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0); + return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1); } /* Look up component name in the structure type definition. */ @@ -1682,12 +1797,20 @@ build_component_ref (datum, component, basetype_path, protect) 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 + || TREE_CODE (component) == TYPE_DECL) + { + field = component; + } 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, component, - protect && ! VFIELD_NAME_P (component), 0); + field = lookup_field (basetype_path, name, + protect && !VFIELD_NAME_P (name), 0); if (field == error_mark_node) return error_mark_node; @@ -1696,7 +1819,7 @@ build_component_ref (datum, component, basetype_path, protect) /* 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, component, 1); + tree fndecls = lookup_fnfields (basetype_path, name, 1); if (fndecls == error_mark_node) return error_mark_node; if (fndecls) @@ -1704,28 +1827,30 @@ build_component_ref (datum, component, basetype_path, protect) if (TREE_CHAIN (fndecls) == NULL_TREE && DECL_CHAIN (TREE_VALUE (fndecls)) == NULL_TREE) { - enum access_type access; - tree fndecl; + tree access, fndecl; /* Unique, so use this one now. */ basetype = TREE_PURPOSE (fndecls); fndecl = TREE_VALUE (fndecls); access = compute_access (TREE_PURPOSE (fndecls), fndecl); - if (access == access_public) + if (access == access_public_node) { if (DECL_VINDEX (fndecl) && ! resolves_to_fixed_type_p (datum, 0)) { tree addr = build_unary_op (ADDR_EXPR, datum, 0); + tree fntype = TREE_TYPE (fndecl); + addr = convert_pointer_to (DECL_CONTEXT (fndecl), addr); datum = build_indirect_ref (addr, NULL_PTR); my_friendly_assert (datum != error_mark_node, 310); fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl)); + TREE_TYPE (fndecl) = build_pointer_type (fntype); } - assemble_external (fndecl); - return fndecl; + mark_used (fndecl); + return build (OFFSET_REF, TREE_TYPE (fndecl), datum, fndecl); } - if (access == access_protected) + if (access == access_protected_node) cp_error ("member function `%D' is protected", fndecl); else cp_error ("member function `%D' is private", fndecl); @@ -1737,9 +1862,6 @@ build_component_ref (datum, component, basetype_path, protect) not matter unless we're actually calling the function. */ tree t; - for (t = TREE_VALUE (fndecls); t; t = DECL_CHAIN (t)) - assemble_external (t); - t = build_tree_list (error_mark_node, fndecls); TREE_TYPE (t) = build_offset_type (basetype, unknown_type_node); @@ -1747,12 +1869,7 @@ build_component_ref (datum, component, basetype_path, protect) } } -#if 0 - if (component == ansi_opname[(int) TYPE_EXPR]) - cp_error ("`%#T' has no such type conversion operator", basetype); - else -#endif - cp_error ("`%#T' has no member named `%D'", basetype, component); + cp_error ("`%#T' has no member named `%D'", basetype, name); return error_mark_node; } else if (TREE_TYPE (field) == error_mark_node) @@ -1765,26 +1882,60 @@ build_component_ref (datum, component, basetype_path, protect) cp_error ("invalid use of type decl `%#D' as expression", field); return error_mark_node; } - if (DECL_RTL (field) != 0) - assemble_external (field); - TREE_USED (field) = 1; + else if (DECL_RTL (field) != 0) + mark_used (field); + else + TREE_USED (field) = 1; return field; } } - if (DECL_FIELD_CONTEXT (field) != basetype - && TYPE_USES_COMPLEX_INHERITANCE (basetype)) + /* 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 addr = build_unary_op (ADDR_EXPR, datum, 0); - if (integer_zerop (addr)) + tree context = DECL_FIELD_CONTEXT (field); + tree base = context; + while (base != basetype && TYPE_NAME (base) + && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base))) { - error ("invalid reference to NULL ptr, use ptr-to-member instead"); - return error_mark_node; + base = TYPE_CONTEXT (base); } - addr = convert_pointer_to (DECL_FIELD_CONTEXT (field), addr); - datum = build_indirect_ref (addr, NULL_PTR); - my_friendly_assert (datum != error_mark_node, 311); - } + + /* 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_AGGRNAME_P (TYPE_IDENTIFIER (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); + } + } + ref = fold (build (COMPONENT_REF, TREE_TYPE (field), break_out_cleanups (datum), field)); @@ -1797,6 +1948,22 @@ build_component_ref (datum, component, basetype_path, protect) 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. @@ -1810,7 +1977,12 @@ build_x_indirect_ref (ptr, errorstring) tree ptr; char *errorstring; { - tree rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE); + 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); @@ -1821,24 +1993,38 @@ build_indirect_ref (ptr, errorstring) tree ptr; char *errorstring; { - register tree pointer = default_conversion (ptr); - register tree type = TREE_TYPE (pointer); + 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_decl) - return C_C_D; + if (ptr == current_class_ptr) + return current_class_ref; - ptr = build_expr_type_conversion (WANT_POINTER, pointer, 1); - if (ptr) + if (IS_AGGR_TYPE (type)) { - pointer = ptr; - type = TREE_TYPE (pointer); + ptr = build_expr_type_conversion (WANT_POINTER, pointer, 1); + + if (ptr) + { + pointer = ptr; + type = TREE_TYPE (pointer); + } } if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE) { if (TREE_CODE (pointer) == ADDR_EXPR - && (TREE_TYPE (TREE_OPERAND (pointer, 0)) - == TREE_TYPE (type))) + && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (pointer, 0))) + == TYPE_MAIN_VARIANT (TREE_TYPE (type))) + && (TREE_READONLY (TREE_OPERAND (pointer, 0)) + == TYPE_READONLY (TREE_TYPE (type))) + && (TREE_THIS_VOLATILE (TREE_OPERAND (pointer, 0)) + == TYPE_VOLATILE (TREE_TYPE (type)))) return TREE_OPERAND (pointer, 0); else { @@ -1884,21 +2070,9 @@ build_indirect_ref (ptr, errorstring) will inherit the type of the array, which will be some pointer type. */ tree -build_x_array_ref (array, index) - tree array, index; -{ - tree rval = build_opfncall (ARRAY_REF, LOOKUP_NORMAL, array, index, NULL_TREE); - if (rval) - return rval; - return build_array_ref (array, index); -} - -tree build_array_ref (array, idx) tree array, idx; { - tree itype; - if (idx == 0) { error ("subscript missing in array reference"); @@ -1909,8 +2083,6 @@ build_array_ref (array, idx) || TREE_TYPE (idx) == error_mark_node) return error_mark_node; - itype = TREE_TYPE (idx); - if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE && TREE_CODE (array) != INDIRECT_REF) { @@ -2026,8 +2198,9 @@ build_array_ref (array, idx) /* Build a function call to function FUNCTION with parameters PARAMS. PARAMS is a list--a chain of TREE_LIST nodes--in which the - TREE_VALUE of each node is a parameter-expression. - FUNCTION's data type may be a function type or a pointer-to-function. + 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 @@ -2042,12 +2215,11 @@ build_array_ref (array, idx) In the second case, TREE_PURPOSE (function) is the function's name directly. - DECL is the class instance variable, usually CURRENT_CLASS_DECL. */ + DECL is the class instance variable, usually CURRENT_CLASS_REF. + + When calling a TEMPLATE_DECL, we don't require a complete return + type. */ -/* - * [eichin:19911015.1726EST] actually return a possibly incomplete - * type - */ tree build_x_function_call (function, params, decl) tree function, params, decl; @@ -2058,7 +2230,27 @@ build_x_function_call (function, params, decl) if (function == error_mark_node) return error_mark_node; + if (processing_template_decl) + return build_min_nt (CALL_EXPR, function, params, NULL_TREE); + 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); + 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) @@ -2066,11 +2258,20 @@ build_x_function_call (function, params, decl) || TREE_CODE (type) == METHOD_TYPE || TYPE_PTRMEMFUNC_P (type)); + if (TREE_CODE (function) == FUNCTION_DECL + && DECL_STATIC_FUNCTION_P (function)) + return build_member_call + (DECL_CONTEXT (function), DECL_NAME (function), params); + /* Handle methods, friends, and overloaded functions, respectively. */ if (is_method) { + tree basetype = NULL_TREE; + if (TREE_CODE (function) == FUNCTION_DECL) { + basetype = DECL_CLASS_CONTEXT (function); + if (DECL_NAME (function)) function = DECL_NAME (function); else @@ -2078,15 +2279,9 @@ build_x_function_call (function, params, decl) } else if (TREE_CODE (function) == TREE_LIST) { -#if 0 - if (TREE_CODE (TREE_VALUE (function)) == TREE_LIST) - function = TREE_PURPOSE (TREE_VALUE (function)); - else - function = TREE_PURPOSE (function); -#else my_friendly_assert (TREE_CODE (TREE_VALUE (function)) == FUNCTION_DECL, 312); + basetype = DECL_CLASS_CONTEXT (TREE_VALUE (function)); function = TREE_PURPOSE (function); -#endif } else if (TREE_CODE (function) != IDENTIFIER_NODE) { @@ -2113,6 +2308,10 @@ build_x_function_call (function, params, decl) 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) @@ -2122,7 +2321,7 @@ build_x_function_call (function, params, decl) return error_mark_node; } /* Yow: call from a static member function. */ - decl = build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type), + decl = build1 (NOP_EXPR, build_pointer_type (current_class_type), error_mark_node); decl = build_indirect_ref (decl, NULL_PTR); } @@ -2135,7 +2334,7 @@ build_x_function_call (function, params, decl) { /* Should we undo what was done in build_component_ref? */ if (TREE_CODE (TREE_PURPOSE (TREE_OPERAND (function, 1))) == TREE_VEC) - /* Get the name that build_component_ref hid. */ + /* Get the name that build_component_ref hid. */ function = DECL_NAME (TREE_VALUE (TREE_OPERAND (function, 1))); else function = TREE_PURPOSE (TREE_OPERAND (function, 1)); @@ -2154,12 +2353,15 @@ build_x_function_call (function, params, decl) { tree val = TREE_VALUE (function); + if (flag_ansi_overloading) + return build_new_function_call (function, params, NULL_TREE); + if (TREE_CODE (val) == TEMPLATE_DECL) - return build_overload_call_maybe - (function, params, LOOKUP_COMPLAIN, (struct candidate *)0); + return build_overload_call_real + (function, params, LOOKUP_COMPLAIN, (struct candidate *)0, 0); else if (DECL_CHAIN (val) != NULL_TREE) return build_overload_call - (function, params, LOOKUP_COMPLAIN, (struct candidate *)0); + (function, params, LOOKUP_COMPLAIN); else my_friendly_abort (360); } @@ -2175,7 +2377,7 @@ build_x_function_call (function, params, decl) if (TREE_OPERAND (function, 0)) decl = TREE_OPERAND (function, 0); else - decl = C_C_D; + decl = current_class_ref; decl_addr = build_unary_op (ADDR_EXPR, decl, 0); function = get_member_function_from_ptrfunc (&decl_addr, @@ -2190,7 +2392,7 @@ build_x_function_call (function, params, decl) if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); - if (TYPE_LANG_SPECIFIC (type) && TYPE_OVERLOADS_CALL_EXPR (type)) + if (IS_AGGR_TYPE (type)) return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE); } @@ -2201,14 +2403,14 @@ build_x_function_call (function, params, decl) /* Explicitly named method? */ if (TREE_CODE (function) == FUNCTION_DECL) - ctypeptr = TYPE_POINTER_TO (DECL_CLASS_CONTEXT (function)); + 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 = TYPE_POINTER_TO (rec); + ctypeptr = build_pointer_type (rec); } /* Unexpected node type? */ else @@ -2229,7 +2431,7 @@ build_x_function_call (function, params, decl) decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl); } else - decl = build_c_cast (ctypeptr, decl, 0); + decl = build_c_cast (ctypeptr, decl); params = tree_cons (NULL_TREE, decl, params); } @@ -2251,30 +2453,32 @@ get_member_function_from_ptrfunc (instance_ptrptr, function) if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function))) { - tree fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function)); - tree index = save_expr (build_component_ref (function, - index_identifier, - 0, 0)); - tree e1 = build (GT_EXPR, boolean_type_node, index, - convert (delta_type_node, integer_zero_node)); - tree delta = convert (ptrdiff_type_node, - build_component_ref (function, delta_identifier, 0, 0)); - tree delta2 = DELTA2_FROM_PTRMEMFUNC (function); - tree e2; - tree e3; - tree aref, vtbl; - + tree fntype, idx, e1, delta, delta2, e2, e3, aref, vtbl; tree instance; + tree instance_ptr = *instance_ptrptr; if (TREE_SIDE_EFFECTS (instance_ptr)) instance_ptr = save_expr (instance_ptr); - /* convert down to the right base, before using the instance. */ + if (TREE_SIDE_EFFECTS (function)) + function = save_expr (function); + + fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function)); + idx = save_expr (build_component_ref (function, + index_identifier, + NULL_TREE, 0)); + e1 = fold (build (GT_EXPR, boolean_type_node, idx, + convert (delta_type_node, integer_zero_node))); + delta = convert (ptrdiff_type_node, + build_component_ref (function, delta_identifier, NULL_TREE, 0)); + delta2 = DELTA2_FROM_PTRMEMFUNC (function); + + /* convert down to the right base, before using the instance. */ instance = convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)), instance_ptr); - if (instance == error_mark_node) + if (instance == error_mark_node && instance_ptr != error_mark_node) return instance; vtbl = convert_pointer_to (ptr_type_node, instance); @@ -2284,19 +2488,14 @@ get_member_function_from_ptrfunc (instance_ptrptr, function) vtbl, convert (ptrdiff_type_node, delta2)); vtbl = build_indirect_ref (vtbl, NULL_PTR); aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR, - index, + idx, integer_one_node, 1)); if (! flag_vtable_thunks) { aref = save_expr (aref); - /* Save the intermediate result in a SAVE_EXPR so we don't have to - compute each component of the virtual function pointer twice. */ - if (/* !building_cleanup && */ TREE_CODE (aref) == INDIRECT_REF) - TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0)); - delta = build_binary_op (PLUS_EXPR, - build_conditional_expr (e1, build_component_ref (aref, delta_identifier, 0, 0), integer_zero_node), + build_conditional_expr (e1, build_component_ref (aref, delta_identifier, NULL_TREE, 0), integer_zero_node), delta, 1); } @@ -2305,11 +2504,18 @@ get_member_function_from_ptrfunc (instance_ptrptr, function) if (flag_vtable_thunks) e2 = aref; else - e2 = build_component_ref (aref, pfn_identifier, 0, 0); + e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0); e3 = PFN_FROM_PTRMEMFUNC (function); TREE_TYPE (e2) = TREE_TYPE (e3); - function = build_conditional_expr (e1, e2, e3); + e1 = build_conditional_expr (e1, e2, e3); + + 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; /* Make sure this doesn't get evaluated first inside one of the branches of the COND_EXPR. */ @@ -2345,7 +2551,7 @@ build_function_call_real (function, params, require_complete, flags) GNU_xref_call (current_function_decl, IDENTIFIER_POINTER (name ? name : TYPE_IDENTIFIER (DECL_CLASS_CONTEXT (function)))); - assemble_external (function); + mark_used (function); fndecl = function; /* Convert anything with function type to a pointer-to-function. */ @@ -2358,41 +2564,38 @@ build_function_call_real (function, params, require_complete, flags) pedwarn ("ANSI C++ forbids calling `main' from within program"); } + if (pedantic && DECL_THIS_INLINE (function) && ! DECL_INITIAL (function) + && ! DECL_ARTIFICIAL (function) + && ! DECL_PENDING_INLINE_INFO (function)) + cp_pedwarn ("inline function `%#D' called before definition", + function); + /* 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)) - { - fntype = build_type_variant (TREE_TYPE (function), - TREE_READONLY (function), - TREE_THIS_VOLATILE (function)); - function = build1 (ADDR_EXPR, build_pointer_type (fntype), function); - } + function = inline_conversion (function); else - { - assemble_external (function); - TREE_USED (function) = 1; - function = default_conversion (function); - } + function = build_addr_func (function); } else { fndecl = NULL_TREE; - /* Convert anything with function type to a pointer-to-function. */ - if (function == error_mark_node) - return error_mark_node; - function = default_conversion (function); + function = build_addr_func (function); } + if (function == error_mark_node) + return error_mark_node; + fntype = TREE_TYPE (function); if (TYPE_PTRMEMFUNC_P (fntype)) { - tree instance_ptr = build_unary_op (ADDR_EXPR, C_C_D, 0); - fntype = TYPE_PTRMEMFUNC_FN_TYPE (fntype); - function = get_member_function_from_ptrfunc (&instance_ptr, function); + 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 @@ -2402,7 +2605,7 @@ build_function_call_real (function, params, require_complete, flags) && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE) || is_method)) { - error ("called object is not a function"); + cp_error ("`%E' cannot be used as a function", function); return error_mark_node; } @@ -2419,6 +2622,12 @@ build_function_call_real (function, params, require_complete, flags) coerced_params = convert_arguments (NULL_TREE, 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)) @@ -2444,17 +2653,17 @@ build_function_call_real (function, params, require_complete, flags) /* C++ */ value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node; { - register tree result = - build (CALL_EXPR, value_type, - function, coerced_params, NULL_TREE); + register tree result + = build_call (function, value_type, coerced_params); - TREE_SIDE_EFFECTS (result) = 1; - - if (! require_complete) - return convert_from_reference (result); - if (value_type == void_type_node) - return result; - result = require_complete_type (result); + 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); } } @@ -2465,14 +2674,6 @@ build_function_call (function, params) { return build_function_call_real (function, params, 1, LOOKUP_NORMAL); } - -tree -build_function_call_maybe (function, params) - tree function, params; -{ - return build_function_call_real (function, params, 0, 0); -} - /* Convert the actual parameter expressions in the list VALUES to the types in the list TYPELIST. @@ -2502,7 +2703,6 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) tree return_loc, typelist, values, fndecl; int flags; { - extern tree gc_protect_fndecl; register tree typetail, valtail; register tree result = NULL_TREE; char *called_thing; @@ -2511,6 +2711,9 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) if (! flag_elide_constructors) return_loc = 0; + /* Argument passing is always copy-initialization. */ + flags |= LOOKUP_ONLYCONVERTING; + if (fndecl) { if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE) @@ -2533,15 +2736,14 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) register tree val = TREE_VALUE (valtail); if (val == error_mark_node) - continue; + return error_mark_node; if (type == void_type_node) { if (fndecl) { - char *buf = (char *)alloca (40 + strlen (called_thing)); - sprintf (buf, "too many arguments to %s `%%s'", called_thing); - error_with_decl (fndecl, buf); + cp_error_at ("too many arguments to %s `%+D'", called_thing, + fndecl); error ("at this point in file"); } else @@ -2580,28 +2782,12 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) else if (TREE_CODE (val) == OFFSET_REF && TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE) { - /* This is unclean. Should be handled elsewhere. */ + /* This is unclean. Should be handled elsewhere. */ val = build_unary_op (ADDR_EXPR, val, 0); } else if (TREE_CODE (val) == OFFSET_REF) val = resolve_offset_ref (val); - { -#if 0 - /* This code forces the assumption that if we have a ptr-to-func - type in an arglist, that every routine that wants to check - its validity has done so, and thus we need not do any - more conversion. I don't remember why this is necessary. */ - else if (TREE_CODE (ttype) == FUNCTION_TYPE - && (type == NULL - || TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE - || TREE_CODE (TREE_TYPE (type)) == VOID_TYPE)) - { - type = build_pointer_type (ttype); - } -#endif - } - /* 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 @@ -2620,32 +2806,23 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) } if (val == error_mark_node) - continue; + return error_mark_node; if (type != 0) { /* Formal parm type is specified by a function prototype. */ tree parmval; - if (TYPE_SIZE (type) == 0) + if (TYPE_SIZE (complete_type (type)) == 0) { error ("parameter type of called function is incomplete"); parmval = val; } else { -#if 0 && defined (PROMOTE_PROTOTYPES) - /* This breaks user-defined conversions. */ - /* Rather than truncating and then reextending, - convert directly to int, if that's the type we will want. */ - if (! flag_traditional - && (TREE_CODE (type) == INTEGER_TYPE - || TREE_CODE (type) == ENUMERAL_TYPE) - && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) - type = integer_type_node; -#endif - parmval = convert_for_initialization (return_loc, type, val, flags, - "argument passing", fndecl, i); + parmval = convert_for_initialization + (return_loc, type, val, flags, + "argument passing", fndecl, i); #ifdef PROMOTE_PROTOTYPES if ((TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == ENUMERAL_TYPE) @@ -2653,6 +2830,10 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) parmval = default_conversion (parmval); #endif } + + if (parmval == error_mark_node) + return error_mark_node; + result = tree_cons (NULL_TREE, parmval, result); } else @@ -2677,17 +2858,6 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) result = tree_cons (NULL_TREE, default_conversion (val), result); } - if (flag_gc - /* There are certain functions for which we don't need - to protect our arguments. GC_PROTECT_FNDECL is one. */ - && fndecl != gc_protect_fndecl - && type_needs_gc_entry (TREE_TYPE (TREE_VALUE (result))) - && ! value_safe_from_gc (NULL_TREE, TREE_VALUE (result))) - /* This will build a temporary variable whose cleanup is - to clear the obstack entry. */ - TREE_VALUE (result) = protect_value_from_gc (NULL_TREE, - TREE_VALUE (result)); - if (typetail) typetail = TREE_CHAIN (typetail); } @@ -2700,7 +2870,7 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) for (; typetail != void_list_node; ++i) { tree type = TREE_VALUE (typetail); - tree val = TREE_PURPOSE (typetail); + tree val = break_out_target_exprs (TREE_PURPOSE (typetail)); tree parmval; if (val == NULL_TREE) @@ -2727,10 +2897,8 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) #endif } - if (flag_gc - && type_needs_gc_entry (TREE_TYPE (parmval)) - && ! value_safe_from_gc (NULL_TREE, parmval)) - parmval = protect_value_from_gc (NULL_TREE, parmval); + if (parmval == error_mark_node) + return error_mark_node; result = tree_cons (0, parmval, result); typetail = TREE_CHAIN (typetail); @@ -2765,8 +2933,16 @@ build_x_binary_op (code, arg1, arg2) enum tree_code code; tree arg1, arg2; { - tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY, - arg1, arg2, NULL_TREE); + tree rval; + + if (processing_template_decl) + return build_min_nt (code, arg1, arg2); + + if (flag_ansi_overloading) + return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE); + + rval = build_opfncall (code, LOOKUP_SPECULATIVELY, + arg1, arg2, NULL_TREE); if (rval) return build_opfncall (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE); if (code == MEMBER_REF) @@ -2788,10 +2964,9 @@ build_binary_op (code, arg1, arg2, convert_p) if (convert_p) { - tree args_save [2]; tree type0, type1; - args[0] = args_save [0] = default_conversion (args[0]); - args[1] = args_save [1] = default_conversion (args[1]); + args[0] = decay_conversion (args[0]); + args[1] = decay_conversion (args[1]); if (args[0] == error_mark_node || args[1] == error_mark_node) return error_mark_node; @@ -2802,13 +2977,13 @@ build_binary_op (code, arg1, arg2, convert_p) if (type_unknown_p (args[0])) { args[0] = instantiate_type (type1, args[0], 1); - args[0] = default_conversion (args[0]); + args[0] = decay_conversion (args[0]); } else if (type_unknown_p (args[1])) { args[1] = require_instantiated_type (type0, args[1], error_mark_node); - args[1] = default_conversion (args[1]); + args[1] = decay_conversion (args[1]); } if (IS_AGGR_TYPE (type0) || IS_AGGR_TYPE (type1)) @@ -2821,11 +2996,6 @@ build_binary_op (code, arg1, arg2, convert_p) return error_mark_node; } } - - if (args[0] == args_save[0]) - args[0] = arg1; - if (args[1] == args_save[1]) - args[1] = arg2; } return build_binary_op_nodefault (code, args[0], args[1], code); } @@ -2904,8 +3074,18 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) int common = 0; /* Apply default conversions. */ - op0 = default_conversion (orig_op0); - op1 = default_conversion (orig_op1); + 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); @@ -2971,7 +3151,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) resultcode = RDIV_EXPR; else /* When dividing two signed integers, we have to promote to int. - unless we divide by a conatant != -1. Note that default + 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. */ @@ -3173,14 +3353,14 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1)) { - op0 = build_component_ref (op0, index_identifier, 0, 0); + 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, 0, 0); + op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0); op1 = integer_zero_node; result_type = TREE_TYPE (op0); } @@ -3194,8 +3374,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) && ((op1.index != -1 && op0.delta2 == op1.delta2) || op0.pfn == op1.pfn)) */ - tree index0 = build_component_ref (op0, index_identifier, 0, 0); - tree index1 = save_expr (build_component_ref (op1, index_identifier, 0, 0)); + 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); @@ -3216,7 +3396,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_FN_TYPE (type0) == type1) { - tree index0 = build_component_ref (op0, index_identifier, 0, 0); + 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); @@ -3306,18 +3486,12 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) { result_type = type0; - if (pedantic) - pedwarn ("ANSI C++ forbids comparison between pointer and integer"); - else if (! flag_traditional) - warning ("comparison between pointer and integer"); + pedwarn ("ANSI C++ forbids comparison between pointer and integer"); } else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) { result_type = type1; - if (pedantic) - pedwarn ("ANSI C++ forbids comparison between pointer and integer"); - else if (! flag_traditional) - warning ("comparison between pointer and integer"); + pedwarn ("ANSI C++ forbids comparison between pointer and integer"); } break; } @@ -3425,7 +3599,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) it never happens because available widths are 2**N. */ && (!TREE_UNSIGNED (final_type) || unsigned_arg - || ((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0)) + || (((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0))) <= TYPE_PRECISION (result_type)))) { /* Do an unsigned shift if the operand was zero-extended. */ @@ -3459,7 +3633,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) resultcode = xresultcode; } - if (short_compare && extra_warnings) + if (short_compare && warn_sign_compare) { int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0)); int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1)); @@ -3468,6 +3642,17 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) tree primop0 = get_narrower (op0, &unsignedp0); tree primop1 = get_narrower (op1, &unsignedp1); + /* Check for comparison of different enum types. */ + if (flag_int_enum_equivalence == 0 + && 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 @@ -3509,8 +3694,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code) 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) + ^ (TREE_CODE (primop1) == BIT_NOT_EXPR)) { if (TREE_CODE (primop0) == BIT_NOT_EXPR) primop0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0); @@ -3631,12 +3816,12 @@ pointer_int_sum (resultcode, ptrop, intop) } else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE) { - if (pedantic) + 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 (TREE_TYPE (result_type)); + size_exp = size_in_bytes (complete_type (TREE_TYPE (result_type))); /* Needed to make OOPS V2R3 work. */ intop = folded; @@ -3662,11 +3847,11 @@ pointer_int_sum (resultcode, ptrop, intop) intop = TREE_OPERAND (intop, 0); } - /* Convert the integer argument to a type the same size as a pointer + /* 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)) != POINTER_SIZE) - intop = convert (type_for_size (POINTER_SIZE, 0), intop); + if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)) + intop = 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 @@ -3697,7 +3882,7 @@ pointer_diff (op0, op1) tree restype = ptrdiff_type_node; tree target_type = TREE_TYPE (TREE_TYPE (op0)); - if (pedantic) + if (pedantic || warn_pointer_arith) { if (TREE_CODE (target_type) == VOID_TYPE) pedwarn ("ANSI C++ forbids using pointer of type `void *' in subtraction"); @@ -3759,9 +3944,6 @@ build_component_addr (arg, argtype, msg) return error_mark_node; } - if (flag_gc) - cp_warning ("address of `%T::%D' taken", basetype, field); - if (TREE_CODE (field) == FIELD_DECL && TYPE_USES_COMPLEX_INHERITANCE (basetype)) { @@ -3797,8 +3979,11 @@ 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. */ + error message. */ if (code == ADDR_EXPR && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg))) && TYPE_SIZE (TREE_TYPE (xarg)) == NULL_TREE) @@ -3806,12 +3991,31 @@ build_x_unary_op (code, xarg) /* don't look for a function */; else { - tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg, - NULL_TREE, NULL_TREE); - if (rval) - return build_opfncall (code, LOOKUP_NORMAL, xarg, + tree rval; + + if (flag_ansi_overloading) + { + rval = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE); + if (rval || code != ADDR_EXPR) + return rval; + } + else + { + rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg, + NULL_TREE, NULL_TREE); + if (rval) + return build_opfncall (code, LOOKUP_NORMAL, xarg, + NULL_TREE, NULL_TREE); + } + } + + if (code == ADDR_EXPR) + { + if (TREE_CODE (xarg) == TARGET_EXPR) + warning ("taking address of temporary"); } + return build_unary_op (code, xarg, 0); } @@ -3821,7 +4025,10 @@ tree condition_conversion (expr) tree expr; { - tree t = convert (boolean_type_node, expr); + tree t; + if (processing_template_decl) + return expr; + t = convert (boolean_type_node, expr); t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t)); return t; } @@ -3834,6 +4041,7 @@ condition_conversion (expr) NOCONVERT nonzero suppresses the default promotions (such as from short to int). */ + tree build_unary_op (code, xarg, noconvert) enum tree_code code; @@ -3952,7 +4160,7 @@ build_unary_op (code, xarg, noconvert) if (TREE_CODE (argtype) == POINTER_TYPE) { enum tree_code tmp = TREE_CODE (TREE_TYPE (argtype)); - if (TYPE_SIZE (TREE_TYPE (argtype)) == 0) + 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) @@ -3982,7 +4190,7 @@ build_unary_op (code, xarg, noconvert) case FIX_ROUND_EXPR: case FIX_CEIL_EXPR: { - tree incremented, modify, value; + tree incremented, modify, value, compound; if (! lvalue_p (arg) && pedantic) pedwarn ("cast to non-reference type used as lvalue"); arg = stabilize_reference (arg); @@ -3995,8 +4203,13 @@ build_unary_op (code, xarg, noconvert) ? PLUS_EXPR : MINUS_EXPR), argtype, value, inc); TREE_SIDE_EFFECTS (incremented) = 1; + modify = build_modify_expr (arg, NOP_EXPR, incremented); - return build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value); + compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value); + + /* Eliminate warning about unused result of + or -. */ + TREE_NO_UNUSED_WARNING (compound) = 1; + return compound; } } @@ -4048,8 +4261,10 @@ build_unary_op (code, xarg, noconvert) argtype = TREE_TYPE (arg); if (TREE_CODE (argtype) == REFERENCE_TYPE) { - arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg); - TREE_REFERENCE_EXPR (arg) = 1; + arg = build1 + (CONVERT_EXPR, + build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg); + TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0)); return arg; } else if (pedantic @@ -4065,21 +4280,17 @@ build_unary_op (code, xarg, noconvert) /* Let &* cancel out to simplify resulting code. */ if (TREE_CODE (arg) == INDIRECT_REF) { - /* We don't need to have `current_class_decl' wrapped in a + /* We don't need to have `current_class_ptr' wrapped in a NON_LVALUE_EXPR node. */ - if (arg == C_C_D) - return current_class_decl; + if (arg == current_class_ref) + return current_class_ptr; - /* Keep `default_conversion' from converting if - ARG is of REFERENCE_TYPE. */ arg = TREE_OPERAND (arg, 0); if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE) { - if (TREE_CODE (arg) == VAR_DECL && DECL_INITIAL (arg) - && !TREE_SIDE_EFFECTS (DECL_INITIAL (arg))) - arg = DECL_INITIAL (arg); - arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg); - TREE_REFERENCE_EXPR (arg) = 1; + 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)) @@ -4185,6 +4396,14 @@ build_unary_op (code, xarg, noconvert) 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; } } @@ -4200,6 +4419,7 @@ build_unary_op (code, xarg, noconvert) 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. */ @@ -4226,6 +4446,7 @@ convert_sequence (conversions, arg) return arg; } } +#endif /* Apply unary lvalue-demanding operator CODE to the expression ARG for certain kinds of expressions which are not really lvalues @@ -4265,15 +4486,9 @@ unary_complex_lvalue (code, arg) || TREE_CODE (arg) == INIT_EXPR) { tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0); - return build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result); - } - - if (TREE_CODE (arg) == WITH_CLEANUP_EXPR) - { - tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0); - real_result = build (WITH_CLEANUP_EXPR, TREE_TYPE (real_result), - real_result, 0, TREE_OPERAND (arg, 2)); - return real_result; + 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 @@ -4284,7 +4499,6 @@ unary_complex_lvalue (code, arg) is really the representation of a pointer to it. Here give the representation its true type. */ tree t; - tree offset; my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313); @@ -4293,12 +4507,15 @@ unary_complex_lvalue (code, arg) t = TREE_OPERAND (arg, 1); - if (TREE_CODE (t) == FUNCTION_DECL) /* Check all this code for right semantics. */ + if (TREE_CODE (t) == FUNCTION_DECL) /* Check all this code for right semantics. */ 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; + tree offset = integer_zero_node; + if (TREE_OPERAND (arg, 0) && (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR || TREE_OPERAND (TREE_OPERAND (arg, 0), 0) != error_mark_node)) @@ -4310,38 +4527,40 @@ unary_complex_lvalue (code, arg) return error_mark_node; } - offset = get_delta_difference (DECL_FIELD_CONTEXT (t), - TREE_TYPE (TREE_OPERAND (arg, 0)), - 0); + type = TREE_TYPE (TREE_OPERAND (arg, 0)); + + if (TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE) + { + /* Add in the offset to the intermediate subobject, if any. */ + offset = get_delta_difference (TYPE_OFFSET_BASETYPE (TREE_TYPE (arg)), + type, + 0); + type = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg)); + } + + /* Now in the offset to the final subobject. */ + offset = size_binop (PLUS_EXPR, + offset, + get_delta_difference (DECL_FIELD_CONTEXT (t), + type, + 0)); + + /* Add in the offset to the field. */ offset = size_binop (PLUS_EXPR, offset, size_binop (EASY_DIV_EXPR, DECL_FIELD_BITPOS (t), size_int (BITS_PER_UNIT))); - return convert (build_pointer_type (TREE_TYPE (arg)), offset); - } - } - if (TREE_CODE (arg) == OFFSET_REF) - { - tree left = TREE_OPERAND (arg, 0), left_addr; - tree right_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 1), 0); - - if (left == 0) - if (current_class_decl) - left_addr = current_class_decl; - else - { - error ("no `this' for pointer to member"); - return error_mark_node; - } - else - left_addr = build_unary_op (ADDR_EXPR, left, 0); + /* We offset all pointer to data memebers by 1 so that we can + distinguish between a null pointer to data member and the first + data member of a structure. */ + offset = size_binop (PLUS_EXPR, offset, size_int (1)); - return build (PLUS_EXPR, build_pointer_type (TREE_TYPE (arg)), - build1 (NOP_EXPR, integer_type_node, left_addr), - build1 (NOP_EXPR, integer_type_node, right_addr)); + return convert (build_pointer_type (TREE_TYPE (arg)), offset); + } } + /* We permit compiler to make function calls returning objects of aggregate type look like lvalues. */ { @@ -4355,24 +4574,13 @@ unary_complex_lvalue (code, arg) if (TREE_CODE (arg) == SAVE_EXPR) targ = arg; else - targ = build_cplus_new (TREE_TYPE (arg), arg, 1); - return build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (arg)), targ); + 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, TYPE_POINTER_TO (TREE_TYPE (arg)), + return build (SAVE_EXPR, build_pointer_type (TREE_TYPE (arg)), TREE_OPERAND (targ, 0), current_function_decl, NULL); - - /* We shouldn't wrap WITH_CLEANUP_EXPRs inside of SAVE_EXPRs, but in case - we do, here's how to handle it. */ - if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == WITH_CLEANUP_EXPR) - { -#if 0 - /* Not really a bug, but something to turn on when testing. */ - compiler_error ("WITH_CLEANUP_EXPR wrapped in SAVE_EXPR"); -#endif - return unary_complex_lvalue (ADDR_EXPR, targ); - } } /* Don't let anything else be handled specially. */ @@ -4383,7 +4591,7 @@ unary_complex_lvalue (code, arg) address of it; it should not be allocated in a register. Value is 1 if successful. - C++: we do not allow `current_class_decl' to be addressable. */ + C++: we do not allow `current_class_ptr' to be addressable. */ int mark_addressable (exp) @@ -4404,18 +4612,18 @@ mark_addressable (exp) break; case PARM_DECL: - if (x == current_class_decl) + if (x == current_class_ptr) { - error ("address of `this' not available"); + 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) + if (TREE_STATIC (x) && TREE_READONLY (x) && DECL_RTL (x) != 0 - && ! decl_in_memory_p (x)) + && ! DECL_IN_MEMORY_P (x)) { /* We thought this would make a good constant variable, but we were wrong. */ @@ -4440,8 +4648,10 @@ mark_addressable (exp) case CONST_DECL: case RESULT_DECL: - /* For C++, we don't warn about taking the address of a register - variable for CONST_DECLs; ARM p97 explicitly says it's okay. */ + 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; @@ -4465,6 +4675,15 @@ mark_addressable (exp) 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; } @@ -4478,6 +4697,12 @@ build_x_conditional_expr (ifexp, op1, op2) { tree rval = NULL_TREE; + if (processing_template_decl) + return build_min_nt (COND_EXPR, ifexp, op1, op2); + + if (flag_ansi_overloading) + return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2); + /* See comments in `build_x_binary_op'. */ if (op1 != 0) rval = build_opfncall (COND_EXPR, LOOKUP_SPECULATIVELY, ifexp, op1, op2); @@ -4496,7 +4721,6 @@ build_conditional_expr (ifexp, op1, op2) register enum tree_code code1; register enum tree_code code2; register tree result_type = NULL_TREE; - tree orig_op1 = op1, orig_op2 = op2; /* If second operand is omitted, it is the same as the first one; make sure it is calculated only once. */ @@ -4507,7 +4731,7 @@ build_conditional_expr (ifexp, op1, op2) ifexp = op1 = save_expr (ifexp); } - ifexp = truthvalue_conversion (ifexp); + ifexp = convert (boolean_type_node, ifexp); if (TREE_CODE (ifexp) == ERROR_MARK) return error_mark_node; @@ -4538,17 +4762,12 @@ build_conditional_expr (ifexp, op1, op2) code2 = TREE_CODE (type2); } -#if 1 /* Produces wrong result if within sizeof. Sorry. */ /* Don't promote the operands separately if they promote the same way. Return the unpromoted type and let the combined value get promoted if necessary. */ if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2) && code2 != ARRAY_TYPE -#if 0 - /* For C++, let the enumeral type come through. */ - && code2 != ENUMERAL_TYPE -#endif && code2 != FUNCTION_TYPE && code2 != METHOD_TYPE) { @@ -4577,9 +4796,17 @@ build_conditional_expr (ifexp, op1, op2) 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; } -#endif /* They don't match; promote them both and then try to reconcile them. But don't permit mismatching enum types. */ @@ -4616,9 +4843,21 @@ build_conditional_expr (ifexp, op1, op2) code2 = TREE_CODE (type2); } + if (code1 == RECORD_TYPE && code2 == RECORD_TYPE + && real_lvalue_p (op1) && real_lvalue_p (op2) + && comptypes (type1, type2, -1)) + { + 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. */ - if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)) + else if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)) { if (type1 == type2) result_type = type1; @@ -4639,16 +4878,14 @@ build_conditional_expr (ifexp, op1, op2) 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 (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node - && TREE_CODE (orig_op1) != NOP_EXPR) - result_type = qualify_type (type2, type1); - else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node - && TREE_CODE (orig_op2) != NOP_EXPR) - result_type = qualify_type (type1, type2); else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node) { if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE) @@ -4682,7 +4919,7 @@ build_conditional_expr (ifexp, op1, op2) cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression", type1, type2, result_type); - result_type = TYPE_POINTER_TO (result_type); + result_type = build_pointer_type (result_type); } } else @@ -4693,30 +4930,12 @@ build_conditional_expr (ifexp, op1, op2) } else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) { - if (!integer_zerop (op2)) - pedwarn ("pointer/integer type mismatch in conditional expression"); - else - { - op2 = null_pointer_node; -#if 0 /* Sez who? */ - if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE) - pedwarn ("ANSI C++ forbids conditional expr between 0 and function pointer"); -#endif - } + pedwarn ("pointer/integer type mismatch in conditional expression"); result_type = type1; } else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE) { - if (!integer_zerop (op1)) - pedwarn ("pointer/integer type mismatch in conditional expression"); - else - { - op1 = null_pointer_node; -#if 0 /* Sez who? */ - if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE) - pedwarn ("ANSI C++ forbids conditional expr between 0 and function pointer"); -#endif - } + pedwarn ("pointer/integer type mismatch in conditional expression"); result_type = type2; } @@ -4729,30 +4948,52 @@ build_conditional_expr (ifexp, op1, op2) 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)) { - tree tmp = build_type_conversion (CONVERT_EXPR, type2, op1, 0); + /* There are other types besides pointers and records. */ + tree tmp; + if (code2 == POINTER_TYPE) + tmp = build_pointer_type + (build_type_variant (TREE_TYPE (type2), 1, 1)); + else + tmp = type2; + tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0); if (tmp == NULL_TREE) { - cp_error ("aggregate type `%T' could not convert on lhs of `:'", type1); + cp_error ("incompatible types `%T' and `%T' in `?:'", + type1, type2); return error_mark_node; } if (tmp == error_mark_node) error ("ambiguous pointer conversion"); - result_type = type2; + 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 = build_type_conversion (CONVERT_EXPR, type1, op2, 0); + tree tmp; + if (code1 == POINTER_TYPE) + tmp = build_pointer_type + (build_type_variant (TREE_TYPE (type1), 1, 1)); + else + tmp = type1; + + tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0); if (tmp == NULL_TREE) { - cp_error ("aggregate type `%T' could not convert on rhs of `:'", type2); + cp_error ("incompatible types `%T' and `%T' in `?:'", + type1, type2); return error_mark_node; } if (tmp == error_mark_node) error ("ambiguous pointer conversion"); - result_type = type1; + else + STRIP_NOPS (tmp); + result_type = common_type (type1, TREE_TYPE (tmp)); op2 = tmp; } else if (flag_cond_mismatch) @@ -4773,51 +5014,16 @@ build_conditional_expr (ifexp, op1, op2) if (result_type != TREE_TYPE (op2)) op2 = convert_and_check (result_type, op2); -#if 0 - /* XXX delete me, I've been here for years. */ - if (IS_AGGR_TYPE_CODE (code1)) - { - result_type = TREE_TYPE (op1); - if (TREE_CONSTANT (ifexp)) - return (integer_zerop (ifexp) ? op2 : op1); - - if (TYPE_MODE (result_type) == BLKmode) - { - register tree tempvar - = build_decl (VAR_DECL, NULL_TREE, result_type); - register tree xop1 = build_modify_expr (tempvar, NOP_EXPR, op1); - register tree xop2 = build_modify_expr (tempvar, NOP_EXPR, op2); - register tree result = fold (build (COND_EXPR, result_type, - ifexp, xop1, xop2)); - - layout_decl (tempvar, 0); - /* No way to handle variable-sized objects here. - I fear that the entire handling of BLKmode conditional exprs - needs to be redone. */ - my_friendly_assert (TREE_CONSTANT (DECL_SIZE (tempvar)), 315); - DECL_RTL (tempvar) - = assign_stack_local (DECL_MODE (tempvar), - (TREE_INT_CST_LOW (DECL_SIZE (tempvar)) - + BITS_PER_UNIT - 1) - / BITS_PER_UNIT, - 0); - - TREE_SIDE_EFFECTS (result) - = TREE_SIDE_EFFECTS (ifexp) | TREE_SIDE_EFFECTS (op1) - | TREE_SIDE_EFFECTS (op2); - return build (COMPOUND_EXPR, result_type, result, tempvar); - } - } -#endif /* 0 */ - if (TREE_CONSTANT (ifexp)) return integer_zerop (ifexp) ? op2 : op1; - return fold (build (COND_EXPR, result_type, ifexp, op1, op2)); + 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; @@ -4825,6 +5031,9 @@ build_x_compound_expr (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); @@ -4889,124 +5098,251 @@ build_compound_expr (list) break_out_cleanups (TREE_VALUE (list)), rest); } -#ifdef __GNUC__ -__inline -#endif -int -null_ptr_cst_p (t) - tree t; -{ - return (TREE_CODE (t) == INTEGER_CST && integer_zerop (t)); -} - -tree build_static_cast (type, expr) +tree +build_static_cast (type, expr) tree type, expr; { - return build_c_cast (type, expr, 0); -} + tree intype, binfo; + int ok; -tree build_reinterpret_cast (type, expr) - tree type, expr; -{ - tree intype = TREE_TYPE (expr); + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; - if (TYPE_PTRMEMFUNC_P (type)) - type = TYPE_PTRMEMFUNC_FN_TYPE (type); - if (TYPE_PTRMEMFUNC_P (intype)) - intype = TYPE_PTRMEMFUNC_FN_TYPE (intype); + if (TREE_CODE (expr) == OFFSET_REF) + expr = resolve_offset_ref (expr); - if (! POINTER_TYPE_P (type) && ! TREE_CODE (type) == INTEGER_TYPE) - { - cp_error ("reinterpret_cast cannot convert to type `%T'", type); - return error_mark_node; - } - if (! POINTER_TYPE_P (intype) && ! TREE_CODE (intype) == INTEGER_TYPE) - { - cp_error ("reinterpret_cast cannot convert from type `%T'", type); - return error_mark_node; - } - if (TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (intype) != POINTER_TYPE) + if (processing_template_decl) { - cp_error ("reinterpret_cast cannot convert non-pointer type `%T' to `%T'", - intype, type); - return error_mark_node; + tree t = build_min (STATIC_CAST_EXPR, type, expr); + return t; } - if (TREE_CODE (intype) == INTEGER_TYPE && TREE_CODE (type) != POINTER_TYPE) + + /* 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 (type_unknown_p (expr)) { - cp_error ("reinterpret_cast cannot convert `%T' to non-pointer type `%T'", - intype, type); - return error_mark_node; + expr = instantiate_type (type, expr, 1); + if (expr == error_mark_node) + return error_mark_node; } - if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) == POINTER_TYPE) - expr = convert (ptr_type_node, expr); - - return build_c_cast (type, expr, 0); + 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_tree_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)) + && (TYPE_READONLY (TREE_TYPE (type)) + >= TYPE_READONLY (TREE_TYPE (intype))) + && (TYPE_VOLATILE (TREE_TYPE (type)) + >= TYPE_VOLATILE (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 (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))), + TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (intype))), 1) + && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (type))) + >= TYPE_READONLY (TREE_TYPE (TREE_TYPE (intype)))) + && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (type))) + >= TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (intype)))) + && (binfo = get_binfo (TYPE_OFFSET_BASETYPE (intype), + TYPE_OFFSET_BASETYPE (type), 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_const_cast (type, expr) +tree +build_reinterpret_cast (type, expr) tree type, expr; { - tree intype = TREE_TYPE (expr); - tree t1, t2; + tree intype; + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; - if (TYPE_PTRMEMFUNC_P (type)) - type = TYPE_PTRMEMFUNC_FN_TYPE (type); - if (TYPE_PTRMEMFUNC_P (intype)) - intype = TYPE_PTRMEMFUNC_FN_TYPE (intype); + if (TREE_CODE (expr) == OFFSET_REF) + expr = resolve_offset_ref (expr); - if (! POINTER_TYPE_P (type)) + if (processing_template_decl) { - cp_error ("const_cast cannot convert to non-pointer type `%T'", type); - return error_mark_node; + tree t = build_min (REINTERPRET_CAST_EXPR, type, expr); + return t; } - if (TREE_CODE (type) == REFERENCE_TYPE && ! real_lvalue_p (expr)) + + if (TREE_CODE (type) != REFERENCE_TYPE) { - cp_error ("const_cast cannot convert rvalue to type `%T'", type); - return error_mark_node; + 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); } - if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) != POINTER_TYPE) + + if (type_unknown_p (expr)) { - cp_error ("const_cast cannot convert non-pointer type `%T' to type `%T'", - intype, type); - return error_mark_node; + expr = instantiate_type (type, expr, 1); + if (expr == error_mark_node) + return error_mark_node; } + intype = TREE_TYPE (expr); + if (TREE_CODE (type) == REFERENCE_TYPE) { - t1 = TREE_TYPE (type); - t2 = intype; + 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 (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1)) + 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 { - t1 = TREE_TYPE (type); - t2 = TREE_TYPE (intype); + cp_error ("reinterpret_cast from `%T' to `%T'", intype, type); + return error_mark_node; + } + + return convert (type, expr); +} - for (; TREE_CODE (t1) == POINTER_TYPE && TREE_CODE (t2) == POINTER_TYPE; - t1 = TREE_TYPE (t1), t2 = TREE_TYPE (t2)) - ; +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, type, expr); + return t; } - if (TREE_CODE (t1) == OFFSET_TYPE && TREE_CODE (t2) == OFFSET_TYPE) + if (TREE_CODE (type) != REFERENCE_TYPE) { - if (TYPE_OFFSET_BASETYPE (t1) != TYPE_OFFSET_BASETYPE (t2)) + 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); + } + + if (type_unknown_p (expr)) + { + expr = instantiate_type (type, expr, 1); + if (expr == error_mark_node) + return error_mark_node; + } + + intype = TREE_TYPE (expr); + + if (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1)) + return build_static_cast (type, expr); + else if (TREE_CODE (type) == REFERENCE_TYPE) + { + if (! real_lvalue_p (expr)) { - cp_error ("const_cast cannot convert between pointers to members of different types `%T' and `%T'", - TYPE_OFFSET_BASETYPE (t2), TYPE_OFFSET_BASETYPE (t1)); + cp_error ("const_cast from `%T' rvalue to `%T'", intype, type); return error_mark_node; } - t1 = TREE_TYPE (t1); - t2 = TREE_TYPE (t2); - } - if (TYPE_MAIN_VARIANT (t1) != TYPE_MAIN_VARIANT (t2)) - { - cp_error ("const_cast cannot convert unrelated type `%T' to `%T'", - t2, t1); - return error_mark_node; + if (comp_ptr_ttypes_const (TREE_TYPE (type), intype)) + return (convert_from_reference + (convert_to_reference (type, expr, CONV_CONST|CONV_IMPLICIT, + LOOKUP_COMPLAIN, NULL_TREE))); } + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (intype) == POINTER_TYPE + && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype))) + return convert (type, expr); - return build_c_cast (type, expr, 0); + 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. @@ -5015,10 +5351,8 @@ tree build_const_cast (type, expr) when doing the cast. */ tree -build_c_cast (type, expr, allow_nonconverting) - register tree type; - tree expr; - int allow_nonconverting; +build_c_cast (type, expr) + tree type, expr; { register tree value = expr; @@ -5068,11 +5402,12 @@ build_c_cast (type, expr, allow_nonconverting) return error_mark_node; } - /* If there's only one function in the overloaded space, - just take it. */ - if (TREE_CODE (value) == TREE_LIST - && TREE_CHAIN (value) == NULL_TREE) - value = TREE_VALUE (value); + if (processing_template_decl) + { + tree t = build_min (CAST_EXPR, type, + min_tree_cons (NULL_TREE, value, NULL_TREE)); + return t; + } if (TREE_CODE (type) == VOID_TYPE) value = build1 (CONVERT_EXPR, type, value); @@ -5087,13 +5422,16 @@ build_c_cast (type, expr, allow_nonconverting) else { tree otype; - int flag; /* Convert functions and arrays to pointers and convert references to their expanded types, but don't convert any other types. */ if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE - || TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE + || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE + /* Don't do the default conversion if we want a + pointer to a function. */ + && TREE_CODE (type) != POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE) || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE) value = default_conversion (value); @@ -5125,6 +5463,8 @@ build_c_cast (type, expr, allow_nonconverting) 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)) @@ -5139,11 +5479,9 @@ build_c_cast (type, expr, allow_nonconverting) warning ("cast to pointer from integer of different size"); #endif - flag = allow_nonconverting ? CONV_NONCONVERTING : 0; - if (TREE_CODE (type) == REFERENCE_TYPE) value = (convert_from_reference - (convert_to_reference (type, value, CONV_OLD_CONVERT|flag, + (convert_to_reference (type, value, CONV_C_CAST, LOOKUP_COMPLAIN, NULL_TREE))); else { @@ -5153,7 +5491,7 @@ build_c_cast (type, expr, allow_nonconverting) value = decl_constant_value (value); ovalue = value; - value = convert_force (type, value, flag); + value = convert_force (type, value, CONV_C_CAST); /* Ignore any integer overflow caused by the cast. */ if (TREE_CODE (value) == INTEGER_CST) @@ -5165,312 +5503,45 @@ build_c_cast (type, expr, allow_nonconverting) } /* Always produce some operator for an explicit cast, - so we can tell (for -pedantic) that the cast is no lvalue. - Also, pedantically, don't let (void *) (FOO *) 0 be a null - pointer constant. */ - if (value == expr - || (pedantic - && TREE_CODE (value) == INTEGER_CST - && TREE_CODE (expr) == INTEGER_CST - && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)) + 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; } -#if 0 -/* Build an assignment expression of lvalue LHS from value RHS. - - In C++, if the left hand side of the assignment is a REFERENCE_TYPE, - that reference becomes deferenced down to it base type. */ - -/* Return a reference to the BASE_INDEX part of EXPR. TYPE is - the type to which BASE_INDEX applies. */ -static tree -get_base_ref (type, base_index, expr) - tree type; - int base_index; - tree expr; -{ - tree binfos = TYPE_BINFO_BASETYPES (type); - tree base_binfo = TREE_VEC_ELT (binfos, base_index); - tree ref; - - if (TREE_CODE (expr) == ARRAY_REF - || ! BINFO_OFFSET_ZEROP (base_binfo) - || TREE_VIA_VIRTUAL (base_binfo) - || TYPE_MODE (type) != TYPE_MODE (BINFO_TYPE (base_binfo))) - { - tree addr = build_unary_op (ADDR_EXPR, expr, 0); - ref = build_indirect_ref (convert_pointer_to (base_binfo, addr), - NULL_PTR); - } - else - { - ref = copy_node (expr); - TREE_TYPE (ref) = BINFO_TYPE (base_binfo); - } - return ref; -} - -/* Build an assignment expression of lvalue LHS from value RHS. - MODIFYCODE is the code for a binary operator that we use - to combine the old value of LHS with RHS to get the new value. - Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment. - - C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed. - - `build_modify_expr_1' implements recursive part of memberwise - assignment operation. */ -static tree -build_modify_expr_1 (lhs, modifycode, rhs, basetype_path) - tree lhs, rhs; - enum tree_code modifycode; - tree basetype_path; -{ - register tree result; - tree newrhs = rhs; - tree lhstype = TREE_TYPE (lhs); - tree olhstype = lhstype; - - /* Avoid duplicate error messages from operands that had errors. */ - if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK) - return error_mark_node; - - /* If a binary op has been requested, combine the old LHS value with the RHS - producing the value we should actually store into the LHS. */ - - if (modifycode == INIT_EXPR) - ; - else if (modifycode == NOP_EXPR) - { - /* must deal with overloading of `operator=' here. */ - if (TREE_CODE (lhstype) == REFERENCE_TYPE) - lhstype = TREE_TYPE (lhstype); - else - lhstype = olhstype; - } - else - { - lhs = stabilize_reference (lhs); - newrhs = build_binary_op (modifycode, lhs, rhs, 1); - modifycode = NOP_EXPR; - } - - /* If storing into a structure or union member, - it has probably been given type `int'. - Compute the type that would go with - the actual amount of storage the member occupies. */ - - if (TREE_CODE (lhs) == COMPONENT_REF - && (TREE_CODE (lhstype) == INTEGER_TYPE - || TREE_CODE (lhstype) == REAL_TYPE - || TREE_CODE (lhstype) == ENUMERAL_TYPE)) - lhstype = TREE_TYPE (get_unwidened (lhs, 0)); - - /* C++: The semantics of C++ differ from those of C when an - assignment of an aggregate is desired. Assignment in C++ is - now defined as memberwise assignment of non-static members - and base class objects. This rule applies recursively - until a member of a built-in type is found. - - Also, we cannot do a bit-wise copy of aggregates which - contain virtual function table pointers. Those - pointer values must be preserved through the copy. - However, this is handled in expand_expr, and not here. - This is because much better code can be generated at - that stage than this one. */ - if (TREE_CODE (lhstype) == RECORD_TYPE - && TYPE_LANG_SPECIFIC (lhstype) - && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs))) - { - register tree elt; - int i; - - /* Perform operation on object. */ - if (modifycode == INIT_EXPR && TYPE_HAS_INIT_REF (lhstype)) - { - result = build_method_call (lhs, constructor_name_full (lhstype), - build_tree_list (NULL_TREE, rhs), - basetype_path, LOOKUP_NORMAL); - return build_indirect_ref (result, NULL_PTR); - } - else if (modifycode == NOP_EXPR) - { - /* `operator=' is not an inheritable operator; see 13.4.3. */ - if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_ASSIGNMENT (lhstype)) - { - result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, - lhs, rhs, make_node (NOP_EXPR)); - if (result == NULL_TREE) - return error_mark_node; - return result; - } - } - - if (TYPE_USES_VIRTUAL_BASECLASSES (lhstype) - || (modifycode == NOP_EXPR && TYPE_GETS_ASSIGNMENT (lhstype)) - || (modifycode == INIT_EXPR && TYPE_GETS_INIT_REF (lhstype))) - { - tree binfos = BINFO_BASETYPES (TYPE_BINFO (lhstype)); - result = NULL_TREE; - - if (binfos != NULL_TREE) - /* Perform operation on each member, depth-first, left-right. */ - for (i = 0; i <= TREE_VEC_LENGTH (binfos)-1; i++) - { - tree base_binfo = TREE_VEC_ELT (binfos, i); - tree base_lhs, base_rhs; - tree new_result; - - /* Assignments from virtual baseclasses handled elsewhere. */ - if (TREE_VIA_VIRTUAL (base_binfo)) - continue; - - base_lhs = get_base_ref (lhstype, i, lhs); - base_rhs = get_base_ref (lhstype, i, newrhs); - - BINFO_INHERITANCE_CHAIN (base_binfo) = basetype_path; - new_result - = build_modify_expr_1 (base_lhs, modifycode, base_rhs, - base_binfo); - - /* We either get back a compound stmt, or a simple one. */ - if (new_result && TREE_CODE (new_result) == TREE_LIST) - new_result = build_compound_expr (new_result); - result = tree_cons (NULL_TREE, new_result, result); - } - - for (elt = TYPE_FIELDS (lhstype); elt; elt = TREE_CHAIN (elt)) - { - tree vbases = NULL_TREE; - tree elt_lhs, elt_rhs; - - if (TREE_CODE (elt) != FIELD_DECL) - continue; - if (DECL_NAME (elt) - && (VFIELD_NAME_P (DECL_NAME (elt)) - || VBASE_NAME_P (DECL_NAME (elt)))) - continue; - - if (TREE_READONLY (elt) - || TREE_CODE (TREE_TYPE (elt)) == REFERENCE_TYPE) - { - cp_error ("cannot generate default `%T::operator ='", - lhstype); - if (TREE_CODE (TREE_TYPE (elt)) == REFERENCE_TYPE) - cp_error_at ("because member `%#D' is a reference", elt); - else - cp_error_at ("because member `%#D' is const", elt); - - return error_mark_node; - } - - if (IS_AGGR_TYPE (TREE_TYPE (elt)) - && TYPE_LANG_SPECIFIC (TREE_TYPE (elt))) - vbases = CLASSTYPE_VBASECLASSES (TREE_TYPE (elt)); - - elt_lhs = build (COMPONENT_REF, TREE_TYPE (elt), lhs, elt); - elt_rhs = build (COMPONENT_REF, TREE_TYPE (elt), newrhs, elt); - /* It is not always safe to go through `build_modify_expr_1' - when performing element-wise copying. This is because - an element may be of ARRAY_TYPE, which will not - be properly copied as a naked element. */ - if (TREE_CODE (TREE_TYPE (elt)) == RECORD_TYPE - && TYPE_LANG_SPECIFIC (TREE_TYPE (elt))) - basetype_path = TYPE_BINFO (TREE_TYPE (elt)); - - while (vbases) - { - tree elt_lhs_addr = build_unary_op (ADDR_EXPR, elt_lhs, 0); - tree elt_rhs_addr = build_unary_op (ADDR_EXPR, elt_rhs, 0); - - elt_lhs_addr = convert_pointer_to (vbases, elt_lhs_addr); - elt_rhs_addr = convert_pointer_to (vbases, elt_rhs_addr); - result - = tree_cons (NULL_TREE, - build_modify_expr_1 - (build_indirect_ref (elt_lhs_addr, NULL_PTR), - modifycode, - build_indirect_ref (elt_rhs_addr, NULL_PTR), - basetype_path), - result); - if (TREE_VALUE (result) == error_mark_node) - return error_mark_node; - vbases = TREE_CHAIN (vbases); - } - elt_lhs = build_modify_expr_1 (elt_lhs, modifycode, elt_rhs, - basetype_path); - result = tree_cons (NULL_TREE, elt_lhs, result); - } - - if (result) - return build_compound_expr (result); - /* No fields to move. */ - return integer_zero_node; - } - else - { - result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, - void_type_node, lhs, rhs); - TREE_SIDE_EFFECTS (result) = 1; - return result; - } - } - - result = build_modify_expr (lhs, modifycode, newrhs); - /* ARRAY_TYPEs cannot be converted to anything meaningful, - and leaving it there screws up `build_compound_expr' when - it tries to defaultly convert everything. */ - if (TREE_CODE (TREE_TYPE (result)) == ARRAY_TYPE) - TREE_TYPE (result) = void_type_node; - return result; -} -#endif - -/* Taken from expr.c: - Subroutine of expand_expr: - record the non-copied parts (LIST) of an expr (LHS), and return a list - which specifies the initial values of these parts. */ - -static tree -init_noncopied_parts (lhs, list) - tree lhs; - tree list; -{ - tree tail; - tree parts = 0; - - for (tail = list; tail; tail = TREE_CHAIN (tail)) - if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST) - parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail))); - else - { - tree part = TREE_VALUE (tail); - tree part_type = TREE_TYPE (part); - tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part); - parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts); - } - return parts; -} - tree expand_target_expr (t) tree t; { + extern int temp_slot_level; + extern int target_temp_slot_level; + int old_temp_level = target_temp_slot_level; + tree xval = make_node (RTL_EXPR); rtx rtxval; + /* Any TARGET_EXPR temps live only as long as the outer temp level. + Since they are preserved in this new inner level, we know they + will make it into the outer level. */ + push_temp_slots (); + target_temp_slot_level = temp_slot_level; + do_pending_stack_adjust (); start_sequence_for_rtl_expr (xval); emit_note (0, -1); - rtxval = expand_expr (t, NULL, VOIDmode, 0); + rtxval = expand_expr (t, NULL_RTX, VOIDmode, 0); do_pending_stack_adjust (); TREE_SIDE_EFFECTS (xval) = 1; RTL_EXPR_SEQUENCE (xval) = get_insns (); end_sequence (); RTL_EXPR_RTL (xval) = rtxval; TREE_TYPE (xval) = TREE_TYPE (t); + + pop_temp_slots (); + target_temp_slot_level = old_temp_level; + return xval; } @@ -5479,8 +5550,8 @@ expand_target_expr (t) 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. -*/ + C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed. */ + tree build_modify_expr (lhs, modifycode, rhs) tree lhs; @@ -5494,18 +5565,12 @@ build_modify_expr (lhs, modifycode, rhs) tree olhs = lhs; /* Avoid duplicate error messages from operands that had errors. */ - if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK) + 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); - /* Decide early if we are going to protect RHS from GC - before assigning it to LHS. */ - if (type_needs_gc_entry (TREE_TYPE (rhs)) - && ! value_safe_from_gc (lhs, rhs)) - rhs = protect_value_from_gc (lhs, rhs); - newrhs = rhs; /* Handle assignment to signature pointers/refs. */ @@ -5525,7 +5590,8 @@ build_modify_expr (lhs, modifycode, rhs) 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))); + stabilize_reference (TREE_OPERAND (lhs, 0)), + TREE_OPERAND (lhs, 1)); return build (COMPOUND_EXPR, lhstype, lhs, build_modify_expr (TREE_OPERAND (lhs, 0), @@ -5535,14 +5601,14 @@ build_modify_expr (lhs, modifycode, rhs) case COMPOUND_EXPR: newrhs = build_modify_expr (TREE_OPERAND (lhs, 1), modifycode, rhs); - if (TREE_CODE (newrhs) == ERROR_MARK) + 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 (TREE_CODE (newrhs) == ERROR_MARK) + if (newrhs == error_mark_node) return error_mark_node; return build (COMPOUND_EXPR, lhstype, lhs, newrhs); @@ -5559,7 +5625,7 @@ build_modify_expr (lhs, modifycode, rhs) modifycode, rhs), build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)), modifycode, rhs)); - if (TREE_CODE (cond) == ERROR_MARK) + if (cond == error_mark_node) return cond; /* Make sure the code to compute the rhs comes out before the split. */ @@ -5605,15 +5671,18 @@ build_modify_expr (lhs, modifycode, rhs) if (! IS_AGGR_TYPE (lhstype)) /* Do the default thing */; else if (! TYPE_HAS_CONSTRUCTOR (lhstype)) - cp_error ("`%T' has no constructors", lhstype); + { + cp_error ("`%T' has no constructors", lhstype); + return error_mark_node; + } else if (TYPE_HAS_TRIVIAL_INIT_REF (lhstype) && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs))) /* Do the default thing */; else { - result = build_method_call (lhs, constructor_name_full (lhstype), + result = build_method_call (lhs, ctor_identifier, build_tree_list (NULL_TREE, rhs), - NULL_TREE, LOOKUP_NORMAL); + TYPE_BINFO (lhstype), LOOKUP_NORMAL); if (result == NULL_TREE) return error_mark_node; return result; @@ -5621,63 +5690,30 @@ build_modify_expr (lhs, modifycode, rhs) } else if (modifycode == NOP_EXPR) { -#if 1 /* `operator=' is not an inheritable operator. */ if (! IS_AGGR_TYPE (lhstype)) /* Do the default thing */; else if (! TYPE_HAS_ASSIGNMENT (lhstype)) - cp_error ("`%T' does not define operator=", lhstype); + { + cp_error ("`%T' does not define operator=", lhstype); + return error_mark_node; + } else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (lhstype) && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs))) - /* 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; + build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, + lhs, rhs, make_node (NOP_EXPR)); + + /* Do the default thing */; } -#else - /* Treat `operator=' as an inheritable operator. */ - if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_GETS_ASSIGNMENT (lhstype)) + else { - tree orig_lhstype = lhstype; - while (! TYPE_HAS_ASSIGNMENT (lhstype)) - { - int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (lhstype); - tree basetype = NULL_TREE; - for (i = 0; i < n_baseclasses; i++) - if (TYPE_GETS_ASSIGNMENT (TYPE_BINFO_BASETYPE (lhstype, i))) - { - if (basetype != NULL_TREE) - { - message_2_types (error, "base classes `%s' and `%s' both have operator ='", - basetype, - TYPE_BINFO_BASETYPE (lhstype, i)); - return error_mark_node; - } - basetype = TYPE_BINFO_BASETYPE (lhstype, i); - } - lhstype = basetype; - } - if (orig_lhstype != lhstype) - { - lhs = build_indirect_ref (convert_pointer_to (lhstype, - build_unary_op (ADDR_EXPR, lhs, 0)), NULL_PTR); - if (lhs == error_mark_node) - { - cp_error ("conversion to private basetype `%T'", lhstype); - return error_mark_node; - } - } result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, make_node (NOP_EXPR)); if (result == NULL_TREE) return error_mark_node; return result; } -#endif lhstype = olhstype; } else if (PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE)) @@ -5689,13 +5725,13 @@ build_modify_expr (lhs, modifycode, rhs) if (build_default_binary_type_conversion (modifycode, &lhs_tmp, &rhs_tmp)) { lhs = stabilize_reference (lhs_tmp); - /* Forget is was ever anything else. */ + /* Forget it was ever anything else. */ olhstype = lhstype = TREE_TYPE (lhs); newrhs = build_binary_op (modifycode, lhs, rhs_tmp, 1); } else { - cp_error ("no match for `%O(%#T, %#T)'", modifycode, + cp_error ("no match for `%Q(%#T, %#T)'", modifycode, TREE_TYPE (lhs), TREE_TYPE (rhs)); return error_mark_node; } @@ -5704,6 +5740,12 @@ build_modify_expr (lhs, modifycode, rhs) { 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". @@ -5730,13 +5772,16 @@ build_modify_expr (lhs, modifycode, rhs) { tree inner_lhs = TREE_OPERAND (lhs, 0); tree result; - if (! lvalue_p (lhs) && pedantic) - pedwarn ("cast to non-reference type used as lvalue"); + + /* 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, convert (TREE_TYPE (inner_lhs), convert (lhstype, newrhs))); - if (TREE_CODE (result) == ERROR_MARK) + if (result == error_mark_node) return result; return convert (TREE_TYPE (lhs), result); } @@ -5789,7 +5834,7 @@ build_modify_expr (lhs, modifycode, rhs) } /* check to see if there is an assignment to `this' */ - if (lhs == current_class_decl) + if (lhs == current_class_ptr) { if (flag_this_is_variable > 0 && DECL_NAME (current_function_decl) != NULL_TREE @@ -5841,104 +5886,6 @@ build_modify_expr (lhs, modifycode, rhs) if (TREE_SIDE_EFFECTS (newrhs)) newrhs = stabilize_reference (newrhs); -#if 0 - /* This is now done by generating X(X&) and operator=(X&). */ - /* C++: The semantics of C++ differ from those of C when an - assignment of an aggregate is desired. Assignment in C++ is - now defined as memberwise assignment of non-static members - and base class objects. This rule applies recursively - until a member of a built-in type is found. - - Also, we cannot do a bit-wise copy of aggregates which - contain virtual function table pointers. Those - pointer values must be preserved through the copy. - However, this is handled in expand_expr, and not here. - This is because much better code can be generated at - that stage than this one. */ - if (TREE_CODE (lhstype) == RECORD_TYPE - && ! TYPE_PTRMEMFUNC_P (lhstype) - && (TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)) - || (TREE_CODE (TREE_TYPE (newrhs)) == RECORD_TYPE - && UNIQUELY_DERIVED_FROM_P (lhstype, TREE_TYPE (newrhs))))) - { - tree vbases = CLASSTYPE_VBASECLASSES (lhstype); - tree lhs_addr = build_unary_op (ADDR_EXPR, lhs, 0); - tree rhs_addr; - - /* Memberwise assignment would cause NEWRHS to be - evaluated for every member that gets assigned. - By wrapping side-effecting exprs in a SAVE_EXPR, - NEWRHS will only be evaluated once. */ - if (IS_AGGR_TYPE (TREE_TYPE (newrhs)) - && TREE_SIDE_EFFECTS (newrhs) - /* This are things we don't have to save. */ - && TREE_CODE (newrhs) != COND_EXPR - && TREE_CODE (newrhs) != TARGET_EXPR - && TREE_CODE (newrhs) != WITH_CLEANUP_EXPR) - /* Call `break_out_cleanups' on NEWRHS in case there are cleanups. - If NEWRHS is a CALL_EXPR that needs a cleanup, failure to do so - will result in expand_expr expanding the call without knowing - that it should run the cleanup. */ - newrhs = save_expr (break_out_cleanups (newrhs)); - - if (TREE_CODE (newrhs) == COND_EXPR) - rhs_addr = rationalize_conditional_expr (ADDR_EXPR, newrhs); - else - rhs_addr = build_unary_op (ADDR_EXPR, newrhs, 0); - - result = tree_cons (NULL_TREE, - convert (build_reference_type (lhstype), lhs), - NULL_TREE); - - if (! comptypes (TREE_TYPE (lhs_addr), TREE_TYPE (rhs_addr), 1)) - rhs_addr = convert_pointer_to (TREE_TYPE (TREE_TYPE (lhs_addr)), rhs_addr); - { - tree noncopied_parts = NULL_TREE; - - if (TYPE_NONCOPIED_PARTS (lhstype) != 0) - noncopied_parts = init_noncopied_parts (lhs, - TYPE_NONCOPIED_PARTS (lhstype)); - while (noncopied_parts != 0) - { - result = tree_cons (NULL_TREE, - build_modify_expr (convert (ptr_type_node, TREE_VALUE (noncopied_parts)), - NOP_EXPR, - TREE_PURPOSE (noncopied_parts)), - result); - noncopied_parts = TREE_CHAIN (noncopied_parts); - } - } - /* Once we have our hands on an address, we must change NEWRHS - to work from there. Otherwise we can get multiple evaluations - of NEWRHS. */ - if (TREE_CODE (newrhs) != SAVE_EXPR) - newrhs = build_indirect_ref (rhs_addr, NULL_PTR); - - while (vbases) - { - tree elt_lhs = convert_pointer_to (vbases, lhs_addr); - tree elt_rhs = convert_pointer_to (vbases, rhs_addr); - result - = tree_cons (NULL_TREE, - build_modify_expr_1 (build_indirect_ref (elt_lhs, NULL_PTR), - modifycode, - build_indirect_ref (elt_rhs, NULL_PTR), - TYPE_BINFO (lhstype)), - result); - if (TREE_VALUE (result) == error_mark_node) - return error_mark_node; - vbases = TREE_CHAIN (vbases); - } - result = tree_cons (NULL_TREE, - build_modify_expr_1 (lhs, - modifycode, - newrhs, - TYPE_BINFO (lhstype)), - result); - return build_compound_expr (result); - } -#endif - /* Convert new value to destination type. */ if (TREE_CODE (lhstype) == ARRAY_TYPE) @@ -5997,16 +5944,7 @@ build_modify_expr (lhs, modifycode, rhs) } else { -#if 0 - if (IS_AGGR_TYPE (lhstype)) - { - if (result = build_opfncall (MODIFY_EXPR, - LOOKUP_NORMAL, lhs, newrhs, - make_node (NOP_EXPR))) - return result; - } -#endif - /* Avoid warnings on enum bit fields. */ + /* Avoid warnings on enum bit fields. */ if (TREE_CODE (olhstype) == ENUMERAL_TYPE && TREE_CODE (lhstype) == INTEGER_TYPE) { @@ -6019,17 +5957,18 @@ build_modify_expr (lhs, modifycode, rhs) NULL_TREE, 0); if (TREE_CODE (newrhs) == CALL_EXPR && TYPE_NEEDS_CONSTRUCTING (lhstype)) - newrhs = build_cplus_new (lhstype, newrhs, 0); + newrhs = build_cplus_new (lhstype, newrhs); /* Can't initialize directly from a TARGET_EXPR, since that would - cause the lhs to be constructed twice. So we force the - TARGET_EXPR to be expanded. expand_expr should really do this - by itself. */ + 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 = expand_target_expr (newrhs); + newrhs = build (COMPOUND_EXPR, TREE_TYPE (newrhs), newrhs, + TREE_OPERAND (newrhs, 0)); } - if (TREE_CODE (newrhs) == ERROR_MARK) + if (newrhs == error_mark_node) return error_mark_node; if (TREE_CODE (newrhs) == COND_EXPR) @@ -6067,38 +6006,10 @@ build_modify_expr (lhs, modifycode, rhs) TREE_OPERAND (newrhs, 2)))); } } - else if (modifycode != INIT_EXPR && TREE_CODE (newrhs) == WITH_CLEANUP_EXPR) - { - tree cleanup = TREE_OPERAND (newrhs, 2); - tree slot; - - /* Finish up by running cleanups and having the "value" of the lhs. */ - tree exprlist = tree_cons (NULL_TREE, cleanup, - build_tree_list (NULL_TREE, lhs)); - newrhs = TREE_OPERAND (newrhs, 0); - if (TREE_CODE (newrhs) == TARGET_EXPR) - slot = TREE_OPERAND (newrhs, 0); - else if (TREE_CODE (newrhs) == ADDR_EXPR) - { - /* Bad but valid. */ - slot = newrhs; - warning ("address taken of temporary object"); - } - else - my_friendly_abort (118); - - /* Copy the value computed in SLOT into LHS. */ - exprlist = tree_cons (NULL_TREE, - build_modify_expr (lhs, modifycode, slot), - exprlist); - /* Evaluate the expression that needs CLEANUP. This will - compute the value into SLOT. */ - exprlist = tree_cons (NULL_TREE, newrhs, exprlist); - result = convert (lhstype, build_compound_expr (exprlist)); - } 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, @@ -6109,7 +6020,7 @@ build_modify_expr (lhs, modifycode, rhs) if (olhstype == TREE_TYPE (result)) return result; /* Avoid warnings converting integral types back into enums - for enum bit fields. */ + for enum bit fields. */ if (TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE && TREE_CODE (olhstype) == ENUMERAL_TYPE) { @@ -6121,6 +6032,25 @@ build_modify_expr (lhs, modifycode, rhs) 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); +} /* Return 0 if EXP is not a valid lvalue in this language even though `lvalue_or_else' would accept it. */ @@ -6132,9 +6062,10 @@ language_lvalue_valid (exp) return 1; } -/* Get differnce in deltas for different pointer to member function - types. Return inetger_zero_node, if FROM cannot be converted to a +/* 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; @@ -6154,7 +6085,7 @@ get_delta_difference (from, to, force) binfo = get_binfo (from, to, 1); if (binfo == error_mark_node) { - error (" in pointer to member function conversion"); + error (" in pointer to member function conversiona"); return delta; } if (binfo == 0) @@ -6162,27 +6093,34 @@ get_delta_difference (from, to, force) if (!force) { error_not_base_type (from, to); - error (" in pointer to member function conversion"); + error (" in pointer to member conversion"); return delta; } binfo = get_binfo (to, from, 1); if (binfo == error_mark_node) { - error (" in pointer to member function conversion"); + if (!force) + error (" in pointer to member conversion"); return delta; } if (binfo == 0) { - error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to); + if (!force) + cp_error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to); return delta; } if (TREE_VIA_VIRTUAL (binfo)) { + binfo = binfo_member (BINFO_TYPE (binfo), + CLASSTYPE_VBASECLASSES (from)); warning ("pointer to member conversion to virtual base class will only work if you are very careful"); } + delta = BINFO_OFFSET (binfo); + delta = convert (ptrdiff_type_node, delta); + return build_binary_op (MINUS_EXPR, integer_zero_node, - BINFO_OFFSET (binfo), 1); + delta, 1); } if (TREE_VIA_VIRTUAL (binfo)) { @@ -6191,6 +6129,79 @@ get_delta_difference (from, to, force) 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, + tree_cons (pfn_identifier, pfn, NULL_TREE)); + } + else + { + u = build_nt (CONSTRUCTOR, NULL_TREE, + tree_cons (delta2_identifier, delta2, NULL_TREE)); + } + + u = build_nt (CONSTRUCTOR, NULL_TREE, + tree_cons (NULL_TREE, delta, + tree_cons (NULL_TREE, idx, + 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 = 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 = 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 = tree_cons (delta_field, delta, + tree_cons (idx_field, idx, + 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 @@ -6207,114 +6218,81 @@ build_ptrmemfunc (type, pfn, force) tree type, pfn; int force; { - tree index = integer_zero_node; + tree idx = integer_zero_node; tree delta = integer_zero_node; tree delta2 = integer_zero_node; tree vfield_offset; - tree npfn; - tree u; + tree npfn = NULL_TREE; - /* Handle multiple conversions of pointer to member fucntions. */ + /* Handle multiple conversions of pointer to member functions. */ if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn))) { - tree ndelta, ndelta2, nindex; + tree ndelta, ndelta2; + tree e1, e2, e3, n; + /* Is is already the right type? */ -#if 0 - /* Sorry, can't do this, the backend is too stupid. */ - if (TYPE_METHOD_BASETYPE (TREE_TYPE (type)) - == TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn))))) - { - if (type != TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn))) - { - npfn = build1 (NOP_EXPR, TYPE_GET_PTRMEMFUNC_TYPE (type), pfn); - TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn); - } - return pfn; - } -#else if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn))) return pfn; -#endif - if (TREE_CODE (pfn) != CONSTRUCTOR) - { - tree e1, e2, e3; - ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, 0, 0)); - ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn)); - index = build_component_ref (pfn, index_identifier, 0, 0); - delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))), - TYPE_METHOD_BASETYPE (TREE_TYPE (type)), - force); - delta = build_binary_op (PLUS_EXPR, delta, ndelta, 1); - delta2 = build_binary_op (PLUS_EXPR, ndelta2, delta2, 1); - e1 = fold (build (GT_EXPR, boolean_type_node, index, integer_zero_node)); - - u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE)); - u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta, - tree_cons (NULL_TREE, index, - tree_cons (NULL_TREE, u, NULL_TREE)))); - e2 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0); + ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0)); + ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn)); + idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0); - pfn = PFN_FROM_PTRMEMFUNC (pfn); - npfn = build1 (NOP_EXPR, type, pfn); - TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn); + n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))), + TYPE_METHOD_BASETYPE (TREE_TYPE (type)), + force); - u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE)); - u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta, - tree_cons (NULL_TREE, index, - tree_cons (NULL_TREE, u, NULL_TREE)))); - e3 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0); - return build_conditional_expr (e1, e2, e3); - } + 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); - ndelta = TREE_VALUE (CONSTRUCTOR_ELTS (pfn)); - nindex = TREE_VALUE (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn))); - npfn = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn)))); - npfn = TREE_VALUE (CONSTRUCTOR_ELTS (npfn)); - if (integer_zerop (nindex)) - pfn = integer_zero_node; - else - { - sorry ("value casting of varible nonnull pointer to member functions not supported"); - return error_mark_node; - } + 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. */ + /* Handle null pointer to member function conversions. */ if (integer_zerop (pfn)) { - pfn = build_c_cast (type, integer_zero_node, 0); - u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE)); - u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, integer_zero_node, - tree_cons (NULL_TREE, integer_zero_node, - tree_cons (NULL_TREE, u, NULL_TREE)))); - return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0); + 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 (TREE_CODE (pfn) == TREE_LIST || (TREE_CODE (pfn) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (pfn, 0)) == TREE_LIST)) - { - pfn = instantiate_type (type, pfn, 1); - if (pfn == error_mark_node) - return error_mark_node; - if (TREE_CODE (pfn) != ADDR_EXPR) - pfn = build_unary_op (ADDR_EXPR, pfn, 0); - } + return instantiate_type (type, pfn, 1); - /* Allow pointer to member conversions here. */ + /* 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 0 + /* We need to check the argument types to see if they are compatible + (any const or volatile violations. */ + something like this: + comptype (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (type))), + TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))), ?); +#endif + 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. */ + /* 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); @@ -6322,25 +6300,26 @@ build_ptrmemfunc (type, pfn, force) delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2); /* Map everything down one to make room for the null pointer to member. */ - index = size_binop (PLUS_EXPR, - DECL_VINDEX (TREE_OPERAND (pfn, 0)), - integer_one_node); - u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE)); + idx = size_binop (PLUS_EXPR, + DECL_VINDEX (TREE_OPERAND (pfn, 0)), + integer_one_node); } else { - index = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node); + idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node); - npfn = build1 (NOP_EXPR, type, pfn); - TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn); - - u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE)); + if (type == TREE_TYPE (pfn)) + { + npfn = pfn; + } + else + { + npfn = build1 (NOP_EXPR, type, pfn); + TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn); + } } - u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta, - tree_cons (NULL_TREE, index, - tree_cons (NULL_TREE, u, NULL_TREE)))); - return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0); + return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2); } /* Convert value RHS to type TYPE as preparation for an assignment @@ -6465,7 +6444,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) || (coder == ENUMERAL_TYPE && (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE))) { - return cp_convert (type, rhs, CONV_IMPLICIT, 0); + return cp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL); } /* Conversions among pointers */ else if (codel == POINTER_TYPE @@ -6541,13 +6520,13 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) return error_mark_node; } - if (ctt < 0) + if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr)) cp_pedwarn ("converting `%T' to `%T' is a contravariance violation", - ttr, ttl); + rhstype, type); if (TYPE_MAIN_VARIANT (ttl) != void_type_node && TYPE_MAIN_VARIANT (ttr) == void_type_node - && rhs != null_pointer_node) + && ! null_ptr_cst_p (rhs)) { if (coder == RECORD_TYPE) cp_pedwarn ("implicit conversion of signature pointer to type `%T'", @@ -6598,31 +6577,6 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) } } } - else if (TREE_CODE (ttr) == OFFSET_TYPE - && TREE_CODE (ttl) != OFFSET_TYPE) - { - /* Normally, pointers to different type codes (other - than void) are not compatible, but we perform - some type instantiation if that resolves the - ambiguity of (X Y::*) and (X *). */ - - if (current_class_decl) - { - if (TREE_CODE (rhs) == INTEGER_CST) - { - rhs = build (PLUS_EXPR, build_pointer_type (TREE_TYPE (ttr)), - current_class_decl, rhs); - return convert_for_assignment (type, rhs, - errtype, fndecl, parmnum); - } - } - if (TREE_CODE (ttl) == METHOD_TYPE) - error ("%s between pointer-to-method and pointer-to-member types", - errtype); - else - error ("%s between pointer and pointer-to-member types", errtype); - return error_mark_node; - } else { int add_quals = 0, const_parity = 0, volatile_parity = 0; @@ -6634,8 +6588,8 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr)) { nptrs -= 1; - const_parity |= TYPE_READONLY (ttl) < TYPE_READONLY (ttr); - volatile_parity |= TYPE_VOLATILE (ttl) < TYPE_VOLATILE (ttr); + const_parity |= (TYPE_READONLY (ttl) < TYPE_READONLY (ttr)); + volatile_parity |= (TYPE_VOLATILE (ttl) < TYPE_VOLATILE (ttr)); if (! left_const && (TYPE_READONLY (ttl) > TYPE_READONLY (ttr) @@ -6714,24 +6668,6 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) cp_warning ("\t`%T' != `%T'", type, rhstype); } } - else if (TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE) - { - /* When does this happen? */ - my_friendly_abort (119); - /* Conversion of a pointer-to-member type to void *. */ - rhs = build_unary_op (ADDR_EXPR, rhs, 0); - TREE_TYPE (rhs) = type; - return rhs; - } - else if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE) - { - /* When does this happen? */ - my_friendly_abort (120); - /* Conversion of a pointer-to-member type to void *. */ - rhs = build_unary_op (ADDR_EXPR, rhs, 0); - TREE_TYPE (rhs) = type; - return rhs; - } else { if (fndecl) @@ -6756,9 +6692,8 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) else cp_pedwarn ("%s to `%T' from `%T' lacks a cast", errtype, type, rhstype); - return convert (type, rhs); } - return null_pointer_node; + return convert (type, rhs); } else if (codel == INTEGER_TYPE && (coder == POINTER_TYPE @@ -6801,7 +6736,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) else if (ctt == 0) cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr); - /* compatible pointer to member functions. */ + /* compatible pointer to member functions. */ return build_ptrmemfunc (ttl, rhs, 0); } else if (codel == ERROR_MARK || coder == ERROR_MARK) @@ -6820,6 +6755,13 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) } else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs))) return 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 convert (type, rhs); cp_error ("%s to `%T' from `%T'", errtype, type, rhstype); return error_mark_node; @@ -6837,7 +6779,10 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) latter (X(X&)). If using constructor make sure no conversion operator exists, if one does - exist, an ambiguity exists. */ + 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; @@ -6892,12 +6837,6 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum) if (coder == ERROR_MARK) return error_mark_node; -#if 0 - /* This is *not* the quick way out! It is the way to disaster. */ - if (type == rhstype) - goto converted; -#endif - /* We accept references to incomplete types, so we can return here before checking if RHS is of complete type. */ @@ -6932,6 +6871,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum) 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); @@ -6939,6 +6880,9 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum) if (IS_AGGR_TYPE (type) && (TYPE_NEEDS_CONSTRUCTING (type) || TREE_HAS_CONSTRUCTOR (rhs))) { + if (flag_ansi_overloading) + return cp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags); + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)) { /* This is sufficient to perform initialization. No need, @@ -6947,7 +6891,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum) cleanups if it is used. */ if (TREE_CODE (rhs) == CALL_EXPR) { - rhs = build_cplus_new (type, rhs, 0); + rhs = build_cplus_new (type, rhs); return rhs; } /* Handle the case of default parameter initialization and @@ -6964,7 +6908,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum) = build_unary_op (ADDR_EXPR, exp, 0); } else - rhs = build_cplus_new (type, TREE_OPERAND (rhs, 0), 0); + rhs = build_cplus_new (type, TREE_OPERAND (rhs, 0)); return rhs; } else if (TYPE_HAS_TRIVIAL_INIT_REF (type)) @@ -6975,7 +6919,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum) { if (TYPE_HAS_INIT_REF (type)) { - tree init = build_method_call (exp, constructor_name_full (type), + tree init = build_method_call (exp, ctor_identifier, build_tree_list (NULL_TREE, rhs), TYPE_BINFO (type), LOOKUP_NORMAL); @@ -6984,7 +6928,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum) if (exp == 0) { - exp = build_cplus_new (type, init, 0); + exp = build_cplus_new (type, init); return exp; } @@ -7008,7 +6952,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum) return rhs; } - return convert (type, rhs); + return cp_convert (type, rhs, CONV_OLD_CONVERT, + flags | LOOKUP_NO_CONVERSION); } if (type == TREE_TYPE (rhs)) @@ -7097,8 +7042,6 @@ c_expand_return (retval) extern tree dtor_label, ctor_label; tree result = DECL_RESULT (current_function_decl); tree valtype = TREE_TYPE (result); - register int use_temp = 0; - int returns_value = 1; if (TREE_THIS_VOLATILE (current_function_decl)) warning ("function declared `noreturn' has a `return' statement"); @@ -7109,6 +7052,12 @@ c_expand_return (retval) return; } + if (processing_template_decl) + { + add_tree (build_min_nt (RETURN_STMT, retval)); + return; + } + if (retval == NULL_TREE) { /* A non-named return value does not count. */ @@ -7121,7 +7070,7 @@ c_expand_return (retval) } if (DECL_CONSTRUCTOR_P (current_function_decl)) - retval = current_class_decl; + retval = current_class_ptr; else if (DECL_NAME (result) != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE) retval = result; @@ -7146,22 +7095,28 @@ c_expand_return (retval) } } else if (DECL_CONSTRUCTOR_P (current_function_decl) - && retval != current_class_decl) + && retval != current_class_ptr) { - error ("return from a constructor: use `this = ...' instead"); - retval = current_class_decl; + if (flag_this_is_variable) + error ("return from a constructor: use `this = ...' instead"); + else + error ("return from a constructor"); + retval = current_class_ptr; } + /* Effective C++ rule 15. See also start_function. */ + if (extra_warnings + && 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; - /* We do this here so we'll avoid a warning about how the function - "may or may not return a value" in finish_function. */ - returns_value = 0; - - if (retval) + if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) pedwarn ("`return' with a value, in function returning void"); expand_return (retval); + return; } /* Add some useful error checking for C++. */ else if (TREE_CODE (valtype) == REFERENCE_TYPE) @@ -7178,9 +7133,9 @@ c_expand_return (retval) /* convert to reference now, so we can give error if we return an reference to a non-lvalue. */ - retval = convert_for_initialization (tmp_result, valtype, retval, - LOOKUP_NORMAL, "return", - NULL_TREE, 0); + retval = convert_for_initialization + (tmp_result, valtype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING, + "return", NULL_TREE, 0); /* Sort through common things to see what it is we are returning. */ @@ -7191,12 +7146,13 @@ c_expand_return (retval) if (TREE_CODE (whats_returned) == ADDR_EXPR) whats_returned = TREE_OPERAND (whats_returned, 0); } + if (TREE_CODE (whats_returned) == CONVERT_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) == NEW_EXPR - || TREE_CODE (whats_returned) == TARGET_EXPR - || TREE_CODE (whats_returned) == WITH_CLEANUP_EXPR) + || TREE_CODE (whats_returned) == TARGET_EXPR) { /* Get the target. */ whats_returned = TREE_OPERAND (whats_returned, 0); @@ -7209,7 +7165,8 @@ c_expand_return (retval) if (TEMP_NAME_P (DECL_NAME (whats_returned))) warning ("reference to non-lvalue returned"); else if (! TREE_STATIC (whats_returned) - && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))) + && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned)) + && !TREE_PUBLIC (whats_returned)) cp_warning_at ("reference to local variable `%D' returned", whats_returned); } } @@ -7220,9 +7177,19 @@ c_expand_return (retval) if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned) && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned)) - && !TREE_STATIC (whats_returned)) + && !TREE_STATIC (whats_returned) + && !TREE_PUBLIC (whats_returned)) cp_warning_at ("address of local variable `%D' returned", whats_returned); } + else if (TREE_CODE (retval) == VAR_DECL) + { + if (TREE_CODE (TREE_TYPE (retval)) == ARRAY_TYPE + && DECL_NAME (retval) + && IDENTIFIER_LOCAL_VALUE (DECL_NAME (retval)) + && !TREE_STATIC (retval) + && !TREE_PUBLIC (retval)) + cp_warning_at ("address of local array `%D' returned", retval); + } /* Now deal with possible C++ hair: (1) Compute the return value. @@ -7232,154 +7199,56 @@ c_expand_return (retval) (3) If an X(X&) constructor is defined, the return value must be returned via that. */ - /* If we're returning in a register, we can't initialize the - return value from a TARGET_EXPR. */ - if (TREE_CODE (retval) == TARGET_EXPR - && TYPE_MAIN_VARIANT (TREE_TYPE (retval)) == TYPE_MAIN_VARIANT (valtype) - && ! current_function_returns_struct) - retval = expand_target_expr (retval); - if (retval == result - /* Watch out for constructors, which "return" aggregates - via initialization, but which otherwise "return" a pointer. */ || DECL_CONSTRUCTOR_P (current_function_decl)) + /* It's already done for us. */; + else if (TREE_TYPE (retval) == void_type_node) { - /* This is just an error--it's already been reported. */ - if (TYPE_SIZE (valtype) == NULL_TREE) - return; - - if (TYPE_MODE (valtype) != BLKmode - && any_pending_cleanups (1)) - { - retval = get_temp_regvar (valtype, retval); - use_temp = obey_regdecls; - } - } - else if (IS_AGGR_TYPE (valtype) && current_function_returns_struct) - { - expand_aggr_init (result, retval, 0, LOOKUP_ONLYCONVERTING); - expand_cleanups_to (NULL_TREE); - DECL_INITIAL (result) = NULL_TREE; + pedwarn ("return of void value in function returning non-void"); + expand_expr_stmt (retval); retval = 0; } else { - if (TYPE_MODE (valtype) == VOIDmode) - { - if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode - && warn_return_type) - warning ("return of void value in function returning non-void"); - expand_expr_stmt (retval); - retval = 0; - result = 0; - } - else if (TYPE_MODE (valtype) != BLKmode - && any_pending_cleanups (1)) - { - retval = get_temp_regvar (valtype, retval); - expand_cleanups_to (NULL_TREE); - use_temp = obey_regdecls; - result = 0; - } - else + /* We already did this above for refs, don't do it again. */ + if (TREE_CODE (valtype) != REFERENCE_TYPE) + retval = convert_for_initialization + (NULL_TREE, valtype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING, + "return", NULL_TREE, 0); + + /* We can't initialize a register from a NEW_EXPR. */ + if (! current_function_returns_struct + && TREE_CODE (retval) == TARGET_EXPR + && TREE_CODE (TREE_OPERAND (retval, 1)) == NEW_EXPR) + retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval, + TREE_OPERAND (retval, 0)); + + if (retval == error_mark_node) { - retval = convert_for_initialization (result, valtype, retval, - LOOKUP_NORMAL, - "return", NULL_TREE, 0); - DECL_INITIAL (result) = NULL_TREE; + /* Avoid warning about control reaching end of function. */ + expand_null_return (); + return; } - if (retval == error_mark_node) - return; } - emit_queue (); - 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 (result) + if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK) { - /* Everything's great--RETVAL is in RESULT. */ - if (original_result_rtx) - { - store_expr (result, original_result_rtx, 0); - expand_cleanups_to (NULL_TREE); - } - else if (retval && retval != result) - { - /* Clear this out so the later call to decl_function_context - won't end up bombing on us. */ - if (DECL_CONTEXT (result) == error_mark_node) - DECL_CONTEXT (result) = NULL_TREE; - /* Here is where we finally get RETVAL into RESULT. - `expand_return' does the magic of protecting - RESULT from cleanups. */ - retval = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (result), - retval)); - /* This part _must_ come second, because expand_return looks for - the INIT_EXPR as the toplevel node only. :-( */ - retval = build (INIT_EXPR, TREE_TYPE (result), result, retval); - TREE_SIDE_EFFECTS (retval) = 1; - expand_return (retval); - } - else - expand_return (result); - - use_variable (DECL_RTL (result)); - if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK) - expand_goto (ctor_label); - else - expand_null_return (); + /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do. */ + expand_goto (ctor_label); } - else + + if (retval && retval != result) { - /* We may still need to put RETVAL into RESULT. */ - result = DECL_RESULT (current_function_decl); - if (original_result_rtx) - { - /* Here we have a named return value that went - into memory. We can compute RETVAL into that. */ - if (retval) - expand_assignment (result, retval, 0, 0); - else - store_expr (result, original_result_rtx, 0); - result = make_tree (TREE_TYPE (result), original_result_rtx); - } - else if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK) - { - /* Here RETVAL is CURRENT_CLASS_DECL, so there's nothing to do. */ - expand_goto (ctor_label); - } - else if (retval) - { - /* Here is where we finally get RETVAL into RESULT. - `expand_return' does the magic of protecting - RESULT from cleanups. */ - result = build (INIT_EXPR, TREE_TYPE (result), result, retval); - TREE_SIDE_EFFECTS (result) = 1; - expand_return (result); - } - else if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode) - expand_return (result); + result = build (INIT_EXPR, TREE_TYPE (result), result, retval); + TREE_SIDE_EFFECTS (result) = 1; } - - current_function_returns_value = returns_value; -#if 0 - /* These wind up after the BARRIER, which causes problems for - expand_end_binding. What purpose were they supposed to serve? */ - if (original_result_rtx) - use_variable (original_result_rtx); - if (use_temp) - use_variable (DECL_RTL (DECL_RESULT (current_function_decl))); -#endif - - /* One way to clear out cleanups that EXPR might - generate. Note that this code will really be - dead code, but that is ok--cleanups that were - needed were handled by the magic of `return'. */ - expand_cleanups_to (NULL_TREE); + expand_return (result); + current_function_returns_value = 1; } /* Start a C switch statement, testing expression EXP. @@ -7415,18 +7284,18 @@ c_expand_start_case (exp) } else { - tree index; + tree idx; exp = default_conversion (exp); type = TREE_TYPE (exp); - index = get_unwidened (exp, 0); + 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 (index))) - exp = index; + == TREE_UNSIGNED (TREE_TYPE (idx))) + exp = idx; } expand_start_case @@ -7438,7 +7307,8 @@ c_expand_start_case (exp) /* CONSTP remembers whether or not all the intervening pointers in the `to' type have been const. */ -int + +static int comp_ptr_ttypes_real (to, from, constp) tree to, from; int constp; @@ -7448,15 +7318,25 @@ comp_ptr_ttypes_real (to, from, constp) if (TREE_CODE (to) != TREE_CODE (from)) return 0; - if (TYPE_READONLY (from) > TYPE_READONLY (to) - || TYPE_VOLATILE (from) > TYPE_VOLATILE (to)) - return 0; + if (TREE_CODE (from) == OFFSET_TYPE + && comptypes (TYPE_OFFSET_BASETYPE (from), + TYPE_OFFSET_BASETYPE (to), 1)) + continue; - if (! constp - && (TYPE_READONLY (to) > TYPE_READONLY (from) - || TYPE_VOLATILE (to) > TYPE_READONLY (from))) - return 0; - constp &= TYPE_READONLY (to); + /* 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 (TYPE_READONLY (from) > TYPE_READONLY (to) + || TYPE_VOLATILE (from) > TYPE_VOLATILE (to)) + return 0; + + if (! constp + && (TYPE_READONLY (to) > TYPE_READONLY (from) + || TYPE_VOLATILE (to) > TYPE_READONLY (from))) + return 0; + constp &= TYPE_READONLY (to); + } if (TREE_CODE (to) != POINTER_TYPE) return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1); @@ -7466,9 +7346,92 @@ comp_ptr_ttypes_real (to, from, constp) /* 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), -1)) + continue; + + if (TREE_CODE (to) != POINTER_TYPE) + return comptypes + (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), -1); + } +} + +/* 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 + && comptypes (TYPE_OFFSET_BASETYPE (from), + TYPE_OFFSET_BASETYPE (to), 1)) + continue; + + if (TREE_CODE (to) != POINTER_TYPE) + return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1); + } +} + +/* 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); + + if (TREE_CODE (to) != TREE_CODE (from)) + return 1; + + /* 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 (TYPE_READONLY (from) > TYPE_READONLY (to) + || TYPE_VOLATILE (from) > TYPE_VOLATILE (to)) + return 0; + + if (! constp + && (TYPE_READONLY (to) > TYPE_READONLY (from) + || TYPE_VOLATILE (to) > TYPE_READONLY (from))) + return 0; + constp &= TYPE_READONLY (to); + } + + if (TREE_CODE (to) != POINTER_TYPE) + return 1; + } +}