diff options
Diffstat (limited to 'gcc/cp/typeck.c')
-rw-r--r-- | gcc/cp/typeck.c | 380 |
1 files changed, 190 insertions, 190 deletions
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 6ca524233d8..82867eba0b3 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -285,7 +285,7 @@ commonparms (p1, p2) if (TREE_VALUE (p1) != TREE_VALUE (p2)) { any_change = 1; - TREE_VALUE (n) = common_type (TREE_VALUE (p1), TREE_VALUE (p2)); + TREE_VALUE (n) = merge_types (TREE_VALUE (p1), TREE_VALUE (p2)); } else TREE_VALUE (n) = TREE_VALUE (p1); @@ -330,16 +330,38 @@ type_after_usual_arithmetic_conversions (t1, t2) /* FIXME: Attributes. */ my_friendly_assert (ARITHMETIC_TYPE_P (t1) + || TREE_CODE (t1) == COMPLEX_TYPE || TREE_CODE (t1) == ENUMERAL_TYPE, 19990725); my_friendly_assert (ARITHMETIC_TYPE_P (t2) + || TREE_CODE (t2) == COMPLEX_TYPE || TREE_CODE (t2) == ENUMERAL_TYPE, 19990725); - /* In what follows, we slightly generalize the rules given in [expr] - so as to deal with `long long'. First, merge the attributes. */ + /* In what follows, we slightly generalize the rules given in [expr] so + as to deal with `long long' and `complex'. First, merge the + attributes. */ attributes = (*targetm.merge_type_attributes) (t1, t2); + /* If one type is complex, form the common type of the non-complex + components, then make that complex. Use T1 or T2 if it is the + required type. */ + if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) + { + tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1; + tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2; + tree subtype + = type_after_usual_arithmetic_conversions (subtype1, subtype2); + + if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype) + return build_type_attribute_variant (t1, attributes); + else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype) + return build_type_attribute_variant (t2, attributes); + else + return build_type_attribute_variant (build_complex_type (subtype), + attributes); + } + /* If only one is real, use it as the result. */ if (code1 == REAL_TYPE && code2 != REAL_TYPE) return build_type_attribute_variant (t1, attributes); @@ -359,6 +381,10 @@ type_after_usual_arithmetic_conversions (t1, t2) else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1)) return build_type_attribute_variant (t2, attributes); + /* The types are the same; no need to do anything fancy. */ + if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) + return build_type_attribute_variant (t1, attributes); + if (code1 != REAL_TYPE) { /* If one is a sizetype, use it so size_binop doesn't blow up. */ @@ -420,9 +446,17 @@ type_after_usual_arithmetic_conversions (t1, t2) || same_type_p (TYPE_MAIN_VARIANT (t2), double_type_node)) return build_type_attribute_variant (double_type_node, attributes); - else + if (same_type_p (TYPE_MAIN_VARIANT (t1), float_type_node) + || same_type_p (TYPE_MAIN_VARIANT (t2), float_type_node)) return build_type_attribute_variant (float_type_node, attributes); + + /* Two floating-point types whose TYPE_MAIN_VARIANTs are none of + the standard C++ floating-point types. Logic earlier in this + function has already eliminated the possibility that + TYPE_PRECISION (t2) != TYPE_PRECISION (t1), so there's no + compelling reason to choose one or the other. */ + return build_type_attribute_variant (t1, attributes); } } @@ -439,6 +473,7 @@ composite_pointer_type (t1, t2, arg1, arg2, location) const char* location; { tree result_type; + tree attributes; /* [expr.rel] @@ -456,6 +491,9 @@ composite_pointer_type (t1, t2, arg1, arg2, location) if (TYPE_PTRMEMFUNC_P (t2)) t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2); + /* Merge the attributes. */ + attributes = (*targetm.merge_type_attributes) (t1, t2); + /* We have: [expr.rel] @@ -504,21 +542,18 @@ composite_pointer_type (t1, t2, arg1, arg2, location) } } - return result_type; + return build_type_attribute_variant (result_type, attributes); } -/* Return the common type of two types. +/* Return the merged type of two types. We assume that comptypes has already been done and returned 1; if that isn't so, this may crash. - This is the type for the result of most arithmetic operations - if the operands have the given two types. - - We do not deal with enumeral types here because they have already been - converted to integer types. */ + This just combines attributes and default arguments; any other + differences would cause the two types to compare unalike. */ tree -common_type (t1, t2) +merge_types (t1, t2) tree t1, t2; { register enum tree_code code1; @@ -528,9 +563,7 @@ common_type (t1, t2) /* Save time if the two types are the same. */ if (t1 == t2) return t1; - t1 = original_type (t1); - t2 = original_type (t2); - if (t1 == t2) + if (original_type (t1) == original_type (t2)) return t1; /* If one type is nonsense, use the other. */ @@ -539,20 +572,11 @@ common_type (t1, t2) if (t2 == error_mark_node) return t1; - if ((ARITHMETIC_TYPE_P (t1) || TREE_CODE (t1) == ENUMERAL_TYPE) - && (ARITHMETIC_TYPE_P (t2) || TREE_CODE (t2) == ENUMERAL_TYPE)) - return type_after_usual_arithmetic_conversions (t1, t2); - /* Merge the attributes. */ attributes = (*targetm.merge_type_attributes) (t1, t2); /* Treat an enum type as the unsigned integer type of the same width. */ - if (TREE_CODE (t1) == ENUMERAL_TYPE) - t1 = type_for_size (TYPE_PRECISION (t1), 1); - if (TREE_CODE (t2) == ENUMERAL_TYPE) - t2 = type_for_size (TYPE_PRECISION (t2), 1); - if (TYPE_PTRMEMFUNC_P (t1)) t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1); if (TYPE_PTRMEMFUNC_P (t2)) @@ -561,88 +585,21 @@ common_type (t1, t2) code1 = TREE_CODE (t1); code2 = TREE_CODE (t2); - /* If one type is complex, form the common type of the non-complex - components, then make that complex. Use T1 or T2 if it is the - required type. */ - if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) - { - tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1; - tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2; - tree subtype = common_type (subtype1, subtype2); - - if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype) - return build_type_attribute_variant (t1, attributes); - else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype) - return build_type_attribute_variant (t2, attributes); - else - return build_type_attribute_variant (build_complex_type (subtype), - attributes); - } - switch (code1) { - case INTEGER_TYPE: - case REAL_TYPE: - /* We should have called type_after_usual_arithmetic_conversions - above. */ - abort (); - break; - case POINTER_TYPE: case REFERENCE_TYPE: - /* For two pointers, do this recursively on the target type, - and combine the qualifiers of the two types' targets. */ - /* This code was turned off; I don't know why. - But ISO C++ specifies doing this with the qualifiers. - So I turned it on again. */ + /* For two pointers, do this recursively on the target type. */ { - tree tt1 = TREE_TYPE (t1); - tree tt2 = TREE_TYPE (t2); - tree b1, b2; - int type_quals; - tree target; - - if (TREE_CODE (tt1) == OFFSET_TYPE) - { - b1 = TYPE_OFFSET_BASETYPE (tt1); - b2 = TYPE_OFFSET_BASETYPE (tt2); - tt1 = TREE_TYPE (tt1); - tt2 = TREE_TYPE (tt2); - } - else - b1 = b2 = NULL_TREE; - - type_quals = (cp_type_quals (tt1) | cp_type_quals (tt2)); - tt1 = TYPE_MAIN_VARIANT (tt1); - tt2 = TYPE_MAIN_VARIANT (tt2); - - if (tt1 == tt2) - target = tt1; - else if (VOID_TYPE_P (tt1) || VOID_TYPE_P (tt2)) - target = void_type_node; - else if (tt1 == unknown_type_node) - target = tt2; - else if (tt2 == unknown_type_node) - target = tt1; - else - target = common_type (tt1, tt2); - - target = cp_build_qualified_type (target, type_quals); - - if (b1) - { - if (same_type_p (b1, b2) - || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))) - target = build_offset_type (b2, target); - else if (binfo_or_else (b2, b1)) - target = build_offset_type (b1, target); - } + tree target = merge_types (TREE_TYPE (t1), TREE_TYPE (t2)); + int quals = cp_type_quals (t1); if (code1 == POINTER_TYPE) t1 = build_pointer_type (target); else t1 = build_reference_type (target); t1 = build_type_attribute_variant (t1, attributes); + t1 = cp_build_qualified_type (t1, quals); if (TREE_CODE (target) == METHOD_TYPE) t1 = build_ptrmemfunc_type (t1); @@ -650,9 +607,17 @@ common_type (t1, t2) return t1; } + case OFFSET_TYPE: + { + tree base = TYPE_OFFSET_BASETYPE (t1); + tree target = merge_types (TREE_TYPE (t1), TREE_TYPE (t2)); + t1 = build_offset_type (base, target); + break; + } + case ARRAY_TYPE: { - tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2)); + tree elt = merge_types (TREE_TYPE (t1), TREE_TYPE (t2)); /* Save space: see if the result is identical to one of the args. */ if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1)) return build_type_attribute_variant (t1, attributes); @@ -661,14 +626,14 @@ common_type (t1, t2) /* Merge the element types, and have a size if either arg has one. */ t1 = build_cplus_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2)); - return build_type_attribute_variant (t1, attributes); + break; } case FUNCTION_TYPE: /* Function types: prefer the one that specified arg types. If both do, merge the arg types. Also merge the return types. */ { - tree valtype = common_type (TREE_TYPE (t1), TREE_TYPE (t2)); + tree valtype = merge_types (TREE_TYPE (t1), TREE_TYPE (t2)); tree p1 = TYPE_ARG_TYPES (t1); tree p2 = TYPE_ARG_TYPES (t2); tree rval, raises; @@ -697,73 +662,72 @@ common_type (t1, t2) } rval = build_function_type (valtype, commonparms (p1, p2)); - rval = build_exception_variant (rval, raises); - return build_type_attribute_variant (rval, attributes); + t1 = build_exception_variant (rval, raises); + break; } - case RECORD_TYPE: - case UNION_TYPE: - t1 = TYPE_MAIN_VARIANT (t1); - t2 = TYPE_MAIN_VARIANT (t2); + case METHOD_TYPE: + { + /* Get this value the long way, since TYPE_METHOD_BASETYPE + is just the main variant of this. */ + tree basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2))); + tree raises = TYPE_RAISES_EXCEPTIONS (t1); + tree t3; + + /* If this was a member function type, get back to the + original type of type member function (i.e., without + the class instance variable up front. */ + t1 = build_function_type (TREE_TYPE (t1), + TREE_CHAIN (TYPE_ARG_TYPES (t1))); + t2 = build_function_type (TREE_TYPE (t2), + TREE_CHAIN (TYPE_ARG_TYPES (t2))); + t3 = merge_types (t1, t2); + t3 = build_cplus_method_type (basetype, TREE_TYPE (t3), + TYPE_ARG_TYPES (t3)); + t1 = build_exception_variant (t3, raises); + break; + } - if (DERIVED_FROM_P (t1, t2) && binfo_or_else (t1, t2)) - return build_type_attribute_variant (t1, attributes); - else if (binfo_or_else (t2, t1)) - return build_type_attribute_variant (t2, attributes); - else - { - compiler_error ("common_type called with uncommon aggregate types"); - return error_mark_node; - } + default:; + } + return build_type_attribute_variant (t1, attributes); +} - case METHOD_TYPE: - if (TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2))) - { - /* Get this value the long way, since TYPE_METHOD_BASETYPE - is just the main variant of this. */ - tree basetype; - tree raises, t3; +/* Return the common type of two types. + We assume that comptypes has already been done and returned 1; + if that isn't so, this may crash. - tree b1 = TYPE_OFFSET_BASETYPE (t1); - tree b2 = TYPE_OFFSET_BASETYPE (t2); + This is the type for the result of most arithmetic operations + if the operands have the given two types. */ - if (same_type_p (b1, b2) - || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))) - basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2))); - else - { - if (binfo_or_else (b2, b1) == NULL_TREE) - compiler_error ("common_type called with uncommon method types"); - basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1))); - } +tree +common_type (t1, t2) + tree t1, t2; +{ + enum tree_code code1; + enum tree_code code2; - raises = TYPE_RAISES_EXCEPTIONS (t1); - - /* If this was a member function type, get back to the - original type of type member function (i.e., without - the class instance variable up front. */ - t1 = build_function_type (TREE_TYPE (t1), - TREE_CHAIN (TYPE_ARG_TYPES (t1))); - t2 = build_function_type (TREE_TYPE (t2), - TREE_CHAIN (TYPE_ARG_TYPES (t2))); - t3 = common_type (t1, t2); - t3 = build_cplus_method_type (basetype, TREE_TYPE (t3), - TYPE_ARG_TYPES (t3)); - t1 = build_exception_variant (t3, raises); - } - else - compiler_error ("common_type called with uncommon method types"); + /* If one type is nonsense, bail. */ + if (t1 == error_mark_node || t2 == error_mark_node) + return error_mark_node; - return build_type_attribute_variant (t1, attributes); + code1 = TREE_CODE (t1); + code2 = TREE_CODE (t2); - case OFFSET_TYPE: - /* Pointers to members should now be handled by the POINTER_TYPE - case above. */ - abort (); + if ((ARITHMETIC_TYPE_P (t1) || code1 == ENUMERAL_TYPE + || code1 == COMPLEX_TYPE) + && (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE + || code2 == COMPLEX_TYPE)) + return type_after_usual_arithmetic_conversions (t1, t2); - default: - return build_type_attribute_variant (t1, attributes); - } + else if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2)) + || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2)) + || (TYPE_PTRMEMFUNC_P (t1) && TYPE_PTRMEMFUNC_P (t2))) + return composite_pointer_type (t1, t2, error_mark_node, error_mark_node, + "conversion"); + + else + abort (); } /* Compare two exception specifier types for exactness or subsetness, if @@ -1037,20 +1001,6 @@ comptypes (t1, t2, strict) && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)); break; - case METHOD_TYPE: - if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1), - TYPE_RAISES_EXCEPTIONS (t2), 1)) - return 0; - - /* This case is anti-symmetrical! - One can pass a base member (or member function) - to something expecting a derived member (or member function), - but not vice-versa! */ - - val = (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict) - && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))); - break; - case POINTER_TYPE: case REFERENCE_TYPE: t1 = TREE_TYPE (t1); @@ -1065,11 +1015,8 @@ comptypes (t1, t2, strict) goto look_hard; break; + case METHOD_TYPE: case FUNCTION_TYPE: - if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1), - TYPE_RAISES_EXCEPTIONS (t2), 1)) - return 0; - val = ((TREE_TYPE (t1) == TREE_TYPE (t2) || comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)) && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))); @@ -1597,7 +1544,7 @@ c_sizeof (type) TYPE_IS_SIZETYPE means that certain things (like overflow) will never happen. However, this node should really have type `size_t', which is just a typedef for an ordinary integer type. */ - size = fold (build1 (NOP_EXPR, c_size_type_node, size)); + size = fold (build1 (NOP_EXPR, size_type_node, size)); my_friendly_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (size)), 20001021); return size; @@ -1666,7 +1613,7 @@ c_sizeof_nowarn (type) TYPE_IS_SIZETYPE means that certain things (like overflow) will never happen. However, this node should really have type `size_t', which is just a typedef for an ordinary integer type. */ - size = fold (build1 (NOP_EXPR, c_size_type_node, size)); + size = fold (build1 (NOP_EXPR, size_type_node, size)); my_friendly_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (size)), 20001021); return size; @@ -2926,19 +2873,18 @@ get_member_function_from_ptrfunc (instance_ptrptr, function) load-with-sign-extend, while the second used normal load then shift to sign-extend. An optimizer flaw, perhaps, but it's easier to make this change. */ + idx = cp_build_binary_op (TRUNC_DIV_EXPR, + build1 (NOP_EXPR, vtable_index_type, e3), + TYPE_SIZE_UNIT (vtable_entry_type)); switch (TARGET_PTRMEMFUNC_VBIT_LOCATION) { case ptrmemfunc_vbit_in_pfn: - idx = cp_build_binary_op (TRUNC_DIV_EXPR, - build1 (NOP_EXPR, vtable_index_type, e3), - TYPE_SIZE_UNIT (vtable_entry_type)); e1 = cp_build_binary_op (BIT_AND_EXPR, build1 (NOP_EXPR, vtable_index_type, e3), integer_one_node); break; case ptrmemfunc_vbit_in_delta: - idx = build1 (NOP_EXPR, vtable_index_type, e3); e1 = cp_build_binary_op (BIT_AND_EXPR, delta, integer_one_node); delta = cp_build_binary_op (RSHIFT_EXPR, @@ -4076,8 +4022,14 @@ cp_pointer_int_sum (resultcode, ptrop, intop) enum tree_code resultcode; register tree ptrop, intop; { - if (!complete_type_or_else (TREE_TYPE (ptrop), ptrop)) - return error_mark_node; + tree res_type = TREE_TYPE (ptrop); + + /* pointer_int_sum() uses size_in_bytes() on the TREE_TYPE(res_type) + in certain circumstance (when it's valid to do so). So we need + to make sure it's complete. We don't need to check here, if we + can actually complete it at all, as those checks will be done in + pointer_int_sum() anyway. */ + complete_type (TREE_TYPE (res_type)); return pointer_int_sum (resultcode, ptrop, fold (intop)); } @@ -4215,6 +4167,25 @@ build_x_unary_op (code, xarg) } if (code == ADDR_EXPR) { + /* A pointer to member-function can be formed only by saying + &X::mf. */ + if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE + && (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg))) + { + if (TREE_CODE (xarg) != OFFSET_REF) + { + error ("invalid use of '%E' to form a pointer-to-member-function. Use a qualified-id.", + xarg); + return error_mark_node; + } + else + { + error ("parenthesis around '%E' cannot be used to form a pointer-to-member-function", + xarg); + PTRMEM_OK_P (xarg) = 1; + } + } + if (TREE_CODE (xarg) == OFFSET_REF) { ptrmem = PTRMEM_OK_P (xarg); @@ -4854,9 +4825,6 @@ mark_addressable (exp) { register tree x = exp; - if (TREE_ADDRESSABLE (x) == 1) - return 1; - while (1) switch (TREE_CODE (x)) { @@ -4875,6 +4843,8 @@ mark_addressable (exp) TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */ return 1; } + /* FALLTHRU */ + case VAR_DECL: /* Caller should not be trying to mark initialized constant fields addressable. */ @@ -4882,6 +4852,7 @@ mark_addressable (exp) || DECL_IN_AGGR_P (x) == 0 || TREE_STATIC (x) || DECL_EXTERNAL (x), 314); + /* FALLTHRU */ case CONST_DECL: case RESULT_DECL: @@ -4890,6 +4861,7 @@ mark_addressable (exp) warning ("address requested for `%D', which is declared `register'", x); TREE_ADDRESSABLE (x) = 1; + put_var_into_stack (x); return 1; case FUNCTION_DECL: @@ -5072,6 +5044,22 @@ build_static_cast (type, expr) && kind != bk_via_virtual) ok = 1; } + else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) + { + /* They're pointers to members. The pointed to objects must be + the same (ignoring CV qualifiers), and the containing classes + must be related non-virtually. */ + base_kind kind; + + if (same_type_p + (strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (type))), + strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (intype)))) + && (lookup_base (TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)), + TYPE_OFFSET_BASETYPE (TREE_TYPE (type)), + ba_ignore | ba_quiet, &kind)) + && kind != bk_via_virtual) + ok = 1; + } else if (TREE_CODE (intype) != BOOLEAN_TYPE && TREE_CODE (type) != ARRAY_TYPE && TREE_CODE (type) != FUNCTION_TYPE @@ -5481,7 +5469,10 @@ build_modify_expr (lhs, modifycode, rhs) so the code to compute it is only emitted once. */ tree cond; - rhs = save_expr (rhs); + if (lvalue_p (rhs)) + rhs = stabilize_reference (rhs); + else + rhs = save_expr (rhs); /* Check this here to avoid odd errors when trying to convert a throw to the type of the COND_EXPR. */ @@ -5688,15 +5679,16 @@ build_modify_expr (lhs, modifycode, rhs) { int from_array; - if (!same_or_base_type_p (lhstype, TREE_TYPE (rhs))) + if (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype), + TYPE_MAIN_VARIANT (TREE_TYPE (rhs)))) { error ("incompatible types in assignment of `%T' to `%T'", - TREE_TYPE (rhs), lhstype); + TREE_TYPE (rhs), lhstype); return error_mark_node; } /* Allow array assignment in compiler-generated code. */ - if (pedantic && ! DECL_ARTIFICIAL (current_function_decl)) + if (! DECL_ARTIFICIAL (current_function_decl)) pedwarn ("ISO C++ forbids assignment of arrays"); from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE @@ -6203,8 +6195,16 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum) /* Simplify the RHS if possible. */ if (TREE_CODE (rhs) == CONST_DECL) rhs = DECL_INITIAL (rhs); - else if (coder != ARRAY_TYPE) - rhs = decl_constant_value (rhs); + + /* We do not use decl_constant_value here because of this case: + + const char* const s = "s"; + + The conversion rules for a string literal are more lax than for a + variable; in particular, a string literal can be converted to a + "char *" but the variable "s" cannot be converted in the same + way. If the conversion is allowed, the optimization should be + performed while creating the converted expression. */ /* [expr.ass] |