/* Build expressions with type checking for C compiler.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GCC.
#include "c-lang.h"
#include "flags.h"
#include "output.h"
-#include "toplev.h"
#include "intl.h"
#include "target.h"
#include "tree-iterator.h"
#include "bitmap.h"
#include "gimple.h"
+#include "c-family/c-objc.h"
/* Possible cases of implicit bad conversions. Used to select
diagnostic messages in convert_for_assignment. */
ic_return
};
+/* Possibe cases of scalar_to_vector conversion. */
+enum stv_conv {
+ stv_error, /* Error occured. */
+ stv_nothing, /* Nothing happened. */
+ stv_firstarg, /* First argument must be expanded. */
+ stv_secondarg /* Second argument must be expanded. */
+};
+
/* The level of nesting inside "__alignof__". */
int in_alignof;
static void set_nonincremental_init (struct obstack *);
static void set_nonincremental_init_from_string (tree, struct obstack *);
static tree find_init_member (tree, struct obstack *);
-static void readonly_error (tree, enum lvalue_use);
static void readonly_warning (tree, enum lvalue_use);
-static int lvalue_or_else (const_tree, enum lvalue_use);
+static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
static void record_maybe_used_decl (tree);
static int comptypes_internal (const_tree, const_tree, bool *, bool *);
\f
tree pointed_to_1 = TREE_TYPE (t1);
tree pointed_to_2 = TREE_TYPE (t2);
tree target = composite_type (pointed_to_1, pointed_to_2);
- t1 = build_pointer_type (target);
+ t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false);
t1 = build_type_attribute_variant (t1, attributes);
return qualify_type (t1, t2);
}
/* If both args specify argument types, we must merge the two
lists, argument by argument. */
- /* Tell global_bindings_p to return false so that variable_size
- doesn't die on VLAs in parameter types. */
- c_override_global_bindings_to_false = true;
len = list_length (p1);
newargs = 0;
parm_done: ;
}
- c_override_global_bindings_to_false = false;
t1 = build_function_type (valtype, newargs);
t1 = qualify_type (t1, t2);
/* ... falls through ... */
compatible integer type, then this sets *ENUM_AND_INT_P to true;
*ENUM_AND_INT_P is never set to false. If DIFFERENT_TYPES_P is not
NULL, and the types are compatible but different enough not to be
- permitted in C1X typedef redeclarations, then this sets
+ permitted in C11 typedef redeclarations, then this sets
*DIFFERENT_TYPES_P to true; *DIFFERENT_TYPES_P is never set to
false, but may or may not be set if the types are incompatible.
This differs from comptypes, in that we don't free the seen
return 1;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
- if (!(attrval = targetm.comp_type_attributes (t1, t2)))
+ if (!(attrval = comp_type_attributes (t1, t2)))
return 0;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
}
}
else if (TREE_CODE (pointer) != ERROR_MARK)
- switch (errstring)
- {
- case RO_ARRAY_INDEXING:
- error_at (loc,
- "invalid type argument of array indexing (have %qT)",
- type);
- break;
- case RO_UNARY_STAR:
- error_at (loc,
- "invalid type argument of unary %<*%> (have %qT)",
- type);
- break;
- case RO_ARROW:
- error_at (loc,
- "invalid type argument of %<->%> (have %qT)",
- type);
- break;
- default:
- gcc_unreachable ();
- }
+ invalid_indirection_error (loc, type, errstring);
+
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE)
{
- error_at (loc,
+ error_at (loc,
"subscripted value is neither array nor pointer nor vector");
return error_mark_node;
index = default_conversion (index);
gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE);
-
- /* For vector[index], convert the vector to a
+
+ /* For vector[index], convert the vector to a
pointer of the underlying type. */
if (TREE_CODE (TREE_TYPE (array)) == VECTOR_TYPE)
{
tree type1;
if (TREE_CODE (index) == INTEGER_CST)
- if (!host_integerp (index, 1)
- || ((unsigned HOST_WIDE_INT) tree_low_cst (index, 1)
+ if (!host_integerp (index, 1)
+ || ((unsigned HOST_WIDE_INT) tree_low_cst (index, 1)
>= TYPE_VECTOR_SUBPARTS (TREE_TYPE (array))))
warning_at (loc, OPT_Warray_bounds, "index value is out of bound");
-
+
c_common_mark_addressable_vec (array);
type = build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
type = build_pointer_type (type);
return tem;
name = DECL_NAME (function);
+
+ if (flag_tm)
+ tm_malloc_replacement (function);
fundecl = function;
+ /* Atomic functions have type checking/casting already done. They are
+ often rewritten and don't match the original parameter list. */
+ if (name && !strncmp (IDENTIFIER_POINTER (name), "__atomic_", 9))
+ origtypes = NULL;
}
if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
function = function_to_pointer_conversion (loc, function);
&& !comptypes (fntype, TREE_TYPE (tem)))
{
tree return_type = TREE_TYPE (fntype);
- tree trap = build_function_call (loc, built_in_decls[BUILT_IN_TRAP],
+ tree trap = build_function_call (loc,
+ builtin_decl_explicit (BUILT_IN_TRAP),
NULL_TREE);
int i;
return error_mark_node;
/* Check that the arguments to the function are valid. */
- check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
- TYPE_ARG_TYPES (fntype));
+ check_function_arguments (fntype, nargs, argarray);
if (name != NULL_TREE
&& !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
}
return require_complete_type (result);
}
+
+/* Build a VEC_PERM_EXPR if V0, V1 and MASK are not error_mark_nodes
+ and have vector types, V0 has the same type as V1, and the number of
+ elements of V0, V1, MASK is the same.
+
+ In case V1 is a NULL_TREE it is assumed that __builtin_shuffle was
+ called with two arguments. In this case implementation passes the
+ first argument twice in order to share the same tree code. This fact
+ could enable the mask-values being twice the vector length. This is
+ an implementation accident and this semantics is not guaranteed to
+ the user. */
+tree
+c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask)
+{
+ tree ret;
+ bool wrap = true;
+ bool maybe_const = false;
+ bool two_arguments = false;
+
+ if (v1 == NULL_TREE)
+ {
+ two_arguments = true;
+ v1 = v0;
+ }
+
+ if (v0 == error_mark_node || v1 == error_mark_node
+ || mask == error_mark_node)
+ return error_mark_node;
+
+ if (TREE_CODE (TREE_TYPE (mask)) != VECTOR_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_TYPE (mask))) != INTEGER_TYPE)
+ {
+ error_at (loc, "__builtin_shuffle last argument must "
+ "be an integer vector");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (TREE_TYPE (v0)) != VECTOR_TYPE
+ || TREE_CODE (TREE_TYPE (v1)) != VECTOR_TYPE)
+ {
+ error_at (loc, "__builtin_shuffle arguments must be vectors");
+ return error_mark_node;
+ }
+
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (v0)) != TYPE_MAIN_VARIANT (TREE_TYPE (v1)))
+ {
+ error_at (loc, "__builtin_shuffle argument vectors must be of "
+ "the same type");
+ return error_mark_node;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (TREE_TYPE (v0))
+ != TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask))
+ && TYPE_VECTOR_SUBPARTS (TREE_TYPE (v1))
+ != TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask)))
+ {
+ error_at (loc, "__builtin_shuffle number of elements of the "
+ "argument vector(s) and the mask vector should "
+ "be the same");
+ return error_mark_node;
+ }
+
+ if (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (v0))))
+ != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (mask)))))
+ {
+ error_at (loc, "__builtin_shuffle argument vector(s) inner type "
+ "must have the same size as inner type of the mask");
+ return error_mark_node;
+ }
+
+ /* Avoid C_MAYBE_CONST_EXPRs inside VEC_PERM_EXPR. */
+ v0 = c_fully_fold (v0, false, &maybe_const);
+ wrap &= maybe_const;
+
+ if (two_arguments)
+ v1 = v0 = save_expr (v0);
+ else
+ {
+ v1 = c_fully_fold (v1, false, &maybe_const);
+ wrap &= maybe_const;
+ }
+
+ mask = c_fully_fold (mask, false, &maybe_const);
+ wrap &= maybe_const;
+
+ ret = build3_loc (loc, VEC_PERM_EXPR, TREE_TYPE (v0), v0, v1, mask);
+
+ if (!wrap)
+ ret = c_wrap_maybe_const (ret, true);
+
+ return ret;
+}
\f
/* Convert the argument expressions in the vector VALUES
to the types in the list TYPELIST.
if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
{
- error_at (input_location,
+ error_at (input_location,
"too few arguments to function %qE", function);
if (fundecl && !DECL_BUILT_IN (fundecl))
inform (DECL_SOURCE_LOCATION (fundecl), "declared here");
/* Complain about anything that is not a true lvalue. In
Objective-C, skip this check for property_refs. */
- if (!objc_is_property_ref (arg)
- && !lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
+ if (!objc_is_property_ref (arg)
+ && !lvalue_or_else (location,
+ arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? lv_increment
: lv_decrement)))
}
inc = c_size_in_bytes (TREE_TYPE (argtype));
- inc = fold_convert_loc (location, sizetype, inc);
+ inc = convert_to_ptrofftype_loc (location, inc);
}
else if (FRACT_MODE_P (TYPE_MODE (argtype)))
{
need to ask Objective-C to build the increment or decrement
expression for it. */
if (objc_is_property_ref (arg))
- return objc_build_incr_expr_for_property_ref (location, code,
+ return objc_build_incr_expr_for_property_ref (location, code,
arg, inc);
/* Report a read-only lvalue. */
tree op0 = TREE_OPERAND (arg, 0);
if (!c_mark_addressable (op0))
return error_mark_node;
- return build_binary_op (location, PLUS_EXPR,
- (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE
- ? array_to_pointer_conversion (location,
- op0)
- : op0),
- TREE_OPERAND (arg, 1), 1);
}
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
- && !lvalue_or_else (arg, lv_addressof))
+ && !lvalue_or_else (location, arg, lv_addressof))
return error_mark_node;
/* Move address operations inside C_MAYBE_CONST_EXPR to simplify
argtype = TREE_TYPE (arg);
/* If the lvalue is const or volatile, merge that into the type
- to which the address will point. This should only be needed
+ to which the address will point. This is only needed
for function types. */
if ((DECL_P (arg) || REFERENCE_CLASS_P (arg))
- && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
+ && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg))
+ && TREE_CODE (argtype) == FUNCTION_TYPE)
{
int orig_quals = TYPE_QUALS (strip_array_types (argtype));
int quals = orig_quals;
if (TREE_THIS_VOLATILE (arg))
quals |= TYPE_QUAL_VOLATILE;
- gcc_assert (quals == orig_quals
- || TREE_CODE (argtype) == FUNCTION_TYPE);
-
argtype = c_build_qualified_type (argtype, quals);
}
if (val && TREE_CODE (val) == INDIRECT_REF
&& TREE_CONSTANT (TREE_OPERAND (val, 0)))
{
- tree op0 = fold_convert_loc (location, sizetype,
- fold_offsetof (arg, val)), op1;
-
- op1 = fold_convert_loc (location, argtype, TREE_OPERAND (val, 0));
- ret = fold_build2_loc (location, POINTER_PLUS_EXPR, argtype, op1, op0);
+ ret = fold_convert_loc (location, argtype, fold_offsetof_1 (arg));
goto return_build_unary_op;
}
}
}
\f
-/* Give an error for storing in something that is 'const'. */
-
-static void
-readonly_error (tree arg, enum lvalue_use use)
-{
- gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
- || use == lv_asm);
- /* Using this macro rather than (for example) arrays of messages
- ensures that all the format strings are checked at compile
- time. */
-#define READONLY_MSG(A, I, D, AS) (use == lv_assign ? (A) \
- : (use == lv_increment ? (I) \
- : (use == lv_decrement ? (D) : (AS))))
- if (TREE_CODE (arg) == COMPONENT_REF)
- {
- if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
- readonly_error (TREE_OPERAND (arg, 0), use);
- else
- error (READONLY_MSG (G_("assignment of read-only member %qD"),
- G_("increment of read-only member %qD"),
- G_("decrement of read-only member %qD"),
- G_("read-only member %qD used as %<asm%> output")),
- TREE_OPERAND (arg, 1));
- }
- else if (TREE_CODE (arg) == VAR_DECL)
- error (READONLY_MSG (G_("assignment of read-only variable %qD"),
- G_("increment of read-only variable %qD"),
- G_("decrement of read-only variable %qD"),
- G_("read-only variable %qD used as %<asm%> output")),
- arg);
- else
- error (READONLY_MSG (G_("assignment of read-only location %qE"),
- G_("increment of read-only location %qE"),
- G_("decrement of read-only location %qE"),
- G_("read-only location %qE used as %<asm%> output")),
- arg);
-}
-
/* Give a warning for storing in something that is read-only in GCC
terms but not const in ISO C terms. */
/* Return nonzero if REF is an lvalue valid for this language;
otherwise, print an error message and return zero. USE says
- how the lvalue is being used and so selects the error message. */
+ how the lvalue is being used and so selects the error message.
+ LOCATION is the location at which any error should be reported. */
static int
-lvalue_or_else (const_tree ref, enum lvalue_use use)
+lvalue_or_else (location_t loc, const_tree ref, enum lvalue_use use)
{
int win = lvalue_p (ref);
if (!win)
- lvalue_error (use);
+ lvalue_error (loc, use);
return win;
}
return error_mark_node;
/* For ObjC properties, defer this check. */
- if (!objc_is_property_ref (lhs) && !lvalue_or_else (lhs, lv_assign))
+ if (!objc_is_property_ref (lhs) && !lvalue_or_else (location, lhs, lv_assign))
return error_mark_node;
if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
return result;
/* Else, do the check that we postponed for Objective-C. */
- if (!lvalue_or_else (lhs, lv_assign))
+ if (!lvalue_or_else (location, lhs, lv_assign))
return error_mark_node;
}
{
tree ret;
bool save = in_late_binary_op;
- if (codel == BOOLEAN_TYPE)
+ if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE)
in_late_binary_op = true;
ret = convert_and_check (type, orig_rhs);
- if (codel == BOOLEAN_TYPE)
+ if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE)
in_late_binary_op = save;
return ret;
}
if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
& ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
{
- /* Types differing only by the presence of the 'volatile'
- qualifier are acceptable if the 'volatile' has been added
- in by the Objective-C EH machinery. */
- if (!objc_type_quals_match (ttl, ttr))
- WARN_FOR_QUALIFIERS (location, 0,
- G_("passing argument %d of %qE discards "
- "%qv qualifier from pointer target type"),
- G_("assignment discards %qv qualifier "
- "from pointer target type"),
- G_("initialization discards %qv qualifier "
- "from pointer target type"),
- G_("return discards %qv qualifier from "
- "pointer target type"),
- TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+ WARN_FOR_QUALIFIERS (location, 0,
+ G_("passing argument %d of %qE discards "
+ "%qv qualifier from pointer target type"),
+ G_("assignment discards %qv qualifier "
+ "from pointer target type"),
+ G_("initialization discards %qv qualifier "
+ "from pointer target type"),
+ G_("return discards %qv qualifier from "
+ "pointer target type"),
+ TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
}
/* If this is not a case of ignoring a mismatch in signedness,
no warning. */
/* For int foo[] = (int [3]){1}; we need to set array size
now since later on array initializer will be just the
brace enclosed list of the compound literal. */
+ tree etype = strip_array_types (TREE_TYPE (decl));
type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
- TREE_TYPE (decl) = type;
TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (cldecl));
layout_type (type);
layout_decl (cldecl, 0);
+ TREE_TYPE (decl)
+ = c_build_qualified_type (type, TYPE_QUALS (etype));
}
}
}
pedwarn_init (location_t location, int opt, const char *gmsgid)
{
char *ofwhat;
-
+
/* The gmsgid may be a format string with %< and %>. */
pedwarn (location, opt, gmsgid);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
{
/* Vectors are like simple fixed-size arrays. */
constructor_max_index =
- build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
+ bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
constructor_index = bitsize_zero_node;
constructor_unfilled_index = constructor_index;
}
{
/* Vectors are like simple fixed-size arrays. */
constructor_max_index =
- build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
- constructor_index = convert (bitsizetype, integer_zero_node);
+ bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
+ constructor_index = bitsize_int (0);
constructor_unfilled_index = constructor_index;
}
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
&& TREE_CODE (constructor_type) == RECORD_TYPE
&& constructor_unfilled_fields)
{
+ bool constructor_zeroinit =
+ (VEC_length (constructor_elt, constructor_elements) == 1
+ && integer_zerop
+ (VEC_index (constructor_elt, constructor_elements, 0)->value));
+
/* Do not warn for flexible array members or zero-length arrays. */
while (constructor_unfilled_fields
&& (!DECL_SIZE (constructor_unfilled_fields)
|| integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
constructor_unfilled_fields = DECL_CHAIN (constructor_unfilled_fields);
- /* Do not warn if this level of the initializer uses member
- designators; it is likely to be deliberate. */
- if (constructor_unfilled_fields && !constructor_designated)
+ if (constructor_unfilled_fields
+ /* Do not warn if this level of the initializer uses member
+ designators; it is likely to be deliberate. */
+ && !constructor_designated
+ /* Do not warn about initializing with ` = {0}'. */
+ && !constructor_zeroinit)
{
push_member_name (constructor_unfilled_fields);
warning_init (OPT_Wmissing_field_initializers,
get an error. Gross, but ... */
STRIP_NOPS (output);
- if (!lvalue_or_else (output, lv_asm))
+ if (!lvalue_or_else (loc, output, lv_asm))
output = error_mark_node;
if (output != error_mark_node
mark it addressable. */
if (!allows_reg && !c_mark_addressable (output))
output = error_mark_node;
+ if (!(!allows_reg && allows_mem)
+ && output != error_mark_node
+ && VOID_TYPE_P (TREE_TYPE (output)))
+ {
+ error_at (loc, "invalid use of void expression");
+ output = error_mark_node;
+ }
}
else
output = error_mark_node;
STRIP_NOPS (input);
if (!c_mark_addressable (input))
input = error_mark_node;
- }
+ }
+ else if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input)))
+ {
+ error_at (loc, "invalid use of void expression");
+ input = error_mark_node;
+ }
}
else
input = error_mark_node;
exprv = expr;
while (TREE_CODE (exprv) == COMPOUND_EXPR)
exprv = TREE_OPERAND (exprv, 1);
- if (DECL_P (exprv) || handled_component_p (exprv))
+ while (CONVERT_EXPR_P (exprv))
+ exprv = TREE_OPERAND (exprv, 0);
+ if (DECL_P (exprv)
+ || handled_component_p (exprv)
+ || TREE_CODE (exprv) == ADDR_EXPR)
mark_exp_read (exprv);
/* If the expression is not of a type to which we cannot assign a line
do the wrong thing for ({ { 1; } }) or ({ 1; { } }). In particular,
STATEMENT_LISTs merge, and thus we can lose track of what statement
was really last. */
- if (cur_stmt_list
+ if (building_stmt_list_p ()
&& STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
&& TREE_CODE (stmt) != BIND_EXPR)
{
TREE_OPERAND (stmt, 0) = list;
STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
}
+
+/* Convert scalar to vector for the range of operations. */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+ tree type0 = TREE_TYPE (op0);
+ tree type1 = TREE_TYPE (op1);
+ bool integer_only_op = false;
+ enum stv_conv ret = stv_firstarg;
+
+ gcc_assert (TREE_CODE (type0) == VECTOR_TYPE
+ || TREE_CODE (type1) == VECTOR_TYPE);
+ switch (code)
+ {
+ case RSHIFT_EXPR:
+ case LSHIFT_EXPR:
+ if (TREE_CODE (type0) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+ {
+ if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+ {
+ error_at (loc, "conversion of scalar to vector "
+ "involves truncation");
+ return stv_error;
+ }
+ else
+ return stv_firstarg;
+ }
+ break;
+
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ integer_only_op = true;
+ /* ... fall through ... */
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ case RDIV_EXPR:
+ if (TREE_CODE (type0) == VECTOR_TYPE)
+ {
+ tree tmp;
+ ret = stv_secondarg;
+ /* Swap TYPE0 with TYPE1 and OP0 with OP1 */
+ tmp = type0; type0 = type1; type1 = tmp;
+ tmp = op0; op0 = op1; op1 = tmp;
+ }
+
+ if (TREE_CODE (type0) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+ {
+ if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+ {
+ error_at (loc, "conversion of scalar to vector "
+ "involves truncation");
+ return stv_error;
+ }
+ return ret;
+ }
+ else if (!integer_only_op
+ /* Allow integer --> real conversion if safe. */
+ && (TREE_CODE (type0) == REAL_TYPE
+ || TREE_CODE (type0) == INTEGER_TYPE)
+ && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+ {
+ if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+ {
+ error_at (loc, "conversion of scalar to vector "
+ "involves truncation");
+ return stv_error;
+ }
+ return ret;
+ }
+ default:
+ break;
+ }
+
+ return stv_nothing;
+}
\f
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
else
int_const = int_const_or_overflow = false;
- if (convert_p)
+ /* Do not apply default conversion in mixed vector/scalar expression. */
+ if (convert_p
+ && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE)
+ != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
{
op0 = default_conversion (op0);
op1 = default_conversion (op1);
objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
+ /* In case when one of the operands of the binary operation is
+ a vector and another is a scalar -- convert scalar to vector. */
+ if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+ {
+ enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+
+ switch (convert_flag)
+ {
+ case stv_error:
+ return error_mark_node;
+ case stv_firstarg:
+ {
+ bool maybe_const = true;
+ tree sc;
+ sc = c_fully_fold (op0, false, &maybe_const);
+ sc = save_expr (sc);
+ sc = convert (TREE_TYPE (type1), sc);
+ op0 = build_vector_from_val (type1, sc);
+ if (!maybe_const)
+ op0 = c_wrap_maybe_const (op0, true);
+ orig_type0 = type0 = TREE_TYPE (op0);
+ code0 = TREE_CODE (type0);
+ converted = 1;
+ break;
+ }
+ case stv_secondarg:
+ {
+ bool maybe_const = true;
+ tree sc;
+ sc = c_fully_fold (op1, false, &maybe_const);
+ sc = save_expr (sc);
+ sc = convert (TREE_TYPE (type0), sc);
+ op1 = build_vector_from_val (type0, sc);
+ if (!maybe_const)
+ op0 = c_wrap_maybe_const (op1, true);
+ orig_type1 = type1 = TREE_TYPE (op1);
+ code1 = TREE_CODE (type1);
+ converted = 1;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
switch (code)
{
case PLUS_EXPR:
case EQ_EXPR:
case NE_EXPR:
+ if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+ {
+ tree intt;
+ if (TREE_TYPE (type0) != TREE_TYPE (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "element types");
+ return error_mark_node;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (type0) != TYPE_VECTOR_SUBPARTS (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "number of elements");
+ return error_mark_node;
+ }
+
+ /* Always construct signed integer vector type. */
+ intt = c_common_type_for_size (GET_MODE_BITSIZE
+ (TYPE_MODE (TREE_TYPE (type0))), 0);
+ result_type = build_opaque_vector_type (intt,
+ TYPE_VECTOR_SUBPARTS (type0));
+ converted = 1;
+ break;
+ }
if (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1))
warning_at (location,
OPT_Wfloat_equal,
{
if (code == EQ_EXPR)
warning_at (location,
- OPT_Waddress,
+ OPT_Waddress,
"the comparison will always evaluate as %<false%> "
"for the address of %qD will never be NULL",
TREE_OPERAND (op1, 0));
case GE_EXPR:
case LT_EXPR:
case GT_EXPR:
+ if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+ {
+ tree intt;
+ if (TREE_TYPE (type0) != TREE_TYPE (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "element types");
+ return error_mark_node;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (type0) != TYPE_VECTOR_SUBPARTS (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "number of elements");
+ return error_mark_node;
+ }
+
+ /* Always construct signed integer vector type. */
+ intt = c_common_type_for_size (GET_MODE_BITSIZE
+ (TYPE_MODE (TREE_TYPE (type0))), 0);
+ result_type = build_opaque_vector_type (intt,
+ TYPE_VECTOR_SUBPARTS (type0));
+ converted = 1;
+ break;
+ }
build_type = integer_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == FIXED_POINT_TYPE)
{
case MULT_EXPR:
case TRUNC_DIV_EXPR:
+ op1 = c_save_expr (op1);
imag = build2 (resultcode, real_type, imag, op1);
/* Fall through. */
case PLUS_EXPR:
switch (code)
{
case MULT_EXPR:
+ op0 = c_save_expr (op0);
imag = build2 (resultcode, real_type, op0, imag);
/* Fall through. */
case PLUS_EXPR:
warn_for_sign_compare (location, orig_op0_folded,
orig_op1_folded, op0, op1,
result_type, resultcode);
- if (!in_late_binary_op)
+ if (!in_late_binary_op && !int_operands)
{
if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST)
op0 = c_wrap_maybe_const (op0, !op0_maybe_const);
error_at (location, "used union type value where scalar is required");
return error_mark_node;
+ case VOID_TYPE:
+ error_at (location, "void value not ignored as it ought to be");
+ return error_mark_node;
+
case FUNCTION_TYPE:
gcc_unreachable ();
+ case VECTOR_TYPE:
+ error_at (location, "used vector type where scalar is required");
+ return error_mark_node;
+
default:
break;
}
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? */
+ /* ??? Should we also give an error for vectors rather than leaving
+ those to give errors later? */
expr = c_common_truthvalue_conversion (location, expr);
if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const)
case PLUS_EXPR:
case MULT_EXPR:
case MINUS_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
break;
case BIT_AND_EXPR:
r_name = "&";
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_FINAL:
+ case OMP_CLAUSE_MERGEABLE:
pc = &OMP_CLAUSE_CHAIN (c);
continue;
case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
break;
case OMP_CLAUSE_DEFAULT_SHARED:
+ /* const vars may be specified in firstprivate clause. */
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+ && TREE_READONLY (t))
+ break;
share_name = "shared";
break;
case OMP_CLAUSE_DEFAULT_PRIVATE:
return clauses;
}
+/* Create a transaction node. */
+
+tree
+c_finish_transaction (location_t loc, tree block, int flags)
+{
+ tree stmt = build_stmt (loc, TRANSACTION_EXPR, block);
+ if (flags & TM_STMT_ATTR_OUTER)
+ TRANSACTION_EXPR_OUTER (stmt) = 1;
+ if (flags & TM_STMT_ATTR_RELAXED)
+ TRANSACTION_EXPR_RELAXED (stmt) = 1;
+ return add_stmt (stmt);
+}
+
/* Make a variant type in the proper way for C/C++, propagating qualifiers
down to the element type of an array. */