#include "config.h"
#include "system.h"
#include "tree.h"
#include "c-lex.h"
#include "c-tree.h"
#include "flags.h"
#include "obstack.h"
#include "toplev.h"
#include "output.h"
#include "c-pragma.h"
#include "rtl.h"
#if USE_CPPLIB
#include "cpplib.h"
cpp_reader parse_in;
cpp_options parse_options;
static enum cpp_token cpp_token;
#endif
#ifndef WCHAR_TYPE_SIZE
#ifdef INT_TYPE_SIZE
#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
#else
#define WCHAR_TYPE_SIZE BITS_PER_WORD
#endif
#endif
extern struct obstack permanent_obstack;
int skip_evaluation;
enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS};
enum format_type { printf_format_type, scanf_format_type,
strftime_format_type };
static void declare_hidden_char_array PROTO((const char *, const char *));
static void add_attribute PROTO((enum attrs, const char *,
int, int, int));
static void init_attributes PROTO((void));
static void record_function_format PROTO((tree, tree, enum format_type,
int, int));
static void record_international_format PROTO((tree, tree, int));
static tree c_find_base_decl PROTO((tree));
static int default_valid_lang_attribute PROTO ((tree, tree, tree, tree));
typedef struct
{
int compstmt_count;
int line;
const char *file;
int needs_warning;
} if_elt;
static void tfaff PROTO((void));
static if_elt *if_stack;
static int if_stack_space = 0;
static int if_stack_pointer = 0;
void
c_expand_start_cond (cond, exitflag, compstmt_count)
tree cond;
int exitflag;
int compstmt_count;
{
if (if_stack_space == 0)
{
if_stack_space = 10;
if_stack = (if_elt *)xmalloc (10 * sizeof (if_elt));
}
else if (if_stack_space == if_stack_pointer)
{
if_stack_space += 10;
if_stack = (if_elt *)xrealloc (if_stack, if_stack_space * sizeof (if_elt));
}
if_stack[if_stack_pointer].compstmt_count = compstmt_count;
if_stack[if_stack_pointer].file = input_filename;
if_stack[if_stack_pointer].line = lineno;
if_stack[if_stack_pointer].needs_warning = 0;
if_stack_pointer++;
expand_start_cond (cond, exitflag);
}
void
c_expand_end_cond ()
{
if_stack_pointer--;
if (if_stack[if_stack_pointer].needs_warning)
warning_with_file_and_line (if_stack[if_stack_pointer].file,
if_stack[if_stack_pointer].line,
"suggest explicit braces to avoid ambiguous `else'");
expand_end_cond ();
}
void
c_expand_start_else ()
{
if (warn_parentheses
&& if_stack_pointer > 1
&& (if_stack[if_stack_pointer - 1].compstmt_count
== if_stack[if_stack_pointer - 2].compstmt_count))
if_stack[if_stack_pointer - 2].needs_warning = 1;
if_stack[if_stack_pointer - 1].needs_warning = 0;
if_stack[if_stack_pointer - 1].compstmt_count--;
expand_start_else ();
}
void
declare_function_name ()
{
const char *name, *printable_name;
if (current_function_decl == NULL)
{
name = "";
printable_name = "top level";
}
else
{
if (DECL_NAME (current_function_decl))
name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
else
name = "";
printable_name = (*decl_printable_name) (current_function_decl, 2);
}
declare_hidden_char_array ("__FUNCTION__", name);
declare_hidden_char_array ("__PRETTY_FUNCTION__", printable_name);
declare_hidden_char_array ("__func__", name);
}
static void
declare_hidden_char_array (name, value)
const char *name, *value;
{
tree decl, type, init;
int vlen;
vlen = strlen (value) + 1;
type = char_array_type_node;
if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < vlen
|| warn_larger_than)
type = build_array_type (char_type_node,
build_index_type (build_int_2 (vlen, 0)));
push_obstacks_nochange ();
decl = build_decl (VAR_DECL, get_identifier (name), type);
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
TREE_ASM_WRITTEN (decl) = 1;
DECL_SOURCE_LINE (decl) = 0;
DECL_ARTIFICIAL (decl) = 1;
DECL_IN_SYSTEM_HEADER (decl) = 1;
DECL_IGNORED_P (decl) = 1;
init = build_string (vlen, value);
TREE_TYPE (init) = type;
DECL_INITIAL (decl) = init;
finish_decl (pushdecl (decl), init, NULL_TREE);
}
tree
choose_string_type ( wide_flag, ps_flag )
int wide_flag, ps_flag;
{
if (wide_flag)
return wchar_type_node;
#ifndef PASCAL_STRINGS
return char_type_node;
#else
return ps_flag? unsigned_char_type_node : char_type_node ;
#endif
}
tree
combine_strings (strings)
tree strings;
{
register tree value, t;
register int length = 1;
int wide_length = 0;
int wide_flag = 0;
int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
int nchars;
int is_pascal_string = 0;
#ifdef PASCAL_STRINGS
if (TREE_TYPE (strings) == unsigned_char_array_type_node)
{
is_pascal_string = 1;
length = 2;
}
#endif
if (TREE_CHAIN (strings))
{
register char *p, *q;
for (t = strings; t; t = TREE_CHAIN (t))
{
if (TREE_TYPE (t) == wchar_array_type_node)
{
wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
wide_flag = 1;
}
#ifdef PASCAL_STRINGS
else if (TREE_TYPE (t) == unsigned_char_array_type_node)
{
length += (TREE_STRING_LENGTH (t) - 2);
if (t != strings)
if (is_pascal_string)
warning ("pascal-string length escape (\"\\p\") ignored");
else
error ("pascal-string length escape (\"\\p\") ignored");
}
#endif
else
length += (TREE_STRING_LENGTH (t) - 1);
}
if (wide_flag)
length = length * wchar_bytes + wide_length;
p = savealloc (length);
q = p;
#ifdef PASCAL_STRINGS
if (is_pascal_string) ++q;
#endif
for (t = strings; t; t = TREE_CHAIN (t))
{
int len = (TREE_STRING_LENGTH (t)
- ((TREE_TYPE (t) == wchar_array_type_node)
? wchar_bytes : 1));
char *string_ptr = TREE_STRING_POINTER (t);
#ifdef PASCAL_STRINGS
if (TREE_TYPE (t) == unsigned_char_array_type_node)
++string_ptr, --len;
#endif
if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
{
memcpy (q, string_ptr, len);
q += len;
}
else
{
int i;
for (i = 0; i < len; i++)
{
if (WCHAR_TYPE_SIZE == HOST_BITS_PER_SHORT)
((short *) q)[i] = string_ptr[i];
else
((int *) q)[i] = string_ptr[i];
}
q += len * wchar_bytes;
}
}
if (wide_flag)
{
int i;
for (i = 0; i < wchar_bytes; i++)
*q++ = 0;
}
else
*q = 0;
#ifdef PASCAL_STRINGS
if (is_pascal_string)
{
*p = length -2;
if (length -2 > 255)
{
error ("pascal-string too long");
}
}
#endif
value = make_node (STRING_CST);
TREE_STRING_POINTER (value) = p;
TREE_STRING_LENGTH (value) = length;
}
else
{
value = strings;
length = TREE_STRING_LENGTH (value);
if (TREE_TYPE (value) == wchar_array_type_node)
wide_flag = 1;
}
nchars = wide_flag ? length / wchar_bytes : length;
if (flag_const_strings
&& (! flag_traditional && ! flag_writable_strings))
{
tree elements
= build_type_variant (choose_string_type(wide_flag, is_pascal_string),
1, 0);
TREE_TYPE (value)
= build_array_type (elements,
build_index_type (build_int_2 (nchars - 1, 0)));
}
else
TREE_TYPE (value)
= build_array_type (choose_string_type(wide_flag, is_pascal_string),
build_index_type (build_int_2 (nchars - 1, 0)));
TREE_READONLY (value) = TREE_CONSTANT (value) = ! flag_writable_strings;
TREE_STATIC (value) = 1;
return value;
}
static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50];
static int attrtab_idx = 0;
static void
add_attribute (id, string, min_len, max_len, decl_req)
enum attrs id;
const char *string;
int min_len, max_len;
int decl_req;
{
char buf[100];
attrtab[attrtab_idx].id = id;
attrtab[attrtab_idx].name = get_identifier (string);
attrtab[attrtab_idx].min = min_len;
attrtab[attrtab_idx].max = max_len;
attrtab[attrtab_idx++].decl_req = decl_req;
sprintf (buf, "__%s__", string);
attrtab[attrtab_idx].id = id;
attrtab[attrtab_idx].name = get_identifier (buf);
attrtab[attrtab_idx].min = min_len;
attrtab[attrtab_idx].max = max_len;
attrtab[attrtab_idx++].decl_req = decl_req;
}
static void
init_attributes ()
{
add_attribute (A_PACKED, "packed", 0, 0, 0);
add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1);
add_attribute (A_COMMON, "common", 0, 0, 1);
add_attribute (A_NORETURN, "noreturn", 0, 0, 1);
add_attribute (A_NORETURN, "volatile", 0, 0, 1);
add_attribute (A_UNUSED, "unused", 0, 0, 0);
add_attribute (A_CONST, "const", 0, 0, 1);
add_attribute (A_T_UNION, "transparent_union", 0, 0, 0);
add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1);
add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1);
add_attribute (A_MODE, "mode", 1, 1, 1);
add_attribute (A_SECTION, "section", 1, 1, 1);
add_attribute (A_ALIGNED, "aligned", 0, 1, 0);
add_attribute (A_FORMAT, "format", 3, 3, 1);
add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1);
add_attribute (A_WEAK, "weak", 0, 0, 1);
add_attribute (A_ALIAS, "alias", 1, 1, 1);
add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1);
add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1);
}
static int
default_valid_lang_attribute (attr_name, attr_args, decl, type)
tree attr_name ATTRIBUTE_UNUSED;
tree attr_args ATTRIBUTE_UNUSED;
tree decl ATTRIBUTE_UNUSED;
tree type ATTRIBUTE_UNUSED;
{
return 0;
}
int (*valid_lang_attribute) PROTO ((tree, tree, tree, tree))
= default_valid_lang_attribute;
void
decl_attributes (node, attributes, prefix_attributes)
tree node, attributes, prefix_attributes;
{
tree decl = 0, type = 0;
int is_type = 0;
tree a;
if (attrtab_idx == 0)
init_attributes ();
if (TREE_CODE_CLASS (TREE_CODE (node)) == 'd')
{
decl = node;
type = TREE_TYPE (decl);
is_type = TREE_CODE (node) == TYPE_DECL;
}
else if (TREE_CODE_CLASS (TREE_CODE (node)) == 't')
type = node, is_type = 1;
#ifdef PRAGMA_INSERT_ATTRIBUTES
PRAGMA_INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes);
#endif
#ifdef INSERT_ATTRIBUTES
INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes);
#endif
attributes = chainon (prefix_attributes, attributes);
for (a = attributes; a; a = TREE_CHAIN (a))
{
tree name = TREE_PURPOSE (a);
tree args = TREE_VALUE (a);
int i;
enum attrs id;
for (i = 0; i < attrtab_idx; i++)
if (attrtab[i].name == name)
break;
if (i == attrtab_idx)
{
if (! valid_machine_attribute (name, args, decl, type)
&& ! (* valid_lang_attribute) (name, args, decl, type))
warning ("`%s' attribute directive ignored",
IDENTIFIER_POINTER (name));
else if (decl != 0)
type = TREE_TYPE (decl);
continue;
}
else if (attrtab[i].decl_req && decl == 0)
{
warning ("`%s' attribute does not apply to types",
IDENTIFIER_POINTER (name));
continue;
}
else if (list_length (args) < attrtab[i].min
|| list_length (args) > attrtab[i].max)
{
error ("wrong number of arguments specified for `%s' attribute",
IDENTIFIER_POINTER (name));
continue;
}
id = attrtab[i].id;
switch (id)
{
case A_PACKED:
if (is_type)
TYPE_PACKED (type) = 1;
else if (TREE_CODE (decl) == FIELD_DECL)
DECL_PACKED (decl) = 1;
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_NOCOMMON:
if (TREE_CODE (decl) == VAR_DECL)
DECL_COMMON (decl) = 0;
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_COMMON:
if (TREE_CODE (decl) == VAR_DECL)
DECL_COMMON (decl) = 1;
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_NORETURN:
if (TREE_CODE (decl) == FUNCTION_DECL)
TREE_THIS_VOLATILE (decl) = 1;
else if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
TREE_TYPE (decl) = type
= build_pointer_type
(build_type_variant (TREE_TYPE (type),
TREE_READONLY (TREE_TYPE (type)), 1));
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_UNUSED:
if (is_type)
TREE_USED (type) = 1;
else if (TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == LABEL_DECL)
TREE_USED (decl) = 1;
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_CONST:
if (TREE_CODE (decl) == FUNCTION_DECL)
TREE_READONLY (decl) = 1;
else if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
TREE_TYPE (decl) = type
= build_pointer_type
(build_type_variant (TREE_TYPE (type), 1,
TREE_THIS_VOLATILE (TREE_TYPE (type))));
else
warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_T_UNION:
if (is_type
&& TREE_CODE (type) == UNION_TYPE
&& (decl == 0
|| (TYPE_FIELDS (type) != 0
&& TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))))
TYPE_TRANSPARENT_UNION (type) = 1;
else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
&& TREE_CODE (type) == UNION_TYPE
&& TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
DECL_TRANSPARENT_UNION (decl) = 1;
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_CONSTRUCTOR:
if (TREE_CODE (decl) == FUNCTION_DECL
&& TREE_CODE (type) == FUNCTION_TYPE
&& decl_function_context (decl) == 0)
{
DECL_STATIC_CONSTRUCTOR (decl) = 1;
TREE_USED (decl) = 1;
}
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_DESTRUCTOR:
if (TREE_CODE (decl) == FUNCTION_DECL
&& TREE_CODE (type) == FUNCTION_TYPE
&& decl_function_context (decl) == 0)
{
DECL_STATIC_DESTRUCTOR (decl) = 1;
TREE_USED (decl) = 1;
}
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_MODE:
if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
else
{
int j;
const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
int len = strlen (p);
enum machine_mode mode = VOIDmode;
tree typefm;
if (len > 4 && p[0] == '_' && p[1] == '_'
&& p[len - 1] == '_' && p[len - 2] == '_')
{
char *newp = (char *) alloca (len - 1);
strcpy (newp, &p[2]);
newp[len - 4] = '\0';
p = newp;
}
if (! strcmp (p, "byte"))
mode = byte_mode;
else if (!strcmp (p, "word"))
mode = word_mode;
else if (! strcmp (p, "pointer"))
mode = ptr_mode;
else
for (j = 0; j < NUM_MACHINE_MODES; j++)
if (!strcmp (p, GET_MODE_NAME (j)))
mode = (enum machine_mode) j;
if (mode == VOIDmode)
error ("unknown machine mode `%s'", p);
else if (0 == (typefm = type_for_mode (mode,
TREE_UNSIGNED (type))))
error ("no data type for mode `%s'", p);
else
{
TREE_TYPE (decl) = type = typefm;
DECL_SIZE (decl) = 0;
layout_decl (decl, 0);
}
}
break;
case A_SECTION:
#ifdef ASM_OUTPUT_SECTION_NAME
if ((TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL)
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
{
if (TREE_CODE (decl) == VAR_DECL
&& current_function_decl != NULL_TREE
&& ! TREE_STATIC (decl))
error_with_decl (decl,
"section attribute cannot be specified for local variables");
else if (DECL_SECTION_NAME (decl) != NULL_TREE
&& strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
error_with_decl (node,
"section of `%s' conflicts with previous declaration");
else
DECL_SECTION_NAME (decl) = TREE_VALUE (args);
}
else
error_with_decl (node,
"section attribute not allowed for `%s'");
#else
error_with_decl (node,
"section attributes are not supported for this target");
#endif
break;
case A_ALIGNED:
{
tree align_expr
= (args ? TREE_VALUE (args)
: size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
int align;
while (TREE_CODE (align_expr) == NOP_EXPR
|| TREE_CODE (align_expr) == CONVERT_EXPR
|| TREE_CODE (align_expr) == NON_LVALUE_EXPR)
align_expr = TREE_OPERAND (align_expr, 0);
if (TREE_CODE (align_expr) != INTEGER_CST)
{
error ("requested alignment is not a constant");
continue;
}
align = TREE_INT_CST_LOW (align_expr) * BITS_PER_UNIT;
if (exact_log2 (align) == -1)
error ("requested alignment is not a power of 2");
else if (is_type)
TYPE_ALIGN (type) = align;
else if (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != FIELD_DECL)
error_with_decl (decl,
"alignment may not be specified for `%s'");
else
DECL_ALIGN (decl) = align;
}
break;
case A_FORMAT:
{
tree format_type_id = TREE_VALUE (args);
tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
tree first_arg_num_expr
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
int format_num;
int first_arg_num;
enum format_type format_type;
tree argument;
int arg_num;
if (TREE_CODE (decl) != FUNCTION_DECL)
{
error_with_decl (decl,
"argument format specified for non-function `%s'");
continue;
}
if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
{
error ("unrecognized format specifier");
continue;
}
else
{
const char *p = IDENTIFIER_POINTER (format_type_id);
if (!strcmp (p, "printf") || !strcmp (p, "__printf__"))
format_type = printf_format_type;
else if (!strcmp (p, "scanf") || !strcmp (p, "__scanf__"))
format_type = scanf_format_type;
else if (!strcmp (p, "strftime")
|| !strcmp (p, "__strftime__"))
format_type = strftime_format_type;
else
{
warning ("`%s' is an unrecognized format function type", p);
continue;
}
}
while (TREE_CODE (format_num_expr) == NOP_EXPR
|| TREE_CODE (format_num_expr) == CONVERT_EXPR
|| TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
format_num_expr = TREE_OPERAND (format_num_expr, 0);
while (TREE_CODE (first_arg_num_expr) == NOP_EXPR
|| TREE_CODE (first_arg_num_expr) == CONVERT_EXPR
|| TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR)
first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0);
if (TREE_CODE (format_num_expr) != INTEGER_CST
|| TREE_CODE (first_arg_num_expr) != INTEGER_CST)
{
error ("format string has non-constant operand number");
continue;
}
format_num = TREE_INT_CST_LOW (format_num_expr);
first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr);
if (first_arg_num != 0 && first_arg_num <= format_num)
{
error ("format string arg follows the args to be formatted");
continue;
}
argument = TYPE_ARG_TYPES (type);
if (argument)
{
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 ("format string arg not a string type");
continue;
}
if (first_arg_num != 0)
{
while (argument)
arg_num++, argument = TREE_CHAIN (argument);
if (arg_num != first_arg_num)
{
error ("args to be formatted is not ...");
continue;
}
}
}
record_function_format (DECL_NAME (decl),
DECL_ASSEMBLER_NAME (decl),
format_type, format_num, first_arg_num);
break;
}
case A_FORMAT_ARG:
{
tree format_num_expr = TREE_VALUE (args);
int format_num, arg_num;
tree argument;
if (TREE_CODE (decl) != FUNCTION_DECL)
{
error_with_decl (decl,
"argument format specified for non-function `%s'");
continue;
}
while (TREE_CODE (format_num_expr) == NOP_EXPR
|| TREE_CODE (format_num_expr) == CONVERT_EXPR
|| TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
format_num_expr = TREE_OPERAND (format_num_expr, 0);
if (TREE_CODE (format_num_expr) != INTEGER_CST)
{
error ("format string has non-constant operand number");
continue;
}
format_num = TREE_INT_CST_LOW (format_num_expr);
argument = TYPE_ARG_TYPES (type);
if (argument)
{
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 ("format string arg not a string type");
continue;
}
}
if (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) != POINTER_TYPE
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_TYPE (decl))))
!= char_type_node))
{
error ("function does not return string type");
continue;
}
record_international_format (DECL_NAME (decl),
DECL_ASSEMBLER_NAME (decl),
format_num);
break;
}
case A_WEAK:
declare_weak (decl);
break;
case A_ALIAS:
if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
|| (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
error_with_decl (decl,
"`%s' defined both normally and as an alias");
else if (decl_function_context (decl) == 0)
{
tree id;
id = TREE_VALUE (args);
if (TREE_CODE (id) != STRING_CST)
{
error ("alias arg not a string");
break;
}
id = get_identifier (TREE_STRING_POINTER (id));
if (TREE_CODE (decl) == FUNCTION_DECL)
DECL_INITIAL (decl) = error_mark_node;
else
DECL_EXTERNAL (decl) = 0;
assemble_alias (decl, id);
}
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_NO_CHECK_MEMORY_USAGE:
if (TREE_CODE (decl) != FUNCTION_DECL)
{
error_with_decl (decl,
"`%s' attribute applies only to functions",
IDENTIFIER_POINTER (name));
}
else if (DECL_INITIAL (decl))
{
error_with_decl (decl,
"can't set `%s' attribute after definition",
IDENTIFIER_POINTER (name));
}
else
DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
break;
case A_NO_INSTRUMENT_FUNCTION:
if (TREE_CODE (decl) != FUNCTION_DECL)
{
error_with_decl (decl,
"`%s' attribute applies only to functions",
IDENTIFIER_POINTER (name));
}
else if (DECL_INITIAL (decl))
{
error_with_decl (decl,
"can't set `%s' attribute after definition",
IDENTIFIER_POINTER (name));
}
else
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
break;
}
}
}
void
split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
tree specs_attrs;
tree *declspecs, *prefix_attributes;
{
tree t, s, a, next, specs, attrs;
if (specs_attrs != NULL_TREE
&& TREE_CODE (specs_attrs) != TREE_LIST)
{
*declspecs = specs_attrs;
*prefix_attributes = NULL_TREE;
return;
}
specs = s = NULL_TREE;
attrs = a = NULL_TREE;
for (t = specs_attrs; t; t = next)
{
next = TREE_CHAIN (t);
if (TREE_VALUE (t) != NULL_TREE)
{
if (specs == NULL_TREE)
specs = s = t;
else
{
TREE_CHAIN (s) = t;
s = t;
}
}
else
{
if (attrs == NULL_TREE)
attrs = a = TREE_PURPOSE (t);
else
{
TREE_CHAIN (a) = TREE_PURPOSE (t);
a = TREE_PURPOSE (t);
}
while (TREE_CHAIN (a) != NULL_TREE)
a = TREE_CHAIN (a);
}
}
if (s != NULL_TREE)
TREE_CHAIN (s) = NULL_TREE;
if (a != NULL_TREE)
TREE_CHAIN (a) = NULL_TREE;
*declspecs = specs;
*prefix_attributes = attrs;
}
tree
strip_attrs (specs_attrs)
tree specs_attrs;
{
tree specs, attrs;
split_specs_attrs (specs_attrs, &specs, &attrs);
while (attrs)
{
warning ("`%s' attribute ignored",
IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
attrs = TREE_CHAIN (attrs);
}
return specs;
}
#define T_I &integer_type_node
#define T_L &long_integer_type_node
#define T_LL &long_long_integer_type_node
#define T_S &short_integer_type_node
#define T_UI &unsigned_type_node
#define T_UL &long_unsigned_type_node
#define T_ULL &long_long_unsigned_type_node
#define T_US &short_unsigned_type_node
#define T_F &float_type_node
#define T_D &double_type_node
#define T_LD &long_double_type_node
#define T_C &char_type_node
#define T_UC &unsigned_char_type_node
#define T_V &void_type_node
#define T_W &wchar_type_node
#define T_ST &sizetype
typedef struct {
const char *format_chars;
int pointer_count;
tree *nolen;
tree *hhlen;
tree *hlen;
tree *llen;
tree *qlen;
tree *bigllen;
tree *zlen;
const char *flag_chars;
} format_char_info;
static format_char_info print_char_table[] = {
{ "di", 0, T_I, T_I, T_I, T_L, T_LL, T_LL, T_ST, "-wp0 +" },
{ "oxX", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0#" },
{ "u", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0" },
{ "m", 0, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" },
{ "feEgGaA", 0, T_D, NULL, NULL, NULL, NULL, T_LD, NULL, "-wp0 +#" },
{ "c", 0, T_I, NULL, NULL, T_W, NULL, NULL, NULL, "-w" },
{ "C", 0, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-w" },
{ "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "-wp" },
{ "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" },
{ "p", 1, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-w" },
{ "n", 1, T_I, NULL, T_S, T_L, T_LL, NULL, NULL, "" },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
static format_char_info scan_char_table[] = {
{ "di", 1, T_I, T_C, T_S, T_L, T_LL, T_LL, NULL, "*" },
{ "ouxX", 1, T_UI, T_UC, T_US, T_UL, T_ULL, T_ULL, NULL, "*" },
{ "efgEGaA", 1, T_F, NULL, NULL, T_D, NULL, T_LD, NULL, "*" },
{ "c", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*" },
{ "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*a" },
{ "[", 1, T_C, NULL, NULL, NULL, NULL, NULL, NULL, "*a" },
{ "C", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*" },
{ "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*a" },
{ "p", 2, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "*" },
{ "n", 1, T_I, T_C, T_S, T_L, T_LL, NULL, NULL, "" },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
static format_char_info time_char_table[] = {
{ "y", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2EO-_0w" },
{ "D", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2" },
{ "g", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2O-_0w" },
{ "cx", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "3E" },
{ "%RTXnrt", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "" },
{ "P", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "G" },
{ "HIMSUWdemw", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Ow" },
{ "Vju", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Oow" },
{ "Gklsz", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0OGw" },
{ "ABZa", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^#" },
{ "p", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "#" },
{ "bh", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^" },
{ "CY", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0EOw" },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
typedef struct function_format_info
{
struct function_format_info *next;
tree name;
tree assembler_name;
enum format_type format_type;
int format_num;
int first_arg_num;
} function_format_info;
static function_format_info *function_format_list = NULL;
typedef struct international_format_info
{
struct international_format_info *next;
tree name;
tree assembler_name;
int format_num;
} international_format_info;
static international_format_info *international_format_list = NULL;
static void check_format_info PROTO((function_format_info *, tree));
void
init_function_format_info ()
{
record_function_format (get_identifier ("printf"), NULL_TREE,
printf_format_type, 1, 2);
record_function_format (get_identifier ("fprintf"), NULL_TREE,
printf_format_type, 2, 3);
record_function_format (get_identifier ("sprintf"), NULL_TREE,
printf_format_type, 2, 3);
record_function_format (get_identifier ("scanf"), NULL_TREE,
scanf_format_type, 1, 2);
record_function_format (get_identifier ("fscanf"), NULL_TREE,
scanf_format_type, 2, 3);
record_function_format (get_identifier ("sscanf"), NULL_TREE,
scanf_format_type, 2, 3);
record_function_format (get_identifier ("vprintf"), NULL_TREE,
printf_format_type, 1, 0);
record_function_format (get_identifier ("vfprintf"), NULL_TREE,
printf_format_type, 2, 0);
record_function_format (get_identifier ("vsprintf"), NULL_TREE,
printf_format_type, 2, 0);
#ifndef NEXT_SEMANTICS
record_function_format (get_identifier ("strftime"), NULL_TREE,
strftime_format_type, 3, 0);
#endif
record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
}
static void
record_function_format (name, assembler_name, format_type,
format_num, first_arg_num)
tree name;
tree assembler_name;
enum format_type format_type;
int format_num;
int first_arg_num;
{
function_format_info *info;
for (info = function_format_list; info; info = info->next)
{
if (info->name == name && info->assembler_name == assembler_name)
break;
}
if (! info)
{
info = (function_format_info *) xmalloc (sizeof (function_format_info));
info->next = function_format_list;
function_format_list = info;
info->name = name;
info->assembler_name = assembler_name;
}
info->format_type = format_type;
info->format_num = format_num;
info->first_arg_num = first_arg_num;
}
static void
record_international_format (name, assembler_name, format_num)
tree name;
tree assembler_name;
int format_num;
{
international_format_info *info;
for (info = international_format_list; info; info = info->next)
{
if (info->name == name && info->assembler_name == assembler_name)
break;
}
if (! info)
{
info
= (international_format_info *)
xmalloc (sizeof (international_format_info));
info->next = international_format_list;
international_format_list = info;
info->name = name;
info->assembler_name = assembler_name;
}
info->format_num = format_num;
}
static void
tfaff ()
{
warning ("too few arguments for format");
}
void
check_function_format (name, assembler_name, params)
tree name;
tree assembler_name;
tree params;
{
function_format_info *info;
for (info = function_format_list; info; info = info->next)
{
if (info->assembler_name
? (info->assembler_name == assembler_name)
: (info->name == name))
{
check_format_info (info, params);
break;
}
}
}
static void
check_format_info (info, params)
function_format_info *info;
tree params;
{
int i;
int arg_num;
int suppressed, wide, precise;
int length_char = 0;
int format_char;
int format_length;
tree format_tree;
tree cur_param;
tree cur_type;
tree wanted_type;
tree first_fillin_param;
const char *format_chars;
format_char_info *fci = NULL;
char flag_chars[8];
int has_operand_number = 0;
for (arg_num = 1; ; ++arg_num)
{
if (params == 0)
return;
if (arg_num == info->format_num)
break;
params = TREE_CHAIN (params);
}
format_tree = TREE_VALUE (params);
params = TREE_CHAIN (params);
if (format_tree == 0)
return;
while (TREE_CODE (format_tree) == NOP_EXPR)
format_tree = TREE_OPERAND (format_tree, 0);
if (TREE_CODE (format_tree) == CALL_EXPR
&& TREE_CODE (TREE_OPERAND (format_tree, 0)) == ADDR_EXPR
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0))
== FUNCTION_DECL))
{
tree function = TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0);
international_format_info *info;
for (info = international_format_list; info; info = info->next)
if (info->assembler_name
? (info->assembler_name == DECL_ASSEMBLER_NAME (function))
: (info->name == DECL_NAME (function)))
{
tree inner_args;
int i;
for (inner_args = TREE_OPERAND (format_tree, 1), i = 1;
inner_args != 0;
inner_args = TREE_CHAIN (inner_args), i++)
if (i == info->format_num)
{
format_tree = TREE_VALUE (inner_args);
while (TREE_CODE (format_tree) == NOP_EXPR)
format_tree = TREE_OPERAND (format_tree, 0);
}
}
}
if (integer_zerop (format_tree))
{
warning ("null format string");
return;
}
if (TREE_CODE (format_tree) != ADDR_EXPR)
return;
format_tree = TREE_OPERAND (format_tree, 0);
if (TREE_CODE (format_tree) != STRING_CST)
return;
format_chars = TREE_STRING_POINTER (format_tree);
format_length = TREE_STRING_LENGTH (format_tree);
if (format_length <= 1)
warning ("zero-length format string");
if (format_chars[--format_length] != 0)
{
warning ("unterminated format string");
return;
}
while (arg_num + 1 < info->first_arg_num)
{
if (params == 0)
return;
params = TREE_CHAIN (params);
++arg_num;
}
first_fillin_param = params;
while (1)
{
int aflag;
if (*format_chars == 0)
{
if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
warning ("embedded `\\0' in format");
if (info->first_arg_num != 0 && params != 0 && ! has_operand_number)
warning ("too many arguments for format");
return;
}
if (*format_chars++ != '%')
continue;
if (*format_chars == 0)
{
warning ("spurious trailing `%%' in format");
continue;
}
if (*format_chars == '%')
{
++format_chars;
continue;
}
flag_chars[0] = 0;
suppressed = wide = precise = FALSE;
if (info->format_type == scanf_format_type)
{
suppressed = *format_chars == '*';
if (suppressed)
++format_chars;
while (ISDIGIT (*format_chars))
++format_chars;
}
else if (info->format_type == strftime_format_type)
{
while (*format_chars != 0 && index ("_-0^#", *format_chars) != 0)
{
if (pedantic)
warning ("ANSI C does not support the strftime `%c' flag",
*format_chars);
if (index (flag_chars, *format_chars) != 0)
{
warning ("repeated `%c' flag in format",
*format_chars);
++format_chars;
}
else
{
i = strlen (flag_chars);
flag_chars[i++] = *format_chars++;
flag_chars[i] = 0;
}
}
while (ISDIGIT ((unsigned char) *format_chars))
{
wide = TRUE;
++format_chars;
}
if (wide && pedantic)
warning ("ANSI C does not support strftime format width");
if (*format_chars == 'E' || *format_chars == 'O')
{
i = strlen (flag_chars);
flag_chars[i++] = *format_chars++;
flag_chars[i] = 0;
if (*format_chars == 'E' || *format_chars == 'O')
{
warning ("multiple E/O modifiers in format");
while (*format_chars == 'E' || *format_chars == 'O')
++format_chars;
}
}
}
else if (info->format_type == printf_format_type)
{
if (*format_chars >= '0' && *format_chars <= '9')
{
const char *p = format_chars;
while (*p >= '0' && *p++ <= '9')
;
if (*p == '$')
{
int opnum = atoi (format_chars);
params = first_fillin_param;
format_chars = p + 1;
has_operand_number = 1;
for (i = 1; i < opnum && params != 0; i++)
params = TREE_CHAIN (params);
if (opnum == 0 || params == 0)
{
warning ("operand number out of range in format");
return;
}
}
}
while (*format_chars != 0 && index (" +#0-", *format_chars) != 0)
{
if (index (flag_chars, *format_chars) != 0)
warning ("repeated `%c' flag in format", *format_chars++);
else
{
i = strlen (flag_chars);
flag_chars[i++] = *format_chars++;
flag_chars[i] = 0;
}
}
if (index (flag_chars, ' ') != 0
&& index (flag_chars, '+') != 0)
warning ("use of both ` ' and `+' flags in format");
if (index (flag_chars, '0') != 0
&& index (flag_chars, '-') != 0)
warning ("use of both `0' and `-' flags in format");
if (*format_chars == '*')
{
wide = TRUE;
++format_chars;
if (params == 0)
{
tfaff ();
return;
}
if (info->first_arg_num != 0)
{
cur_param = TREE_VALUE (params);
params = TREE_CHAIN (params);
++arg_num;
if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
!= integer_type_node)
&&
(TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
!= unsigned_type_node))
warning ("field width is not type int (arg %d)", arg_num);
}
}
else
{
while (ISDIGIT (*format_chars))
{
wide = TRUE;
++format_chars;
}
}
if (*format_chars == '.')
{
precise = TRUE;
++format_chars;
if (*format_chars != '*' && !ISDIGIT (*format_chars))
warning ("`.' not followed by `*' or digit in format");
if (*format_chars == '*')
{
if (info->first_arg_num != 0)
{
++format_chars;
if (params == 0)
{
tfaff ();
return;
}
cur_param = TREE_VALUE (params);
params = TREE_CHAIN (params);
++arg_num;
if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
!= integer_type_node)
warning ("field width is not type int (arg %d)",
arg_num);
}
}
else
{
while (ISDIGIT (*format_chars))
++format_chars;
}
}
}
if (*format_chars == 'h' || *format_chars == 'l')
length_char = *format_chars++;
else if (*format_chars == 'q' || *format_chars == 'L')
{
length_char = *format_chars++;
if (pedantic)
pedwarn ("ANSI C does not support the `%c' length modifier",
length_char);
}
else
length_char = 0;
if (length_char == 'l' && *format_chars == 'l')
{
length_char = 'q', format_chars++;
if (pedantic)
pedwarn ("ANSI C does not support the `ll' length modifier");
}
aflag = 0;
if (info->format_type != strftime_format_type)
{
if (*format_chars == 'h' || *format_chars == 'l')
length_char = *format_chars++;
else if (*format_chars == 'q' || *format_chars == 'L')
{
length_char = *format_chars++;
if (pedantic)
warning ("ANSI C does not support the `%c' length modifier",
length_char);
}
else if (*format_chars == 'Z')
{
length_char = *format_chars++;
if (pedantic)
warning ("ANSI C does not support the `Z' length modifier");
}
#if !defined (NEXT_SEMANTICS) && !defined (NEXT_PDO)
else
length_char = 0;
#endif
if (length_char == 'l' && *format_chars == 'l')
{
length_char = 'q', format_chars++;
if (pedantic)
warning ("ANSI C does not support the `ll' length modifier");
}
else if (length_char == 'h' && *format_chars == 'h')
{
length_char = 'H', format_chars++;
if (pedantic)
warning ("ANSI C does not support the `hh' length modifier");
}
if (*format_chars == 'a' && info->format_type == scanf_format_type)
{
if (format_chars[1] == 's' || format_chars[1] == 'S'
|| format_chars[1] == '[')
{
aflag = 1;
format_chars++;
}
}
if (suppressed && length_char != 0)
warning ("use of `*' and `%c' together in format", length_char);
}
format_char = *format_chars;
if (format_char == 0
|| (info->format_type != strftime_format_type && format_char == '%'))
{
warning ("conversion lacks type at end of format");
continue;
}
if (pedantic && info->format_type != strftime_format_type
&& (format_char == 'm' || format_char == 'C' || format_char == 'S'))
warning ("ANSI C does not support the `%c' format", format_char);
if (pedantic && info->format_type != strftime_format_type
&& (format_char == 'a' || format_char == 'A'))
warning ("ANSI C does not support the `%c' format", format_char);
format_chars++;
switch (info->format_type)
{
case printf_format_type:
fci = print_char_table;
break;
case scanf_format_type:
fci = scan_char_table;
break;
case strftime_format_type:
fci = time_char_table;
break;
default:
abort ();
}
while (fci->format_chars != 0
&& index (fci->format_chars, format_char) == 0)
++fci;
if (fci->format_chars == 0)
{
if (format_char >= 040 && format_char < 0177)
warning ("unknown conversion type character `%c' in format",
format_char);
else
warning ("unknown conversion type character 0x%x in format",
format_char);
continue;
}
if (pedantic)
{
if (index (fci->flag_chars, 'G') != 0)
warning ("ANSI C does not support `%%%c'", format_char);
if (index (fci->flag_chars, 'o') != 0
&& index (flag_chars, 'O') != 0)
warning ("ANSI C does not support `%%O%c'", format_char);
}
if (wide && index (fci->flag_chars, 'w') == 0)
warning ("width used with `%c' format", format_char);
if (index (fci->flag_chars, '2') != 0)
warning ("`%%%c' yields only last 2 digits of year", format_char);
else if (index (fci->flag_chars, '3') != 0)
warning ("`%%%c' yields only last 2 digits of year in some locales",
format_char);
if (precise && index (fci->flag_chars, 'p') == 0)
warning ("precision used with `%c' format", format_char);
if (aflag && index (fci->flag_chars, 'a') == 0)
{
warning ("`a' flag used with `%c' format", format_char);
aflag = 0;
}
else if (pedantic && aflag)
warning ("ANSI C does not support the `a' flag");
if (info->format_type == scanf_format_type && format_char == '[')
{
if (*format_chars == '^')
++format_chars;
if (*format_chars == ']')
++format_chars;
while (*format_chars && *format_chars != ']')
++format_chars;
if (*format_chars != ']')
warning ("no closing `]' for `%%[' format");
}
if (suppressed)
{
if (index (fci->flag_chars, '*') == 0)
warning ("suppression of `%c' conversion in format", format_char);
continue;
}
for (i = 0; flag_chars[i] != 0; ++i)
{
if (index (fci->flag_chars, flag_chars[i]) == 0)
warning ("flag `%c' used with type `%c'",
flag_chars[i], format_char);
}
if (info->format_type == strftime_format_type)
continue;
if (precise && index (flag_chars, '0') != 0
&& (format_char == 'd' || format_char == 'i'
|| format_char == 'o' || format_char == 'u'
|| format_char == 'x' || format_char == 'X'))
warning ("`0' flag ignored with precision specifier and `%c' format",
format_char);
switch (length_char)
{
default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break;
case 'H': wanted_type = fci->hhlen ? *(fci->hhlen) : 0; break;
case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break;
case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break;
case 'q': wanted_type = fci->qlen ? *(fci->qlen) : 0; break;
case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break;
case 'Z': wanted_type = fci->zlen ? *fci->zlen : 0; break;
}
if (wanted_type == 0)
warning ("use of `%c' length character with `%c' type character",
length_char, format_char);
if (info->first_arg_num == 0)
continue;
if (fci->pointer_count == 0 && wanted_type == void_type_node)
continue;
if (params == 0)
{
tfaff ();
return;
}
cur_param = TREE_VALUE (params);
params = TREE_CHAIN (params);
++arg_num;
cur_type = TREE_TYPE (cur_param);
STRIP_NOPS (cur_param);
for (i = 0; i < fci->pointer_count + aflag; ++i)
{
if (TREE_CODE (cur_type) == POINTER_TYPE)
{
cur_type = TREE_TYPE (cur_type);
if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
cur_param = TREE_OPERAND (cur_param, 0);
else
cur_param = 0;
continue;
}
if (TREE_CODE (cur_type) != ERROR_MARK)
warning ((fci->pointer_count + aflag == 1
? "format argument is not a pointer (arg %d)"
: "format argument is not a pointer to a pointer (arg %d)"),
arg_num);
break;
}
if ((info->format_type == scanf_format_type
|| (info->format_type == printf_format_type
&& format_char == 'n'))
&& i == fci->pointer_count + aflag
&& wanted_type != 0
&& TREE_CODE (cur_type) != ERROR_MARK
&& (TYPE_READONLY (cur_type)
|| (cur_param != 0
&& (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c'
|| (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'd'
&& TREE_READONLY (cur_param))))))
warning ("writing into constant object (arg %d)", arg_num);
if (i == fci->pointer_count + aflag && wanted_type != 0
&& TREE_CODE (cur_type) != ERROR_MARK
&& wanted_type != TYPE_MAIN_VARIANT (cur_type)
&& ! (wanted_type == void_type_node
&& fci->pointer_count > 0)
&& !(TREE_CODE (wanted_type) == INTEGER_TYPE
&& TREE_CODE (TYPE_MAIN_VARIANT (cur_type)) == INTEGER_TYPE
&& (TREE_UNSIGNED (wanted_type)
? wanted_type == (cur_type = unsigned_type (cur_type))
: wanted_type == (cur_type = signed_type (cur_type))))
&& ! (wanted_type == char_type_node
&& (TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node
|| TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node)))
{
register const char *this;
register const char *that;
this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
that = 0;
if (TREE_CODE (cur_type) != ERROR_MARK
&& TYPE_NAME (cur_type) != 0
&& TREE_CODE (cur_type) != INTEGER_TYPE
&& !(TREE_CODE (cur_type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (cur_type)) == INTEGER_TYPE))
{
if (TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL
&& DECL_NAME (TYPE_NAME (cur_type)) != 0)
that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
else
that = IDENTIFIER_POINTER (TYPE_NAME (cur_type));
}
if (that == 0)
{
if (TREE_CODE (cur_type) == POINTER_TYPE)
that = "pointer";
else
that = "different type";
}
if (TREE_CODE (cur_type) == INTEGER_TYPE
&& TREE_CODE (wanted_type) == INTEGER_TYPE
&& TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type)
&& TYPE_NAME (cur_type) != 0
&& TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL)
that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
if (strcmp (this, that) != 0)
warning ("%s format, %s arg (arg %d)", this, that, arg_num);
}
}
}
void
constant_expression_warning (value)
tree value;
{
if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
|| TREE_CODE (value) == COMPLEX_CST || TREE_CODE (value) == VECTOR_CST)
&& TREE_CONSTANT_OVERFLOW (value) && pedantic)
pedwarn ("overflow in constant expression");
}
void
overflow_warning (value)
tree value;
{
if ((TREE_CODE (value) == INTEGER_CST
|| (TREE_CODE (value) == COMPLEX_CST
&& TREE_CODE (TREE_REALPART (value)) == INTEGER_CST))
&& TREE_OVERFLOW (value))
{
TREE_OVERFLOW (value) = 0;
if (skip_evaluation == 0)
warning ("integer overflow in expression");
}
else if ((TREE_CODE (value) == REAL_CST
|| (TREE_CODE (value) == COMPLEX_CST
&& TREE_CODE (TREE_REALPART (value)) == REAL_CST))
&& TREE_OVERFLOW (value))
{
TREE_OVERFLOW (value) = 0;
if (skip_evaluation == 0)
warning ("floating point overflow in expression");
}
else if (TREE_CODE (value) == VECTOR_CST && TREE_OVERFLOW (value))
{
TREE_OVERFLOW (value) = 0;
if (skip_evaluation == 0)
warning ("vector overflow in expression");
}
}
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))
&& skip_evaluation == 0
&& !int_fits_type_p (operand, TREE_TYPE (result)))
{
if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
warning ("large integer implicitly truncated to unsigned type");
else if (warn_conversion)
warning ("negative integer implicitly converted to unsigned type");
}
}
tree
convert_and_check (type, expr)
tree type, expr;
{
tree t = convert (type, expr);
if (TREE_CODE (t) == INTEGER_CST)
{
if (TREE_OVERFLOW (t))
{
TREE_OVERFLOW (t) = 0;
TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr);
if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr))
&& TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
&& TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr))))
if ((pedantic
|| TREE_UNSIGNED (type)
|| ! int_fits_type_p (expr, unsigned_type (type)))
&& skip_evaluation == 0)
warning ("overflow in implicit constant conversion");
}
else
unsigned_conversion_warning (t, expr);
}
return t;
}
void
c_expand_expr_stmt (expr)
tree expr;
{
if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr))
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
expr = default_conversion (expr);
if (TREE_TYPE (expr) != error_mark_node
&& TYPE_SIZE (TREE_TYPE (expr)) == 0
&& TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
error ("expression statement has incomplete type");
expand_expr_stmt (expr);
}
tree
check_case_value (value)
tree value;
{
if (value == NULL_TREE)
return value;
STRIP_TYPE_NOPS (value);
if (TREE_CODE (value) != INTEGER_CST
&& value != error_mark_node)
{
error ("case label does not reduce to an integer constant");
value = error_mark_node;
}
else
value = default_conversion (value);
constant_expression_warning (value);
return value;
}
tree
type_for_size (bits, unsignedp)
unsigned bits;
int unsignedp;
{
if (bits == TYPE_PRECISION (integer_type_node))
return unsignedp ? unsigned_type_node : integer_type_node;
if (bits == TYPE_PRECISION (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
if (bits == TYPE_PRECISION (short_integer_type_node))
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
if (bits == TYPE_PRECISION (long_integer_type_node))
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
if (bits == TYPE_PRECISION (long_long_integer_type_node))
return (unsignedp ? long_long_unsigned_type_node
: long_long_integer_type_node);
if (bits <= TYPE_PRECISION (intQI_type_node))
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
if (bits <= TYPE_PRECISION (intHI_type_node))
return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
if (bits <= TYPE_PRECISION (intSI_type_node))
return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
if (bits <= TYPE_PRECISION (intDI_type_node))
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
return 0;
}
tree
type_for_mode (mode, unsignedp)
enum machine_mode mode;
int unsignedp;
{
if (mode == TYPE_MODE (integer_type_node))
return unsignedp ? unsigned_type_node : integer_type_node;
if (mode == TYPE_MODE (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
if (mode == TYPE_MODE (short_integer_type_node))
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
if (mode == TYPE_MODE (long_integer_type_node))
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
if (mode == TYPE_MODE (long_long_integer_type_node))
return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node;
if (mode == TYPE_MODE (intQI_type_node))
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
if (mode == TYPE_MODE (intHI_type_node))
return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
if (mode == TYPE_MODE (intSI_type_node))
return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
if (mode == TYPE_MODE (intDI_type_node))
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
#if HOST_BITS_PER_WIDE_INT >= 64
if (mode == TYPE_MODE (intTI_type_node))
return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
#endif
if (mode == TYPE_MODE (float_type_node))
return float_type_node;
if (mode == TYPE_MODE (double_type_node))
return double_type_node;
if (mode == TYPE_MODE (long_double_type_node))
return long_double_type_node;
if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
return build_pointer_type (char_type_node);
if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
return build_pointer_type (integer_type_node);
return 0;
}
int
min_precision (value, unsignedp)
tree value;
int unsignedp;
{
int log;
if (tree_int_cst_sgn (value) < 0)
value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value));
if (integer_zerop (value))
log = 0;
else if (TREE_INT_CST_HIGH (value) != 0)
log = HOST_BITS_PER_WIDE_INT + floor_log2 (TREE_INT_CST_HIGH (value));
else
log = floor_log2 (TREE_INT_CST_LOW (value));
return log + 1 + ! unsignedp;
}
void
binary_op_error (code)
enum tree_code code;
{
register const char *opname;
switch (code)
{
case NOP_EXPR:
error ("invalid truth-value expression");
return;
case PLUS_EXPR:
opname = "+"; break;
case MINUS_EXPR:
opname = "-"; break;
case MULT_EXPR:
opname = "*"; break;
case MAX_EXPR:
opname = "max"; break;
case MIN_EXPR:
opname = "min"; break;
case EQ_EXPR:
opname = "=="; break;
case NE_EXPR:
opname = "!="; break;
case LE_EXPR:
opname = "<="; break;
case GE_EXPR:
opname = ">="; break;
case LT_EXPR:
opname = "<"; break;
case GT_EXPR:
opname = ">"; break;
case LSHIFT_EXPR:
opname = "<<"; break;
case RSHIFT_EXPR:
opname = ">>"; break;
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
opname = "%"; break;
case TRUNC_DIV_EXPR:
case FLOOR_DIV_EXPR:
opname = "/"; break;
case BIT_AND_EXPR:
opname = "&"; break;
case BIT_IOR_EXPR:
opname = "|"; break;
case TRUTH_ANDIF_EXPR:
opname = "&&"; break;
case TRUTH_ORIF_EXPR:
opname = "||"; break;
case BIT_XOR_EXPR:
opname = "^"; break;
case LROTATE_EXPR:
case RROTATE_EXPR:
opname = "rotate"; break;
default:
opname = "unknown"; break;
}
error ("invalid operands to binary %s", opname);
}
tree
shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
tree *op0_ptr, *op1_ptr;
tree *restype_ptr;
enum tree_code *rescode_ptr;
{
register tree type;
tree op0 = *op0_ptr;
tree op1 = *op1_ptr;
int unsignedp0, unsignedp1;
int real1, real2;
tree primop0, primop1;
enum tree_code code = *rescode_ptr;
primop0 = get_narrower (op0, &unsignedp0);
primop1 = get_narrower (op1, &unsignedp1);
if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr)
unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0));
if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr)
unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1));
real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE;
real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE;
if (TREE_CONSTANT (primop0)
&& ! integer_zerop (primop1) && ! real_zerop (primop1))
{
register tree tem = primop0;
register int temi = unsignedp0;
primop0 = primop1;
primop1 = tem;
tem = op0;
op0 = op1;
op1 = tem;
*op0_ptr = op0;
*op1_ptr = op1;
unsignedp0 = unsignedp1;
unsignedp1 = temi;
temi = real1;
real1 = real2;
real2 = temi;
switch (code)
{
case LT_EXPR:
code = GT_EXPR;
break;
case GT_EXPR:
code = LT_EXPR;
break;
case LE_EXPR:
code = GE_EXPR;
break;
case GE_EXPR:
code = LE_EXPR;
break;
default:
break;
}
*rescode_ptr = code;
}
if (!real1 && !real2
&& TREE_CODE (primop1) == INTEGER_CST
&& TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr))
{
int min_gt, max_gt, min_lt, max_lt;
tree maxval, minval;
int unsignedp = TREE_UNSIGNED (*restype_ptr);
tree val;
type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
if (TREE_CODE (type) == ENUMERAL_TYPE)
type = type_for_size (TYPE_PRECISION (type), unsignedp0);
maxval = TYPE_MAX_VALUE (type);
minval = TYPE_MIN_VALUE (type);
if (unsignedp && !unsignedp0)
*restype_ptr = signed_type (*restype_ptr);
if (TREE_TYPE (primop1) != *restype_ptr)
primop1 = convert (*restype_ptr, primop1);
if (type != *restype_ptr)
{
minval = convert (*restype_ptr, minval);
maxval = convert (*restype_ptr, maxval);
}
if (unsignedp && unsignedp0)
{
min_gt = INT_CST_LT_UNSIGNED (primop1, minval);
max_gt = INT_CST_LT_UNSIGNED (primop1, maxval);
min_lt = INT_CST_LT_UNSIGNED (minval, primop1);
max_lt = INT_CST_LT_UNSIGNED (maxval, primop1);
}
else
{
min_gt = INT_CST_LT (primop1, minval);
max_gt = INT_CST_LT (primop1, maxval);
min_lt = INT_CST_LT (minval, primop1);
max_lt = INT_CST_LT (maxval, primop1);
}
val = 0;
if (code == NE_EXPR)
{
if (max_lt || min_gt)
val = boolean_true_node;
}
else if (code == EQ_EXPR)
{
if (max_lt || min_gt)
val = boolean_false_node;
}
else if (code == LT_EXPR)
{
if (max_lt)
val = boolean_true_node;
if (!min_lt)
val = boolean_false_node;
}
else if (code == GT_EXPR)
{
if (min_gt)
val = boolean_true_node;
if (!max_gt)
val = boolean_false_node;
}
else if (code == LE_EXPR)
{
if (!max_gt)
val = boolean_true_node;
if (min_gt)
val = boolean_false_node;
}
else if (code == GE_EXPR)
{
if (!min_lt)
val = boolean_true_node;
if (max_lt)
val = boolean_false_node;
}
if (unsignedp && !unsignedp0)
{
if (val != 0)
switch (code)
{
case LT_EXPR:
case GE_EXPR:
primop1 = TYPE_MIN_VALUE (type);
val = 0;
break;
case LE_EXPR:
case GT_EXPR:
primop1 = TYPE_MAX_VALUE (type);
val = 0;
break;
default:
break;
}
type = unsigned_type (type);
}
if (!max_gt && !unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
{
if (val == boolean_false_node)
warning ("comparison is always false due to limited range of data type");
if (val == boolean_true_node)
warning ("comparison is always true due to limited range of data type");
}
if (!min_lt && unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
{
if (val == boolean_false_node)
warning ("comparison is always false due to limited range of data type");
if (val == boolean_true_node)
warning ("comparison is always true due to limited range of data type");
}
if (val != 0)
{
if (TREE_SIDE_EFFECTS (primop0))
return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
return val;
}
}
else if (real1 && real2
&& (TYPE_PRECISION (TREE_TYPE (primop0))
== TYPE_PRECISION (TREE_TYPE (primop1))))
type = TREE_TYPE (primop0);
else if (unsignedp0 == unsignedp1 && real1 == real2
&& TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
&& TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
{
type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
type = signed_or_unsigned_type (unsignedp0
|| TREE_UNSIGNED (*restype_ptr),
type);
primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)),
primop0);
primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)),
primop1);
}
else
{
type = *restype_ptr;
primop0 = op0;
primop1 = op1;
if (!real1 && !real2 && integer_zerop (primop1)
&& TREE_UNSIGNED (*restype_ptr))
{
tree value = 0;
switch (code)
{
case GE_EXPR:
if (extra_warnings
&& ! (TREE_CODE (primop0) == INTEGER_CST
&& ! TREE_OVERFLOW (convert (signed_type (type),
primop0))))
warning ("comparison of unsigned expression >= 0 is always true");
value = boolean_true_node;
break;
case LT_EXPR:
if (extra_warnings
&& ! (TREE_CODE (primop0) == INTEGER_CST
&& ! TREE_OVERFLOW (convert (signed_type (type),
primop0))))
warning ("comparison of unsigned expression < 0 is always false");
value = boolean_false_node;
break;
default:
break;
}
if (value != 0)
{
if (TREE_SIDE_EFFECTS (primop0))
return build (COMPOUND_EXPR, TREE_TYPE (value),
primop0, value);
return value;
}
}
}
*op0_ptr = convert (type, primop0);
*op1_ptr = convert (type, primop1);
*restype_ptr = boolean_type_node;
return 0;
}
tree
truthvalue_conversion (expr)
tree expr;
{
if (TREE_CODE (expr) == ERROR_MARK)
return expr;
#if 0
switch (TREE_CODE (TREE_TYPE (expr)))
{
case RECORD_TYPE:
error ("struct type value used where scalar is required");
return boolean_false_node;
case UNION_TYPE:
error ("union type value used where scalar is required");
return boolean_false_node;
case ARRAY_TYPE:
error ("array type value used where scalar is required");
return boolean_false_node;
default:
break;
}
#endif
switch (TREE_CODE (expr))
{
#if 0
case COMPONENT_REF:
if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1)))
&& TREE_UNSIGNED (TREE_OPERAND (expr, 1)))
return expr;
break;
#endif
case EQ_EXPR:
#if 0
if (integer_zerop (TREE_OPERAND (expr, 1)))
return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0);
#endif
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:
TREE_TYPE (expr) = boolean_type_node;
return expr;
case ERROR_MARK:
return expr;
case INTEGER_CST:
return integer_zerop (expr) ? boolean_false_node : boolean_true_node;
case REAL_CST:
return real_zerop (expr) ? boolean_false_node : boolean_true_node;
case ADDR_EXPR:
if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (expr, 0))) == 'd'
&& DECL_EXTERNAL (TREE_OPERAND (expr, 0)))
break;
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
return build (COMPOUND_EXPR, boolean_type_node,
TREE_OPERAND (expr, 0), boolean_true_node);
else
return boolean_true_node;
case COMPLEX_EXPR:
return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
truthvalue_conversion (TREE_OPERAND (expr, 0)),
truthvalue_conversion (TREE_OPERAND (expr, 1)),
0);
case NEGATE_EXPR:
case ABS_EXPR:
case FLOAT_EXPR:
case FFS_EXPR:
return truthvalue_conversion (TREE_OPERAND (expr, 0));
case LROTATE_EXPR:
case RROTATE_EXPR:
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 1),
truthvalue_conversion (TREE_OPERAND (expr, 0)));
else
return truthvalue_conversion (TREE_OPERAND (expr, 0));
case COND_EXPR:
return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0),
truthvalue_conversion (TREE_OPERAND (expr, 1)),
truthvalue_conversion (TREE_OPERAND (expr, 2))));
case CONVERT_EXPR:
if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
|| TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
break;
case NOP_EXPR:
if (TYPE_PRECISION (TREE_TYPE (expr))
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
return truthvalue_conversion (TREE_OPERAND (expr, 0));
break;
case MINUS_EXPR:
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
&& TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
break;
case BIT_XOR_EXPR:
if (TREE_TYPE (TREE_OPERAND (expr, 0))
== TREE_TYPE (TREE_OPERAND (expr, 1)))
return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
TREE_OPERAND (expr, 1), 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 BIT_AND_EXPR:
if (integer_onep (TREE_OPERAND (expr, 1))
&& TREE_TYPE (expr) != boolean_type_node)
return build1 (NOP_EXPR, boolean_type_node, expr);
break;
case MODIFY_EXPR:
if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
warning ("suggest parentheses around assignment used as truth value");
break;
default:
break;
}
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
{
tree tem = save_expr (expr);
return (build_binary_op
((TREE_SIDE_EFFECTS (expr)
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
truthvalue_conversion (build_unary_op (REALPART_EXPR, tem, 0)),
truthvalue_conversion (build_unary_op (IMAGPART_EXPR, tem, 0)),
0));
}
return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
}
#if USE_CPPLIB
unsigned char *yy_cur, *yy_lim;
#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ())
#define UNGETC(c) ((c) == EOF ? 0 : yy_cur--)
int
yy_get_token ()
{
for (;;)
{
parse_in.limit = parse_in.token_buffer;
cpp_token = cpp_get_token (&parse_in);
if (cpp_token == CPP_EOF)
return -1;
yy_lim = CPP_PWRITTEN (&parse_in);
yy_cur = parse_in.token_buffer;
if (yy_cur < yy_lim)
return *yy_cur++;
}
}
char *
get_directive_line ()
{
static char *directive_buffer = NULL;
static unsigned buffer_length = 0;
register char *p;
register char *buffer_limit;
register int looking_for = 0;
register int char_escaped = 0;
if (buffer_length == 0)
{
directive_buffer = (char *)xmalloc (128);
buffer_length = 128;
}
buffer_limit = &directive_buffer[buffer_length];
for (p = directive_buffer; ; )
{
int c;
if (p >= buffer_limit)
{
register unsigned bytes_used = (p - directive_buffer);
buffer_length *= 2;
directive_buffer
= (char *)xrealloc (directive_buffer, buffer_length);
p = &directive_buffer[bytes_used];
buffer_limit = &directive_buffer[buffer_length];
}
c = GETC ();
if ((c == ' ' || c == '\t') && p == directive_buffer)
continue;
if (c == '\n' && looking_for == 0)
{
UNGETC (c);
c = '\0';
}
*p++ = c;
if (c == 0)
return directive_buffer;
if (looking_for)
{
if (looking_for == c && !char_escaped)
looking_for = 0;
}
else
if (c == '\'' || c == '"')
looking_for = c;
char_escaped = (c == '\\' && ! char_escaped);
}
}
#else
char *
get_directive_line (finput)
register FILE *finput;
{
static char *directive_buffer = NULL;
static unsigned buffer_length = 0;
register char *p;
register char *buffer_limit;
register int looking_for = 0;
register int char_escaped = 0;
if (buffer_length == 0)
{
directive_buffer = (char *)xmalloc (128);
buffer_length = 128;
}
buffer_limit = &directive_buffer[buffer_length];
for (p = directive_buffer; ; )
{
int c;
if (p >= buffer_limit)
{
register unsigned bytes_used = (p - directive_buffer);
buffer_length *= 2;
directive_buffer
= (char *)xrealloc (directive_buffer, buffer_length);
p = &directive_buffer[bytes_used];
buffer_limit = &directive_buffer[buffer_length];
}
c = getc (finput);
if ((c == ' ' || c == '\t') && p == directive_buffer)
continue;
if (looking_for == 0
&& (c == '\n' || c == EOF))
{
ungetc (c, finput);
c = '\0';
}
*p++ = c;
if (c == 0)
return directive_buffer;
if (looking_for)
{
if (looking_for == c && !char_escaped)
looking_for = 0;
}
else
if (c == '\'' || c == '"')
looking_for = c;
char_escaped = (c == '\\' && ! char_escaped);
}
}
#endif
tree
c_build_qualified_type (type, type_quals)
tree type;
int type_quals;
{
if ((type_quals & TYPE_QUAL_RESTRICT)
&& (!POINTER_TYPE_P (type)
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))))
{
error ("invalid use of `restrict'");
type_quals &= ~TYPE_QUAL_RESTRICT;
}
if (TREE_CODE (type) == ARRAY_TYPE)
return build_array_type (c_build_qualified_type (TREE_TYPE (type),
type_quals),
TYPE_DOMAIN (type));
return build_qualified_type (type, type_quals);
}
tree
maybe_objc_method_name (decl)
tree decl;
{
#ifdef OBJC_TREE_CODES
if (TREE_CODE (decl) == INSTANCE_METHOD_DECL
|| TREE_CODE (decl) == CLASS_METHOD_DECL)
return 1;
#endif
return 0;
}
void
c_apply_type_quals_to_decl (type_quals, decl)
int type_quals;
tree decl;
{
if (type_quals & TYPE_QUAL_CONST)
TREE_READONLY (decl) = 1;
if (type_quals & TYPE_QUAL_VOLATILE)
{
TREE_SIDE_EFFECTS (decl) = 1;
TREE_THIS_VOLATILE (decl) = 1;
}
if (type_quals & TYPE_QUAL_RESTRICT)
{
if (!TREE_TYPE (decl)
|| !POINTER_TYPE_P (TREE_TYPE (decl))
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (TREE_TYPE (decl))))
error ("invalid use of `restrict'");
else if (flag_strict_aliasing)
{
int pointed_to_alias_set
= get_alias_set (TREE_TYPE (TREE_TYPE (decl)));
if (!pointed_to_alias_set)
;
else
{
DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
record_alias_subset (pointed_to_alias_set,
DECL_POINTER_ALIAS_SET (decl));
}
}
}
}
static tree
c_find_base_decl (t)
tree t;
{
int i;
tree decl;
if (t == NULL_TREE || t == error_mark_node)
return NULL_TREE;
if (!POINTER_TYPE_P (TREE_TYPE (t)))
return NULL_TREE;
decl = NULL_TREE;
if (TREE_CODE (t) == FIELD_DECL
|| TREE_CODE (t) == PARM_DECL
|| TREE_CODE (t) == VAR_DECL)
return t;
switch (TREE_CODE_CLASS (TREE_CODE (t)))
{
case '1':
case '2':
case '3':
for (i = tree_code_length [(int) TREE_CODE (t)]; --i >= 0;)
{
tree d = c_find_base_decl (TREE_OPERAND (t, i));
if (d)
{
if (!decl)
decl = d;
else if (d && d != decl)
decl = NULL_TREE;
}
}
break;
default:
break;
}
return decl;
}
int
c_get_alias_set (t)
tree t;
{
tree type;
tree u;
if (t == error_mark_node)
return 0;
type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
? t : TREE_TYPE (t);
if (type == error_mark_node)
return 0;
if (TREE_CODE (t) == BIT_FIELD_REF)
return 0;
for (u = t;
TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF;
u = TREE_OPERAND (u, 0))
if (TREE_CODE (u) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
return 0;
if (TREE_CODE (t) == INDIRECT_REF)
{
tree decl = c_find_base_decl (TREE_OPERAND (t, 0));
if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
return DECL_POINTER_ALIAS_SET (decl);
}
if (TREE_CODE (t) == COMPONENT_REF
&& DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1)))
type = DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1));
if (TYPE_ALIAS_SET_KNOWN_P (type))
return TYPE_ALIAS_SET (type);
else if (TYPE_MAIN_VARIANT (type) != type)
TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type));
else if (TREE_CODE (type) == INTEGER_TYPE)
{
tree signed_variant;
signed_variant = signed_type (type);
if (signed_variant != type)
TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant);
else if (signed_variant == signed_char_type_node)
TYPE_ALIAS_SET (type) = 0;
}
else if (TREE_CODE (type) == ARRAY_TYPE)
TYPE_ALIAS_SET (type) = c_get_alias_set (TREE_TYPE (type));
else if (TREE_CODE (type) == FUNCTION_TYPE)
TYPE_ALIAS_SET (type) = 0;
else if (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
TYPE_ALIAS_SET (type) = 0;
else if (TREE_CODE (type) == POINTER_TYPE
|| TREE_CODE (type) == REFERENCE_TYPE)
{
tree t;
t = TYPE_MAIN_VARIANT (TREE_TYPE (type));
t = ((TREE_CODE (type) == POINTER_TYPE)
? build_pointer_type (t) : build_reference_type (t));
if (t != type)
TYPE_ALIAS_SET (type) = c_get_alias_set (t);
}
if (!TYPE_ALIAS_SET_KNOWN_P (type))
{
if (! TREE_PERMANENT (type))
TYPE_ALIAS_SET (type) = 0;
else
TYPE_ALIAS_SET (type) = new_alias_set ();
}
return TYPE_ALIAS_SET (type);
}