/* Build expressions with type checking for C++ compiler.
- Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-99, 2000 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
#include "tree.h"
#include "rtl.h"
#include "cp-tree.h"
+#include "tm_p.h"
#include "flags.h"
#include "output.h"
#include "expr.h"
#include "toplev.h"
+#include "defaults.h"
-static tree convert_for_assignment PROTO((tree, tree, const char *, tree,
+static tree convert_for_assignment PARAMS ((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_target_parms PROTO((tree, tree, int));
-static int comp_ptr_ttypes_real PROTO((tree, tree, int));
-static int comp_ptr_ttypes_const PROTO((tree, tree));
-static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
-static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
+static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree));
+static tree rationalize_conditional_expr PARAMS ((enum tree_code, tree));
+static int comp_target_parms PARAMS ((tree, tree, int));
+static int comp_ptr_ttypes_real PARAMS ((tree, tree, int));
+static int comp_ptr_ttypes_const PARAMS ((tree, tree));
+static int comp_ptr_ttypes_reinterpret PARAMS ((tree, tree));
+static int comp_except_types PARAMS ((tree, tree, int));
+static int comp_array_types PARAMS ((int (*) (tree, tree, int), tree,
tree, int));
-static tree common_base_type PROTO((tree, tree));
+static tree common_base_type PARAMS ((tree, tree));
#if 0
-static tree convert_sequence PROTO((tree, tree));
+static tree convert_sequence PARAMS ((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));
-
-/* Return the target type of TYPE, which meas return T for:
+static tree lookup_anon_field PARAMS ((tree, tree));
+static tree pointer_diff PARAMS ((tree, tree, tree));
+static tree build_component_addr PARAMS ((tree, tree));
+static tree qualify_type PARAMS ((tree, tree));
+static tree get_delta_difference PARAMS ((tree, tree, int));
+static int comp_cv_target_types PARAMS ((tree, tree, int));
+static void casts_away_constness_r PARAMS ((tree *, tree *));
+static int casts_away_constness PARAMS ((tree, tree));
+static void maybe_warn_about_returning_address_of_local PARAMS ((tree));
+static tree strip_all_pointer_quals PARAMS ((tree));
+
+/* Return the target type of TYPE, which means return T for:
T*, T&, T[], T (...), and otherwise, just T. */
tree
/* First, detect a valid value with a complete type. */
if (TYPE_SIZE (type) != 0
- && TYPE_SIZE (type) != size_zero_node
- && ! (TYPE_LANG_SPECIFIC (type)
- && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))
- && TYPE_SIZE (SIGNATURE_TYPE (type)) == 0))
+ && TYPE_SIZE (type) != size_zero_node)
return value;
/* If we see X::Y, we build an OFFSET_TYPE which has
return error_mark_node;
}
-/* Makes sure EXPR is a complete type when used in a void context, like a
- whole expression, or lhs of a comma operator. Issue a diagnostic and
- return error_mark_node on failure. This is a little tricky, because some
- valid void types look stunningly similar to invalid void types. We err on
- the side of caution */
-
-tree
-require_complete_type_in_void (expr)
- tree expr;
-{
- switch (TREE_CODE (expr))
- {
- case COND_EXPR:
- {
- tree op;
-
- op = TREE_OPERAND (expr,2);
- op = require_complete_type_in_void (op);
- TREE_OPERAND (expr,2) = op;
- if (op == error_mark_node)
- {
- expr = op;
- break;
- }
-
- /* fallthrough */
- }
-
- case COMPOUND_EXPR:
- {
- tree op;
-
- op = TREE_OPERAND (expr,1);
- op = require_complete_type_in_void (op);
- TREE_OPERAND (expr,1) = op;
- if (op == error_mark_node)
- {
- expr = op;
- break;
- }
-
- break;
- }
-
- case NON_LVALUE_EXPR:
- case NOP_EXPR:
- {
- tree op;
-
- op = TREE_OPERAND (expr,0);
- op = require_complete_type_in_void (op);
- TREE_OPERAND (expr,0) = op;
- if (op == error_mark_node)
- {
- expr = op;
- break;
- }
- break;
- }
-
- case CALL_EXPR: /* function call return can be ignored */
- case RTL_EXPR: /* RTL nodes have no value */
- case DELETE_EXPR: /* delete expressions have no type */
- case VEC_DELETE_EXPR:
- case INTEGER_CST: /* used for null pointer */
- case EXIT_EXPR: /* have no return */
- case LOOP_EXPR: /* have no return */
- case BIND_EXPR: /* have no return */
- case THROW_EXPR: /* have no return */
- case MODIFY_EXPR: /* sometimes this has a void type, but that's ok */
- case CONVERT_EXPR: /* sometimes has a void type */
- break;
-
- case INDIRECT_REF:
- {
- tree op = TREE_OPERAND (expr,0);
-
- /* Calling a function returning a reference has an implicit
- dereference applied. We don't want to make that an error. */
- if (TREE_CODE (op) == CALL_EXPR
- && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
- break;
- /* else fallthrough */
- }
-
- default:
- expr = require_complete_type (expr);
- break;
- }
-
- return expr;
-}
-
/* Try to complete TYPE, if it is incomplete. For example, if TYPE is
a template instantiation, do the instantiation. Returns TYPE,
whether or not it could be completed, unless something goes
return t;
}
+/* T1 and T2 are arithmetic or enumeration types. Return the type
+ that will result from the "usual arithmetic converions" on T1 and
+ T2 as described in [expr]. */
+
+tree
+type_after_usual_arithmetic_conversions (t1, t2)
+ tree t1;
+ tree t2;
+{
+ enum tree_code code1 = TREE_CODE (t1);
+ enum tree_code code2 = TREE_CODE (t2);
+ tree attributes;
+
+ /* FIXME: Attributes. */
+ my_friendly_assert (ARITHMETIC_TYPE_P (t1)
+ || TREE_CODE (t1) == ENUMERAL_TYPE,
+ 19990725);
+ my_friendly_assert (ARITHMETIC_TYPE_P (t2)
+ || TREE_CODE (t2) == ENUMERAL_TYPE,
+ 19990725);
+
+ /* In what follows, we slightly generalize the rules given in [expr]
+ so as to deal with `long long'. First, merge the attributes. */
+ attributes = merge_machine_type_attributes (t1, t2);
+
+ /* If only one is real, use it as the result. */
+ if (code1 == REAL_TYPE && code2 != REAL_TYPE)
+ return build_type_attribute_variant (t1, attributes);
+ if (code2 == REAL_TYPE && code1 != REAL_TYPE)
+ return build_type_attribute_variant (t2, attributes);
+
+ /* Perform the integral promotions. */
+ if (code1 != REAL_TYPE)
+ {
+ t1 = type_promotes_to (t1);
+ t2 = type_promotes_to (t2);
+ }
+
+ /* Both real or both integers; use the one with greater precision. */
+ if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
+ return build_type_attribute_variant (t1, attributes);
+ else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
+ return build_type_attribute_variant (t2, attributes);
+
+ if (code1 != REAL_TYPE)
+ {
+ /* If one is unsigned long long, then convert the other to unsigned
+ long long. */
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_unsigned_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_long_unsigned_type_node))
+ return build_type_attribute_variant (long_long_unsigned_type_node,
+ attributes);
+ /* If one is a long long, and the other is an unsigned long, and
+ long long can represent all the values of an unsigned long, then
+ convert to a long long. Otherwise, convert to an unsigned long
+ long. Otherwise, if either operand is long long, convert the
+ other to long long.
+
+ Since we're here, we know the TYPE_PRECISION is the same;
+ therefore converting to long long cannot represent all the values
+ of an unsigned long, so we choose unsigned long long in that
+ case. */
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_integer_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_long_integer_type_node))
+ {
+ tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+ ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+ return build_type_attribute_variant (t, attributes);
+ }
+
+ /* Go through the same procedure, but for longs. */
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_unsigned_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_unsigned_type_node))
+ return build_type_attribute_variant (long_unsigned_type_node,
+ attributes);
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_integer_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_integer_type_node))
+ {
+ tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+ ? long_unsigned_type_node : long_integer_type_node);
+ return build_type_attribute_variant (t, attributes);
+ }
+ /* Otherwise prefer the unsigned one. */
+ if (TREE_UNSIGNED (t1))
+ return build_type_attribute_variant (t1, attributes);
+ else
+ return build_type_attribute_variant (t2, attributes);
+ }
+ else
+ {
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), long_double_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), long_double_type_node))
+ return build_type_attribute_variant (long_double_type_node,
+ attributes);
+ if (same_type_p (TYPE_MAIN_VARIANT (t1), double_type_node)
+ || same_type_p (TYPE_MAIN_VARIANT (t2), double_type_node))
+ return build_type_attribute_variant (double_type_node,
+ attributes);
+ else
+ return build_type_attribute_variant (float_type_node,
+ attributes);
+ }
+}
+
+/* Return the composite pointer type (see [expr.rel]) for T1 and T2.
+ ARG1 and ARG2 are the values with those types. The LOCATION is a
+ string describing the current location, in case an error occurs. */
+
+tree
+composite_pointer_type (t1, t2, arg1, arg2, location)
+ tree t1;
+ tree t2;
+ tree arg1;
+ tree arg2;
+ const char* location;
+{
+ tree result_type;
+
+ /* [expr.rel]
+
+ If one operand is a null pointer constant, the composite pointer
+ type is the type of the other operand. */
+ if (null_ptr_cst_p (arg1))
+ return t2;
+ if (null_ptr_cst_p (arg2))
+ return t1;
+
+ /* Deal with pointer-to-member functions in the same way as we deal
+ with pointers to functions. */
+ if (TYPE_PTRMEMFUNC_P (t1))
+ t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+ if (TYPE_PTRMEMFUNC_P (t2))
+ t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
+ if (comp_target_types (t1, t2, 1))
+ result_type = common_type (t1, t2);
+ else if (TYPE_MAIN_VARIANT (TREE_TYPE (t1)) == void_type_node)
+ {
+ if (pedantic && TREE_CODE (t2) == FUNCTION_TYPE)
+ pedwarn ("ISO C++ forbids %s between pointer of type `void *' and pointer-to-function", 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 ("ISO C++ forbids %s between pointer of type `void *' and pointer-to-function", 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 ("types `%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:
/* For two pointers, do this recursively on the target type,
and combine the qualifiers of the two types' targets. */
/* This code was turned off; I don't know why.
- But ANSI C++ specifies doing this with the qualifiers.
+ But ISO C++ specifies doing this with the qualifiers.
So I turned it on again. */
{
tree tt1 = TREE_TYPE (t1);
if (tt1 == tt2)
target = tt1;
- else if (b1)
- {
- compiler_error ("common_type called with uncommon member types");
- target = tt1;
- }
else if (tt1 == void_type_node || tt2 == void_type_node)
target = void_type_node;
else if (tt1 == unknown_type_node)
}
}
\f
-/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */
+/* Compare two exception specifier types for exactness or subsetness, if
+ allowed. Returns 0 for mismatch, 1 for same, 2 if B is allowed by A.
+
+ [except.spec] "If a class X ... objects of class X or any class publicly
+ and unambigously derrived from X. Similarly, if a pointer type Y * ...
+ exceptions of type Y * or that are pointers to any type publicly and
+ unambigously derrived from Y. Otherwise a function only allows exceptions
+ that have the same type ..."
+ This does not mention cv qualifiers and is different to what throw
+ [except.throw] and catch [except.catch] will do. They will ignore the
+ top level cv qualifiers, and allow qualifiers in the pointer to class
+ example.
+
+ We implement the letter of the standard. */
+
+static int
+comp_except_types (a, b, exact)
+ tree a, b;
+ int exact;
+{
+ if (same_type_p (a, b))
+ return 1;
+ else if (!exact)
+ {
+ if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+ return 0;
+
+ if (TREE_CODE (a) == POINTER_TYPE
+ && TREE_CODE (b) == POINTER_TYPE)
+ {
+ a = TREE_TYPE (a);
+ b = TREE_TYPE (b);
+ if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+ return 0;
+ }
+
+ if (TREE_CODE (a) != RECORD_TYPE
+ || TREE_CODE (b) != RECORD_TYPE)
+ return 0;
+
+ if (ACCESSIBLY_UNIQUELY_DERIVED_P (a, b))
+ return 2;
+ }
+ return 0;
+}
+
+/* Return 1 if TYPE1 and TYPE2 are equivalent exception specifiers.
+ If EXACT is 0, T2 can be a subset of T1 (according to 15.4/7),
+ otherwise it must be exact. Exception lists are unordered, but
+ we've already filtered out duplicates. Most lists will be in order,
+ we should try to make use of that. */
int
-compexcepttypes (t1, t2)
+comp_except_specs (t1, t2, exact)
tree t1, t2;
+ int exact;
{
- return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
+ tree probe;
+ tree base;
+ int length = 0;
+
+ if (t1 == t2)
+ return 1;
+
+ if (t1 == NULL_TREE) /* T1 is ... */
+ return t2 == NULL_TREE || !exact;
+ if (!TREE_VALUE (t1)) /* t1 is EMPTY */
+ return t2 != NULL_TREE && !TREE_VALUE (t2);
+ if (t2 == NULL_TREE) /* T2 is ... */
+ return 0;
+ if (TREE_VALUE(t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
+ return !exact;
+
+ /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
+ Count how many we find, to determine exactness. For exact matching and
+ ordered T1, T2, this is an O(n) operation, otherwise its worst case is
+ O(nm). */
+ for (base = t1; t2 != NULL_TREE; t2 = TREE_CHAIN (t2))
+ {
+ for (probe = base; probe != NULL_TREE; probe = TREE_CHAIN (probe))
+ {
+ tree a = TREE_VALUE (probe);
+ tree b = TREE_VALUE (t2);
+
+ if (comp_except_types (a, b, exact))
+ {
+ if (probe == base && exact)
+ base = TREE_CHAIN (probe);
+ length++;
+ break;
+ }
+ }
+ if (probe == NULL_TREE)
+ return 0;
+ }
+ return !exact || base == NULL_TREE || length == list_length (t1);
}
/* Compare the array types T1 and T2, using CMP as the type comparison
static int
comp_array_types (cmp, t1, t2, strict)
- register int (*cmp) PROTO((tree, tree, int));
+ register int (*cmp) PARAMS ((tree, tree, int));
tree t1, t2;
int strict;
{
TYPE_MAX_VALUE (d2)));
}
-/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
- or various other operations. STRICT is a bitwise-or of the
- COMPARE_* flags. */
+/* Return 1 if T1 and T2 are compatible types for assignment or
+ various other operations. STRICT is a bitwise-or of the COMPARE_*
+ flags. */
int
-comptypes (type1, type2, strict)
- tree type1, type2;
+comptypes (t1, t2, strict)
+ tree t1;
+ tree t2;
int strict;
{
- register tree t1 = type1;
- register tree t2 = type2;
int attrval, val;
int orig_strict = strict;
TYPE_TI_ARGS (t2));
look_hard:
if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
- {
- val = 1;
- break;
- }
- if ((strict & COMPARE_RELAXED) && DERIVED_FROM_P (t2, t1))
- {
- val = 1;
- break;
- }
+ val = 1;
+ else if ((strict & COMPARE_RELAXED) && DERIVED_FROM_P (t2, t1))
+ val = 1;
break;
case OFFSET_TYPE:
break;
case METHOD_TYPE:
- if (! compexcepttypes (t1, t2))
+ if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+ TYPE_RAISES_EXCEPTIONS (t2), 1))
return 0;
/* This case is anti-symmetrical!
break;
case FUNCTION_TYPE:
- if (! compexcepttypes (t1, t2))
+ if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+ TYPE_RAISES_EXCEPTIONS (t2), 1))
return 0;
val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
return 0;
return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
+ case COMPLEX_TYPE:
+ return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+
default:
break;
}
if (t1 == 0 && t2 != 0)
{
- cp_pedwarn ("ANSI C++ prohibits conversion from `(%#T)' to `(...)'",
- parms2);
+ if (! flag_strict_prototype && t2 == void_list_node)
+ /* t1 might be the arglist of a function pointer in extern "C"
+ declared to take (), which we fudged to (...). Don't make the
+ user pay for our mistake. */;
+ else
+ cp_pedwarn ("ISO 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 == FUNCTION_TYPE)
{
if (pedantic || warn_pointer_arith)
- pedwarn ("ANSI C++ forbids taking the sizeof a function type");
+ pedwarn ("ISO C++ forbids applying `sizeof' to a function type");
return size_int (1);
}
if (code == METHOD_TYPE)
{
if (pedantic || warn_pointer_arith)
- pedwarn ("ANSI C++ forbids taking the sizeof a method type");
+ pedwarn ("ISO C++ forbids applying `sizeof' to a member function");
return size_int (1);
}
if (code == VOID_TYPE)
{
if (pedantic || warn_pointer_arith)
- pedwarn ("ANSI C++ forbids taking the sizeof a void type");
+ pedwarn ("ISO C++ forbids applying `sizeof' to type `void' which is an incomplete type");
return size_int (1);
}
if (code == ERROR_MARK)
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))
- {
- pedwarn ("ANSI C++ forbids taking the sizeof a function type");
+ if (is_overloaded_fn (e))
+ {
+ pedwarn ("ISO C++ forbids applying `sizeof' to an expression of 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;
code = TREE_CODE (type);
}
+ if (type == error_mark_node)
+ return error_mark_node;
+
/* Constants can be used directly unless they're not loadable. */
if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp);
return cp_convert (ptrtype, adr);
}
+ /* [basic.lval]: Class rvalues can have cv-qualified types; non-class
+ rvalues always have cv-unqualified types. */
+ if (! CLASS_TYPE_P (type))
+ exp = cp_convert (TYPE_MAIN_VARIANT (type), exp);
+
return exp;
}
basetype, field, dtype);
return error_mark_node;
}
- else if (IS_SIGNATURE (basetype))
- {
- warning ("signature name in scope resolution ignored");
- return build_component_ref (datum, field, NULL_TREE, 1);
- }
else if (is_aggr_type (basetype, 1))
{
tree binfo = binfo_or_else (basetype, dtype);
}
/* Look up component name in the structure type definition. */
- if (CLASSTYPE_VFIELD (basetype)
- && DECL_NAME (CLASSTYPE_VFIELD (basetype)) == component)
+ if (TYPE_VFIELD (basetype)
+ && DECL_NAME (TYPE_VFIELD (basetype)) == component)
/* Special-case this because if we use normal lookups in an ambiguous
hierarchy, the compiler will abort (because vptr lookups are
not supposed to be ambiguous. */
- field = CLASSTYPE_VFIELD (basetype);
+ field = TYPE_VFIELD (basetype);
else if (TREE_CODE (component) == FIELD_DECL)
field = component;
else if (TREE_CODE (component) == TYPE_DECL)
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,
unknown_type_node to be really overloaded, so
let's oblige. */
TREE_VALUE (fndecls)
- = scratch_ovl_cons (TREE_VALUE (fndecls), NULL_TREE);
+ = ovl_cons (TREE_VALUE (fndecls), NULL_TREE);
}
}
}
/* Handle base classes here... */
- if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+ if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype))
{
tree addr = build_unary_op (ADDR_EXPR, datum, 0);
if (integer_zerop (addr))
not const, even within a const object. */
if (DECL_LANG_SPECIFIC (field) && DECL_MUTABLE_P (field))
type_quals &= ~TYPE_QUAL_CONST;
- if (!IS_SIGNATURE (field_type))
- field_type = cp_build_qualified_type (field_type, type_quals);
+ field_type = cp_build_qualified_type (field_type, type_quals);
}
ref = fold (build (COMPONENT_REF, field_type,
types. */
tree t = canonical_type_variant (TREE_TYPE (type));
- if (TREE_CODE (pointer) == ADDR_EXPR
+ if (same_type_p (TYPE_MAIN_VARIANT (t), void_type_node))
+ {
+ /* A pointer to incomplete type (other than cv void) can be
+ dereferenced [expr.unary.op]/1 */
+ cp_error ("`%T' is not a pointer-to-object type", type);
+ return error_mark_node;
+ }
+ else if (TREE_CODE (pointer) == ADDR_EXPR
&& !flag_volatile
&& same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
/* The POINTER was something like `&x'. We simplify `*&x' to
pointer to member, so it's cool to check for this here. */
else if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
error ("invalid use of `%s' on pointer to member", errorstring);
- else if (TREE_CODE (type) == RECORD_TYPE
- && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
- error ("cannot dereference signature pointer/reference");
else if (pointer != error_mark_node)
{
if (errorstring)
}
if (pedantic && !lvalue_p (array))
- pedwarn ("ANSI C++ forbids subscripting non-lvalue array");
+ pedwarn ("ISO C++ forbids subscripting non-lvalue array");
/* Note in C++ it is valid to subscript a `register' array, since
it is valid to take the address of something with that
/* 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);
+ function = ovl_cons (function, NULL_TREE);
/* Handle methods, friends, and overloaded functions, respectively. */
if (is_method)
if (TREE_CODE (function) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (function))
{
- basetype = DECL_CLASS_CONTEXT (function);
+ basetype = DECL_CONTEXT (function);
if (DECL_NAME (function))
function = DECL_NAME (function);
else
- function = TYPE_IDENTIFIER (DECL_CLASS_CONTEXT (function));
+ function = TYPE_IDENTIFIER (DECL_CONTEXT (function));
}
else if (TREE_CODE (function) == TREE_LIST)
{
my_friendly_assert (TREE_CODE (TREE_VALUE (function))
== FUNCTION_DECL, 312);
- basetype = DECL_CLASS_CONTEXT (TREE_VALUE (function));
+ basetype = DECL_CONTEXT (TREE_VALUE (function));
function = TREE_PURPOSE (function);
}
else if (TREE_CODE (function) != IDENTIFIER_NODE)
function = TREE_OPERAND (function, 1);
function = get_member_function_from_ptrfunc (&decl_addr, function);
- params = expr_tree_cons (NULL_TREE, decl_addr, params);
+ params = tree_cons (NULL_TREE, decl_addr, params);
return build_function_call (function, params);
}
}
else
decl = build_c_cast (ctypeptr, decl);
- params = expr_tree_cons (NULL_TREE, decl, params);
+ params = tree_cons (NULL_TREE, decl, params);
}
return build_function_call (function, params);
tree instance_ptr = *instance_ptrptr;
+ if (instance_ptr == error_mark_node
+ && TREE_CODE (function) == PTRMEM_CST)
+ {
+ /* Extracting the function address from a pmf is only
+ allowed with -Wno-pmf-conversions. It only works for
+ pmf constants. */
+ e1 = build_addr_func (PTRMEM_CST_MEMBER (function));
+ e1 = convert (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function)), e1);
+ return e1;
+ }
+
if (TREE_SIDE_EFFECTS (instance_ptr))
instance_ptr = save_expr (instance_ptr);
NULL_TREE, 0));
e3 = PFN_FROM_PTRMEMFUNC (function);
- if (TYPE_SIZE (basetype) != NULL_TREE
- && ! TYPE_VIRTUAL_P (basetype))
- /* If basetype doesn't have virtual functions, don't emit code to
- handle that case. */
- e1 = e3;
- else
- {
- /* Promoting idx before saving it improves performance on RISC
- targets. Without promoting, the first compare used
- load-with-sign-extend, while the second used normal load then
- shift to sign-extend. An optimizer flaw, perhaps, but it's
- easier to make this change. */
- idx = save_expr (default_conversion
- (build_component_ref (function,
- index_identifier,
- NULL_TREE, 0)));
- e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
-
- /* Convert down to the right base, before using the instance. */
- instance = convert_pointer_to_real (basetype, instance_ptr);
- if (instance == error_mark_node && instance_ptr != error_mark_node)
- return instance;
-
- vtbl = convert_pointer_to (ptr_type_node, instance);
- delta2 = DELTA2_FROM_PTRMEMFUNC (function);
- vtbl = build
+ /* This used to avoid checking for virtual functions if basetype
+ has no virtual functions, according to an earlier ANSI draft.
+ With the final ISO C++ rules, such an optimization is
+ incorrect: A pointer to a derived member can be static_cast
+ to pointer-to-base-member, as long as the dynamic object
+ later has the right member. */
+
+ /* Promoting idx before saving it improves performance on RISC
+ targets. Without promoting, the first compare used
+ load-with-sign-extend, while the second used normal load then
+ shift to sign-extend. An optimizer flaw, perhaps, but it's
+ easier to make this change. */
+ idx = save_expr (default_conversion
+ (build_component_ref (function,
+ index_identifier,
+ NULL_TREE, 0)));
+ e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
+
+ /* Convert down to the right base, before using the instance. */
+ instance = convert_pointer_to_real (basetype, instance_ptr);
+ if (instance == error_mark_node && instance_ptr != error_mark_node)
+ return instance;
+
+ vtbl = convert_pointer_to (ptr_type_node, instance);
+ delta2 = DELTA2_FROM_PTRMEMFUNC (function);
+ vtbl = build
+ (PLUS_EXPR,
+ build_pointer_type (build_pointer_type (vtable_entry_type)),
+ vtbl, cp_convert (ptrdiff_type_node, delta2));
+ vtbl = build_indirect_ref (vtbl, NULL_PTR);
+ aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
+ idx,
+ integer_one_node));
+ if (! flag_vtable_thunks)
+ {
+ aref = save_expr (aref);
+
+ delta = build_binary_op
(PLUS_EXPR,
- build_pointer_type (build_pointer_type (vtable_entry_type)),
- vtbl, cp_convert (ptrdiff_type_node, delta2));
- vtbl = build_indirect_ref (vtbl, NULL_PTR);
- aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
- idx,
- integer_one_node));
- if (! flag_vtable_thunks)
- {
- aref = save_expr (aref);
-
- delta = build_binary_op
- (PLUS_EXPR,
- build_conditional_expr (e1,
- build_component_ref (aref,
- delta_identifier,
- NULL_TREE, 0),
- integer_zero_node),
- delta);
- }
-
- if (flag_vtable_thunks)
- e2 = aref;
- else
- e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
- TREE_TYPE (e2) = TREE_TYPE (e3);
- e1 = build_conditional_expr (e1, e2, e3);
-
- /* Make sure this doesn't get evaluated first inside one of the
- branches of the COND_EXPR. */
- if (TREE_CODE (instance_ptr) == SAVE_EXPR)
- e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
- instance_ptr, e1);
+ build_conditional_expr (e1,
+ build_component_ref (aref,
+ delta_identifier,
+ NULL_TREE, 0),
+ integer_zero_node),
+ delta);
}
+ if (flag_vtable_thunks)
+ e2 = aref;
+ else
+ e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
+ TREE_TYPE (e2) = TREE_TYPE (e3);
+ e1 = build_conditional_expr (e1, e2, e3);
+
+ /* Make sure this doesn't get evaluated first inside one of the
+ branches of the COND_EXPR. */
+ if (TREE_CODE (instance_ptr) == SAVE_EXPR)
+ e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
+ instance_ptr, e1);
+
*instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
instance_ptr, delta);
register tree fntype, fndecl;
register tree value_type;
register tree coerced_params;
+ tree result;
tree name = NULL_TREE, assembler_name = NULL_TREE;
int is_method;
/* Convert anything with function type to a pointer-to-function. */
if (pedantic && DECL_MAIN_P (function))
- pedwarn ("ANSI C++ forbids calling `main' from within program");
+ pedwarn ("ISO C++ forbids calling `::main' from within program");
/* Differs from default_conversion by not setting TREE_ADDRESSABLE
(because calling an inline function does not mean the function
if (TREE_CODE (function) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (function, 0)))
- switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0)))
- {
- case BUILT_IN_ABS:
- case BUILT_IN_LABS:
- case BUILT_IN_FABS:
- if (coerced_params == 0)
- return integer_zero_node;
- return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
-
- default:
- break;
- }
+ {
+ result = expand_tree_builtin (TREE_OPERAND (function, 0),
+ params, coerced_params);
+ if (result)
+ return result;
+ }
/* C++ */
value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
- {
- register tree result
- = build_call (function, value_type, coerced_params);
+ result = build_call (function, value_type, coerced_params);
- if (require_complete)
- {
- if (TREE_CODE (value_type) == VOID_TYPE)
- return result;
- result = require_complete_type (result);
- }
- if (IS_AGGR_TYPE (value_type))
- result = build_cplus_new (value_type, result);
- return convert_from_reference (result);
- }
+ if (require_complete)
+ {
+ if (TREE_CODE (value_type) == VOID_TYPE)
+ return result;
+ result = require_complete_type (result);
+ }
+ if (IS_AGGR_TYPE (value_type))
+ result = build_cplus_new (value_type, result);
+ return convert_from_reference (result);
}
tree
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)
tree t = instantiate_type (TREE_TYPE (op1), op0, 0);
if (t != error_mark_node)
{
- cp_pedwarn ("assuming cast to `%T' from overloaded function",
+ cp_pedwarn ("assuming cast to type `%T' from overloaded function",
TREE_TYPE (t));
op0 = t;
}
tree t = instantiate_type (TREE_TYPE (op0), op1, 0);
if (t != error_mark_node)
{
- cp_pedwarn ("assuming cast to `%T' from overloaded function",
+ cp_pedwarn ("assuming cast to type `%T' from overloaded function",
TREE_TYPE (t));
op1 = t;
}
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 (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE
&& tree_int_cst_lt (TYPE_SIZE (type0), TYPE_SIZE (type1)))
- pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer");
+ pedwarn ("ISO C++ forbids comparison of `void *' with function pointer");
else if (TREE_CODE (tt1) == OFFSET_TYPE)
- pedwarn ("ANSI C++ forbids conversion of a pointer to member to `void *'");
+ pedwarn ("ISO C++ forbids conversion of a pointer to member to `void *'");
}
else if (tt1 == void_type_node)
{
if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE
&& tree_int_cst_lt (TYPE_SIZE (type1), TYPE_SIZE (type0)))
- pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer");
+ pedwarn ("ISO C++ forbids comparison of `void *' with function pointer");
}
else
cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
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 = type0;
- error ("ANSI C++ forbids comparison between pointer and integer");
+ error ("ISO C++ forbids comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- error ("ANSI C++ forbids comparison between pointer and integer");
+ error ("ISO C++ forbids comparison between pointer and integer");
}
- else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST
- && integer_zerop (op1))
+ else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
{
op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
result_type = TREE_TYPE (op0);
}
- else if (TYPE_PTRMEMFUNC_P (type1) && TREE_CODE (op0) == INTEGER_CST
- && integer_zerop (op0))
+ else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
{
op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
DECL_VINDEX (TREE_OPERAND (op1, 0)),
integer_one_node);
op1 = integer_zero_node;
- delta21 = CLASSTYPE_VFIELD (TYPE_METHOD_BASETYPE
- (TREE_TYPE (type1)));
+ delta21 = TYPE_VFIELD (TYPE_METHOD_BASETYPE
+ (TREE_TYPE (type1)));
delta21 = DECL_FIELD_BITPOS (delta21);
delta21 = size_binop (FLOOR_DIV_EXPR, delta21,
size_int (BITS_PER_UNIT));
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- pedwarn ("ANSI C++ forbids comparison between pointer and integer");
+ pedwarn ("ISO C++ forbids comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- pedwarn ("ANSI C++ forbids comparison between pointer and integer");
+ pedwarn ("ISO C++ forbids comparison between pointer and integer");
+ }
+ break;
+
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNEQ_EXPR:
+ build_type = integer_type_node;
+ if (code0 != REAL_TYPE || code1 != REAL_TYPE)
+ {
+ error ("unordered comparison on non-floating point argument");
+ return error_mark_node;
}
+ common = 1;
break;
default:
&& TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
!= TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
{
- cp_warning ("comparison between `%#T' and `%#T'",
+ cp_warning ("comparison between types `%#T' and `%#T'",
TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
}
signed_type (result_type)))))
/* OK */;
else
- warning ("comparison between signed and unsigned");
+ warning ("comparison between a signed and an unsigned integer expressions");
/* Warn if two unsigned values are being compared in a size
larger than their original size, and one (and only one) is the
if (!result_type)
{
- cp_error ("invalid operands `%T' and `%T' to binary `%O'",
+ cp_error ("invalid operands of types `%T' and `%T' to binary `%O'",
TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), error_code);
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
{
if (pedantic || warn_pointer_arith)
- pedwarn ("ANSI C++ forbids using pointer of type `void *' in arithmetic");
+ pedwarn ("ISO C++ forbids using pointer of type `void *' in pointer arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
{
if (pedantic || warn_pointer_arith)
- pedwarn ("ANSI C++ forbids using pointer to a function in arithmetic");
+ pedwarn ("ISO C++ forbids using a pointer-to-function in pointer arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
{
if (pedantic || warn_pointer_arith)
- pedwarn ("ANSI C++ forbids using pointer to a method in arithmetic");
+ pedwarn ("ISO C++ forbids using a pointer to member function in pointer arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
{
if (pedantic || warn_pointer_arith)
- pedwarn ("ANSI C++ forbids using pointer to a member in arithmetic");
+ pedwarn ("ISO C++ forbids using pointer to a member in pointer arithmetic");
size_exp = integer_one_node;
}
else
if (pedantic || warn_pointer_arith)
{
if (TREE_CODE (target_type) == VOID_TYPE)
- pedwarn ("ANSI C++ forbids using pointer of type `void *' in subtraction");
+ pedwarn ("ISO C++ forbids using pointer of type `void *' in subtraction");
if (TREE_CODE (target_type) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids using pointer to a function in subtraction");
+ pedwarn ("ISO C++ forbids using pointer to a function in subtraction");
if (TREE_CODE (target_type) == METHOD_TYPE)
- pedwarn ("ANSI C++ forbids using pointer to a method in subtraction");
+ pedwarn ("ISO C++ forbids using pointer to a method in subtraction");
if (TREE_CODE (target_type) == OFFSET_TYPE)
- pedwarn ("ANSI C++ forbids using pointer to a member in subtraction");
+ pedwarn ("ISO C++ forbids using pointer to a member in subtraction");
}
/* First do the subtraction as integers;
/* This generates an error if op1 is a pointer to an incomplete type. */
if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0)
- error ("arithmetic on pointer to an incomplete type");
+ error ("invalid use of a pointer to an incomplete type in pointer arithmetic");
op1 = ((TREE_CODE (target_type) == VOID_TYPE
|| TREE_CODE (target_type) == FUNCTION_TYPE
}
if (TREE_CODE (field) == FIELD_DECL
- && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+ && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype))
{
/* Can't convert directly to ARGTYPE, since that
may have the same pointer type as one of our
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;
}
/* ARM $5.2.5 last annotation says this should be forbidden. */
if (TREE_CODE (argtype) == ENUMERAL_TYPE)
- pedwarn ("ANSI C++ forbids %sing an enum",
+ pedwarn ("ISO C++ forbids %sing an enum",
(code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
? "increment" : "decrement");
else if ((pedantic || warn_pointer_arith)
&& (tmp == FUNCTION_TYPE || tmp == METHOD_TYPE
|| tmp == VOID_TYPE || tmp == OFFSET_TYPE))
- cp_pedwarn ("ANSI C++ forbids %sing a pointer of type `%T'",
+ cp_pedwarn ("ISO C++ forbids %sing a pointer of type `%T'",
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"), argtype);
|| 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);
}
else if (pedantic && DECL_MAIN_P (arg))
/* ARM $3.4 */
- pedwarn ("taking address of function `main'");
+ pedwarn ("ISO C++ forbids taking address of function `::main'");
/* Let &* cancel out to simplify resulting code. */
if (TREE_CODE (arg) == INDIRECT_REF)
&& OVL_NEXT (TREE_OPERAND (arg, 1)) == NULL_TREE)
{
/* They're trying to take the address of a unique non-static
- member function. This is ill-formed, but let's try to DTRT. */
- tree base, name;
+ member function. This is ill-formed, but let's try to DTRT.
+ Note: We only handle unique functions here because we don't
+ want to complain if there's a static overload; non-unique
+ cases will be handled by instantiate_type. But we need to
+ handle this case here to allow casts on the resulting PMF. */
- if (current_class_type
- && TREE_OPERAND (arg, 0) == current_class_ref)
- /* An expression like &memfn. */
- pedwarn ("taking the address of a non-static member function");
- else
- pedwarn ("taking the address of a bound member function");
+ tree base = TREE_TYPE (TREE_OPERAND (arg, 0));
+ tree name = DECL_NAME (OVL_CURRENT (TREE_OPERAND (arg, 1)));
- base = TREE_TYPE (TREE_OPERAND (arg, 0));
- 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. */
+ cp_pedwarn ("ISO C++ forbids taking the address of a non-static member function to form a pointer to member function. Say `&%T::%D'", base, name);
+ else
+ cp_pedwarn ("ISO C++ forbids taking the address of a bound member function to form a pointer to member function", base, name);
+ }
- cp_pedwarn (" to form a pointer to member function, say `&%T::%D'",
- base, name);
arg = build_offset_ref (base, name);
}
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
if (! lvalue_p (arg) && pedantic)
- pedwarn ("taking the address of a cast to non-reference type");
+ pedwarn ("ISO C++ forbids taking the address of a cast to a non-lvalue expression");
break;
default:
return fold (build1 (code, argtype, arg));
}
- error (errstring);
+ error ("%s", errstring);
return error_mark_node;
}
if (x == current_class_ptr)
{
if (! flag_this_is_variable)
- error ("address of `this' not available");
+ error ("cannot take the address of `this', which is an ravlue expression");
TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
put_var_into_stack (x);
return 1;
&& 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 (cfun && 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);
- }
-
- type1 = TREE_TYPE (op1);
- code1 = TREE_CODE (type1);
- type2 = TREE_TYPE (op2);
- code2 = TREE_CODE (type2);
- if (op1 == error_mark_node || op2 == error_mark_node
- || type1 == error_mark_node || type2 == error_mark_node)
- return error_mark_node;
-
- ifexp = cp_convert (boolean_type_node, ifexp);
-
- if (TREE_CODE (ifexp) == ERROR_MARK)
- return error_mark_node;
-
- /* C++: REFERENCE_TYPES must be dereferenced. */
- if (code1 == REFERENCE_TYPE)
- {
- op1 = convert_from_reference (op1);
- type1 = TREE_TYPE (op1);
- code1 = TREE_CODE (type1);
- }
- if (code2 == REFERENCE_TYPE)
- {
- op2 = convert_from_reference (op2);
- type2 = TREE_TYPE (op2);
- code2 = TREE_CODE (type2);
- }
-
- /* Don't promote the operands separately if they promote
- the same way. Return the unpromoted type and let the combined
- value get promoted if necessary. */
-
- if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
- && code2 != ARRAY_TYPE
- && code2 != FUNCTION_TYPE
- && code2 != METHOD_TYPE)
- {
- tree result;
-
- if (TREE_CONSTANT (ifexp)
- && (TREE_CODE (ifexp) == INTEGER_CST
- || TREE_CODE (ifexp) == ADDR_EXPR))
- return (integer_zerop (ifexp) ? op2 : op1);
-
- if (TREE_CODE (op1) == CONST_DECL)
- op1 = DECL_INITIAL (op1);
- else if (TREE_READONLY_DECL_P (op1))
- op1 = decl_constant_value (op1);
- if (TREE_CODE (op2) == CONST_DECL)
- op2 = DECL_INITIAL (op2);
- else if (TREE_READONLY_DECL_P (op2))
- op2 = decl_constant_value (op2);
- if (type1 != type2)
- type1 = cp_build_qualified_type
- (type1, (CP_TYPE_QUALS (TREE_TYPE (op1))
- | CP_TYPE_QUALS (TREE_TYPE (op2))));
- /* ??? This is a kludge to deal with the fact that
- we don't sort out integers and enums properly, yet. */
- result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
- if (TREE_TYPE (result) != type1)
- result = build1 (NOP_EXPR, type1, result);
- /* Expand both sides into the same slot,
- hopefully the target of the ?: expression. */
- if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
- {
- tree slot = build (VAR_DECL, TREE_TYPE (result));
- layout_decl (slot, 0);
- result = build (TARGET_EXPR, TREE_TYPE (result),
- slot, result, NULL_TREE, NULL_TREE);
- }
- return result;
- }
-
- /* They don't match; promote them both and then try to reconcile them.
- But don't permit mismatching enum types. */
- if (code1 == ENUMERAL_TYPE)
- {
- if (code2 == ENUMERAL_TYPE)
- {
- cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'",
- type1, type2);
- return error_mark_node;
- }
- else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2)
- && type2 != type_promotes_to (type1))
- warning ("enumeral and non-enumeral type in conditional expression");
- }
- else if (extra_warnings
- && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1)
- && type1 != type_promotes_to (type2))
- warning ("enumeral and non-enumeral type in conditional expression");
-
- if (code1 != VOID_TYPE)
- {
- op1 = default_conversion (op1);
- type1 = TREE_TYPE (op1);
- if (TYPE_PTRMEMFUNC_P (type1))
- type1 = TYPE_PTRMEMFUNC_FN_TYPE (type1);
- code1 = TREE_CODE (type1);
- }
- if (code2 != VOID_TYPE)
- {
- op2 = default_conversion (op2);
- type2 = TREE_TYPE (op2);
- if (TYPE_PTRMEMFUNC_P (type2))
- type2 = TYPE_PTRMEMFUNC_FN_TYPE (type2);
- code2 = TREE_CODE (type2);
- }
-
- if (code1 == RECORD_TYPE && code2 == RECORD_TYPE
- && real_lvalue_p (op1) && real_lvalue_p (op2)
- && comptypes (type1, type2, COMPARE_BASE | COMPARE_RELAXED))
- {
- type1 = build_reference_type (type1);
- type2 = build_reference_type (type2);
- result_type = common_type (type1, type2);
- op1 = convert_to_reference (result_type, op1, CONV_IMPLICIT,
- LOOKUP_NORMAL, NULL_TREE);
- op2 = convert_to_reference (result_type, op2, CONV_IMPLICIT,
- LOOKUP_NORMAL, NULL_TREE);
- }
- /* Quickly detect the usual case where op1 and op2 have the same type
- after promotion. */
- else if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
- {
- if (type1 == type2)
- result_type = type1;
- else
- result_type =
- cp_build_qualified_type (type1,
- CP_TYPE_QUALS (TREE_TYPE (op1))
- | CP_TYPE_QUALS (TREE_TYPE (op2)));
- }
- else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE)
- && (code2 == INTEGER_TYPE || code2 == REAL_TYPE))
- {
- result_type = common_type (type1, type2);
- }
- else if (code1 == VOID_TYPE || code2 == VOID_TYPE)
- {
- if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE))
- pedwarn ("ANSI C++ forbids conditional expr with only one void side");
- result_type = void_type_node;
- }
- else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2))
- result_type = qualify_type (type1, type2);
- else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1))
- result_type = qualify_type (type2, type1);
- else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
- {
- if (comp_target_types (type1, type2, 1))
- result_type = common_type (type1, type2);
- else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
- {
- if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
- result_type = qualify_type (type1, type2);
- }
- else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node)
- {
- if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
- result_type = qualify_type (type2, type1);
- }
- /* C++ */
- else if (same_or_base_type_p (type2, type1))
- result_type = type2;
- else if (IS_AGGR_TYPE (TREE_TYPE (type1))
- && IS_AGGR_TYPE (TREE_TYPE (type2))
- && (result_type = common_base_type (TREE_TYPE (type1),
- TREE_TYPE (type2))))
- {
- if (result_type == error_mark_node)
- {
- cp_error ("common base type of types `%T' and `%T' is ambiguous",
- TREE_TYPE (type1), TREE_TYPE (type2));
- result_type = ptr_type_node;
- }
- else
- {
- if (pedantic
- && result_type != TREE_TYPE (type1)
- && result_type != TREE_TYPE (type2))
- cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression",
- type1, type2, result_type);
-
- result_type = build_pointer_type (result_type);
- }
- }
- else
- {
- pedwarn ("pointer type mismatch in conditional expression");
- result_type = ptr_type_node;
- }
- }
- else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
- {
- pedwarn ("pointer/integer type mismatch in conditional expression");
- result_type = type1;
- }
- else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
- {
- pedwarn ("pointer/integer type mismatch in conditional expression");
- result_type = type2;
- }
- if (type2 == unknown_type_node)
- result_type = type1;
- else if (type1 == unknown_type_node)
- result_type = type2;
-
- if (!result_type)
- {
- /* The match does not look good. If either is
- an aggregate value, try converting to a scalar type. */
- if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
- {
- cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'",
- type1, type2);
- return error_mark_node;
- }
- /* Warning: this code assumes that conversion between cv-variants of
- a type is done using NOP_EXPRs. */
- if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
- {
- /* There are other types besides pointers and records. */
- tree tmp;
- if (code2 == POINTER_TYPE)
- tmp = build_pointer_type
- (cp_build_qualified_type (TREE_TYPE (type2),
- TYPE_QUAL_CONST
- | TYPE_QUAL_VOLATILE
- | TYPE_QUAL_RESTRICT));
- else
- tmp = type2;
- tmp = build_type_conversion (tmp, op1, 0);
- if (tmp == NULL_TREE)
- {
- cp_error ("incompatible types `%T' and `%T' in `?:'",
- type1, type2);
- return error_mark_node;
- }
- if (tmp == error_mark_node)
- error ("ambiguous pointer conversion");
- else
- STRIP_NOPS (tmp);
- result_type = common_type (type2, TREE_TYPE (tmp));
- op1 = tmp;
- }
- else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
- {
- tree tmp;
- if (code1 == POINTER_TYPE)
- tmp = build_pointer_type
- (cp_build_qualified_type (TREE_TYPE (type1),
- TYPE_QUAL_CONST
- | TYPE_QUAL_VOLATILE
- | TYPE_QUAL_RESTRICT));
- else
- tmp = type1;
-
- tmp = build_type_conversion (tmp, op2, 0);
- if (tmp == NULL_TREE)
- {
- cp_error ("incompatible types `%T' and `%T' in `?:'",
- type1, type2);
- return error_mark_node;
- }
- if (tmp == error_mark_node)
- error ("ambiguous pointer conversion");
- else
- STRIP_NOPS (tmp);
- result_type = common_type (type1, TREE_TYPE (tmp));
- op2 = tmp;
- }
- else if (flag_cond_mismatch)
- result_type = void_type_node;
- else
- {
- error ("type mismatch in conditional expression");
- return error_mark_node;
- }
- }
-
- if (TREE_CODE (result_type) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
- result_type = build_ptrmemfunc_type (result_type);
-
- if (result_type != TREE_TYPE (op1))
- op1 = convert_for_initialization
- (NULL_TREE, result_type, op1, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
- if (result_type != TREE_TYPE (op2))
- op2 = convert_for_initialization
- (NULL_TREE, result_type, op2, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
-
- if (TREE_CODE (ifexp) == INTEGER_CST)
- return integer_zerop (ifexp) ? op2 : op1;
-
- return convert_from_reference
- (fold (build (COND_EXPR, result_type, ifexp, op1, op2)));
+ 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),
- build_expr_list (NULL_TREE,
+ (tree_cons (NULL_TREE, TREE_VALUE (list),
+ build_tree_list (NULL_TREE,
build_x_compound_expr (rest))));
}
if (TREE_CODE (list) == NOP_EXPR
&& TREE_TYPE (list) == TREE_TYPE (TREE_OPERAND (list, 0)))
list = TREE_OPERAND (list, 0);
-
- /* Convert arrays to pointers. */
- if (TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE)
- return default_conversion (TREE_VALUE (list));
- else
- return TREE_VALUE (list);
+
+ return TREE_VALUE (list);
}
first = TREE_VALUE (list);
- first = require_complete_type_in_void (first);
+ first = convert_to_void (first, "left-hand operand of comma");
if (first == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
- tree t = build_min (STATIC_CAST_EXPR, copy_to_permanent (type),
- expr);
+ tree t = build_min (STATIC_CAST_EXPR, type, expr);
return t;
}
expr = TREE_OPERAND (expr, 0);
if (TREE_CODE (type) == VOID_TYPE)
- return build1 (CONVERT_EXPR, type, expr);
+ {
+ expr = convert_to_void (expr, /*implicit=*/NULL);
+ return expr;
+ }
if (TREE_CODE (type) == REFERENCE_TYPE)
return (convert_from_reference
if (IS_AGGR_TYPE (type))
return build_cplus_new
(type, (build_method_call
- (NULL_TREE, ctor_identifier, build_expr_list (NULL_TREE, expr),
+ (NULL_TREE, ctor_identifier, build_tree_list (NULL_TREE, expr),
TYPE_BINFO (type), LOOKUP_NORMAL)));
expr = decay_conversion (expr);
/* FIXME handle casting to array type. */
ok = 0;
- if (can_convert_arg (type, intype, expr))
+ if (IS_AGGR_TYPE (intype)
+ ? can_convert_arg (type, intype, expr)
+ : can_convert_arg (strip_all_pointer_quals (type),
+ strip_all_pointer_quals (intype), expr))
ok = 1;
else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
{
tree binfo;
if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
- && at_least_as_qualified_p (TREE_TYPE (type),
- TREE_TYPE (intype))
&& (binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 0))
&& ! TREE_VIA_VIRTUAL (binfo))
ok = 1;
{
if (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))),
TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (intype))))
- && at_least_as_qualified_p (TREE_TYPE (TREE_TYPE (type)),
- TREE_TYPE (TREE_TYPE (intype)))
&& (binfo = get_binfo (TYPE_OFFSET_BASETYPE (TREE_TYPE (type)),
TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)), 0))
&& ! TREE_VIA_VIRTUAL (binfo))
else if (TREE_CODE (intype) != BOOLEAN_TYPE
&& TREE_CODE (type) != ARRAY_TYPE
&& TREE_CODE (type) != FUNCTION_TYPE
- && can_convert (intype, type))
+ && can_convert (intype, strip_all_pointer_quals (type)))
ok = 1;
+ /* [expr.static.cast]
+
+ The static_cast operator shall not be used to cast away
+ constness. */
+ if (ok && casts_away_constness (intype, type))
+ {
+ cp_error ("static_cast from type `%T' to type `%T' casts away constness",
+ intype, type);
+ return error_mark_node;
+ }
+
if (ok)
return build_c_cast (type, expr);
- cp_error ("static_cast from `%T' to `%T'", intype, type);
+ cp_error ("invalid static_cast from type `%T' to type `%T'", intype, type);
return error_mark_node;
}
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 (! real_lvalue_p (expr))
{
- cp_error ("reinterpret_cast from `%T' rvalue to `%T'", intype, type);
+ cp_error ("invalid reinterpret_cast of an rvalue expression of type `%T' to type `%T'", intype, type);
return error_mark_node;
}
expr = build_unary_op (ADDR_EXPR, expr, 0);
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
{
- pedwarn ("ANSI C++ forbids casting between pointers to functions and objects");
+ pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
if (TREE_READONLY_DECL_P (expr))
expr = decl_constant_value (expr);
return fold (build1 (NOP_EXPR, type, expr));
}
else
{
- cp_error ("reinterpret_cast from `%T' to `%T'", intype, type);
+ cp_error ("invalid reinterpret_cast from type `%T' to type `%T'",
+ intype, type);
return error_mark_node;
}
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");
- }
+ cp_error ("invalid use of const_cast with type `%T', which is not a pointer, reference, nor a pointer-to-data-member type", type);
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");
+ cp_error ("invalid use of const_cast with type `%T', which is a pointer or reference to a function type", type);
return error_mark_node;
}
{
if (! real_lvalue_p (expr))
{
- cp_error ("const_cast from `%T' rvalue to `%T'", intype, type);
+ cp_error ("invalid const_cast of an rvalue of type `%T' to type `%T'", intype, type);
return error_mark_node;
}
&& comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
return cp_convert (type, expr);
- cp_error ("const_cast from `%T' to `%T'", intype, type);
+ cp_error ("invalid const_cast from type `%T' to type `%T'", intype, type);
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
{
if (pedantic)
- pedwarn ("ANSI C++ forbids casting to an array type");
+ pedwarn ("ISO C++ forbids casting to an array type");
type = build_pointer_type (TREE_TYPE (type));
}
else
{
- error ("ANSI C++ forbids casting to an array type");
+ error ("ISO C++ forbids casting to an array type");
return error_mark_node;
}
}
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
{
- cp_error ("casting to function type `%T'", type);
- return error_mark_node;
- }
-
- if (IS_SIGNATURE (type))
- {
- error ("cast specifies signature type");
+ cp_error ("invalid cast to function type `%T'", type);
return error_mark_node;
}
if (processing_template_decl)
{
tree t = build_min (CAST_EXPR, type,
- min_tree_cons (NULL_TREE, value, NULL_TREE));
+ tree_cons (NULL_TREE, value, NULL_TREE));
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
&& TREE_CODE (otype) == POINTER_TYPE
&& !at_least_as_qualified_p (TREE_TYPE (type),
TREE_TYPE (otype)))
- cp_warning ("cast discards qualifiers from pointer target type");
-
- /* Warn about possible alignment problems. */
- if (STRICT_ALIGNMENT && warn_cast_align
- && TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (otype) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
- && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
- && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
- warning ("cast increases required alignment of target type");
+ cp_warning ("cast from `%T' to `%T' discards qualifiers from pointer target type",
+ otype, type);
#if 0
/* We should see about re-enabling these, they seem useful to
warning ("cast to pointer from integer of different size");
#endif
- if (TREE_CODE (type) == VOID_TYPE)
- {
- value = require_complete_type_in_void (value);
- if (value != error_mark_node)
- value = build1 (CONVERT_EXPR, void_type_node, value);
- }
- else if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (TREE_CODE (type) == REFERENCE_TYPE)
value = (convert_from_reference
(convert_to_reference (type, value, CONV_C_CAST,
LOOKUP_COMPLAIN, NULL_TREE)));
}
}
+ /* Warn about possible alignment problems. Do this here when we will have
+ instantiated any necessary template types. */
+ if (STRICT_ALIGNMENT && warn_cast_align
+ && TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
+ && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
+ && TYPE_SIZE (TREE_TYPE (otype))
+ && TYPE_SIZE (TREE_TYPE (type))
+ && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
+ cp_warning ("cast from `%T' to `%T' increases required alignment of target type",
+ otype, type);
+
/* Always produce some operator for an explicit cast,
so we can tell (for -pedantic) that the cast is no lvalue. */
if (TREE_CODE (type) != REFERENCE_TYPE && value == expr
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
else
{
result = build_method_call (lhs, ctor_identifier,
- build_expr_list (NULL_TREE, rhs),
+ build_tree_list (NULL_TREE, rhs),
TYPE_BINFO (lhstype), LOOKUP_NORMAL);
if (result == NULL_TREE)
return error_mark_node;
/* WP 5.4.1: The result is an lvalue if T is a reference type,
otherwise the result is an rvalue. */
if (! lvalue_p (lhs))
- pedwarn ("ANSI C++ forbids cast to non-reference type used as lvalue");
+ pedwarn ("ISO C++ forbids cast to non-reference type used as lvalue");
result = build_modify_expr (inner_lhs, NOP_EXPR,
cp_convert (TREE_TYPE (inner_lhs),
/* Warn about storing in something that is `const'. */
/* For C++, don't warn if this is initialization. */
if (modifycode != INIT_EXPR
- /* For assignment to `const' signature pointer/reference fields,
- don't warn either, we already printed a better message before. */
- && ! (TREE_CODE (lhs) == COMPONENT_REF
- && (IS_SIGNATURE_POINTER (TREE_TYPE (TREE_OPERAND (lhs, 0)))
- || IS_SIGNATURE_REFERENCE (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
&& (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
/* Functions are not modifiable, even though they are
lvalues. */
}
}
- /* 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. */
/* Allow array assignment in compiler-generated code. */
if (pedantic && ! DECL_ARTIFICIAL (current_function_decl))
- pedwarn ("ANSI C++ forbids assignment of arrays");
-
- /* Have to wrap this in RTL_EXPR for two cases:
- in base or member initialization and if we
- are a branch of a ?: operator. Since we
- can't easily know the latter, just do it always. */
-
- result = make_node (RTL_EXPR);
-
- TREE_TYPE (result) = void_type_node;
- do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (result);
-
- /* As a matter of principle, `start_sequence' should do this. */
- emit_note (0, -1);
+ pedwarn ("ISO C++ forbids assignment of arrays");
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");
if (TREE_SIDE_EFFECTS (lhs))
cond = build_compound_expr (tree_cons
(NULL_TREE, lhs,
- build_expr_list (NULL_TREE, cond)));
+ build_tree_list (NULL_TREE, cond)));
/* Cannot have two identical lhs on this one tree (result) as preexpand
calls will rip them out and fill in RTL for them, but when the
\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));
- cp_warning ("pointer to member cast to virtual base `%T'",
- BINFO_TYPE (binfo));
- warning (" will only work if you are very careful");
+ binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), from);
+ cp_warning ("pointer to member cast to virtual base `%T' will only work if you are very careful", BINFO_TYPE (binfo));
}
delta = BINFO_OFFSET (binfo);
delta = cp_convert (ptrdiff_type_node, delta);
delta);
}
- if (TREE_VIA_VIRTUAL (binfo))
+ if (binfo_from_vbase (binfo))
{
if (force)
{
- cp_warning ("pointer to member cast from virtual base `%T'",
- BINFO_TYPE (binfo));
- warning (" will only work if you are very careful");
+ cp_warning ("pointer to member cast from virtual base `%T' will only wokr if you are very careful", BINFO_TYPE (binfo));
}
else
cp_error ("pointer to member conversion from virtual base `%T'",
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;
if (!force
&& !can_convert_arg (to_type, TREE_TYPE (pfn), pfn))
- cp_error ("conversion to `%T' from `%T'",
+ cp_error ("invalid conversion to type `%T' from type `%T'",
to_type, pfn_type);
if (TREE_CODE (pfn) == PTRMEM_CST)
{
tree type = TREE_TYPE (cst);
tree fn = PTRMEM_CST_MEMBER (cst);
+ tree ptr_class, fn_class;
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
-
- *delta
- = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)),
- TYPE_PTRMEMFUNC_OBJECT_TYPE (type),
- /*force=*/0);
+
+ /* The class that the function belongs to. */
+ fn_class = DECL_CONTEXT (fn);
+
+ /* The class that we're creating a pointer to member of. */
+ ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
+
+ /* First, calculate the adjustment to the function's class. */
+ *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0);
+
if (!DECL_VIRTUAL_P (fn))
{
- *idx = size_binop (MINUS_EXPR, integer_zero_node,
- integer_one_node);
- *pfn = build_addr_func (fn);
- if (!same_type_p (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)),
- TYPE_PTRMEMFUNC_OBJECT_TYPE (type)))
- *pfn = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
- *pfn);
+ *idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+ *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
*delta2 = NULL_TREE;
}
else
{
- *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn),
- integer_one_node);
+ /* If we're dealing with a virtual function, we have to adjust 'this'
+ again, to point to the base which provides the vtable entry for
+ fn; the call will do the opposite adjustment. */
+ tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
+ tree binfo = binfo_or_else (orig_class, fn_class);
+ *delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo));
+
+ /* Map everything down one to make room for the null PMF. */
+ *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node);
*pfn = NULL_TREE;
- *delta2 = get_binfo (DECL_CONTEXT (fn),
- DECL_CLASS_CONTEXT (fn),
- 0);
- *delta2 = get_vfield_offset (*delta2);
- *delta2 = size_binop (PLUS_EXPR, *delta2,
- build_binary_op (PLUS_EXPR,
- *delta,
- integer_zero_node));
+
+ /* Offset from an object of PTR_CLASS to the vptr for ORIG_CLASS. */
+ *delta2 = size_binop (PLUS_EXPR, *delta,
+ get_vfield_offset (TYPE_BINFO (orig_class)));
}
}
pfn_identifier, NULL_TREE, 0));
}
-/* Convert value RHS to type TYPE as preparation for an assignment
- to an lvalue of type TYPE.
- The real work of conversion is done by `convert'.
- The purpose of this function is to generate error messages
- for assignments that are not allowed in C.
- ERRTYPE is a string to use in error messages:
- "assignment", "return", etc.
-
- C++: attempts to allow `convert' to find conversions involving
- implicit type conversion between aggregate and scalar types
- as per 8.5.6 of C++ manual. Does not randomly dereference
- pointers to aggregates! */
+/* Convert value RHS to type TYPE as preparation for an assignment to
+ an lvalue of type TYPE. ERRTYPE is a string to use in error
+ messages: "assignment", "return", etc. If FNDECL is non-NULL, we
+ are doing the conversion in order to pass the PARMNUMth argument of
+ FNDECL. */
static tree
convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
rhs = TREE_OPERAND (rhs, 0);
- if (rhs == error_mark_node || TREE_TYPE (rhs) == error_mark_node)
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+
+ if (rhs == error_mark_node || rhstype == error_mark_node)
return error_mark_node;
if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)
return error_mark_node;
- if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
- || is_overloaded_fn (rhs))
- rhs = default_conversion (rhs);
- else if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
- rhs = convert_from_reference (rhs);
-
- /* If rhs is some sort of overloaded function, ocp_convert will either
- do the right thing or complain; we don't need to check anything else.
- So just hand off. */
- if (type_unknown_p (rhs))
- return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
-
- rhstype = TREE_TYPE (rhs);
- coder = TREE_CODE (rhstype);
-
- /* Issue warnings about peculiar, but legal, uses of NULL. */
+ /* Issue warnings about peculiar, but legal, uses of NULL. We
+ do this *before* the call to decl_constant_value so as to
+ avoid duplicate warnings on code like `const int I = NULL;
+ f(I);'. */
if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
cp_warning ("converting NULL to non-pointer type");
- /* This should no longer change types on us. */
- if (TREE_CODE (rhs) == CONST_DECL)
- rhs = DECL_INITIAL (rhs);
- else if (TREE_READONLY_DECL_P (rhs))
- rhs = decl_constant_value (rhs);
-
- if (same_type_p (type, rhstype))
- {
- overflow_warning (rhs);
- return rhs;
- }
-
+ /* The RHS of an assignment cannot have void type. */
if (coder == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
- /* Arithmetic types all interconvert. */
- if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE
- || codel == COMPLEX_TYPE)
- && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE
- || coder == COMPLEX_TYPE))
- {
- /* But we should warn if assigning REAL_TYPE to INTEGER_TYPE. */
- if (coder == REAL_TYPE && codel == INTEGER_TYPE)
- {
- if (fndecl)
- cp_warning ("`%T' used for argument %P of `%D'",
- rhstype, parmnum, fndecl);
- else
- cp_warning ("%s to `%T' from `%T'", errtype, type, rhstype);
- }
- /* And we should warn if assigning a negative value to
- an unsigned variable. */
- else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
- {
- if (TREE_CODE (rhs) == INTEGER_CST
- && TREE_NEGATED_INT (rhs))
- {
- if (fndecl)
- cp_warning ("negative value `%E' passed as argument %P of `%D'",
- rhs, parmnum, fndecl);
- else
- cp_warning ("%s of negative value `%E' to `%T'",
- errtype, rhs, type);
- }
- overflow_warning (rhs);
- if (TREE_CONSTANT (rhs))
- rhs = fold (rhs);
- }
-
- return convert_and_check (type, rhs);
- }
- /* Conversions involving enums. */
- else if ((codel == ENUMERAL_TYPE
- && (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE))
- || (coder == ENUMERAL_TYPE
- && (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
- {
- return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
- }
- /* Conversions among pointers */
- else if (codel == POINTER_TYPE
- && (coder == POINTER_TYPE
- || (coder == RECORD_TYPE
- && (IS_SIGNATURE_POINTER (rhstype)
- || IS_SIGNATURE_REFERENCE (rhstype)))))
- {
- register tree ttl = TREE_TYPE (type);
- register tree ttr;
- int ctt = 0;
-
- if (coder == RECORD_TYPE)
- {
- rhs = build_optr_ref (rhs);
- rhstype = TREE_TYPE (rhs);
- }
- ttr = TREE_TYPE (rhstype);
-
- /* If both pointers are of aggregate type, then we
- can give better error messages, and save some work
- as well. */
- if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
- {
- tree binfo;
-
- if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr)
- || type == class_star_type_node
- || rhstype == class_star_type_node)
- binfo = TYPE_BINFO (ttl);
- else
- binfo = get_binfo (ttl, ttr, 1);
-
- if (binfo == error_mark_node)
- return error_mark_node;
- if (binfo == 0)
- return error_not_base_type (ttl, ttr);
-
- if (!at_least_as_qualified_p (ttl, ttr))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
- errtype, type, rhstype);
- }
- }
- /* Any non-function converts to a [const][volatile] void *
- and vice versa; otherwise, targets must be the same.
- Meanwhile, the lhs target must have all the qualifiers of the rhs. */
- else if (TYPE_MAIN_VARIANT (ttl) == void_type_node
- || TYPE_MAIN_VARIANT (ttr) == void_type_node
- || (ctt = comp_target_types (type, rhstype, 1))
- || (unsigned_type (TYPE_MAIN_VARIANT (ttl))
- == unsigned_type (TYPE_MAIN_VARIANT (ttr))))
- {
- /* ARM $4.8, commentary on p39. */
- if (TYPE_MAIN_VARIANT (ttl) == void_type_node
- && TREE_CODE (ttr) == OFFSET_TYPE)
- {
- cp_error ("no standard conversion from `%T' to `void *'", ttr);
- return error_mark_node;
- }
-
- if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr))
- cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
- rhstype, type);
+ /* Simplify the RHS if possible. */
+ if (TREE_CODE (rhs) == CONST_DECL)
+ rhs = DECL_INITIAL (rhs);
+ else if (TREE_READONLY_DECL_P (rhs))
+ rhs = decl_constant_value (rhs);
- if (TYPE_MAIN_VARIANT (ttl) != void_type_node
- && TYPE_MAIN_VARIANT (ttr) == void_type_node
- && ! null_ptr_cst_p (rhs))
- {
- if (coder == RECORD_TYPE)
- cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
- type);
- else
- pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s",
- errtype);
- }
- /* Const and volatile mean something different for function types,
- so the usual warnings are not appropriate. */
- else if ((TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttr) != METHOD_TYPE)
- || (TREE_CODE (ttl) != FUNCTION_TYPE && TREE_CODE (ttl) != METHOD_TYPE))
- {
- if (TREE_CODE (ttl) == OFFSET_TYPE
- && binfo_member (TYPE_OFFSET_BASETYPE (ttr),
- CLASSTYPE_VBASECLASSES (TYPE_OFFSET_BASETYPE (ttl))))
- {
- error ("%s between pointer to members converting across virtual baseclasses", errtype);
- return error_mark_node;
- }
- else if (!at_least_as_qualified_p (ttl, ttr))
- {
- if (string_conv_p (type, rhs, 1))
- /* converting from string constant to char *, OK. */;
- else if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
- errtype, type, rhstype);
- }
- else if (TREE_CODE (ttl) == TREE_CODE (ttr)
- && ! comp_target_types (type, rhstype, 1))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' changes signedness",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' changes signedness",
- errtype, type, rhstype);
- }
- }
- }
+ /* Warn about assigning a floating-point type to an integer type. */
+ if (coder == REAL_TYPE && codel == INTEGER_TYPE)
+ {
+ if (fndecl)
+ cp_warning ("`%T' used for argument %P of `%D'",
+ rhstype, parmnum, fndecl);
else
- {
- int add_quals = 0;
- int drops_quals = 0;
- int left_const = 1;
- int unsigned_parity;
- int nptrs = 0;
-
- /* This code is basically a duplicate of comp_ptr_ttypes_real. */
- for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr))
- {
- nptrs -= 1;
- drops_quals |= !at_least_as_qualified_p (ttl, ttr);
-
- if (! left_const
- && !at_least_as_qualified_p (ttr, ttl))
- add_quals = 1;
- left_const &= TYPE_READONLY (ttl);
-
- if (TREE_CODE (ttl) != POINTER_TYPE
- || TREE_CODE (ttr) != POINTER_TYPE)
- break;
- }
- unsigned_parity = TREE_UNSIGNED (ttl) - TREE_UNSIGNED (ttr);
- if (unsigned_parity)
- {
- if (TREE_UNSIGNED (ttl))
- ttr = unsigned_type (ttr);
- else
- ttl = unsigned_type (ttl);
- }
-
- if (comp_target_types (ttl, ttr, nptrs) > 0)
- {
- if (add_quals)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' adds cv-quals without intervening `const'",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' adds cv-quals without intervening `const'",
- errtype, type, rhstype);
- }
- if (drops_quals)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
- errtype, type, rhstype);
- }
- if (unsigned_parity > 0)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' changes signed to unsigned",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' changes signed to unsigned",
- errtype, type, rhstype);
- }
- else if (unsigned_parity < 0)
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D' changes unsigned to signed",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' changes unsigned to signed",
- errtype, type, rhstype);
- }
-
- /* C++ is not so friendly about converting function and
- member function pointers as C. Emit warnings here. */
- if (TREE_CODE (ttl) == FUNCTION_TYPE
- || TREE_CODE (ttl) == METHOD_TYPE)
- if (!same_or_base_type_p (ttl, ttr))
- {
- warning ("conflicting function types in %s:", errtype);
- cp_warning ("\t`%T' != `%T'", type, rhstype);
- }
- }
- else
- {
- if (fndecl)
- cp_error ("passing `%T' as argument %P of `%D'",
- rhstype, parmnum, fndecl);
- else
- cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
- return error_mark_node;
- }
- }
- return cp_convert (type, rhs);
+ cp_warning ("%s to `%T' from `%T'", errtype, type, rhstype);
}
- else if (codel == POINTER_TYPE
- && (coder == INTEGER_TYPE
- || coder == BOOLEAN_TYPE))
+ /* And warn about assigning a negative value to an unsigned
+ variable. */
+ else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
{
- /* An explicit constant 0 can convert to a pointer,
- but not a 0 that results from casting or folding. */
- if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs)))
+ if (TREE_CODE (rhs) == INTEGER_CST
+ && TREE_NEGATED_INT (rhs))
{
if (fndecl)
- cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast",
- rhstype, parmnum, fndecl);
+ cp_warning ("negative value `%E' passed as argument %P of `%D'",
+ rhs, parmnum, fndecl);
else
- cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
- errtype, type, rhstype);
+ cp_warning ("%s of negative value `%E' to `%T'",
+ errtype, rhs, type);
+ }
+ overflow_warning (rhs);
+ if (TREE_CONSTANT (rhs))
+ rhs = fold (rhs);
+ }
+
+ /* [expr.ass]
+
+ The expression is implicitly converted (clause _conv_) to the
+ cv-unqualified type of the left operand. */
+ if (!can_convert_arg (type, rhstype, rhs))
+ {
+ /* When -Wno-pmf-conversions is use, we just silently allow
+ conversions from pointers-to-members to plain pointers. If
+ the conversion doesn't work, cp_convert will complain. */
+ if (!warn_pmf2ptr
+ && TYPE_PTR_P (type)
+ && TYPE_PTRMEMFUNC_P (rhstype))
+ rhs = cp_convert (strip_top_quals (type), rhs);
+ else
+ {
+ /* If the right-hand side has unknown type, then it is an
+ overloaded function. Call instantiate_type to get error
+ messages. */
+ if (rhstype == unknown_type_node)
+ instantiate_type (type, rhs, 1);
+ else if (fndecl)
+ cp_error ("cannot convert `%T' to `%T' for argument `%P' to `%D'",
+ rhstype, type, parmnum, fndecl);
+ else
+ cp_error ("cannot convert `%T' to `%T' in %s", rhstype, type,
+ errtype);
+ return error_mark_node;
}
- return cp_convert (type, rhs);
- }
- else if (codel == INTEGER_TYPE
- && (coder == POINTER_TYPE
- || (coder == RECORD_TYPE
- && (IS_SIGNATURE_POINTER (rhstype)
- || TYPE_PTRMEMFUNC_FLAG (rhstype)
- || IS_SIGNATURE_REFERENCE (rhstype)))))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
- errtype, type, rhstype);
- return cp_convert (type, rhs);
- }
- else if (codel == BOOLEAN_TYPE
- && (coder == POINTER_TYPE
- || (coder == RECORD_TYPE
- && (IS_SIGNATURE_POINTER (rhstype)
- || TYPE_PTRMEMFUNC_FLAG (rhstype)
- || IS_SIGNATURE_REFERENCE (rhstype)))))
- return cp_convert (type, rhs);
-
- /* C++ */
- else if (((coder == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (rhstype)) == METHOD_TYPE)
- || integer_zerop (rhs)
- || TYPE_PTRMEMFUNC_P (rhstype))
- && TYPE_PTRMEMFUNC_P (type))
- {
- tree ttl = TYPE_PTRMEMFUNC_FN_TYPE (type);
- tree ttr = (TYPE_PTRMEMFUNC_P (rhstype)
- ? TYPE_PTRMEMFUNC_FN_TYPE (rhstype)
- : rhstype);
- int ctt = (TREE_CODE (rhstype) == INTEGER_TYPE ? 1
- : comp_target_types (ttl, ttr, 1));
-
- if (ctt < 0)
- cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
- ttr, ttl);
- else if (ctt == 0)
- cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
-
- /* compatible pointer to member functions. */
- return build_ptrmemfunc (ttl, rhs, 0);
- }
- else if (codel == ERROR_MARK || coder == ERROR_MARK)
- return error_mark_node;
-
- /* This should no longer happen. References are initialized via
- `convert_for_initialization'. They should otherwise be
- bashed before coming here. */
- else if (codel == REFERENCE_TYPE)
- my_friendly_abort (317);
- else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (rhs)))
- {
- tree nrhs = build1 (NOP_EXPR, type, rhs);
- TREE_CONSTANT (nrhs) = TREE_CONSTANT (rhs);
- return nrhs;
}
- else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
- return cp_convert (type, rhs);
- /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */
- else if (TREE_CODE (type) == POINTER_TYPE
- && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
- || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
- && TREE_TYPE (rhs)
- && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
- return cp_convert (type, rhs);
-
- cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
- return error_mark_node;
+ return perform_implicit_conversion (strip_top_quals (type), rhs);
}
/* Convert RHS to be of type TYPE.
if (fndecl)
savew = warningcount, savee = errorcount;
- rhs = convert_to_reference (type, rhs, CONV_IMPLICIT, flags,
- exp ? exp : error_mark_node);
+ rhs = initialize_reference (type, rhs);
if (fndecl)
{
if (warningcount > savew)
type = complete_type (type);
- if (TYPE_LANG_SPECIFIC (type)
- && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
- return build_signature_pointer_constructor (type, rhs);
-
if (IS_AGGR_TYPE (type))
return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
- if (type == TREE_TYPE (rhs))
- {
- /* Issue warnings about peculiar, but legal, uses of NULL. We
- do this *before* the call to decl_constant_value so as to
- avoid duplicate warnings on code like `const int I = NULL;
- f(I);'. */
- if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
- cp_warning ("converting NULL to non-pointer type");
-
- if (TREE_READONLY_DECL_P (rhs))
- rhs = decl_constant_value (rhs);
-
- return rhs;
- }
-
return convert_for_assignment (type, rhs, errtype, fndecl, parmnum);
}
\f
emit_queue ();
}
\f
-/* Expand a C `return' statement.
- RETVAL is the expression for what to return,
- or a null pointer for `return;' with no value.
+/* If RETVAL is the address of, or a reference to, a local variable or
+ temporary give an appropraite warning. */
- C++: upon seeing a `return', we must call destructors on all
- variables in scope which had constructors called on them.
- This means that if in a destructor, the base class destructors
- must be called before returning.
+static void
+maybe_warn_about_returning_address_of_local (retval)
+ tree retval;
+{
+ tree valtype = TREE_TYPE (DECL_RESULT (current_function_decl));
- The RETURN statement in C++ has initialization semantics. */
+ if (TREE_CODE (valtype) == REFERENCE_TYPE)
+ {
+ tree whats_returned;
-void
-c_expand_return (retval)
+ /* Sort through common things to see what it is
+ we are returning. */
+ whats_returned = retval;
+ if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
+ {
+ whats_returned = TREE_OPERAND (whats_returned, 1);
+ if (TREE_CODE (whats_returned) == ADDR_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ }
+ while (TREE_CODE (whats_returned) == CONVERT_EXPR
+ || TREE_CODE (whats_returned) == NOP_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ if (TREE_CODE (whats_returned) == ADDR_EXPR)
+ {
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
+ || TREE_CODE (whats_returned) == TARGET_EXPR)
+ {
+ /* Get the target. */
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ warning ("returning reference to temporary");
+ }
+ }
+
+ if (TREE_CODE (whats_returned) == VAR_DECL
+ && DECL_NAME (whats_returned))
+ {
+ if (TEMP_NAME_P (DECL_NAME (whats_returned)))
+ warning ("reference to non-lvalue returned");
+ else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
+ && DECL_FUNCTION_SCOPE_P (whats_returned)
+ && !(TREE_STATIC (whats_returned)
+ || TREE_PUBLIC (whats_returned)))
+ cp_warning_at ("reference to local variable `%D' returned",
+ whats_returned);
+ }
+ }
+ else if (TREE_CODE (retval) == ADDR_EXPR)
+ {
+ tree whats_returned = TREE_OPERAND (retval, 0);
+
+ if (TREE_CODE (whats_returned) == VAR_DECL
+ && DECL_NAME (whats_returned)
+ && DECL_FUNCTION_SCOPE_P (whats_returned)
+ && !(TREE_STATIC (whats_returned)
+ || TREE_PUBLIC (whats_returned)))
+ cp_warning_at ("address of local variable `%D' returned",
+ whats_returned);
+ }
+}
+
+/* Check that returning RETVAL from the current function is legal.
+ Return an expression explicitly showing all conversions required to
+ change RETVAL into the function return type, and to assign it to
+ the DECL_RESULT for the function. */
+
+tree
+check_return_expr (retval)
tree retval;
{
- extern struct nesting *cond_stack, *loop_stack, *case_stack;
- extern tree dtor_label, ctor_label;
- tree result = DECL_RESULT (current_function_decl);
- tree valtype = TREE_TYPE (result);
-
+ tree result;
+ /* The type actually returned by the function, after any
+ promotions. */
+ tree valtype;
+ int fn_returns_value_p;
+
+ /* A `volatile' function is one that isn't supposed to return, ever.
+ (This is a G++ extension, used to get better code for functions
+ that call the `volatile' function.) */
if (TREE_THIS_VOLATILE (current_function_decl))
warning ("function declared `noreturn' has a `return' statement");
+ /* Check for various simple errors. */
if (retval == error_mark_node)
{
+ /* If an error occurred, there's nothing to do. */
current_function_returns_null = 1;
- return;
- }
-
- if (processing_template_decl)
- {
- add_tree (build_min_nt (RETURN_STMT, retval));
- return;
+ return error_mark_node;
}
-
- if (dtor_label)
+ else if (dtor_label)
{
if (retval)
error ("returning a value from a destructor");
+ return NULL_TREE;
+ }
+ else if (in_function_try_handler
+ && DECL_CONSTRUCTOR_P (current_function_decl))
+ {
+ /* If a return statement appears in a handler of the
+ function-try-block of a constructor, the program is ill-formed. */
+ error ("cannot return from a handler of a function-try-block of a constructor");
+ return error_mark_node;
+ }
+ else if (retval && DECL_CONSTRUCTOR_P (current_function_decl))
+ /* You can't return a value from a constructor. */
+ error ("returning a value from a constructor");
+
+ /* Constructors actually always return `this', even though in C++
+ you can't return a value from a constructor. */
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ retval = current_class_ptr;
+
+ /* When no explicit return-value is given in a function with a named
+ return value, the named return value is used. */
+ result = DECL_RESULT (current_function_decl);
+ valtype = TREE_TYPE (result);
+ my_friendly_assert (valtype != NULL_TREE, 19990924);
+ fn_returns_value_p = !same_type_p (valtype, void_type_node);
+ if (!retval && DECL_NAME (result) && fn_returns_value_p)
+ retval = result;
+
+ /* Check for a return statement with no return value in a function
+ that's supposed to return a value. */
+ if (!retval && fn_returns_value_p)
+ {
+ pedwarn ("return-statement with no value, in function declared with a non-void return type");
+ /* Clear this, so finish_function won't say that we reach the
+ end of a non-void function (which we don't, we gave a
+ return!). */
+ current_function_returns_null = 0;
+ }
+ /* Check for a return statement with a value in a function that
+ isn't supposed to return a value. */
+ else if (retval && !fn_returns_value_p)
+ {
+ if (same_type_p (TREE_TYPE (retval), void_type_node))
+ /* You can return a `void' value from a function of `void'
+ type. In that case, we have to evaluate the expression for
+ its side-effects. */
+ finish_expr_stmt (retval);
+ else
+ pedwarn ("return-statement with a value, in function declared with a void return type");
- /* Can't just return from a destructor. */
- expand_goto (dtor_label);
- return;
+ current_function_returns_null = 1;
+
+ /* There's really no value to return, after all. */
+ return NULL_TREE;
}
+ else if (!retval)
+ /* Remember that this function can sometimes return without a
+ value. */
+ current_function_returns_null = 1;
/* Only operator new(...) throw(), can return NULL [expr.new/13]. */
if ((DECL_NAME (current_function_decl) == ansi_opname[(int) NEW_EXPR]
|| DECL_NAME (current_function_decl) == ansi_opname[(int) VEC_NEW_EXPR])
&& !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
&& null_ptr_cst_p (retval))
- cp_pedwarn ("operator new should throw an exception, not return NULL");
-
- if (retval == NULL_TREE)
- {
- /* A non-named return value does not count. */
-
- if (DECL_CONSTRUCTOR_P (current_function_decl))
- retval = current_class_ptr;
- else if (DECL_NAME (result) != NULL_TREE
- && TREE_CODE (valtype) != VOID_TYPE)
- retval = result;
- else
- {
- current_function_returns_null = 1;
-
- if (valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE)
- {
- if (DECL_NAME (DECL_RESULT (current_function_decl)) == NULL_TREE)
- {
- pedwarn ("`return' with no value, in function returning non-void");
- /* Clear this, so finish_function won't say that we
- reach the end of a non-void function (which we don't,
- we gave a return!). */
- current_function_returns_null = 0;
- }
- }
-
- expand_null_return ();
- return;
- }
- }
- else if (DECL_CONSTRUCTOR_P (current_function_decl))
- {
- if (flag_this_is_variable)
- error ("return from a constructor: use `this = ...' instead");
- else
- error ("returning a value from a constructor");
- retval = current_class_ptr;
- }
+ cp_warning ("`operator new' should throw an exception, not return NULL");
/* Effective C++ rule 15. See also start_function. */
if (warn_ecpp
&& retval != current_class_ref)
cp_warning ("`operator=' should return a reference to `*this'");
- if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
- {
- current_function_returns_null = 1;
- if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
- pedwarn ("`return' with a value, in function returning void");
- expand_return (retval);
- return;
- }
-
- /* Now deal with possible C++ hair:
- (1) Compute the return value.
- (2) If there are aggregate values with destructors which
- must be cleaned up, clean them (taking care
- not to clobber the return value).
- (3) If an X(X&) constructor is defined, the return
- value must be returned via that. */
-
- if (retval == result
- || DECL_CONSTRUCTOR_P (current_function_decl))
- /* It's already done for us. */;
- else if (TREE_CODE (TREE_TYPE (retval)) == VOID_TYPE)
- {
- pedwarn ("return of void value in function returning non-void");
- expand_expr_stmt (retval);
- retval = 0;
- }
+ /* We don't need to do any conversions when there's nothing being
+ returned. */
+ if (!retval)
+ return NULL_TREE;
+
+ /* Do any required conversions. */
+ if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))
+ /* No conversions are required. */
+ ;
else
{
+ /* The type the function is declared to return. */
tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
/* First convert the value to the function's return type, then
to the type of return value's location to handle the
case that functype is thiner than the valtype. */
-
retval = convert_for_initialization
(NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
"return", NULL_TREE, 0);
-
retval = convert (valtype, retval);
+ /* If the conversion failed, treat this just like `return;'. */
if (retval == error_mark_node)
- {
- /* Avoid warning about control reaching end of function. */
- expand_null_return ();
- return;
- }
-
+ return NULL_TREE;
/* We can't initialize a register from a AGGR_INIT_EXPR. */
else if (! current_function_returns_struct
&& TREE_CODE (retval) == TARGET_EXPR
&& TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
TREE_OPERAND (retval, 0));
+ else
+ maybe_warn_about_returning_address_of_local (retval);
+ }
+
+ /* Actually copy the value returned into the appropriate location. */
+ if (retval && retval != result)
+ retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
- /* Add some useful error checking for C++. */
- else if (TREE_CODE (valtype) == REFERENCE_TYPE)
- {
- tree whats_returned;
-
- /* Sort through common things to see what it is
- we are returning. */
- whats_returned = retval;
- if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
- {
- whats_returned = TREE_OPERAND (whats_returned, 1);
- if (TREE_CODE (whats_returned) == ADDR_EXPR)
- whats_returned = TREE_OPERAND (whats_returned, 0);
- }
- while (TREE_CODE (whats_returned) == CONVERT_EXPR
- || TREE_CODE (whats_returned) == NOP_EXPR)
- whats_returned = TREE_OPERAND (whats_returned, 0);
- if (TREE_CODE (whats_returned) == ADDR_EXPR)
- {
- whats_returned = TREE_OPERAND (whats_returned, 0);
- while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
- || TREE_CODE (whats_returned) == TARGET_EXPR)
- {
- /* Get the target. */
- whats_returned = TREE_OPERAND (whats_returned, 0);
- warning ("returning reference to temporary");
- }
- }
-
- 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);
+ /* 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)
- && 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.
c_expand_start_case (exp)
tree exp;
{
- tree type, idx;
-
- exp = build_expr_type_conversion (WANT_INT | WANT_ENUM, exp, 1);
- if (exp == NULL_TREE)
- {
- error ("switch quantity not an integer");
- exp = error_mark_node;
- }
- if (exp == error_mark_node)
- return error_mark_node;
-
- exp = default_conversion (exp);
- type = TREE_TYPE (exp);
- idx = get_unwidened (exp, 0);
- /* We can't strip a conversion from a signed type to an unsigned,
- because if we did, int_fits_type_p would do the wrong thing
- when checking case values for being in range,
- and it's too hard to do the right thing. */
- if (TREE_UNSIGNED (TREE_TYPE (exp)) == TREE_UNSIGNED (TREE_TYPE (idx)))
- exp = idx;
-
- expand_start_case
- (1, fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp)),
- type, "switch statement");
+ expand_start_case (1, exp, TREE_TYPE (exp), "switch statement");
return 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;
+}
+
+/* Returns TYPE with its cv qualifiers removed
+ TYPE is T cv* .. *cv where T is not a pointer type,
+ returns T * .. *. (If T is an array type, then the cv qualifiers
+ above are those of the array members.) */
+
+static tree
+strip_all_pointer_quals (type)
+ tree type;
+{
+ if (TREE_CODE (type) == POINTER_TYPE)
+ return build_pointer_type (strip_all_pointer_quals (TREE_TYPE (type)));
+ else
+ return TYPE_MAIN_VARIANT (type);
+}