#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 "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_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;
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 *);
{
{ "_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 },
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 },
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;
+
+ /* 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 (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);
+
+ /* 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 (code, TREE_TYPE (expr), op0, op1)
+ : fold_build2 (code, TREE_TYPE (expr), op0, op1);
+ else
+ ret = fold (expr);
+ 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 (code, TREE_TYPE (expr), op0)
+ : fold_build1 (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);
+ }
+ 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);
+ op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
+ if (op0 != orig_op0 || op1 != orig_op1 || in_init)
+ ret = in_init
+ ? fold_build2_initializer (code, TREE_TYPE (expr), op0, op1)
+ : fold_build2 (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);
+ op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
+ op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self);
+ if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2)
+ ret = fold_build3 (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.
}
}
+/* 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 (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)
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;
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);
+ 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_at (EXPR_HAS_LOCATION (writer)
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 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. */
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 (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 (location,
- TREE_OPERAND (expr, 1)),
- c_common_truthvalue_conversion (location,
- TREE_OPERAND (expr, 2)));
+ if (c_dialect_cxx ())
+ return fold_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)));
+ else
+ /* Folding will happen later for C. */
+ return 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)));
CASE_CONVERT:
/* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
{
- tree t = save_expr (expr);
+ tree t = c_save_expr (expr);
return (build_binary_op
(EXPR_LOCATION (expr),
(TREE_SIDE_EFFECTS (expr)
tree fixed_zero_node = build_fixed (TREE_TYPE (expr),
FCONST0 (TYPE_MODE
(TREE_TYPE (expr))));
- return build_binary_op (EXPR_LOCATION (expr),
- NE_EXPR, expr, fixed_zero_node, 1);
+ return build_binary_op (location, NE_EXPR, expr, fixed_zero_node, 1);
}
- return build_binary_op (EXPR_LOCATION (expr),
- NE_EXPR, expr, integer_zero_node, 1);
+ return build_binary_op (location, NE_EXPR, expr, integer_zero_node, 1);
}
\f
static void def_builtin_1 (enum built_in_function fncode,
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. */
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)));
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. */
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;
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)
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
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
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 ("__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
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;
}
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;
}
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;
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
}
+/* 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. */
+
+bool
+c_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level,
+ location_t location, unsigned int column_override,
+ const char *msg, va_list *ap)
+{
+ diagnostic_info diagnostic;
+ diagnostic_t dlevel;
+ int save_warn_system_headers = warn_system_headers;
+ bool ret;
+
+ switch (level)
+ {
+ 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 CPP_DL_PEDWARN:
+ if (flag_no_output && !flag_pedantic_errors)
+ return false;
+ dlevel = DK_PEDWARN;
+ break;
+ case CPP_DL_ERROR:
+ dlevel = DK_ERROR;
+ break;
+ case CPP_DL_ICE:
+ dlevel = DK_ICE;
+ break;
+ case CPP_DL_NOTE:
+ dlevel = DK_NOTE;
+ break;
+ case CPP_DL_FATAL:
+ dlevel = DK_FATAL;
+ break;
+ default:
+ 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;
+}
+
/* 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. */
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);
}
continue. */
tree
-resolve_overloaded_builtin (tree function, tree params)
+resolve_overloaded_builtin (tree function, VEC(tree,gc) *params)
{
enum built_in_function orig_code = DECL_FUNCTION_CODE (function);
switch (DECL_BUILT_IN_CLASS (function))
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 (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;
}
}
}
+/* 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"