#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"
-extern void compiler_error ();
-
-static tree convert_for_assignment PROTO((tree, tree, char*, tree,
+static tree convert_for_assignment PROTO((tree, tree, const char *, tree,
int));
static tree pointer_int_sum PROTO((enum tree_code, tree, tree));
static tree rationalize_conditional_expr PROTO((enum tree_code, tree));
static int comp_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 build_ptrmemfunc1 PROTO((tree, tree, tree, tree, tree));
static tree common_base_type PROTO((tree, tree));
#if 0
static tree convert_sequence PROTO((tree, tree));
#endif
static tree lookup_anon_field PROTO((tree, tree));
static tree pointer_diff PROTO((tree, tree, tree));
+static tree build_component_addr 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
{
tree type;
- if (processing_template_decl)
+ if (processing_template_decl || value == error_mark_node)
return value;
if (TREE_CODE (value) == OVERLOAD)
/* First, detect a valid value with a complete type. */
if (TYPE_SIZE (type) != 0
- && type != void_type_node
- && ! (TYPE_LANG_SPECIFIC (type)
- && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))
- && TYPE_SIZE (SIGNATURE_TYPE (type)) == 0))
+ && TYPE_SIZE (type) != size_zero_node)
return value;
/* If we see X::Y, we build an OFFSET_TYPE which has
return require_complete_type (value);
}
- if (complete_type_or_else (type))
+ if (complete_type_or_else (type, value))
return value;
else
return error_mark_node;
}
/* Like complete_type, but issue an error if the TYPE cannot be
- completed. Returns NULL_TREE if the type cannot be made
- complete. */
+ completed. VALUE is used for informative diagnostics.
+ Returns NULL_TREE if the type cannot be made complete. */
tree
-complete_type_or_else (type)
+complete_type_or_else (type, value)
tree type;
+ tree value;
{
type = complete_type (type);
if (type == error_mark_node)
/* We already issued an error. */
return NULL_TREE;
- else if (!TYPE_SIZE (type))
+ else if (!TYPE_SIZE (type) || TYPE_SIZE (type) == size_zero_node)
{
- incomplete_type_error (NULL_TREE, type);
+ incomplete_type_error (value, type);
return NULL_TREE;
}
else
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:
But ANSI C++ specifies doing this with the qualifiers.
So I turned it on again. */
{
- tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (t1));
- tree tt2 = TYPE_MAIN_VARIANT (TREE_TYPE (t2));
- int type_quals = (CP_TYPE_QUALS (TREE_TYPE (t1))
- | CP_TYPE_QUALS (TREE_TYPE (t2)));
+ tree tt1 = TREE_TYPE (t1);
+ tree tt2 = TREE_TYPE (t2);
+ tree b1, b2;
+ int type_quals;
tree target;
+ if (TREE_CODE (tt1) == OFFSET_TYPE)
+ {
+ b1 = TYPE_OFFSET_BASETYPE (tt1);
+ b2 = TYPE_OFFSET_BASETYPE (tt2);
+ tt1 = TREE_TYPE (tt1);
+ tt2 = TREE_TYPE (tt2);
+ }
+ else
+ b1 = b2 = NULL_TREE;
+
+ type_quals = (CP_TYPE_QUALS (tt1) | CP_TYPE_QUALS (tt2));
+ tt1 = TYPE_MAIN_VARIANT (tt1);
+ tt2 = TYPE_MAIN_VARIANT (tt2);
+
if (tt1 == tt2)
target = tt1;
else if (tt1 == void_type_node || tt2 == void_type_node)
target = common_type (tt1, tt2);
target = cp_build_qualified_type (target, type_quals);
+
+ if (b1)
+ {
+ if (same_type_p (b1, b2)
+ || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
+ target = build_offset_type (b2, target);
+ else if (binfo_or_else (b2, b1))
+ target = build_offset_type (b1, target);
+ }
+
if (code1 == POINTER_TYPE)
t1 = build_pointer_type (target);
else
return build_type_attribute_variant (t1, attributes);
case OFFSET_TYPE:
- if (TREE_TYPE (t1) == TREE_TYPE (t2))
- {
- tree b1 = TYPE_OFFSET_BASETYPE (t1);
- tree b2 = TYPE_OFFSET_BASETYPE (t2);
-
- if (same_type_p (b1, b2)
- || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
- return build_type_attribute_variant (t2, attributes);
- else if (binfo_or_else (b2, b1))
- return build_type_attribute_variant (t1, attributes);
- }
- compiler_error ("common_type called with uncommon member types");
+ /* Pointers to members should now be handled by the POINTER_TYPE
+ case above. */
+ my_friendly_abort (990325);
default:
return build_type_attribute_variant (t1, attributes);
}
}
\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;
#define COMP_TYPE_ATTRIBUTES(t1,t2) 1
#endif
+ if (strict & COMPARE_NO_ATTRIBUTES)
+ attrval = 1;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
- if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2)))
+ else if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2)))
return 0;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
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;
}
{
ttl = TYPE_MAIN_VARIANT (ttl);
ttr = TYPE_MAIN_VARIANT (ttr);
- if (ttl == ttr)
+ if (same_type_p (ttl, ttr))
return 1;
if (TREE_CODE (ttr) != TREE_CODE (ttl))
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);
}
+ else if (type_unknown_p (e))
+ {
+ 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;
}
\f
-/* Perform default promotions for C data used in expressions.
- Arrays and functions are converted to pointers;
- enumeral types or short or char, to int.
- In addition, manifest constants symbols are replaced by their values.
+/* Perform the array-to-pointer and function-to-pointer conversions
+ for EXP.
- C++: this will automatically bash references to their target type. */
+ In addition, references are converted to rvalues and manifest
+ constants are replaced by their values. */
tree
decay_conversion (exp)
tree exp;
{
- register tree type = TREE_TYPE (exp);
- register enum tree_code code = TREE_CODE (type);
-
- if (code == OFFSET_TYPE)
- {
- if (TREE_CODE (exp) == OFFSET_REF)
- return decay_conversion (resolve_offset_ref (exp));
+ register tree type;
+ register enum tree_code code;
- type = TREE_TYPE (type);
- code = TREE_CODE (type);
+ if (TREE_CODE (exp) == OFFSET_REF)
+ exp = resolve_offset_ref (exp);
- if (type == unknown_type_node)
- {
- cp_pedwarn ("assuming & on overloaded member function");
- return build_unary_op (ADDR_EXPR, exp, 0);
- }
- }
+ type = TREE_TYPE (exp);
+ code = TREE_CODE (type);
if (code == REFERENCE_TYPE)
{
/* Constants can be used directly unless they're not loadable. */
if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp);
- /* Replace a nonvolatile const static variable with its value. */
- else if (TREE_READONLY_DECL_P (exp))
+ /* Replace a nonvolatile const static variable with its value. We
+ don't do this for arrays, though; we want the address of the
+ first element of the array, not the address of the first element
+ of its initializing constant. We *do* replace variables that the
+ user isn't really supposed to know about; this is a hack to deal
+ with __PRETTY_FUNCTION__ and the like. */
+ else if (TREE_READONLY_DECL_P (exp)
+ && (code != ARRAY_TYPE
+ || (TREE_CODE (exp) == VAR_DECL && DECL_IGNORED_P (exp))))
{
exp = decl_constant_value (exp);
type = TREE_TYPE (exp);
return error_mark_node;
}
if (code == METHOD_TYPE)
- {
- cp_pedwarn ("assuming & on `%E'", exp);
- return build_unary_op (ADDR_EXPR, exp, 0);
- }
+ my_friendly_abort (990506);
if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
- {
- return build_unary_op (ADDR_EXPR, exp, 0);
- }
+ return build_unary_op (ADDR_EXPR, exp, 0);
if (code == ARRAY_TYPE)
{
register tree adr;
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;
}
if (TREE_CODE (exp) == STRING_CST)
{
/* Make sure that we don't try to convert between char and wchar_t. */
- if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (exp))) != t)
+ if (!same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (exp))), t))
return 0;
}
else
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);
/* Otherwise, it could be nested, search harder. */
if (DECL_NAME (field) == NULL_TREE
- && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
tree subfield = lookup_anon_field (TREE_TYPE (field), type);
if (subfield)
return error_mark_node;
}
- if (!complete_type_or_else (basetype))
+ if (!complete_type_or_else (basetype, datum))
return error_mark_node;
if (TREE_CODE (component) == BIT_NOT_EXPR)
}
/* 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,
}
ref = build (COMPONENT_REF, unknown_type_node,
- datum, fndecls);
+ datum, TREE_VALUE (fndecls));
return ref;
}
tree context = DECL_FIELD_CONTEXT (field);
tree base = context;
while (!same_type_p (base, basetype) && TYPE_NAME (base)
- && ANON_UNION_TYPE_P (base))
+ && ANON_AGGR_TYPE_P (base))
{
base = TYPE_CONTEXT (base);
}
basetype = base;
/* Handle things from anon unions here... */
- if (TYPE_NAME (context) && ANON_UNION_TYPE_P (context))
+ if (TYPE_NAME (context) && ANON_AGGR_TYPE_P (context))
{
tree subfield = lookup_anon_field (basetype, context);
tree subdatum = build_component_ref (datum, subfield,
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,
tree
build_x_indirect_ref (ptr, errorstring)
tree ptr;
- char *errorstring;
+ const char *errorstring;
{
tree rval;
tree
build_indirect_ref (ptr, errorstring)
tree ptr;
- char *errorstring;
+ const char *errorstring;
{
register tree pointer, type;
if (ptr == error_mark_node)
return error_mark_node;
+ if (ptr == current_class_ptr)
+ return current_class_ref;
+
pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
? ptr : default_conversion (ptr));
type = TREE_TYPE (pointer);
- if (ptr == current_class_ptr)
- return current_class_ref;
-
if (TYPE_PTR_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
{
/* [expr.unary.op]
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)
TYPE_BINFO (type), LOOKUP_NORMAL);
}
+ if ((TREE_CODE (function) == FUNCTION_DECL
+ && DECL_STATIC_FUNCTION_P (function))
+ || (TREE_CODE (function) == TEMPLATE_DECL
+ && DECL_STATIC_FUNCTION_P (DECL_RESULT (function))))
+ return build_member_call(DECL_CONTEXT (function),
+ template_id
+ ? template_id : DECL_NAME (function),
+ params);
+
is_method = ((TREE_CODE (function) == TREE_LIST
&& current_class_type != NULL_TREE
&& (IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function))
== function))
+ || (TREE_CODE (function) == OVERLOAD
+ && DECL_FUNCTION_MEMBER_P (OVL_CURRENT (function)))
|| TREE_CODE (function) == IDENTIFIER_NODE
|| TREE_CODE (type) == METHOD_TYPE
|| TYPE_PTRMEMFUNC_P (type));
- if ((TREE_CODE (function) == FUNCTION_DECL
- && DECL_STATIC_FUNCTION_P (function))
- || (TREE_CODE (function) == TEMPLATE_DECL
- && DECL_STATIC_FUNCTION_P (DECL_RESULT (function))))
- return build_member_call
- (DECL_CONTEXT (function), DECL_NAME (function), params);
-
/* A friend template. Make it look like a toplevel declaration. */
if (! is_method && TREE_CODE (function) == TEMPLATE_DECL)
function = scratch_ovl_cons (function, NULL_TREE);
{
tree basetype = NULL_TREE;
+ if (TREE_CODE (function) == OVERLOAD)
+ function = OVL_CURRENT (function);
+
if (TREE_CODE (function) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (function))
{
{
if (current_class_type == NULL_TREE)
{
- error ("object missing in call to method `%s'",
- IDENTIFIER_POINTER (function));
+ cp_error ("object missing in call to method `%D'", function);
return error_mark_node;
}
/* Yow: call from a static member function. */
/* Undo what we did in build_component_ref. */
decl = TREE_OPERAND (function, 0);
function = TREE_OPERAND (function, 1);
- function = DECL_NAME (OVL_CURRENT (TREE_VALUE (function)));
+ function = DECL_NAME (OVL_CURRENT (function));
+
+ if (template_id)
+ {
+ TREE_OPERAND (template_id, 0) = function;
+ function = template_id;
+ }
+
return build_method_call (decl, function, params,
NULL_TREE, LOOKUP_NORMAL);
}
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 (GT_EXPR, idx, integer_zero_node, 1);
-
- /* Convert down to the right base, before using the instance. */
- instance = convert_pointer_to_real (basetype, instance_ptr);
- if (instance == error_mark_node && instance_ptr != error_mark_node)
- return instance;
-
- vtbl = convert_pointer_to (ptr_type_node, instance);
- delta2 = DELTA2_FROM_PTRMEMFUNC (function);
- vtbl = build
+ /* 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, 1));
- if (! flag_vtable_thunks)
- {
- aref = save_expr (aref);
-
- delta = build_binary_op
- (PLUS_EXPR,
- build_conditional_expr (e1,
- build_component_ref (aref,
- delta_identifier,
- NULL_TREE, 0),
- integer_zero_node),
- delta, 1);
- }
-
- if (flag_vtable_thunks)
- e2 = aref;
- else
- e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
- TREE_TYPE (e2) = TREE_TYPE (e3);
- e1 = build_conditional_expr (e1, e2, e3);
-
- /* Make sure this doesn't get evaluated first inside one of the
- branches of the COND_EXPR. */
- if (TREE_CODE (instance_ptr) == SAVE_EXPR)
- e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
- instance_ptr, e1);
+ 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:
if (require_complete)
{
- if (value_type == void_type_node)
+ if (TREE_CODE (value_type) == VOID_TYPE)
return result;
result = require_complete_type (result);
}
{
register tree typetail, valtail;
register tree result = NULL_TREE;
- char *called_thing = 0;
+ const char *called_thing = 0;
int i = 0;
/* Argument passing is always copy-initialization. */
{
if (fndecl)
{
- cp_error_at ("too many arguments to %s `%+D'", called_thing,
+ cp_error_at ("too many arguments to %s `%+#D'", called_thing,
fndecl);
error ("at this point in file");
}
|| TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
val = default_conversion (val);
-
- val = require_complete_type (val);
}
if (val == error_mark_node)
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)
{
if (fndecl)
{
- char *buf = (char *)alloca (32 + strlen (called_thing));
- sprintf (buf, "too few arguments to %s `%%#D'", called_thing);
- cp_error_at (buf, fndecl);
+ cp_error_at ("too few arguments to %s `%+#D'",
+ called_thing, fndecl);
error ("at this point in file");
}
else
}
tree
-build_binary_op (code, arg1, arg2, convert_p)
+build_binary_op (code, arg1, arg2)
enum tree_code code;
tree arg1, arg2;
- int convert_p ATTRIBUTE_UNUSED;
{
return build_binary_op_nodefault (code, arg1, arg2, code);
}
op1 = default_conversion (orig_op1);
}
+ /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
+ STRIP_TYPE_NOPS (op0);
+ STRIP_TYPE_NOPS (op1);
+
+ /* DTRT if one side is an overloaded function, but complain about it. */
+ if (type_unknown_p (op0))
+ {
+ tree t = instantiate_type (TREE_TYPE (op1), op0, 0);
+ if (t != error_mark_node)
+ {
+ cp_pedwarn ("assuming cast to `%T' from overloaded function",
+ TREE_TYPE (t));
+ op0 = t;
+ }
+ }
+ if (type_unknown_p (op1))
+ {
+ tree t = instantiate_type (TREE_TYPE (op0), op1, 0);
+ if (t != error_mark_node)
+ {
+ cp_pedwarn ("assuming cast to `%T' from overloaded function",
+ TREE_TYPE (t));
+ op1 = t;
+ }
+ }
+
type0 = TREE_TYPE (op0);
type1 = TREE_TYPE (op1);
code0 = TREE_CODE (type0);
code1 = TREE_CODE (type1);
- /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
- STRIP_TYPE_NOPS (op0);
- STRIP_TYPE_NOPS (op1);
-
/* If an error was already reported for one of the arguments,
avoid reporting another error. */
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;
result_type = TREE_TYPE (op0);
}
else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
- && (TYPE_PTRMEMFUNC_FN_TYPE (type0)
- == TYPE_PTRMEMFUNC_FN_TYPE (type1)))
+ && same_type_p (type0, type1))
{
/* The code we generate for the test is:
tree e1, e2, e3;
tree integer_neg_one_node
= build_binary_op (MINUS_EXPR, integer_zero_node,
- integer_one_node, 1);
- e1 = build_binary_op (EQ_EXPR, index0, index1, 1);
- e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node, 1);
+ integer_one_node);
+ e1 = build_binary_op (EQ_EXPR, index0, index1);
+ e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
- build_binary_op (EQ_EXPR, delta20, delta21, 1),
- 1);
- e3 = build_binary_op (EQ_EXPR, pfn0, pfn1, 1);
- e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3, 1);
- e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2, 1);
+ build_binary_op (EQ_EXPR, delta20, delta21));
+ /* We can't use build_binary_op for this cmp because it would get
+ confused by the ptr to method types and think we want pmfs. */
+ e3 = build (EQ_EXPR, boolean_type_node, pfn0, pfn1);
+ e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
+ e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
if (code == EQ_EXPR)
return e2;
- return build_binary_op (EQ_EXPR, e2, integer_zero_node, 1);
+ return build_binary_op (EQ_EXPR, e2, integer_zero_node);
}
else if (TYPE_PTRMEMFUNC_P (type0)
- && TYPE_PTRMEMFUNC_FN_TYPE (type0) == type1)
+ && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type0), type1))
{
tree index0 = build_component_ref (op0, index_identifier,
NULL_TREE, 0);
tree delta21 = integer_zero_node;
tree e1, e2, e3;
tree integer_neg_one_node
- = build_binary_op (MINUS_EXPR, integer_zero_node, integer_one_node, 1);
+ = build_binary_op (MINUS_EXPR, integer_zero_node, integer_one_node);
if (TREE_CODE (TREE_OPERAND (op1, 0)) == FUNCTION_DECL
&& DECL_VINDEX (TREE_OPERAND (op1, 0)))
{
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_CONSTANT (nop1) = TREE_CONSTANT (op1);
op1 = nop1;
}
- e1 = build_binary_op (EQ_EXPR, index0, index1, 1);
- e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node, 1);
+ e1 = build_binary_op (EQ_EXPR, index0, index1);
+ e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
- build_binary_op (EQ_EXPR, delta20, delta21, 1),
- 1);
- e3 = build_binary_op (EQ_EXPR, pfn0, op1, 1);
- e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3, 1);
- e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2, 1);
+ build_binary_op (EQ_EXPR, delta20, delta21));
+ /* We can't use build_binary_op for this cmp because it would get
+ confused by the ptr to method types and think we want pmfs. */
+ e3 = build (EQ_EXPR, boolean_type_node, pfn0, op1);
+ e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
+ e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
if (code == EQ_EXPR)
return e2;
- return build_binary_op (EQ_EXPR, e2, integer_zero_node, 1);
+ return build_binary_op (EQ_EXPR, e2, integer_zero_node);
}
else if (TYPE_PTRMEMFUNC_P (type1)
- && TYPE_PTRMEMFUNC_FN_TYPE (type1) == type0)
- {
- return build_binary_op (code, op1, op0, 1);
- }
+ && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type1), type0))
+ return build_binary_op (code, op1, op0);
break;
case MAX_EXPR:
register tree result_type = TREE_TYPE (ptrop);
- if (!complete_type_or_else (result_type))
+ if (!complete_type_or_else (result_type, ptrop))
return error_mark_node;
if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
enum tree_code subcode = resultcode;
if (TREE_CODE (intop) == MINUS_EXPR)
subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
- ptrop = build_binary_op (subcode, ptrop, TREE_OPERAND (intop, 1), 1);
+ ptrop = build_binary_op (subcode, ptrop, TREE_OPERAND (intop, 1));
intop = TREE_OPERAND (intop, 0);
}
intop = cp_convert (result_type,
build_binary_op (MULT_EXPR, intop,
cp_convert (TREE_TYPE (intop),
- size_exp),
- 1));
+ size_exp)));
/* Create the sum or difference. */
tree restype = ptrdiff_type_node;
tree target_type = TREE_TYPE (ptrtype);
- if (!complete_type_or_else (target_type))
+ if (!complete_type_or_else (target_type, NULL_TREE))
return error_mark_node;
if (pedantic || warn_pointer_arith)
then drop through to build the divide operator. */
op0 = build_binary_op (MINUS_EXPR, cp_convert (restype, op0),
- cp_convert (restype, op1), 1);
+ cp_convert (restype, op1));
/* This generates an error if op1 is a pointer to an incomplete type. */
if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0)
}
\f
/* Handle the case of taking the address of a COMPONENT_REF.
- Called by `build_unary_op' and `build_up_reference'.
+ Called by `build_unary_op'.
ARG is the COMPONENT_REF whose address we want.
- ARGTYPE is the pointer type that this address should have.
- MSG is an error message to print if this COMPONENT_REF is not
- addressable (such as a bitfield). */
+ ARGTYPE is the pointer type that this address should have. */
-tree
-build_component_addr (arg, argtype, msg)
+static tree
+build_component_addr (arg, argtype)
tree arg, argtype;
- char *msg;
{
tree field = TREE_OPERAND (arg, 1);
tree basetype = decl_type_context (field);
if (DECL_C_BIT_FIELD (field))
{
- error (msg, IDENTIFIER_POINTER (DECL_NAME (field)));
+ cp_error ("attempt to take address of bit-field structure member `%D'",
+ field);
return error_mark_node;
}
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;
}
/* No default_conversion here. It causes trouble for ADDR_EXPR. */
register tree arg = xarg;
register tree argtype = 0;
- char *errstring = NULL;
+ const char *errstring = NULL;
tree val;
if (arg == error_mark_node)
|| 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);
if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
return error_mark_node;
return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
- TREE_OPERAND (arg, 1), 1);
+ TREE_OPERAND (arg, 1));
}
/* Uninstantiated types are all functions. Taking the
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
+ if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
+ && 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.
+ 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. */
+
+ 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");
+
+ cp_pedwarn
+ (" to form a pointer to member function, say `&%T::%D'",
+ base, name);
+ }
+
+ arg = build_offset_ref (base, name);
+ }
+
if (type_unknown_p (arg))
return build1 (ADDR_EXPR, unknown_type_node, arg);
tree addr;
if (TREE_CODE (arg) == COMPONENT_REF)
- addr = build_component_addr
- (arg, argtype,
- "attempt to take address of bit-field structure member `%s'");
+ addr = build_component_addr (arg, argtype);
else
- addr = build1 (code, argtype, arg);
+ addr = build1 (ADDR_EXPR, argtype, arg);
/* Address of a static or external variable or
function counts as a constant */
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);
-}
-
-tree
-build_conditional_expr (ifexp, op1, op2)
- tree ifexp, op1, op2;
-{
- register tree type1;
- register tree type2;
- register enum tree_code code1;
- register enum tree_code code2;
- register tree result_type = NULL_TREE;
-
- /* If second operand is omitted, it is the same as the first one;
- make sure it is calculated only once. */
- if (op1 == 0)
- {
- if (pedantic)
- pedwarn ("ANSI C++ forbids omitting the middle term of a ?: expression");
- ifexp = op1 = save_expr (ifexp);
- }
-
- ifexp = cp_convert (boolean_type_node, ifexp);
-
- if (TREE_CODE (ifexp) == ERROR_MARK)
- return error_mark_node;
-
- /* C++: REFERENCE_TYPES must be dereferenced. */
- type1 = TREE_TYPE (op1);
- code1 = TREE_CODE (type1);
- type2 = TREE_TYPE (op2);
- code2 = TREE_CODE (type2);
-
- if (code1 == REFERENCE_TYPE)
- {
- op1 = convert_from_reference (op1);
- type1 = TREE_TYPE (op1);
- code1 = TREE_CODE (type1);
- }
- if (code2 == REFERENCE_TYPE)
- {
- op2 = convert_from_reference (op2);
- type2 = TREE_TYPE (op2);
- code2 = TREE_CODE (type2);
- }
-
- /* Don't promote the operands separately if they promote
- the same way. Return the unpromoted type and let the combined
- value get promoted if necessary. */
-
- if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
- && code2 != ARRAY_TYPE
- && code2 != FUNCTION_TYPE
- && code2 != METHOD_TYPE)
- {
- tree result;
-
- if (TREE_CONSTANT (ifexp)
- && (TREE_CODE (ifexp) == INTEGER_CST
- || TREE_CODE (ifexp) == ADDR_EXPR))
- return (integer_zerop (ifexp) ? op2 : op1);
-
- if (TREE_CODE (op1) == CONST_DECL)
- op1 = DECL_INITIAL (op1);
- else if (TREE_READONLY_DECL_P (op1))
- op1 = decl_constant_value (op1);
- if (TREE_CODE (op2) == CONST_DECL)
- op2 = DECL_INITIAL (op2);
- else if (TREE_READONLY_DECL_P (op2))
- op2 = decl_constant_value (op2);
- if (type1 != type2)
- type1 = cp_build_qualified_type
- (type1, (CP_TYPE_QUALS (TREE_TYPE (op1))
- | CP_TYPE_QUALS (TREE_TYPE (op2))));
- /* ??? This is a kludge to deal with the fact that
- we don't sort out integers and enums properly, yet. */
- result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
- if (TREE_TYPE (result) != type1)
- result = build1 (NOP_EXPR, type1, result);
- /* Expand both sides into the same slot,
- hopefully the target of the ?: expression. */
- if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
- {
- tree slot = build (VAR_DECL, TREE_TYPE (result));
- layout_decl (slot, 0);
- result = build (TARGET_EXPR, TREE_TYPE (result),
- slot, result, NULL_TREE, NULL_TREE);
- }
- return result;
- }
-
- /* They don't match; promote them both and then try to reconcile them.
- But don't permit mismatching enum types. */
- if (code1 == ENUMERAL_TYPE)
- {
- if (code2 == ENUMERAL_TYPE)
- {
- cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'",
- type1, type2);
- return error_mark_node;
- }
- else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2)
- && type2 != type_promotes_to (type1))
- warning ("enumeral and non-enumeral type in conditional expression");
- }
- else if (extra_warnings
- && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1)
- && type1 != type_promotes_to (type2))
- warning ("enumeral and non-enumeral type in conditional expression");
-
- if (code1 != VOID_TYPE)
- {
- op1 = default_conversion (op1);
- type1 = TREE_TYPE (op1);
- if (TYPE_PTRMEMFUNC_P (type1))
- type1 = TYPE_PTRMEMFUNC_FN_TYPE (type1);
- code1 = TREE_CODE (type1);
- }
- if (code2 != VOID_TYPE)
- {
- op2 = default_conversion (op2);
- type2 = TREE_TYPE (op2);
- if (TYPE_PTRMEMFUNC_P (type2))
- type2 = TYPE_PTRMEMFUNC_FN_TYPE (type2);
- code2 = TREE_CODE (type2);
- }
-
- if (code1 == RECORD_TYPE && code2 == RECORD_TYPE
- && real_lvalue_p (op1) && real_lvalue_p (op2)
- && comptypes (type1, type2, COMPARE_BASE | COMPARE_RELAXED))
- {
- type1 = build_reference_type (type1);
- type2 = build_reference_type (type2);
- result_type = common_type (type1, type2);
- op1 = convert_to_reference (result_type, op1, CONV_IMPLICIT,
- LOOKUP_NORMAL, NULL_TREE);
- op2 = convert_to_reference (result_type, op2, CONV_IMPLICIT,
- LOOKUP_NORMAL, NULL_TREE);
- }
- /* Quickly detect the usual case where op1 and op2 have the same type
- after promotion. */
- else if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
- {
- if (type1 == type2)
- result_type = type1;
- else
- result_type =
- cp_build_qualified_type (type1,
- CP_TYPE_QUALS (TREE_TYPE (op1))
- | CP_TYPE_QUALS (TREE_TYPE (op2)));
- }
- else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE)
- && (code2 == INTEGER_TYPE || code2 == REAL_TYPE))
- {
- result_type = common_type (type1, type2);
- }
- else if (code1 == VOID_TYPE || code2 == VOID_TYPE)
- {
- if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE))
- pedwarn ("ANSI C++ forbids conditional expr with only one void side");
- result_type = void_type_node;
- }
- else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2))
- result_type = qualify_type (type1, type2);
- else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1))
- result_type = qualify_type (type2, type1);
- else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
- {
- if (comp_target_types (type1, type2, 1))
- result_type = common_type (type1, type2);
- else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
- {
- if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
- result_type = qualify_type (type1, type2);
- }
- else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node)
- {
- if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
- result_type = qualify_type (type2, type1);
- }
- /* C++ */
- else if (same_or_base_type_p (type2, type1))
- result_type = type2;
- else if (IS_AGGR_TYPE (TREE_TYPE (type1))
- && IS_AGGR_TYPE (TREE_TYPE (type2))
- && (result_type = common_base_type (TREE_TYPE (type1),
- TREE_TYPE (type2))))
- {
- if (result_type == error_mark_node)
- {
- cp_error ("common base type of types `%T' and `%T' is ambiguous",
- TREE_TYPE (type1), TREE_TYPE (type2));
- result_type = ptr_type_node;
- }
- else
- {
- if (pedantic
- && result_type != TREE_TYPE (type1)
- && result_type != TREE_TYPE (type2))
- cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression",
- type1, type2, result_type);
-
- result_type = build_pointer_type (result_type);
- }
- }
- else
- {
- pedwarn ("pointer type mismatch in conditional expression");
- result_type = ptr_type_node;
- }
- }
- else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
- {
- pedwarn ("pointer/integer type mismatch in conditional expression");
- result_type = type1;
- }
- else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
- {
- pedwarn ("pointer/integer type mismatch in conditional expression");
- result_type = type2;
- }
- if (type2 == unknown_type_node)
- result_type = type1;
- else if (type1 == unknown_type_node)
- result_type = type2;
-
- if (!result_type)
- {
- /* The match does not look good. If either is
- an aggregate value, try converting to a scalar type. */
- if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
- {
- cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'",
- type1, type2);
- return error_mark_node;
- }
- /* Warning: this code assumes that conversion between cv-variants of
- a type is done using NOP_EXPRs. */
- if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
- {
- /* There are other types besides pointers and records. */
- tree tmp;
- if (code2 == POINTER_TYPE)
- tmp = build_pointer_type
- (cp_build_qualified_type (TREE_TYPE (type2),
- TYPE_QUAL_CONST
- | TYPE_QUAL_VOLATILE
- | TYPE_QUAL_RESTRICT));
- else
- tmp = type2;
- tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0);
- if (tmp == NULL_TREE)
- {
- cp_error ("incompatible types `%T' and `%T' in `?:'",
- type1, type2);
- return error_mark_node;
- }
- if (tmp == error_mark_node)
- error ("ambiguous pointer conversion");
- else
- STRIP_NOPS (tmp);
- result_type = common_type (type2, TREE_TYPE (tmp));
- op1 = tmp;
- }
- else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
- {
- tree tmp;
- if (code1 == POINTER_TYPE)
- tmp = build_pointer_type
- (cp_build_qualified_type (TREE_TYPE (type1),
- TYPE_QUAL_CONST
- | TYPE_QUAL_VOLATILE
- | TYPE_QUAL_RESTRICT));
- else
- tmp = type1;
-
- tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0);
- if (tmp == NULL_TREE)
- {
- cp_error ("incompatible types `%T' and `%T' in `?:'",
- type1, type2);
- return error_mark_node;
- }
- if (tmp == error_mark_node)
- error ("ambiguous pointer conversion");
- else
- STRIP_NOPS (tmp);
- result_type = common_type (type1, TREE_TYPE (tmp));
- op2 = tmp;
- }
- else if (flag_cond_mismatch)
- result_type = void_type_node;
- else
- {
- error ("type mismatch in conditional expression");
- return error_mark_node;
- }
- }
-
- if (TREE_CODE (result_type) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
- result_type = build_ptrmemfunc_type (result_type);
-
- if (result_type != TREE_TYPE (op1))
- op1 = convert_for_initialization
- (NULL_TREE, result_type, op1, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
- if (result_type != TREE_TYPE (op2))
- op2 = convert_for_initialization
- (NULL_TREE, result_type, op2, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
-
- if (TREE_CODE (ifexp) == INTEGER_CST)
- return integer_zerop (ifexp) ? op2 : op1;
-
- return convert_from_reference
- (fold (build (COND_EXPR, result_type, ifexp, op1, op2)));
+ return build_conditional_expr (ifexp, op1, op2);
}
\f
/* Handle overloading of the ',' operator when needed. Otherwise,
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))));
}
tree list;
{
register tree rest;
+ tree first;
if (TREE_READONLY_DECL_P (TREE_VALUE (list)))
TREE_VALUE (list) = decl_constant_value (TREE_VALUE (list));
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 = convert_to_void (first, "lhs of comma");
+ if (first == error_mark_node)
+ return error_mark_node;
+
rest = build_compound_expr (TREE_CHAIN (list));
+ if (rest == error_mark_node)
+ return error_mark_node;
/* When pedantic, a compound expression cannot be a constant expression. */
- if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)) && ! pedantic)
+ if (! TREE_SIDE_EFFECTS (first) && ! pedantic)
return rest;
return build (COMPOUND_EXPR, TREE_TYPE (rest),
- break_out_cleanups (TREE_VALUE (list)), rest);
+ break_out_cleanups (first), rest);
}
tree
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;
}
+ if (!POINTER_TYPE_P (type))
+ {
+ cp_error ("`%T' is not a pointer, reference, or pointer-to-data-member type",
+ type);
+ cp_error ("as required by const_cast");
+ }
+ else if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ {
+ cp_error ("`%T' is a pointer or reference to a function type",
+ type);
+ cp_error ("which is forbidden by const_cast");
+ return error_mark_node;
+ }
+
if (TREE_CODE (type) != REFERENCE_TYPE)
{
expr = decay_conversion (expr);
&& TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
value = TREE_OPERAND (value, 0);
- if (TREE_TYPE (expr)
- && TREE_CODE (TREE_TYPE (expr)) == OFFSET_TYPE
- && TREE_CODE (type) != OFFSET_TYPE)
+ if (TREE_CODE (value) == OFFSET_REF)
value = resolve_offset_ref (value);
if (TREE_CODE (type) == ARRAY_TYPE)
return error_mark_node;
}
- if (IS_SIGNATURE (type))
- {
- error ("cast specifies signature type");
- return error_mark_node;
- }
-
if (processing_template_decl)
{
tree t = build_min (CAST_EXPR, type,
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
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
olhstype = lhstype = TREE_TYPE (lhs);
}
+ if (lhs == error_mark_node)
+ return lhs;
+
if (TREE_CODE (lhstype) == REFERENCE_TYPE
&& modifycode != INIT_EXPR)
{
else
{
lhs = stabilize_reference (lhs);
- newrhs = build_binary_op (modifycode, lhs, rhs, 1);
+ newrhs = build_binary_op (modifycode, lhs, rhs);
if (newrhs == error_mark_node)
{
cp_error (" in evaluation of `%Q(%#T, %#T)'", modifycode,
/* Warn about storing in something that is `const'. */
/* For C++, don't warn if this is initialization. */
if (modifycode != INIT_EXPR
- /* For assignment to `const' signature pointer/reference fields,
- don't warn either, we already printed a better message before. */
- && ! (TREE_CODE (lhs) == COMPONENT_REF
- && (IS_SIGNATURE_POINTER (TREE_TYPE (TREE_OPERAND (lhs, 0)))
- || IS_SIGNATURE_REFERENCE (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
&& (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
/* Functions are not modifiable, even though they are
lvalues. */
|| TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE
- || ((TREE_CODE (lhstype) == RECORD_TYPE
- || TREE_CODE (lhstype) == UNION_TYPE)
+ || (IS_AGGR_TYPE_CODE (TREE_CODE (lhstype))
&& C_TYPE_FIELDS_READONLY (lhstype))
|| (TREE_CODE (lhstype) == REFERENCE_TYPE
&& CP_TYPE_CONST_P (TREE_TYPE (lhstype)))))
}
}
- /* check to see if there is an assignment to `this' */
- if (lhs == current_class_ptr)
- {
- if (flag_this_is_variable > 0
- && DECL_NAME (current_function_decl) != NULL_TREE
- && (DECL_NAME (current_function_decl)
- != constructor_name (current_class_type)))
- warning ("assignment to `this' not in constructor or destructor");
- current_function_just_assigned_this = 1;
- }
-
if (modifycode != INIT_EXPR)
{
/* Make modifycode now either a NOP_EXPR or an INIT_EXPR. */
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));
return build_binary_op (MINUS_EXPR,
integer_zero_node,
- delta, 1);
+ delta);
}
- if (TREE_VIA_VIRTUAL (binfo))
+ if (binfo_from_vbase (binfo))
{
if (force)
{
return BINFO_OFFSET (binfo);
}
-static tree
+tree
build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
tree type, delta, idx, pfn, delta2;
{
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 vfield_offset;
- 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, 1);
- delta2 = build_binary_op (PLUS_EXPR, ndelta2, n, 1);
+ 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);
}
if (type_unknown_p (pfn))
return instantiate_type (type, pfn, 1);
- if (!force
- && comp_target_types (type, TREE_TYPE (pfn), 0) != 1)
- cp_error ("conversion to `%T' from `%T'", type, TREE_TYPE (pfn));
+ fn = TREE_OPERAND (pfn, 0);
+ my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
+ return make_ptrmem_cst (to_type, fn);
+}
- /* Allow pointer to member conversions here. */
- delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
- TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
- force);
- delta2 = build_binary_op (PLUS_EXPR, delta2, delta, 1);
+/* Return the DELTA, IDX, PFN, and DELTA2 values for the PTRMEM_CST
+ given by CST. */
- if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL)
- warning ("assuming pointer to member function is non-virtual");
+void
+expand_ptrmemfunc_cst (cst, delta, idx, pfn, delta2)
+ tree cst;
+ tree *delta;
+ tree *idx;
+ tree *pfn;
+ tree *delta2;
+{
+ tree type = TREE_TYPE (cst);
+ tree fn = PTRMEM_CST_MEMBER (cst);
+ tree ptr_class, fn_class;
- if (TREE_CODE (TREE_OPERAND (pfn, 0)) == FUNCTION_DECL
- && DECL_VINDEX (TREE_OPERAND (pfn, 0)))
- {
- /* Find the offset to the vfield pointer in the object. */
- vfield_offset = get_binfo (DECL_CONTEXT (TREE_OPERAND (pfn, 0)),
- DECL_CLASS_CONTEXT (TREE_OPERAND (pfn, 0)),
- 0);
- vfield_offset = get_vfield_offset (vfield_offset);
- delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2);
+ my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
+
+ /* The class that the function belongs to. */
+ fn_class = DECL_CLASS_CONTEXT (fn);
- /* Map everything down one to make room for the null pointer to member. */
- idx = size_binop (PLUS_EXPR,
- DECL_VINDEX (TREE_OPERAND (pfn, 0)),
- integer_one_node);
+ /* 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 = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
+ *delta2 = NULL_TREE;
}
else
{
- idx = size_binop (MINUS_EXPR, integer_zero_node, 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));
- if (type == TREE_TYPE (pfn))
- {
- npfn = pfn;
- }
- else
- {
- npfn = build1 (NOP_EXPR, type, pfn);
- TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
- }
+ /* 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;
+
+ /* 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)));
+ }
+}
+
+/* Return an expression for DELTA2 from the pointer-to-member function
+ given by T. */
+
+tree
+delta2_from_ptrmemfunc (t)
+ tree t;
+{
+ if (TREE_CODE (t) == PTRMEM_CST)
+ {
+ tree delta;
+ tree idx;
+ tree pfn;
+ tree delta2;
+
+ expand_ptrmemfunc_cst (t, &delta, &idx, &pfn, &delta2);
+ if (delta2)
+ return delta2;
}
- return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2);
+ return (build_component_ref
+ (build_component_ref (t,
+ pfn_or_delta2_identifier, NULL_TREE,
+ 0),
+ delta2_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.
+/* Return an expression for PFN from the pointer-to-member function
+ given by T. */
+
+tree
+pfn_from_ptrmemfunc (t)
+ tree t;
+{
+ if (TREE_CODE (t) == PTRMEM_CST)
+ {
+ tree delta;
+ tree idx;
+ tree pfn;
+ tree delta2;
+
+ expand_ptrmemfunc_cst (t, &delta, &idx, &pfn, &delta2);
+ if (pfn)
+ return pfn;
+ }
+
+ return (build_component_ref
+ (build_component_ref (t,
+ pfn_or_delta2_identifier, NULL_TREE,
+ 0),
+ pfn_identifier, NULL_TREE, 0));
+}
- 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)
tree type, rhs;
- char *errtype;
+ const char *errtype;
tree fndecl;
int parmnum;
{
register enum tree_code codel = TREE_CODE (type);
register tree rhstype;
- register enum tree_code coder = TREE_CODE (TREE_TYPE (rhs));
-
- /* Issue warnings about peculiar, but legal, uses of NULL. */
- if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
- cp_warning ("converting NULL to non-pointer type");
-
- if (coder == ERROR_MARK)
- return error_mark_node;
+ register enum tree_code coder;
if (codel == OFFSET_TYPE)
- {
- type = TREE_TYPE (type);
- codel = TREE_CODE (type);
- }
+ my_friendly_abort (990505);
+
+ if (TREE_CODE (rhs) == OFFSET_REF)
+ rhs = resolve_offset_ref (rhs);
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
rhs = TREE_OPERAND (rhs, 0);
- if (rhs == error_mark_node)
- return error_mark_node;
+ 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)) == OFFSET_TYPE)
+ /* 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");
+
+ /* The RHS of an assignment cannot have void type. */
+ if (coder == VOID_TYPE)
{
- rhs = resolve_offset_ref (rhs);
- if (rhs == error_mark_node)
- return error_mark_node;
- rhstype = TREE_TYPE (rhs);
- coder = TREE_CODE (rhstype);
+ error ("void value not ignored as it ought to be");
+ 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);
-
- /* This should no longer change types on us. */
+ /* 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 (same_type_p (type, rhstype))
+ /* Warn about assigning a floating-point type to an integer type. */
+ if (coder == REAL_TYPE && codel == INTEGER_TYPE)
{
- overflow_warning (rhs);
- return rhs;
- }
-
- if (coder == VOID_TYPE)
- {
- error ("void value not ignored as it ought to be");
- return error_mark_node;
+ 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);
}
- /* 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))
+ /* And warn about assigning a negative value to an unsigned
+ variable. */
+ else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
{
- /* But we should warn if assigning REAL_TYPE to INTEGER_TYPE. */
- if (coder == REAL_TYPE && codel == INTEGER_TYPE)
+ if (TREE_CODE (rhs) == INTEGER_CST
+ && TREE_NEGATED_INT (rhs))
{
if (fndecl)
- cp_warning ("`%T' used for argument %P of `%D'",
- rhstype, parmnum, fndecl);
- else
- cp_warning ("%s to `%T' from `%T'", errtype, type, rhstype);
- }
- /* And we should warn if assigning a negative value to
- an unsigned variable. */
- else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
- {
- if (TREE_CODE (rhs) == INTEGER_CST
- && TREE_NEGATED_INT (rhs))
- {
- if (fndecl)
- cp_warning ("negative value `%E' passed as argument %P of `%D'",
- rhs, parmnum, fndecl);
- else
- cp_warning ("%s of negative value `%E' to `%T'",
- errtype, rhs, type);
- }
- overflow_warning (rhs);
- if (TREE_CONSTANT (rhs))
- rhs = fold (rhs);
- }
-
- return convert_and_check (type, rhs);
- }
- /* Conversions involving enums. */
- else if ((codel == ENUMERAL_TYPE
- && (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE))
- || (coder == ENUMERAL_TYPE
- && (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
- {
- return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
- }
- /* Conversions among pointers */
- else if (codel == POINTER_TYPE
- && (coder == POINTER_TYPE
- || (coder == RECORD_TYPE
- && (IS_SIGNATURE_POINTER (rhstype)
- || IS_SIGNATURE_REFERENCE (rhstype)))))
- {
- register tree ttl = TREE_TYPE (type);
- register tree ttr;
- int ctt = 0;
-
- if (coder == RECORD_TYPE)
- {
- rhs = build_optr_ref (rhs);
- rhstype = TREE_TYPE (rhs);
- }
- ttr = TREE_TYPE (rhstype);
-
- /* If both pointers are of aggregate type, then we
- can give better error messages, and save some work
- as well. */
- if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
- {
- tree binfo;
-
- if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr)
- || type == class_star_type_node
- || rhstype == class_star_type_node)
- binfo = TYPE_BINFO (ttl);
- else
- binfo = get_binfo (ttl, ttr, 1);
-
- if (binfo == error_mark_node)
- return error_mark_node;
- if (binfo == 0)
- return error_not_base_type (ttl, ttr);
-
- if (!at_least_as_qualified_p (ttl, ttr))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
- errtype, type, rhstype);
- }
- }
-
- /* Any non-function converts to a [const][volatile] void *
- and vice versa; otherwise, targets must be the same.
- Meanwhile, the lhs target must have all the qualifiers of the rhs. */
- else if (TYPE_MAIN_VARIANT (ttl) == void_type_node
- || TYPE_MAIN_VARIANT (ttr) == void_type_node
- || (ctt = comp_target_types (type, rhstype, 1))
- || (unsigned_type (TYPE_MAIN_VARIANT (ttl))
- == unsigned_type (TYPE_MAIN_VARIANT (ttr))))
- {
- /* ARM $4.8, commentary on p39. */
- if (TYPE_MAIN_VARIANT (ttl) == void_type_node
- && TREE_CODE (ttr) == OFFSET_TYPE)
- {
- cp_error ("no standard conversion from `%T' to `void *'", ttr);
- return error_mark_node;
- }
-
- if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr))
- cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
- rhstype, type);
-
- if (TYPE_MAIN_VARIANT (ttl) != void_type_node
- && TYPE_MAIN_VARIANT (ttr) == void_type_node
- && ! null_ptr_cst_p (rhs))
- {
- if (coder == RECORD_TYPE)
- cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
- type);
- else
- pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s",
- errtype);
- }
- /* Const and volatile mean something different for function types,
- so the usual warnings are not appropriate. */
- else if ((TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttr) != METHOD_TYPE)
- || (TREE_CODE (ttl) != FUNCTION_TYPE && TREE_CODE (ttl) != METHOD_TYPE))
- {
- if (TREE_CODE (ttl) == OFFSET_TYPE
- && binfo_member (TYPE_OFFSET_BASETYPE (ttr),
- CLASSTYPE_VBASECLASSES (TYPE_OFFSET_BASETYPE (ttl))))
- {
- error ("%s between pointer to members converting across virtual baseclasses", errtype);
- return error_mark_node;
- }
- else if (!at_least_as_qualified_p (ttl, ttr))
- {
- if (string_conv_p (type, rhs, 1))
- /* converting from string constant to char *, OK. */;
- else if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
- errtype, type, rhstype);
- }
- else if (TREE_CODE (ttl) == TREE_CODE (ttr)
- && ! comp_target_types (type, rhstype, 1))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' changes signedness",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' changes signedness",
- errtype, type, rhstype);
- }
- }
- }
- else
- {
- int add_quals = 0;
- int drops_quals = 0;
- int left_const = 1;
- int unsigned_parity;
- int nptrs = 0;
-
- /* This code is basically a duplicate of comp_ptr_ttypes_real. */
- for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr))
- {
- nptrs -= 1;
- drops_quals |= !at_least_as_qualified_p (ttl, ttr);
-
- if (! left_const
- && !at_least_as_qualified_p (ttr, ttl))
- add_quals = 1;
- left_const &= TYPE_READONLY (ttl);
-
- if (TREE_CODE (ttl) != POINTER_TYPE
- || TREE_CODE (ttr) != POINTER_TYPE)
- break;
- }
- unsigned_parity = TREE_UNSIGNED (ttl) - TREE_UNSIGNED (ttr);
- if (unsigned_parity)
- {
- if (TREE_UNSIGNED (ttl))
- ttr = unsigned_type (ttr);
- else
- ttl = unsigned_type (ttl);
- }
-
- if (comp_target_types (ttl, ttr, nptrs) > 0)
- {
- if (add_quals)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' adds cv-quals without intervening `const'",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' adds cv-quals without intervening `const'",
- errtype, type, rhstype);
- }
- if (drops_quals)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
- errtype, type, rhstype);
- }
- if (unsigned_parity > 0)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' changes signed to unsigned",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' changes signed to unsigned",
- errtype, type, rhstype);
- }
- else if (unsigned_parity < 0)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' changes unsigned to signed",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' changes unsigned to signed",
- errtype, type, rhstype);
- }
-
- /* C++ is not so friendly about converting function and
- member function pointers as C. Emit warnings here. */
- if (TREE_CODE (ttl) == FUNCTION_TYPE
- || TREE_CODE (ttl) == METHOD_TYPE)
- if (!same_or_base_type_p (ttl, ttr))
- {
- warning ("conflicting function types in %s:", errtype);
- cp_warning ("\t`%T' != `%T'", type, rhstype);
- }
- }
+ cp_warning ("negative value `%E' passed as argument %P of `%D'",
+ rhs, parmnum, fndecl);
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;
- }
+ cp_warning ("%s of negative value `%E' to `%T'",
+ errtype, rhs, type);
}
- return cp_convert (type, rhs);
- }
- else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
- {
- /* An explicit constant 0 can convert to a pointer,
- but not a 0 that results from casting or folding. */
- if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs)))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast",
- rhstype, parmnum, fndecl);
+ 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_pedwarn ("%s to `%T' from `%T' lacks a cast",
- errtype, type, rhstype);
+ 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.
convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
tree exp, type, rhs;
int flags;
- char *errtype;
+ const char *errtype;
tree fndecl;
int parmnum;
{
|| (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node))
return error_mark_node;
- if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
+ if (TREE_CODE (rhs) == OFFSET_REF)
{
rhs = resolve_offset_ref (rhs);
if (rhs == error_mark_node)
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)
return rhs;
}
- rhs = require_complete_type (rhs);
- if (rhs == error_mark_node)
- return error_mark_node;
-
- if (exp != 0) exp = require_complete_type (exp);
+ if (exp != 0)
+ exp = require_complete_type (exp);
if (exp == error_mark_node)
return error_mark_node;
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
{
tree type = TREE_TYPE (o[i]);
if (CP_TYPE_CONST_P (type)
- || ((TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == UNION_TYPE)
+ || (IS_AGGR_TYPE_CODE (TREE_CODE (type))
&& C_TYPE_FIELDS_READONLY (type)))
readonly_error (o[i], "modification by `asm'", 1);
}
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");
-
- /* Can't just return from a destructor. */
- expand_goto (dtor_label);
- return;
+ return NULL_TREE;
}
-
- if (retval == NULL_TREE)
+ else if (in_function_try_handler
+ && DECL_CONSTRUCTOR_P (current_function_decl))
{
- /* 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;
+ /* 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
- {
- current_function_returns_null = 1;
+ pedwarn ("`return' with a value, in function returning void");
- 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;
- }
- }
+ current_function_returns_null = 1;
- 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;
+ /* 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_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_TYPE (retval) == void_type_node)
- {
- 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;
+}