diff options
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 851 |
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 (¤t_options); + decode_options (2, os_argv); + optimization_hot_node = build_optimization_node (); + cl_optimization_restore (¤t_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 (¤t_options); + decode_options (2, os_argv); + optimization_cold_node = build_optimization_node (); + cl_optimization_restore (¤t_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" |