#include "tree.h"
#include "rtl.h"
#include "cp-tree.h"
+#include "tm_p.h"
#include "flags.h"
#include "output.h"
#include "expr.h"
#include "toplev.h"
+#include "defaults.h"
static tree convert_for_assignment PROTO((tree, tree, const char *, tree,
int));
static int comp_ptr_ttypes_real PROTO((tree, tree, int));
static int comp_ptr_ttypes_const PROTO((tree, tree));
static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
+static int comp_except_types PROTO((tree, tree, int));
static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
tree, int));
static tree common_base_type PROTO((tree, tree));
static tree qualify_type PROTO((tree, tree));
static tree get_delta_difference PROTO((tree, tree, int));
static int comp_cv_target_types PROTO((tree, tree, int));
+static void casts_away_constness_r PROTO((tree *, tree *));
+static int casts_away_constness PROTO ((tree, tree));
+static void maybe_warn_about_returning_address_of_local PROTO ((tree));
-/* Return the target type of TYPE, which meas return T for:
+/* Return the target type of TYPE, which means return T for:
T*, T&, T[], T (...), and otherwise, just T. */
tree
/* First, detect a valid value with a complete type. */
if (TYPE_SIZE (type) != 0
- && TYPE_SIZE (type) != size_zero_node
- && ! (TYPE_LANG_SPECIFIC (type)
- && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))
- && TYPE_SIZE (SIGNATURE_TYPE (type)) == 0))
+ && TYPE_SIZE (type) != size_zero_node)
return value;
/* If we see X::Y, we build an OFFSET_TYPE which has
return error_mark_node;
}
-/* Makes sure EXPR is a complete type when used in a void context, like a
- whole expression, or lhs of a comma operator. Issue a diagnostic and
- return error_mark_node on failure. This is a little tricky, because some
- valid void types look stunningly similar to invalid void types. We err on
- the side of caution */
-
-tree
-require_complete_type_in_void (expr)
- tree expr;
-{
- switch (TREE_CODE (expr))
- {
- case COND_EXPR:
- {
- tree op;
-
- op = TREE_OPERAND (expr,2);
- op = require_complete_type_in_void (op);
- TREE_OPERAND (expr,2) = op;
- if (op == error_mark_node)
- {
- expr = op;
- break;
- }
-
- /* fallthrough */
- }
-
- case COMPOUND_EXPR:
- {
- tree op;
-
- op = TREE_OPERAND (expr,1);
- op = require_complete_type_in_void (op);
- TREE_OPERAND (expr,1) = op;
- if (op == error_mark_node)
- {
- expr = op;
- break;
- }
-
- break;
- }
-
- case NON_LVALUE_EXPR:
- case NOP_EXPR:
- {
- tree op;
-
- op = TREE_OPERAND (expr,0);
- op = require_complete_type_in_void (op);
- TREE_OPERAND (expr,0) = op;
- if (op == error_mark_node)
- {
- expr = op;
- break;
- }
- break;
- }
-
- case CALL_EXPR: /* function call return can be ignored */
- case RTL_EXPR: /* RTL nodes have no value */
- case DELETE_EXPR: /* delete expressions have no type */
- case VEC_DELETE_EXPR:
- case INTEGER_CST: /* used for null pointer */
- case EXIT_EXPR: /* have no return */
- case LOOP_EXPR: /* have no return */
- case BIND_EXPR: /* have no return */
- case THROW_EXPR: /* have no return */
- case MODIFY_EXPR: /* sometimes this has a void type, but that's ok */
- case CONVERT_EXPR: /* sometimes has a void type */
- break;
-
- case INDIRECT_REF:
- {
- tree op = TREE_OPERAND (expr,0);
-
- /* Calling a function returning a reference has an implicit
- dereference applied. We don't want to make that an error. */
- if (TREE_CODE (op) == CALL_EXPR
- && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
- break;
- /* else fallthrough */
- }
-
- default:
- expr = require_complete_type (expr);
- break;
- }
-
- return expr;
-}
-
/* Try to complete TYPE, if it is incomplete. For example, if TYPE is
a template instantiation, do the instantiation. Returns TYPE,
whether or not it could be completed, unless something goes
return t;
}
+/* T1 and T2 are arithmetic or enumeration types. Return the type
+ that will result from the "usual arithmetic converions" on T1 and
+ T2 as described in [expr]. */
+
+tree
+type_after_usual_arithmetic_conversions (t1, t2)
+ tree t1;
+ tree t2;
+{
+ enum tree_code code1 = TREE_CODE (t1);
+ enum tree_code code2 = TREE_CODE (t2);
+ tree attributes;
+
+ /* FIXME: Attributes. */
+ my_friendly_assert (ARITHMETIC_TYPE_P (t1)
+ || TREE_CODE (t1) == ENUMERAL_TYPE,
+ 19990725);
+ my_friendly_assert (ARITHMETIC_TYPE_P (t2)
+ || 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. */
+ attributes = merge_machine_type_attributes (t1, t2);
+
+ /* If only one is real, use it as the result. */
+ if (code1 == REAL_TYPE && code2 != REAL_TYPE)
+ return build_type_attribute_variant (t1, attributes);
+ if (code2 == REAL_TYPE && code1 != REAL_TYPE)
+ return build_type_attribute_variant (t2, attributes);
+
+ /* Perform the integral promotions. */
+ if (code1 != REAL_TYPE)
+ {
+ t1 = type_promotes_to (t1);
+ t2 = type_promotes_to (t2);
+ }
+
+ /* Both real or both integers; use the one with greater precision. */
+ if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
+ return build_type_attribute_variant (t1, attributes);
+ else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
+ return build_type_attribute_variant (t2, attributes);
+
+ if (code1 != REAL_TYPE)
+ {
+ /* If one is unsigned long long, then convert the other to unsigned
+ long long. */
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_unsigned_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_long_unsigned_type_node))
+ return build_type_attribute_variant (long_long_unsigned_type_node,
+ attributes);
+ /* If one is a long long, and the other is an unsigned long, and
+ long long can represent all the values of an unsigned long, then
+ convert to a long long. Otherwise, convert to an unsigned long
+ long. Otherwise, if either operand is long long, convert the
+ other to long long.
+
+ Since we're here, we know the TYPE_PRECISION is the same;
+ therefore converting to long long cannot represent all the values
+ of an unsigned long, so we choose unsigned long long in that
+ case. */
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_integer_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_long_integer_type_node))
+ {
+ tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+ ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+ return build_type_attribute_variant (t, attributes);
+ }
+
+ /* Go through the same procedure, but for longs. */
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_unsigned_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_unsigned_type_node))
+ return build_type_attribute_variant (long_unsigned_type_node,
+ attributes);
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_integer_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_integer_type_node))
+ {
+ tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+ ? long_unsigned_type_node : long_integer_type_node);
+ return build_type_attribute_variant (t, attributes);
+ }
+ /* Otherwise prefer the unsigned one. */
+ if (TREE_UNSIGNED (t1))
+ return build_type_attribute_variant (t1, attributes);
+ else
+ return build_type_attribute_variant (t2, attributes);
+ }
+ else
+ {
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_double_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_double_type_node))
+ return build_type_attribute_variant (long_double_type_node,
+ attributes);
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), double_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), double_type_node))
+ return build_type_attribute_variant (double_type_node,
+ attributes);
+ else
+ return build_type_attribute_variant (float_type_node,
+ attributes);
+ }
+}
+
+/* Return the composite pointer type (see [expr.rel]) for T1 and T2.
+ ARG1 and ARG2 are the values with those types. The LOCATION is a
+ string describing the current location, in case an error occurs. */
+
+tree
+composite_pointer_type (t1, t2, arg1, arg2, location)
+ tree t1;
+ tree t2;
+ tree arg1;
+ tree arg2;
+ const char* location;
+{
+ tree result_type;
+
+ /* [expr.rel]
+
+ If one operand is a null pointer constant, the composite pointer
+ type is the type of the other operand. */
+ if (null_ptr_cst_p (arg1))
+ return t2;
+ if (null_ptr_cst_p (arg2))
+ return t1;
+
+ /* Deal with pointer-to-member functions in the same way as we deal
+ with pointers to functions. */
+ if (TYPE_PTRMEMFUNC_P (t1))
+ t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+ if (TYPE_PTRMEMFUNC_P (t2))
+ t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
+ if (comp_target_types (t1, t2, 1))
+ result_type = common_type (t1, t2);
+ else if (TYPE_MAIN_VARIANT (TREE_TYPE (t1)) == void_type_node)
+ {
+ if (pedantic && TREE_CODE (t2) == FUNCTION_TYPE)
+ pedwarn ("ANSI C++ forbids %s between `void *' and function pointer",
+ location);
+ result_type = qualify_type (t1, t2);
+ }
+ else if (TYPE_MAIN_VARIANT (TREE_TYPE (t2)) == void_type_node)
+ {
+ if (pedantic && TREE_CODE (t1) == FUNCTION_TYPE)
+ pedwarn ("ANSI C++ forbids %s between `void *' and function pointer",
+ location);
+ result_type = qualify_type (t2, t1);
+ }
+ /* C++ */
+ else if (same_or_base_type_p (t2, t1))
+ result_type = t2;
+ else if (IS_AGGR_TYPE (TREE_TYPE (t1))
+ && IS_AGGR_TYPE (TREE_TYPE (t2))
+ && (result_type = common_base_type (TREE_TYPE (t1),
+ TREE_TYPE (t2))))
+ {
+ if (result_type == error_mark_node)
+ {
+ cp_error ("common base type of types `%T' and `%T' is ambiguous",
+ TREE_TYPE (t1), TREE_TYPE (t2));
+ result_type = ptr_type_node;
+ }
+ else
+ {
+ if (pedantic
+ && result_type != TREE_TYPE (t1)
+ && result_type != TREE_TYPE (t2))
+ cp_pedwarn ("`%T' and `%T' converted to `%T *' in %s",
+ t1, t2, result_type, location);
+
+ result_type = build_pointer_type (result_type);
+ }
+ }
+ else
+ {
+ cp_pedwarn ("pointer type mismatch in %s", location);
+ result_type = ptr_type_node;
+ }
+
+ return result_type;
+}
+
/* 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.
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 = merge_machine_type_attributes (t1, t2);
- { register tree a1, a2;
- a1 = TYPE_ATTRIBUTES (t1);
- a2 = TYPE_ATTRIBUTES (t2);
-
- /* Either one unset? Take the set one. */
-
- if (!(attributes = a1))
- attributes = a2;
-
- /* One that completely contains the other? Take it. */
-
- else if (a2 && !attribute_list_contained (a1, a2))
- {
- if (attribute_list_contained (a2, a1))
- attributes = a2;
- else
- {
- /* Pick the longest list, and hang on the other list. */
- /* ??? For the moment we punt on the issue of attrs with args. */
-
- if (list_length (a1) < list_length (a2))
- attributes = a2, a2 = a1;
-
- for (; a2; a2 = TREE_CHAIN (a2))
- if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
- attributes) == NULL_TREE)
- {
- a1 = copy_node (a2);
- TREE_CHAIN (a1) = attributes;
- attributes = a1;
- }
- }
- }
- }
-
/* Treat an enum type as the unsigned integer type of the same width. */
if (TREE_CODE (t1) == ENUMERAL_TYPE)
{
case INTEGER_TYPE:
case REAL_TYPE:
- /* If only one is real, use it as the result. */
-
- if (code1 == REAL_TYPE && code2 != REAL_TYPE)
- return build_type_attribute_variant (t1, attributes);
-
- if (code2 == REAL_TYPE && code1 != REAL_TYPE)
- return build_type_attribute_variant (t2, attributes);
-
- /* Both real or both integers; use the one with greater precision. */
-
- if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
- return build_type_attribute_variant (t1, attributes);
- else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
- return build_type_attribute_variant (t2, attributes);
-
- /* Same precision. Prefer longs to ints even when same size. */
-
- if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
- || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
- return build_type_attribute_variant (long_unsigned_type_node,
- attributes);
-
- if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
- || TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
- {
- /* But preserve unsignedness from the other type,
- since long cannot hold all the values of an unsigned int. */
- if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
- t1 = long_unsigned_type_node;
- else
- t1 = long_integer_type_node;
- return build_type_attribute_variant (t1, attributes);
- }
-
- if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
- || TYPE_MAIN_VARIANT (t2) == long_double_type_node)
- return build_type_attribute_variant (long_double_type_node,
- attributes);
-
- /* Otherwise prefer the unsigned one. */
-
- if (TREE_UNSIGNED (t1))
- return build_type_attribute_variant (t1, attributes);
- else
- return build_type_attribute_variant (t2, attributes);
+ /* We should have called type_after_usual_arithmetic_conversions
+ above. */
+ my_friendly_abort (19990725);
+ break;
case POINTER_TYPE:
case REFERENCE_TYPE:
if (tt1 == tt2)
target = tt1;
- else if (b1)
- {
- compiler_error ("common_type called with uncommon member types");
- target = tt1;
- }
else if (tt1 == void_type_node || tt2 == void_type_node)
target = void_type_node;
else if (tt1 == unknown_type_node)
}
}
\f
-/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */
+/* Compare two exception specifier types for exactness or subsetness, if
+ allowed. Returns 0 for mismatch, 1 for same, 2 if B is allowed by A.
+
+ [except.spec] "If a class X ... objects of class X or any class publicly
+ and unambigously derrived from X. Similarly, if a pointer type Y * ...
+ exceptions of type Y * or that are pointers to any type publicly and
+ unambigously derrived from Y. Otherwise a function only allows exceptions
+ that have the same type ..."
+ This does not mention cv qualifiers and is different to what throw
+ [except.throw] and catch [except.catch] will do. They will ignore the
+ top level cv qualifiers, and allow qualifiers in the pointer to class
+ example.
+
+ We implement the letter of the standard. */
+
+static int
+comp_except_types (a, b, exact)
+ tree a, b;
+ int exact;
+{
+ if (same_type_p (a, b))
+ return 1;
+ else if (!exact)
+ {
+ if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+ return 0;
+
+ if (TREE_CODE (a) == POINTER_TYPE
+ && TREE_CODE (b) == POINTER_TYPE)
+ {
+ a = TREE_TYPE (a);
+ b = TREE_TYPE (b);
+ if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+ return 0;
+ }
+
+ if (TREE_CODE (a) != RECORD_TYPE
+ || TREE_CODE (b) != RECORD_TYPE)
+ return 0;
+
+ if (ACCESSIBLY_UNIQUELY_DERIVED_P (a, b))
+ return 2;
+ }
+ return 0;
+}
+
+/* Return 1 if TYPE1 and TYPE2 are equivalent exception specifiers.
+ If EXACT is 0, T2 can be a subset of T1 (according to 15.4/7),
+ otherwise it must be exact. Exception lists are unordered, but
+ we've already filtered out duplicates. Most lists will be in order,
+ we should try to make use of that. */
int
-compexcepttypes (t1, t2)
+comp_except_specs (t1, t2, exact)
tree t1, t2;
+ int exact;
{
- return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
+ tree probe;
+ tree base;
+ int length = 0;
+
+ if (t1 == t2)
+ return 1;
+
+ if (t1 == NULL_TREE) /* T1 is ... */
+ return t2 == NULL_TREE || !exact;
+ if (!TREE_VALUE (t1)) /* t1 is EMPTY */
+ return t2 != NULL_TREE && !TREE_VALUE (t2);
+ if (t2 == NULL_TREE) /* T2 is ... */
+ return 0;
+ if (TREE_VALUE(t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
+ return !exact;
+
+ /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
+ Count how many we find, to determine exactness. For exact matching and
+ ordered T1, T2, this is an O(n) operation, otherwise its worst case is
+ O(nm). */
+ for (base = t1; t2 != NULL_TREE; t2 = TREE_CHAIN (t2))
+ {
+ for (probe = base; probe != NULL_TREE; probe = TREE_CHAIN (probe))
+ {
+ tree a = TREE_VALUE (probe);
+ tree b = TREE_VALUE (t2);
+
+ if (comp_except_types (a, b, exact))
+ {
+ if (probe == base && exact)
+ base = TREE_CHAIN (probe);
+ length++;
+ break;
+ }
+ }
+ if (probe == NULL_TREE)
+ return 0;
+ }
+ return !exact || base == NULL_TREE || length == list_length (t1);
}
/* Compare the array types T1 and T2, using CMP as the type comparison
TYPE_MAX_VALUE (d2)));
}
-/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
- or various other operations. STRICT is a bitwise-or of the
- COMPARE_* flags. */
+/* Return 1 if T1 and T2 are compatible types for assignment or
+ various other operations. STRICT is a bitwise-or of the COMPARE_*
+ flags. */
int
-comptypes (type1, type2, strict)
- tree type1, type2;
+comptypes (t1, t2, strict)
+ tree t1;
+ tree t2;
int strict;
{
- register tree t1 = type1;
- register tree t2 = type2;
int attrval, val;
int orig_strict = strict;
TYPE_TI_ARGS (t2));
look_hard:
if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
- {
- val = 1;
- break;
- }
- if ((strict & COMPARE_RELAXED) && DERIVED_FROM_P (t2, t1))
- {
- val = 1;
- break;
- }
+ val = 1;
+ else if ((strict & COMPARE_RELAXED) && DERIVED_FROM_P (t2, t1))
+ val = 1;
break;
case OFFSET_TYPE:
break;
case METHOD_TYPE:
- if (! compexcepttypes (t1, t2))
+ if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+ TYPE_RAISES_EXCEPTIONS (t2), 1))
return 0;
/* This case is anti-symmetrical!
break;
case FUNCTION_TYPE:
- if (! compexcepttypes (t1, t2))
+ if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+ TYPE_RAISES_EXCEPTIONS (t2), 1))
return 0;
val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
return 0;
return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
+ case COMPLEX_TYPE:
+ return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+
default:
break;
}
if (t1 == 0 && t2 != 0)
{
- cp_pedwarn ("ANSI C++ prohibits conversion from `(%#T)' to `(...)'",
- parms2);
+ if (! flag_strict_prototype && t2 == void_list_node)
+ /* t1 might be the arglist of a function pointer in extern "C"
+ declared to take (), which we fudged to (...). Don't make the
+ user pay for our mistake. */;
+ else
+ cp_pedwarn ("ANSI C++ prohibits conversion from `%#T' to `(...)'",
+ parms2);
return self_promoting_args_p (t2);
}
if (t2 == 0)
}
return warn_contravariance ? -1 : 1;
}
-
-/* Return 1 if PARMS specifies a fixed number of parameters
- and none of their types is affected by default promotions. */
-
-int
-self_promoting_args_p (parms)
- tree parms;
-{
- register tree t;
- for (t = parms; t; t = TREE_CHAIN (t))
- {
- register tree type = TREE_VALUE (t);
-
- if (TREE_CHAIN (t) == 0 && type != void_type_node)
- return 0;
-
- if (type == 0)
- return 0;
-
- if (TYPE_MAIN_VARIANT (type) == float_type_node)
- return 0;
-
- if (C_PROMOTING_INTEGER_TYPE_P (type))
- return 0;
- }
- return 1;
-}
\f
-/* Return an unsigned type the same as TYPE in other respects.
-
- C++: must make these work for type variants as well. */
-
-tree
-unsigned_type (type)
- tree type;
-{
- tree type1 = TYPE_MAIN_VARIANT (type);
- if (type1 == signed_char_type_node || type1 == char_type_node)
- return unsigned_char_type_node;
- if (type1 == integer_type_node)
- return unsigned_type_node;
- if (type1 == short_integer_type_node)
- return short_unsigned_type_node;
- if (type1 == long_integer_type_node)
- return long_unsigned_type_node;
- if (type1 == long_long_integer_type_node)
- return long_long_unsigned_type_node;
-#if HOST_BITS_PER_WIDE_INT >= 64
- if (type1 == intTI_type_node)
- return unsigned_intTI_type_node;
-#endif
- if (type1 == intDI_type_node)
- return unsigned_intDI_type_node;
- if (type1 == intSI_type_node)
- return unsigned_intSI_type_node;
- if (type1 == intHI_type_node)
- return unsigned_intHI_type_node;
- if (type1 == intQI_type_node)
- return unsigned_intQI_type_node;
-
- return signed_or_unsigned_type (1, type);
-}
-
-/* Return a signed type the same as TYPE in other respects. */
-
-tree
-signed_type (type)
- tree type;
-{
- tree type1 = TYPE_MAIN_VARIANT (type);
- if (type1 == unsigned_char_type_node || type1 == char_type_node)
- return signed_char_type_node;
- if (type1 == unsigned_type_node)
- return integer_type_node;
- if (type1 == short_unsigned_type_node)
- return short_integer_type_node;
- if (type1 == long_unsigned_type_node)
- return long_integer_type_node;
- if (type1 == long_long_unsigned_type_node)
- return long_long_integer_type_node;
-#if HOST_BITS_PER_WIDE_INT >= 64
- if (type1 == unsigned_intTI_type_node)
- return intTI_type_node;
-#endif
- if (type1 == unsigned_intDI_type_node)
- return intDI_type_node;
- if (type1 == unsigned_intSI_type_node)
- return intSI_type_node;
- if (type1 == unsigned_intHI_type_node)
- return intHI_type_node;
- if (type1 == unsigned_intQI_type_node)
- return intQI_type_node;
-
- return signed_or_unsigned_type (0, type);
-}
-
-/* Return a type the same as TYPE except unsigned or
- signed according to UNSIGNEDP. */
-
-tree
-signed_or_unsigned_type (unsignedp, type)
- int unsignedp;
- tree type;
-{
- if (! INTEGRAL_TYPE_P (type)
- || TREE_UNSIGNED (type) == unsignedp)
- return type;
-
- if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
- return unsignedp ? unsigned_char_type_node : signed_char_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
- return unsignedp ? unsigned_type_node : integer_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
- return unsignedp ? short_unsigned_type_node : short_integer_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
- return unsignedp ? long_unsigned_type_node : long_integer_type_node;
- if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
- return (unsignedp ? long_long_unsigned_type_node
- : long_long_integer_type_node);
- return type;
-}
-
/* Compute the value of the `sizeof' operator. */
tree
if (code == REFERENCE_TYPE)
type = TREE_TYPE (type);
- /* We couldn't find anything in the ARM or the draft standard that says,
- one way or the other, if doing sizeof on something that doesn't have
- an object associated with it is correct or incorrect. For example, if
- you declare `struct S { char str[16]; };', and in your program do
- a `sizeof (S::str)', should we flag that as an error or should we give
- the size of it? Since it seems like a reasonable thing to do, we'll go
- with giving the value. */
if (code == OFFSET_TYPE)
- type = TREE_TYPE (type);
-
- /* @@ This also produces an error for a signature ref.
- In that case we should be able to do better. */
- if (IS_SIGNATURE (type))
{
- error ("`sizeof' applied to a signature type");
+ cp_error ("`sizeof' applied to non-static member");
return size_int (0);
}
if (TREE_CODE (e) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
error ("sizeof applied to a bit-field");
- /* ANSI says arrays and functions are converted inside comma.
- But we can't really convert them in build_compound_expr
- because that would break commas in lvalues.
- So do the conversion here if operand was a comma. */
- if (TREE_CODE (e) == COMPOUND_EXPR
- && (TREE_CODE (TREE_TYPE (e)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (e)) == FUNCTION_TYPE))
- e = default_conversion (e);
- else if (is_overloaded_fn (e))
+ if (is_overloaded_fn (e))
{
pedwarn ("ANSI C++ forbids taking the sizeof a function type");
return size_int (1);
incomplete_type_error (e, TREE_TYPE (e));
return size_int (1);
}
+ /* It's illegal to say `sizeof (X::i)' for `i' a non-static data
+ member unless you're in a non-static member of X. So hand off to
+ resolve_offset_ref. [expr.prim] */
+ else if (TREE_CODE (e) == OFFSET_REF)
+ e = resolve_offset_ref (e);
+
+ if (e == error_mark_node)
+ return e;
return c_sizeof (TREE_TYPE (e));
}
if (code == REFERENCE_TYPE)
type = TREE_TYPE (type);
- /* @@ This also produces an error for a signature ref.
- In that case we should be able to do better. */
- if (IS_SIGNATURE (type))
- {
- error ("`__alignof' applied to a signature type");
- return size_int (1);
- }
-
t = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
force_fit_type (t, 0);
return t;
return cp_convert (ptrtype, adr);
}
+ /* [basic.lval]: Class rvalues can have cv-qualified types; non-class
+ rvalues always have cv-unqualified types. */
+ if (! CLASS_TYPE_P (type))
+ exp = cp_convert (TYPE_MAIN_VARIANT (type), exp);
+
return exp;
}
basetype, field, dtype);
return error_mark_node;
}
- else if (IS_SIGNATURE (basetype))
- {
- warning ("signature name in scope resolution ignored");
- return build_component_ref (datum, field, NULL_TREE, 1);
- }
else if (is_aggr_type (basetype, 1))
{
tree binfo = binfo_or_else (basetype, dtype);
}
/* Look up component name in the structure type definition. */
- if (CLASSTYPE_VFIELD (basetype)
- && DECL_NAME (CLASSTYPE_VFIELD (basetype)) == component)
+ if (TYPE_VFIELD (basetype)
+ && DECL_NAME (TYPE_VFIELD (basetype)) == component)
/* Special-case this because if we use normal lookups in an ambiguous
hierarchy, the compiler will abort (because vptr lookups are
not supposed to be ambiguous. */
- field = CLASSTYPE_VFIELD (basetype);
+ field = TYPE_VFIELD (basetype);
else if (TREE_CODE (component) == FIELD_DECL)
field = component;
else if (TREE_CODE (component) == TYPE_DECL)
cp_error ("invalid use of type decl `%#D' as expression", component);
return error_mark_node;
}
+ else if (TREE_CODE (component) == TEMPLATE_DECL)
+ {
+ cp_error ("invalid use of template `%#D' as expression", component);
+ return error_mark_node;
+ }
else
{
tree name = component;
if (TREE_CODE (component) == VAR_DECL)
name = DECL_NAME (component);
+ if (TREE_CODE (component) == NAMESPACE_DECL)
+ /* Source is in error, but produce a sensible diagnostic. */
+ name = DECL_NAME (component);
if (basetype_path == NULL_TREE)
basetype_path = TYPE_BINFO (basetype);
field = lookup_field (basetype_path, name,
not const, even within a const object. */
if (DECL_LANG_SPECIFIC (field) && DECL_MUTABLE_P (field))
type_quals &= ~TYPE_QUAL_CONST;
- if (!IS_SIGNATURE (field_type))
- field_type = cp_build_qualified_type (field_type, type_quals);
+ field_type = cp_build_qualified_type (field_type, type_quals);
}
ref = fold (build (COMPONENT_REF, field_type,
types. */
tree t = canonical_type_variant (TREE_TYPE (type));
- if (TREE_CODE (pointer) == ADDR_EXPR
+ if (same_type_p (TYPE_MAIN_VARIANT (t), void_type_node))
+ {
+ /* A pointer to incomplete type (other than cv void) can be
+ dereferenced [expr.unary.op]/1 */
+ cp_error ("`%T' is not a pointer-to-object type", type);
+ return error_mark_node;
+ }
+ else if (TREE_CODE (pointer) == ADDR_EXPR
&& !flag_volatile
&& same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
/* The POINTER was something like `&x'. We simplify `*&x' to
pointer to member, so it's cool to check for this here. */
else if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
error ("invalid use of `%s' on pointer to member", errorstring);
- else if (TREE_CODE (type) == RECORD_TYPE
- && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
- error ("cannot dereference signature pointer/reference");
else if (pointer != error_mark_node)
{
if (errorstring)
function = TREE_OPERAND (function, 1);
function = get_member_function_from_ptrfunc (&decl_addr, function);
- params = expr_tree_cons (NULL_TREE, decl_addr, params);
+ params = tree_cons (NULL_TREE, decl_addr, params);
return build_function_call (function, params);
}
}
else
decl = build_c_cast (ctypeptr, decl);
- params = expr_tree_cons (NULL_TREE, decl, params);
+ params = tree_cons (NULL_TREE, decl, params);
}
return build_function_call (function, params);
tree instance_ptr = *instance_ptrptr;
+ if (instance_ptr == error_mark_node
+ && TREE_CODE (function) == PTRMEM_CST)
+ {
+ /* Extracting the function address from a pmf is only
+ allowed with -Wno-pmf-conversions. It only works for
+ pmf constants. */
+ e1 = build_addr_func (PTRMEM_CST_MEMBER (function));
+ e1 = convert (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function)), e1);
+ return e1;
+ }
+
if (TREE_SIDE_EFFECTS (instance_ptr))
instance_ptr = save_expr (instance_ptr);
NULL_TREE, 0));
e3 = PFN_FROM_PTRMEMFUNC (function);
- if (TYPE_SIZE (basetype) != NULL_TREE
- && ! TYPE_VIRTUAL_P (basetype))
- /* If basetype doesn't have virtual functions, don't emit code to
- handle that case. */
- e1 = e3;
- else
- {
- /* Promoting idx before saving it improves performance on RISC
- targets. Without promoting, the first compare used
- load-with-sign-extend, while the second used normal load then
- shift to sign-extend. An optimizer flaw, perhaps, but it's
- easier to make this change. */
- idx = save_expr (default_conversion
- (build_component_ref (function,
- index_identifier,
- NULL_TREE, 0)));
- e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
-
- /* Convert down to the right base, before using the instance. */
- instance = convert_pointer_to_real (basetype, instance_ptr);
- if (instance == error_mark_node && instance_ptr != error_mark_node)
- return instance;
-
- vtbl = convert_pointer_to (ptr_type_node, instance);
- delta2 = DELTA2_FROM_PTRMEMFUNC (function);
- vtbl = build
+ /* This used to avoid checking for virtual functions if basetype
+ has no virtual functions, according to an earlier ANSI draft.
+ With the final ISO C++ rules, such an optimization is
+ incorrect: A pointer to a derived member can be static_cast
+ to pointer-to-base-member, as long as the dynamic object
+ later has the right member. */
+
+ /* Promoting idx before saving it improves performance on RISC
+ targets. Without promoting, the first compare used
+ load-with-sign-extend, while the second used normal load then
+ shift to sign-extend. An optimizer flaw, perhaps, but it's
+ easier to make this change. */
+ idx = save_expr (default_conversion
+ (build_component_ref (function,
+ index_identifier,
+ NULL_TREE, 0)));
+ e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
+
+ /* Convert down to the right base, before using the instance. */
+ instance = convert_pointer_to_real (basetype, instance_ptr);
+ if (instance == error_mark_node && instance_ptr != error_mark_node)
+ return instance;
+
+ vtbl = convert_pointer_to (ptr_type_node, instance);
+ delta2 = DELTA2_FROM_PTRMEMFUNC (function);
+ vtbl = build
+ (PLUS_EXPR,
+ build_pointer_type (build_pointer_type (vtable_entry_type)),
+ vtbl, cp_convert (ptrdiff_type_node, delta2));
+ vtbl = build_indirect_ref (vtbl, NULL_PTR);
+ aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
+ idx,
+ integer_one_node));
+ if (! flag_vtable_thunks)
+ {
+ aref = save_expr (aref);
+
+ delta = build_binary_op
(PLUS_EXPR,
- build_pointer_type (build_pointer_type (vtable_entry_type)),
- vtbl, cp_convert (ptrdiff_type_node, delta2));
- vtbl = build_indirect_ref (vtbl, NULL_PTR);
- aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
- idx,
- integer_one_node));
- if (! flag_vtable_thunks)
- {
- aref = save_expr (aref);
-
- delta = build_binary_op
- (PLUS_EXPR,
- build_conditional_expr (e1,
- build_component_ref (aref,
- delta_identifier,
- NULL_TREE, 0),
- integer_zero_node),
- delta);
- }
-
- if (flag_vtable_thunks)
- e2 = aref;
- else
- e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
- TREE_TYPE (e2) = TREE_TYPE (e3);
- e1 = build_conditional_expr (e1, e2, e3);
-
- /* Make sure this doesn't get evaluated first inside one of the
- branches of the COND_EXPR. */
- if (TREE_CODE (instance_ptr) == SAVE_EXPR)
- e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
- instance_ptr, e1);
+ build_conditional_expr (e1,
+ build_component_ref (aref,
+ delta_identifier,
+ NULL_TREE, 0),
+ integer_zero_node),
+ delta);
}
+ if (flag_vtable_thunks)
+ e2 = aref;
+ else
+ e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
+ TREE_TYPE (e2) = TREE_TYPE (e3);
+ e1 = build_conditional_expr (e1, e2, e3);
+
+ /* Make sure this doesn't get evaluated first inside one of the
+ branches of the COND_EXPR. */
+ if (TREE_CODE (instance_ptr) == SAVE_EXPR)
+ e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
+ instance_ptr, e1);
+
*instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
instance_ptr, delta);
if (TREE_CODE (function) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
- && DECL_BUILT_IN (TREE_OPERAND (function, 0)))
+ && DECL_BUILT_IN (TREE_OPERAND (function, 0))
+ && DECL_BUILT_IN_CLASS (TREE_OPERAND (function, 0)) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0)))
{
case BUILT_IN_ABS:
parmval = convert_for_initialization
(NULL_TREE, type, val, flags,
"argument passing", fndecl, i);
-#ifdef PROMOTE_PROTOTYPES
- if ((TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE)
+ if (PROMOTE_PROTOTYPES
+ && (TREE_CODE (type) == INTEGER_TYPE
+ || TREE_CODE (type) == ENUMERAL_TYPE)
&& (TYPE_PRECISION (type)
< TYPE_PRECISION (integer_type_node)))
parmval = default_conversion (parmval);
-#endif
}
if (parmval == error_mark_node)
return error_mark_node;
- result = expr_tree_cons (NULL_TREE, parmval, result);
+ result = tree_cons (NULL_TREE, parmval, result);
}
else
{
if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
val = convert_from_reference (val);
- result = expr_tree_cons (NULL_TREE,
+ result = tree_cons (NULL_TREE,
convert_arg_to_ellipsis (val),
result);
}
if (parmval == error_mark_node)
return error_mark_node;
- result = expr_tree_cons (0, parmval, result);
+ result = tree_cons (0, parmval, result);
typetail = TREE_CHAIN (typetail);
/* ends with `...'. */
if (typetail == NULL_TREE)
case EQ_EXPR:
case NE_EXPR:
+ if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
+ warning ("comparing floating point with == or != is unsafe");
+
build_type = boolean_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == COMPLEX_TYPE)
if (result_type == NULL_TREE)
result_type = ptr_type_node;
}
- else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
- && integer_zerop (op1))
+ else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
result_type = type0;
- else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
- && integer_zerop (op0))
+ else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
result_type = type1;
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type1;
error ("ANSI C++ forbids comparison between pointer and integer");
}
- else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST
- && integer_zerop (op1))
+ else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
{
op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
result_type = TREE_TYPE (op0);
}
- else if (TYPE_PTRMEMFUNC_P (type1) && TREE_CODE (op0) == INTEGER_CST
- && integer_zerop (op0))
+ else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
{
op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
DECL_VINDEX (TREE_OPERAND (op1, 0)),
integer_one_node);
op1 = integer_zero_node;
- delta21 = CLASSTYPE_VFIELD (TYPE_METHOD_BASETYPE
- (TREE_TYPE (type1)));
+ delta21 = TYPE_VFIELD (TYPE_METHOD_BASETYPE
+ (TREE_TYPE (type1)));
delta21 = DECL_FIELD_BITPOS (delta21);
delta21 = size_binop (FLOOR_DIV_EXPR, delta21,
size_int (BITS_PER_UNIT));
tree t;
if (processing_template_decl)
return expr;
- t = cp_convert (boolean_type_node, expr);
+ t = perform_implicit_conversion (boolean_type_node, expr);
t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
return t;
}
|| code == POSTINCREMENT_EXPR)
? PLUS_EXPR : MINUS_EXPR),
argtype, value, inc);
- TREE_SIDE_EFFECTS (incremented) = 1;
modify = build_modify_expr (arg, NOP_EXPR, incremented);
compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
arg = stabilize_reference (arg);
val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
boolean_true_node);
- TREE_SIDE_EFFECTS (val) = 1;
arg = save_expr (arg);
val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
&& OVL_NEXT (TREE_OPERAND (arg, 1)) == NULL_TREE)
{
/* They're trying to take the address of a unique non-static
- member function. This is ill-formed, but let's try to DTRT. */
- tree base, name;
+ member function. This is ill-formed, but let's try to DTRT.
+ Note: We only handle unique functions here because we don't
+ want to complain if there's a static overload; non-unique
+ cases will be handled by instantiate_type. But we need to
+ handle this case here to allow casts on the resulting PMF. */
- if (current_class_type
- && TREE_OPERAND (arg, 0) == current_class_ref)
- /* An expression like &memfn. */
- pedwarn ("taking the address of a non-static member function");
- else
- pedwarn ("taking the address of a bound member function");
+ tree base = TREE_TYPE (TREE_OPERAND (arg, 0));
+ tree name = DECL_NAME (OVL_CURRENT (TREE_OPERAND (arg, 1)));
+
+ if (! flag_ms_extensions)
+ {
+ if (current_class_type
+ && TREE_OPERAND (arg, 0) == current_class_ref)
+ /* An expression like &memfn. */
+ pedwarn ("taking the address of a non-static member function");
+ else
+ pedwarn ("taking the address of a bound member function");
- base = TREE_TYPE (TREE_OPERAND (arg, 0));
- name = DECL_NAME (OVL_CURRENT (TREE_OPERAND (arg, 1)));
+ cp_pedwarn
+ (" to form a pointer to member function, say `&%T::%D'",
+ base, name);
+ }
- cp_pedwarn (" to form a pointer to member function, say `&%T::%D'",
- base, name);
arg = build_offset_ref (base, name);
}
return fold (build1 (code, argtype, arg));
}
- error (errstring);
+ error ("%s", errstring);
return error_mark_node;
}
type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
type = build_pointer_type (type);
- t = make_node (PTRMEM_CST);
- TREE_TYPE (t) = type;
- PTRMEM_CST_MEMBER (t) = TREE_OPERAND (arg, 1);
+ t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
return t;
}
}
&& DECL_RTL (x) != 0
&& ! DECL_IN_MEMORY_P (x))
{
- /* We thought this would make a good constant variable,
- but we were wrong. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
TREE_ASM_WRITTEN (x) = 0;
DECL_RTL (x) = 0;
rest_of_decl_compilation (x, 0,
0);
TREE_ADDRESSABLE (x) = 1;
- pop_obstacks ();
-
return 1;
}
/* Caller should not be trying to mark initialized
&& !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;
+ TREE_USED (x) = 1;
+ if (current_function && expanding_p)
+ put_var_into_stack (x);
return 1;
case FUNCTION_DECL:
if (processing_template_decl)
return build_min_nt (COND_EXPR, ifexp, op1, op2);
- return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
+ return build_conditional_expr (ifexp, op1, op2);
}
+\f
+/* Handle overloading of the ',' operator when needed. Otherwise,
+ this function just builds an expression list. */
tree
-build_conditional_expr (ifexp, op1, op2)
- tree ifexp, op1, op2;
-{
- register tree type1;
- register tree type2;
- register enum tree_code code1;
- register enum tree_code code2;
- register tree result_type = NULL_TREE;
-
- /* If second operand is omitted, it is the same as the first one;
- make sure it is calculated only once. */
- if (op1 == 0)
- {
- if (pedantic)
- pedwarn ("ANSI C++ forbids omitting the middle term of a ?: expression");
- ifexp = op1 = save_expr (ifexp);
- }
-
- ifexp = cp_convert (boolean_type_node, ifexp);
-
- if (TREE_CODE (ifexp) == ERROR_MARK)
- return error_mark_node;
-
- /* C++: REFERENCE_TYPES must be dereferenced. */
- type1 = TREE_TYPE (op1);
- code1 = TREE_CODE (type1);
- type2 = TREE_TYPE (op2);
- code2 = TREE_CODE (type2);
-
- if (code1 == REFERENCE_TYPE)
- {
- op1 = convert_from_reference (op1);
- type1 = TREE_TYPE (op1);
- code1 = TREE_CODE (type1);
- }
- if (code2 == REFERENCE_TYPE)
- {
- op2 = convert_from_reference (op2);
- type2 = TREE_TYPE (op2);
- code2 = TREE_CODE (type2);
- }
-
- /* Don't promote the operands separately if they promote
- the same way. Return the unpromoted type and let the combined
- value get promoted if necessary. */
-
- if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
- && code2 != ARRAY_TYPE
- && code2 != FUNCTION_TYPE
- && code2 != METHOD_TYPE)
- {
- tree result;
-
- if (TREE_CONSTANT (ifexp)
- && (TREE_CODE (ifexp) == INTEGER_CST
- || TREE_CODE (ifexp) == ADDR_EXPR))
- return (integer_zerop (ifexp) ? op2 : op1);
-
- if (TREE_CODE (op1) == CONST_DECL)
- op1 = DECL_INITIAL (op1);
- else if (TREE_READONLY_DECL_P (op1))
- op1 = decl_constant_value (op1);
- if (TREE_CODE (op2) == CONST_DECL)
- op2 = DECL_INITIAL (op2);
- else if (TREE_READONLY_DECL_P (op2))
- op2 = decl_constant_value (op2);
- if (type1 != type2)
- type1 = cp_build_qualified_type
- (type1, (CP_TYPE_QUALS (TREE_TYPE (op1))
- | CP_TYPE_QUALS (TREE_TYPE (op2))));
- /* ??? This is a kludge to deal with the fact that
- we don't sort out integers and enums properly, yet. */
- result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
- if (TREE_TYPE (result) != type1)
- result = build1 (NOP_EXPR, type1, result);
- /* Expand both sides into the same slot,
- hopefully the target of the ?: expression. */
- if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
- {
- tree slot = build (VAR_DECL, TREE_TYPE (result));
- layout_decl (slot, 0);
- result = build (TARGET_EXPR, TREE_TYPE (result),
- slot, result, NULL_TREE, NULL_TREE);
- }
- return result;
- }
-
- /* They don't match; promote them both and then try to reconcile them.
- But don't permit mismatching enum types. */
- if (code1 == ENUMERAL_TYPE)
- {
- if (code2 == ENUMERAL_TYPE)
- {
- cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'",
- type1, type2);
- return error_mark_node;
- }
- else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2)
- && type2 != type_promotes_to (type1))
- warning ("enumeral and non-enumeral type in conditional expression");
- }
- else if (extra_warnings
- && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1)
- && type1 != type_promotes_to (type2))
- warning ("enumeral and non-enumeral type in conditional expression");
-
- if (code1 != VOID_TYPE)
- {
- op1 = default_conversion (op1);
- type1 = TREE_TYPE (op1);
- if (TYPE_PTRMEMFUNC_P (type1))
- type1 = TYPE_PTRMEMFUNC_FN_TYPE (type1);
- code1 = TREE_CODE (type1);
- }
- if (code2 != VOID_TYPE)
- {
- op2 = default_conversion (op2);
- type2 = TREE_TYPE (op2);
- if (TYPE_PTRMEMFUNC_P (type2))
- type2 = TYPE_PTRMEMFUNC_FN_TYPE (type2);
- code2 = TREE_CODE (type2);
- }
-
- if (code1 == RECORD_TYPE && code2 == RECORD_TYPE
- && real_lvalue_p (op1) && real_lvalue_p (op2)
- && comptypes (type1, type2, COMPARE_BASE | COMPARE_RELAXED))
- {
- type1 = build_reference_type (type1);
- type2 = build_reference_type (type2);
- result_type = common_type (type1, type2);
- op1 = convert_to_reference (result_type, op1, CONV_IMPLICIT,
- LOOKUP_NORMAL, NULL_TREE);
- op2 = convert_to_reference (result_type, op2, CONV_IMPLICIT,
- LOOKUP_NORMAL, NULL_TREE);
- }
- /* Quickly detect the usual case where op1 and op2 have the same type
- after promotion. */
- else if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
- {
- if (type1 == type2)
- result_type = type1;
- else
- result_type =
- cp_build_qualified_type (type1,
- CP_TYPE_QUALS (TREE_TYPE (op1))
- | CP_TYPE_QUALS (TREE_TYPE (op2)));
- }
- else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE)
- && (code2 == INTEGER_TYPE || code2 == REAL_TYPE))
- {
- result_type = common_type (type1, type2);
- }
- else if (code1 == VOID_TYPE || code2 == VOID_TYPE)
- {
- if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE))
- pedwarn ("ANSI C++ forbids conditional expr with only one void side");
- result_type = void_type_node;
- }
- else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2))
- result_type = qualify_type (type1, type2);
- else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1))
- result_type = qualify_type (type2, type1);
- else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
- {
- if (comp_target_types (type1, type2, 1))
- result_type = common_type (type1, type2);
- else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
- {
- if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
- result_type = qualify_type (type1, type2);
- }
- else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node)
- {
- if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
- result_type = qualify_type (type2, type1);
- }
- /* C++ */
- else if (same_or_base_type_p (type2, type1))
- result_type = type2;
- else if (IS_AGGR_TYPE (TREE_TYPE (type1))
- && IS_AGGR_TYPE (TREE_TYPE (type2))
- && (result_type = common_base_type (TREE_TYPE (type1),
- TREE_TYPE (type2))))
- {
- if (result_type == error_mark_node)
- {
- cp_error ("common base type of types `%T' and `%T' is ambiguous",
- TREE_TYPE (type1), TREE_TYPE (type2));
- result_type = ptr_type_node;
- }
- else
- {
- if (pedantic
- && result_type != TREE_TYPE (type1)
- && result_type != TREE_TYPE (type2))
- cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression",
- type1, type2, result_type);
-
- result_type = build_pointer_type (result_type);
- }
- }
- else
- {
- pedwarn ("pointer type mismatch in conditional expression");
- result_type = ptr_type_node;
- }
- }
- else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
- {
- pedwarn ("pointer/integer type mismatch in conditional expression");
- result_type = type1;
- }
- else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
- {
- pedwarn ("pointer/integer type mismatch in conditional expression");
- result_type = type2;
- }
- if (type2 == unknown_type_node)
- result_type = type1;
- else if (type1 == unknown_type_node)
- result_type = type2;
-
- if (!result_type)
- {
- /* The match does not look good. If either is
- an aggregate value, try converting to a scalar type. */
- if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
- {
- cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'",
- type1, type2);
- return error_mark_node;
- }
- /* Warning: this code assumes that conversion between cv-variants of
- a type is done using NOP_EXPRs. */
- if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
- {
- /* There are other types besides pointers and records. */
- tree tmp;
- if (code2 == POINTER_TYPE)
- tmp = build_pointer_type
- (cp_build_qualified_type (TREE_TYPE (type2),
- TYPE_QUAL_CONST
- | TYPE_QUAL_VOLATILE
- | TYPE_QUAL_RESTRICT));
- else
- tmp = type2;
- tmp = build_type_conversion (tmp, op1, 0);
- if (tmp == NULL_TREE)
- {
- cp_error ("incompatible types `%T' and `%T' in `?:'",
- type1, type2);
- return error_mark_node;
- }
- if (tmp == error_mark_node)
- error ("ambiguous pointer conversion");
- else
- STRIP_NOPS (tmp);
- result_type = common_type (type2, TREE_TYPE (tmp));
- op1 = tmp;
- }
- else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
- {
- tree tmp;
- if (code1 == POINTER_TYPE)
- tmp = build_pointer_type
- (cp_build_qualified_type (TREE_TYPE (type1),
- TYPE_QUAL_CONST
- | TYPE_QUAL_VOLATILE
- | TYPE_QUAL_RESTRICT));
- else
- tmp = type1;
-
- tmp = build_type_conversion (tmp, op2, 0);
- if (tmp == NULL_TREE)
- {
- cp_error ("incompatible types `%T' and `%T' in `?:'",
- type1, type2);
- return error_mark_node;
- }
- if (tmp == error_mark_node)
- error ("ambiguous pointer conversion");
- else
- STRIP_NOPS (tmp);
- result_type = common_type (type1, TREE_TYPE (tmp));
- op2 = tmp;
- }
- else if (flag_cond_mismatch)
- result_type = void_type_node;
- else
- {
- error ("type mismatch in conditional expression");
- return error_mark_node;
- }
- }
-
- if (TREE_CODE (result_type) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
- result_type = build_ptrmemfunc_type (result_type);
-
- if (result_type != TREE_TYPE (op1))
- op1 = convert_for_initialization
- (NULL_TREE, result_type, op1, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
- if (result_type != TREE_TYPE (op2))
- op2 = convert_for_initialization
- (NULL_TREE, result_type, op2, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
-
- if (TREE_CODE (ifexp) == INTEGER_CST)
- return integer_zerop (ifexp) ? op2 : op1;
-
- return convert_from_reference
- (fold (build (COND_EXPR, result_type, ifexp, op1, op2)));
-}
-\f
-/* Handle overloading of the ',' operator when needed. Otherwise,
- this function just builds an expression list. */
-
-tree
-build_x_compound_expr (list)
- tree list;
+build_x_compound_expr (list)
+ tree list;
{
tree rest = TREE_CHAIN (list);
tree result;
result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
if (result)
- return build_x_compound_expr (expr_tree_cons (NULL_TREE, result,
+ return build_x_compound_expr (tree_cons (NULL_TREE, result,
TREE_CHAIN (rest)));
if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
{
+ /* FIXME: This test should be in the implicit cast to void of the LHS. */
/* the left-hand operand of a comma expression is like an expression
statement: we should warn if it doesn't have any side-effects,
unless it was explicitly cast to (void). */
#endif
return build_compound_expr
- (expr_tree_cons (NULL_TREE, TREE_VALUE (list),
+ (tree_cons (NULL_TREE, TREE_VALUE (list),
build_expr_list (NULL_TREE,
build_x_compound_expr (rest))));
}
if (TREE_CODE (list) == NOP_EXPR
&& TREE_TYPE (list) == TREE_TYPE (TREE_OPERAND (list, 0)))
list = TREE_OPERAND (list, 0);
-
- /* Convert arrays to pointers. */
- if (TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE)
- return default_conversion (TREE_VALUE (list));
- else
- return TREE_VALUE (list);
+
+ return TREE_VALUE (list);
}
first = TREE_VALUE (list);
- first = require_complete_type_in_void (first);
+ first = convert_to_void (first, "lhs of comma");
if (first == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
- tree t = build_min (STATIC_CAST_EXPR, copy_to_permanent (type),
- expr);
+ tree t = build_min (STATIC_CAST_EXPR, type, expr);
return t;
}
expr = TREE_OPERAND (expr, 0);
if (TREE_CODE (type) == VOID_TYPE)
- return build1 (CONVERT_EXPR, type, expr);
+ {
+ expr = convert_to_void (expr, /*implicit=*/NULL);
+ return expr;
+ }
if (TREE_CODE (type) == REFERENCE_TYPE)
return (convert_from_reference
&& can_convert (intype, type))
ok = 1;
+ /* [expr.static.cast]
+
+ The static_cast operator shall not be used to cast away
+ constnes. */
+ if (ok && casts_away_constness (intype, type))
+ {
+ cp_error ("static_cast from `%T' to `%T' casts away constness",
+ intype, type);
+ return error_mark_node;
+ }
+
if (ok)
return build_c_cast (type, expr);
if (processing_template_decl)
{
- tree t = build_min (REINTERPRET_CAST_EXPR,
- copy_to_permanent (type), expr);
+ tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
return t;
}
if (processing_template_decl)
{
- tree t = build_min (CONST_CAST_EXPR, copy_to_permanent (type),
- expr);
+ tree t = build_min (CONST_CAST_EXPR, type, expr);
return t;
}
return error_mark_node;
}
- if (IS_SIGNATURE (type))
- {
- error ("cast specifies signature type");
- return error_mark_node;
- }
-
if (processing_template_decl)
{
tree t = build_min (CAST_EXPR, type,
return t;
}
+ if (TREE_CODE (type) == VOID_TYPE)
+ {
+ /* Conversion to void does not cause any of the normal function to
+ * pointer, array to pointer and lvalue to rvalue decays. */
+
+ value = convert_to_void (value, /*implicit=*/NULL);
+ return value;
+ }
/* Convert functions and arrays to pointers and
convert references to their expanded types,
but don't convert any other types. If, however, we are
warning ("cast to pointer from integer of different size");
#endif
- if (TREE_CODE (type) == VOID_TYPE)
- {
- value = require_complete_type_in_void (value);
- if (value != error_mark_node)
- value = build1 (CONVERT_EXPR, void_type_node, value);
- }
- else if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (TREE_CODE (type) == REFERENCE_TYPE)
value = (convert_from_reference
(convert_to_reference (type, value, CONV_C_CAST,
LOOKUP_COMPLAIN, NULL_TREE)));
newrhs = rhs;
- /* Handle assignment to signature pointers/refs. */
-
- if (TYPE_LANG_SPECIFIC (lhstype)
- && (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype)))
- {
- return build_signature_pointer_constructor (lhs, rhs);
- }
-
/* Handle control structure constructs used as "lvalues". */
switch (TREE_CODE (lhs))
/* Produce (a ? (b = rhs) : (c = rhs))
except that the RHS goes through a save-expr
so the code to compute it is only emitted once. */
- tree cond
- = build_conditional_expr (TREE_OPERAND (lhs, 0),
- build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
- modifycode, rhs),
- build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
- modifycode, rhs));
+ tree cond;
+
+ /* Check this here to avoid odd errors when trying to convert
+ a throw to the type of the COND_EXPR. */
+ if (!lvalue_or_else (lhs, "assignment"))
+ return error_mark_node;
+
+ cond = build_conditional_expr
+ (TREE_OPERAND (lhs, 0),
+ build_modify_expr (cp_convert (TREE_TYPE (lhs),
+ TREE_OPERAND (lhs, 1)),
+ modifycode, rhs),
+ build_modify_expr (cp_convert (TREE_TYPE (lhs),
+ TREE_OPERAND (lhs, 2)),
+ modifycode, rhs));
+
if (cond == error_mark_node)
return cond;
/* Make sure the code to compute the rhs comes out
/* Warn about storing in something that is `const'. */
/* For C++, don't warn if this is initialization. */
if (modifycode != INIT_EXPR
- /* For assignment to `const' signature pointer/reference fields,
- don't warn either, we already printed a better message before. */
- && ! (TREE_CODE (lhs) == COMPONENT_REF
- && (IS_SIGNATURE_POINTER (TREE_TYPE (TREE_OPERAND (lhs, 0)))
- || IS_SIGNATURE_REFERENCE (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
&& (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
/* Functions are not modifiable, even though they are
lvalues. */
}
}
- /* check to see if there is an assignment to `this' */
- if (lhs == current_class_ptr)
- {
- if (flag_this_is_variable > 0
- && DECL_NAME (current_function_decl) != NULL_TREE
- && (DECL_NAME (current_function_decl)
- != constructor_name (current_class_type)))
- warning ("assignment to `this' not in constructor or destructor");
- current_function_just_assigned_this = 1;
- }
-
if (modifycode != INIT_EXPR)
{
/* Make modifycode now either a NOP_EXPR or an INIT_EXPR. */
if (pedantic && ! DECL_ARTIFICIAL (current_function_decl))
pedwarn ("ANSI C++ forbids assignment of arrays");
- /* Have to wrap this in RTL_EXPR for two cases:
- in base or member initialization and if we
- are a branch of a ?: operator. Since we
- can't easily know the latter, just do it always. */
-
- result = make_node (RTL_EXPR);
-
- TREE_TYPE (result) = void_type_node;
- do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (result);
-
- /* As a matter of principle, `start_sequence' should do this. */
- emit_note (0, -1);
-
from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
? 1 + (modifycode != INIT_EXPR): 0;
- expand_vec_init (lhs, lhs, array_type_nelts (lhstype), newrhs,
- from_array);
-
- do_pending_stack_adjust ();
-
- TREE_SIDE_EFFECTS (result) = 1;
- RTL_EXPR_SEQUENCE (result) = get_insns ();
- RTL_EXPR_RTL (result) = const0_rtx;
- end_sequence ();
- return result;
+ return (build_vec_init
+ (lhs, lhs, array_type_nelts (lhstype), newrhs,
+ from_array));
}
if (modifycode == INIT_EXPR)
{
newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
"assignment", NULL_TREE, 0);
- if (lhs == DECL_RESULT (current_function_decl))
+ if (current_function_decl &&
+ lhs == DECL_RESULT (current_function_decl))
{
if (DECL_INITIAL (lhs))
warning ("return value from function receives multiple initializations");
\f
/* 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. */
+ TO type. If FORCE is true, then allow reverse conversions as well.
+
+ Note that the naming of FROM and TO is kind of backwards; the return
+ value is what we add to a TO in order to get a FROM. They are named
+ this way because we call this function to find out how to convert from
+ a pointer to member of FROM to a pointer to member of TO. */
static tree
get_delta_difference (from, to, force)
binfo = get_binfo (to, from, 1);
if (binfo == 0 || binfo == error_mark_node)
return delta;
- if (TREE_VIA_VIRTUAL (binfo))
+ if (binfo_from_vbase (binfo))
{
binfo = binfo_member (BINFO_TYPE (binfo),
CLASSTYPE_VBASECLASSES (from));
delta);
}
- if (TREE_VIA_VIRTUAL (binfo))
+ if (binfo_from_vbase (binfo))
{
if (force)
{
if (pfn)
{
u = build_nt (CONSTRUCTOR, NULL_TREE,
- expr_tree_cons (pfn_identifier, pfn, NULL_TREE));
+ tree_cons (pfn_identifier, pfn, NULL_TREE));
}
else
{
u = build_nt (CONSTRUCTOR, NULL_TREE,
- expr_tree_cons (delta2_identifier, delta2, NULL_TREE));
+ tree_cons (delta2_identifier, delta2, NULL_TREE));
}
u = build_nt (CONSTRUCTOR, NULL_TREE,
- expr_tree_cons (NULL_TREE, delta,
- expr_tree_cons (NULL_TREE, idx,
- expr_tree_cons (NULL_TREE, u, NULL_TREE))));
+ 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
{
allconstant = TREE_CONSTANT (pfn);
allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
- u = expr_tree_cons (pfn_field, pfn, NULL_TREE);
+ 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 = expr_tree_cons (delta2_field, delta2, NULL_TREE);
+ u = tree_cons (delta2_field, delta2, NULL_TREE);
}
delta = convert_and_check (delta_type_node, delta);
&& initializer_constant_valid_p (idx, TREE_TYPE (idx));
u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
- u = expr_tree_cons (delta_field, delta,
- expr_tree_cons (idx_field, idx,
- expr_tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
+ u = 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;
tree type, pfn;
int force;
{
- tree idx = integer_zero_node;
- tree delta = integer_zero_node;
- tree delta2 = integer_zero_node;
- tree npfn = NULL_TREE;
tree fn;
-
+ tree pfn_type = TREE_TYPE (pfn);
+ tree to_type = build_ptrmemfunc_type (type);
+
/* Handle multiple conversions of pointer to member functions. */
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
{
+ tree idx = integer_zero_node;
+ tree delta = integer_zero_node;
+ tree delta2 = integer_zero_node;
+ tree npfn = NULL_TREE;
tree ndelta, ndelta2;
tree e1, e2, e3, n;
- tree pfn_type;
- /* Is is already the right type? */
- if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
+ if (!force
+ && !can_convert_arg (to_type, TREE_TYPE (pfn), pfn))
+ cp_error ("conversion to `%T' from `%T'",
+ to_type, pfn_type);
+
+ if (TREE_CODE (pfn) == PTRMEM_CST)
+ {
+ /* We could just build the resulting CONSTRUCTOR now, but we
+ don't, relying on the general machinery below, together
+ with constant-folding, to do the right thing. We don't
+ want to return a PTRMEM_CST here, since a
+ pointer-to-member constant is no longer a valid template
+ argument once it is cast to any type, including its
+ original type. */
+ expand_ptrmemfunc_cst (pfn, &ndelta, &idx, &npfn, &ndelta2);
+ if (npfn)
+ /* This constant points to a non-virtual function.
+ NDELTA2 will be NULL, but it's value doesn't really
+ matter since we won't use it anyhow. */
+ ndelta2 = integer_zero_node;
+ }
+ else if (same_type_p (to_type, pfn_type))
+ /* We don't have to do any conversion. Note that we do this
+ after checking for a PTRMEM_CST so that a PTRMEM_CST, cast
+ to its own type, will not be considered a legal non-type
+ template argument. */
return pfn;
+ else
+ {
+ ndelta = cp_convert (ptrdiff_type_node,
+ build_component_ref (pfn,
+ delta_identifier,
+ NULL_TREE, 0));
+ ndelta2 = cp_convert (ptrdiff_type_node,
+ DELTA2_FROM_PTRMEMFUNC (pfn));
+ idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0);
+ }
- pfn_type = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn));
- if (!force
- && comp_target_types (type, pfn_type, 1) != 1)
- cp_error ("conversion to `%T' from `%T'", type, pfn_type);
-
- ndelta = cp_convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0));
- ndelta2 = cp_convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
- idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0);
-
- n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (pfn_type)),
- TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
+ n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
+ TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
force);
-
delta = build_binary_op (PLUS_EXPR, ndelta, n);
delta2 = build_binary_op (PLUS_EXPR, ndelta2, n);
e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
- e2 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx,
+ /* If it's a virtual function, this is what we want. */
+ e2 = build_ptrmemfunc1 (to_type, delta, idx,
NULL_TREE, delta2);
pfn = PFN_FROM_PTRMEMFUNC (pfn);
npfn = build1 (NOP_EXPR, type, pfn);
TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
- e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn,
- NULL_TREE);
+ /* But if it's a non-virtual function, or NULL, we use this
+ instead. */
+ e3 = build_ptrmemfunc1 (to_type, delta,
+ idx, npfn, NULL_TREE);
return build_conditional_expr (e1, e2, e3);
}
if (integer_zerop (pfn))
{
pfn = build_c_cast (type, integer_zero_node);
- return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type),
+ return build_ptrmemfunc1 (to_type,
integer_zero_node, integer_zero_node,
pfn, NULL_TREE);
}
fn = TREE_OPERAND (pfn, 0);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
- npfn = make_node (PTRMEM_CST);
- TREE_TYPE (npfn) = build_ptrmemfunc_type (type);
- PTRMEM_CST_MEMBER (npfn) = fn;
- return npfn;
+ return make_ptrmem_cst (to_type, fn);
}
/* Return the DELTA, IDX, PFN, and DELTA2 values for the PTRMEM_CST
{
tree type = TREE_TYPE (cst);
tree fn = PTRMEM_CST_MEMBER (cst);
+ tree ptr_class, fn_class;
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
-
- *delta
- = get_delta_difference (TYPE_METHOD_BASETYPE
- (TREE_TYPE (fn)),
- TYPE_PTRMEMFUNC_OBJECT_TYPE (type),
- /*force=*/0);
+
+ /* The class that the function belongs to. */
+ fn_class = DECL_CLASS_CONTEXT (fn);
+
+ /* The class that we're creating a pointer to member of. */
+ ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
+
+ /* First, calculate the adjustment to the function's class. */
+ *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0);
+
if (!DECL_VIRTUAL_P (fn))
{
- *idx = size_binop (MINUS_EXPR, integer_zero_node,
- integer_one_node);
- *pfn = build_addr_func (fn);
- if (!same_type_p (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)),
- TYPE_PTRMEMFUNC_OBJECT_TYPE (type)))
- *pfn = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
- *pfn);
+ *idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+ *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
*delta2 = NULL_TREE;
}
else
{
- *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn),
- integer_one_node);
+ /* If we're dealing with a virtual function, we have to adjust 'this'
+ again, to point to the base which provides the vtable entry for
+ fn; the call will do the opposite adjustment. */
+ tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
+ tree binfo = binfo_or_else (orig_class, fn_class);
+ *delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo));
+
+ /* Map everything down one to make room for the null PMF. */
+ *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node);
*pfn = NULL_TREE;
- *delta2 = get_binfo (DECL_CONTEXT (fn),
- DECL_CLASS_CONTEXT (fn),
- 0);
- *delta2 = get_vfield_offset (*delta2);
- *delta2 = size_binop (PLUS_EXPR, *delta2,
- build_binary_op (PLUS_EXPR,
- *delta,
- integer_zero_node));
+
+ /* Offset from an object of PTR_CLASS to the vptr for ORIG_CLASS. */
+ *delta2 = size_binop (PLUS_EXPR, *delta,
+ get_vfield_offset (TYPE_BINFO (orig_class)));
}
}
pfn_identifier, NULL_TREE, 0));
}
-/* Convert value RHS to type TYPE as preparation for an assignment
- to an lvalue of type TYPE.
- The real work of conversion is done by `convert'.
- The purpose of this function is to generate error messages
- for assignments that are not allowed in C.
- ERRTYPE is a string to use in error messages:
- "assignment", "return", etc.
-
- C++: attempts to allow `convert' to find conversions involving
- implicit type conversion between aggregate and scalar types
- as per 8.5.6 of C++ manual. Does not randomly dereference
- pointers to aggregates! */
+/* Convert value RHS to type TYPE as preparation for an assignment to
+ an lvalue of type TYPE. ERRTYPE is a string to use in error
+ messages: "assignment", "return", etc. If FNDECL is non-NULL, we
+ are doing the conversion in order to pass the PARMNUMth argument of
+ FNDECL. */
static tree
convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
rhs = TREE_OPERAND (rhs, 0);
- if (rhs == error_mark_node || TREE_TYPE (rhs) == error_mark_node)
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+
+ if (rhs == error_mark_node || rhstype == error_mark_node)
return error_mark_node;
if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)
return error_mark_node;
- if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
- || is_overloaded_fn (rhs))
- rhs = default_conversion (rhs);
- else if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
- rhs = convert_from_reference (rhs);
-
- /* If rhs is some sort of overloaded function, ocp_convert will either
- do the right thing or complain; we don't need to check anything else.
- So just hand off. */
- if (type_unknown_p (rhs))
- return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
-
- rhstype = TREE_TYPE (rhs);
- coder = TREE_CODE (rhstype);
-
- /* Issue warnings about peculiar, but legal, uses of NULL. */
+ /* Issue warnings about peculiar, but legal, uses of NULL. We
+ do this *before* the call to decl_constant_value so as to
+ avoid duplicate warnings on code like `const int I = NULL;
+ f(I);'. */
if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
cp_warning ("converting NULL to non-pointer type");
- /* This should no longer change types on us. */
- if (TREE_CODE (rhs) == CONST_DECL)
- rhs = DECL_INITIAL (rhs);
- else if (TREE_READONLY_DECL_P (rhs))
- rhs = decl_constant_value (rhs);
-
- if (same_type_p (type, rhstype))
- {
- overflow_warning (rhs);
- return rhs;
- }
-
+ /* The RHS of an assignment cannot have void type. */
if (coder == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
- /* Arithmetic types all interconvert. */
- if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE
- || codel == COMPLEX_TYPE)
- && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE
- || coder == COMPLEX_TYPE))
- {
- /* But we should warn if assigning REAL_TYPE to INTEGER_TYPE. */
- if (coder == REAL_TYPE && codel == INTEGER_TYPE)
- {
- if (fndecl)
- cp_warning ("`%T' used for argument %P of `%D'",
- rhstype, parmnum, fndecl);
- else
- cp_warning ("%s to `%T' from `%T'", errtype, type, rhstype);
- }
- /* And we should warn if assigning a negative value to
- an unsigned variable. */
- else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
- {
- if (TREE_CODE (rhs) == INTEGER_CST
- && TREE_NEGATED_INT (rhs))
- {
- if (fndecl)
- cp_warning ("negative value `%E' passed as argument %P of `%D'",
- rhs, parmnum, fndecl);
- else
- cp_warning ("%s of negative value `%E' to `%T'",
- errtype, rhs, type);
- }
- overflow_warning (rhs);
- if (TREE_CONSTANT (rhs))
- rhs = fold (rhs);
- }
-
- return convert_and_check (type, rhs);
- }
- /* Conversions involving enums. */
- else if ((codel == ENUMERAL_TYPE
- && (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE))
- || (coder == ENUMERAL_TYPE
- && (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
- {
- return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
- }
- /* Conversions among pointers */
- else if (codel == POINTER_TYPE
- && (coder == POINTER_TYPE
- || (coder == RECORD_TYPE
- && (IS_SIGNATURE_POINTER (rhstype)
- || IS_SIGNATURE_REFERENCE (rhstype)))))
- {
- register tree ttl = TREE_TYPE (type);
- register tree ttr;
- int ctt = 0;
-
- if (coder == RECORD_TYPE)
- {
- rhs = build_optr_ref (rhs);
- rhstype = TREE_TYPE (rhs);
- }
- ttr = TREE_TYPE (rhstype);
-
- /* If both pointers are of aggregate type, then we
- can give better error messages, and save some work
- as well. */
- if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
- {
- tree binfo;
-
- if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr)
- || type == class_star_type_node
- || rhstype == class_star_type_node)
- binfo = TYPE_BINFO (ttl);
- else
- binfo = get_binfo (ttl, ttr, 1);
-
- if (binfo == error_mark_node)
- return error_mark_node;
- if (binfo == 0)
- return error_not_base_type (ttl, ttr);
- if (!at_least_as_qualified_p (ttl, ttr))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
- errtype, type, rhstype);
- }
- }
-
- /* Any non-function converts to a [const][volatile] void *
- and vice versa; otherwise, targets must be the same.
- Meanwhile, the lhs target must have all the qualifiers of the rhs. */
- else if (TYPE_MAIN_VARIANT (ttl) == void_type_node
- || TYPE_MAIN_VARIANT (ttr) == void_type_node
- || (ctt = comp_target_types (type, rhstype, 1))
- || (unsigned_type (TYPE_MAIN_VARIANT (ttl))
- == unsigned_type (TYPE_MAIN_VARIANT (ttr))))
- {
- /* ARM $4.8, commentary on p39. */
- if (TYPE_MAIN_VARIANT (ttl) == void_type_node
- && TREE_CODE (ttr) == OFFSET_TYPE)
- {
- cp_error ("no standard conversion from `%T' to `void *'", ttr);
- return error_mark_node;
- }
-
- if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr))
- cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
- rhstype, type);
+ /* Simplify the RHS if possible. */
+ if (TREE_CODE (rhs) == CONST_DECL)
+ rhs = DECL_INITIAL (rhs);
+ else if (TREE_READONLY_DECL_P (rhs))
+ rhs = decl_constant_value (rhs);
- if (TYPE_MAIN_VARIANT (ttl) != void_type_node
- && TYPE_MAIN_VARIANT (ttr) == void_type_node
- && ! null_ptr_cst_p (rhs))
- {
- if (coder == RECORD_TYPE)
- cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
- type);
- else
- pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s",
- errtype);
- }
- /* Const and volatile mean something different for function types,
- so the usual warnings are not appropriate. */
- else if ((TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttr) != METHOD_TYPE)
- || (TREE_CODE (ttl) != FUNCTION_TYPE && TREE_CODE (ttl) != METHOD_TYPE))
- {
- if (TREE_CODE (ttl) == OFFSET_TYPE
- && binfo_member (TYPE_OFFSET_BASETYPE (ttr),
- CLASSTYPE_VBASECLASSES (TYPE_OFFSET_BASETYPE (ttl))))
- {
- error ("%s between pointer to members converting across virtual baseclasses", errtype);
- return error_mark_node;
- }
- else if (!at_least_as_qualified_p (ttl, ttr))
- {
- if (string_conv_p (type, rhs, 1))
- /* converting from string constant to char *, OK. */;
- else if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
- errtype, type, rhstype);
- }
- else if (TREE_CODE (ttl) == TREE_CODE (ttr)
- && ! comp_target_types (type, rhstype, 1))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' changes signedness",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' changes signedness",
- errtype, type, rhstype);
- }
- }
- }
+ /* Warn about assigning a floating-point type to an integer type. */
+ if (coder == REAL_TYPE && codel == INTEGER_TYPE)
+ {
+ if (fndecl)
+ cp_warning ("`%T' used for argument %P of `%D'",
+ rhstype, parmnum, fndecl);
else
- {
- int add_quals = 0;
- int drops_quals = 0;
- int left_const = 1;
- int unsigned_parity;
- int nptrs = 0;
-
- /* This code is basically a duplicate of comp_ptr_ttypes_real. */
- for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr))
- {
- nptrs -= 1;
- drops_quals |= !at_least_as_qualified_p (ttl, ttr);
-
- if (! left_const
- && !at_least_as_qualified_p (ttr, ttl))
- add_quals = 1;
- left_const &= TYPE_READONLY (ttl);
-
- if (TREE_CODE (ttl) != POINTER_TYPE
- || TREE_CODE (ttr) != POINTER_TYPE)
- break;
- }
- unsigned_parity = TREE_UNSIGNED (ttl) - TREE_UNSIGNED (ttr);
- if (unsigned_parity)
- {
- if (TREE_UNSIGNED (ttl))
- ttr = unsigned_type (ttr);
- else
- ttl = unsigned_type (ttl);
- }
-
- if (comp_target_types (ttl, ttr, nptrs) > 0)
- {
- if (add_quals)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' adds cv-quals without intervening `const'",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' adds cv-quals without intervening `const'",
- errtype, type, rhstype);
- }
- if (drops_quals)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
- errtype, type, rhstype);
- }
- if (unsigned_parity > 0)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' changes signed to unsigned",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' changes signed to unsigned",
- errtype, type, rhstype);
- }
- else if (unsigned_parity < 0)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' changes unsigned to signed",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' changes unsigned to signed",
- errtype, type, rhstype);
- }
-
- /* C++ is not so friendly about converting function and
- member function pointers as C. Emit warnings here. */
- if (TREE_CODE (ttl) == FUNCTION_TYPE
- || TREE_CODE (ttl) == METHOD_TYPE)
- if (!same_or_base_type_p (ttl, ttr))
- {
- warning ("conflicting function types in %s:", errtype);
- cp_warning ("\t`%T' != `%T'", type, rhstype);
- }
- }
- else
- {
- if (fndecl)
- cp_error ("passing `%T' as argument %P of `%D'",
- rhstype, parmnum, fndecl);
- else
- cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
- return error_mark_node;
- }
- }
- return cp_convert (type, rhs);
+ cp_warning ("%s to `%T' from `%T'", errtype, type, rhstype);
}
- else if (codel == POINTER_TYPE
- && (coder == INTEGER_TYPE
- || coder == BOOLEAN_TYPE))
+ /* And warn about assigning a negative value to an unsigned
+ variable. */
+ else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
{
- /* An explicit constant 0 can convert to a pointer,
- but not a 0 that results from casting or folding. */
- if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs)))
+ if (TREE_CODE (rhs) == INTEGER_CST
+ && TREE_NEGATED_INT (rhs))
{
if (fndecl)
- cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast",
- rhstype, parmnum, fndecl);
+ cp_warning ("negative value `%E' passed as argument %P of `%D'",
+ rhs, parmnum, fndecl);
else
- cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
- errtype, type, rhstype);
+ cp_warning ("%s of negative value `%E' to `%T'",
+ errtype, rhs, type);
+ }
+ overflow_warning (rhs);
+ if (TREE_CONSTANT (rhs))
+ rhs = fold (rhs);
+ }
+
+ /* [expr.ass]
+
+ The expression is implicitly converted (clause _conv_) to the
+ cv-unqualified type of the left operand. */
+ if (!can_convert_arg (type, rhstype, rhs))
+ {
+ /* When -Wno-pmf-conversions is use, we just silently allow
+ conversions from pointers-to-members to plain pointers. If
+ the conversion doesn't work, cp_convert will complain. */
+ if (!warn_pmf2ptr
+ && TYPE_PTR_P (type)
+ && TYPE_PTRMEMFUNC_P (rhstype))
+ rhs = cp_convert (strip_top_quals (type), rhs);
+ else
+ {
+ /* If the right-hand side has unknown type, then it is an
+ overloaded function. Call instantiate_type to get error
+ messages. */
+ if (rhstype == unknown_type_node)
+ instantiate_type (type, rhs, 1);
+ else if (fndecl)
+ cp_error ("cannot convert `%T' to `%T' for argument `%P' to `%D'",
+ rhstype, type, parmnum, fndecl);
+ else
+ cp_error ("cannot convert `%T' to `%T' in %s", rhstype, type,
+ errtype);
+ return error_mark_node;
}
- return cp_convert (type, rhs);
- }
- else if (codel == INTEGER_TYPE
- && (coder == POINTER_TYPE
- || (coder == RECORD_TYPE
- && (IS_SIGNATURE_POINTER (rhstype)
- || TYPE_PTRMEMFUNC_FLAG (rhstype)
- || IS_SIGNATURE_REFERENCE (rhstype)))))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
- errtype, type, rhstype);
- return cp_convert (type, rhs);
- }
- else if (codel == BOOLEAN_TYPE
- && (coder == POINTER_TYPE
- || (coder == RECORD_TYPE
- && (IS_SIGNATURE_POINTER (rhstype)
- || TYPE_PTRMEMFUNC_FLAG (rhstype)
- || IS_SIGNATURE_REFERENCE (rhstype)))))
- return cp_convert (type, rhs);
-
- /* C++ */
- else if (((coder == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (rhstype)) == METHOD_TYPE)
- || integer_zerop (rhs)
- || TYPE_PTRMEMFUNC_P (rhstype))
- && TYPE_PTRMEMFUNC_P (type))
- {
- tree ttl = TYPE_PTRMEMFUNC_FN_TYPE (type);
- tree ttr = (TYPE_PTRMEMFUNC_P (rhstype)
- ? TYPE_PTRMEMFUNC_FN_TYPE (rhstype)
- : rhstype);
- int ctt = (TREE_CODE (rhstype) == INTEGER_TYPE ? 1
- : comp_target_types (ttl, ttr, 1));
-
- if (ctt < 0)
- cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
- ttr, ttl);
- else if (ctt == 0)
- cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
-
- /* compatible pointer to member functions. */
- return build_ptrmemfunc (ttl, rhs, 0);
- }
- else if (codel == ERROR_MARK || coder == ERROR_MARK)
- return error_mark_node;
-
- /* This should no longer happen. References are initialized via
- `convert_for_initialization'. They should otherwise be
- bashed before coming here. */
- else if (codel == REFERENCE_TYPE)
- my_friendly_abort (317);
- else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (rhs)))
- {
- tree nrhs = build1 (NOP_EXPR, type, rhs);
- TREE_CONSTANT (nrhs) = TREE_CONSTANT (rhs);
- return nrhs;
}
- else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
- return cp_convert (type, rhs);
- /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */
- else if (TREE_CODE (type) == POINTER_TYPE
- && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
- || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
- && TREE_TYPE (rhs)
- && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
- return cp_convert (type, rhs);
-
- cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
- return error_mark_node;
+ return perform_implicit_conversion (strip_top_quals (type), rhs);
}
/* Convert RHS to be of type TYPE.
if (fndecl)
savew = warningcount, savee = errorcount;
- rhs = convert_to_reference (type, rhs, CONV_IMPLICIT, flags,
- exp ? exp : error_mark_node);
+ rhs = initialize_reference (type, rhs);
if (fndecl)
{
if (warningcount > savew)
type = complete_type (type);
- if (TYPE_LANG_SPECIFIC (type)
- && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
- return build_signature_pointer_constructor (type, rhs);
-
if (IS_AGGR_TYPE (type))
return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
- if (type == TREE_TYPE (rhs))
- {
- /* Issue warnings about peculiar, but legal, uses of NULL. We
- do this *before* the call to decl_constant_value so as to
- avoid duplicate warnings on code like `const int I = NULL;
- f(I);'. */
- if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
- cp_warning ("converting NULL to non-pointer type");
-
- if (TREE_READONLY_DECL_P (rhs))
- rhs = decl_constant_value (rhs);
-
- return rhs;
- }
-
return convert_for_assignment (type, rhs, errtype, fndecl, parmnum);
}
\f
emit_queue ();
}
\f
-/* Expand a C `return' statement.
- RETVAL is the expression for what to return,
- or a null pointer for `return;' with no value.
+/* If RETVAL is the address of, or a reference to, a local variable or
+ temporary give an appropraite warning. */
- C++: upon seeing a `return', we must call destructors on all
- variables in scope which had constructors called on them.
- This means that if in a destructor, the base class destructors
- must be called before returning.
+static void
+maybe_warn_about_returning_address_of_local (retval)
+ tree retval;
+{
+ tree valtype = TREE_TYPE (DECL_RESULT (current_function_decl));
- The RETURN statement in C++ has initialization semantics. */
+ if (TREE_CODE (valtype) == REFERENCE_TYPE)
+ {
+ tree whats_returned;
-void
-c_expand_return (retval)
+ /* Sort through common things to see what it is
+ we are returning. */
+ whats_returned = retval;
+ if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
+ {
+ whats_returned = TREE_OPERAND (whats_returned, 1);
+ if (TREE_CODE (whats_returned) == ADDR_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ }
+ while (TREE_CODE (whats_returned) == CONVERT_EXPR
+ || TREE_CODE (whats_returned) == NOP_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ if (TREE_CODE (whats_returned) == ADDR_EXPR)
+ {
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
+ || TREE_CODE (whats_returned) == TARGET_EXPR)
+ {
+ /* Get the target. */
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ warning ("returning reference to temporary");
+ }
+ }
+
+ if (TREE_CODE (whats_returned) == VAR_DECL
+ && DECL_NAME (whats_returned))
+ {
+ if (TEMP_NAME_P (DECL_NAME (whats_returned)))
+ warning ("reference to non-lvalue returned");
+ else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
+ && DECL_FUNCTION_SCOPE_P (whats_returned)
+ && !(TREE_STATIC (whats_returned)
+ || TREE_PUBLIC (whats_returned)))
+ cp_warning_at ("reference to local variable `%D' returned",
+ whats_returned);
+ }
+ }
+ else if (TREE_CODE (retval) == ADDR_EXPR)
+ {
+ tree whats_returned = TREE_OPERAND (retval, 0);
+
+ if (TREE_CODE (whats_returned) == VAR_DECL
+ && DECL_NAME (whats_returned)
+ && DECL_FUNCTION_SCOPE_P (whats_returned)
+ && !(TREE_STATIC (whats_returned)
+ || TREE_PUBLIC (whats_returned)))
+ cp_warning_at ("address of local variable `%D' returned",
+ whats_returned);
+ }
+}
+
+/* Check that returning RETVAL from the current function is legal.
+ Return an expression explicitly showing all conversions required to
+ change RETVAL into the function return type, and to assign it to
+ the DECL_RESULT for the function. */
+
+tree
+check_return_expr (retval)
tree retval;
{
- extern struct nesting *cond_stack, *loop_stack, *case_stack;
- extern tree dtor_label, ctor_label;
- tree result = DECL_RESULT (current_function_decl);
- tree valtype = TREE_TYPE (result);
-
+ tree result;
+ /* The type actually returned by the function, after any
+ promotions. */
+ tree valtype;
+ int fn_returns_value_p;
+
+ /* A `volatile' function is one that isn't supposed to return, ever.
+ (This is a G++ extension, used to get better code for functions
+ that call the `volatile' function.) */
if (TREE_THIS_VOLATILE (current_function_decl))
warning ("function declared `noreturn' has a `return' statement");
+ /* Check for various simple errors. */
if (retval == error_mark_node)
{
+ /* If an error occurred, there's nothing to do. */
current_function_returns_null = 1;
- return;
- }
-
- if (processing_template_decl)
- {
- add_tree (build_min_nt (RETURN_STMT, retval));
- return;
+ return error_mark_node;
}
-
- if (dtor_label)
+ else if (dtor_label)
{
if (retval)
error ("returning a value from a destructor");
+ return NULL_TREE;
+ }
+ else if (in_function_try_handler
+ && DECL_CONSTRUCTOR_P (current_function_decl))
+ {
+ /* If a return statement appears in a handler of the
+ function-try-block of a constructor, the program is ill-formed. */
+ error ("cannot return from a handler of a function-try-block of a constructor");
+ return error_mark_node;
+ }
+ else if (retval && DECL_CONSTRUCTOR_P (current_function_decl))
+ /* You can't return a value from a constructor. */
+ error ("returning a value from a constructor");
+
+ /* Constructors actually always return `this', even though in C++
+ you can't return a value from a constructor. */
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ retval = current_class_ptr;
+
+ /* When no explicit return-value is given in a function with a named
+ return value, the named return value is used. */
+ result = DECL_RESULT (current_function_decl);
+ valtype = TREE_TYPE (result);
+ my_friendly_assert (valtype != NULL_TREE, 19990924);
+ fn_returns_value_p = !same_type_p (valtype, void_type_node);
+ if (!retval && DECL_NAME (result) && fn_returns_value_p)
+ retval = result;
+
+ /* Check for a return statement with no return value in a function
+ that's supposed to return a value. */
+ if (!retval && fn_returns_value_p)
+ {
+ pedwarn ("`return' with no value, in function returning non-void");
+ /* Clear this, so finish_function won't say that we reach the
+ end of a non-void function (which we don't, we gave a
+ return!). */
+ current_function_returns_null = 0;
+ }
+ /* Check for a return statement with a value in a function that
+ isn't supposed to return a value. */
+ else if (retval && !fn_returns_value_p)
+ {
+ if (same_type_p (TREE_TYPE (retval), void_type_node))
+ /* You can return a `void' value from a function of `void'
+ type. In that case, we have to evaluate the expression for
+ its side-effects. */
+ finish_expr_stmt (retval);
+ else
+ pedwarn ("`return' with a value, in function returning void");
- /* Can't just return from a destructor. */
- expand_goto (dtor_label);
- return;
+ current_function_returns_null = 1;
+
+ /* There's really no value to return, after all. */
+ return NULL_TREE;
}
+ else if (!retval)
+ /* Remember that this function can sometimes return without a
+ value. */
+ current_function_returns_null = 1;
/* Only operator new(...) throw(), can return NULL [expr.new/13]. */
if ((DECL_NAME (current_function_decl) == ansi_opname[(int) NEW_EXPR]
|| DECL_NAME (current_function_decl) == ansi_opname[(int) VEC_NEW_EXPR])
&& !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
&& null_ptr_cst_p (retval))
- cp_pedwarn ("operator new should throw an exception, not return NULL");
-
- if (retval == NULL_TREE)
- {
- /* A non-named return value does not count. */
-
- if (DECL_CONSTRUCTOR_P (current_function_decl))
- retval = current_class_ptr;
- else if (DECL_NAME (result) != NULL_TREE
- && TREE_CODE (valtype) != VOID_TYPE)
- retval = result;
- else
- {
- current_function_returns_null = 1;
-
- if (valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE)
- {
- if (DECL_NAME (DECL_RESULT (current_function_decl)) == NULL_TREE)
- {
- pedwarn ("`return' with no value, in function returning non-void");
- /* Clear this, so finish_function won't say that we
- reach the end of a non-void function (which we don't,
- we gave a return!). */
- current_function_returns_null = 0;
- }
- }
-
- expand_null_return ();
- return;
- }
- }
- else if (DECL_CONSTRUCTOR_P (current_function_decl))
- {
- if (flag_this_is_variable)
- error ("return from a constructor: use `this = ...' instead");
- else
- error ("returning a value from a constructor");
- retval = current_class_ptr;
- }
+ cp_warning ("operator new should throw an exception, not return NULL");
/* Effective C++ rule 15. See also start_function. */
if (warn_ecpp
&& retval != current_class_ref)
cp_warning ("`operator=' should return a reference to `*this'");
- if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
- {
- current_function_returns_null = 1;
- if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
- pedwarn ("`return' with a value, in function returning void");
- expand_return (retval);
- return;
- }
-
- /* Now deal with possible C++ hair:
- (1) Compute the return value.
- (2) If there are aggregate values with destructors which
- must be cleaned up, clean them (taking care
- not to clobber the return value).
- (3) If an X(X&) constructor is defined, the return
- value must be returned via that. */
-
- if (retval == result
- || DECL_CONSTRUCTOR_P (current_function_decl))
- /* It's already done for us. */;
- else if (TREE_CODE (TREE_TYPE (retval)) == VOID_TYPE)
- {
- pedwarn ("return of void value in function returning non-void");
- expand_expr_stmt (retval);
- retval = 0;
- }
+ /* We don't need to do any conversions when there's nothing being
+ returned. */
+ if (!retval)
+ return NULL_TREE;
+
+ /* Do any required conversions. */
+ if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))
+ /* No conversions are required. */
+ ;
else
{
+ /* The type the function is declared to return. */
tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
/* First convert the value to the function's return type, then
to the type of return value's location to handle the
case that functype is thiner than the valtype. */
-
retval = convert_for_initialization
(NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
"return", NULL_TREE, 0);
-
retval = convert (valtype, retval);
+ /* If the conversion failed, treat this just like `return;'. */
if (retval == error_mark_node)
- {
- /* Avoid warning about control reaching end of function. */
- expand_null_return ();
- return;
- }
-
+ return NULL_TREE;
/* We can't initialize a register from a AGGR_INIT_EXPR. */
else if (! current_function_returns_struct
&& TREE_CODE (retval) == TARGET_EXPR
&& TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
TREE_OPERAND (retval, 0));
+ else
+ maybe_warn_about_returning_address_of_local (retval);
+ }
+
+ /* Actually copy the value returned into the appropriate location. */
+ if (retval && retval != result)
+ retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
- /* Add some useful error checking for C++. */
- else if (TREE_CODE (valtype) == REFERENCE_TYPE)
- {
- tree whats_returned;
-
- /* Sort through common things to see what it is
- we are returning. */
- whats_returned = retval;
- if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
- {
- whats_returned = TREE_OPERAND (whats_returned, 1);
- if (TREE_CODE (whats_returned) == ADDR_EXPR)
- whats_returned = TREE_OPERAND (whats_returned, 0);
- }
- while (TREE_CODE (whats_returned) == CONVERT_EXPR
- || TREE_CODE (whats_returned) == NOP_EXPR)
- whats_returned = TREE_OPERAND (whats_returned, 0);
- if (TREE_CODE (whats_returned) == ADDR_EXPR)
- {
- whats_returned = TREE_OPERAND (whats_returned, 0);
- while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
- || TREE_CODE (whats_returned) == TARGET_EXPR)
- {
- /* Get the target. */
- whats_returned = TREE_OPERAND (whats_returned, 0);
- warning ("returning reference to temporary");
- }
- }
+ /* All done. Remember that this function did return a value. */
+ current_function_returns_value = 1;
+ return retval;
+}
- if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
- {
- if (TEMP_NAME_P (DECL_NAME (whats_returned)))
- warning ("reference to non-lvalue returned");
- else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
- && DECL_FUNCTION_SCOPE_P (whats_returned)
- && !(TREE_STATIC (whats_returned)
- || TREE_PUBLIC (whats_returned)))
- cp_warning_at ("reference to local variable `%D' returned", whats_returned);
- }
- }
- else if (TREE_CODE (retval) == ADDR_EXPR)
- {
- tree whats_returned = TREE_OPERAND (retval, 0);
-
- if (TREE_CODE (whats_returned) == VAR_DECL
- && DECL_NAME (whats_returned)
- && DECL_FUNCTION_SCOPE_P (whats_returned)
- && !(TREE_STATIC (whats_returned)
- || TREE_PUBLIC (whats_returned)))
- cp_warning_at ("address of local variable `%D' returned", whats_returned);
- }
- }
+/* Expand a C `return' statement.
+ RETVAL is the expression for what to return,
+ or a null pointer for `return;' with no value.
- 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;
+ C++: upon seeing a `return', we must call destructors on all
+ variables in scope which had constructors called on them.
+ This means that if in a destructor, the base class destructors
+ must be called before returning.
- if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
- {
- /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do. */
- expand_goto (ctor_label);
- }
+ The RETURN statement in C++ has initialization semantics. */
- if (retval && retval != result)
+void
+c_expand_return (retval)
+ tree retval;
+{
+ if (!retval)
+ expand_null_return ();
+ else
{
- result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
- TREE_SIDE_EFFECTS (result) = 1;
+ expand_start_target_temps ();
+ expand_return (retval);
+ expand_end_target_temps ();
}
-
- expand_start_target_temps ();
-
- expand_return (result);
-
- expand_end_target_temps ();
-
- current_function_returns_value = 1;
}
\f
/* Start a C switch statement, testing expression EXP.
}
}
-/* Returns the type-qualifier set corresponding to TYPE. */
+/* Recursively examines the array elements of TYPE, until a non-array
+ element type is found. */
-int
-cp_type_quals (type)
+tree
+strip_array_types (type)
tree type;
{
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
- return TYPE_QUALS (type);
+ return type;
+}
+
+/* Returns the type-qualifier set corresponding to TYPE. */
+
+int
+cp_type_quals (type)
+ tree type;
+{
+ return TYPE_QUALS (strip_array_types (type));
}
/* Returns non-zero if the TYPE contains a mutable member */
return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
}
+
+/* Subroutine of casts_away_constness. Make T1 and T2 point at
+ exemplar types such that casting T1 to T2 is casting away castness
+ if and only if there is no implicit conversion from T1 to T2. */
+
+static void
+casts_away_constness_r (t1, t2)
+ tree *t1;
+ tree *t2;
+{
+ int quals1;
+ int quals2;
+
+ /* [expr.const.cast]
+
+ For multi-level pointer to members and multi-level mixed pointers
+ and pointers to members (conv.qual), the "member" aspect of a
+ pointer to member level is ignored when determining if a const
+ cv-qualifier has been cast away. */
+ if (TYPE_PTRMEM_P (*t1))
+ *t1 = build_pointer_type (TREE_TYPE (TREE_TYPE (*t1)));
+ if (TYPE_PTRMEM_P (*t2))
+ *t2 = build_pointer_type (TREE_TYPE (TREE_TYPE (*t2)));
+
+ /* [expr.const.cast]
+
+ For two pointer types:
+
+ X1 is T1cv1,1 * ... cv1,N * where T1 is not a pointer type
+ X2 is T2cv2,1 * ... cv2,M * where T2 is not a pointer type
+ K is min(N,M)
+
+ casting from X1 to X2 casts away constness if, for a non-pointer
+ type T there does not exist an implicit conversion (clause
+ _conv_) from:
+
+ Tcv1,(N-K+1) * cv1,(N-K+2) * ... cv1,N *
+
+ to
+
+ Tcv2,(M-K+1) * cv2,(M-K+2) * ... cv2,M *. */
+
+ if (TREE_CODE (*t1) != POINTER_TYPE
+ || TREE_CODE (*t2) != POINTER_TYPE)
+ {
+ *t1 = cp_build_qualified_type (void_type_node,
+ CP_TYPE_QUALS (*t1));
+ *t2 = cp_build_qualified_type (void_type_node,
+ CP_TYPE_QUALS (*t2));
+ return;
+ }
+
+ quals1 = CP_TYPE_QUALS (*t1);
+ quals2 = CP_TYPE_QUALS (*t2);
+ *t1 = TREE_TYPE (*t1);
+ *t2 = TREE_TYPE (*t2);
+ casts_away_constness_r (t1, t2);
+ *t1 = build_pointer_type (*t1);
+ *t2 = build_pointer_type (*t2);
+ *t1 = cp_build_qualified_type (*t1, quals1);
+ *t2 = cp_build_qualified_type (*t2, quals2);
+}
+
+/* Returns non-zero if casting from TYPE1 to TYPE2 casts away
+ constness. */
+
+static int
+casts_away_constness (t1, t2)
+ tree t1;
+ tree t2;
+{
+ if (TREE_CODE (t2) == REFERENCE_TYPE)
+ {
+ /* [expr.const.cast]
+
+ Casting from an lvalue of type T1 to an lvalue of type T2
+ using a reference cast casts away constness if a cast from an
+ rvalue of type "pointer to T1" to the type "pointer to T2"
+ casts away constness. */
+ t1 = (TREE_CODE (t1) == REFERENCE_TYPE
+ ? TREE_TYPE (t1) : t1);
+ return casts_away_constness (build_pointer_type (t1),
+ build_pointer_type (TREE_TYPE (t2)));
+ }
+
+ if (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
+ /* [expr.const.cast]
+
+ Casting from an rvalue of type "pointer to data member of X
+ of type T1" to the type "pointer to data member of Y of type
+ T2" casts away constness if a cast from an rvalue of type
+ "poitner to T1" to the type "pointer to T2" casts away
+ constness. */
+ return casts_away_constness
+ (build_pointer_type (TREE_TYPE (TREE_TYPE (t1))),
+ build_pointer_type (TREE_TYPE (TREE_TYPE (t2))));
+
+ /* Casting away constness is only something that makes sense for
+ pointer or reference types. */
+ if (TREE_CODE (t1) != POINTER_TYPE
+ || TREE_CODE (t2) != POINTER_TYPE)
+ return 0;
+
+ /* Top-level qualifiers don't matter. */
+ t1 = TYPE_MAIN_VARIANT (t1);
+ t2 = TYPE_MAIN_VARIANT (t2);
+ casts_away_constness_r (&t1, &t2);
+ if (!can_convert (t2, t1))
+ return 1;
+
+ return 0;
+}