return ret;
}
+/* Having checked whether EXPR may appear in an unevaluated part of an
+ integer constant expression and found that it may, remove any
+ C_MAYBE_CONST_EXPR noting this fact and return the resulting
+ expression. */
+
+static inline tree
+remove_c_maybe_const_expr (tree expr)
+{
+ if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR)
+ return C_MAYBE_CONST_EXPR_EXPR (expr);
+ else
+ return expr;
+}
+
\f/* This is a cache to hold if two types are compatible or not. */
struct tagged_tu_seen_cache {
\f
/* Build an external reference to identifier ID. FUN indicates
whether this will be used for a function call. LOC is the source
- location of the identifier. */
+ location of the identifier. This sets *TYPE to the type of the
+ identifier, which is not the same as the type of the returned value
+ for CONST_DECLs defined as enum constants. If the type of the
+ identifier is not available, *TYPE is set to NULL. */
tree
-build_external_ref (tree id, int fun, location_t loc)
+build_external_ref (tree id, int fun, location_t loc, tree *type)
{
tree ref;
tree decl = lookup_name (id);
whatever lookup_name() found. */
decl = objc_lookup_ivar (decl, id);
+ *type = NULL;
if (decl && decl != error_mark_node)
- ref = decl;
+ {
+ ref = decl;
+ *type = TREE_TYPE (ref);
+ }
else if (fun)
/* Implicit function declaration. */
ref = implicitly_declare (id);
{
ret.value = error_mark_node;
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
pop_maybe_used (false);
}
else
&expr_const_operands);
ret.value = c_sizeof (TREE_TYPE (folded_expr));
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
if (c_vla_type_p (TREE_TYPE (folded_expr)))
{
/* sizeof is evaluated when given a vla (C99 6.5.3.4p2). */
type = groktypename (t, &type_expr, &type_expr_const);
ret.value = c_sizeof (type);
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
if (type_expr && c_vla_type_p (type))
{
ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
result.value = build_unary_op (loc, code, arg.value, 0);
result.original_code = code;
-
+ result.original_type = NULL;
+
if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value))
overflow_warning (result.value);
enum tree_code code1 = arg1.original_code;
enum tree_code code2 = arg2.original_code;
+ tree type1 = (arg1.original_type
+ ? arg1.original_type
+ : TREE_TYPE (arg1.value));
+ tree type2 = (arg2.original_type
+ ? arg2.original_type
+ : TREE_TYPE (arg2.value));
result.value = build_binary_op (location, code,
arg1.value, arg2.value, 1);
result.original_code = code;
+ result.original_type = NULL;
if (TREE_CODE (result.value) == ERROR_MARK)
return result;
&& !TREE_OVERFLOW_P (arg2.value))
overflow_warning (result.value);
+ /* Warn about comparisons of different enum types. */
+ if (warn_enum_compare
+ && TREE_CODE_CLASS (code) == tcc_comparison
+ && TREE_CODE (type1) == ENUMERAL_TYPE
+ && TREE_CODE (type2) == ENUMERAL_TYPE
+ && TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2))
+ warning_at (location, OPT_Wenum_compare,
+ "comparison between %qT and %qT",
+ type1, type2);
+
return result;
}
\f
bool int_operands;
int_operands = EXPR_INT_CONST_OPERANDS (xarg);
+ if (int_operands)
+ arg = remove_c_maybe_const_expr (arg);
if (code != ADDR_EXPR)
arg = require_complete_type (arg);
tree ep_result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
bool int_const, op1_int_operands, op2_int_operands, int_operands;
+ bool ifexp_int_operands;
tree ret;
bool objc_ok;
+ op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1);
+ if (op1_int_operands)
+ op1 = remove_c_maybe_const_expr (op1);
+ op2_int_operands = EXPR_INT_CONST_OPERANDS (orig_op2);
+ if (op2_int_operands)
+ op2 = remove_c_maybe_const_expr (op2);
+ ifexp_int_operands = EXPR_INT_CONST_OPERANDS (ifexp);
+ if (ifexp_int_operands)
+ ifexp = remove_c_maybe_const_expr (ifexp);
+
/* Promote both alternatives. */
if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE)
if (result_type != TREE_TYPE (op2))
op2 = convert_and_check (result_type, op2);
- op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1);
- op2_int_operands = EXPR_INT_CONST_OPERANDS (orig_op2);
if (ifexp_bcp && ifexp == truthvalue_true_node)
{
op2_int_operands = true;
op1_int_operands = true;
op2 = c_fully_fold (op2, require_constant_value, NULL);
}
- int_const = int_operands = (EXPR_INT_CONST_OPERANDS (ifexp)
+ int_const = int_operands = (ifexp_int_operands
&& op1_int_operands
&& op2_int_operands);
if (int_operands)
tree
build_compound_expr (tree expr1, tree expr2)
{
+ bool expr1_int_operands, expr2_int_operands;
tree eptype = NULL_TREE;
tree ret;
+ expr1_int_operands = EXPR_INT_CONST_OPERANDS (expr1);
+ if (expr1_int_operands)
+ expr1 = remove_c_maybe_const_expr (expr1);
+ expr2_int_operands = EXPR_INT_CONST_OPERANDS (expr2);
+ if (expr2_int_operands)
+ expr2 = remove_c_maybe_const_expr (expr2);
+
if (TREE_CODE (expr1) == EXCESS_PRECISION_EXPR)
expr1 = TREE_OPERAND (expr1, 0);
if (TREE_CODE (expr2) == EXCESS_PRECISION_EXPR)
ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
if (flag_isoc99
- && EXPR_INT_CONST_OPERANDS (expr1)
- && EXPR_INT_CONST_OPERANDS (expr2))
+ && expr1_int_operands
+ && expr2_int_operands)
ret = note_integer_operands (ret);
if (eptype)
tree typ2 = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)));
expr.value = inside_init;
expr.original_code = (strict_string ? STRING_CST : ERROR_MARK);
+ expr.original_type = NULL;
maybe_warn_string_init (type, expr);
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
if (type == 0)
type = TREE_TYPE (constructor_decl);
- if (targetm.vector_opaque_p (type))
+ if (TREE_CODE (type) == VECTOR_TYPE
+ && TYPE_VECTOR_OPAQUE (type))
error ("opaque vector types cannot be initialized");
p->type = constructor_type;
p->depth = constructor_depth;
p->replacement_value.value = 0;
p->replacement_value.original_code = ERROR_MARK;
+ p->replacement_value.original_type = NULL;
p->implicit = 0;
p->range_stack = 0;
p->outer = 0;
p->depth = constructor_depth;
p->replacement_value.value = 0;
p->replacement_value.original_code = ERROR_MARK;
+ p->replacement_value.original_type = NULL;
p->implicit = implicit;
p->outer = 0;
p->incremental = constructor_incremental;
struct c_expr ret;
ret.value = 0;
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
if (implicit == 0)
{
{
tree label = NULL_TREE;
+ if (low_value && TREE_CODE (low_value) != INTEGER_CST)
+ {
+ low_value = c_fully_fold (low_value, false, NULL);
+ if (TREE_CODE (low_value) == INTEGER_CST)
+ pedwarn (input_location, OPT_pedantic,
+ "case label is not an integer constant expression");
+ }
+
+ if (high_value && TREE_CODE (high_value) != INTEGER_CST)
+ {
+ high_value = c_fully_fold (high_value, false, NULL);
+ if (TREE_CODE (high_value) == INTEGER_CST)
+ pedwarn (input_location, OPT_pedantic,
+ "case label is not an integer constant expression");
+ }
+
if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
&& !c_switch_stack->blocked_vm)
{
tree op0, op1;
tree ret = error_mark_node;
const char *invalid_op_diag;
+ bool op0_int_operands, op1_int_operands;
bool int_const, int_const_or_overflow, int_operands;
/* Expression code to give to the expression when it is built.
if (location == UNKNOWN_LOCATION)
location = input_location;
- int_operands = (EXPR_INT_CONST_OPERANDS (orig_op0)
- && EXPR_INT_CONST_OPERANDS (orig_op1));
+ op0 = orig_op0;
+ op1 = orig_op1;
+
+ op0_int_operands = EXPR_INT_CONST_OPERANDS (orig_op0);
+ if (op0_int_operands)
+ op0 = remove_c_maybe_const_expr (op0);
+ op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1);
+ if (op1_int_operands)
+ op1 = remove_c_maybe_const_expr (op1);
+ int_operands = (op0_int_operands && op1_int_operands);
if (int_operands)
{
int_const_or_overflow = (TREE_CODE (orig_op0) == INTEGER_CST
if (convert_p)
{
- op0 = default_conversion (orig_op0);
- op1 = default_conversion (orig_op1);
- }
- else
- {
- op0 = orig_op0;
- op1 = orig_op1;
+ op0 = default_conversion (op0);
+ op1 = default_conversion (op1);
}
orig_type0 = type0 = TREE_TYPE (op0);
int_const = (TREE_CODE (expr) == INTEGER_CST && !TREE_OVERFLOW (expr));
int_operands = EXPR_INT_CONST_OPERANDS (expr);
+ if (int_operands)
+ expr = remove_c_maybe_const_expr (expr);
/* ??? Should we also give an error for void and vectors rather than
leaving those to give errors later? */