#include "c-lex.h"
#include "c-tree.h"
#include "flags.h"
+#include "obstack.h"
#include <stdio.h>
-#undef NULL
-#define NULL 0
+extern struct obstack permanent_obstack;
/* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
void
declare_function_name ()
{
- tree decl, init;
+ tree decl, type, init;
char *name, *printable_name;
+ int len;
if (current_function_decl == NULL)
{
char *kind = "function";
if (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE)
kind = "method";
- name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
+ /* Allow functions to be nameless (such as artificial ones). */
+ if (DECL_NAME (current_function_decl))
+ name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
+ else
+ name = "";
printable_name = (*decl_printable_name) (current_function_decl, &kind);
}
+ /* If the default size of char arrays isn't big enough for the name,
+ make a bigger one. */
+ len = strlen (name) + 1;
+ type = char_array_type_node;
+ if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TREE_TYPE (char_array_type_node)))
+ < len)
+ type = build_array_type (char_type_node,
+ build_index_type (build_int_2 (len, 0)));
+
push_obstacks_nochange ();
- decl = build_decl (VAR_DECL, get_identifier ("__FUNCTION__"),
- char_array_type_node);
+ decl = build_decl (VAR_DECL, get_identifier ("__FUNCTION__"), type);
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
+ DECL_SOURCE_LINE (decl) = 0;
DECL_IN_SYSTEM_HEADER (decl) = 1;
DECL_IGNORED_P (decl) = 1;
- init = build_string (strlen (name) + 1, name);
- TREE_TYPE (init) = char_array_type_node;
+ init = build_string (len, name);
+ TREE_TYPE (init) = type;
DECL_INITIAL (decl) = init;
finish_decl (pushdecl (decl), init, NULL_TREE);
+ len = strlen (printable_name) + 1;
+ type = char_array_type_node;
+ if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TREE_TYPE (char_array_type_node)))
+ < len)
+ type = build_array_type (char_type_node,
+ build_index_type (build_int_2 (len, 0)));
+
push_obstacks_nochange ();
- decl = build_decl (VAR_DECL, get_identifier ("__PRETTY_FUNCTION__"),
- char_array_type_node);
+ decl = build_decl (VAR_DECL, get_identifier ("__PRETTY_FUNCTION__"), type);
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
+ DECL_SOURCE_LINE (decl) = 0;
DECL_IN_SYSTEM_HEADER (decl) = 1;
DECL_IGNORED_P (decl) = 1;
- init = build_string (strlen (printable_name) + 1, printable_name);
- TREE_TYPE (init) = char_array_type_node;
+ init = build_string (len, printable_name);
+ TREE_TYPE (init) = type;
DECL_INITIAL (decl) = init;
finish_decl (pushdecl (decl), init, NULL_TREE);
}
if (TREE_CODE (decl) == FIELD_DECL)
DECL_PACKED (decl) = 1;
/* We can't set DECL_PACKED for a VAR_DECL, because the bit is
- used for TREE_REGDECL. It wouldn't mean anything anyway. */
+ used for DECL_REGISTER. It wouldn't mean anything anyway. */
}
else if (TREE_VALUE (a) != 0
&& TREE_CODE (TREE_VALUE (a)) == TREE_LIST
{
TREE_TYPE (decl) = type;
DECL_SIZE (decl) = 0;
- layout_decl (decl);
+ layout_decl (decl, 0);
}
else
error ("no data type for mode `%s'", specified_name);
int format_num = TREE_INT_CST_LOW (TREE_PURPOSE (TREE_VALUE (list)));
int first_arg_num = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (list)));
int is_scan;
+ tree argument;
+ int arg_num;
if (TREE_CODE (decl) != FUNCTION_DECL)
{
"format string arg follows the args to be formatted, for `%s'");
return;
}
+
+ /* Verify that the format_num argument is actually a string, in case
+ the format attribute is in error. */
+ argument = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ for (arg_num = 1; ; ++arg_num)
+ {
+ if (argument == 0 || arg_num == format_num)
+ break;
+ argument = TREE_CHAIN (argument);
+ }
+ if (! argument
+ || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
+ != char_type_node))
+ {
+ error_with_decl (decl,
+ "format string arg not a string type, for `%s'");
+ return;
+ }
+ /* Verify that first_arg_num points to the last argument, the ... */
+ while (argument)
+ arg_num++, argument = TREE_CHAIN (argument);
+ if (arg_num != first_arg_num)
+ {
+ error_with_decl (decl,
+ "args to be formatted is not ..., for `%s'");
+ return;
+ }
record_format_info (DECL_NAME (decl), is_scan, format_num,
first_arg_num);
}
}
\f
+/* 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.
+ Note the ANSI C standard says it is erroneous for a
+ constant expression to overflow. */
+
+void
+constant_expression_warning (value)
+ tree value;
+{
+ if (TREE_CODE (value) == INTEGER_CST && TREE_CONSTANT_OVERFLOW (value))
+ {
+ pedwarn ("overflow in constant expression");
+ /* Suppress duplicate warnings. */
+ TREE_CONSTANT_OVERFLOW (value) = 0;
+ }
+}
+
+/* Print a warning if an expression had overflow in folding.
+ Invoke this function on every expression that
+ (1) appears in the source code, and
+ (2) might be a constant expression that overflowed, and
+ (3) is not already checked by convert_and_check;
+ however, do not invoke this function on operands of explicit casts. */
+
+void
+overflow_warning (value)
+ tree value;
+{
+ if (TREE_CODE (value) == INTEGER_CST && TREE_CONSTANT_OVERFLOW (value))
+ {
+ pedwarn ("integer overflow in expression");
+ TREE_CONSTANT_OVERFLOW (value) = 0;
+ }
+}
+
+/* Print a warning if a large constant is truncated to unsigned,
+ or if -Wconversion is used and a constant < 0 is converted to unsigned.
+ Invoke this function on every expression that might be implicitly
+ converted to an unsigned type. */
+
+void
+unsigned_conversion_warning (result, operand)
+ tree result, operand;
+{
+ if (TREE_CODE (operand) == INTEGER_CST
+ && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
+ && TREE_UNSIGNED (TREE_TYPE (result))
+ && !int_fits_type_p (operand, TREE_TYPE (result)))
+ {
+ if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
+ /* This detects cases like converting -129 or 256 to unsigned char. */
+ pedwarn ("large integer implicitly truncated to unsigned type");
+ else if (warn_conversion)
+ pedwarn ("negative integer implicitly converted to unsigned type");
+ }
+}
+
+/* Convert EXPR to TYPE, warning about conversion problems with constants.
+ Invoke this function on every expression that is converted implicitly,
+ i.e. because of language rules and not because of an explicit cast. */
+
+tree
+convert_and_check (type, expr)
+ tree type, expr;
+{
+ tree t = convert (type, expr);
+ if (TREE_CODE (t) == INTEGER_CST)
+ {
+ if (TREE_UNSIGNED (TREE_TYPE (expr))
+ && !TREE_UNSIGNED (type)
+ && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+ && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr)))
+ /* No warning for converting 0x80000000 to int. */
+ TREE_CONSTANT_OVERFLOW (t) = 0;
+ else if (TREE_CONSTANT_OVERFLOW (t))
+ {
+ pedwarn ("overflow in implicit constant conversion");
+ TREE_CONSTANT_OVERFLOW (t) = 0;
+ }
+ else
+ unsigned_conversion_warning (t, expr);
+ }
+ return t;
+}
+\f
void
c_expand_expr_stmt (expr)
tree expr;
return value;
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- if (TREE_CODE (value) == NON_LVALUE_EXPR)
- value = TREE_OPERAND (value, 0);
+ STRIP_TYPE_NOPS (value);
if (TREE_CODE (value) != INTEGER_CST
&& value != error_mark_node)
/* Promote char or short to int. */
value = default_conversion (value);
+ constant_expression_warning (value);
+
return value;
}
\f
TYPE is already properly set. */
}
else if (real1 && real2
- && TYPE_PRECISION (TREE_TYPE (primop0)) == TYPE_PRECISION (TREE_TYPE (primop1)))
+ && (TYPE_PRECISION (TREE_TYPE (primop0))
+ == TYPE_PRECISION (TREE_TYPE (primop1))))
type = TREE_TYPE (primop0);
/* If args' natural types are both narrower than nominal type
{
register enum tree_code code;
+ if (TREE_CODE (expr) == ERROR_MARK)
+ return expr;
+
+#if 0 /* This appears to be wrong for C++. */
+ /* These really should return error_mark_node after 2.4 is stable.
+ But not all callers handle ERROR_MARK properly. */
+ switch (TREE_CODE (TREE_TYPE (expr)))
+ {
+ case RECORD_TYPE:
+ error ("struct type value used where scalar is required");
+ return integer_zero_node;
+
+ case UNION_TYPE:
+ error ("union type value used where scalar is required");
+ return integer_zero_node;
+
+ case ARRAY_TYPE:
+ error ("array type value used where scalar is required");
+ return integer_zero_node;
+
+ default:
+ break;
+ }
+#endif /* 0 */
+
switch (TREE_CODE (expr))
{
/* It is simpler and generates better code to have only TRUTH_*_EXPR
case TRUTH_ORIF_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
case ERROR_MARK:
return expr;
else
return integer_one_node;
+ case COMPLEX_EXPR:
+ return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
+ ? TRUTH_AND_EXPR : TRUTH_ANDIF_EXPR),
+ truthvalue_conversion (TREE_OPERAND (expr, 0)),
+ truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ 0);
+
case NEGATE_EXPR:
case ABS_EXPR:
case FLOAT_EXPR:
return truthvalue_conversion (TREE_OPERAND (expr, 0));
break;
- case BIT_XOR_EXPR:
case MINUS_EXPR:
- /* These can be changed into a comparison of the two objects. */
+ /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize
+ this case. */
+ if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+ && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+ break;
+ /* fall through... */
+ case BIT_XOR_EXPR:
+ /* This and MINUS_EXPR can be changed into a comparison of the
+ two objects. */
if (TREE_TYPE (TREE_OPERAND (expr, 0))
== TREE_TYPE (TREE_OPERAND (expr, 1)))
return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
fold (build1 (NOP_EXPR,
TREE_TYPE (TREE_OPERAND (expr, 0)),
TREE_OPERAND (expr, 1))), 1);
+
+ case MODIFY_EXPR:
+ if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
+ warning ("suggest parentheses around assignment used as truth value");
+ break;
}
+ if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
+ return (build_binary_op
+ ((TREE_SIDE_EFFECTS (expr)
+ ? TRUTH_AND_EXPR : TRUTH_ANDIF_EXPR),
+ truthvalue_conversion (build_unary_op (REALPART_EXPR, expr, 0)),
+ truthvalue_conversion (build_unary_op (IMAGPART_EXPR, expr, 0)),
+ 0));
+
return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
}
\f
char_escaped = (c == '\\' && ! char_escaped);
}
}
+\f
+/* Make a variant type in the proper way for C/C++, propagating qualifiers
+ down to the element type of an array. */
+
+tree
+c_build_type_variant (type, constp, volatilep)
+ tree type;
+ int constp, volatilep;
+{
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree real_main_variant = TYPE_MAIN_VARIANT (type);
+ int permanent = TREE_PERMANENT (type);
+
+ if (permanent)
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ type = build_array_type (c_build_type_variant (TREE_TYPE (type),
+ constp, volatilep),
+ TYPE_DOMAIN (type));
+ TYPE_MAIN_VARIANT (type) = real_main_variant;
+ if (permanent)
+ pop_obstacks ();
+ }
+ return build_type_variant (type, constp, volatilep);
+}