summaryrefslogtreecommitdiff
path: root/gcc/c-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r--gcc/c-common.c851
1 files changed, 703 insertions, 148 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c
index e93d2fba6df..8bac9cb4f03 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "real.h"
#include "cgraph.h"
#include "target-def.h"
+#include "gimple.h"
#include "fixed-value.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -341,10 +342,6 @@ int flag_isoc99;
int flag_hosted = 1;
-/* Warn if main is suspicious. */
-
-int warn_main;
-
/* ObjC language option variables. */
@@ -574,6 +571,8 @@ static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
+static tree handle_option_attribute (tree *, tree, tree, int, bool *);
+static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
static void check_function_nonnull (tree, int, tree *);
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -595,7 +594,7 @@ static int resort_field_decl_cmp (const void *, const void *);
If -fno-asm is used, D_ASM is added to the mask. If
-fno-gnu-keywords is used, D_EXT is added. If -fno-asm and C in
C89 mode, D_EXT89 is added for both -fno-asm and -fno-gnu-keywords.
- In C with -Wcxx-compat, we warn if D_CXXWARN is set. */
+ In C with -Wc++-compat, we warn if D_CXXWARN is set. */
const struct c_common_resword c_common_reswords[] =
{
@@ -662,44 +661,44 @@ const struct c_common_resword c_common_reswords[] =
{ "__volatile__", RID_VOLATILE, 0 },
{ "asm", RID_ASM, D_ASM },
{ "auto", RID_AUTO, 0 },
- { "bool", RID_BOOL, D_CXXONLY },
+ { "bool", RID_BOOL, D_CXXONLY | D_CXXWARN },
{ "break", RID_BREAK, 0 },
{ "case", RID_CASE, 0 },
- { "catch", RID_CATCH, D_CXX_OBJC },
+ { "catch", RID_CATCH, D_CXX_OBJC | D_CXXWARN },
{ "char", RID_CHAR, 0 },
- { "char16_t", RID_CHAR16, D_CXXONLY | D_CXX0X },
- { "char32_t", RID_CHAR32, D_CXXONLY | D_CXX0X },
- { "class", RID_CLASS, D_CXX_OBJC },
+ { "char16_t", RID_CHAR16, D_CXXONLY | D_CXX0X | D_CXXWARN },
+ { "char32_t", RID_CHAR32, D_CXXONLY | D_CXX0X | D_CXXWARN },
+ { "class", RID_CLASS, D_CXX_OBJC | D_CXXWARN },
{ "const", RID_CONST, 0 },
{ "const_cast", RID_CONSTCAST, D_CXXONLY | D_CXXWARN },
{ "continue", RID_CONTINUE, 0 },
- { "decltype", RID_DECLTYPE, D_CXXONLY | D_CXX0X },
+ { "decltype", RID_DECLTYPE, D_CXXONLY | D_CXX0X | D_CXXWARN },
{ "default", RID_DEFAULT, 0 },
- { "delete", RID_DELETE, D_CXXONLY },
+ { "delete", RID_DELETE, D_CXXONLY | D_CXXWARN },
{ "do", RID_DO, 0 },
{ "double", RID_DOUBLE, 0 },
{ "dynamic_cast", RID_DYNCAST, D_CXXONLY | D_CXXWARN },
{ "else", RID_ELSE, 0 },
{ "enum", RID_ENUM, 0 },
- { "explicit", RID_EXPLICIT, D_CXXONLY },
- { "export", RID_EXPORT, D_CXXONLY },
+ { "explicit", RID_EXPLICIT, D_CXXONLY | D_CXXWARN },
+ { "export", RID_EXPORT, D_CXXONLY | D_CXXWARN },
{ "extern", RID_EXTERN, 0 },
- { "false", RID_FALSE, D_CXXONLY },
+ { "false", RID_FALSE, D_CXXONLY | D_CXXWARN },
{ "float", RID_FLOAT, 0 },
{ "for", RID_FOR, 0 },
- { "friend", RID_FRIEND, D_CXXONLY },
+ { "friend", RID_FRIEND, D_CXXONLY | D_CXXWARN },
{ "goto", RID_GOTO, 0 },
{ "if", RID_IF, 0 },
{ "inline", RID_INLINE, D_EXT89 },
{ "int", RID_INT, 0 },
{ "long", RID_LONG, 0 },
{ "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN },
- { "namespace", RID_NAMESPACE, D_CXXONLY },
- { "new", RID_NEW, D_CXXONLY },
- { "operator", RID_OPERATOR, D_CXXONLY },
- { "private", RID_PRIVATE, D_CXX_OBJC },
- { "protected", RID_PROTECTED, D_CXX_OBJC },
- { "public", RID_PUBLIC, D_CXX_OBJC },
+ { "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN },
+ { "new", RID_NEW, D_CXXONLY | D_CXXWARN },
+ { "operator", RID_OPERATOR, D_CXXONLY | D_CXXWARN },
+ { "private", RID_PRIVATE, D_CXX_OBJC | D_CXXWARN },
+ { "protected", RID_PROTECTED, D_CXX_OBJC | D_CXXWARN },
+ { "public", RID_PUBLIC, D_CXX_OBJC | D_CXXWARN },
{ "register", RID_REGISTER, 0 },
{ "reinterpret_cast", RID_REINTCAST, D_CXXONLY | D_CXXWARN },
{ "restrict", RID_RESTRICT, D_CONLY | D_C99 },
@@ -712,19 +711,19 @@ const struct c_common_resword c_common_reswords[] =
{ "static_cast", RID_STATCAST, D_CXXONLY | D_CXXWARN },
{ "struct", RID_STRUCT, 0 },
{ "switch", RID_SWITCH, 0 },
- { "template", RID_TEMPLATE, D_CXXONLY },
- { "this", RID_THIS, D_CXXONLY },
- { "throw", RID_THROW, D_CXX_OBJC },
- { "true", RID_TRUE, D_CXXONLY },
- { "try", RID_TRY, D_CXX_OBJC },
+ { "template", RID_TEMPLATE, D_CXXONLY | D_CXXWARN },
+ { "this", RID_THIS, D_CXXONLY | D_CXXWARN },
+ { "throw", RID_THROW, D_CXX_OBJC | D_CXXWARN },
+ { "true", RID_TRUE, D_CXXONLY | D_CXXWARN },
+ { "try", RID_TRY, D_CXX_OBJC | D_CXXWARN },
{ "typedef", RID_TYPEDEF, 0 },
- { "typename", RID_TYPENAME, D_CXXONLY },
- { "typeid", RID_TYPEID, D_CXXONLY },
+ { "typename", RID_TYPENAME, D_CXXONLY | D_CXXWARN },
+ { "typeid", RID_TYPEID, D_CXXONLY | D_CXXWARN },
{ "typeof", RID_TYPEOF, D_ASM | D_EXT },
{ "union", RID_UNION, 0 },
{ "unsigned", RID_UNSIGNED, 0 },
- { "using", RID_USING, D_CXXONLY },
- { "virtual", RID_VIRTUAL, D_CXXONLY },
+ { "using", RID_USING, D_CXXONLY | D_CXXWARN },
+ { "virtual", RID_VIRTUAL, D_CXXONLY | D_CXXWARN },
{ "void", RID_VOID, 0 },
{ "volatile", RID_VOLATILE, 0 },
{ "wchar_t", RID_WCHAR, D_CXXONLY },
@@ -857,6 +856,10 @@ const struct attribute_spec c_common_attribute_table[] =
handle_error_attribute },
{ "error", 1, 1, true, false, false,
handle_error_attribute },
+ { "option", 1, -1, true, false, false,
+ handle_option_attribute },
+ { "optimize", 1, -1, true, false, false,
+ handle_optimize_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
@@ -1041,7 +1044,7 @@ fname_decl (unsigned int rid, tree id)
input_location = saved_location;
}
if (!ix && !current_function_decl)
- pedwarn ("%qD is not defined outside of function scope", decl);
+ pedwarn (0, "%qD is not defined outside of function scope", decl);
return decl;
}
@@ -1090,7 +1093,8 @@ fix_string_type (tree value)
separate the %d from the 'C'. 'ISO' should not be
translated, but it may be moved after 'C%d' in languages
where modifiers follow nouns. */
- pedwarn ("string length %qd is greater than the length %qd "
+ pedwarn (OPT_Woverlength_strings,
+ "string length %qd is greater than the length %qd "
"ISO C%d compilers are required to support",
nchars - 1, nchars_max, relevant_std);
}
@@ -1137,7 +1141,7 @@ constant_expression_warning (tree value)
|| TREE_CODE (value) == VECTOR_CST
|| TREE_CODE (value) == COMPLEX_CST)
&& TREE_OVERFLOW (value))
- pedwarn ("overflow in constant expression");
+ pedwarn (OPT_Woverflow, "overflow in constant expression");
}
/* The same as above but print an unconditional error. */
@@ -1355,7 +1359,8 @@ check_main_parameter_types (tree decl)
{
case 1:
if (TYPE_MAIN_VARIANT (type) != integer_type_node)
- pedwarn ("first argument of %q+D should be %<int%>", decl);
+ pedwarn (OPT_Wmain, "first argument of %q+D should be %<int%>",
+ decl);
break;
case 2:
@@ -1363,8 +1368,8 @@ check_main_parameter_types (tree decl)
|| TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
!= char_type_node))
- pedwarn ("second argument of %q+D should be %<char **%>",
- decl);
+ pedwarn (OPT_Wmain, "second argument of %q+D should be %<char **%>",
+ decl);
break;
case 3:
@@ -1372,8 +1377,8 @@ check_main_parameter_types (tree decl)
|| TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
!= char_type_node))
- pedwarn ("third argument of %q+D should probably be "
- "%<char **%>", decl);
+ pedwarn (OPT_Wmain, "third argument of %q+D should probably be "
+ "%<char **%>", decl);
break;
}
}
@@ -1382,7 +1387,7 @@ check_main_parameter_types (tree decl)
argument because it's only mentioned in an appendix of the
standard. */
if (argct > 0 && (argct < 2 || argct > 3))
- pedwarn ("%q+D takes only zero or two arguments", decl);
+ pedwarn (OPT_Wmain, "%q+D takes only zero or two arguments", decl);
}
/* True if pointers to distinct types T1 and T2 can be converted to
@@ -1439,6 +1444,110 @@ vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note)
return false;
}
+/* This is a helper function of build_binary_op.
+
+ For certain operations if both args were extended from the same
+ smaller type, do the arithmetic in that type and then extend.
+
+ BITWISE indicates a bitwise operation.
+ For them, this optimization is safe only if
+ both args are zero-extended or both are sign-extended.
+ Otherwise, we might change the result.
+ Eg, (short)-1 | (unsigned short)-1 is (int)-1
+ but calculated in (unsigned short) it would be (unsigned short)-1.
+*/
+tree shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
+{
+ int unsigned0, unsigned1;
+ tree arg0, arg1;
+ int uns;
+ tree type;
+
+ /* Cast OP0 and OP1 to RESULT_TYPE. Doing so prevents
+ excessive narrowing when we call get_narrower below. For
+ example, suppose that OP0 is of unsigned int extended
+ from signed char and that RESULT_TYPE is long long int.
+ If we explicitly cast OP0 to RESULT_TYPE, OP0 would look
+ like
+
+ (long long int) (unsigned int) signed_char
+
+ which get_narrower would narrow down to
+
+ (unsigned int) signed char
+
+ If we do not cast OP0 first, get_narrower would return
+ signed_char, which is inconsistent with the case of the
+ explicit cast. */
+ op0 = convert (result_type, op0);
+ op1 = convert (result_type, op1);
+
+ arg0 = get_narrower (op0, &unsigned0);
+ arg1 = get_narrower (op1, &unsigned1);
+
+ /* UNS is 1 if the operation to be done is an unsigned one. */
+ uns = TYPE_UNSIGNED (result_type);
+
+ /* Handle the case that OP0 (or OP1) does not *contain* a conversion
+ but it *requires* conversion to FINAL_TYPE. */
+
+ if ((TYPE_PRECISION (TREE_TYPE (op0))
+ == TYPE_PRECISION (TREE_TYPE (arg0)))
+ && TREE_TYPE (op0) != result_type)
+ unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0));
+ if ((TYPE_PRECISION (TREE_TYPE (op1))
+ == TYPE_PRECISION (TREE_TYPE (arg1)))
+ && TREE_TYPE (op1) != result_type)
+ unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1));
+
+ /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */
+
+ /* For bitwise operations, signedness of nominal type
+ does not matter. Consider only how operands were extended. */
+ if (bitwise)
+ uns = unsigned0;
+
+ /* Note that in all three cases below we refrain from optimizing
+ an unsigned operation on sign-extended args.
+ That would not be valid. */
+
+ /* Both args variable: if both extended in same way
+ from same width, do it in that width.
+ Do it unsigned if args were zero-extended. */
+ if ((TYPE_PRECISION (TREE_TYPE (arg0))
+ < TYPE_PRECISION (result_type))
+ && (TYPE_PRECISION (TREE_TYPE (arg1))
+ == TYPE_PRECISION (TREE_TYPE (arg0)))
+ && unsigned0 == unsigned1
+ && (unsigned0 || !uns))
+ return c_common_signed_or_unsigned_type
+ (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+
+ else if (TREE_CODE (arg0) == INTEGER_CST
+ && (unsigned1 || !uns)
+ && (TYPE_PRECISION (TREE_TYPE (arg1))
+ < TYPE_PRECISION (result_type))
+ && (type
+ = c_common_signed_or_unsigned_type (unsigned1,
+ TREE_TYPE (arg1)))
+ && !POINTER_TYPE_P (type)
+ && int_fits_type_p (arg0, type))
+ return type;
+
+ else if (TREE_CODE (arg1) == INTEGER_CST
+ && (unsigned0 || !uns)
+ && (TYPE_PRECISION (TREE_TYPE (arg0))
+ < TYPE_PRECISION (result_type))
+ && (type
+ = c_common_signed_or_unsigned_type (unsigned0,
+ TREE_TYPE (arg0)))
+ && !POINTER_TYPE_P (type)
+ && int_fits_type_p (arg1, type))
+ return type;
+
+ return result_type;
+}
+
/* Warns if the conversion of EXPR to TYPE may alter a value.
This is a helper function for warnings_for_convert_and_check. */
@@ -1447,39 +1556,63 @@ conversion_warning (tree type, tree expr)
{
bool give_warning = false;
- unsigned int formal_prec = TYPE_PRECISION (type);
+ tree expr_type = TREE_TYPE (expr);
if (!warn_conversion && !warn_sign_conversion)
return;
- if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
+ switch (TREE_CODE (expr))
{
+ case EQ_EXPR:
+ case NE_EXPR:
+ case LE_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case GT_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ case TRUTH_NOT_EXPR:
+ /* Conversion from boolean to a signed:1 bit-field (which only
+ can hold the values 0 and -1) doesn't lose information - but
+ it does change the value. */
+ if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+ warning (OPT_Wconversion,
+ "conversion to %qT from boolean expression", type);
+ return;
+
+ case REAL_CST:
+ case INTEGER_CST:
+
/* Warn for real constant that is not an exact integer converted
to integer type. */
- if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+ if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == INTEGER_TYPE)
{
- if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (TREE_TYPE (expr))))
+ if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
give_warning = true;
}
/* Warn for an integer constant that does not fit into integer type. */
- else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+ else if (TREE_CODE (expr_type) == INTEGER_TYPE
&& TREE_CODE (type) == INTEGER_TYPE
&& !int_fits_type_p (expr, type))
{
- if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr)))
+ if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
+ && tree_int_cst_sgn (expr) < 0)
warning (OPT_Wsign_conversion,
"negative integer implicitly converted to unsigned type");
- else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (TREE_TYPE (expr)))
- warning (OPT_Wsign_conversion,
- "conversion of unsigned constant value to negative integer");
+ else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
+ warning (OPT_Wsign_conversion, "conversion of unsigned constant "
+ "value to negative integer");
else
give_warning = true;
}
else if (TREE_CODE (type) == REAL_TYPE)
{
/* Warn for an integer constant that does not fit into real type. */
- if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE)
+ if (TREE_CODE (expr_type) == INTEGER_TYPE)
{
REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
if (!exact_real_truncate (TYPE_MODE (type), &a))
@@ -1487,8 +1620,8 @@ conversion_warning (tree type, tree expr)
}
/* Warn for a real constant that does not fit into a smaller
real type. */
- else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
- && formal_prec < TYPE_PRECISION (TREE_TYPE (expr)))
+ else if (TREE_CODE (expr_type) == REAL_TYPE
+ && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
{
REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
if (!exact_real_truncate (TYPE_MODE (type), &a))
@@ -1499,48 +1632,102 @@ conversion_warning (tree type, tree expr)
if (give_warning)
warning (OPT_Wconversion,
"conversion to %qT alters %qT constant value",
- type, TREE_TYPE (expr));
- }
- else /* 'expr' is not a constant. */
- {
+ type, expr_type);
+
+ return;
+
+ case COND_EXPR:
+ {
+ /* In case of COND_EXPR, if both operands are constants or
+ COND_EXPR, then we do not care about the type of COND_EXPR,
+ only about the conversion of each operand. */
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree op2 = TREE_OPERAND (expr, 2);
+
+ if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
+ || TREE_CODE (op1) == COND_EXPR)
+ && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
+ || TREE_CODE (op2) == COND_EXPR))
+ {
+ conversion_warning (type, op1);
+ conversion_warning (type, op2);
+ return;
+ }
+ /* Fall through. */
+ }
+
+ default: /* 'expr' is not a constant. */
+
/* Warn for real types converted to integer types. */
- if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+ if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == INTEGER_TYPE)
give_warning = true;
- else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+ else if (TREE_CODE (expr_type) == INTEGER_TYPE
&& TREE_CODE (type) == INTEGER_TYPE)
{
/* Don't warn about unsigned char y = 0xff, x = (int) y; */
expr = get_unwidened (expr, 0);
+ expr_type = TREE_TYPE (expr);
+ /* Don't warn for short y; short x = ((int)y & 0xff); */
+ if (TREE_CODE (expr) == BIT_AND_EXPR
+ || TREE_CODE (expr) == BIT_IOR_EXPR
+ || TREE_CODE (expr) == BIT_XOR_EXPR)
+ {
+ /* If both args were extended from a shortest type,
+ use that type if that is safe. */
+ expr_type = shorten_binary_op (expr_type,
+ TREE_OPERAND (expr, 0),
+ TREE_OPERAND (expr, 1),
+ /* bitwise */1);
+
+ /* If one of the operands is a non-negative constant
+ that fits in the target type, then the type of the
+ other operand does not matter. */
+ if (TREE_CODE (expr) == BIT_AND_EXPR)
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ if ((TREE_CODE (op0) == INTEGER_CST
+ && int_fits_type_p (op0, c_common_signed_type (type))
+ && int_fits_type_p (op0, c_common_unsigned_type (type)))
+ || (TREE_CODE (op1) == INTEGER_CST
+ && int_fits_type_p (op1, c_common_signed_type (type))
+ && int_fits_type_p (op1,
+ c_common_unsigned_type (type))))
+ return;
+ }
+ }
/* Warn for integer types converted to smaller integer types. */
- if (formal_prec < TYPE_PRECISION (TREE_TYPE (expr)))
+ if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
give_warning = true;
/* When they are the same width but different signedness,
then the value may change. */
- else if ((formal_prec == TYPE_PRECISION (TREE_TYPE (expr))
- && TYPE_UNSIGNED (TREE_TYPE (expr)) != TYPE_UNSIGNED (type))
+ else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
+ && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
/* Even when converted to a bigger type, if the type is
unsigned but expr is signed, then negative values
will be changed. */
- || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr))))
- warning (OPT_Wsign_conversion,
- "conversion to %qT from %qT may change the sign of the result",
- type, TREE_TYPE (expr));
+ || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+ warning (OPT_Wsign_conversion, "conversion to %qT from %qT "
+ "may change the sign of the result",
+ type, expr_type);
}
/* Warn for integer types converted to real types if and only if
all the range of values of the integer type cannot be
represented by the real type. */
- else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+ else if (TREE_CODE (expr_type) == INTEGER_TYPE
&& TREE_CODE (type) == REAL_TYPE)
{
- tree type_low_bound = TYPE_MIN_VALUE (TREE_TYPE (expr));
- tree type_high_bound = TYPE_MAX_VALUE (TREE_TYPE (expr));
- REAL_VALUE_TYPE real_low_bound = real_value_from_int_cst (0, type_low_bound);
- REAL_VALUE_TYPE real_high_bound = real_value_from_int_cst (0, type_high_bound);
+ tree type_low_bound = TYPE_MIN_VALUE (expr_type);
+ tree type_high_bound = TYPE_MAX_VALUE (expr_type);
+ REAL_VALUE_TYPE real_low_bound
+ = real_value_from_int_cst (0, type_low_bound);
+ REAL_VALUE_TYPE real_high_bound
+ = real_value_from_int_cst (0, type_high_bound);
if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
|| !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
@@ -1548,16 +1735,16 @@ conversion_warning (tree type, tree expr)
}
/* Warn for real types converted to smaller real types. */
- else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+ else if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == REAL_TYPE
- && formal_prec < TYPE_PRECISION (TREE_TYPE (expr)))
+ && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
give_warning = true;
if (give_warning)
warning (OPT_Wconversion,
"conversion to %qT from %qT may alter its value",
- type, TREE_TYPE (expr));
+ type, expr_type);
}
}
@@ -1759,8 +1946,10 @@ warn_for_collisions_1 (tree written, tree writer, struct tlist *list,
&& DECL_NAME (list->expr))
{
warned_ids = new_tlist (warned_ids, written, NULL_TREE);
- warning (OPT_Wsequence_point, "operation on %qE may be undefined",
- list->expr);
+ warning_at (EXPR_HAS_LOCATION (writer)
+ ? EXPR_LOCATION (writer) : input_location,
+ OPT_Wsequence_point, "operation on %qE may be undefined",
+ list->expr);
}
list = list->next;
}
@@ -3073,20 +3262,20 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
{
- if (pedantic || warn_pointer_arith)
- pedwarn ("pointer of type %<void *%> used in arithmetic");
+ pedwarn (pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "pointer of type %<void *%> used in arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
{
- if (pedantic || warn_pointer_arith)
- pedwarn ("pointer to a function used in arithmetic");
+ pedwarn (pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "pointer to a function used in arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
{
- if (pedantic || warn_pointer_arith)
- pedwarn ("pointer to member function used in arithmetic");
+ pedwarn (pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "pointer to member function used in arithmetic");
size_exp = integer_one_node;
}
else
@@ -3594,7 +3783,8 @@ c_sizeof_or_alignof_type (tree type, bool is_sizeof, int complain)
if (is_sizeof)
{
if (complain && (pedantic || warn_pointer_arith))
- pedwarn ("invalid application of %<sizeof%> to a function type");
+ pedwarn (pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "invalid application of %<sizeof%> to a function type");
else if (!complain)
return error_mark_node;
value = size_one_node;
@@ -3606,7 +3796,8 @@ c_sizeof_or_alignof_type (tree type, bool is_sizeof, int complain)
{
if (type_code == VOID_TYPE
&& complain && (pedantic || warn_pointer_arith))
- pedwarn ("invalid application of %qs to a void type", op_name);
+ pedwarn (pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "invalid application of %qs to a void type", op_name);
else if (!complain)
return error_mark_node;
value = size_one_node;
@@ -4472,8 +4663,9 @@ c_add_case_label (splay_tree cases, tree cond, tree orig_type,
}
/* Case ranges are a GNU extension. */
- if (high_value && pedantic)
- pedwarn ("range expressions in switch statements are non-standard");
+ if (high_value)
+ pedwarn (OPT_pedantic,
+ "range expressions in switch statements are non-standard");
type = TREE_TYPE (cond);
if (low_value)
@@ -4786,8 +4978,7 @@ finish_label_address_expr (tree label)
{
tree result;
- if (pedantic)
- pedwarn ("taking the address of a label is non-standard");
+ pedwarn (OPT_pedantic, "taking the address of a label is non-standard");
if (label == error_mark_node)
return error_mark_node;
@@ -4895,6 +5086,8 @@ c_stddef_cpp_builtins(void)
builtin_define_with_value ("__WINT_TYPE__", WINT_TYPE, 0);
builtin_define_with_value ("__INTMAX_TYPE__", INTMAX_TYPE, 0);
builtin_define_with_value ("__UINTMAX_TYPE__", UINTMAX_TYPE, 0);
+ builtin_define_with_value ("__CHAR16_TYPE__", CHAR16_TYPE, 0);
+ builtin_define_with_value ("__CHAR32_TYPE__", CHAR32_TYPE, 0);
}
static void
@@ -5025,7 +5218,7 @@ handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args),
static tree
handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
- int ARG_UNUSED (flags), bool *no_add_attrs)
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
{
@@ -5035,8 +5228,34 @@ handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
name, "cold");
*no_add_attrs = true;
}
- /* Do nothing else, just set the attribute. We'll get at
- it later with lookup_attribute. */
+ else
+ {
+ tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+ /* If we are not at -O3, but are optimizing, turn on -O3
+ optimizations just for this one function. */
+ if (((optimize > 0 && optimize < 3) || optimize_size)
+ && targetm.target_option.hot_attribute_sets_optimization
+ && (!old_opts || old_opts == optimization_default_node))
+ {
+ /* Create the hot optimization node if needed. */
+ if (!optimization_hot_node)
+ {
+ struct cl_optimization current_options;
+ static const char *os_argv[] = { NULL, "-O3", NULL };
+
+ cl_optimization_save (&current_options);
+ decode_options (2, os_argv);
+ optimization_hot_node = build_optimization_node ();
+ cl_optimization_restore (&current_options);
+ }
+
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+ = optimization_hot_node;
+ }
+ /* Most of the rest of the hot processing is done later with
+ lookup_attribute. */
+ }
}
else
{
@@ -5061,8 +5280,34 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
name, "hot");
*no_add_attrs = true;
}
- /* Do nothing else, just set the attribute. We'll get at
- it later with lookup_attribute. */
+ else
+ {
+ tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+ /* If we are optimizing, but not optimizing for space, turn on -Os
+ optimizations just for this one function. */
+ if (optimize && !optimize_size
+ && targetm.target_option.cold_attribute_sets_optimization
+ && (!old_opts || old_opts == optimization_default_node))
+ {
+ /* Create the cold optimization node if needed. */
+ if (!optimization_cold_node)
+ {
+ struct cl_optimization current_options;
+ static const char *os_argv[] = { NULL, "-Os", NULL };
+
+ cl_optimization_save (&current_options);
+ decode_options (2, os_argv);
+ optimization_cold_node = build_optimization_node ();
+ cl_optimization_restore (&current_options);
+ }
+
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+ = optimization_cold_node;
+ }
+ /* Most of the rest of the cold processing is done later with
+ lookup_attribute. */
+ }
}
else
{
@@ -6760,6 +7005,186 @@ handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
return NULL_TREE;
}
+
+/* For handling "option" attribute. arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_option_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+ /* Ensure we have a function type. */
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else if (targetm.target_option.valid_attribute_p
+ == default_target_option_valid_attribute_p)
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute is not supported on this machine",
+ name);
+ *no_add_attrs = true;
+ }
+ else if (! targetm.target_option.valid_attribute_p (*node, name, args,
+ flags))
+ *no_add_attrs = true;
+
+ return NULL_TREE;
+}
+
+/* Arguments being collected for optimization. */
+typedef const char *const_char_p; /* For DEF_VEC_P. */
+DEF_VEC_P(const_char_p);
+DEF_VEC_ALLOC_P(const_char_p, gc);
+static GTY(()) VEC(const_char_p, gc) *optimize_args;
+
+
+/* Inner function to convert a TREE_LIST to argv string to parse the optimize
+ options in ARGS. ATTR_P is true if this is for attribute(optimize), and
+ false for #pragma GCC optimize. */
+
+bool
+parse_optimize_options (tree args, bool attr_p)
+{
+ bool ret = true;
+ unsigned opt_argc;
+ unsigned i;
+ const char **opt_argv;
+ tree ap;
+
+ /* Build up argv vector. Just in case the string is stored away, use garbage
+ collected strings. */
+ VEC_truncate (const_char_p, optimize_args, 0);
+ VEC_safe_push (const_char_p, gc, optimize_args, NULL);
+
+ for (ap = args; ap != NULL_TREE; ap = TREE_CHAIN (ap))
+ {
+ tree value = TREE_VALUE (ap);
+
+ if (TREE_CODE (value) == INTEGER_CST)
+ {
+ char buffer[20];
+ sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value));
+ VEC_safe_push (const_char_p, gc, optimize_args, ggc_strdup (buffer));
+ }
+
+ else if (TREE_CODE (value) == STRING_CST)
+ {
+ /* Split string into multiple substrings. */
+ size_t len = TREE_STRING_LENGTH (value);
+ char *p = ASTRDUP (TREE_STRING_POINTER (value));
+ char *end = p + len;
+ char *comma;
+ char *next_p = p;
+
+ while (next_p != NULL)
+ {
+ size_t len2;
+ char *q, *r;
+
+ p = next_p;
+ comma = strchr (p, ',');
+ if (comma)
+ {
+ len2 = comma - p;
+ *comma = '\0';
+ next_p = comma+1;
+ }
+ else
+ {
+ len2 = end - p;
+ next_p = NULL;
+ }
+
+ r = q = (char *) ggc_alloc (len2 + 3);
+
+ /* If the user supplied -Oxxx or -fxxx, only allow -Oxxx or -fxxx
+ options. */
+ if (*p == '-' && p[1] != 'O' && p[1] != 'f')
+ {
+ ret = false;
+ if (attr_p)
+ warning (OPT_Wattributes,
+ "Bad option %s to optimize attribute.", p);
+ else
+ warning (OPT_Wpragmas,
+ "Bad option %s to pragma attribute", p);
+ continue;
+ }
+
+ if (*p != '-')
+ {
+ *r++ = '-';
+
+ /* Assume that Ox is -Ox, a numeric value is -Ox, a s by
+ itself is -Os, and any other switch begins with a -f. */
+ if ((*p >= '0' && *p <= '9')
+ || (p[0] == 's' && p[1] == '\0'))
+ *r++ = 'O';
+ else if (*p != 'O')
+ *r++ = 'f';
+ }
+
+ memcpy (r, p, len2);
+ r[len2] = '\0';
+ VEC_safe_push (const_char_p, gc, optimize_args, q);
+ }
+
+ }
+ }
+
+ opt_argc = VEC_length (const_char_p, optimize_args);
+ opt_argv = (const char **) alloca (sizeof (char *) * (opt_argc + 1));
+
+ for (i = 1; i < opt_argc; i++)
+ opt_argv[i] = VEC_index (const_char_p, optimize_args, i);
+
+ /* Now parse the options. */
+ decode_options (opt_argc, opt_argv);
+
+ VEC_truncate (const_char_p, optimize_args, 0);
+ return ret;
+}
+
+/* For handling "optimize" attribute. arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_optimize_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ /* Ensure we have a function type. */
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else
+ {
+ struct cl_optimization cur_opts;
+ tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+ /* Save current options. */
+ cl_optimization_save (&cur_opts);
+
+ /* If we previously had some optimization options, use them as the
+ default. */
+ if (old_opts)
+ cl_optimization_restore (TREE_OPTIMIZATION (old_opts));
+
+ /* Parse options, and update the vector. */
+ parse_optimize_options (args, true);
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+ = build_optimization_node ();
+
+ /* Restore current options. */
+ cl_optimization_restore (&cur_opts);
+ }
+
+ return NULL_TREE;
+}
/* Check for valid arguments being passed to a function.
ATTRS is a list of attributes. There are NARGS arguments in the array
@@ -7133,71 +7558,60 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token, tree value)
inlining, so we don't have to worry about that. */
void
-c_warn_unused_result (tree *top_p)
+c_warn_unused_result (gimple_seq seq)
{
- tree t = *top_p;
- tree_stmt_iterator i;
tree fdecl, ftype;
+ gimple_stmt_iterator i;
- switch (TREE_CODE (t))
+ for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i))
{
- case STATEMENT_LIST:
- for (i = tsi_start (*top_p); !tsi_end_p (i); tsi_next (&i))
- c_warn_unused_result (tsi_stmt_ptr (i));
- break;
+ gimple g = gsi_stmt (i);
- case COND_EXPR:
- c_warn_unused_result (&COND_EXPR_THEN (t));
- c_warn_unused_result (&COND_EXPR_ELSE (t));
- break;
- case BIND_EXPR:
- c_warn_unused_result (&BIND_EXPR_BODY (t));
- break;
- case TRY_FINALLY_EXPR:
- case TRY_CATCH_EXPR:
- c_warn_unused_result (&TREE_OPERAND (t, 0));
- c_warn_unused_result (&TREE_OPERAND (t, 1));
- break;
- case CATCH_EXPR:
- c_warn_unused_result (&CATCH_BODY (t));
- break;
- case EH_FILTER_EXPR:
- c_warn_unused_result (&EH_FILTER_FAILURE (t));
- break;
+ switch (gimple_code (g))
+ {
+ case GIMPLE_BIND:
+ c_warn_unused_result (gimple_bind_body (g));
+ break;
+ case GIMPLE_TRY:
+ c_warn_unused_result (gimple_try_eval (g));
+ c_warn_unused_result (gimple_try_cleanup (g));
+ break;
+ case GIMPLE_CATCH:
+ c_warn_unused_result (gimple_catch_handler (g));
+ break;
+ case GIMPLE_EH_FILTER:
+ c_warn_unused_result (gimple_eh_filter_failure (g));
+ break;
- case CALL_EXPR:
- if (TREE_USED (t))
- break;
+ case GIMPLE_CALL:
+ if (gimple_call_lhs (g))
+ break;
- /* This is a naked call, as opposed to a CALL_EXPR nested inside
- a MODIFY_EXPR. All calls whose value is ignored should be
- represented like this. Look for the attribute. */
- fdecl = get_callee_fndecl (t);
- if (fdecl)
- ftype = TREE_TYPE (fdecl);
- else
- {
- ftype = TREE_TYPE (CALL_EXPR_FN (t));
- /* Look past pointer-to-function to the function type itself. */
- ftype = TREE_TYPE (ftype);
- }
+ /* This is a naked call, as opposed to a GIMPLE_CALL with an
+ LHS. All calls whose value is ignored should be
+ represented like this. Look for the attribute. */
+ fdecl = gimple_call_fndecl (g);
+ ftype = TREE_TYPE (TREE_TYPE (gimple_call_fn (g)));
- if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype)))
- {
- if (fdecl)
- warning (0, "%Hignoring return value of %qD, "
- "declared with attribute warn_unused_result",
- EXPR_LOCUS (t), fdecl);
- else
- warning (0, "%Hignoring return value of function "
- "declared with attribute warn_unused_result",
- EXPR_LOCUS (t));
- }
- break;
+ if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype)))
+ {
+ location_t loc = gimple_location (g);
- default:
- /* Not a container, not a call, or a call whose value is used. */
- break;
+ if (fdecl)
+ warning (0, "%Hignoring return value of %qD, "
+ "declared with attribute warn_unused_result",
+ &loc, fdecl);
+ else
+ warning (0, "%Hignoring return value of function "
+ "declared with attribute warn_unused_result",
+ &loc);
+ }
+ break;
+
+ default:
+ /* Not a container, not a call, or a call whose value is used. */
+ break;
+ }
}
}
@@ -7827,4 +8241,145 @@ warn_for_div_by_zero (tree divisor)
warning (OPT_Wdiv_by_zero, "division by zero");
}
+/* Subroutine of build_binary_op. Give warnings for comparisons
+ between signed and unsigned quantities that may fail. Do the
+ checking based on the original operand trees ORIG_OP0 and ORIG_OP1,
+ so that casts will be considered, but default promotions won't
+ be.
+
+ The arguments of this function map directly to local variables
+ of build_binary_op. */
+
+void
+warn_for_sign_compare (tree orig_op0, tree orig_op1,
+ tree op0, tree op1,
+ tree result_type, enum tree_code resultcode)
+{
+ int op0_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op0));
+ int op1_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op1));
+ int unsignedp0, unsignedp1;
+
+ /* In C++, check for comparison of different enum types. */
+ if (c_dialect_cxx()
+ && TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE
+ && TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
+ != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
+ {
+ warning (OPT_Wsign_compare, "comparison between types %qT and %qT",
+ TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
+ }
+
+ /* Do not warn if the comparison is being done in a signed type,
+ since the signed type will only be chosen if it can represent
+ all the values of the unsigned type. */
+ if (!TYPE_UNSIGNED (result_type))
+ /* OK */;
+ /* Do not warn if both operands are unsigned. */
+ else if (op0_signed == op1_signed)
+ /* OK */;
+ else
+ {
+ tree sop, uop;
+ bool ovf;
+
+ if (op0_signed)
+ sop = orig_op0, uop = orig_op1;
+ else
+ sop = orig_op1, uop = orig_op0;
+
+ STRIP_TYPE_NOPS (sop);
+ STRIP_TYPE_NOPS (uop);
+
+ /* Do not warn if the signed quantity is an unsuffixed integer
+ literal (or some static constant expression involving such
+ literals or a conditional expression involving such literals)
+ and it is non-negative. */
+ if (tree_expr_nonnegative_warnv_p (sop, &ovf))
+ /* OK */;
+ /* Do not warn if the comparison is an equality operation, the
+ unsigned quantity is an integral constant, and it would fit
+ in the result if the result were signed. */
+ else if (TREE_CODE (uop) == INTEGER_CST
+ && (resultcode == EQ_EXPR || resultcode == NE_EXPR)
+ && int_fits_type_p (uop, c_common_signed_type (result_type)))
+ /* OK */;
+ /* In C, do not warn if the unsigned quantity is an enumeration
+ constant and its maximum value would fit in the result if the
+ result were signed. */
+ else if (!c_dialect_cxx() && TREE_CODE (uop) == INTEGER_CST
+ && TREE_CODE (TREE_TYPE (uop)) == ENUMERAL_TYPE
+ && int_fits_type_p (TYPE_MAX_VALUE (TREE_TYPE (uop)),
+ c_common_signed_type (result_type)))
+ /* OK */;
+ else
+ warning (OPT_Wsign_compare,
+ "comparison between signed and 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 result of
+ a `~' operator. This comparison will always fail.
+
+ Also warn if one operand is a constant, and the constant does not
+ have all bits set that are set in the ~ operand when it is
+ extended. */
+
+ op0 = get_narrower (op0, &unsignedp0);
+ op1 = get_narrower (op1, &unsignedp1);
+
+ if ((TREE_CODE (op0) == BIT_NOT_EXPR)
+ ^ (TREE_CODE (op1) == BIT_NOT_EXPR))
+ {
+ if (TREE_CODE (op0) == BIT_NOT_EXPR)
+ op0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
+ if (TREE_CODE (op1) == BIT_NOT_EXPR)
+ op1 = get_narrower (TREE_OPERAND (op1, 0), &unsignedp1);
+
+ if (host_integerp (op0, 0) || host_integerp (op1, 0))
+ {
+ tree primop;
+ HOST_WIDE_INT constant, mask;
+ int unsignedp;
+ unsigned int bits;
+
+ if (host_integerp (op0, 0))
+ {
+ primop = op1;
+ unsignedp = unsignedp1;
+ constant = tree_low_cst (op0, 0);
+ }
+ else
+ {
+ primop = op0;
+ unsignedp = unsignedp0;
+ constant = tree_low_cst (op1, 0);
+ }
+
+ bits = TYPE_PRECISION (TREE_TYPE (primop));
+ if (bits < TYPE_PRECISION (result_type)
+ && bits < HOST_BITS_PER_LONG && unsignedp)
+ {
+ mask = (~ (HOST_WIDE_INT) 0) << bits;
+ if ((mask & constant) != mask)
+ {
+ if (constant == 0)
+ warning (OPT_Wsign_compare,
+ "promoted ~unsigned is always non-zero");
+ else
+ warning (OPT_Wsign_compare,
+ "comparison of promoted ~unsigned with constant");
+ }
+ }
+ }
+ else if (unsignedp0 && unsignedp1
+ && (TYPE_PRECISION (TREE_TYPE (op0))
+ < TYPE_PRECISION (result_type))
+ && (TYPE_PRECISION (TREE_TYPE (op1))
+ < TYPE_PRECISION (result_type)))
+ warning (OPT_Wsign_compare,
+ "comparison of promoted ~unsigned with unsigned");
+ }
+}
+
#include "gt-c-common.h"