/* Subroutines shared by all languages that are variants of C.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of GCC.
#include "varray.h"
#include "expr.h"
#include "c-common.h"
-#include "diagnostic.h"
#include "tm_p.h"
#include "obstack.h"
#include "cpplib.h"
#include "tree-inline.h"
#include "c-tree.h"
#include "toplev.h"
+#include "diagnostic.h"
#include "tree-iterator.h"
#include "hashtab.h"
#include "tree-mudflap.h"
#include "real.h"
#include "cgraph.h"
#include "target-def.h"
+#include "gimple.h"
#include "fixed-value.h"
+#include "libfuncs.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
-/* We let tm.h override the types used here, to handle trivial differences
- such as the choice of unsigned int or long unsigned int for size_t.
- When machines start needing nontrivial differences in the size type,
- it would be best to do something here to figure out automatically
- from other information what type to use. */
-
-#ifndef SIZE_TYPE
-#define SIZE_TYPE "long unsigned int"
-#endif
-
-#ifndef PID_TYPE
-#define PID_TYPE "int"
-#endif
-
-#ifndef CHAR16_TYPE
-#define CHAR16_TYPE "short unsigned int"
-#endif
-
-#ifndef CHAR32_TYPE
-#define CHAR32_TYPE "unsigned int"
-#endif
-
-#ifndef WCHAR_TYPE
-#define WCHAR_TYPE "int"
-#endif
-
-/* WCHAR_TYPE gets overridden by -fshort-wchar. */
-#define MODIFIED_WCHAR_TYPE \
- (flag_short_wchar ? "short unsigned int" : WCHAR_TYPE)
-
-#ifndef PTRDIFF_TYPE
-#define PTRDIFF_TYPE "long int"
-#endif
-
-#ifndef WINT_TYPE
-#define WINT_TYPE "unsigned int"
-#endif
-
-#ifndef INTMAX_TYPE
-#define INTMAX_TYPE ((INT_TYPE_SIZE == LONG_LONG_TYPE_SIZE) \
- ? "int" \
- : ((LONG_TYPE_SIZE == LONG_LONG_TYPE_SIZE) \
- ? "long int" \
- : "long long int"))
-#endif
-
-#ifndef UINTMAX_TYPE
-#define UINTMAX_TYPE ((INT_TYPE_SIZE == LONG_LONG_TYPE_SIZE) \
- ? "unsigned int" \
- : ((LONG_TYPE_SIZE == LONG_LONG_TYPE_SIZE) \
- ? "long unsigned int" \
- : "long long unsigned int"))
-#endif
-
/* The following symbols are subsumed in the c_global_trees array, and
listed here individually for documentation purposes.
tree unsigned_char_type_node;
tree signed_char_type_node;
tree wchar_type_node;
- tree signed_wchar_type_node;
- tree unsigned_wchar_type_node;
tree char16_type_node;
tree char32_type_node;
int flag_hosted = 1;
-/* Warn if main is suspicious. */
-
-int warn_main;
-
/* ObjC language option variables. */
int flag_threadsafe_statics = 1;
+/* Nonzero if we want to pretty-print template specializations as the
+ template signature followed by the arguments. */
+
+int flag_pretty_templates = 1;
+
/* Nonzero means warn about implicit declarations. */
int warn_implicit = 1;
-/* Maximum template instantiation depth. This limit is rather
- arbitrary, but it exists to limit the time it takes to notice
- infinite template instantiations. */
+/* Maximum template instantiation depth. This limit exists to limit the
+ time it takes to notice infinite template instantiations; the default
+ value of 1024 is likely to be in the next C++ standard. */
-int max_tinst_depth = 500;
+int max_tinst_depth = 1024;
type names and storage classes. It is indexed by a RID_... value. */
tree *ridpointers;
-tree (*make_fname_decl) (tree, int);
+tree (*make_fname_decl) (location_t, tree, int);
+
+/* Nonzero means don't warn about problems that occur when the code is
+ executed. */
+int c_inhibit_evaluation_warnings;
-/* Nonzero means the expression being parsed will never be evaluated.
- This is a count, since unevaluated expressions can nest. */
-int skip_evaluation;
+/* Whether lexing has been completed, so subsequent preprocessor
+ errors should use the compiler's input_location. */
+bool done_lexing = false;
/* Information about how a function name is generated. */
struct fname_var_t
{NULL, 0, 0},
};
+static tree c_fully_fold_internal (tree expr, bool, bool *, bool *);
static tree check_case_value (tree);
static bool check_case_bounds (tree, tree, tree *, tree *);
static tree handle_hot_attribute (tree *, tree, tree, int, bool *);
static tree handle_cold_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
+static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
static tree handle_always_inline_attribute (tree *, tree, tree, int,
bool *);
static tree handle_gnu_inline_attribute (tree *, tree, tree, int, bool *);
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_target_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);
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[] =
{
{ "_Bool", RID_BOOL, D_CONLY },
{ "_Complex", RID_COMPLEX, 0 },
+ { "_Imaginary", RID_IMAGINARY, D_CONLY },
{ "_Decimal32", RID_DFLOAT32, D_CONLY | D_EXT },
{ "_Decimal64", RID_DFLOAT64, D_CONLY | D_EXT },
{ "_Decimal128", RID_DFLOAT128, D_CONLY | D_EXT },
{ "__is_enum", RID_IS_ENUM, D_CXXONLY },
{ "__is_pod", RID_IS_POD, D_CXXONLY },
{ "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY },
+ { "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY },
+ { "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY },
{ "__is_union", RID_IS_UNION, D_CXXONLY },
{ "__imag", RID_IMAGPART, 0 },
{ "__imag__", RID_IMAGPART, 0 },
{ "__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 },
{ "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 },
handle_noreturn_attribute },
{ "noinline", 0, 0, true, false, false,
handle_noinline_attribute },
+ { "noclone", 0, 0, true, false, false,
+ handle_noclone_attribute },
{ "always_inline", 0, 0, true, false, false,
handle_always_inline_attribute },
{ "gnu_inline", 0, 0, true, false, false,
to prevent its usage in source code. */
{ "no vops", 0, 0, true, false, false,
handle_novops_attribute },
- { "deprecated", 0, 0, false, false, false,
+ { "deprecated", 0, 1, false, false, false,
handle_deprecated_attribute },
{ "vector_size", 1, 1, false, true, false,
handle_vector_size_attribute },
handle_error_attribute },
{ "error", 1, 1, true, false, false,
handle_error_attribute },
+ { "target", 1, -1, true, false, false,
+ handle_target_attribute },
+ { "optimize", 1, -1, true, false, false,
+ handle_optimize_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
return namep;
}
-/* Expand DECL if it declares an entity not handled by the
- common code. */
-
-int
-c_expand_decl (tree decl)
-{
- if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
- {
- /* Let the back-end know about this variable. */
- if (!anon_aggr_type_p (TREE_TYPE (decl)))
- emit_local_var (decl);
- else
- expand_anon_union_decl (decl, NULL_TREE,
- DECL_ANON_UNION_ELEMS (decl));
- }
- else
- return 0;
-
- return 1;
-}
-
-
/* Return the VAR_DECL for a const char array naming the current
function. If the VAR_DECL has not yet been created, create it
now. RID indicates how it should be formatted and IDENTIFIER_NODE
ID is its name (unfortunately C and C++ hold the RID values of
keywords in different places, so we can't derive RID from ID in
- this language independent code. */
+ this language independent code. LOC is the location of the
+ function. */
tree
-fname_decl (unsigned int rid, tree id)
+fname_decl (location_t loc, unsigned int rid, tree id)
{
unsigned ix;
tree decl = NULL_TREE;
input_location = UNKNOWN_LOCATION;
stmts = push_stmt_list ();
- decl = (*make_fname_decl) (id, fname_vars[ix].pretty);
+ decl = (*make_fname_decl) (loc, id, fname_vars[ix].pretty);
stmts = pop_stmt_list (stmts);
if (!IS_EMPTY_STMT (stmts))
saved_function_name_decls
input_location = saved_location;
}
if (!ix && !current_function_decl)
- pedwarn ("%qD is not defined outside of function scope", decl);
+ pedwarn (loc, 0, "%qD is not defined outside of function scope", decl);
return decl;
}
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 (input_location, 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);
}
return value;
}
\f
+/* Fully fold EXPR, an expression that was not folded (beyond integer
+ constant expressions and null pointer constants) when being built
+ up. If IN_INIT, this is in a static initializer and certain
+ changes are made to the folding done. Clear *MAYBE_CONST if
+ MAYBE_CONST is not NULL and EXPR is definitely not a constant
+ expression because it contains an evaluated operator (in C99) or an
+ operator outside of sizeof returning an integer constant (in C90)
+ not permitted in constant expressions, or because it contains an
+ evaluated arithmetic overflow. (*MAYBE_CONST should typically be
+ set to true by callers before calling this function.) Return the
+ folded expression. Function arguments have already been folded
+ before calling this function, as have the contents of SAVE_EXPR,
+ TARGET_EXPR, BIND_EXPR, VA_ARG_EXPR, OBJ_TYPE_REF and
+ C_MAYBE_CONST_EXPR. */
+
+tree
+c_fully_fold (tree expr, bool in_init, bool *maybe_const)
+{
+ tree ret;
+ tree eptype = NULL_TREE;
+ bool dummy = true;
+ bool maybe_const_itself = true;
+ location_t loc = EXPR_LOCATION (expr);
+
+ /* This function is not relevant to C++ because C++ folds while
+ parsing, and may need changes to be correct for C++ when C++
+ stops folding while parsing. */
+ if (c_dialect_cxx ())
+ gcc_unreachable ();
+
+ if (!maybe_const)
+ maybe_const = &dummy;
+ if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+ {
+ eptype = TREE_TYPE (expr);
+ expr = TREE_OPERAND (expr, 0);
+ }
+ ret = c_fully_fold_internal (expr, in_init, maybe_const,
+ &maybe_const_itself);
+ if (eptype)
+ ret = fold_convert_loc (loc, eptype, ret);
+ *maybe_const &= maybe_const_itself;
+ return ret;
+}
+
+/* Internal helper for c_fully_fold. EXPR and IN_INIT are as for
+ c_fully_fold. *MAYBE_CONST_OPERANDS is cleared because of operands
+ not permitted, while *MAYBE_CONST_ITSELF is cleared because of
+ arithmetic overflow (for C90, *MAYBE_CONST_OPERANDS is carried from
+ both evaluated and unevaluated subexpressions while
+ *MAYBE_CONST_ITSELF is carried from only evaluated
+ subexpressions). */
+
+static tree
+c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
+ bool *maybe_const_itself)
+{
+ tree ret = expr;
+ enum tree_code code = TREE_CODE (expr);
+ enum tree_code_class kind = TREE_CODE_CLASS (code);
+ location_t loc = EXPR_LOCATION (expr);
+ tree op0, op1, op2, op3;
+ tree orig_op0, orig_op1, orig_op2;
+ bool op0_const = true, op1_const = true, op2_const = true;
+ bool op0_const_self = true, op1_const_self = true, op2_const_self = true;
+ bool nowarning = TREE_NO_WARNING (expr);
+ int unused_p;
+
+ /* This function is not relevant to C++ because C++ folds while
+ parsing, and may need changes to be correct for C++ when C++
+ stops folding while parsing. */
+ if (c_dialect_cxx ())
+ gcc_unreachable ();
+
+ /* Constants, declarations, statements, errors, SAVE_EXPRs and
+ anything else not counted as an expression cannot usefully be
+ folded further at this point. */
+ if (!IS_EXPR_CODE_CLASS (kind)
+ || kind == tcc_statement
+ || code == SAVE_EXPR)
+ return expr;
+
+ /* Operands of variable-length expressions (function calls) have
+ already been folded, as have __builtin_* function calls, and such
+ expressions cannot occur in constant expressions. */
+ if (kind == tcc_vl_exp)
+ {
+ *maybe_const_operands = false;
+ ret = fold (expr);
+ goto out;
+ }
+
+ if (code == C_MAYBE_CONST_EXPR)
+ {
+ tree pre = C_MAYBE_CONST_EXPR_PRE (expr);
+ tree inner = C_MAYBE_CONST_EXPR_EXPR (expr);
+ if (C_MAYBE_CONST_EXPR_NON_CONST (expr))
+ *maybe_const_operands = false;
+ if (C_MAYBE_CONST_EXPR_INT_OPERANDS (expr))
+ *maybe_const_itself = false;
+ if (pre && !in_init)
+ ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr), pre, inner);
+ else
+ ret = inner;
+ goto out;
+ }
+
+ /* Assignment, increment, decrement, function call and comma
+ operators, and statement expressions, cannot occur in constant
+ expressions if evaluated / outside of sizeof. (Function calls
+ were handled above, though VA_ARG_EXPR is treated like a function
+ call here, and statement expressions are handled through
+ C_MAYBE_CONST_EXPR to avoid folding inside them.) */
+ switch (code)
+ {
+ case MODIFY_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case COMPOUND_EXPR:
+ *maybe_const_operands = false;
+ break;
+
+ case VA_ARG_EXPR:
+ case TARGET_EXPR:
+ case BIND_EXPR:
+ case OBJ_TYPE_REF:
+ *maybe_const_operands = false;
+ ret = fold (expr);
+ goto out;
+
+ default:
+ break;
+ }
+
+ /* Fold individual tree codes as appropriate. */
+ switch (code)
+ {
+ case COMPOUND_LITERAL_EXPR:
+ /* Any non-constancy will have been marked in a containing
+ C_MAYBE_CONST_EXPR; there is no more folding to do here. */
+ goto out;
+
+ case COMPONENT_REF:
+ orig_op0 = op0 = TREE_OPERAND (expr, 0);
+ op1 = TREE_OPERAND (expr, 1);
+ op2 = TREE_OPERAND (expr, 2);
+ op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+ maybe_const_itself);
+ if (op0 != orig_op0)
+ ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2);
+ if (ret != expr)
+ {
+ TREE_READONLY (ret) = TREE_READONLY (expr);
+ TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
+ }
+ goto out;
+
+ case ARRAY_REF:
+ orig_op0 = op0 = TREE_OPERAND (expr, 0);
+ orig_op1 = op1 = TREE_OPERAND (expr, 1);
+ op2 = TREE_OPERAND (expr, 2);
+ op3 = TREE_OPERAND (expr, 3);
+ op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+ maybe_const_itself);
+ op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
+ maybe_const_itself);
+ op1 = decl_constant_value_for_optimization (op1);
+ if (op0 != orig_op0 || op1 != orig_op1)
+ ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3);
+ if (ret != expr)
+ {
+ TREE_READONLY (ret) = TREE_READONLY (expr);
+ TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr);
+ TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
+ }
+ ret = fold (ret);
+ goto out;
+
+ case COMPOUND_EXPR:
+ case MODIFY_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case POINTER_PLUS_EXPR:
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ case RDIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case COMPLEX_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNEQ_EXPR:
+ /* Binary operations evaluating both arguments (increment and
+ decrement are binary internally in GCC). */
+ orig_op0 = op0 = TREE_OPERAND (expr, 0);
+ orig_op1 = op1 = TREE_OPERAND (expr, 1);
+ op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+ maybe_const_itself);
+ if (code != MODIFY_EXPR
+ && code != PREDECREMENT_EXPR
+ && code != PREINCREMENT_EXPR
+ && code != POSTDECREMENT_EXPR
+ && code != POSTINCREMENT_EXPR)
+ op0 = decl_constant_value_for_optimization (op0);
+ /* The RHS of a MODIFY_EXPR was fully folded when building that
+ expression for the sake of conversion warnings. */
+ if (code != MODIFY_EXPR)
+ op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
+ maybe_const_itself);
+ op1 = decl_constant_value_for_optimization (op1);
+ if (op0 != orig_op0 || op1 != orig_op1 || in_init)
+ ret = in_init
+ ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1)
+ : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1);
+ else
+ ret = fold (expr);
+ if (TREE_OVERFLOW_P (ret)
+ && !TREE_OVERFLOW_P (op0)
+ && !TREE_OVERFLOW_P (op1))
+ overflow_warning (EXPR_LOCATION (expr), ret);
+ goto out;
+
+ case INDIRECT_REF:
+ case FIX_TRUNC_EXPR:
+ case FLOAT_EXPR:
+ CASE_CONVERT:
+ case NON_LVALUE_EXPR:
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_NOT_EXPR:
+ case ADDR_EXPR:
+ case CONJ_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ /* Unary operations. */
+ orig_op0 = op0 = TREE_OPERAND (expr, 0);
+ op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+ maybe_const_itself);
+ if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR)
+ op0 = decl_constant_value_for_optimization (op0);
+ if (op0 != orig_op0 || in_init)
+ ret = in_init
+ ? fold_build1_initializer_loc (loc, code, TREE_TYPE (expr), op0)
+ : fold_build1_loc (loc, code, TREE_TYPE (expr), op0);
+ else
+ ret = fold (expr);
+ if (code == INDIRECT_REF
+ && ret != expr
+ && TREE_CODE (ret) == INDIRECT_REF)
+ {
+ TREE_READONLY (ret) = TREE_READONLY (expr);
+ TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr);
+ TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
+ }
+ switch (code)
+ {
+ case FIX_TRUNC_EXPR:
+ case FLOAT_EXPR:
+ CASE_CONVERT:
+ /* Don't warn about explicit conversions. We will already
+ have warned about suspect implicit conversions. */
+ break;
+
+ default:
+ if (TREE_OVERFLOW_P (ret) && !TREE_OVERFLOW_P (op0))
+ overflow_warning (EXPR_LOCATION (expr), ret);
+ break;
+ }
+ goto out;
+
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ /* Binary operations not necessarily evaluating both
+ arguments. */
+ orig_op0 = op0 = TREE_OPERAND (expr, 0);
+ orig_op1 = op1 = TREE_OPERAND (expr, 1);
+ op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self);
+
+ unused_p = (op0 == (code == TRUTH_ANDIF_EXPR
+ ? truthvalue_false_node
+ : truthvalue_true_node));
+ c_inhibit_evaluation_warnings += unused_p;
+ op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
+ c_inhibit_evaluation_warnings -= unused_p;
+
+ if (op0 != orig_op0 || op1 != orig_op1 || in_init)
+ ret = in_init
+ ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1)
+ : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1);
+ else
+ ret = fold (expr);
+ *maybe_const_operands &= op0_const;
+ *maybe_const_itself &= op0_const_self;
+ if (!(flag_isoc99
+ && op0_const
+ && op0_const_self
+ && (code == TRUTH_ANDIF_EXPR
+ ? op0 == truthvalue_false_node
+ : op0 == truthvalue_true_node)))
+ *maybe_const_operands &= op1_const;
+ if (!(op0_const
+ && op0_const_self
+ && (code == TRUTH_ANDIF_EXPR
+ ? op0 == truthvalue_false_node
+ : op0 == truthvalue_true_node)))
+ *maybe_const_itself &= op1_const_self;
+ goto out;
+
+ case COND_EXPR:
+ orig_op0 = op0 = TREE_OPERAND (expr, 0);
+ orig_op1 = op1 = TREE_OPERAND (expr, 1);
+ orig_op2 = op2 = TREE_OPERAND (expr, 2);
+ op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self);
+
+ c_inhibit_evaluation_warnings += (op0 == truthvalue_false_node);
+ op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
+ c_inhibit_evaluation_warnings -= (op0 == truthvalue_false_node);
+
+ c_inhibit_evaluation_warnings += (op0 == truthvalue_true_node);
+ op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self);
+ c_inhibit_evaluation_warnings -= (op0 == truthvalue_true_node);
+
+ if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2)
+ ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2);
+ else
+ ret = fold (expr);
+ *maybe_const_operands &= op0_const;
+ *maybe_const_itself &= op0_const_self;
+ if (!(flag_isoc99
+ && op0_const
+ && op0_const_self
+ && op0 == truthvalue_false_node))
+ *maybe_const_operands &= op1_const;
+ if (!(op0_const
+ && op0_const_self
+ && op0 == truthvalue_false_node))
+ *maybe_const_itself &= op1_const_self;
+ if (!(flag_isoc99
+ && op0_const
+ && op0_const_self
+ && op0 == truthvalue_true_node))
+ *maybe_const_operands &= op2_const;
+ if (!(op0_const
+ && op0_const_self
+ && op0 == truthvalue_true_node))
+ *maybe_const_itself &= op2_const_self;
+ goto out;
+
+ case EXCESS_PRECISION_EXPR:
+ /* Each case where an operand with excess precision may be
+ encountered must remove the EXCESS_PRECISION_EXPR around
+ inner operands and possibly put one around the whole
+ expression or possibly convert to the semantic type (which
+ c_fully_fold does); we cannot tell at this stage which is
+ appropriate in any particular case. */
+ gcc_unreachable ();
+
+ default:
+ /* Various codes may appear through folding built-in functions
+ and their arguments. */
+ goto out;
+ }
+
+ out:
+ /* Some folding may introduce NON_LVALUE_EXPRs; all lvalue checks
+ have been done by this point, so remove them again. */
+ nowarning |= TREE_NO_WARNING (ret);
+ STRIP_TYPE_NOPS (ret);
+ if (nowarning && !TREE_NO_WARNING (ret))
+ {
+ if (!CAN_HAVE_LOCATION_P (ret))
+ ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
+ TREE_NO_WARNING (ret) = 1;
+ }
+ if (ret != expr)
+ protected_set_expr_location (ret, loc);
+ return ret;
+}
+
+/* If not optimizing, EXP is not a VAR_DECL, or EXP has array type,
+ return EXP. Otherwise, return either EXP or its known constant
+ value (if it has one), but return EXP if EXP has mode BLKmode. ???
+ Is the BLKmode test appropriate? */
+
+tree
+decl_constant_value_for_optimization (tree exp)
+{
+ tree ret;
+
+ /* This function is only used by C, for c_fully_fold and other
+ optimization, and may not be correct for C++. */
+ if (c_dialect_cxx ())
+ gcc_unreachable ();
+
+ if (!optimize
+ || TREE_CODE (exp) != VAR_DECL
+ || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
+ || DECL_MODE (exp) == BLKmode)
+ return exp;
+
+ ret = decl_constant_value (exp);
+ /* Avoid unwanted tree sharing between the initializer and current
+ function's body where the tree can be modified e.g. by the
+ gimplifier. */
+ if (ret != exp && TREE_STATIC (exp))
+ ret = unshare_expr (ret);
+ return ret;
+}
+
/* Print a warning if a constant expression had overflow in folding.
Invoke this function on every expression that the language
requires to be a constant expression.
|| TREE_CODE (value) == VECTOR_CST
|| TREE_CODE (value) == COMPLEX_CST)
&& TREE_OVERFLOW (value))
- pedwarn ("overflow in constant expression");
+ pedwarn (input_location, OPT_Woverflow, "overflow in constant expression");
}
/* The same as above but print an unconditional error. */
already overflowed. */
void
-overflow_warning (tree value)
+overflow_warning (location_t loc, tree value)
{
- if (skip_evaluation) return;
+ if (c_inhibit_evaluation_warnings != 0)
+ return;
switch (TREE_CODE (value))
{
case INTEGER_CST:
- warning (OPT_Woverflow, "integer overflow in expression");
+ warning_at (loc, OPT_Woverflow, "integer overflow in expression");
break;
case REAL_CST:
- warning (OPT_Woverflow, "floating point overflow in expression");
+ warning_at (loc, OPT_Woverflow,
+ "floating point overflow in expression");
break;
case FIXED_CST:
- warning (OPT_Woverflow, "fixed-point overflow in expression");
+ warning_at (loc, OPT_Woverflow, "fixed-point overflow in expression");
break;
case VECTOR_CST:
- warning (OPT_Woverflow, "vector overflow in expression");
+ warning_at (loc, OPT_Woverflow, "vector overflow in expression");
break;
case COMPLEX_CST:
if (TREE_CODE (TREE_REALPART (value)) == INTEGER_CST)
- warning (OPT_Woverflow, "complex integer overflow in expression");
+ warning_at (loc, OPT_Woverflow,
+ "complex integer overflow in expression");
else if (TREE_CODE (TREE_REALPART (value)) == REAL_CST)
- warning (OPT_Woverflow, "complex floating point overflow in expression");
+ warning_at (loc, OPT_Woverflow,
+ "complex floating point overflow in expression");
break;
default:
}
}
+/* Warn about uses of logical || / && operator in a context where it
+ is likely that the bitwise equivalent was intended by the
+ programmer. We have seen an expression in which CODE is a binary
+ operator used to combine expressions OP_LEFT and OP_RIGHT, which before folding
+ had CODE_LEFT and CODE_RIGHT, into an expression of type TYPE. */
+void
+warn_logical_operator (location_t location, enum tree_code code, tree type,
+ enum tree_code code_left, tree op_left,
+ enum tree_code ARG_UNUSED (code_right), tree op_right)
+{
+ int or_op = (code == TRUTH_ORIF_EXPR || code == TRUTH_OR_EXPR);
+ int in0_p, in1_p, in_p;
+ tree low0, low1, low, high0, high1, high, lhs, rhs, tem;
+ bool strict_overflow_p = false;
+
+ if (code != TRUTH_ANDIF_EXPR
+ && code != TRUTH_AND_EXPR
+ && code != TRUTH_ORIF_EXPR
+ && code != TRUTH_OR_EXPR)
+ return;
-/* Warn about use of a logical || / && operator being used in a
- context where it is likely that the bitwise equivalent was intended
- by the programmer. CODE is the TREE_CODE of the operator, ARG1
- and ARG2 the arguments. */
+ /* Warn if &&/|| are being used in a context where it is
+ likely that the bitwise equivalent was intended by the
+ programmer. That is, an expression such as op && MASK
+ where op should not be any boolean expression, nor a
+ constant, and mask seems to be a non-boolean integer constant. */
+ if (!truth_value_p (code_left)
+ && INTEGRAL_TYPE_P (TREE_TYPE (op_left))
+ && !CONSTANT_CLASS_P (op_left)
+ && !TREE_NO_WARNING (op_left)
+ && TREE_CODE (op_right) == INTEGER_CST
+ && !integer_zerop (op_right)
+ && !integer_onep (op_right))
+ {
+ if (or_op)
+ warning_at (location, OPT_Wlogical_op, "logical %<or%>"
+ " applied to non-boolean constant");
+ else
+ warning_at (location, OPT_Wlogical_op, "logical %<and%>"
+ " applied to non-boolean constant");
+ TREE_NO_WARNING (op_left) = true;
+ return;
+ }
-void
-warn_logical_operator (enum tree_code code, tree arg1, tree
- arg2)
-{
- switch (code)
- {
- case TRUTH_ANDIF_EXPR:
- case TRUTH_ORIF_EXPR:
- case TRUTH_OR_EXPR:
- case TRUTH_AND_EXPR:
- if (!TREE_NO_WARNING (arg1)
- && INTEGRAL_TYPE_P (TREE_TYPE (arg1))
- && !CONSTANT_CLASS_P (arg1)
- && TREE_CODE (arg2) == INTEGER_CST
- && !integer_zerop (arg2))
- {
- warning (OPT_Wlogical_op,
- "logical %<%s%> with non-zero constant "
- "will always evaluate as true",
- ((code == TRUTH_ANDIF_EXPR)
- || (code == TRUTH_AND_EXPR)) ? "&&" : "||");
- TREE_NO_WARNING (arg1) = true;
- }
- break;
- default:
- break;
+ /* We do not warn for constants because they are typical of macro
+ expansions that test for features. */
+ if (CONSTANT_CLASS_P (op_left) || CONSTANT_CLASS_P (op_right))
+ return;
+
+ /* This warning only makes sense with logical operands. */
+ if (!(truth_value_p (TREE_CODE (op_left))
+ || INTEGRAL_TYPE_P (TREE_TYPE (op_left)))
+ || !(truth_value_p (TREE_CODE (op_right))
+ || INTEGRAL_TYPE_P (TREE_TYPE (op_right))))
+ return;
+
+ lhs = make_range (op_left, &in0_p, &low0, &high0, &strict_overflow_p);
+ rhs = make_range (op_right, &in1_p, &low1, &high1, &strict_overflow_p);
+
+ if (lhs && TREE_CODE (lhs) == C_MAYBE_CONST_EXPR)
+ lhs = C_MAYBE_CONST_EXPR_EXPR (lhs);
+
+ if (rhs && TREE_CODE (rhs) == C_MAYBE_CONST_EXPR)
+ rhs = C_MAYBE_CONST_EXPR_EXPR (rhs);
+
+ /* If this is an OR operation, invert both sides; we will invert
+ again at the end. */
+ if (or_op)
+ in0_p = !in0_p, in1_p = !in1_p;
+
+ /* If both expressions are the same, if we can merge the ranges, and we
+ can build the range test, return it or it inverted. */
+ if (lhs && rhs && operand_equal_p (lhs, rhs, 0)
+ && merge_ranges (&in_p, &low, &high, in0_p, low0, high0,
+ in1_p, low1, high1)
+ && 0 != (tem = build_range_check (UNKNOWN_LOCATION,
+ type, lhs, in_p, low, high)))
+ {
+ if (TREE_CODE (tem) != INTEGER_CST)
+ return;
+
+ if (or_op)
+ warning_at (location, OPT_Wlogical_op,
+ "logical %<or%> "
+ "of collectively exhaustive tests is always true");
+ else
+ warning_at (location, OPT_Wlogical_op,
+ "logical %<and%> "
+ "of mutually exclusive tests is always false");
}
}
bool
strict_aliasing_warning (tree otype, tree type, tree expr)
{
+ /* Strip pointer conversion chains and get to the correct original type. */
+ STRIP_NOPS (expr);
+ otype = TREE_TYPE (expr);
+
if (!(flag_strict_aliasing
&& POINTER_TYPE_P (type)
&& POINTER_TYPE_P (otype)
return false;
}
-/* Print a warning about if (); or if () .. else; constructs
- via the special empty statement node that we create. INNER_THEN
- and INNER_ELSE are the statement lists of the if and the else
- block. */
-
-void
-empty_if_body_warning (tree inner_then, tree inner_else)
-{
- if (TREE_CODE (inner_then) == STATEMENT_LIST
- && STATEMENT_LIST_TAIL (inner_then))
- inner_then = STATEMENT_LIST_TAIL (inner_then)->stmt;
-
- if (inner_else && TREE_CODE (inner_else) == STATEMENT_LIST
- && STATEMENT_LIST_TAIL (inner_else))
- inner_else = STATEMENT_LIST_TAIL (inner_else)->stmt;
-
- if (IS_EMPTY_STMT (inner_then) && !inner_else)
- warning (OPT_Wempty_body, "%Hsuggest braces around empty body "
- "in an %<if%> statement", EXPR_LOCUS (inner_then));
-
- else if (inner_else && IS_EMPTY_STMT (inner_else))
- warning (OPT_Wempty_body, "%Hsuggest braces around empty body "
- "in an %<else%> statement", EXPR_LOCUS (inner_else));
-}
-
/* Warn for unlikely, improbable, or stupid DECL declarations
of `main'. */
{
case 1:
if (TYPE_MAIN_VARIANT (type) != integer_type_node)
- pedwarn ("first argument of %q+D should be %<int%>", decl);
+ pedwarn (input_location, OPT_Wmain, "first argument of %q+D should be %<int%>",
+ decl);
break;
case 2:
|| 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 (input_location, OPT_Wmain, "second argument of %q+D should be %<char **%>",
+ decl);
break;
case 3:
|| 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 (input_location, OPT_Wmain, "third argument of %q+D should probably be "
+ "%<char **%>", decl);
break;
}
}
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 (input_location, OPT_Wmain, "%q+D takes only zero or two arguments", decl);
}
/* True if pointers to distinct types T1 and T2 can be converted to
vector_targets_convertible_p (const_tree t1, const_tree t2)
{
if (TREE_CODE (t1) == VECTOR_TYPE && TREE_CODE (t2) == VECTOR_TYPE
- && (targetm.vector_opaque_p (t1) || targetm.vector_opaque_p (t2))
+ && (TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2))
&& tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)))
return true;
static bool emitted_lax_note = false;
bool convertible_lax;
- if ((targetm.vector_opaque_p (t1) || targetm.vector_opaque_p (t2))
+ if ((TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2))
&& tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)))
return true;
if (emit_lax_note && !emitted_lax_note)
{
emitted_lax_note = true;
- inform ("use -flax-vector-conversions to permit "
+ inform (input_location, "use -flax-vector-conversions to permit "
"conversions between vectors with differing "
"element types or numbers of subparts");
}
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. */
{
bool give_warning = false;
- unsigned int formal_prec = TYPE_PRECISION (type);
+ int i;
+ const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
+ tree expr_type = TREE_TYPE (expr);
if (!warn_conversion && !warn_sign_conversion)
return;
- if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
+ /* If any operand is artificial, then this expression was generated
+ by the compiler and we do not warn. */
+ for (i = 0; i < expr_num_operands; i++)
{
+ tree op = TREE_OPERAND (expr, i);
+ if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
+ return;
+ }
+
+ 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))
}
/* 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))
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 (TREE_CODE (expr) == BIT_AND_EXPR)
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ bool unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0));
+ bool unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1));
+
+ /* 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 (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;
+ /* If constant is unsigned and fits in the target
+ type, then the result will also fit. */
+ else if ((TREE_CODE (op0) == INTEGER_CST
+ && unsigned0
+ && int_fits_type_p (op0, type))
+ || (TREE_CODE (op1) == INTEGER_CST
+ && unsigned1
+ && int_fits_type_p (op1, 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))
}
/* 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);
}
}
convert_and_check (tree type, tree expr)
{
tree result;
+ tree expr_for_warning;
+
+ /* Convert from a value with possible excess precision rather than
+ via the semantic type, but do not warn about values not fitting
+ exactly in the semantic type. */
+ if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+ {
+ tree orig_type = TREE_TYPE (expr);
+ expr = TREE_OPERAND (expr, 0);
+ expr_for_warning = convert (orig_type, expr);
+ if (orig_type == type)
+ return expr_for_warning;
+ }
+ else
+ expr_for_warning = expr;
if (TREE_TYPE (expr) == type)
return expr;
result = convert (type, expr);
- if (!skip_evaluation && !TREE_OVERFLOW_P (expr) && result != error_mark_node)
- warnings_for_convert_and_check (type, expr, result);
+ if (c_inhibit_evaluation_warnings == 0
+ && !TREE_OVERFLOW_P (expr)
+ && result != error_mark_node)
+ warnings_for_convert_and_check (type, expr_for_warning, result);
return result;
}
static void merge_tlist (struct tlist **, struct tlist *, int);
static void verify_tree (tree, struct tlist **, struct tlist **, tree);
static int warning_candidate_p (tree);
+static bool candidate_equal_p (const_tree, const_tree);
static void warn_for_collisions (struct tlist *);
static void warn_for_collisions_1 (tree, tree, struct tlist *, int);
static struct tlist *new_tlist (struct tlist *, tree, tree);
struct tlist *next = add->next;
if (!copy)
add->next = *to;
- if (!exclude_writer || add->writer != exclude_writer)
+ if (!exclude_writer || !candidate_equal_p (add->writer, exclude_writer))
*to = copy ? new_tlist (*to, add->expr, add->writer) : add;
add = next;
}
struct tlist *next = add->next;
for (tmp2 = *to; tmp2; tmp2 = tmp2->next)
- if (tmp2->expr == add->expr)
+ if (candidate_equal_p (tmp2->expr, add->expr))
{
found = 1;
if (!tmp2->writer)
/* Avoid duplicate warnings. */
for (tmp = warned_ids; tmp; tmp = tmp->next)
- if (tmp->expr == written)
+ if (candidate_equal_p (tmp->expr, written))
return;
while (list)
{
- if (list->expr == written
- && list->writer != writer
- && (!only_writes || list->writer)
- && DECL_NAME (list->expr))
+ if (candidate_equal_p (list->expr, written)
+ && !candidate_equal_p (list->writer, writer)
+ && (!only_writes || list->writer))
{
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;
}
static int
warning_candidate_p (tree x)
{
- return TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == PARM_DECL;
+ /* !VOID_TYPE_P (TREE_TYPE (x)) is workaround for cp/tree.c
+ (lvalue_p) crash on TRY/CATCH. */
+ return !(DECL_P (x) && DECL_ARTIFICIAL (x))
+ && TREE_TYPE (x) && !VOID_TYPE_P (TREE_TYPE (x)) && lvalue_p (x);
+}
+
+/* Return nonzero if X and Y appear to be the same candidate (or NULL) */
+static bool
+candidate_equal_p (const_tree x, const_tree y)
+{
+ return (x == y) || (x && y && operand_equal_p (x, y, 0));
}
/* Walk the tree X, and record accesses to variables. If X is written by the
cl = TREE_CODE_CLASS (code);
if (warning_candidate_p (x))
- {
- *pno_sp = new_tlist (*pno_sp, x, writer);
- return;
- }
+ *pno_sp = new_tlist (*pno_sp, x, writer);
switch (code)
{
{
struct tlist_cache *t;
for (t = save_expr_cache; t; t = t->next)
- if (t->expr == x)
+ if (candidate_equal_p (t->expr, x))
break;
if (!t)
return;
}
+ case ADDR_EXPR:
+ x = TREE_OPERAND (x, 0);
+ if (DECL_P (x))
+ return;
+ writer = 0;
+ goto restart;
+
default:
/* For other expressions, simply recurse on their operands.
Manual tail recursion for unary expressions.
#define TYPE_OK(node) \
(TYPE_MODE (type) == TYPE_MODE (node) \
- && (c_dialect_cxx () || TYPE_PRECISION (type) == TYPE_PRECISION (node)))
+ && TYPE_PRECISION (type) == TYPE_PRECISION (node))
if (TYPE_OK (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
if (TYPE_OK (integer_type_node))
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
#undef TYPE_OK
- if (c_dialect_cxx ())
- return type;
- else
- return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp);
+ return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp);
}
/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */
{
tree decl;
- decl = build_decl (TYPE_DECL, get_identifier (name), type);
+ decl = build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, get_identifier (name), type);
DECL_ARTIFICIAL (decl) = 1;
if (!TYPE_NAME (type))
TYPE_NAME (type) = decl;
registered_builtin_types = tree_cons (0, type, registered_builtin_types);
}
-
-\f
-/* Return the minimum number of bits needed to represent VALUE in a
- signed or unsigned type, UNSIGNEDP says which. */
-
-unsigned int
-min_precision (tree value, int unsignedp)
-{
- int log;
-
- /* If the value is negative, compute its negative minus 1. The latter
- adjustment is because the absolute value of the largest negative value
- is one larger than the largest positive value. This is equivalent to
- a bit-wise negation, so use that operation instead. */
-
- if (tree_int_cst_sgn (value) < 0)
- value = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (value), value);
-
- /* Return the number of bits needed, taking into account the fact
- that we need one more bit for a signed than unsigned type. */
-
- if (integer_zerop (value))
- log = 0;
- else
- log = tree_floor_log2 (value);
-
- return log + 1 + !unsignedp;
-}
\f
/* Print an error message for invalid operands to arith operation
- CODE with TYPE0 for operand 0, and TYPE1 for operand 1. */
+ CODE with TYPE0 for operand 0, and TYPE1 for operand 1.
+ LOCATION is the location of the message. */
void
-binary_op_error (enum tree_code code, tree type0, tree type1)
+binary_op_error (location_t location, enum tree_code code,
+ tree type0, tree type1)
{
const char *opname;
default:
gcc_unreachable ();
}
- error ("invalid operands to binary %s (have %qT and %qT)", opname,
- type0, type1);
+ error_at (location,
+ "invalid operands to binary %s (have %qT and %qT)", opname,
+ type0, type1);
}
\f
/* Subroutine of build_binary_op, used for comparison operations.
of pointer PTROP and integer INTOP. */
tree
-pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
+pointer_int_sum (location_t loc, enum tree_code resultcode,
+ tree ptrop, tree intop)
{
tree size_exp, ret;
if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
{
- if (pedantic || warn_pointer_arith)
- pedwarn ("pointer of type %<void *%> used in arithmetic");
+ pedwarn (loc, 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 (loc, 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 (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "pointer to member function used in arithmetic");
size_exp = integer_one_node;
}
else
/* Convert both subexpression types to the type of intop,
because weird cases involving pointer arithmetic
can result in a sum or difference with different type args. */
- ptrop = build_binary_op (subcode, ptrop,
+ ptrop = build_binary_op (EXPR_LOCATION (TREE_OPERAND (intop, 1)),
+ subcode, ptrop,
convert (int_type, TREE_OPERAND (intop, 1)), 1);
intop = convert (int_type, TREE_OPERAND (intop, 0));
}
Do this multiplication as signed, then convert to the appropriate
type for the pointer operation. */
intop = convert (sizetype,
- build_binary_op (MULT_EXPR, intop,
+ build_binary_op (loc,
+ MULT_EXPR, intop,
convert (TREE_TYPE (intop), size_exp), 1));
/* Create the sum or difference. */
if (resultcode == MINUS_EXPR)
- intop = fold_build1 (NEGATE_EXPR, sizetype, intop);
+ intop = fold_build1_loc (loc, NEGATE_EXPR, sizetype, intop);
- ret = fold_build2 (POINTER_PLUS_EXPR, result_type, ptrop, intop);
+ ret = fold_build2_loc (loc, POINTER_PLUS_EXPR, result_type, ptrop, intop);
fold_undefer_and_ignore_overflow_warnings ();
return ret;
}
\f
+/* Wrap a SAVE_EXPR around EXPR, if appropriate. Like save_expr, but
+ for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR
+ around the SAVE_EXPR if needed so that c_fully_fold does not need
+ to look inside SAVE_EXPRs. */
+
+tree
+c_save_expr (tree expr)
+{
+ bool maybe_const = true;
+ if (c_dialect_cxx ())
+ return save_expr (expr);
+ expr = c_fully_fold (expr, false, &maybe_const);
+ expr = save_expr (expr);
+ if (!maybe_const)
+ {
+ expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr);
+ C_MAYBE_CONST_EXPR_NON_CONST (expr) = 1;
+ }
+ return expr;
+}
+
/* Return whether EXPR is a declaration whose address can never be
NULL. */
have been validated to be of suitable type; otherwise, a bad
diagnostic may result.
+ The EXPR is located at LOCATION.
+
This preparation consists of taking the ordinary
representation of an expression expr and producing a valid tree
boolean expression describing whether expr is nonzero. We could
The resulting type should always be `truthvalue_type_node'. */
tree
-c_common_truthvalue_conversion (tree expr)
+c_common_truthvalue_conversion (location_t location, tree expr)
{
switch (TREE_CODE (expr))
{
case ORDERED_EXPR: case UNORDERED_EXPR:
if (TREE_TYPE (expr) == truthvalue_type_node)
return expr;
- return build2 (TREE_CODE (expr), truthvalue_type_node,
+ expr = build2 (TREE_CODE (expr), truthvalue_type_node,
TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
+ goto ret;
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
case TRUTH_XOR_EXPR:
if (TREE_TYPE (expr) == truthvalue_type_node)
return expr;
- return build2 (TREE_CODE (expr), truthvalue_type_node,
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)),
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)));
+ expr = build2 (TREE_CODE (expr), truthvalue_type_node,
+ c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 0)),
+ c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 1)));
+ goto ret;
case TRUTH_NOT_EXPR:
if (TREE_TYPE (expr) == truthvalue_type_node)
return expr;
- return build1 (TREE_CODE (expr), truthvalue_type_node,
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
+ expr = build1 (TREE_CODE (expr), truthvalue_type_node,
+ c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 0)));
+ goto ret;
case ERROR_MARK:
return expr;
: truthvalue_false_node;
case FUNCTION_DECL:
- expr = build_unary_op (ADDR_EXPR, expr, 0);
+ expr = build_unary_op (location, ADDR_EXPR, expr, 0);
/* Fall through. */
case ADDR_EXPR:
if (decl_with_nonnull_addr_p (inner))
{
/* Common Ada/Pascal programmer's mistake. */
- warning (OPT_Waddress,
- "the address of %qD will always evaluate as %<true%>",
- inner);
+ warning_at (location,
+ OPT_Waddress,
+ "the address of %qD will always evaluate as %<true%>",
+ inner);
return truthvalue_true_node;
}
}
if (TREE_SIDE_EFFECTS (inner))
- return build2 (COMPOUND_EXPR, truthvalue_type_node,
- inner, truthvalue_true_node);
+ {
+ expr = build2 (COMPOUND_EXPR, truthvalue_type_node,
+ inner, truthvalue_true_node);
+ goto ret;
+ }
else
return truthvalue_true_node;
}
case COMPLEX_EXPR:
- return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
+ expr = build_binary_op (EXPR_LOCATION (expr),
+ (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)),
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 0)),
+ c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 1)),
0);
+ goto ret;
case NEGATE_EXPR:
case ABS_EXPR:
case FLOAT_EXPR:
+ case EXCESS_PRECISION_EXPR:
/* These don't change whether an object is nonzero or zero. */
- return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
+ return c_common_truthvalue_conversion (location, TREE_OPERAND (expr, 0));
case LROTATE_EXPR:
case RROTATE_EXPR:
/* These don't change whether an object is zero or nonzero, but
we can't ignore them if their second arg has side-effects. */
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
- return build2 (COMPOUND_EXPR, truthvalue_type_node,
- TREE_OPERAND (expr, 1),
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
+ {
+ expr = build2 (COMPOUND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 1),
+ c_common_truthvalue_conversion
+ (location, TREE_OPERAND (expr, 0)));
+ goto ret;
+ }
else
- return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
+ return c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 0));
case COND_EXPR:
/* Distribute the conversion into the arms of a COND_EXPR. */
- return fold_build3 (COND_EXPR, truthvalue_type_node,
- TREE_OPERAND (expr, 0),
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
- c_common_truthvalue_conversion (TREE_OPERAND (expr, 2)));
+ if (c_dialect_cxx ())
+ {
+ expr = fold_build3_loc (location, COND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 0),
+ c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr,
+ 1)),
+ c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr,
+ 2)));
+ goto ret;
+ }
+ else
+ {
+ /* Folding will happen later for C. */
+ expr = build3 (COND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 0),
+ c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 1)),
+ c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 2)));
+ goto ret;
+ }
CASE_CONVERT:
/* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
/* If this is widening the argument, we can ignore it. */
if (TYPE_PRECISION (TREE_TYPE (expr))
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
- return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
+ return c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 0));
break;
case MODIFY_EXPR:
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
{
- tree t = save_expr (expr);
- return (build_binary_op
- ((TREE_SIDE_EFFECTS (expr)
+ tree t = c_save_expr (expr);
+ expr = (build_binary_op
+ (EXPR_LOCATION (expr),
+ (TREE_SIDE_EFFECTS (expr)
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
- c_common_truthvalue_conversion (build_unary_op (REALPART_EXPR, t, 0)),
- c_common_truthvalue_conversion (build_unary_op (IMAGPART_EXPR, t, 0)),
+ c_common_truthvalue_conversion
+ (location,
+ build_unary_op (location, REALPART_EXPR, t, 0)),
+ c_common_truthvalue_conversion
+ (location,
+ build_unary_op (location, IMAGPART_EXPR, t, 0)),
0));
+ goto ret;
}
if (TREE_CODE (TREE_TYPE (expr)) == FIXED_POINT_TYPE)
tree fixed_zero_node = build_fixed (TREE_TYPE (expr),
FCONST0 (TYPE_MODE
(TREE_TYPE (expr))));
- return build_binary_op (NE_EXPR, expr, fixed_zero_node, 1);
+ return build_binary_op (location, NE_EXPR, expr, fixed_zero_node, 1);
}
+ else
+ return build_binary_op (location, NE_EXPR, expr, integer_zero_node, 1);
- return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
+ ret:
+ protected_set_expr_location (expr, location);
+ return expr;
}
\f
static void def_builtin_1 (enum built_in_function fncode,
|| !POINTER_TYPE_P (type)
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))
error ("invalid use of %<restrict%>");
- else if (flag_strict_aliasing && type == TREE_TYPE (decl))
- /* Indicate we need to make a unique alias set for this pointer.
- We can't do it here because it might be pointing to an
- incomplete type. */
- DECL_POINTER_ALIAS_SET (decl) = -2;
}
}
return -1;
}
\f
-/* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where the
- second parameter indicates which OPERATOR is being applied. The COMPLAIN
- flag controls whether we should diagnose possibly ill-formed
- constructs or not. */
+/* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where
+ the second parameter indicates which OPERATOR is being applied.
+ The COMPLAIN flag controls whether we should diagnose possibly
+ ill-formed constructs or not. LOC is the location of the SIZEOF or
+ TYPEOF operator. */
tree
-c_sizeof_or_alignof_type (tree type, bool is_sizeof, int complain)
+c_sizeof_or_alignof_type (location_t loc,
+ tree type, bool is_sizeof, int complain)
{
const char *op_name;
tree value = NULL;
if (is_sizeof)
{
if (complain && (pedantic || warn_pointer_arith))
- pedwarn ("invalid application of %<sizeof%> to a function type");
+ pedwarn (loc, 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;
{
if (type_code == VOID_TYPE
&& complain && (pedantic || warn_pointer_arith))
- pedwarn ("invalid application of %qs to a void type", op_name);
+ pedwarn (loc, 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;
else if (!COMPLETE_TYPE_P (type))
{
if (complain)
- error ("invalid application of %qs to incomplete type %qT ",
- op_name, type);
+ error_at (loc, "invalid application of %qs to incomplete type %qT ",
+ op_name, type);
value = size_zero_node;
}
else
{
if (is_sizeof)
/* Convert in case a char is more than one unit. */
- value = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
- size_int (TYPE_PRECISION (char_type_node)
- / BITS_PER_UNIT));
+ value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
+ size_int (TYPE_PRECISION (char_type_node)
+ / BITS_PER_UNIT));
else
value = size_int (TYPE_ALIGN_UNIT (type));
}
TYPE_IS_SIZETYPE means that certain things (like overflow) will
never happen. However, this node should really have type
`size_t', which is just a typedef for an ordinary integer type. */
- value = fold_convert (size_type_node, value);
+ value = fold_convert_loc (loc, size_type_node, value);
gcc_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value)));
return value;
/* Implement the __alignof keyword: Return the minimum required
alignment of EXPR, measured in bytes. For VAR_DECLs,
FUNCTION_DECLs and FIELD_DECLs return DECL_ALIGN (which can be set
- from an "aligned" __attribute__ specification). */
+ from an "aligned" __attribute__ specification). LOC is the
+ location of the ALIGNOF operator. */
tree
-c_alignof_expr (tree expr)
+c_alignof_expr (location_t loc, tree expr)
{
tree t;
else if (TREE_CODE (expr) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
{
- error ("%<__alignof%> applied to a bit-field");
+ error_at (loc, "%<__alignof%> applied to a bit-field");
t = size_one_node;
}
else if (TREE_CODE (expr) == COMPONENT_REF
if (thisalign > bestalign)
best = t, bestalign = thisalign;
}
- return c_alignof (TREE_TYPE (TREE_TYPE (best)));
+ return c_alignof (loc, TREE_TYPE (TREE_TYPE (best)));
}
else
- return c_alignof (TREE_TYPE (expr));
+ return c_alignof (loc, TREE_TYPE (expr));
- return fold_convert (size_type_node, t);
+ return fold_convert_loc (loc, size_type_node, t);
}
\f
/* Handle C and C++ default attributes. */
mudflap_init ();
}
+/* Like get_identifier, but avoid warnings about null arguments when
+ the argument may be NULL for targets where GCC lacks stdint.h type
+ information. */
+
+static inline tree
+c_get_ident (const char *id)
+{
+ return get_identifier (id);
+}
+
/* Build tree nodes and builtin functions common to both C and C++ language
frontends. */
/* These are types that c_common_type_for_size and
c_common_type_for_mode use. */
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
intQI_type_node));
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
intHI_type_node));
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
intSI_type_node));
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
intDI_type_node));
#if HOST_BITS_PER_WIDE_INT >= 64
if (targetm.scalar_mode_supported_p (TImode))
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL,
get_identifier ("__int128_t"),
intTI_type_node));
#endif
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
unsigned_intQI_type_node));
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
unsigned_intHI_type_node));
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
unsigned_intSI_type_node));
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
unsigned_intDI_type_node));
#if HOST_BITS_PER_WIDE_INT >= 64
if (targetm.scalar_mode_supported_p (TImode))
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL,
get_identifier ("__uint128_t"),
unsigned_intTI_type_node));
#endif
/* Create the widest literal types. */
widest_integer_literal_type_node
= make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
widest_integer_literal_type_node));
widest_unsigned_literal_type_node
= make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2);
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, NULL_TREE,
widest_unsigned_literal_type_node));
/* `unsigned long' is the standard type for sizeof.
}
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL,
get_identifier ("complex int"),
complex_integer_type_node));
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL,
get_identifier ("complex float"),
complex_float_type_node));
- lang_hooks.decls.pushdecl (build_decl (TYPE_DECL,
+ lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL,
get_identifier ("complex double"),
complex_double_type_node));
lang_hooks.decls.pushdecl
- (build_decl (TYPE_DECL, get_identifier ("complex long double"),
+ (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, get_identifier ("complex long double"),
complex_long_double_type_node));
if (c_dialect_cxx ())
wchar_type_node = get_identifier (MODIFIED_WCHAR_TYPE);
wchar_type_node = TREE_TYPE (identifier_global_value (wchar_type_node));
wchar_type_size = TYPE_PRECISION (wchar_type_node);
+ underlying_wchar_type_node = wchar_type_node;
if (c_dialect_cxx ())
{
if (TYPE_UNSIGNED (wchar_type_node))
wchar_type_node = make_signed_type (wchar_type_size);
record_builtin_type (RID_WCHAR, "wchar_t", wchar_type_node);
}
- else
- {
- signed_wchar_type_node = c_common_signed_type (wchar_type_node);
- unsigned_wchar_type_node = c_common_unsigned_type (wchar_type_node);
- }
/* This is for wide string constants. */
wchar_array_type_node
uintmax_type_node =
TREE_TYPE (identifier_global_value (get_identifier (UINTMAX_TYPE)));
+ if (SIG_ATOMIC_TYPE)
+ sig_atomic_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (SIG_ATOMIC_TYPE)));
+ if (INT8_TYPE)
+ int8_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT8_TYPE)));
+ if (INT16_TYPE)
+ int16_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT16_TYPE)));
+ if (INT32_TYPE)
+ int32_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT32_TYPE)));
+ if (INT64_TYPE)
+ int64_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT64_TYPE)));
+ if (UINT8_TYPE)
+ uint8_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT8_TYPE)));
+ if (UINT16_TYPE)
+ uint16_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT16_TYPE)));
+ if (UINT32_TYPE)
+ c_uint32_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT32_TYPE)));
+ if (UINT64_TYPE)
+ c_uint64_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT64_TYPE)));
+ if (INT_LEAST8_TYPE)
+ int_least8_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST8_TYPE)));
+ if (INT_LEAST16_TYPE)
+ int_least16_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST16_TYPE)));
+ if (INT_LEAST32_TYPE)
+ int_least32_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST32_TYPE)));
+ if (INT_LEAST64_TYPE)
+ int_least64_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST64_TYPE)));
+ if (UINT_LEAST8_TYPE)
+ uint_least8_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST8_TYPE)));
+ if (UINT_LEAST16_TYPE)
+ uint_least16_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST16_TYPE)));
+ if (UINT_LEAST32_TYPE)
+ uint_least32_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST32_TYPE)));
+ if (UINT_LEAST64_TYPE)
+ uint_least64_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST64_TYPE)));
+ if (INT_FAST8_TYPE)
+ int_fast8_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST8_TYPE)));
+ if (INT_FAST16_TYPE)
+ int_fast16_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST16_TYPE)));
+ if (INT_FAST32_TYPE)
+ int_fast32_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST32_TYPE)));
+ if (INT_FAST64_TYPE)
+ int_fast64_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST64_TYPE)));
+ if (UINT_FAST8_TYPE)
+ uint_fast8_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST8_TYPE)));
+ if (UINT_FAST16_TYPE)
+ uint_fast16_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST16_TYPE)));
+ if (UINT_FAST32_TYPE)
+ uint_fast32_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST32_TYPE)));
+ if (UINT_FAST64_TYPE)
+ uint_fast64_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST64_TYPE)));
+ if (INTPTR_TYPE)
+ intptr_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (INTPTR_TYPE)));
+ if (UINTPTR_TYPE)
+ uintptr_type_node =
+ TREE_TYPE (identifier_global_value (c_get_ident (UINTPTR_TYPE)));
+
default_function_type = build_function_type (integer_type_node, NULL_TREE);
ptrdiff_type_node
= TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE)));
unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node);
lang_hooks.decls.pushdecl
- (build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"),
+ (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, get_identifier ("__builtin_va_list"),
va_list_type_node));
#ifdef TARGET_ENUM_VA_LIST
{
for (l = 0; TARGET_ENUM_VA_LIST (l, &pname, &ptype); ++l)
{
lang_hooks.decls.pushdecl
- (build_decl (TYPE_DECL, get_identifier (pname),
+ (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL, get_identifier (pname),
ptype));
}
builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
set_user_assembler_name (builtin, asmspec);
- if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMCPY)
- init_block_move_fn (asmspec);
- else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMSET)
- init_block_clear_fn (asmspec);
+ switch (DECL_FUNCTION_CODE (decl))
+ {
+ case BUILT_IN_MEMCPY:
+ init_block_move_fn (asmspec);
+ memcpy_libfunc = set_user_assembler_libfunc ("memcpy", asmspec);
+ break;
+ case BUILT_IN_MEMSET:
+ init_block_clear_fn (asmspec);
+ memset_libfunc = set_user_assembler_libfunc ("memset", asmspec);
+ break;
+ case BUILT_IN_MEMMOVE:
+ memmove_libfunc = set_user_assembler_libfunc ("memmove", asmspec);
+ break;
+ case BUILT_IN_MEMCMP:
+ memcmp_libfunc = set_user_assembler_libfunc ("memcmp", asmspec);
+ break;
+ case BUILT_IN_ABORT:
+ abort_libfunc = set_user_assembler_libfunc ("abort", asmspec);
+ break;
+ default:
+ break;
+ }
}
/* The number of named compound-literals generated thus far. */
}
tree
-build_va_arg (tree expr, tree type)
+build_va_arg (location_t loc, tree expr, tree type)
{
- return build1 (VA_ARG_EXPR, type, expr);
+ expr = build1 (VA_ARG_EXPR, type, expr);
+ SET_EXPR_LOCATION (expr, loc);
+ return expr;
}
return tree_int_cst_compare ((tree) k1, (tree) k2);
}
-/* Process a case label for the range LOW_VALUE ... HIGH_VALUE. If
- LOW_VALUE and HIGH_VALUE are both NULL_TREE then this case label is
- actually a `default' label. If only HIGH_VALUE is NULL_TREE, then
- case label was declared using the usual C/C++ syntax, rather than
- the GNU case range extension. CASES is a tree containing all the
- case ranges processed so far; COND is the condition for the
- switch-statement itself. Returns the CASE_LABEL_EXPR created, or
- ERROR_MARK_NODE if no CASE_LABEL_EXPR is created. */
+/* Process a case label, located at LOC, for the range LOW_VALUE
+ ... HIGH_VALUE. If LOW_VALUE and HIGH_VALUE are both NULL_TREE
+ then this case label is actually a `default' label. If only
+ HIGH_VALUE is NULL_TREE, then case label was declared using the
+ usual C/C++ syntax, rather than the GNU case range extension.
+ CASES is a tree containing all the case ranges processed so far;
+ COND is the condition for the switch-statement itself. Returns the
+ CASE_LABEL_EXPR created, or ERROR_MARK_NODE if no CASE_LABEL_EXPR
+ is created. */
tree
-c_add_case_label (splay_tree cases, tree cond, tree orig_type,
+c_add_case_label (location_t loc, splay_tree cases, tree cond, tree orig_type,
tree low_value, tree high_value)
{
tree type;
splay_tree_node node;
/* Create the LABEL_DECL itself. */
- label = create_artificial_label ();
+ label = create_artificial_label (loc);
/* If there was an error processing the switch condition, bail now
before we get more confused. */
|| (high_value && TREE_TYPE (high_value)
&& POINTER_TYPE_P (TREE_TYPE (high_value))))
{
- error ("pointers are not permitted as case values");
+ error_at (loc, "pointers are not permitted as case values");
goto error_out;
}
/* Case ranges are a GNU extension. */
- if (high_value && pedantic)
- pedwarn ("range expressions in switch statements are non-standard");
+ if (high_value)
+ pedwarn (loc, OPT_pedantic,
+ "range expressions in switch statements are non-standard");
type = TREE_TYPE (cond);
if (low_value)
if (tree_int_cst_equal (low_value, high_value))
high_value = NULL_TREE;
else if (!tree_int_cst_lt (low_value, high_value))
- warning (0, "empty range specified");
+ warning_at (loc, 0, "empty range specified");
}
/* See if the case is in range of the type of the original testing
if (high_value)
{
- error ("duplicate (or overlapping) case value");
- error ("%Jthis is the first entry overlapping that value", duplicate);
+ error_at (loc, "duplicate (or overlapping) case value");
+ error_at (DECL_SOURCE_LOCATION (duplicate),
+ "this is the first entry overlapping that value");
}
else if (low_value)
{
- error ("duplicate case value") ;
- error ("%Jpreviously used here", duplicate);
+ error_at (loc, "duplicate case value") ;
+ error_at (DECL_SOURCE_LOCATION (duplicate), "previously used here");
}
else
{
- error ("multiple default labels in one switch");
- error ("%Jthis is the first default label", duplicate);
+ error_at (loc, "multiple default labels in one switch");
+ error_at (DECL_SOURCE_LOCATION (duplicate),
+ "this is the first default label");
}
goto error_out;
}
/* Add a CASE_LABEL to the statement-tree. */
- case_label = add_stmt (build_case_label (low_value, high_value, label));
+ case_label = add_stmt (build_case_label (loc, low_value, high_value, label));
/* Register this case label in the splay tree. */
splay_tree_insert (cases,
(splay_tree_key) low_value,
that just leads to duplicates and thence to failure later on. */
if (!cases->root)
{
- tree t = create_artificial_label ();
- add_stmt (build_stmt (LABEL_EXPR, t));
+ tree t = create_artificial_label (loc);
+ add_stmt (build_stmt (loc, LABEL_EXPR, t));
}
return error_mark_node;
}
(unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (key));
if (TYPE_NAME (type) == 0)
- warning (warn_switch ? OPT_Wswitch : OPT_Wswitch_enum,
- "%Jcase value %qs not in enumerated type",
- CASE_LABEL (label), buf);
+ warning_at (DECL_SOURCE_LOCATION (CASE_LABEL (label)),
+ warn_switch ? OPT_Wswitch : OPT_Wswitch_enum,
+ "case value %qs not in enumerated type",
+ buf);
else
- warning (warn_switch ? OPT_Wswitch : OPT_Wswitch_enum,
- "%Jcase value %qs not in enumerated type %qT",
- CASE_LABEL (label), buf, type);
+ warning_at (DECL_SOURCE_LOCATION (CASE_LABEL (label)),
+ warn_switch ? OPT_Wswitch : OPT_Wswitch_enum,
+ "case value %qs not in enumerated type %qT",
+ buf, type);
}
/* Subroutine of c_do_switch_warnings, called via splay_tree_foreach.
splay_tree_node default_node;
splay_tree_node node;
tree chain;
- int saved_warn_switch;
if (!warn_switch && !warn_switch_enum && !warn_switch_default)
return;
default_node = splay_tree_lookup (cases, (splay_tree_key) NULL);
if (!default_node)
- warning (OPT_Wswitch_default, "%Hswitch missing default case",
- &switch_location);
+ warning_at (switch_location, OPT_Wswitch_default,
+ "switch missing default case");
/* From here on, we only care about about enumerated types. */
if (!type || TREE_CODE (type) != ENUMERAL_TYPE)
return;
- /* If the switch expression was an enumerated type, check that
- exactly all enumeration literals are covered by the cases.
- The check is made when -Wswitch was specified and there is no
- default case, or when -Wswitch-enum was specified. */
-
- if (!warn_switch_enum
- && !(warn_switch && !default_node))
+ /* From here on, we only care about -Wswitch and -Wswitch-enum. */
+ if (!warn_switch_enum && !warn_switch)
return;
+ /* Check the cases. Warn about case values which are not members of
+ the enumerated type. For -Wswitch-enum, or for -Wswitch when
+ there is no default case, check that exactly all enumeration
+ literals are covered by the cases. */
+
/* Clearing COND if it is not an integer constant simplifies
the tests inside the loop below. */
if (TREE_CODE (cond) != INTEGER_CST)
for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain))
{
tree value = TREE_VALUE (chain);
+ if (TREE_CODE (value) == CONST_DECL)
+ value = DECL_INITIAL (value);
node = splay_tree_lookup (cases, (splay_tree_key) value);
if (node)
{
continue;
/* If there is a default_node, the only relevant option is
- Wswitch-enum. Otherwise, if both are enabled then we prefer
+ Wswitch-enum. Otherwise, if both are enabled then we prefer
to warn using -Wswitch because -Wswitch is enabled by -Wall
while -Wswitch-enum is explicit. */
- warning ((default_node || !warn_switch)
- ? OPT_Wswitch_enum : OPT_Wswitch,
- "%Henumeration value %qE not handled in switch",
- &switch_location, TREE_PURPOSE (chain));
+ warning_at (switch_location,
+ (default_node || !warn_switch
+ ? OPT_Wswitch_enum
+ : OPT_Wswitch),
+ "enumeration value %qE not handled in switch",
+ TREE_PURPOSE (chain));
}
/* Warn if there are case expressions that don't correspond to
every disjoint case label, with CASE_LOW_SEEN and CASE_HIGH_SEEN
above. This scan also resets those fields. */
- /* If there is a default_node, the only relevant option is
- Wswitch-enum. Otherwise, if both are enabled then we prefer
- to warn using -Wswitch because -Wswitch is enabled by -Wall
- while -Wswitch-enum is explicit. */
- saved_warn_switch = warn_switch;
- if (default_node)
- warn_switch = 0;
splay_tree_foreach (cases, match_case_to_enum, type);
- warn_switch = saved_warn_switch;
-
}
/* Finish an expression taking the address of LABEL (an
- IDENTIFIER_NODE). Returns an expression for the address. */
+ IDENTIFIER_NODE). Returns an expression for the address.
+
+ LOC is the location for the expression returned. */
tree
-finish_label_address_expr (tree label)
+finish_label_address_expr (tree label, location_t loc)
{
tree result;
- if (pedantic)
- pedwarn ("taking the address of a label is non-standard");
+ pedwarn (input_location, OPT_pedantic, "taking the address of a label is non-standard");
if (label == error_mark_node)
return error_mark_node;
/* The current function in not necessarily uninlinable.
Computed gotos are incompatible with inlining, but the value
here could be used only in a diagnostic, for example. */
+ protected_set_expr_location (result, loc);
}
return result;
}
-
-/* Hook used by expand_expr to expand language-specific tree codes. */
-/* The only things that should go here are bits needed to expand
- constant initializers. Everything else should be handled by the
- gimplification routines. */
-
-rtx
-c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
- int modifiera /* Actually enum expand_modifier. */,
- rtx *alt_rtl)
-{
- enum expand_modifier modifier = (enum expand_modifier) modifiera;
- switch (TREE_CODE (exp))
- {
- case COMPOUND_LITERAL_EXPR:
- {
- /* Initialize the anonymous variable declared in the compound
- literal, then return the variable. */
- tree decl = COMPOUND_LITERAL_EXPR_DECL (exp);
- emit_local_var (decl);
- return expand_expr_real (decl, target, tmode, modifier, alt_rtl);
- }
-
- default:
- gcc_unreachable ();
- }
-}
-
-/* Hook used by staticp to handle language-specific tree codes. */
-
-tree
-c_staticp (tree exp)
-{
- return (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
- && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp))
- ? exp : NULL);
-}
\f
/* Given a boolean expression ARG, return a tree representing an increment
break;
case PREDECREMENT_EXPR:
val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg,
- invert_truthvalue (arg));
+ invert_truthvalue_loc (input_location, arg));
break;
case POSTDECREMENT_EXPR:
val = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg,
- invert_truthvalue (arg));
+ invert_truthvalue_loc (input_location, arg));
arg = save_expr (arg);
val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
val = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
return val;
}
\f
-/* Built-in macros for stddef.h, that require macros defined in this
- file. */
+/* Built-in macros for stddef.h and stdint.h, that require macros
+ defined in this file. */
void
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);
+ if (SIG_ATOMIC_TYPE)
+ builtin_define_with_value ("__SIG_ATOMIC_TYPE__", SIG_ATOMIC_TYPE, 0);
+ if (INT8_TYPE)
+ builtin_define_with_value ("__INT8_TYPE__", INT8_TYPE, 0);
+ if (INT16_TYPE)
+ builtin_define_with_value ("__INT16_TYPE__", INT16_TYPE, 0);
+ if (INT32_TYPE)
+ builtin_define_with_value ("__INT32_TYPE__", INT32_TYPE, 0);
+ if (INT64_TYPE)
+ builtin_define_with_value ("__INT64_TYPE__", INT64_TYPE, 0);
+ if (UINT8_TYPE)
+ builtin_define_with_value ("__UINT8_TYPE__", UINT8_TYPE, 0);
+ if (UINT16_TYPE)
+ builtin_define_with_value ("__UINT16_TYPE__", UINT16_TYPE, 0);
+ if (UINT32_TYPE)
+ builtin_define_with_value ("__UINT32_TYPE__", UINT32_TYPE, 0);
+ if (UINT64_TYPE)
+ builtin_define_with_value ("__UINT64_TYPE__", UINT64_TYPE, 0);
+ if (INT_LEAST8_TYPE)
+ builtin_define_with_value ("__INT_LEAST8_TYPE__", INT_LEAST8_TYPE, 0);
+ if (INT_LEAST16_TYPE)
+ builtin_define_with_value ("__INT_LEAST16_TYPE__", INT_LEAST16_TYPE, 0);
+ if (INT_LEAST32_TYPE)
+ builtin_define_with_value ("__INT_LEAST32_TYPE__", INT_LEAST32_TYPE, 0);
+ if (INT_LEAST64_TYPE)
+ builtin_define_with_value ("__INT_LEAST64_TYPE__", INT_LEAST64_TYPE, 0);
+ if (UINT_LEAST8_TYPE)
+ builtin_define_with_value ("__UINT_LEAST8_TYPE__", UINT_LEAST8_TYPE, 0);
+ if (UINT_LEAST16_TYPE)
+ builtin_define_with_value ("__UINT_LEAST16_TYPE__", UINT_LEAST16_TYPE, 0);
+ if (UINT_LEAST32_TYPE)
+ builtin_define_with_value ("__UINT_LEAST32_TYPE__", UINT_LEAST32_TYPE, 0);
+ if (UINT_LEAST64_TYPE)
+ builtin_define_with_value ("__UINT_LEAST64_TYPE__", UINT_LEAST64_TYPE, 0);
+ if (INT_FAST8_TYPE)
+ builtin_define_with_value ("__INT_FAST8_TYPE__", INT_FAST8_TYPE, 0);
+ if (INT_FAST16_TYPE)
+ builtin_define_with_value ("__INT_FAST16_TYPE__", INT_FAST16_TYPE, 0);
+ if (INT_FAST32_TYPE)
+ builtin_define_with_value ("__INT_FAST32_TYPE__", INT_FAST32_TYPE, 0);
+ if (INT_FAST64_TYPE)
+ builtin_define_with_value ("__INT_FAST64_TYPE__", INT_FAST64_TYPE, 0);
+ if (UINT_FAST8_TYPE)
+ builtin_define_with_value ("__UINT_FAST8_TYPE__", UINT_FAST8_TYPE, 0);
+ if (UINT_FAST16_TYPE)
+ builtin_define_with_value ("__UINT_FAST16_TYPE__", UINT_FAST16_TYPE, 0);
+ if (UINT_FAST32_TYPE)
+ builtin_define_with_value ("__UINT_FAST32_TYPE__", UINT_FAST32_TYPE, 0);
+ if (UINT_FAST64_TYPE)
+ builtin_define_with_value ("__UINT_FAST64_TYPE__", UINT_FAST64_TYPE, 0);
+ if (INTPTR_TYPE)
+ builtin_define_with_value ("__INTPTR_TYPE__", INTPTR_TYPE, 0);
+ if (UINTPTR_TYPE)
+ builtin_define_with_value ("__UINTPTR_TYPE__", UINTPTR_TYPE, 0);
}
static void
}
else if (TREE_CODE (*node) == FIELD_DECL)
{
- if (TYPE_ALIGN (TREE_TYPE (*node)) <= BITS_PER_UNIT)
+ if (TYPE_ALIGN (TREE_TYPE (*node)) <= BITS_PER_UNIT
+ /* Still pack bitfields. */
+ && ! DECL_INITIAL (*node))
warning (OPT_Wattributes,
"%qE attribute ignored for field of type %qT",
name, TREE_TYPE (*node));
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)
{
name, "cold");
*no_add_attrs = true;
}
- /* Do nothing else, just set the attribute. We'll get at
- it later with lookup_attribute. */
+ /* Most of the rest of the hot processing is done later with
+ lookup_attribute. */
}
else
{
name, "hot");
*no_add_attrs = true;
}
- /* Do nothing else, just set the attribute. We'll get at
- it later with lookup_attribute. */
+ /* Most of the rest of the cold processing is done later with
+ lookup_attribute. */
}
else
{
return NULL_TREE;
}
+/* Handle a "noclone" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noclone_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "always_inline" attribute; arguments as in
struct attribute_spec.handler. */
int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree type = *node;
+ tree ident = TREE_VALUE (args);
*no_add_attrs = true;
- if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
+ if (TREE_CODE (ident) != IDENTIFIER_NODE)
warning (OPT_Wattributes, "%qE attribute ignored", name);
else
{
int j;
- const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
+ const char *p = IDENTIFIER_POINTER (ident);
int len = strlen (p);
enum machine_mode mode = VOIDmode;
tree typefm;
if (mode == VOIDmode)
{
- error ("unknown machine mode %qs", p);
+ error ("unknown machine mode %qE", ident);
return NULL_TREE;
}
&& current_function_decl != NULL_TREE
&& !TREE_STATIC (decl))
{
- error ("%Jsection attribute cannot be specified for "
- "local variables", decl);
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "section attribute cannot be specified for "
+ "local variables");
*no_add_attrs = true;
}
}
else
{
- error ("%Jsection attributes are not supported for this target", *node);
+ error_at (DECL_SOURCE_LOCATION (*node),
+ "section attributes are not supported for this target");
*no_add_attrs = true;
}
tree *type = NULL;
int is_type = 0;
tree align_expr = (args ? TREE_VALUE (args)
- : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+ : size_int (ATTRIBUTE_ALIGNED_VALUE / BITS_PER_UNIT));
int i;
if (DECL_P (*node))
error ("requested alignment is not a power of 2");
*no_add_attrs = true;
}
- else if (i > HOST_BITS_PER_INT - 2)
+ else if (i >= HOST_BITS_PER_INT - BITS_PER_UNIT_LOG)
{
error ("requested alignment is too large");
*no_add_attrs = true;
else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
*type = build_variant_type_copy (*type);
- TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
+ TYPE_ALIGN (*type) = (1U << i) * BITS_PER_UNIT;
TYPE_USER_ALIGN (*type) = 1;
}
else if (! VAR_OR_FUNCTION_DECL_P (decl)
*no_add_attrs = true;
}
else if (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_ALIGN (decl) > (1 << i) * BITS_PER_UNIT)
+ && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT)
{
if (DECL_USER_ALIGN (decl))
error ("alignment for %q+D was previously specified as %d "
}
else
{
- DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
+ DECL_ALIGN (decl) = (1U << i) * BITS_PER_UNIT;
DECL_USER_ALIGN (decl) = 1;
}
{
tree decl = *node;
- if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+ if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
|| (TREE_CODE (decl) != FUNCTION_DECL
&& TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
/* A static variable declaration is always a tentative definition,
/* We must ignore the attribute when it is associated with
local-scoped decls, since attribute alias is ignored and many
such symbols do not even have a DECL_WEAK field. */
- if (decl_function_context (*node) || current_function_decl)
+ if (decl_function_context (*node)
+ || current_function_decl
+ || (TREE_CODE (*node) != VAR_DECL && TREE_CODE (*node) != FUNCTION_DECL))
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
else
{
if (lookup_attribute ("alias", DECL_ATTRIBUTES (*node)))
- error ("%Jweakref attribute must appear before alias attribute",
- *node);
+ error_at (DECL_SOURCE_LOCATION (*node),
+ "weakref attribute must appear before alias attribute");
/* Can't call declare_weak because it wants this to be TREE_PUBLIC,
and that isn't supported; and because it wants to add it to
visibility_specified depending on #pragma GCC visibility. */
if (!DECL_VISIBILITY_SPECIFIED (decl))
{
- DECL_VISIBILITY (decl) = default_visibility;
- DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma;
+ if (visibility_options.inpragma
+ || DECL_VISIBILITY (decl) != default_visibility)
+ {
+ DECL_VISIBILITY (decl) = default_visibility;
+ DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma;
+ /* If visibility changed and DECL already has DECL_RTL, ensure
+ symbol flags are updated. */
+ if (((TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ && DECL_RTL_SET_P (decl))
+ make_decl_rtl (decl);
+ }
}
return false;
}
*no_add_attrs = true;
- if (!DECL_THREAD_LOCAL_P (decl))
+ if (TREE_CODE (decl) != VAR_DECL || !DECL_THREAD_LOCAL_P (decl))
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
return NULL_TREE;
if (TREE_CODE (decl) != FUNCTION_DECL)
{
- error ("%J%qE attribute applies only to functions", decl, name);
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute applies only to functions", name);
*no_add_attrs = true;
}
else if (DECL_INITIAL (decl))
{
- error ("%Jcan%'t set %qE attribute after definition", decl, name);
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "can%'t set %qE attribute after definition", name);
*no_add_attrs = true;
}
else
if (TREE_CODE (decl) != FUNCTION_DECL)
{
- error ("%J%qE attribute applies only to functions", decl, name);
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute applies only to functions", name);
*no_add_attrs = true;
}
else if (DECL_INITIAL (decl))
{
- error ("%Jcan%'t set %qE attribute after definition", decl, name);
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "can%'t set %qE attribute after definition", name);
*no_add_attrs = true;
}
else
static tree
handle_deprecated_attribute (tree *node, tree name,
- tree ARG_UNUSED (args), int flags,
+ tree args, int flags,
bool *no_add_attrs)
{
tree type = NULL_TREE;
int warn = 0;
tree what = NULL_TREE;
+ if (!args)
+ *no_add_attrs = true;
+ else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+ {
+ error ("deprecated message is not a string");
+ *no_add_attrs = true;
+ }
+
if (DECL_P (*node))
{
tree decl = *node;
|| (!SCALAR_FLOAT_MODE_P (orig_mode)
&& GET_MODE_CLASS (orig_mode) != MODE_INT
&& !ALL_SCALAR_FIXED_POINT_MODE_P (orig_mode))
- || !host_integerp (TYPE_SIZE_UNIT (type), 1))
+ || !host_integerp (TYPE_SIZE_UNIT (type), 1)
+ || TREE_CODE (type) == BOOLEAN_TYPE)
{
error ("invalid vector type for attribute %qE", name);
return NULL_TREE;
return NULL_TREE;
}
+
+/* Handle a "target" attribute. */
+
+static tree
+handle_target_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 (*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;
+ int saved_flag_strict_aliasing;
+ 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);
+
+ saved_flag_strict_aliasing = flag_strict_aliasing;
+
+ /* Now parse the options. */
+ decode_options (opt_argc, opt_argv);
+
+ /* Don't allow changing -fstrict-aliasing. */
+ flag_strict_aliasing = saved_flag_strict_aliasing;
+
+ 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;
+}
\f
/* Check for valid arguments being passed to a function.
ATTRS is a list of attributes. There are NARGS arguments in the array
TOKEN, which had the associated VALUE. */
void
-c_parse_error (const char *gmsgid, enum cpp_ttype token, tree value)
+c_parse_error (const char *gmsgid, enum cpp_ttype token_type,
+ tree value, unsigned char token_flags)
{
#define catenate_messages(M1, M2) catenate_strings ((M1), (M2), sizeof (M2))
char *message = NULL;
- if (token == CPP_EOF)
+ if (token_type == CPP_EOF)
message = catenate_messages (gmsgid, " at end of input");
- else if (token == CPP_CHAR || token == CPP_WCHAR || token == CPP_CHAR16
- || token == CPP_CHAR32)
+ else if (token_type == CPP_CHAR
+ || token_type == CPP_WCHAR
+ || token_type == CPP_CHAR16
+ || token_type == CPP_CHAR32)
{
unsigned int val = TREE_INT_CST_LOW (value);
const char *prefix;
- switch (token)
+ switch (token_type)
{
default:
prefix = "";
free (message);
message = NULL;
}
- else if (token == CPP_STRING || token == CPP_WSTRING || token == CPP_STRING16
- || token == CPP_STRING32)
+ else if (token_type == CPP_STRING
+ || token_type == CPP_WSTRING
+ || token_type == CPP_STRING16
+ || token_type == CPP_STRING32)
message = catenate_messages (gmsgid, " before string constant");
- else if (token == CPP_NUMBER)
+ else if (token_type == CPP_NUMBER)
message = catenate_messages (gmsgid, " before numeric constant");
- else if (token == CPP_NAME)
+ else if (token_type == CPP_NAME)
{
message = catenate_messages (gmsgid, " before %qE");
error (message, value);
free (message);
message = NULL;
}
- else if (token == CPP_PRAGMA)
+ else if (token_type == CPP_PRAGMA)
message = catenate_messages (gmsgid, " before %<#pragma%>");
- else if (token == CPP_PRAGMA_EOL)
+ else if (token_type == CPP_PRAGMA_EOL)
message = catenate_messages (gmsgid, " before end of line");
- else if (token < N_TTYPES)
+ else if (token_type < N_TTYPES)
{
message = catenate_messages (gmsgid, " before %qs token");
- error (message, cpp_type2name (token));
+ error (message, cpp_type2name (token_type, token_flags));
free (message);
message = NULL;
}
#undef catenate_messages
}
-/* Walk a gimplified function and warn for functions whose return value is
- ignored and attribute((warn_unused_result)) is set. This is done before
- inlining, so we don't have to worry about that. */
+/* Callback from cpp_error for PFILE to print diagnostics from the
+ preprocessor. The diagnostic is of type LEVEL, at location
+ LOCATION unless this is after lexing and the compiler's location
+ should be used instead, with column number possibly overridden by
+ COLUMN_OVERRIDE if not zero; MSG is the translated message and AP
+ the arguments. Returns true if a diagnostic was emitted, false
+ otherwise. */
-void
-c_warn_unused_result (tree *top_p)
+bool
+c_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level,
+ location_t location, unsigned int column_override,
+ const char *msg, va_list *ap)
{
- tree t = *top_p;
- tree_stmt_iterator i;
- tree fdecl, ftype;
+ diagnostic_info diagnostic;
+ diagnostic_t dlevel;
+ int save_warn_system_headers = warn_system_headers;
+ bool ret;
- switch (TREE_CODE (t))
+ switch (level)
{
- 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;
-
- case COND_EXPR:
- c_warn_unused_result (&COND_EXPR_THEN (t));
- c_warn_unused_result (&COND_EXPR_ELSE (t));
+ case CPP_DL_WARNING_SYSHDR:
+ if (flag_no_output)
+ return false;
+ warn_system_headers = 1;
+ /* Fall through. */
+ case CPP_DL_WARNING:
+ if (flag_no_output)
+ return false;
+ dlevel = DK_WARNING;
break;
- case BIND_EXPR:
- c_warn_unused_result (&BIND_EXPR_BODY (t));
+ case CPP_DL_PEDWARN:
+ if (flag_no_output && !flag_pedantic_errors)
+ return false;
+ dlevel = DK_PEDWARN;
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));
+ case CPP_DL_ERROR:
+ dlevel = DK_ERROR;
break;
- case CATCH_EXPR:
- c_warn_unused_result (&CATCH_BODY (t));
+ case CPP_DL_ICE:
+ dlevel = DK_ICE;
break;
- case EH_FILTER_EXPR:
- c_warn_unused_result (&EH_FILTER_FAILURE (t));
+ case CPP_DL_NOTE:
+ dlevel = DK_NOTE;
break;
-
- case CALL_EXPR:
- if (TREE_USED (t))
- 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);
- }
-
- 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));
- }
+ case CPP_DL_FATAL:
+ dlevel = DK_FATAL;
break;
-
default:
- /* Not a container, not a call, or a call whose value is used. */
- break;
+ gcc_unreachable ();
}
+ if (done_lexing)
+ location = input_location;
+ diagnostic_set_info_translated (&diagnostic, msg, ap,
+ location, dlevel);
+ if (column_override)
+ diagnostic_override_column (&diagnostic, column_override);
+ ret = report_diagnostic (&diagnostic);
+ if (level == CPP_DL_WARNING_SYSHDR)
+ warn_system_headers = save_warn_system_headers;
+ return ret;
}
/* Convert a character from the host to the target execution character
return error_mark_node;
case CALL_EXPR:
+ case TARGET_EXPR:
error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded");
return error_mark_node;
"member %qD", t);
return error_mark_node;
}
- off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
- size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), 1)
- / BITS_PER_UNIT));
+ off = size_binop_loc (input_location, PLUS_EXPR, DECL_FIELD_OFFSET (t),
+ size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t),
+ 1)
+ / BITS_PER_UNIT));
break;
case ARRAY_REF:
if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
{
code = MINUS_EXPR;
- t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t);
+ t = fold_build1_loc (input_location, NEGATE_EXPR, TREE_TYPE (t), t);
}
t = convert (sizetype, t);
off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
tree curindex;
unsigned HOST_WIDE_INT cnt;
constructor_elt *ce;
+ bool fold_p = false;
if (VEC_index (constructor_elt, v, 0)->index)
- maxindex = fold_convert (sizetype,
- VEC_index (constructor_elt,
- v, 0)->index);
+ maxindex = fold_convert_loc (input_location, sizetype,
+ VEC_index (constructor_elt,
+ v, 0)->index);
curindex = maxindex;
for (cnt = 1;
VEC_iterate (constructor_elt, v, cnt, ce);
cnt++)
{
+ bool curfold_p = false;
if (ce->index)
- curindex = fold_convert (sizetype, ce->index);
+ curindex = ce->index, curfold_p = true;
else
- curindex = size_binop (PLUS_EXPR, curindex, size_one_node);
-
+ {
+ if (fold_p)
+ curindex = fold_convert (sizetype, curindex);
+ curindex = size_binop (PLUS_EXPR, curindex,
+ size_one_node);
+ }
if (tree_int_cst_lt (maxindex, curindex))
- maxindex = curindex;
+ maxindex = curindex, fold_p = curfold_p;
}
+ if (fold_p)
+ maxindex = fold_convert (sizetype, maxindex);
}
}
else
Returns 0 if an error is encountered. */
static int
-sync_resolve_size (tree function, tree params)
+sync_resolve_size (tree function, VEC(tree,gc) *params)
{
tree type;
int size;
- if (params == NULL)
+ if (VEC_empty (tree, params))
{
error ("too few arguments to function %qE", function);
return 0;
}
- type = TREE_TYPE (TREE_VALUE (params));
+ type = TREE_TYPE (VEC_index (tree, params, 0));
if (TREE_CODE (type) != POINTER_TYPE)
goto incompatible;
was encountered; true on success. */
static bool
-sync_resolve_params (tree orig_function, tree function, tree params)
+sync_resolve_params (tree orig_function, tree function, VEC(tree, gc) *params)
{
tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
tree ptype;
int number;
+ unsigned int parmnum;
/* We've declared the implementation functions to use "volatile void *"
as the pointer parameter, so we shouldn't get any complaints from the
call to check_function_arguments what ever type the user used. */
arg_types = TREE_CHAIN (arg_types);
- ptype = TREE_TYPE (TREE_TYPE (TREE_VALUE (params)));
+ ptype = TREE_TYPE (TREE_TYPE (VEC_index (tree, params, 0)));
number = 2;
/* For the rest of the values, we need to cast these to FTYPE, so that we
don't get warnings for passing pointer types, etc. */
+ parmnum = 0;
while (arg_types != void_list_node)
{
tree val;
- params = TREE_CHAIN (params);
- if (params == NULL)
+ ++parmnum;
+ if (VEC_length (tree, params) <= parmnum)
{
error ("too few arguments to function %qE", orig_function);
return false;
/* ??? Ideally for the first conversion we'd use convert_for_assignment
so that we get warnings for anything that doesn't match the pointer
type. This isn't portable across the C and C++ front ends atm. */
- val = TREE_VALUE (params);
+ val = VEC_index (tree, params, parmnum);
val = convert (ptype, val);
val = convert (TREE_VALUE (arg_types), val);
- TREE_VALUE (params) = val;
+ VEC_replace (tree, params, parmnum, val);
arg_types = TREE_CHAIN (arg_types);
number++;
being "an optional list of variables protected by the memory barrier".
No clue what that's supposed to mean, precisely, but we consider all
call-clobbered variables to be protected so we're safe. */
- TREE_CHAIN (params) = NULL;
+ VEC_truncate (tree, params, parmnum + 1);
return true;
}
PARAMS. */
static tree
-sync_resolve_return (tree params, tree result)
+sync_resolve_return (tree first_param, tree result)
{
- tree ptype = TREE_TYPE (TREE_TYPE (TREE_VALUE (params)));
+ tree ptype = TREE_TYPE (TREE_TYPE (first_param));
ptype = TYPE_MAIN_VARIANT (ptype);
return convert (ptype, result);
}
function should be called immediately after parsing the call expression
before surrounding code has committed to the type of the expression.
+ LOC is the location of the builtin call.
+
FUNCTION is the DECL that has been invoked; it is known to be a builtin.
PARAMS is the argument list for the call. The return value is non-null
when expansion is complete, and null if normal processing should
continue. */
tree
-resolve_overloaded_builtin (tree function, tree params)
+resolve_overloaded_builtin (location_t loc, tree function, VEC(tree,gc) *params)
{
enum built_in_function orig_code = DECL_FUNCTION_CODE (function);
switch (DECL_BUILT_IN_CLASS (function))
break;
case BUILT_IN_MD:
if (targetm.resolve_overloaded_builtin)
- return targetm.resolve_overloaded_builtin (function, params);
+ return targetm.resolve_overloaded_builtin (loc, function, params);
else
return NULL_TREE;
default:
case BUILT_IN_LOCK_RELEASE_N:
{
int n = sync_resolve_size (function, params);
- tree new_function, result;
+ tree new_function, first_param, result;
if (n == 0)
return error_mark_node;
if (!sync_resolve_params (function, new_function, params))
return error_mark_node;
- result = build_function_call (new_function, params);
+ first_param = VEC_index (tree, params, 0);
+ result = build_function_call_vec (loc, new_function, params, NULL);
if (orig_code != BUILT_IN_BOOL_COMPARE_AND_SWAP_N
&& orig_code != BUILT_IN_LOCK_RELEASE_N)
- result = sync_resolve_return (params, result);
+ result = sync_resolve_return (first_param, result);
return result;
}
/* Implement -Wparentheses for the unexpected C precedence rules, to
cover cases like x + y << z which readers are likely to
misinterpret. We have seen an expression in which CODE is a binary
- operator used to combine expressions headed by CODE_LEFT and
- CODE_RIGHT. CODE_LEFT and CODE_RIGHT may be ERROR_MARK, which
- means that that side of the expression was not formed using a
- binary operator, or it was enclosed in parentheses. */
+ operator used to combine expressions ARG_LEFT and ARG_RIGHT, which
+ before folding had CODE_LEFT and CODE_RIGHT. CODE_LEFT and
+ CODE_RIGHT may be ERROR_MARK, which means that that side of the
+ expression was not formed using a binary or unary operator, or it
+ was enclosed in parentheses. */
void
-warn_about_parentheses (enum tree_code code, enum tree_code code_left,
- enum tree_code code_right)
+warn_about_parentheses (enum tree_code code,
+ enum tree_code code_left, tree arg_left,
+ enum tree_code code_right, tree arg_right)
{
if (!warn_parentheses)
return;
- if (code == LSHIFT_EXPR || code == RSHIFT_EXPR)
+ /* This macro tests that the expression ARG with original tree code
+ CODE appears to be a boolean expression. or the result of folding a
+ boolean expression. */
+#define APPEARS_TO_BE_BOOLEAN_EXPR_P(CODE, ARG) \
+ (truth_value_p (TREE_CODE (ARG)) \
+ || TREE_CODE (TREE_TYPE (ARG)) == BOOLEAN_TYPE \
+ /* Folding may create 0 or 1 integers from other expressions. */ \
+ || ((CODE) != INTEGER_CST \
+ && (integer_onep (ARG) || integer_zerop (ARG))))
+
+ switch (code)
{
- if (code_left == PLUS_EXPR || code_left == MINUS_EXPR
- || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
+ case LSHIFT_EXPR:
+ if (code_left == PLUS_EXPR || code_right == PLUS_EXPR)
warning (OPT_Wparentheses,
- "suggest parentheses around + or - inside shift");
- }
+ "suggest parentheses around %<+%> inside %<<<%>");
+ else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR)
+ warning (OPT_Wparentheses,
+ "suggest parentheses around %<-%> inside %<<<%>");
+ return;
- if (code == TRUTH_ORIF_EXPR)
- {
- if (code_left == TRUTH_ANDIF_EXPR
- || code_right == TRUTH_ANDIF_EXPR)
+ case RSHIFT_EXPR:
+ if (code_left == PLUS_EXPR || code_right == PLUS_EXPR)
warning (OPT_Wparentheses,
- "suggest parentheses around && within ||");
- }
+ "suggest parentheses around %<+%> inside %<>>%>");
+ else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR)
+ warning (OPT_Wparentheses,
+ "suggest parentheses around %<-%> inside %<>>%>");
+ return;
- if (code == BIT_IOR_EXPR)
- {
+ case TRUTH_ORIF_EXPR:
+ if (code_left == TRUTH_ANDIF_EXPR || code_right == TRUTH_ANDIF_EXPR)
+ warning (OPT_Wparentheses,
+ "suggest parentheses around %<&&%> within %<||%>");
+ return;
+
+ case BIT_IOR_EXPR:
if (code_left == BIT_AND_EXPR || code_left == BIT_XOR_EXPR
|| code_left == PLUS_EXPR || code_left == MINUS_EXPR
|| code_right == BIT_AND_EXPR || code_right == BIT_XOR_EXPR
|| code_right == PLUS_EXPR || code_right == MINUS_EXPR)
warning (OPT_Wparentheses,
- "suggest parentheses around arithmetic in operand of |");
+ "suggest parentheses around arithmetic in operand of %<|%>");
/* Check cases like x|y==z */
- if (TREE_CODE_CLASS (code_left) == tcc_comparison
- || TREE_CODE_CLASS (code_right) == tcc_comparison)
+ else if (TREE_CODE_CLASS (code_left) == tcc_comparison
+ || TREE_CODE_CLASS (code_right) == tcc_comparison)
warning (OPT_Wparentheses,
- "suggest parentheses around comparison in operand of |");
- }
+ "suggest parentheses around comparison in operand of %<|%>");
+ /* Check cases like !x | y */
+ else if (code_left == TRUTH_NOT_EXPR
+ && !APPEARS_TO_BE_BOOLEAN_EXPR_P (code_right, arg_right))
+ warning (OPT_Wparentheses, "suggest parentheses around operand of "
+ "%<!%> or change %<|%> to %<||%> or %<!%> to %<~%>");
+ return;
- if (code == BIT_XOR_EXPR)
- {
+ case BIT_XOR_EXPR:
if (code_left == BIT_AND_EXPR
|| code_left == PLUS_EXPR || code_left == MINUS_EXPR
|| code_right == BIT_AND_EXPR
|| code_right == PLUS_EXPR || code_right == MINUS_EXPR)
warning (OPT_Wparentheses,
- "suggest parentheses around arithmetic in operand of ^");
+ "suggest parentheses around arithmetic in operand of %<^%>");
/* Check cases like x^y==z */
- if (TREE_CODE_CLASS (code_left) == tcc_comparison
- || TREE_CODE_CLASS (code_right) == tcc_comparison)
+ else if (TREE_CODE_CLASS (code_left) == tcc_comparison
+ || TREE_CODE_CLASS (code_right) == tcc_comparison)
warning (OPT_Wparentheses,
- "suggest parentheses around comparison in operand of ^");
- }
+ "suggest parentheses around comparison in operand of %<^%>");
+ return;
- if (code == BIT_AND_EXPR)
- {
- if (code_left == PLUS_EXPR || code_left == MINUS_EXPR
- || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
+ case BIT_AND_EXPR:
+ if (code_left == PLUS_EXPR || code_right == PLUS_EXPR)
+ warning (OPT_Wparentheses,
+ "suggest parentheses around %<+%> in operand of %<&%>");
+ else if (code_left == MINUS_EXPR || code_right == MINUS_EXPR)
warning (OPT_Wparentheses,
- "suggest parentheses around + or - in operand of &");
+ "suggest parentheses around %<-%> in operand of %<&%>");
/* Check cases like x&y==z */
- if (TREE_CODE_CLASS (code_left) == tcc_comparison
- || TREE_CODE_CLASS (code_right) == tcc_comparison)
+ else if (TREE_CODE_CLASS (code_left) == tcc_comparison
+ || TREE_CODE_CLASS (code_right) == tcc_comparison)
warning (OPT_Wparentheses,
- "suggest parentheses around comparison in operand of &");
- }
+ "suggest parentheses around comparison in operand of %<&%>");
+ /* Check cases like !x & y */
+ else if (code_left == TRUTH_NOT_EXPR
+ && !APPEARS_TO_BE_BOOLEAN_EXPR_P (code_right, arg_right))
+ warning (OPT_Wparentheses, "suggest parentheses around operand of "
+ "%<!%> or change %<&%> to %<&&%> or %<!%> to %<~%>");
+ return;
- if (code == EQ_EXPR || code == NE_EXPR)
- {
+ case EQ_EXPR:
if (TREE_CODE_CLASS (code_left) == tcc_comparison
|| TREE_CODE_CLASS (code_right) == tcc_comparison)
warning (OPT_Wparentheses,
- "suggest parentheses around comparison in operand of %s",
- code == EQ_EXPR ? "==" : "!=");
- }
- else if (TREE_CODE_CLASS (code) == tcc_comparison)
- {
- if ((TREE_CODE_CLASS (code_left) == tcc_comparison
- && code_left != NE_EXPR && code_left != EQ_EXPR)
- || (TREE_CODE_CLASS (code_right) == tcc_comparison
- && code_right != NE_EXPR && code_right != EQ_EXPR))
- warning (OPT_Wparentheses, "comparisons like X<=Y<=Z do not "
+ "suggest parentheses around comparison in operand of %<==%>");
+ return;
+ case NE_EXPR:
+ if (TREE_CODE_CLASS (code_left) == tcc_comparison
+ || TREE_CODE_CLASS (code_right) == tcc_comparison)
+ warning (OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of %<!=%>");
+ return;
+
+ default:
+ if (TREE_CODE_CLASS (code) == tcc_comparison
+ && ((TREE_CODE_CLASS (code_left) == tcc_comparison
+ && code_left != NE_EXPR && code_left != EQ_EXPR
+ && INTEGRAL_TYPE_P (TREE_TYPE (arg_left)))
+ || (TREE_CODE_CLASS (code_right) == tcc_comparison
+ && code_right != NE_EXPR && code_right != EQ_EXPR
+ && INTEGRAL_TYPE_P (TREE_TYPE (arg_right)))))
+ warning (OPT_Wparentheses, "comparisons like %<X<=Y<=Z%> do not "
"have their mathematical meaning");
+ return;
}
+#undef NOT_A_BOOLEAN_EXPR_P
}
/* If LABEL (a LABEL_DECL) has not been used, issue a warning. */
struct gcc_targetcm targetcm = TARGETCM_INITIALIZER;
#endif
-/* Warn for division by zero according to the value of DIVISOR. */
+/* Warn for division by zero according to the value of DIVISOR. LOC
+ is the location of the division operator. */
void
-warn_for_div_by_zero (tree divisor)
+warn_for_div_by_zero (location_t loc, tree divisor)
{
/* If DIVISOR is zero, and has integral or fixed-point type, issue a warning
about division by zero. Do not issue a warning if DIVISOR has a
floating-point type, since we consider 0.0/0.0 a valid way of
generating a NaN. */
- if (skip_evaluation == 0
+ if (c_inhibit_evaluation_warnings == 0
&& (integer_zerop (divisor) || fixed_zerop (divisor)))
- warning (OPT_Wdiv_by_zero, "division by zero");
+ warning_at (loc, 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.
+
+ LOCATION is the location of the comparison operator.
+
+ The arguments of this function map directly to local variables
+ of build_binary_op. */
+
+void
+warn_for_sign_compare (location_t location,
+ 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_at (location,
+ 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, base_type;
+ 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);
+ base_type = (TREE_CODE (result_type) == COMPLEX_TYPE
+ ? TREE_TYPE (result_type) : result_type);
+
+ /* 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 (base_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 (base_type)))
+ /* OK */;
+ else
+ warning_at (location,
+ 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_at (location, 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_at (location, OPT_Wsign_compare,
+ "comparison of promoted ~unsigned with unsigned");
+ }
+}
+
+/* Setup a TYPE_DECL node as a typedef representation.
+
+ X is a TYPE_DECL for a typedef statement. Create a brand new
+ ..._TYPE node (which will be just a variant of the existing
+ ..._TYPE node with identical properties) and then install X
+ as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
+
+ The whole point here is to end up with a situation where each
+ and every ..._TYPE node the compiler creates will be uniquely
+ associated with AT MOST one node representing a typedef name.
+ This way, even though the compiler substitutes corresponding
+ ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
+ early on, later parts of the compiler can always do the reverse
+ translation and get back the corresponding typedef name. For
+ example, given:
+
+ typedef struct S MY_TYPE;
+ MY_TYPE object;
+
+ Later parts of the compiler might only know that `object' was of
+ type `struct S' if it were not for code just below. With this
+ code however, later parts of the compiler see something like:
+
+ struct S' == struct S
+ typedef struct S' MY_TYPE;
+ struct S' object;
+
+ And they can then deduce (from the node for type struct S') that
+ the original object declaration was:
+
+ MY_TYPE object;
+
+ Being able to do this is important for proper support of protoize,
+ and also for generating precise symbolic debugging information
+ which takes full account of the programmer's (typedef) vocabulary.
+
+ Obviously, we don't want to generate a duplicate ..._TYPE node if
+ the TYPE_DECL node that we are now processing really represents a
+ standard built-in type. */
+
+void
+set_underlying_type (tree x)
+{
+ if (x == error_mark_node)
+ return;
+ if (DECL_IS_BUILTIN (x))
+ {
+ if (TYPE_NAME (TREE_TYPE (x)) == 0)
+ TYPE_NAME (TREE_TYPE (x)) = x;
+ }
+ else if (TREE_TYPE (x) != error_mark_node
+ && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
+ {
+ tree tt = TREE_TYPE (x);
+ DECL_ORIGINAL_TYPE (x) = tt;
+ tt = build_variant_type_copy (tt);
+ TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
+ TYPE_NAME (tt) = x;
+ TREE_USED (tt) = TREE_USED (x);
+ TREE_TYPE (x) = tt;
+ }
+}
+
+/* Returns true if X is a typedef decl. */
+
+bool
+is_typedef_decl (tree x)
+{
+ return (x && TREE_CODE (x) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (x) != NULL_TREE);
+}
+
+/* The C and C++ parsers both use vectors to hold function arguments.
+ For efficiency, we keep a cache of unused vectors. This is the
+ cache. */
+
+typedef VEC(tree,gc)* tree_gc_vec;
+DEF_VEC_P(tree_gc_vec);
+DEF_VEC_ALLOC_P(tree_gc_vec,gc);
+static GTY((deletable)) VEC(tree_gc_vec,gc) *tree_vector_cache;
+
+/* Return a new vector from the cache. If the cache is empty,
+ allocate a new vector. These vectors are GC'ed, so it is OK if the
+ pointer is not released.. */
+
+VEC(tree,gc) *
+make_tree_vector (void)
+{
+ if (!VEC_empty (tree_gc_vec, tree_vector_cache))
+ return VEC_pop (tree_gc_vec, tree_vector_cache);
+ else
+ {
+ /* Passing 0 to VEC_alloc returns NULL, and our callers require
+ that we always return a non-NULL value. The vector code uses
+ 4 when growing a NULL vector, so we do too. */
+ return VEC_alloc (tree, gc, 4);
+ }
+}
+
+/* Release a vector of trees back to the cache. */
+
+void
+release_tree_vector (VEC(tree,gc) *vec)
+{
+ if (vec != NULL)
+ {
+ VEC_truncate (tree, vec, 0);
+ VEC_safe_push (tree_gc_vec, gc, tree_vector_cache, vec);
+ }
+}
+
+/* Get a new tree vector holding a single tree. */
+
+VEC(tree,gc) *
+make_tree_vector_single (tree t)
+{
+ VEC(tree,gc) *ret = make_tree_vector ();
+ VEC_quick_push (tree, ret, t);
+ return ret;
+}
+
+/* Get a new tree vector which is a copy of an existing one. */
+
+VEC(tree,gc) *
+make_tree_vector_copy (const VEC(tree,gc) *orig)
+{
+ VEC(tree,gc) *ret;
+ unsigned int ix;
+ tree t;
+
+ ret = make_tree_vector ();
+ VEC_reserve (tree, gc, ret, VEC_length (tree, orig));
+ for (ix = 0; VEC_iterate (tree, orig, ix, t); ++ix)
+ VEC_quick_push (tree, ret, t);
+ return ret;
}
#include "gt-c-common.h"