/* Subroutines shared by all languages that are variants of C.
- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
- Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
#include "ggc.h"
#include "expr.h"
#include "c-common.h"
+#include "tree-inline.h"
+#include "diagnostic.h"
#include "tm_p.h"
#include "obstack.h"
+#include "c-lex.h"
#include "cpplib.h"
#include "target.h"
cpp_reader *parse_in; /* Declared in c-lex.h. */
: "long long unsigned int"))
#endif
+/* The variant of the C language being processed. */
+
+enum c_language_kind c_language;
+
/* The following symbols are subsumed in the c_global_trees array, and
listed here individually for documentation purposes.
tree void_list_node;
- The lazily created VAR_DECLS for __FUNCTION__, __PRETTY_FUNCTION__,
+ The lazily created VAR_DECLs for __FUNCTION__, __PRETTY_FUNCTION__,
and __func__. (C doesn't generate __FUNCTION__ and__PRETTY_FUNCTION__
VAR_DECLS, but C++ does.)
tree function_name_decl_node;
- tree pretty_function_name_declnode;
+ tree pretty_function_name_decl_node;
tree c99_function_name_decl_node;
Stack of nested function name VAR_DECLs.
int warn_sequence_point;
+/* Nonzero means to warn about compile-time division by zero. */
+int warn_div_by_zero = 1;
+
/* The elements of `ridpointers' are identifier nodes for the reserved
type names and storage classes. It is indexed by a RID_... value. */
tree *ridpointers;
any action required right before expand_function_end is called. */
void (*lang_expand_function_end) PARAMS ((void));
-/* If this variable is defined to a non-NULL value, it will be called
- after the file has been completely parsed. */
-void (*back_end_hook) PARAMS ((tree));
-
/* Nonzero means the expression being parsed will never be evaluated.
This is a count, since unevaluated expressions can nest. */
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, A_MALLOC,
- A_NO_LIMIT_STACK, A_PURE};
-
/* Information about how a function name is generated. */
struct fname_var_t
{
- tree *decl; /* pointer to the VAR_DECL. */
- unsigned rid; /* RID number for the identifier. */
- int pretty; /* How pretty is it? */
+ tree *const decl; /* pointer to the VAR_DECL. */
+ const unsigned rid; /* RID number for the identifier. */
+ const int pretty; /* How pretty is it? */
};
/* The three ways of getting then name of the current function. */
{NULL, 0, 0},
};
-static void init_attributes PARAMS ((void));
static int constant_fits_type_p PARAMS ((tree, tree));
/* Keep a stack of if statements. We record the number of compound
static int if_stack_pointer = 0;
/* Record the start of an if-then, and record the start of it
- for ambiguous else detection. */
+ for ambiguous else detection.
+
+ COND is the condition for the if-then statement.
+
+ IF_STMT is the statement node that has already been created for
+ this if-then statement. It is created before parsing the
+ condition to keep line number information accurate. */
void
-c_expand_start_cond (cond, compstmt_count)
+c_expand_start_cond (cond, compstmt_count, if_stmt)
tree cond;
int compstmt_count;
+ tree if_stmt;
{
- tree if_stmt;
-
/* Make sure there is enough space on the stack. */
if (if_stack_space == 0)
{
if_stack_space = 10;
- if_stack = (if_elt *)xmalloc (10 * sizeof (if_elt));
+ 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_elt *) xrealloc (if_stack, if_stack_space * sizeof (if_elt));
}
- if_stmt = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
IF_COND (if_stmt) = cond;
add_stmt (if_stmt);
RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
}
+/* Begin an if-statement. Returns a newly created IF_STMT if
+ appropriate.
+
+ Unlike the C++ front-end, we do not call add_stmt here; it is
+ probably safe to do so, but I am not very familiar with this
+ code so I am being extra careful not to change its behavior
+ beyond what is strictly necessary for correctness. */
+
+tree
+c_begin_if_stmt ()
+{
+ tree r;
+ r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
+ return r;
+}
+
+/* Begin a while statement. Returns a newly created WHILE_STMT if
+ appropriate.
+
+ Unlike the C++ front-end, we do not call add_stmt here; it is
+ probably safe to do so, but I am not very familiar with this
+ code so I am being extra careful not to change its behavior
+ beyond what is strictly necessary for correctness. */
+
+tree
+c_begin_while_stmt ()
+{
+ tree r;
+ r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
+ return r;
+}
+
+void
+c_finish_while_stmt_cond (cond, while_stmt)
+ tree while_stmt;
+ tree cond;
+{
+ WHILE_COND (while_stmt) = cond;
+}
+
/* Push current bindings for the function name VAR_DECLS. */
void
if (body)
{
- /* They were called into existance, so add to statement tree. */
+ /* They were called into existence, so add to statement tree. */
body = chainon (body,
TREE_CHAIN (DECL_SAVED_TREE (current_function_decl)));
body = build_stmt (COMPOUND_STMT, body);
now. RID indicates how it should be formatted and IDENTIFIER_NODE
ID is its name (unfortunately C and C++ hold the RID values of
keywords in different places, so we can't derive RID from ID in
- this language independant code. */
+ this language independent code. */
tree
fname_decl (rid, id)
it after the function is complete. */
tree stmts = TREE_CHAIN (saved_last_tree);
- TREE_CHAIN (saved_last_tree) = NULL_TREE;
- last_tree = saved_last_tree;
- saved_function_name_decls = tree_cons (decl, stmts,
- saved_function_name_decls);
- }
- *fname_vars[ix].decl = decl;
- }
- if (!ix && !current_function_decl)
- pedwarn_with_decl (decl, "`%s' is not defined outside of function scope");
-
- return decl;
-}
-
-/* Given a chain of STRING_CST nodes,
- concatenate them into one STRING_CST
- and give it a suitable array-of-chars data type. */
-
-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;
- const int nchars_max = flag_isoc99 ? 4095 : 509;
-
- if (TREE_CHAIN (strings))
- {
- /* More than one in the chain, so concatenate. */
- register char *p, *q;
-
- /* Don't include the \0 at the end of each substring,
- except for the last one.
- Count wide strings and ordinary strings separately. */
- 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;
- }
- else
- length += (TREE_STRING_LENGTH (t) - 1);
- }
-
- /* If anything is wide, the non-wides will be converted,
- which makes them take more space. */
- if (wide_flag)
- length = length * wchar_bytes + wide_length;
-
- p = alloca (length);
-
- /* Copy the individual strings into the new combined string.
- If the combined string is wide, convert the chars to ints
- for any individual strings that are not wide. */
-
- q = p;
- for (t = strings; t; t = TREE_CHAIN (t))
- {
- int len = (TREE_STRING_LENGTH (t)
- - ((TREE_TYPE (t) == wchar_array_type_node)
- ? wchar_bytes : 1));
- if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
- {
- memcpy (q, TREE_STRING_POINTER (t), len);
- q += len;
- }
- else
- {
- int i, j;
- for (i = 0; i < len; i++)
- {
- if (BYTES_BIG_ENDIAN)
- {
- for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
- *q++ = 0;
- *q++ = TREE_STRING_POINTER (t)[i];
- }
- else
- {
- *q++ = TREE_STRING_POINTER (t)[i];
- for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
- *q++ = 0;
- }
- }
- }
- }
- if (wide_flag)
- {
- int i;
- for (i = 0; i < wchar_bytes; i++)
- *q++ = 0;
- }
- else
- *q = 0;
-
- value = build_string (length, p);
- }
- else
- {
- value = strings;
- length = TREE_STRING_LENGTH (value);
- if (TREE_TYPE (value) == wchar_array_type_node)
- wide_flag = 1;
- }
-
- /* Compute the number of elements, for the array type. */
- nchars = wide_flag ? length / wchar_bytes : length;
-
- if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
- pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support",
- nchars - 1, nchars_max, flag_isoc99 ? 99 : 89);
-
- /* Create the array type for the string constant.
- -Wwrite-strings says make the string constant an array of const char
- so that copying it to a non-const pointer will get a warning.
- For C++, this is the standard behavior. */
- if (flag_const_strings
- && (! flag_traditional && ! flag_writable_strings))
- {
- tree elements
- = build_type_variant (wide_flag ? wchar_type_node : char_type_node,
- 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 (wide_flag ? wchar_type_node : char_type_node,
- build_index_type (build_int_2 (nchars - 1, 0)));
-
- TREE_CONSTANT (value) = 1;
- TREE_READONLY (value) = ! flag_writable_strings;
- TREE_STATIC (value) = 1;
- return value;
-}
-\f
-/* Table of the tables of attributes (common, language, machine) searched. */
-static const struct attribute_spec *attribute_tables[3];
-
-static bool attributes_initialized = false;
-
-static tree handle_packed_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_nocommon_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_common_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_noreturn_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_unused_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_const_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_transparent_union_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_constructor_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_destructor_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_mode_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_section_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_aligned_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_weak_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_alias_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_no_check_memory_usage_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_malloc_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree handle_pure_attribute PARAMS ((tree *, tree, tree, int, bool *));
-
-/* Table of machine-independent attributes common to all C-like languages. */
-static const struct attribute_spec c_common_attribute_table[] =
-{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
- { "packed", 0, 0, false, false, false,
- handle_packed_attribute },
- { "nocommon", 0, 0, true, false, false,
- handle_nocommon_attribute },
- { "common", 0, 0, true, false, false,
- handle_common_attribute },
- /* FIXME: logically, noreturn attributes should be listed as
- "false, true, true" and apply to function types. But implementing this
- would require all the places in the compiler that use TREE_THIS_VOLATILE
- on a decl to identify non-returning functions to be located and fixed
- to check the function type instead. */
- { "noreturn", 0, 0, true, false, false,
- handle_noreturn_attribute },
- { "volatile", 0, 0, true, false, false,
- handle_noreturn_attribute },
- { "unused", 0, 0, false, false, false,
- handle_unused_attribute },
- /* The same comments as for noreturn attributes apply to const ones. */
- { "const", 0, 0, true, false, false,
- handle_const_attribute },
- { "transparent_union", 0, 0, false, false, false,
- handle_transparent_union_attribute },
- { "constructor", 0, 0, true, false, false,
- handle_constructor_attribute },
- { "destructor", 0, 0, true, false, false,
- handle_destructor_attribute },
- { "mode", 1, 1, true, false, false,
- handle_mode_attribute },
- { "section", 1, 1, true, false, false,
- handle_section_attribute },
- { "aligned", 0, 1, false, false, false,
- handle_aligned_attribute },
- { "format", 3, 3, true, false, false,
- handle_format_attribute },
- { "format_arg", 1, 1, true, false, false,
- handle_format_arg_attribute },
- { "weak", 0, 0, true, false, false,
- handle_weak_attribute },
- { "alias", 1, 1, true, false, false,
- handle_alias_attribute },
- { "no_instrument_function", 0, 0, true, false, false,
- handle_no_instrument_function_attribute },
- { "no_check_memory_usage", 0, 0, true, false, false,
- handle_no_check_memory_usage_attribute },
- { "malloc", 0, 0, true, false, false,
- handle_malloc_attribute },
- { "no_stack_limit", 0, 0, true, false, false,
- handle_no_limit_stack_attribute },
- { "pure", 0, 0, true, false, false,
- handle_pure_attribute },
- { NULL, 0, 0, false, false, false, NULL }
-};
-
-/* Default empty table of language attributes. */
-static const struct attribute_spec default_lang_attribute_table[] =
-{
- { NULL, 0, 0, false, false, false, NULL }
-};
-
-/* Table of machine-independent attributes for a particular language. */
-const struct attribute_spec *lang_attribute_table
- = default_lang_attribute_table;
-
-/* Initialize attribute tables, and make some sanity checks
- if --enable-checking. */
-
-static void
-init_attributes ()
-{
-#ifdef ENABLE_CHECKING
- int i;
-#endif
- attribute_tables[0] = c_common_attribute_table;
- attribute_tables[1] = lang_attribute_table;
- attribute_tables[2] = targetm.attribute_table;
-#ifdef ENABLE_CHECKING
- /* Make some sanity checks on the attribute tables. */
- for (i = 0;
- i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
- i++)
- {
- int j;
- for (j = 0; attribute_tables[i][j].name != NULL; j++)
- {
- /* The name must not begin and end with __. */
- const char *name = attribute_tables[i][j].name;
- int len = strlen (name);
- if (name[0] == '_' && name[1] == '_'
- && name[len - 1] == '_' && name[len - 2] == '_')
- abort ();
- /* The minimum and maximum lengths must be consistent. */
- if (attribute_tables[i][j].min_length < 0)
- abort ();
- if (attribute_tables[i][j].max_length != -1
- && attribute_tables[i][j].max_length < attribute_tables[i][j].min_length)
- abort ();
- /* An attribute cannot require both a DECL and a TYPE. */
- if (attribute_tables[i][j].decl_required
- && attribute_tables[i][j].type_required)
- abort ();
- /* If an attribute requires a function type, in particular
- it requires a type. */
- if (attribute_tables[i][j].function_type_required
- && !attribute_tables[i][j].type_required)
- abort ();
- }
- }
- /* Check that each name occurs just once in each table. */
- for (i = 0;
- i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
- i++)
- {
- int j, k;
- for (j = 0; attribute_tables[i][j].name != NULL; j++)
- for (k = j + 1; attribute_tables[i][k].name != NULL; k++)
- if (!strcmp (attribute_tables[i][j].name,
- attribute_tables[i][k].name))
- abort ();
- }
- /* Check that no name occurs in more than one table. */
- for (i = 0;
- i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
- i++)
- {
- int j;
- for (j = i + 1;
- j < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
- j++)
- {
- int k, l;
- for (k = 0; attribute_tables[i][k].name != NULL; k++)
- for (l = 0; attribute_tables[j][l].name != NULL; l++)
- if (!strcmp (attribute_tables[i][k].name,
- attribute_tables[j][l].name))
- abort ();
- }
- }
-#endif
- attributes_initialized = true;
-}
-\f
-/* Process the attributes listed in ATTRIBUTES and install them in *NODE,
- which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
- it should be modified in place; if a TYPE, a copy should be created
- unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS. FLAGS gives further
- information, in the form of a bitwise OR of flags in enum attribute_flags
- from tree.h. Depending on these flags, some attributes may be
- returned to be applied at a later stage (for example, to apply
- a decl attribute to the declaration rather than to its type). */
-
-tree
-decl_attributes (node, attributes, flags)
- tree *node, attributes;
- int flags;
-{
- tree a;
- tree returned_attrs = NULL_TREE;
-
- if (!attributes_initialized)
- init_attributes ();
-
- (*targetm.insert_attributes) (*node, &attributes);
-
- for (a = attributes; a; a = TREE_CHAIN (a))
- {
- tree name = TREE_PURPOSE (a);
- tree args = TREE_VALUE (a);
- tree *anode = node;
- const struct attribute_spec *spec = NULL;
- bool no_add_attrs = 0;
- int i;
-
- for (i = 0;
- i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
- i++)
- {
- int j;
- for (j = 0; attribute_tables[i][j].name != NULL; j++)
- {
- if (is_attribute_p (attribute_tables[i][j].name, name))
- {
- spec = &attribute_tables[i][j];
- break;
- }
- }
- if (spec != NULL)
- break;
- }
-
- if (spec == NULL)
- {
- warning ("`%s' attribute directive ignored",
- IDENTIFIER_POINTER (name));
- continue;
- }
- else if (list_length (args) < spec->min_length
- || (spec->max_length >= 0
- && list_length (args) > spec->max_length))
- {
- error ("wrong number of arguments specified for `%s' attribute",
- IDENTIFIER_POINTER (name));
- continue;
- }
-
- if (spec->decl_required && !DECL_P (*anode))
- {
- if (flags & ((int) ATTR_FLAG_DECL_NEXT
- | (int) ATTR_FLAG_FUNCTION_NEXT
- | (int) ATTR_FLAG_ARRAY_NEXT))
- {
- /* Pass on this attribute to be tried again. */
- returned_attrs = tree_cons (name, args, returned_attrs);
- continue;
- }
- else
- {
- warning ("`%s' attribute does not apply to types",
- IDENTIFIER_POINTER (name));
- continue;
- }
- }
-
- if (spec->type_required && DECL_P (*anode))
- {
- anode = &TREE_TYPE (*anode);
- }
-
- if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
- && TREE_CODE (*anode) != METHOD_TYPE)
- {
- if (TREE_CODE (*anode) == POINTER_TYPE
- && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
- {
- if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *anode = build_type_copy (*anode);
- anode = &TREE_TYPE (*anode);
- }
- else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
- {
- /* Pass on this attribute to be tried again. */
- returned_attrs = tree_cons (name, args, returned_attrs);
- continue;
- }
-
- if (TREE_CODE (*anode) != FUNCTION_TYPE
- && TREE_CODE (*anode) != METHOD_TYPE)
- {
- warning ("`%s' attribute only applies to function types",
- IDENTIFIER_POINTER (name));
- continue;
- }
- }
-
- if (spec->handler != NULL)
- returned_attrs = chainon ((*spec->handler) (anode, name, args,
- flags, &no_add_attrs),
- returned_attrs);
- if (!no_add_attrs)
- {
- tree old_attrs;
- tree a;
-
- if (DECL_P (*anode))
- old_attrs = DECL_ATTRIBUTES (*anode);
- else
- old_attrs = TYPE_ATTRIBUTES (*anode);
-
- for (a = lookup_attribute (spec->name, old_attrs);
- a != NULL_TREE;
- a = lookup_attribute (spec->name, TREE_CHAIN (a)))
- {
- if (simple_cst_equal (TREE_VALUE (a), args) == 1)
- break;
- }
-
- if (a == NULL_TREE)
- {
- /* This attribute isn't already in the list. */
- if (DECL_P (*anode))
- DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
- else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
- TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
- else
- *anode = build_type_attribute_variant (*anode,
- tree_cons (name, args,
- old_attrs));
- }
- }
- }
-
- return returned_attrs;
-}
-
-/* Handle a "packed" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_packed_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags;
- bool *no_add_attrs;
-{
- tree *type = NULL;
- if (DECL_P (*node))
- {
- if (TREE_CODE (*node) == TYPE_DECL)
- type = &TREE_TYPE (*node);
- }
- else
- type = node;
- if (type)
- {
- if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *type = build_type_copy (*type);
- TYPE_PACKED (*type) = 1;
- }
- else if (TREE_CODE (*node) == FIELD_DECL)
- DECL_PACKED (*node) = 1;
- /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
- used for DECL_REGISTER. It wouldn't mean anything anyway. */
- else
- {
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "nocommon" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_nocommon_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- if (TREE_CODE (*node) == VAR_DECL)
- DECL_COMMON (*node) = 0;
- else
- {
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "common" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_common_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- if (TREE_CODE (*node) == VAR_DECL)
- DECL_COMMON (*node) = 1;
- else
- {
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "noreturn" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_noreturn_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree type = TREE_TYPE (*node);
-
- /* See FIXME comment in c_common_attribute_table. */
- if (TREE_CODE (*node) == FUNCTION_DECL)
- TREE_THIS_VOLATILE (*node) = 1;
- else if (TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- TREE_TYPE (*node)
- = build_pointer_type (build_type_variant (TREE_TYPE (type),
- TREE_READONLY (TREE_TYPE (type)), 1));
- else
- {
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "unused" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_unused_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags;
- bool *no_add_attrs;
-{
- if (DECL_P (*node))
- {
- tree decl = *node;
-
- if (TREE_CODE (decl) == PARM_DECL
- || TREE_CODE (decl) == VAR_DECL
- || TREE_CODE (decl) == FUNCTION_DECL
- || TREE_CODE (decl) == LABEL_DECL
- || TREE_CODE (decl) == TYPE_DECL)
- TREE_USED (decl) = 1;
- else
- {
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
- }
- else
- {
- if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *node = build_type_copy (*node);
- TREE_USED (*node) = 1;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "const" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_const_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree type = TREE_TYPE (*node);
-
- /* See FIXME comment on noreturn in c_common_attribute_table. */
- if (TREE_CODE (*node) == FUNCTION_DECL)
- TREE_READONLY (*node) = 1;
- else if (TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- TREE_TYPE (*node)
- = build_pointer_type (build_type_variant (TREE_TYPE (type), 1,
- TREE_THIS_VOLATILE (TREE_TYPE (type))));
- else
- {
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "transparent_union" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_transparent_union_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags;
- bool *no_add_attrs;
-{
- tree decl = NULL_TREE;
- tree *type = NULL;
- int is_type = 0;
-
- if (DECL_P (*node))
- {
- decl = *node;
- type = &TREE_TYPE (decl);
- is_type = TREE_CODE (*node) == TYPE_DECL;
- }
- else if (TYPE_P (*node))
- type = node, is_type = 1;
-
- if (is_type
- && TREE_CODE (*type) == UNION_TYPE
- && (decl == 0
- || (TYPE_FIELDS (*type) != 0
- && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))))
- {
- if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *type = build_type_copy (*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));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "constructor" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_constructor_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree decl = *node;
- tree type = TREE_TYPE (decl);
-
- 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));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "destructor" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_destructor_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree decl = *node;
- tree type = TREE_TYPE (decl);
-
- 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));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "mode" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_mode_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree decl = *node;
- tree type = TREE_TYPE (decl);
-
- *no_add_attrs = true;
-
- 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;
- }
-
- /* Give this decl a type with the specified mode.
- First check for the special modes. */
- 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
- {
- if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type)
- ? TYPE_PRECISION(uintmax_type_node)
- : TYPE_PRECISION(intmax_type_node))
- && pedantic)
- pedwarn ("type with more precision than %s",
- TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t");
- TREE_TYPE (decl) = type = typefm;
- DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
- if (TREE_CODE (decl) != FIELD_DECL)
- layout_decl (decl, 0);
- }
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "section" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_section_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name ATTRIBUTE_UNUSED;
- tree args;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree decl = *node;
-
- if (targetm.have_named_sections)
- {
- 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");
- *no_add_attrs = true;
- }
- /* The decl may have already been given a section attribute
- from a previous declaration. Ensure they match. */
- 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");
- *no_add_attrs = true;
- }
- else
- DECL_SECTION_NAME (decl) = TREE_VALUE (args);
- }
- else
- {
- error_with_decl (*node,
- "section attribute not allowed for `%s'");
- *no_add_attrs = true;
- }
- }
- else
- {
- error_with_decl (*node,
- "section attributes are not supported for this target");
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "aligned" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_aligned_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name ATTRIBUTE_UNUSED;
- tree args;
- int flags;
- bool *no_add_attrs;
-{
- tree decl = NULL_TREE;
- tree *type = NULL;
- int is_type = 0;
- tree align_expr = (args ? TREE_VALUE (args)
- : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
- int i;
-
- if (DECL_P (*node))
- {
- decl = *node;
- type = &TREE_TYPE (decl);
- is_type = TREE_CODE (*node) == TYPE_DECL;
- }
- else if (TYPE_P (*node))
- type = node, is_type = 1;
-
- /* Strip any NOPs of any kind. */
- 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");
- *no_add_attrs = true;
- }
- else if ((i = tree_log2 (align_expr)) == -1)
- {
- error ("requested alignment is not a power of 2");
- *no_add_attrs = true;
- }
- else if (i > HOST_BITS_PER_INT - 2)
- {
- error ("requested alignment is too large");
- *no_add_attrs = true;
- }
- else if (is_type)
- {
- /* If we have a TYPE_DECL, then copy the type, so that we
- don't accidentally modify a builtin type. See pushdecl. */
- if (decl && TREE_TYPE (decl) != error_mark_node
- && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
- {
- tree tt = TREE_TYPE (decl);
- *type = build_type_copy (*type);
- DECL_ORIGINAL_TYPE (decl) = tt;
- TYPE_NAME (*type) = decl;
- TREE_USED (*type) = TREE_USED (decl);
- TREE_TYPE (decl) = *type;
- }
- else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- *type = build_type_copy (*type);
-
- TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
- TYPE_USER_ALIGN (*type) = 1;
- }
- else if (TREE_CODE (decl) != VAR_DECL
- && TREE_CODE (decl) != FIELD_DECL)
- {
- error_with_decl (decl,
- "alignment may not be specified for `%s'");
- *no_add_attrs = true;
- }
- else
- {
- DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
- DECL_USER_ALIGN (decl) = 1;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "weak" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_weak_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name ATTRIBUTE_UNUSED;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs ATTRIBUTE_UNUSED;
-{
- declare_weak (*node);
-
- return NULL_TREE;
-}
-
-/* Handle an "alias" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_alias_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree decl = *node;
-
- 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");
- *no_add_attrs = true;
- }
- 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");
- *no_add_attrs = true;
- return NULL_TREE;
- }
- id = get_identifier (TREE_STRING_POINTER (id));
- /* This counts as a use of the object pointed to. */
- TREE_USED (id) = 1;
-
- 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));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "no_instrument_function" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_no_instrument_function_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree decl = *node;
-
- if (TREE_CODE (decl) != FUNCTION_DECL)
- {
- error_with_decl (decl,
- "`%s' attribute applies only to functions",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
- else if (DECL_INITIAL (decl))
- {
- error_with_decl (decl,
- "can't set `%s' attribute after definition",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
- else
- DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
-
- return NULL_TREE;
-}
-
-/* Handle a "no_check_memory_usage" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_no_check_memory_usage_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree decl = *node;
-
- if (TREE_CODE (decl) != FUNCTION_DECL)
- {
- error_with_decl (decl,
- "`%s' attribute applies only to functions",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
- else if (DECL_INITIAL (decl))
- {
- error_with_decl (decl,
- "can't set `%s' attribute after definition",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
- else
- DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
-
- return NULL_TREE;
-}
-
-/* Handle a "malloc" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_malloc_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- if (TREE_CODE (*node) == FUNCTION_DECL)
- DECL_IS_MALLOC (*node) = 1;
- /* ??? TODO: Support types. */
- else
- {
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "no_limit_stack" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_no_limit_stack_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- tree decl = *node;
-
- if (TREE_CODE (decl) != FUNCTION_DECL)
- {
- error_with_decl (decl,
- "`%s' attribute applies only to functions",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
- else if (DECL_INITIAL (decl))
- {
- error_with_decl (decl,
- "can't set `%s' attribute after definition",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
- else
- DECL_NO_LIMIT_STACK (decl) = 1;
-
- return NULL_TREE;
-}
-
-/* Handle a "pure" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_pure_attribute (node, name, args, flags, no_add_attrs)
- tree *node;
- tree name;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- if (TREE_CODE (*node) == FUNCTION_DECL)
- DECL_IS_PURE (*node) = 1;
- /* ??? TODO: Support types. */
- else
- {
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
+ TREE_CHAIN (saved_last_tree) = NULL_TREE;
+ last_tree = saved_last_tree;
+ saved_function_name_decls = tree_cons (decl, stmts,
+ saved_function_name_decls);
+ }
+ *fname_vars[ix].decl = decl;
}
-
- return NULL_TREE;
+ if (!ix && !current_function_decl)
+ pedwarn_with_decl (decl, "`%s' is not defined outside of function scope");
+
+ return decl;
}
-/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
- lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
-
- The head of the declspec list is stored in DECLSPECS.
- The head of the attribute list is stored in PREFIX_ATTRIBUTES.
-
- Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
- the list elements. We drop the containing TREE_LIST nodes and link the
- resulting attributes together the way decl_attributes expects them. */
+/* Given a chain of STRING_CST nodes,
+ concatenate them into one STRING_CST
+ and give it a suitable array-of-chars data type. */
-void
-split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
- tree specs_attrs;
- tree *declspecs, *prefix_attributes;
+tree
+combine_strings (strings)
+ tree strings;
{
- tree t, s, a, next, specs, attrs;
-
- /* This can happen after an __extension__ in pedantic mode. */
- if (specs_attrs != NULL_TREE
- && TREE_CODE (specs_attrs) == INTEGER_CST)
- {
- *declspecs = NULL_TREE;
- *prefix_attributes = NULL_TREE;
- return;
- }
+ tree value, t;
+ int length = 1;
+ int wide_length = 0;
+ int wide_flag = 0;
+ int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+ int nchars;
+ const int nchars_max = flag_isoc99 ? 4095 : 509;
- /* This can happen in c++ (eg: decl: typespec initdecls ';'). */
- if (specs_attrs != NULL_TREE
- && TREE_CODE (specs_attrs) != TREE_LIST)
+ if (TREE_CHAIN (strings))
{
- *declspecs = specs_attrs;
- *prefix_attributes = NULL_TREE;
- return;
- }
-
- /* Remember to keep the lists in the same order, element-wise. */
+ /* More than one in the chain, so concatenate. */
+ char *p, *q;
- specs = s = NULL_TREE;
- attrs = a = NULL_TREE;
- for (t = specs_attrs; t; t = next)
- {
- next = TREE_CHAIN (t);
- /* Declspecs have a non-NULL TREE_VALUE. */
- if (TREE_VALUE (t) != NULL_TREE)
+ /* Don't include the \0 at the end of each substring,
+ except for the last one.
+ Count wide strings and ordinary strings separately. */
+ for (t = strings; t; t = TREE_CHAIN (t))
{
- if (specs == NULL_TREE)
- specs = s = t;
- else
+ if (TREE_TYPE (t) == wchar_array_type_node)
{
- TREE_CHAIN (s) = t;
- s = t;
+ wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
+ wide_flag = 1;
}
- }
- /* The TREE_PURPOSE may also be empty in the case of
- __attribute__(()). */
- else if (TREE_PURPOSE (t) != NULL_TREE)
- {
- if (attrs == NULL_TREE)
- attrs = a = TREE_PURPOSE (t);
else
{
- TREE_CHAIN (a) = TREE_PURPOSE (t);
- a = TREE_PURPOSE (t);
+ length += (TREE_STRING_LENGTH (t) - 1);
+ if (C_ARTIFICIAL_STRING_P (t) && !in_system_header)
+ warning ("concatenation of string literals with __FUNCTION__ is deprecated. This feature will be removed in future");
}
- /* More attrs can be linked here, move A to the end. */
- while (TREE_CHAIN (a) != NULL_TREE)
- a = TREE_CHAIN (a);
}
- }
- /* Terminate the lists. */
- if (s != NULL_TREE)
- TREE_CHAIN (s) = NULL_TREE;
- if (a != NULL_TREE)
- TREE_CHAIN (a) = NULL_TREE;
+ /* If anything is wide, the non-wides will be converted,
+ which makes them take more space. */
+ if (wide_flag)
+ length = length * wchar_bytes + wide_length;
- /* All done. */
- *declspecs = specs;
- *prefix_attributes = attrs;
-}
+ p = alloca (length);
+
+ /* Copy the individual strings into the new combined string.
+ If the combined string is wide, convert the chars to ints
+ for any individual strings that are not wide. */
-/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
- This function is used by the parser when a rule will accept attributes
- in a particular position, but we don't want to support that just yet.
+ q = p;
+ for (t = strings; t; t = TREE_CHAIN (t))
+ {
+ int len = (TREE_STRING_LENGTH (t)
+ - ((TREE_TYPE (t) == wchar_array_type_node)
+ ? wchar_bytes : 1));
+ if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
+ {
+ memcpy (q, TREE_STRING_POINTER (t), len);
+ q += len;
+ }
+ else
+ {
+ int i, j;
+ for (i = 0; i < len; i++)
+ {
+ if (BYTES_BIG_ENDIAN)
+ {
+ for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
+ *q++ = 0;
+ *q++ = TREE_STRING_POINTER (t)[i];
+ }
+ else
+ {
+ *q++ = TREE_STRING_POINTER (t)[i];
+ for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
+ *q++ = 0;
+ }
+ }
+ }
+ }
+ if (wide_flag)
+ {
+ int i;
+ for (i = 0; i < wchar_bytes; i++)
+ *q++ = 0;
+ }
+ else
+ *q = 0;
- A warning is issued for every ignored attribute. */
+ value = build_string (length, p);
+ }
+ else
+ {
+ value = strings;
+ length = TREE_STRING_LENGTH (value);
+ if (TREE_TYPE (value) == wchar_array_type_node)
+ wide_flag = 1;
+ }
-tree
-strip_attrs (specs_attrs)
- tree specs_attrs;
-{
- tree specs, attrs;
+ /* Compute the number of elements, for the array type. */
+ nchars = wide_flag ? length / wchar_bytes : length;
- split_specs_attrs (specs_attrs, &specs, &attrs);
+ if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
+ pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support",
+ nchars - 1, nchars_max, flag_isoc99 ? 99 : 89);
- while (attrs)
+ /* Create the array type for the string constant.
+ -Wwrite-strings says make the string constant an array of const char
+ so that copying it to a non-const pointer will get a warning.
+ For C++, this is the standard behavior. */
+ if (flag_const_strings
+ && (! flag_traditional && ! flag_writable_strings))
{
- warning ("`%s' attribute ignored",
- IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
- attrs = TREE_CHAIN (attrs);
+ tree elements
+ = build_type_variant (wide_flag ? wchar_type_node : char_type_node,
+ 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 (wide_flag ? wchar_type_node : char_type_node,
+ build_index_type (build_int_2 (nchars - 1, 0)));
- return specs;
+ TREE_CONSTANT (value) = 1;
+ TREE_READONLY (value) = ! flag_writable_strings;
+ TREE_STATIC (value) = 1;
+ return value;
}
\f
static int is_valid_printf_arglist PARAMS ((tree));
static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier));
static rtx c_expand_builtin_printf PARAMS ((tree, rtx, enum machine_mode,
- enum expand_modifier, int));
+ enum expand_modifier, int, int));
static rtx c_expand_builtin_fprintf PARAMS ((tree, rtx, enum machine_mode,
- enum expand_modifier, int));
+ enum expand_modifier, int, int));
\f
/* Print a warning if a constant expression had overflow in folding.
Invoke this function on every expression that the language
}
}
-/* Return nonzero if X is a tree that can be verified by the sequence poitn
+/* Return nonzero if X is a tree that can be verified by the sequence point
warnings. */
static int
warning_candidate_p (x)
{
/* Do default conversion if safe and possibly important,
in case within ({...}). */
- if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr))
+ if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+ && (flag_isoc99 || lvalue_p (expr)))
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
expr = default_conversion (expr);
return unsignedp ? widest_unsigned_literal_type_node
: widest_integer_literal_type_node;
- if (mode == TYPE_MODE (intQI_type_node))
+ if (mode == QImode)
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
- if (mode == TYPE_MODE (intHI_type_node))
+ if (mode == HImode)
return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
- if (mode == TYPE_MODE (intSI_type_node))
+ if (mode == SImode)
return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
- if (mode == TYPE_MODE (intDI_type_node))
+ if (mode == DImode)
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
#if HOST_BITS_PER_WIDE_INT >= 64
return build_pointer_type (integer_type_node);
#ifdef VECTOR_MODE_SUPPORTED_P
- if (mode == TYPE_MODE (V4SF_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
- return V4SF_type_node;
- if (mode == TYPE_MODE (V4SI_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
- return V4SI_type_node;
- if (mode == TYPE_MODE (V2SI_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
- return V2SI_type_node;
- if (mode == TYPE_MODE (V4HI_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
- return V4HI_type_node;
- if (mode == TYPE_MODE (V8QI_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
- return V8QI_type_node;
+ if (VECTOR_MODE_SUPPORTED_P (mode))
+ {
+ switch (mode)
+ {
+ case V16QImode:
+ return unsignedp ? unsigned_V16QI_type_node : V16QI_type_node;
+ case V8HImode:
+ return unsignedp ? unsigned_V8HI_type_node : V8HI_type_node;
+ case V4SImode:
+ return unsignedp ? unsigned_V4SI_type_node : V4SI_type_node;
+ case V2SImode:
+ return unsignedp ? unsigned_V2SI_type_node : V2SI_type_node;
+ case V4HImode:
+ return unsignedp ? unsigned_V4HI_type_node : V4HI_type_node;
+ case V8QImode:
+ return unsignedp ? unsigned_V8QI_type_node : V8QI_type_node;
+ case V4SFmode:
+ return V4SF_type_node;
+ case V2SFmode:
+ return V2SF_type_node;
+ default:
+ break;
+ }
+ }
#endif
return 0;
binary_op_error (code)
enum tree_code code;
{
- register const char *opname;
+ const char *opname;
switch (code)
{
tree *restype_ptr;
enum tree_code *rescode_ptr;
{
- register tree type;
+ tree type;
tree op0 = *op0_ptr;
tree op1 = *op1_ptr;
int unsignedp0, unsignedp1;
if (TREE_CONSTANT (primop0)
&& ! integer_zerop (primop1) && ! real_zerop (primop1))
{
- register tree tem = primop0;
- register int temi = unsignedp0;
+ tree tem = primop0;
+ int temi = unsignedp0;
primop0 = primop1;
primop1 = tem;
tem = op0;
return real_zerop (expr) ? boolean_false_node : boolean_true_node;
case ADDR_EXPR:
- /* If we are taking the address of a external decl, it might be zero
+ /* If we are taking the address of an external decl, it might be zero
if it is weak, so we cannot optimize. */
if (DECL_P (TREE_OPERAND (expr, 0))
&& DECL_EXTERNAL (TREE_OPERAND (expr, 0)))
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (TREE_TYPE (decl))))
error ("invalid use of `restrict'");
else if (flag_strict_aliasing)
- {
- /* No two restricted pointers can point at the same thing.
- However, a restricted pointer can point at the same thing
- as an unrestricted pointer, if that unrestricted pointer
- is based on the restricted pointer. So, we make the
- alias set for the restricted pointer a subset of the
- alias set for the type pointed to by the type of the
- decl. */
-
- HOST_WIDE_INT pointed_to_alias_set
- = get_alias_set (TREE_TYPE (TREE_TYPE (decl)));
-
- if (pointed_to_alias_set == 0)
- /* It's not legal to make a subset of alias set zero. */
- ;
- else
- {
- DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
- record_alias_subset (pointed_to_alias_set,
- DECL_POINTER_ALIAS_SET (decl));
- }
- }
+ /* Indicate we need to make a unique alias set for this pointer.
+ We can't do it here because it might be pointing to an
+ incomplete type. */
+ DECL_POINTER_ALIAS_SET (decl) = -2;
}
}
or a type. Return -1 if we don't do anything special. */
HOST_WIDE_INT
-lang_get_alias_set (t)
+c_common_get_alias_set (t)
tree t;
{
tree u;
Technically, this approach is actually more conservative that
it needs to be. In particular, `const int *' and `int *'
- chould be in different alias sets, according to the C and C++
+ should be in different alias sets, according to the C and C++
standard, since their types are not the same, and so,
technically, an `int **' and `const int **' cannot point at
the same thing.
if (t1 != t)
return get_alias_set (t1);
}
- /* It's not yet safe to use alias sets for classes in C++ because
- the TYPE_FIELDs list for a class doesn't mention base classes. */
- else if (c_language == clk_cplusplus && AGGREGATE_TYPE_P (t))
- return 0;
return -1;
}
t = size_one_node;
}
else if (TREE_CODE (expr) == COMPONENT_REF
- && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL)
+ && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL)
t = size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT);
else if (TREE_CODE (expr) == INDIRECT_REF)
int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t)));
while (TREE_CODE (t) == NOP_EXPR
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE)
{
int thisalign;
return fold (build1 (NOP_EXPR, c_size_type_node, t));
}
\f
+/* Give the specifications for the format attributes, used by C and all
+ descendents. */
+
+static const struct attribute_spec c_format_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "format", 3, 3, false, true, true,
+ handle_format_attribute },
+ { "format_arg", 1, 1, false, true, true,
+ handle_format_arg_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
/* Build tree nodes and builtin functions common to both C and C++ language
frontends. */
typedef enum builtin_type builtin_type;
- tree builtin_types[(int)BT_LAST];
+ tree builtin_types[(int) BT_LAST];
int wchar_type_size;
tree array_domain_type;
/* Either char* or void*. */
tree va_list_ref_type_node;
tree va_list_arg_type_node;
+ /* We must initialize this before any builtin functions (which might have
+ attributes) are declared. (c_common_init is too late.) */
+ format_attribute_table = c_format_attribute_table;
+
/* Define `int' and `char' first so that dbx will output them first. */
record_builtin_type (RID_INT, NULL, integer_type_node);
record_builtin_type (RID_CHAR, "char", char_type_node);
}
+/* Linked list of disabled built-in functions. */
+
+typedef struct disabled_builtin
+{
+ const char *name;
+ struct disabled_builtin *next;
+} disabled_builtin;
+static disabled_builtin *disabled_builtins = NULL;
+
+static bool builtin_function_disabled_p PARAMS ((const char *));
+
+/* Disable a built-in function specified by -fno-builtin-NAME. If NAME
+ begins with "__builtin_", give an error. */
+
+void
+disable_builtin_function (name)
+ const char *name;
+{
+ if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0)
+ error ("cannot disable built-in function `%s'", name);
+ else
+ {
+ disabled_builtin *new = xmalloc (sizeof (disabled_builtin));
+ new->name = name;
+ new->next = disabled_builtins;
+ disabled_builtins = new;
+ }
+}
+
+
+/* Return true if the built-in function NAME has been disabled, false
+ otherwise. */
+
+static bool
+builtin_function_disabled_p (name)
+ const char *name;
+{
+ disabled_builtin *p;
+ for (p = disabled_builtins; p != NULL; p = p->next)
+ {
+ if (strcmp (name, p->name) == 0)
+ return true;
+ }
+ return false;
+}
+
+
/* Possibly define a builtin function with one or two names. BUILTIN_NAME
is an __builtin_-prefixed name; NAME is the ordinary name; one or both
of these may be NULL (though both being NULL is useless).
TREE_SIDE_EFFECTS (bdecl) = 1;
}
}
- if (name != 0 && !flag_no_builtin && !(nonansi_p && flag_no_nonansi_builtin))
+ if (name != 0 && !flag_no_builtin && !builtin_function_disabled_p (name)
+ && !(nonansi_p && flag_no_nonansi_builtin))
{
decl = builtin_function (name, type, function_code, class, NULL);
if (nonansi_p)
self_promoting_args_p (parms)
tree parms;
{
- register tree t;
+ tree t;
for (t = parms; t; t = TREE_CHAIN (t))
{
- register tree type = TREE_VALUE (t);
+ tree type = TREE_VALUE (t);
if (TREE_CHAIN (t) == 0 && type != void_type_node)
return 0;
void
c_mark_lang_decl (c)
- struct c_lang_decl *c;
+ struct c_lang_decl *c ATTRIBUTE_UNUSED;
{
- ggc_mark_tree (c->saved_tree);
}
/* Mark F for GC. */
STMT_EXPR. */
push_temp_slots ();
rtl_expr = expand_start_stmt_expr ();
+
+ /* If we want the result of this expression, find the last
+ EXPR_STMT in the COMPOUND_STMT and mark it as addressable. */
+ if (target != const0_rtx
+ && TREE_CODE (STMT_EXPR_STMT (exp)) == COMPOUND_STMT
+ && TREE_CODE (COMPOUND_BODY (STMT_EXPR_STMT (exp))) == SCOPE_STMT)
+ {
+ tree expr = COMPOUND_BODY (STMT_EXPR_STMT (exp));
+ tree last = TREE_CHAIN (expr);
+
+ while (TREE_CHAIN (last))
+ {
+ expr = last;
+ last = TREE_CHAIN (last);
+ }
+
+ if (TREE_CODE (last) == SCOPE_STMT
+ && TREE_CODE (expr) == EXPR_STMT)
+ TREE_ADDRESSABLE (expr) = 1;
+ }
+
expand_stmt (STMT_EXPR_STMT (exp));
expand_end_stmt_expr (rtl_expr);
result = expand_expr (rtl_expr, target, tmode, modifier);
== BUILT_IN_FRONTEND))
return c_expand_builtin (exp, target, tmode, modifier);
else
- abort();
+ abort ();
}
break;
+ 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 (decl, target, tmode, modifier);
+ }
+
default:
abort ();
}
return -1;
}
+/* Hook used by staticp to handle language-specific tree codes. */
+
+int
+c_staticp (exp)
+ tree exp;
+{
+ if (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
+ && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)))
+ return 1;
+ return 0;
+}
+
/* Tree code classes. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
-static char c_tree_code_type[] = {
+static const char c_tree_code_type[] = {
'x',
#include "c-common.def"
};
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
-static int c_tree_code_length[] = {
+static const int c_tree_code_length[] = {
0,
#include "c-common.def"
};
{
memcpy (tree_code_type + (int) LAST_AND_UNUSED_TREE_CODE,
c_tree_code_type,
- (int)LAST_C_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE);
+ (int) LAST_C_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE);
memcpy (tree_code_length + (int) LAST_AND_UNUSED_TREE_CODE,
c_tree_code_length,
- (LAST_C_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (int));
+ (LAST_C_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE) * sizeof (int));
memcpy (tree_code_name + (int) LAST_AND_UNUSED_TREE_CODE,
c_tree_code_name,
- (LAST_C_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (char *));
+ (LAST_C_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE) * sizeof (char *));
lang_unsafe_for_reeval = c_unsafe_for_reeval;
}
{
case BUILT_IN_PRINTF:
target = c_expand_builtin_printf (arglist, target, tmode,
- modifier, ignore);
+ modifier, ignore, /*unlocked=*/ 0);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_PRINTF_UNLOCKED:
+ target = c_expand_builtin_printf (arglist, target, tmode,
+ modifier, ignore, /*unlocked=*/ 1);
if (target)
return target;
break;
case BUILT_IN_FPRINTF:
target = c_expand_builtin_fprintf (arglist, target, tmode,
- modifier, ignore);
+ modifier, ignore, /*unlocked=*/ 0);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_FPRINTF_UNLOCKED:
+ target = c_expand_builtin_fprintf (arglist, target, tmode,
+ modifier, ignore, /*unlocked=*/ 1);
if (target)
return target;
break;
following it. */
static int
is_valid_printf_arglist (arglist)
- tree arglist;
+ tree arglist;
{
/* Save this value so we can restore it later. */
const int SAVE_pedantic = pedantic;
int diagnostic_occurred = 0;
+ tree attrs;
/* Set this to a known value so the user setting won't affect code
generation. */
pedantic = 1;
/* Check to make sure there are no format specifier errors. */
- check_function_format (&diagnostic_occurred,
- maybe_get_identifier("printf"),
- NULL_TREE, arglist);
+ attrs = tree_cons (get_identifier ("format"),
+ tree_cons (NULL_TREE,
+ get_identifier ("printf"),
+ tree_cons (NULL_TREE,
+ integer_one_node,
+ tree_cons (NULL_TREE,
+ build_int_2 (2, 0),
+ NULL_TREE))),
+ NULL_TREE);
+ check_function_format (&diagnostic_occurred, attrs, arglist);
/* Restore the value of `pedantic'. */
pedantic = SAVE_pedantic;
/* If the arguments passed to printf are suitable for optimizations,
we attempt to transform the call. */
static rtx
-c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
+c_expand_builtin_printf (arglist, target, tmode, modifier, ignore, unlocked)
tree arglist;
rtx target;
enum machine_mode tmode;
enum expand_modifier modifier;
int ignore;
+ int unlocked;
{
- tree fn_putchar = built_in_decls[BUILT_IN_PUTCHAR],
- fn_puts = built_in_decls[BUILT_IN_PUTS];
+ tree fn_putchar = unlocked ?
+ built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED] : built_in_decls[BUILT_IN_PUTCHAR];
+ tree fn_puts = unlocked ?
+ built_in_decls[BUILT_IN_PUTS_UNLOCKED] : built_in_decls[BUILT_IN_PUTS];
tree fn, format_arg, stripped_string;
/* If the return value is used, or the replacement _DECL isn't
}
else
{
- /* We can't handle anything else with % args or %% ... yet. */
+ /* We can't handle anything else with % args or %% ... yet. */
if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
return 0;
/* If the arguments passed to fprintf are suitable for optimizations,
we attempt to transform the call. */
static rtx
-c_expand_builtin_fprintf (arglist, target, tmode, modifier, ignore)
+c_expand_builtin_fprintf (arglist, target, tmode, modifier, ignore, unlocked)
tree arglist;
rtx target;
enum machine_mode tmode;
enum expand_modifier modifier;
int ignore;
+ int unlocked;
{
- tree fn_fputc = built_in_decls[BUILT_IN_FPUTC],
- fn_fputs = built_in_decls[BUILT_IN_FPUTS];
+ tree fn_fputc = unlocked ?
+ built_in_decls[BUILT_IN_FPUTC_UNLOCKED] : built_in_decls[BUILT_IN_FPUTC];
+ tree fn_fputs = unlocked ?
+ built_in_decls[BUILT_IN_FPUTS_UNLOCKED] : built_in_decls[BUILT_IN_FPUTS];
tree fn, format_arg, stripped_string;
/* If the return value is used, or the replacement _DECL isn't
}
else
{
- /* We can't handle anything else with % args or %% ... yet. */
+ /* We can't handle anything else with % args or %% ... yet. */
if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
return 0;
return val;
}
\f
+/* Handle C and C++ default attributes. */
+
+enum built_in_attribute
+{
+#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
+#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No entry needed in enum. */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+ ATTR_LAST
+};
+
+static tree built_in_attributes[(int) ATTR_LAST];
+
+static bool c_attrs_initialized = false;
+
+static void c_init_attributes PARAMS ((void));
-/* Do the parts of lang_init common to C and C++. */
+/* Common initialization before parsing options. */
void
-c_common_lang_init ()
+c_common_init_options (lang)
+ enum c_language_kind lang;
{
+ c_language = lang;
+ parse_in = cpp_create_reader (lang == clk_c ? CLK_GNUC89:
+ lang == clk_cplusplus ? CLK_GNUCXX: CLK_OBJC);
+
+ /* Mark as "unspecified" (see c_common_post_options). */
+ flag_bounds_check = -1;
+}
+
+/* Post-switch processing. */
+void
+c_common_post_options ()
+{
+ cpp_post_options (parse_in);
+
+ /* Use tree inlining if possible. Function instrumentation is only
+ done in the RTL level, so we disable tree inlining. */
+ if (! flag_instrument_function_entry_exit)
+ {
+ if (!flag_no_inline)
+ {
+ flag_inline_trees = 1;
+ flag_no_inline = 1;
+ }
+ if (flag_inline_functions)
+ {
+ flag_inline_trees = 2;
+ flag_inline_functions = 0;
+ }
+ }
+
/* If still "unspecified", make it match -fbounded-pointers. */
- if (flag_bounds_check < 0)
+ if (flag_bounds_check == -1)
flag_bounds_check = flag_bounded_pointers;
/* Special format checking options don't work without -Wformat; warn if
if (warn_missing_format_attribute && !warn_format)
warning ("-Wmissing-format-attribute ignored without -Wformat");
}
+
+/* Front end initialization common to C, ObjC and C++. */
+const char *
+c_common_init (filename)
+ const char *filename;
+{
+ /* Do this before initializing pragmas, as then cpplib's hash table
+ has been set up. */
+ filename = init_c_lex (filename);
+
+ init_pragma ();
+
+ if (!c_attrs_initialized)
+ c_init_attributes ();
+
+ return filename;
+}
+
+/* Common finish hook for the C, ObjC and C++ front ends. */
+void
+c_common_finish ()
+{
+ cpp_finish (parse_in);
+
+ /* For performance, avoid tearing down cpplib's internal structures.
+ Call cpp_errors () instead of cpp_destroy (). */
+ errorcount += cpp_errors (parse_in);
+}
+
+static void
+c_init_attributes ()
+{
+ /* Fill in the built_in_attributes array. */
+#define DEF_ATTR_NULL_TREE(ENUM) \
+ built_in_attributes[(int) ENUM] = NULL_TREE;
+#define DEF_ATTR_INT(ENUM, VALUE) \
+ built_in_attributes[(int) ENUM] = build_int_2 (VALUE, VALUE < 0 ? -1 : 0);
+#define DEF_ATTR_IDENT(ENUM, STRING) \
+ built_in_attributes[(int) ENUM] = get_identifier (STRING);
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
+ built_in_attributes[(int) ENUM] \
+ = tree_cons (built_in_attributes[(int) PURPOSE], \
+ built_in_attributes[(int) VALUE], \
+ built_in_attributes[(int) CHAIN]);
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No initialization needed. */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+ ggc_add_tree_root (built_in_attributes, (int) ATTR_LAST);
+ c_attrs_initialized = true;
+}
+
+/* Depending on the name of DECL, apply default attributes to it. */
+
+void
+c_common_insert_default_attributes (decl)
+ tree decl;
+{
+ tree name = DECL_NAME (decl);
+
+ if (!c_attrs_initialized)
+ c_init_attributes ();
+
+#define DEF_ATTR_NULL_TREE(ENUM) /* Nothing needed after initialization. */
+#define DEF_ATTR_INT(ENUM, VALUE)
+#define DEF_ATTR_IDENT(ENUM, STRING)
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN)
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) \
+ if ((PREDICATE) && name == built_in_attributes[(int) NAME]) \
+ decl_attributes (&decl, built_in_attributes[(int) ATTRS], \
+ ATTR_FLAG_BUILT_IN);
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+}
+
+/* Output a -Wshadow warning MSGID about NAME, an IDENTIFIER_NODE, and
+ additionally give the location of the previous declaration DECL. */
+void
+shadow_warning (msgid, name, decl)
+ const char *msgid;
+ tree name, decl;
+{
+ warning ("declaration of `%s' shadows %s", IDENTIFIER_POINTER (name), msgid);
+ warning_with_file_and_line (DECL_SOURCE_FILE (decl),
+ DECL_SOURCE_LINE (decl),
+ "shadowed declaration is here");
+}
+