static const char *current_function_prototype_file;
static int current_function_prototype_line;
+/* The current statement tree. */
+
+static struct stmt_tree_s c_stmt_tree;
+
+/* The current scope statement stack. */
+
+static tree c_scope_stmt_stack;
+
+/* Nonzero if __FUNCTION__ and its ilk have been declared in this
+ function. */
+
+static int c_function_name_declared_p;
+
/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
that have names. Here so we can clear out their names' definitions
at the end of the function. */
static tree grokparms PARAMS ((tree, int));
static void layout_array_type PARAMS ((tree));
static tree c_make_fname_decl PARAMS ((tree, const char *, int));
+static void c_expand_body PARAMS ((tree, int));
\f
/* C-specific option variables. */
int warn_bad_function_cast;
-/* Warn about functions which might be candidates for attribute noreturn. */
-
-int warn_missing_noreturn;
-
/* Warn about traditional constructs whose meanings changed in ANSI C. */
int warn_traditional;
int warn_multichar = 1;
-/* Wrapper since C and C++ expand_expr_stmt are different. */
-
-expand_expr_stmt_fn lang_expand_expr_stmt = c_expand_expr_stmt;
-
/* The variant of the C language being processed. */
c_language_kind c_language = clk_c;
if (DECL_ABSTRACT_ORIGIN (decl) != 0
&& DECL_ABSTRACT_ORIGIN (decl) != decl)
TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1;
- else if (DECL_SAVED_INSNS (decl) != 0)
- {
- push_function_context ();
- output_inline_function (decl);
- pop_function_context ();
- }
}
+ /* We used to warn about unused variables in expand_end_bindings,
+ i.e. while generating RTL. But in function-at-a-time mode we may
+ choose to never expand a function at all (e.g. auto inlining), so
+ we do this explicitly now. */
+ warn_about_unused_variables (getdecls ());
+
/* If there were any declarations or structure tags in that level,
or if this level is a function body,
create a BLOCK to record them for the life of this function. */
if (block)
TREE_USED (block) = 1;
+
return block;
}
/* A local extern declaration for a function doesn't constitute nesting.
A local auto declaration does, since it's a forward decl
for a nested function coming later. */
- if (TREE_CODE (x) == FUNCTION_DECL && DECL_INITIAL (x) == 0
- && DECL_EXTERNAL (x))
+ if ((TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL)
+ && DECL_INITIAL (x) == 0 && DECL_EXTERNAL (x))
DECL_CONTEXT (x) = 0;
if (warn_nested_externs && DECL_EXTERNAL (x) && b != global_binding_level
return 1;
return 0;
}
- else if (current_binding_level == global_binding_level)
+ else if (DECL_CONTEXT (newdecl) == NULL_TREE)
{
/* Objects declared at top level: */
/* If at least one is a reference, it's ok. */
decl = build_decl (LABEL_DECL, id, void_type_node);
- /* Make sure every label has an rtx. */
- label_rtx (decl);
-
/* A label not explicitly declared must be local to where it's ref'd. */
DECL_CONTEXT (decl) = current_function_decl;
/* Record our roots. */
ggc_add_tree_root (c_global_trees, CTI_MAX);
+ ggc_add_root (&c_stmt_tree, 1, sizeof c_stmt_tree, mark_stmt_tree);
+ ggc_add_tree_root (&c_scope_stmt_stack, 1);
ggc_add_tree_root (&named_labels, 1);
ggc_add_tree_root (&shadowed_labels, 1);
ggc_add_root (¤t_binding_level, 1, sizeof current_binding_level,
/* But not if this is a duplicate decl
and we preserved the rtl from the previous one
(which may or may not happen). */
- && DECL_RTL (tem) == 0)
+ && DECL_RTL (tem) == 0
+ && !DECL_CONTEXT (tem))
{
if (COMPLETE_TYPE_P (TREE_TYPE (tem)))
expand_decl (tem);
if (failure == 1)
error_with_decl (decl, "initializer fails to determine size of `%s'");
- if (failure == 2)
+ else if (failure == 2)
{
if (do_default)
error_with_decl (decl, "array size missing in `%s'");
/* TYPE_MAX_VALUE is always one less than the number of elements
in the array, because we start counting at zero. Therefore,
warn only if the value is less than zero. */
- if (pedantic && TYPE_DOMAIN (type) != 0
- && tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < 0)
+ else if (pedantic && TYPE_DOMAIN (type) != 0
+ && tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < 0)
error_with_decl (decl, "zero or negative size array `%s'");
layout_decl (decl, 0);
{
/* This is a no-op in c-lang.c or something real in objc-actions.c. */
maybe_objc_check_decl (decl);
- rest_of_decl_compilation (decl, asmspec,
- (DECL_CONTEXT (decl) == 0
- || TREE_ASM_WRITTEN (decl)), 0);
+
+ if (!DECL_CONTEXT (decl))
+ rest_of_decl_compilation (decl, asmspec,
+ (DECL_CONTEXT (decl) == 0
+ || TREE_ASM_WRITTEN (decl)), 0);
+ else
+ {
+ if (asmspec)
+ DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
+ add_decl_stmt (decl);
+ }
if (DECL_CONTEXT (decl) != 0)
{
/* If it's still incomplete now, no init will save it. */
if (DECL_SIZE (decl) == 0)
DECL_INITIAL (decl) = 0;
- expand_decl (decl);
}
- /* Compute and store the initial value. */
- if (TREE_CODE (decl) != FUNCTION_DECL)
- expand_decl_init (decl);
}
}
{
if ((! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
| (1 << (int) RID_SIGNED)
- | (1 << (int) RID_UNSIGNED))))
+ | (1 << (int) RID_UNSIGNED)
+ | (1 << (int) RID_COMPLEX))))
/* Don't warn about typedef foo = bar. */
&& ! (specbits & (1 << (int) RID_TYPEDEF) && initialized)
&& ! in_system_header)
if (specbits & 1 << (int) RID_COMPLEX)
{
+ if (pedantic && !flag_isoc99)
+ pedwarn ("ISO C89 does not support complex types");
/* If we just have "complex", it is equivalent to
"complex double", but if any modifiers at all are specified it is
the complex form of TYPE. E.g, "complex short" is
&& ! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
| (1 << (int) RID_SIGNED)
| (1 << (int) RID_UNSIGNED))))
- type = complex_double_type_node;
+ {
+ if (pedantic)
+ pedwarn ("ISO C does not support plain `complex' meaning `double complex'");
+ type = complex_double_type_node;
+ }
else if (type == integer_type_node)
- type = complex_integer_type_node;
+ {
+ if (pedantic)
+ pedwarn ("ISO C does not support complex integer types");
+ type = complex_integer_type_node;
+ }
else if (type == float_type_node)
type = complex_float_type_node;
else if (type == double_type_node)
else if (type == long_double_type_node)
type = complex_long_double_type_node;
else
- type = build_complex_type (type);
+ {
+ if (pedantic)
+ pedwarn ("ISO C does not support complex integer types");
+ type = build_complex_type (type);
+ }
}
/* Figure out the type qualifiers for the declaration. There are
controlled separately by its own initializer. */
if (type != 0 && typedef_type != 0
- && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type)
- && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0)
+ && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0
+ && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type))
{
type = build_array_type (TREE_TYPE (type), 0);
if (size_varies)
return tree_cons (decl, value, NULL_TREE);
}
+
\f
/* Create the FUNCTION_DECL for a function definition.
DECLSPECS, DECLARATOR, PREFIX_ATTRIBUTES and ATTRIBUTES are the parts of
init_function_start (fndecl, input_filename, lineno);
- /* If this is a varargs function, inform function.c. */
+ /* Begin the statement tree for this function. */
+ DECL_LANG_SPECIFIC (current_function_decl)
+ =((struct lang_decl *) ggc_alloc (sizeof (struct lang_decl)));
+ begin_stmt_tree (&DECL_SAVED_TREE (current_function_decl));
- if (c_function_varargs)
- mark_varargs ();
+ /* This function is being processed in whole-function mode. */
+ cfun->x_whole_function_mode_p = 1;
- /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */
-
- declare_function_name ();
-
- /* Set up parameters and prepare for return, for the function. */
-
- expand_function_start (fndecl, 0);
-
- /* If this function is `main', emit a call to `__main'
- to run global initializers, etc. */
- if (DECL_NAME (fndecl)
- && MAIN_NAME_P (DECL_NAME (fndecl))
- && DECL_CONTEXT (fndecl) == NULL_TREE)
- expand_main_function ();
+ /* Even though we're inside a function body, we still don't want to
+ call expand_expr to calculate the size of a variable-sized array.
+ We haven't necessarily assigned RTL to all variables yet, so it's
+ not safe to try to expand expressions involving them. */
+ immediate_size_expand = 0;
+ cfun->x_dont_save_pending_sizes_p = 1;
}
\f
/* SPECPARMS is an identifier list--a chain of TREE_LIST nodes
}
}
+ /* Tie off the statement tree for this function. */
+ finish_stmt_tree (&DECL_SAVED_TREE (fndecl));
+ /* Clear out memory we no longer need. */
+ free_after_parsing (cfun);
+ /* Since we never call rest_of_compilation, we never clear
+ CFUN. Do so explicitly. */
+ free_after_compilation (cfun);
+ cfun = NULL;
+
+ if (! nested)
+ {
+ /* Generate RTL for the body of this function. */
+ c_expand_body (fndecl, nested);
+ /* Let the error reporting routines know that we're outside a
+ function. For a nested function, this value is used in
+ pop_c_function_context and then reset via pop_function_context. */
+ current_function_decl = NULL;
+ }
+}
+
+/* Generate the RTL for the body of FNDECL. If NESTED_P is non-zero,
+ then we are already in the process of generating RTL for another
+ function. */
+
+static void
+c_expand_body (fndecl, nested_p)
+ tree fndecl;
+ int nested_p;
+{
+ /* There's no reason to do any of the work here if we're only doing
+ semantic analysis; this code just generates RTL. */
+ if (flag_syntax_only)
+ return;
+
+ /* Squirrel away our current state. */
+ if (nested_p)
+ push_function_context ();
+
+ /* Initialize the RTL code for the function. */
+ current_function_decl = fndecl;
+ init_function_start (fndecl, input_filename, lineno);
+
+ /* This function is being processed in whole-function mode. */
+ cfun->x_whole_function_mode_p = 1;
+
+ /* Even though we're inside a function body, we still don't want to
+ call expand_expr to calculate the size of a variable-sized array.
+ We haven't necessarily assigned RTL to all variables yet, so it's
+ not safe to try to expand expressions involving them. */
+ immediate_size_expand = 0;
+ cfun->x_dont_save_pending_sizes_p = 1;
+
+ /* If this is a varargs function, inform function.c. */
+ if (c_function_varargs)
+ mark_varargs ();
+
+ /* Set up parameters and prepare for return, for the function. */
+ expand_function_start (fndecl, 0);
+
+ /* If this function is `main', emit a call to `__main'
+ to run global initializers, etc. */
+ if (DECL_NAME (fndecl)
+ && MAIN_NAME_P (DECL_NAME (fndecl))
+ && DECL_CONTEXT (fndecl) == NULL_TREE)
+ expand_main_function ();
+
+ /* Generate the RTL for this function. */
+ expand_stmt (DECL_SAVED_TREE (fndecl));
+ /* Allow the body of the function to be garbage collected. */
+ DECL_SAVED_TREE (fndecl) = NULL_TREE;
+
+ /* We hard-wired immediate_size_expand to zero in start_function.
+ expand_function_end will decrement this variable. So, we set the
+ variable to one here, so that after the decrement it will remain
+ zero. */
+ immediate_size_expand = 1;
+
+ /* Allow language dialects to perform special processing. */
+ if (lang_expand_function_end)
+ (*lang_expand_function_end) ();
+
/* Generate rtl for function exit. */
expand_function_end (input_filename, lineno, 0);
- /* So we can tell if jump_optimize sets it to 1. */
- can_reach_end = 0;
-
/* If this is a nested function, protect the local variables in the stack
above us from being collected while we're compiling this function. */
- if (nested)
+ if (nested_p)
ggc_push_context ();
/* Run the optimizers and output the assembler code for this function. */
rest_of_compilation (fndecl);
/* Undo the GC context switch. */
- if (nested)
+ if (nested_p)
ggc_pop_context ();
- current_function_returns_null |= can_reach_end;
-
- if (warn_missing_noreturn
- && !TREE_THIS_VOLATILE (fndecl)
- && !current_function_returns_null
- && !current_function_returns_value)
- warning ("function might be possible candidate for attribute `noreturn'");
-
- if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
- warning ("`noreturn' function does return");
- else if (warn_return_type && can_reach_end
- && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl))))
- /* If this function returns non-void and control can drop through,
- complain. */
- warning ("control reaches end of non-void function");
/* With just -W, complain only if function returns both with
and without a value. */
- else if (extra_warnings
- && current_function_returns_value && current_function_returns_null)
+ if (extra_warnings
+ && current_function_returns_value
+ && current_function_returns_null)
warning ("this function may return with or without a value");
/* If requested, warn about function definitions where the function will
}
}
- if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested)
+ if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested_p)
{
/* Stop pointing to the local nodes about to be freed.
But DECL_INITIAL must remain nonzero so we know this
assemble_destructor (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)));
}
- if (! nested)
+ if (nested_p)
{
- /* Let the error reporting routines know that we're outside a
- function. For a nested function, this value is used in
- pop_c_function_context and then reset via pop_function_context. */
- current_function_decl = NULL;
+ /* Return to the enclosing function. */
+ pop_function_context ();
+ /* If the nested function was inline, write it out if that is
+ necessary. */
+ if (!TREE_ASM_WRITTEN (fndecl) && TREE_ADDRESSABLE (fndecl))
+ {
+ push_function_context ();
+ output_inline_function (fndecl);
+ pop_function_context ();
+ }
}
+
}
\f
/* Save and restore the variables in this file and elsewhere
xmalloc (sizeof (struct c_language_function)));
f->language = (struct language_function *) p;
+ p->base.x_stmt_tree = c_stmt_tree;
+ p->base.x_scope_stmt_stack = c_scope_stmt_stack;
+ p->base.x_function_name_declared_p = c_function_name_declared_p;
p->named_labels = named_labels;
p->shadowed_labels = shadowed_labels;
p->returns_value = current_function_returns_value;
IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)))
= TREE_VALUE (link);
- if (DECL_SAVED_INSNS (current_function_decl) == 0)
+ if (DECL_SAVED_INSNS (current_function_decl) == 0
+ && DECL_SAVED_TREE (current_function_decl) == NULL_TREE)
{
/* Stop pointing to the local nodes about to be freed. */
/* But DECL_INITIAL must remain nonzero so we know this
DECL_ARGUMENTS (current_function_decl) = 0;
}
+ c_stmt_tree = p->base.x_stmt_tree;
+ c_scope_stmt_stack = p->base.x_scope_stmt_stack;
+ c_function_name_declared_p = p->base.x_function_name_declared_p;
named_labels = p->named_labels;
shadowed_labels = p->shadowed_labels;
current_function_returns_value = p->returns_value;
if (p == 0)
return;
+ mark_c_language_function (&p->base);
ggc_mark_tree (p->shadowed_labels);
ggc_mark_tree (p->named_labels);
mark_binding_level (&p->binding_level);
}
-/* integrate_decl_tree calls this function, but since we don't use the
- DECL_LANG_SPECIFIC field, this is a no-op. */
+/* Copy the DECL_LANG_SEPECIFIC data associated with NODE. */
void
-copy_lang_decl (node)
- tree node ATTRIBUTE_UNUSED;
+copy_lang_decl (decl)
+ tree decl;
{
-}
+ struct lang_decl *ld;
-/* Mark ARG for GC. */
+ if (!DECL_LANG_SPECIFIC (decl))
+ return;
-void
-lang_mark_false_label_stack (arg)
- struct label_node *arg;
-{
- /* C doesn't use false_label_stack. It better be NULL. */
- if (arg != NULL)
- abort ();
+ ld = (struct lang_decl *) ggc_alloc (sizeof (struct lang_decl));
+ bcopy ((char *)DECL_LANG_SPECIFIC (decl), (char *)ld,
+ sizeof (struct lang_decl));
+ DECL_LANG_SPECIFIC (decl) = ld;
}
/* Mark the language specific bits in T for GC. */
}
else if (TYPE_P (t) && TYPE_LANG_SPECIFIC (t))
ggc_mark (TYPE_LANG_SPECIFIC (t));
+ else if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
+ {
+ ggc_mark (DECL_LANG_SPECIFIC (t));
+ c_mark_lang_decl (&DECL_LANG_SPECIFIC (t)->base);
+ }
}
/* The functions below are required for functionality of doing
stmt_tree
current_stmt_tree ()
{
- return cfun ? &cfun->language->x_stmt_tree : NULL;
+ return &c_stmt_tree;
+}
+
+/* Returns the stack of SCOPE_STMTs for the current function. */
+
+tree *
+current_scope_stmt_stack ()
+{
+ return &c_scope_stmt_stack;
}
/* Nonzero if TYPE is an anonymous union or struct type. Always 0 in
return 0;
}
-/* One if we have already declared __FUNCTION__ (and related
- variables) in the current function. Two if we are in the process
- of doing so. */
+/* Dummy function in place of callback used by C++. */
-int
-current_function_name_declared ()
+void
+extract_interface_info ()
{
- abort ();
- return 0;
}
-/* Code to generate the RTL for a case label in C. */
+/* Return a new COMPOUND_STMT, after adding it to the current
+ statement tree. */
-void
-do_case (low_value, high_value)
- tree low_value;
- tree high_value;
+tree
+c_begin_compound_stmt ()
{
- tree value1 = NULL_TREE, value2 = NULL_TREE, label;
+ tree stmt;
- if (low_value != NULL_TREE)
- value1 = check_case_value (low_value);
- if (high_value != NULL_TREE)
- value2 = check_case_value (high_value);
-
- label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
- if (pedantic && (high_value != NULL_TREE))
- pedwarn ("ISO C forbids case ranges");
-
- if (value1 != error_mark_node && value2 != error_mark_node)
+ /* Create the COMPOUND_STMT. */
+ stmt = add_stmt (build_stmt (COMPOUND_STMT, NULL_TREE));
+ /* If we haven't already declared __FUNCTION__ and its ilk then this
+ is the opening curly brace of the function. Declare them now. */
+ if (!c_function_name_declared_p)
{
- tree duplicate;
- int success;
-
- if (high_value == NULL_TREE && value1 != NULL_TREE &&
- pedantic && ! INTEGRAL_TYPE_P (TREE_TYPE (value1)))
- pedwarn ("label must have integral type in ISO C");
-
- if (low_value == NULL_TREE)
- success = pushcase (NULL_TREE, 0, label, &duplicate);
- else if (high_value == NULL_TREE)
- success = pushcase (value1, convert_and_check, label, &duplicate);
- else
- success = pushcase_range (value1, value2, convert_and_check,
- label, &duplicate);
-
- if (success == 1)
- {
- if (low_value == NULL_TREE)
- error ("default label not within a switch statement");
- else
- error ("case label not within a switch statement");
- }
- else if (success == 2)
- {
- if (low_value == NULL_TREE)
- {
- error ("multiple default labels in one switch");
- error_with_decl (duplicate, "this is the first default label");
- }
- else
- error ("dupicate case value");
- if (high_value != NULL_TREE)
- error_with_decl (duplicate,
- "this is the first entry for that value");
- }
- else if (low_value != NULL_TREE)
- {
- if (success == 3)
- warning ("case value out of range");
- else if (success == 5)
- error ("case label within scope of cleanup or variable array");
- }
+ c_function_name_declared_p = 1;
+ declare_function_name ();
}
+
+ return stmt;
}
-/* Language specific handler of tree nodes used when generating RTL
- from a tree. */
-
-tree
-lang_expand_stmt (t)
- tree t ATTRIBUTE_UNUSED;
-{
- abort ();
- return NULL_TREE;
-}
+/* Expand T (a DECL_STMT) if it declares an entity not handled by the
+ common code. */
-/* Accessor to set the 'current_function_name_declared' flag. */
-
-void
-set_current_function_name_declared (i)
- int i ATTRIBUTE_UNUSED;
-{
- abort ();
-}
-
-/* Dummy function in place of callback used by C++. */
void
-extract_interface_info ()
+c_expand_decl_stmt (t)
+ tree t;
{
+ tree decl = DECL_STMT_DECL (t);
+
+ /* Expand nested functions. */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_CONTEXT (decl) == current_function_decl
+ && DECL_SAVED_TREE (decl))
+ c_expand_body (decl, /*nested_p=*/1);
}