#define obstack_chunk_free free
extern struct obstack permanent_obstack;
-extern struct obstack* saveable_obstack;
extern int current_class_depth;
int ggc_p = 1;
-/* Obstack used for remembering local class declarations (like
- enums and static (const) members. */
-#include "stack.h"
-struct obstack decl_obstack;
-static struct stack_level *decl_stack;
-
-#ifndef CHAR_TYPE_SIZE
-#define CHAR_TYPE_SIZE BITS_PER_UNIT
-#endif
-
-#ifndef SHORT_TYPE_SIZE
-#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
-#endif
-
-#ifndef INT_TYPE_SIZE
-#define INT_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef LONG_TYPE_SIZE
-#define LONG_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef LONG_LONG_TYPE_SIZE
-#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-
#ifndef WCHAR_UNSIGNED
#define WCHAR_UNSIGNED 0
#endif
-#ifndef FLOAT_TYPE_SIZE
-#define FLOAT_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef DOUBLE_TYPE_SIZE
-#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-
-#ifndef LONG_DOUBLE_TYPE_SIZE
-#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
#endif
#ifndef BOOL_TYPE_SIZE
static tree grokparms PROTO((tree, int));
static const char *redeclaration_error_message PROTO((tree, tree));
-static struct stack_level *push_decl_level PROTO((struct stack_level *,
- struct obstack *));
static void push_binding_level PROTO((struct binding_level *, int,
int));
static void pop_binding_level PROTO((void));
static void push_binding PROTO((tree, tree, struct binding_level*));
static int add_binding PROTO((tree, tree));
static void pop_binding PROTO((tree, tree));
-static tree local_variable_p PROTO((tree));
+static tree local_variable_p_walkfn PROTO((tree *, int *, void *));
static tree find_binding PROTO((tree, tree));
static tree select_decl PROTO((tree, int));
static int lookup_flags PROTO((int, int));
static const char *tag_name PROTO((enum tag_types code));
static void find_class_binding_level PROTO((void));
static struct binding_level *innermost_nonclass_level PROTO((void));
-static tree poplevel_class PROTO((void));
static void warn_about_implicit_typename_lookup PROTO((tree, tree));
static int walk_namespaces_r PROTO((tree, walk_namespaces_fn, void *));
static int walk_globals_r PROTO((tree, void *));
static void pop_label PROTO((tree));
static void pop_labels PROTO((tree));
static void maybe_deduce_size_from_array_init PROTO((tree, tree));
-static void layout_var_decl PROTO((tree, tree *));
+static void layout_var_decl PROTO((tree));
static void maybe_commonize_var PROTO((tree));
-static tree build_cleanup_on_safe_obstack PROTO((tree));
-static void check_initializer PROTO((tree, tree *));
+static tree check_initializer PROTO((tree, tree));
static void make_rtl_for_nonlocal_decl PROTO((tree, tree, const char *));
static void push_cp_function_context PROTO((struct function *));
static void pop_cp_function_context PROTO((struct function *));
static void mark_binding_level PROTO((void *));
static void mark_cp_function_context PROTO((struct function *));
static void mark_saved_scope PROTO((void *));
+static void mark_lang_function PROTO((struct language_function *));
+static void mark_stmt_tree PROTO((struct stmt_tree *));
+static void save_function_data PROTO((tree));
+static void check_function_type PROTO((tree));
+static void destroy_local_static PROTO((tree));
+static void destroy_local_var PROTO((tree));
+static void finish_constructor_body PROTO((void));
+static void finish_destructor_body PROTO((void));
+static tree create_array_type_for_decl PROTO((tree, tree, tree));
#if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PROTO((void));
#endif
-/* A node which has tree code ERROR_MARK, and whose type is itself.
- All erroneous expressions are replaced with this node. All functions
- that accept nodes as arguments should avoid generating error messages
- if this node is one of the arguments, since it is undesirable to get
- multiple error messages from one error in the input. */
-
-tree error_mark_node;
-
/* Erroneous argument lists can use this *IFF* they do not modify it. */
tree error_mark_list;
tree cp_global_trees[CPTI_MAX];
-/* These can't be part of the above array, since they are declared
- individually in tree.h, and used by the debug output routines. */
-
-tree void_type_node;
-tree char_type_node;
-tree integer_type_node;
-tree unsigned_type_node;
-
-/* These can't be part of the above array, since they are declared
- individially in tree.h and used by the target routines. */
-
-tree ptr_type_node;
-tree va_list_type_node;
-tree null_pointer_node;
-
/* Indicates that there is a type value in some namespace, although
that is not necessarily in scope at the moment. */
/* Expect only namespace names now. */
static int only_namespace_names;
-/* In a destructor, the last insn emitted after the start of the
- function and the parms. */
-
-#define last_dtor_insn cp_function_chain->x_last_dtor_insn
-
-/* In a constructor, the last insn emitted after the start of the
- function and the parms, the exception specification and any
- function-try-block. The constructor initializers are emitted after
- this insn. */
-
-#define last_parm_cleanup_insn cp_function_chain->x_last_parm_cleanup_insn
-
/* If original DECL_RESULT of current function was a register,
but due to being an addressable named return value, would up
on the stack, this variable holds the named return value's
struct named_label_list *next;
};
-/* A list (chain of TREE_LIST nodes) of named label uses.
- The TREE_PURPOSE field is the list of variables defined
- in the label's scope defined at the point of use.
- The TREE_VALUE field is the LABEL_DECL used.
- The TREE_TYPE field holds `current_binding_level' at the
- point of the label's use.
-
- BWAHAHAAHAHahhahahahaah. No, no, no, said the little chicken.
-
- Look at the pretty struct named_label_list. See the pretty struct
- with the pretty named fields that describe what they do. See the
- pretty lack of gratuitous casts. Notice the code got a lot cleaner.
-
- Used only for jumps to as-yet undefined labels, since
- jumps to defined labels can have their validity checked
- by stmt.c. */
+/* Used only for jumps to as-yet undefined labels, since jumps to
+ defined labels can have their validity checked by stmt.c. */
-#define named_label_uses cp_function_chain->named_label_uses
+#define named_label_uses cp_function_chain->x_named_label_uses
/* A list of objects which have constructors or destructors
which reside in the global scope. The decl is stored in
/* -- end of C++ */
-/* An expression of type `int' for the constant zero. */
+/* A node for the integer constants 2, and 3. */
-tree integer_zero_node;
-
-/* A node for the integer constants 1, 2, and 3. */
-
-tree integer_one_node, integer_two_node, integer_three_node;
-
-/* While defining an enum type, this is 1 plus the last enumerator
- constant value. */
-
-static tree enum_next_value;
-
-/* Nonzero means that there was overflow computing enum_next_value. */
-
-static int enum_overflow;
+tree integer_two_node, integer_three_node;
/* Parsing a function declarator leaves here a chain of structure
and enum types declared in the parmlist. */
extern int flag_no_nonansi_builtin;
-/* Nonzero means enable obscure ANSI features and disable GNU extensions
- that might cause ANSI-compliant code to be miscompiled. */
-
-extern int flag_ansi;
-
/* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes)
objects. */
extern int flag_huge_objects;
\f
/* C and C++ flags are in decl2.c. */
-/* Set to 0 at beginning of a constructor, set to 1
- if that function does an allocation before referencing its
- instance variable. */
-#define current_function_assigns_this cp_function_chain->assigns_this
-#define current_function_just_assigned_this \
- cp_function_chain->just_assigned_this
-
/* Flag used when debugging spew.c */
extern int spew_debug;
unit. */
tree anonymous_namespace_name;
-\f
-/* Allocate a level of searching. */
-
-static
-struct stack_level *
-push_decl_level (stack, obstack)
- struct stack_level *stack;
- struct obstack *obstack;
-{
- struct stack_level tem;
- tem.prev = stack;
-
- return push_stack_level (obstack, (char *)&tem, sizeof (tem));
-}
\f
/* For each binding contour we allocate a binding_level structure
which records the names defined in that contour.
/* The binding level currently in effect. */
-#define current_binding_level cp_function_chain->binding_level
+#define current_binding_level \
+ (current_function \
+ ? cp_function_chain->bindings \
+ : scope_chain->bindings)
/* The binding level of the current class, if any. */
&& !current_binding_level->tag_transparent));
}
-/* Identify this binding level as a level of parameters. */
-
-void
-declare_parm_level ()
-{
- current_binding_level->parm_flag = 1;
-}
-
void
declare_pseudo_global_level ()
{
pushlevel (tag_transparent)
int tag_transparent;
{
- register struct binding_level *newlevel = NULL_BINDING_LEVEL;
-
- /* If this is the top level of a function,
- just make sure that NAMED_LABELS is 0.
- They should have been set to 0 at the end of the previous function. */
+ struct binding_level *newlevel;
- if (current_binding_level == global_binding_level)
- my_friendly_assert (named_labels == NULL_TREE, 134);
+ if (current_function && !doing_semantic_analysis_p ())
+ return;
/* Reuse or create a struct for this binding level. */
-
#if defined(DEBUG_CP_BINDING_LEVELS)
if (0)
#else /* !defined(DEBUG_CP_BINDING_LEVELS) */
current_binding_level->is_for_scope = 1;
}
-void
-pushlevel_temporary (tag_transparent)
- int tag_transparent;
-{
- pushlevel (tag_transparent);
- current_binding_level->keep = 2;
- clear_last_expr ();
-
- /* Note we don't call push_momentary() here. Otherwise, it would cause
- cleanups to be allocated on the momentary obstack, and they will be
- overwritten by the next statement. */
-
- expand_start_bindings (0);
-}
-
/* For a binding between a name and an entity at a block scope,
this is the `struct binding_level' for the block. */
#define BINDING_LEVEL(NODE) \
tree decl;
struct binding_level *b;
{
- /* Only things that will live forever should go in the global
- binding level. */
- my_friendly_assert (!(b == global_binding_level
- && !TREE_PERMANENT (decl)),
- 19990817);
-
/* We build up the list in reverse order, and reverse it later if
necessary. */
TREE_CHAIN (decl) = b->names;
{
tree label = TREE_VALUE (link);
- if (DECL_INITIAL (label) == NULL_TREE)
+ if (!processing_template_decl && doing_semantic_analysis_p ())
{
- cp_error_at ("label `%D' used but not defined", label);
- /* Avoid crashing later. */
- define_label (input_filename, 1, DECL_NAME (label));
+ if (DECL_INITIAL (label) == NULL_TREE)
+ {
+ cp_error_at ("label `%D' used but not defined", label);
+ /* Avoid crashing later. */
+ define_label (input_filename, 1, DECL_NAME (label));
+ }
+ else if (warn_unused && !TREE_USED (label))
+ cp_warning_at ("label `%D' defined but not used", label);
}
- else if (warn_unused && !TREE_USED (label))
- cp_warning_at ("label `%D' defined but not used", label);
SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), TREE_PURPOSE (link));
}
Put it into forward order, just for cleanliness. */
tree decls;
int tmp = functionbody;
- int real_functionbody = current_binding_level->keep == 2
- ? ((functionbody = 0), tmp) : functionbody;
- tree tags = functionbody >= 0 ? current_binding_level->tags : 0;
- tree subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
+ int real_functionbody;
+ tree tags;
+ tree subblocks;
tree block = NULL_TREE;
tree decl;
int block_previously_created;
int leaving_for_scope;
- if (current_binding_level->parm_flag == 2)
- return poplevel_class ();
+ if (current_function && !doing_semantic_analysis_p ())
+ return NULL_TREE;
+
+ my_friendly_assert (current_binding_level->parm_flag != 2,
+ 19990916);
+
+ real_functionbody = (current_binding_level->keep == 2
+ ? ((functionbody = 0), tmp) : functionbody);
+ tags = functionbody >= 0 ? current_binding_level->tags : 0;
+ subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
my_friendly_assert (!current_binding_level->class_shadowed,
19990414);
/* Output any nested inline functions within this block
if they weren't already output. */
-
for (decl = decls; decl; decl = TREE_CHAIN (decl))
if (TREE_CODE (decl) == FUNCTION_DECL
&& ! TREE_ASM_WRITTEN (decl)
}
}
+ /* When not in function-at-a-time mode, expand_end_bindings will
+ warn about unused variables. But, in function-at-a-time mode
+ expand_end_bindings is not passed the list of variables in the
+ current scope, and therefore no warning is emitted. So, we
+ explicitly warn here. */
+ if (!processing_template_decl)
+ 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. */
-
block = NULL_TREE;
block_previously_created = (current_binding_level->this_block != NULL_TREE);
if (block_previously_created)
{
if (decls || tags || subblocks)
{
- if (BLOCK_VARS (block) || BLOCK_TYPE_TAGS (block))
+ if (BLOCK_VARS (block))
warning ("internal compiler error: debugging info corrupted");
BLOCK_VARS (block) = decls;
- BLOCK_TYPE_TAGS (block) = tags;
/* We can have previous subblocks and new subblocks when
doing fixup_gotos with complex cleanups. We chain the new
BLOCK_SUBBLOCKS (block) = chainon (BLOCK_SUBBLOCKS (block),
subblocks);
}
- /* If we created the block earlier on, and we are just
- diddling it now, then it already should have a proper
- BLOCK_END_NOTE value associated with it. */
}
else
{
BLOCK_VARS (block) = decls;
- BLOCK_TYPE_TAGS (block) = tags;
BLOCK_SUBBLOCKS (block) = subblocks;
- /* Otherwise, for a new block, install a new BLOCK_END_NOTE
- value. */
- remember_end_note (block);
}
}
/* In each subblock, record that this is its superior. */
-
if (keep >= 0)
for (link = subblocks; link; link = TREE_CHAIN (link))
BLOCK_SUPERCONTEXT (link) = block;
/* Any uses of undefined labels now operate under constraints
of next binding contour. */
- {
- struct binding_level *level_chain;
- level_chain = current_binding_level->level_chain;
- if (level_chain)
- {
- struct named_label_list *labels;
- for (labels = named_label_uses; labels; labels = labels->next)
- if (labels->binding_level == current_binding_level)
- {
- labels->binding_level = level_chain;
- labels->names_in_scope = level_chain->names;
- }
- }
- }
+ if (current_function)
+ {
+ struct binding_level *level_chain;
+ level_chain = current_binding_level->level_chain;
+ if (level_chain)
+ {
+ struct named_label_list *labels;
+ for (labels = named_label_uses; labels; labels = labels->next)
+ if (labels->binding_level == current_binding_level)
+ {
+ labels->binding_level = level_chain;
+ labels->names_in_scope = level_chain->names;
+ }
+ }
+ }
tmp = current_binding_level->keep;
current_binding_level->blocks
= chainon (current_binding_level->blocks, subblocks);
+ /* Each and every BLOCK node created here in `poplevel' is important
+ (e.g. for proper debugging information) so if we created one
+ earlier, mark it as "used". */
+ if (block)
+ TREE_USED (block) = 1;
+
/* Take care of compiler's internal binding structures. */
if (tmp == 2)
{
- expand_end_bindings (getdecls (), keep, 1);
- /* Each and every BLOCK node created here in `poplevel' is important
- (e.g. for proper debugging information) so if we created one
- earlier, mark it as "used". */
+ tree scope_stmts;
+
+ scope_stmts
+ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/1);
if (block)
- TREE_USED (block) = 1;
- block = poplevel (keep, reverse, real_functionbody);
+ {
+ SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
+ SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
+ }
+
+ block = poplevel (keep, reverse, functionbody);
}
- /* Each and every BLOCK node created here in `poplevel' is important
- (e.g. for proper debugging information) so if we created one
- earlier, mark it as "used". */
- if (block)
- TREE_USED (block) = 1;
return block;
}
push_binding_level (newlevel, 0, 0);
- decl_stack = push_decl_level (decl_stack, &decl_obstack);
class_binding_level = current_binding_level;
class_binding_level->parm_flag = 2;
}
/* ...and a poplevel for class declarations. */
-static tree
+void
poplevel_class ()
{
register struct binding_level *level = class_binding_level;
my_friendly_assert (level != 0, 354);
- decl_stack = pop_stack_level (decl_stack);
/* If we're leaving a toplevel class, don't bother to do the setting
of IDENTIFIER_CLASS_VALUE to NULL_TREE, since first of all this slot
shouldn't even be used when current_class_type isn't set, and second,
#endif /* defined(DEBUG_CP_BINDING_LEVELS) */
pop_binding_level ();
-
- return NULL_TREE;
}
/* We are entering the scope of a class. Clear IDENTIFIER_CLASS_VALUE
}
if (b && (result = find_binding (name, scope)))
return result;
- /* Not found, make a new permanent one. */
- push_obstacks (&permanent_obstack, &permanent_obstack);
+ /* Not found, make a new one. */
result = make_node (CPLUS_BINDING);
TREE_CHAIN (result) = b;
IDENTIFIER_NAMESPACE_BINDINGS (name) = result;
BINDING_SCOPE (result) = scope;
BINDING_TYPE (result) = NULL_TREE;
BINDING_VALUE (result) = NULL_TREE;
- pop_obstacks ();
return result;
}
scope isn't enough, because more binding levels may be pushed. */
struct saved_scope *scope_chain;
+/* Mark ST for GC. */
+
+static void
+mark_stmt_tree (st)
+ struct stmt_tree *st;
+{
+ ggc_mark_tree (st->x_last_stmt);
+ ggc_mark_tree (st->x_last_expr_type);
+}
+
/* Mark ARG (which is really a struct saved_scope **) for GC. */
static void
struct saved_scope *t = *(struct saved_scope **)arg;
while (t)
{
- mark_binding_level (&t->old_binding_level);
mark_binding_level (&t->class_bindings);
ggc_mark_tree (t->old_bindings);
ggc_mark_tree (t->old_namespace);
ggc_mark_tree (t->template_parms);
ggc_mark_tree (t->x_previous_class_type);
ggc_mark_tree (t->x_previous_class_values);
+ ggc_mark_tree (t->x_saved_tree);
+
+ mark_stmt_tree (&t->x_stmt_tree);
+ mark_binding_level (&t->bindings);
t = t->prev;
}
}
maybe_push_to_top_level (pseudo)
int pseudo;
{
- struct saved_scope *s
- = (struct saved_scope *) xmalloc (sizeof (struct saved_scope));
+ struct saved_scope *s;
struct binding_level *b;
- tree old_bindings = NULL_TREE;
+ tree old_bindings;
+ int need_pop;
+
+ s = (struct saved_scope *) xcalloc (1, sizeof (struct saved_scope));
b = scope_chain ? current_binding_level : 0;
- push_function_context_to (NULL_TREE);
+ /* If we're in the middle of some function, save our state. */
+ if (current_function)
+ {
+ need_pop = 1;
+ push_function_context_to (NULL_TREE);
+ }
+ else
+ need_pop = 0;
+ old_bindings = NULL_TREE;
if (scope_chain && previous_class_type)
old_bindings = store_bindings (previous_class_values, old_bindings);
for (t = b->type_shadowed; t; t = TREE_CHAIN (t))
SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (t), TREE_VALUE (t));
}
- if (scope_chain)
- *s = *scope_chain;
- s->old_binding_level = scope_chain ? current_binding_level : 0;
- s->old_bindings = old_bindings;
s->prev = scope_chain;
- scope_chain = s;
- current_binding_level = b;
+ s->old_bindings = old_bindings;
+ s->bindings = b;
+ s->need_pop_function_context = need_pop;
+ s->function_decl = current_function_decl;
- current_class_name = current_class_type = NULL_TREE;
+ scope_chain = s;
current_function_decl = NULL_TREE;
- class_binding_level = (struct binding_level *)0;
VARRAY_TREE_INIT (current_lang_base, 10, "current_lang_base");
current_lang_stack = &VARRAY_TREE (current_lang_base, 0);
current_lang_name = lang_name_cplusplus;
strict_prototype = strict_prototypes_lang_cplusplus;
- named_labels = NULL_TREE;
- previous_class_type = previous_class_values = NULL_TREE;
- class_cache_firstobj = 0;
- processing_specialization = 0;
- processing_explicit_instantiation = 0;
- current_template_parms = NULL_TREE;
- processing_template_decl = 0;
current_namespace = global_namespace;
-
- push_obstacks (&permanent_obstack, &permanent_obstack);
}
void
if (previous_class_type)
invalidate_class_lookup_cache ();
- pop_obstacks ();
-
VARRAY_FREE (current_lang_base);
scope_chain = s->prev;
else if (current_lang_name == lang_name_c)
strict_prototype = strict_prototypes_lang_c;
- free (s);
+ /* If we were in the middle of compiling a function, restore our
+ state. */
+ if (s->need_pop_function_context)
+ pop_function_context_from (NULL_TREE);
+ current_function_decl = s->function_decl;
- pop_function_context_from (NULL_TREE);
+ free (s);
}
\f
/* Push a definition of struct, union or enum tag "name".
that won't happen below because B is not the class
binding level, but is instead the pseudo-global level. */
b->level_chain->tags =
- saveable_tree_cons (name, type, b->level_chain->tags);
+ tree_cons (name, type, b->level_chain->tags);
if (TYPE_SIZE (current_class_type) == NULL_TREE)
CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
}
|| (globalize && b->parm_flag == 2))
b = b->level_chain;
- if (toplevel_bindings_p ())
- b->tags = perm_tree_cons (name, type, b->tags);
- else
- b->tags = saveable_tree_cons (name, type, b->tags);
+ b->tags = tree_cons (name, type, b->tags);
if (name)
{
}
/* If NEWDECL is `static' and an `extern' was seen previously,
- warn about it. (OLDDECL may be NULL_TREE; NAME contains
- information about previous usage as an `extern'.)
+ warn about it. OLDDECL is the previous declaration.
Note that this does not apply to the C++ case of declaring
a variable `extern const' and then later `const'.
warn_extern_redeclared_static (newdecl, olddecl)
tree newdecl, olddecl;
{
- tree name;
-
static const char *explicit_extern_static_warning
= "`%D' was declared `extern' and later `static'";
static const char *implicit_extern_static_warning
= "`%D' was declared implicitly `extern' and later `static'";
- if (TREE_CODE (newdecl) == TYPE_DECL)
+ tree name;
+
+ if (TREE_CODE (newdecl) == TYPE_DECL
+ || TREE_CODE (newdecl) == TEMPLATE_DECL)
+ return;
+
+ /* Don't get confused by static member functions; that's a different
+ use of `static'. */
+ if (TREE_CODE (newdecl) == FUNCTION_DECL
+ && DECL_STATIC_FUNCTION_P (newdecl))
+ return;
+
+ /* If the old declaration was `static', or the new one isn't, then
+ then everything is OK. */
+ if (DECL_THIS_STATIC (olddecl) || !DECL_THIS_STATIC (newdecl))
+ return;
+
+ /* It's OK to declare a builtin function as `static'. */
+ if (TREE_CODE (olddecl) == FUNCTION_DECL
+ && DECL_ARTIFICIAL (olddecl))
return;
name = DECL_ASSEMBLER_NAME (newdecl);
- if (TREE_PUBLIC (name) && DECL_THIS_STATIC (newdecl))
- {
- /* It's okay to redeclare an ANSI built-in function as static,
- or to declare a non-ANSI built-in function as anything. */
- if (! (TREE_CODE (newdecl) == FUNCTION_DECL
- && olddecl != NULL_TREE
- && TREE_CODE (olddecl) == FUNCTION_DECL
- && DECL_ARTIFICIAL (olddecl)))
- {
- cp_pedwarn (IDENTIFIER_IMPLICIT_DECL (name)
- ? implicit_extern_static_warning
- : explicit_extern_static_warning, newdecl);
- if (olddecl != NULL_TREE)
- cp_pedwarn_at ("previous declaration of `%D'", olddecl);
- }
- }
+ cp_pedwarn (IDENTIFIER_IMPLICIT_DECL (name)
+ ? implicit_extern_static_warning
+ : explicit_extern_static_warning, newdecl);
+ cp_pedwarn_at ("previous declaration of `%D'", olddecl);
}
/* Handle when a new declaration NEWDECL has the same name as an old
duplicate_decls (newdecl, olddecl)
tree newdecl, olddecl;
{
- extern struct obstack permanent_obstack;
unsigned olddecl_uid = DECL_UID (olddecl);
int olddecl_friend = 0, types_match = 0;
int new_defines_function = 0;
/* Discard the old built-in function. */
return 0;
}
+
+ if (DECL_THIS_STATIC (newdecl) && !DECL_THIS_STATIC (olddecl))
+ {
+ /* If a builtin function is redeclared as `static', merge
+ the declarations, but make the original one static. */
+ DECL_THIS_STATIC (olddecl) = 1;
+ TREE_PUBLIC (olddecl) = 0;
+
+ /* Make the olddeclaration consistent with the new one so that
+ all remnants of the builtin-ness of this function will be
+ banished. */
+ DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl);
+ DECL_RTL (olddecl) = DECL_RTL (newdecl);
+ DECL_ASSEMBLER_NAME (olddecl) = DECL_ASSEMBLER_NAME (newdecl);
+ SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (newdecl),
+ newdecl);
+ }
}
else if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
{
DECL_ABSTRACT_VIRTUAL_P (newdecl) |= DECL_ABSTRACT_VIRTUAL_P (olddecl);
DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl);
DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl);
+ DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl);
new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE;
/* Optionally warn about more than one declaration for the same
tree oldtype = TREE_TYPE (olddecl);
tree newtype;
- /* Make sure we put the new type in the same obstack as the old one. */
- if (oldtype)
- push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype));
- else
- push_permanent_obstack ();
-
/* Merge the data types specified in the two decls. */
newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
{
cp_error ("declaration of `%F' throws different exceptions",
newdecl);
- cp_error_at ("to previous declaration `%F'", olddecl);
+ cp_error_at ("than previous declaration `%F'", olddecl);
}
}
TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
- /* Keep the old rtl since we can safely use it, unless it's the
- call to abort() used for abstract virtuals. */
- if ((DECL_LANG_SPECIFIC (olddecl)
- && !DECL_ABSTRACT_VIRTUAL_P (olddecl))
- || DECL_RTL (olddecl) != DECL_RTL (abort_fndecl))
- DECL_RTL (newdecl) = DECL_RTL (olddecl);
+ /* Keep the old rtl since we can safely use it. */
+ DECL_RTL (newdecl) = DECL_RTL (olddecl);
- pop_obstacks ();
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
+ {
+ DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
+ |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+ DECL_NO_CHECK_MEMORY_USAGE (newdecl)
+ |= DECL_NO_CHECK_MEMORY_USAGE (olddecl);
+ DECL_NO_LIMIT_STACK (newdecl)
+ |= DECL_NO_LIMIT_STACK (olddecl);
+ }
}
/* If cannot merge, then use the new type and qualifiers,
and don't preserve the old rtl. */
/* Merge the storage class information. */
DECL_WEAK (newdecl) |= DECL_WEAK (olddecl);
DECL_ONE_ONLY (newdecl) |= DECL_ONE_ONLY (olddecl);
+ DECL_DEFER_OUTPUT (newdecl) |= DECL_DEFER_OUTPUT (olddecl);
TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
TREE_STATIC (olddecl) = TREE_STATIC (newdecl) |= TREE_STATIC (olddecl);
if (! DECL_EXTERNAL (olddecl))
it stays built in. */
if (DECL_BUILT_IN (olddecl))
{
- DECL_BUILT_IN (newdecl) = 1;
+ DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
/* If we're keeping the built-in definition, keep the rtl,
regardless of declaration matches. */
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
int function_size;
- struct lang_decl *ol = DECL_LANG_SPECIFIC (olddecl);
- struct lang_decl *nl = DECL_LANG_SPECIFIC (newdecl);
function_size = sizeof (struct tree_decl);
(char *) olddecl + sizeof (struct tree_common),
function_size - sizeof (struct tree_common));
- /* Can we safely free the storage used by newdecl? */
-
-#define ROUND(x) ((x + obstack_alignment_mask (&permanent_obstack)) \
- & ~ obstack_alignment_mask (&permanent_obstack))
-
if (DECL_TEMPLATE_INSTANTIATION (newdecl))
{
/* If newdecl is a template instantiation, it is possible that
if (TREE_VALUE (decls) == newdecl)
TREE_VALUE (decls) = olddecl;
}
-
- if (((char *)newdecl + ROUND (function_size) == (char *)nl
- && ((char *)newdecl + ROUND (function_size)
- + ROUND (sizeof (struct lang_decl))
- == obstack_next_free (&permanent_obstack)))
- || ((char *)newdecl + ROUND (function_size)
- == obstack_next_free (&permanent_obstack)))
- {
- DECL_MAIN_VARIANT (newdecl) = olddecl;
- DECL_LANG_SPECIFIC (olddecl) = ol;
- bcopy ((char *)nl, (char *)ol, sizeof (struct lang_decl));
-
- obstack_free (&permanent_obstack, newdecl);
- }
- else if (LANG_DECL_PERMANENT (ol) && ol != nl)
- {
- if (DECL_MAIN_VARIANT (olddecl) == olddecl)
- {
- struct lang_decl *free_lang_decl = ol;
-
- /* Save these lang_decls that would otherwise be lost. */
- if (DECL_LANG_SPECIFIC (olddecl) == ol)
- abort ();
-
- free_lang_decl->u.next = free_lang_decl_chain;
- free_lang_decl_chain = free_lang_decl;
- }
- else
- {
- /* Storage leak. */;
- }
- }
}
else
{
tree x;
{
register tree t;
- register tree name = DECL_ASSEMBLER_NAME (x);
- int need_new_binding = 1;
+ register tree name;
+ int need_new_binding;
+
+ /* We shouldn't be calling pushdecl when we're generating RTL for a
+ function that we already did semantic analysis on previously. */
+ my_friendly_assert (!current_function || doing_semantic_analysis_p (),
+ 19990913);
+
+ name = DECL_ASSEMBLER_NAME (x);
+ need_new_binding = 1;
if (DECL_TEMPLATE_PARM_P (x))
/* Template parameters have no context; they are not X::T even
if (current_function_decl && x != current_function_decl
/* A local declaration for a function doesn't constitute
nesting. */
- && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x))
+ && !(TREE_CODE (x) == FUNCTION_DECL && !DECL_INITIAL (x))
+ /* A local declaration for an `extern' variable is in the
+ scoped of the current namespace, not the current
+ function. */
+ && !(TREE_CODE (x) == VAR_DECL && DECL_EXTERNAL (x))
/* Don't change DECL_CONTEXT of virtual methods. */
&& (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
&& !DECL_CONTEXT (x))
DECL_CONTEXT (x) = current_function_decl;
if (!DECL_CONTEXT (x))
DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace);
+
+ /* If this is the declaration for a namespace-scope function,
+ but the declaration itself is in a local scope, mark the
+ declaration. */
+ if (TREE_CODE (x) == FUNCTION_DECL
+ && DECL_NAMESPACE_SCOPE_P (x)
+ && current_function_decl
+ && x != current_function_decl)
+ DECL_LOCAL_FUNCTION_P (x) = 1;
}
/* Type are looked up using the DECL_NAME, as that is what the rest of the
if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x))
{
t = push_overloaded_decl (x, PUSH_LOCAL);
- if (t != x || DECL_LANGUAGE (x) == lang_c)
+ if (t != x)
return t;
if (!namespace_bindings_p ())
/* We do not need to create a binding for this name;
&& (!TYPE_NAME (type)
|| TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))
{
- push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
-
DECL_ORIGINAL_TYPE (x) = type;
type = build_type_copy (type);
TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
TYPE_NAME (type) = x;
TREE_TYPE (x) = type;
-
- pop_obstacks ();
}
if (type != error_mark_node
TREE_PUBLIC (name) = 1;
if (!(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)
- && t != NULL_TREE))
+ && t != NULL_TREE)
+ /* For an ordinary function, we create a binding from
+ the mangled name (i.e., NAME) to the DECL. But, for
+ an `extern "C"' function, the mangled name and the
+ ordinary name are the same so we need not do this. */
+ && !(TREE_CODE (x) == FUNCTION_DECL &&
+ DECL_LANGUAGE (x) == lang_c))
{
if (TREE_CODE (x) == FUNCTION_DECL)
my_friendly_assert
/* No shadow warnings for vars made for inlining. */
&& ! DECL_FROM_INLINE (x))
{
- const char *warnstring = NULL;
-
if (oldlocal != NULL_TREE && TREE_CODE (oldlocal) == PARM_DECL)
- warnstring = "declaration of `%s' shadows a parameter";
+ warning ("declaration of `%s' shadows a parameter",
+ IDENTIFIER_POINTER (name));
else if (IDENTIFIER_CLASS_VALUE (name) != NULL_TREE
&& current_class_ptr
&& !TREE_STATIC (name))
- warnstring = "declaration of `%s' shadows a member of `this'";
+ warning ("declaration of `%s' shadows a member of `this'",
+ IDENTIFIER_POINTER (name));
else if (oldlocal != NULL_TREE)
- warnstring = "declaration of `%s' shadows previous local";
+ warning ("declaration of `%s' shadows previous local",
+ IDENTIFIER_POINTER (name));
else if (oldglobal != NULL_TREE)
/* XXX shadow warnings in outer-more namespaces */
- warnstring = "declaration of `%s' shadows global declaration";
-
- if (warnstring)
- warning (warnstring, IDENTIFIER_POINTER (name));
+ warning ("declaration of `%s' shadows global declaration",
+ IDENTIFIER_POINTER (name));
}
}
}
if (need_new_binding)
- add_decl_to_level (x, current_binding_level);
+ add_decl_to_level (x,
+ DECL_NAMESPACE_SCOPE_P (x)
+ ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
+ : current_binding_level);
return x;
}
pushdecl_top_level (x)
tree x;
{
- tree cur_namespace = current_namespace;
- current_namespace = global_namespace;
+ push_to_top_level ();
x = pushdecl_namespace_level (x);
- current_namespace = cur_namespace;
+ pop_from_top_level ();
return x;
}
IDENTIFIER_CLASS_VALUE. */
if (push_class_binding (name, x))
{
- push_cache_obstack ();
class_binding_level->class_shadowed
= tree_cons (name, IDENTIFIER_CLASS_VALUE (name),
class_binding_level->class_shadowed);
- pop_obstacks ();
/* Record the value we are binding NAME to so that we can know
what to pop later. */
TREE_TYPE (class_binding_level->class_shadowed) = x;
ancestor = namespace_ancestor (current_decl_namespace (), used);
ud = current_binding_level->using_directives;
- ud = perm_tree_cons (used, ancestor, ud);
+ ud = tree_cons (used, ancestor, ud);
current_binding_level->using_directives = ud;
return ud;
}
TREE_VALUE (*d) = new_binding;
else
/* Build a TREE_LIST to wrap the OVERLOAD. */
- *d = build_tree_list (NULL_TREE, new_binding);
+ *d = tree_cons (NULL_TREE, new_binding,
+ TREE_CHAIN (*d));
/* And update the CPLUS_BINDING node. */
BINDING_VALUE (IDENTIFIER_BINDING (name))
tree functionid;
{
register tree decl;
- int temp = allocation_temporary_p ();
-
- push_obstacks_nochange ();
-
- /* Save the decl permanently so we can warn if definition follows.
- In ANSI C, warn_implicit is usually false, so the saves little space.
- But in C++, it's usually true, hence the extra code. */
- if (temp && (! warn_implicit || toplevel_bindings_p ()))
- end_temporary_allocation ();
/* We used to reuse an old implicit decl here,
but this loses with inline functions because it can clobber
SET_IDENTIFIER_IMPLICIT_DECL (functionid, decl);
- pop_obstacks ();
-
return decl;
}
{
tree decl;
- if (building_stmt_tree ())
- push_permanent_obstack ();
decl = build_decl (LABEL_DECL, id, void_type_node);
- if (building_stmt_tree ())
- pop_obstacks ();
- else
+ if (expanding_p)
/* Make sure every label has an rtx. */
label_rtx (decl);
switch_stack = switch_stack->next;
}
-/* Same, but for CASE labels. If DECL is NULL_TREE, it's the default. */
-/* XXX Note decl is never actually used. (bpk) */
+/* Note that we've seen a definition of a case label, and complain if this
+ is a bad place for one. */
void
define_case_label ()
struct binding_level *b = current_binding_level;
int identified = 0;
+ if (! switch_stack)
+ /* Don't crash; we'll complain in do_case. */
+ return;
+
if (cleanup)
{
static int explained = 0;
static struct hash_table ht;
- push_obstacks (&permanent_obstack, &permanent_obstack);
-
if (!ht.table)
{
static struct hash_table *h = &ht;
ggc_add_tree_hash_table_root (&h, 1);
}
- /* The FULLNAME needs to exist for the life of the hash table, i.e.,
- for the entire compilation. */
- if (!TREE_PERMANENT (fullname))
- fullname = copy_to_permanent (fullname);
-
/* Build the TYPENAME_TYPE. */
t = make_lang_type (TYPENAME_TYPE);
TYPE_CONTEXT (t) = FROB_CONTEXT (context);
/* Insert the type into the table. */
hash_lookup (&ht, t, /*create=*/true, /*copy=*/0);
- pop_obstacks ();
-
return t;
}
+/* Resolve `typename CONTEXT::NAME'. Returns an appropriate type,
+ unless an error occurs, in which case error_mark_node is returned.
+ If COMPLAIN zero, don't complain about any errors that occur. */
+
tree
-make_typename_type (context, name)
+make_typename_type (context, name, complain)
tree context, name;
+ int complain;
{
tree fullname;
{
/* We can get here from typename_sub0 in the explicit_template_type
expansion. Just fail. */
- cp_error ("no class template named `%#T' in `%#T'",
- name, context);
+ if (complain)
+ cp_error ("no class template named `%#T' in `%#T'",
+ name, context);
return error_mark_node;
}
tmpl = lookup_field (context, name, 0, 0);
if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl))
{
- cp_error ("no class template named `%#T' in `%#T'",
- name, context);
+ if (complain)
+ cp_error ("no class template named `%#T' in `%#T'",
+ name, context);
return error_mark_node;
}
if (!IS_AGGR_TYPE (context))
{
- cp_error ("no type named `%#T' in `%#T'", name, context);
+ if (complain)
+ cp_error ("no type named `%#T' in `%#T'", name, context);
return error_mark_node;
}
there now or its never going to be. */
if (!uses_template_parms (context))
{
- cp_error ("no type named `%#T' in `%#T'", name, context);
+ if (complain)
+ cp_error ("no type named `%#T' in `%#T'", name, context);
return error_mark_node;
}
for (; !val; scope = CP_DECL_CONTEXT (scope))
{
if (spacesp)
- *spacesp = scratch_tree_cons (scope, NULL_TREE, *spacesp);
+ *spacesp = tree_cons (scope, NULL_TREE, *spacesp);
val = binding_for_name (name, scope);
/* Initialize binding for this context. */
if (b->namespace_p)
{
- t = IDENTIFIER_NAMESPACE_VALUE (name);
+ t = IDENTIFIER_NAMESPACE_VALUE (name);
/* extern "C" function() */
if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST)
push_overloaded_decl_1 (x)
tree x;
{
- push_overloaded_decl (x, PUSH_GLOBAL);
+ pushdecl (x);
}
-#ifdef __GNUC__
-__inline
-#endif
-tree
-auto_function (name, type, code)
+inline tree
+auto_function (name, type)
tree name, type;
- enum built_in_function code;
{
return define_function
- (IDENTIFIER_POINTER (name), type, code, push_overloaded_decl_1,
+ (IDENTIFIER_POINTER (name), type, push_overloaded_decl_1,
IDENTIFIER_POINTER (build_decl_overload (name, TYPE_ARG_TYPES (type),
0)));
}
/* Let the back-end now how to save and restore language-specific
per-function globals. */
- save_lang_status = &push_cp_function_context;
- restore_lang_status = &pop_cp_function_context;
+ init_lang_status = &push_cp_function_context;
+ free_lang_status = &pop_cp_function_context;
mark_lang_status = &mark_cp_function_context;
cp_parse_init ();
current_lang_name = lang_name_c;
current_function_decl = NULL_TREE;
- named_labels = NULL_TREE;
- named_label_uses = NULL;
current_binding_level = NULL_BINDING_LEVEL;
free_binding_level = NULL_BINDING_LEVEL;
signal (SIGBUS, signal_catch);
#endif
- gcc_obstack_init (&decl_obstack);
+ build_common_tree_nodes (flag_signed_char);
- /* Must lay these out before anything else gets laid out. */
- error_mark_node = make_node (ERROR_MARK);
- TREE_PERMANENT (error_mark_node) = 1;
- TREE_TYPE (error_mark_node) = error_mark_node;
error_mark_list = build_tree_list (error_mark_node, error_mark_node);
TREE_TYPE (error_mark_list) = error_mark_node;
pfn_or_delta2_identifier = get_identifier ("__pfn_or_delta2");
/* Define `int' and `char' first so that dbx will output them first. */
-
- integer_type_node = make_signed_type (INT_TYPE_SIZE);
record_builtin_type (RID_INT, NULL_PTR, integer_type_node);
-
- /* Define `char', which is like either `signed char' or `unsigned char'
- but not the same as either. */
-
- char_type_node
- = (flag_signed_char
- ? make_signed_type (CHAR_TYPE_SIZE)
- : make_unsigned_type (CHAR_TYPE_SIZE));
record_builtin_type (RID_CHAR, "char", char_type_node);
/* `signed' is the same as `int' */
record_builtin_type (RID_SIGNED, NULL_PTR, integer_type_node);
-
- long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
record_builtin_type (RID_LONG, "long int", long_integer_type_node);
-
- unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node);
-
- long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
record_builtin_type (RID_MAX, "long unsigned int", long_unsigned_type_node);
record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node);
-
- long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
record_builtin_type (RID_MAX, "long long int", long_long_integer_type_node);
-
- long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
record_builtin_type (RID_MAX, "long long unsigned int",
long_long_unsigned_type_node);
record_builtin_type (RID_MAX, "long long unsigned",
long_long_unsigned_type_node);
-
- short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
record_builtin_type (RID_SHORT, "short int", short_integer_type_node);
- short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
record_builtin_type (RID_MAX, "short unsigned int", short_unsigned_type_node);
record_builtin_type (RID_MAX, "unsigned short", short_unsigned_type_node);
- /* `unsigned long' is the standard type for sizeof.
- Note that stddef.h uses `unsigned long',
- and this must agree, even if long and int are the same size. */
- set_sizetype
- (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))));
-
ptrdiff_type_node
= TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
/* Define both `signed char' and `unsigned char'. */
- signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
record_builtin_type (RID_MAX, "signed char", signed_char_type_node);
- unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node);
+ /* `unsigned long' is the standard type for sizeof.
+ Note that stddef.h uses `unsigned long',
+ and this must agree, even if long and int are the same size. */
+ set_sizetype
+ (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))));
+
/* Create the widest literal types. */
widest_integer_literal_type_node = make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
pushdecl (build_decl (TYPE_DECL, NULL_TREE,
widest_unsigned_literal_type_node));
/* These are types that type_for_size and type_for_mode use. */
- intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node));
- intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node));
- intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node));
- intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
#if HOST_BITS_PER_WIDE_INT >= 64
- intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
pushdecl (build_decl (TYPE_DECL, get_identifier ("__int128_t"), intTI_type_node));
#endif
- unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
- unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node));
- unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node));
- unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
#if HOST_BITS_PER_WIDE_INT >= 64
- unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
pushdecl (build_decl (TYPE_DECL, get_identifier ("__uint128_t"), unsigned_intTI_type_node));
#endif
- float_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
- record_builtin_type (RID_FLOAT, NULL_PTR, float_type_node);
- layout_type (float_type_node);
-
- double_type_node = make_node (REAL_TYPE);
- if (flag_short_double)
- TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE;
- else
- TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
- record_builtin_type (RID_DOUBLE, NULL_PTR, double_type_node);
- layout_type (double_type_node);
-
- long_double_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
- record_builtin_type (RID_MAX, "long double", long_double_type_node);
- layout_type (long_double_type_node);
-
- complex_integer_type_node = make_node (COMPLEX_TYPE);
- pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
- complex_integer_type_node));
- TREE_TYPE (complex_integer_type_node) = integer_type_node;
- layout_type (complex_integer_type_node);
-
- complex_float_type_node = make_node (COMPLEX_TYPE);
- pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
- complex_float_type_node));
- TREE_TYPE (complex_float_type_node) = float_type_node;
- layout_type (complex_float_type_node);
-
- complex_double_type_node = make_node (COMPLEX_TYPE);
- pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
- complex_double_type_node));
- TREE_TYPE (complex_double_type_node) = double_type_node;
- layout_type (complex_double_type_node);
-
- complex_long_double_type_node = make_node (COMPLEX_TYPE);
- pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
- complex_long_double_type_node));
- TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
- layout_type (complex_long_double_type_node);
+ build_common_tree_nodes_2 (flag_short_double);
java_byte_type_node = record_builtin_java_type ("__java_byte", 8);
java_short_type_node = record_builtin_java_type ("__java_short", 16);
java_char_type_node = record_builtin_java_type ("__java_char", -16);
java_boolean_type_node = record_builtin_java_type ("__java_boolean", -1);
- integer_zero_node = build_int_2 (0, 0);
- TREE_TYPE (integer_zero_node) = integer_type_node;
- integer_one_node = build_int_2 (1, 0);
- TREE_TYPE (integer_one_node) = integer_type_node;
integer_two_node = build_int_2 (2, 0);
TREE_TYPE (integer_two_node) = integer_type_node;
integer_three_node = build_int_2 (3, 0);
boolean_true_node = build_int_2 (1, 0);
TREE_TYPE (boolean_true_node) = boolean_type_node;
- /* These are needed by stor-layout.c. */
- size_zero_node = size_int (0);
- size_one_node = size_int (1);
+ signed_size_zero_node = build_int_2 (0, 0); record_builtin_type (RID_FLOAT, NULL_PTR, float_type_node);
+ record_builtin_type (RID_DOUBLE, NULL_PTR, double_type_node);
+ record_builtin_type (RID_MAX, "long double", long_double_type_node);
+
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
+ complex_integer_type_node));
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
+ complex_float_type_node));
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
+ complex_double_type_node));
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
+ complex_long_double_type_node));
- signed_size_zero_node = build_int_2 (0, 0);
TREE_TYPE (signed_size_zero_node) = make_signed_type (TYPE_PRECISION (sizetype));
- void_type_node = make_node (VOID_TYPE);
record_builtin_type (RID_VOID, NULL_PTR, void_type_node);
- layout_type (void_type_node); /* Uses integer_zero_node. */
void_list_node = build_tree_list (NULL_TREE, void_type_node);
TREE_PARMLIST (void_list_node) = 1;
- null_pointer_node = build_int_2 (0, 0);
- TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
- layout_type (TREE_TYPE (null_pointer_node));
-
/* Used for expressions that do nothing, but are not errors. */
void_zero_node = build_int_2 (0, 0);
TREE_TYPE (void_zero_node) = void_type_node;
= build_pointer_type (build_qualified_type (void_type_node,
TYPE_QUAL_CONST));
c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin);
+ lang_type_promotes_to = convert_type_from_ellipsis;
void_ftype_ptr
= build_exception_variant (void_ftype_ptr, empty_except_spec);
TYPE_REFERENCE_TO (unknown_type_node) = unknown_type_node;
/* This is special for C++ so functions can be overloaded. */
- wchar_type_node
- = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE)));
+ wchar_type_node = get_identifier (flag_short_wchar
+ ? "short unsigned int"
+ : WCHAR_TYPE);
+ wchar_type_node = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (wchar_type_node));
wchar_type_size = TYPE_PRECISION (wchar_type_node);
signed_wchar_type_node = make_signed_type (wchar_type_size);
unsigned_wchar_type_node = make_unsigned_type (wchar_type_size);
newtype = build_exception_variant
(ptr_ftype_sizetype, add_exception_specifier (NULL_TREE, bad_alloc_type_node, -1));
deltype = build_exception_variant (void_ftype_ptr, empty_except_spec);
- auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN);
- auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN);
- global_delete_fndecl
- = auto_function (ansi_opname[(int) DELETE_EXPR], deltype, NOT_BUILT_IN);
- auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype, NOT_BUILT_IN);
+ auto_function (ansi_opname[(int) NEW_EXPR], newtype);
+ auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype);
+ global_delete_fndecl = auto_function (ansi_opname[(int) DELETE_EXPR],
+ deltype);
+ auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype);
}
abort_fndecl
- = define_function ("__pure_virtual", void_ftype,
- NOT_BUILT_IN, 0, 0);
+ = define_function ("__pure_virtual", void_ftype, 0, 0);
/* Perform other language dependent initializations. */
init_class_processing ();
init_init_processing ();
init_search_processing ();
- if (flag_rtti)
- init_rtti_processing ();
+ init_rtti_processing ();
if (flag_exceptions)
init_exception_processing ();
/* Add GC roots for all of our global variables. */
ggc_add_tree_root (c_global_trees, sizeof c_global_trees / sizeof(tree));
ggc_add_tree_root (cp_global_trees, sizeof cp_global_trees / sizeof(tree));
- ggc_add_tree_root (&char_type_node, 1);
- ggc_add_tree_root (&error_mark_node, 1);
- ggc_add_tree_root (&integer_type_node, 1);
ggc_add_tree_root (&integer_three_node, 1);
ggc_add_tree_root (&integer_two_node, 1);
- ggc_add_tree_root (&integer_one_node, 1);
- ggc_add_tree_root (&integer_zero_node, 1);
ggc_add_tree_root (&signed_size_zero_node, 1);
ggc_add_tree_root (&size_one_node, 1);
ggc_add_tree_root (&size_zero_node, 1);
- ggc_add_tree_root (&unsigned_type_node, 1);
- ggc_add_tree_root (&ptr_type_node, 1);
- ggc_add_tree_root (&null_pointer_node, 1);
- ggc_add_tree_root (&va_list_type_node, 1);
- ggc_add_tree_root (&void_type_node, 1);
ggc_add_root (&global_binding_level, 1, sizeof global_binding_level,
mark_binding_level);
ggc_add_root (&scope_chain, 1, sizeof scope_chain, &mark_saved_scope);
ggc_add_tree_root (&static_dtors, 1);
ggc_add_tree_root (&lastiddecl, 1);
- ggc_add_tree_root (&enum_next_value, 1);
ggc_add_tree_root (&last_function_parm_tags, 1);
ggc_add_tree_root (¤t_function_return_value, 1);
ggc_add_tree_root (¤t_function_parms, 1);
/* Make a definition for a builtin function named NAME and whose data type
is TYPE. TYPE should be a function type with argument types.
- FUNCTION_CODE tells later passes how to compile calls to this function.
- See tree.h for its possible values.
If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
the name to be called if we can't opencode the function. */
tree
-define_function (name, type, function_code, pfn, library_name)
+define_function (name, type, pfn, library_name)
const char *name;
tree type;
- enum built_in_function function_code;
void (*pfn) PROTO((tree));
const char *library_name;
{
if (library_name)
DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name);
make_function_rtl (decl);
- if (function_code != NOT_BUILT_IN)
- {
- DECL_BUILT_IN (decl) = 1;
- DECL_FUNCTION_CODE (decl) = function_code;
- }
return decl;
}
-tree
-builtin_function (name, type, code, libname)
- const char *name;
+
+/* Wrapper around define_function, for the benefit of
+ c_common_nodes_and_builtins.
+ FUNCTION_CODE tells later passes how to compile calls to this function.
+ See tree.h for its possible values. */
+
+tree
+builtin_function (name, type, code, class, libname)
+ const char *name;
tree type;
- enum built_in_function code;
+ int code;
+ enum built_in_class class;
const char *libname;
{
- return define_function (name, type, code, (void (*) PROTO((tree)))pushdecl, libname);
+ tree decl = define_function (name, type, (void (*) PROTO((tree)))pushdecl,
+ libname);
+ DECL_BUILT_IN_CLASS (decl) = class;
+ DECL_FUNCTION_CODE (decl) = code;
+ return decl;
}
\f
/* When we call finish_struct for an anonymous union, we create
if (type == error_mark_node)
return NULL_TREE;
- /* Don't lose if destructors must be executed at file-level. */
- if (! processing_template_decl && TREE_STATIC (decl)
- && TYPE_NEEDS_DESTRUCTOR (complete_type (type))
- && !TREE_PERMANENT (decl))
- {
- push_obstacks (&permanent_obstack, &permanent_obstack);
- decl = copy_node (decl);
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- tree itype = TYPE_DOMAIN (type);
- if (itype && ! TREE_PERMANENT (itype))
- {
- itype = build_index_type (copy_to_permanent (TYPE_MAX_VALUE (itype)));
- type = build_cplus_array_type (TREE_TYPE (type), itype);
- TREE_TYPE (decl) = type;
- }
- }
- pop_obstacks ();
- }
-
context
= (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))
? DECL_CLASS_CONTEXT (decl)
tem = maybe_push_decl (decl);
if (processing_template_decl)
- {
- if (at_function_scope_p ())
- push_permanent_obstack ();
-
- tem = push_template_decl (tem);
- /* In a a local scope, add a representation of this declaration
- to the statement tree. */
- if (at_function_scope_p ())
- {
- add_decl_stmt (decl);
- pop_obstacks ();
- }
- }
-
+ tem = push_template_decl (tem);
#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
/* Tell the back-end to use or not use .common as appropriate. If we say
if (! processing_template_decl)
start_decl_1 (tem);
- /* Corresponding pop_obstacks is done in `cp_finish_decl'. */
- push_obstacks_nochange ();
-
return tem;
}
if (type == error_mark_node)
return;
- /* If this type of object needs a cleanup, and control may
- jump past it, make a new binding level so that it is cleaned
- up only when it is initialized first. */
+ /* If this type of object needs a cleanup, but we're not allowed to
+ add any more objects with cleanups to the current scope, create a
+ new binding level. */
if (TYPE_NEEDS_DESTRUCTOR (type)
&& current_binding_level->more_cleanups_ok == 0)
- pushlevel_temporary (1);
+ {
+ keep_next_level (2);
+ pushlevel (1);
+ clear_last_expr ();
+ add_scope_stmt (/*begin_p=*/1, /*partial_p=*/1);
+ }
if (initialized)
/* Is it valid for this decl to have an initializer at all?
if ((DECL_LANG_SPECIFIC (decl) == 0
|| DECL_IN_AGGR_P (decl) == 0)
&& ! DECL_THIS_EXTERN (decl))
- {
- cp_error ("`%D' declared as reference but not initialized", decl);
- if (TREE_CODE (decl) == VAR_DECL)
- SET_DECL_REFERENCE_SLOT (decl, error_mark_node);
- }
+ cp_error ("`%D' declared as reference but not initialized", decl);
return;
}
if (init == error_mark_node)
return;
- if (TREE_CODE (type) == REFERENCE_TYPE
- && TREE_CODE (init) == CONSTRUCTOR)
+ if (TREE_CODE (init) == CONSTRUCTOR)
{
cp_error ("ANSI C++ forbids use of initializer list to initialize reference `%D'", decl);
return;
/* Note: default conversion is only called in very special cases. */
init = default_conversion (init);
}
-
+
+ /* Convert INIT to the reference type TYPE. This may involve the
+ creation of a temporary, whose lifetime must be the same as that
+ of the reference. If so, a DECL_STMT for the temporary will be
+ added just after the DECL_STMT for DECL. That's why we don't set
+ DECL_INITIAL for local references (instead assigning to them
+ explicitly); we need to allow the temporary to be initialized
+ first. */
tmp = convert_to_reference
(type, init, CONV_IMPLICIT,
LOOKUP_SPECULATIVELY|LOOKUP_NORMAL|DIRECT_BIND, decl);
if (tmp == error_mark_node)
- goto fail;
+ return;
else if (tmp != NULL_TREE)
{
init = tmp;
- DECL_INITIAL (decl) = save_expr (init);
+ tmp = save_expr (tmp);
+ if (building_stmt_tree ())
+ {
+ /* Initialize the declaration. */
+ tmp = build (INIT_EXPR, TREE_TYPE (decl), decl, tmp);
+ finish_expr_stmt (tmp);
+ }
+ else
+ DECL_INITIAL (decl) = tmp;
}
else
{
cp_error ("cannot initialize `%T' from `%T'", type, TREE_TYPE (init));
- goto fail;
- }
-
- /* ?? Can this be optimized in some cases to
- hand back the DECL_INITIAL slot?? */
- if (TYPE_SIZE (TREE_TYPE (type)))
- {
- init = convert_from_reference (decl);
- if (TREE_PERMANENT (decl))
- init = copy_to_permanent (init);
- SET_DECL_REFERENCE_SLOT (decl, init);
+ return;
}
if (TREE_STATIC (decl) && ! TREE_CONSTANT (DECL_INITIAL (decl)))
DECL_INITIAL (decl) = NULL_TREE;
}
return;
-
- fail:
- if (TREE_CODE (decl) == VAR_DECL)
- SET_DECL_REFERENCE_SLOT (decl, error_mark_node);
- return;
}
/* Fill in DECL_INITIAL with some magical value to prevent expand_decl from
}
/* Set DECL_SIZE, DECL_ALIGN, etc. for DECL (a VAR_DECL), and issue
- any appropriate error messages regarding the layout. INITP is a
- pointer to the initializer for DECL; the initializer may be
- modified by this function. */
+ any appropriate error messages regarding the layout. */
static void
-layout_var_decl (decl, initp)
+layout_var_decl (decl)
tree decl;
- tree *initp;
{
- tree ttype = target_type (TREE_TYPE (decl));
+ tree type = TREE_TYPE (decl);
+#if 0
+ tree ttype = target_type (type);
+#endif
- if (DECL_SIZE (decl) == NULL_TREE
- && TYPE_SIZE (complete_type (TREE_TYPE (decl))) != NULL_TREE)
+ /* If we haven't already layed out this declaration, do so now.
+ Note that we must not call complete type for an external object
+ because it's type might involve templates that we are not
+ supposed to isntantiate yet. (And it's perfectly legal to say
+ `extern X x' for some incomplete type `X'.) */
+ if (!DECL_EXTERNAL (decl))
+ complete_type (type);
+ if (!DECL_SIZE (decl)&& TYPE_SIZE (type))
layout_decl (decl, 0);
- if (TREE_STATIC (decl) && DECL_SIZE (decl) == NULL_TREE)
- {
- /* A static variable with an incomplete type:
- that is an error if it is initialized.
- Otherwise, let it through, but if it is not `extern'
- then it may cause an error message later. */
- if (DECL_INITIAL (decl) != NULL_TREE)
- cp_error ("storage size of `%D' isn't known", decl);
- *initp = NULL_TREE;
- }
- else if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE)
+ if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE)
{
/* An automatic variable with an incomplete type: that is an error.
Don't talk about array types here, since we took care of that
cp_error ("storage size of `%D' isn't known", decl);
TREE_TYPE (decl) = error_mark_node;
}
+#if 0
+ /* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". (jason 1999-11-11) */
+
else if (!DECL_EXTERNAL (decl) && IS_AGGR_TYPE (ttype))
/* Let debugger know it should output info for this type. */
note_debug_info_needed (ttype);
if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl))
note_debug_info_needed (DECL_CONTEXT (decl));
+#endif
if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
&& DECL_SIZE (decl) != NULL_TREE
}
}
-/* Return a cleanup for DECL, created on whatever obstack is
- appropriate. */
-
-static tree
-build_cleanup_on_safe_obstack (decl)
- tree decl;
-{
- tree cleanup;
- tree type;
- int need_pop;
-
- type = TREE_TYPE (decl);
-
- /* Only variables get cleaned up. */
- if (TREE_CODE (decl) != VAR_DECL)
- return NULL_TREE;
-
- /* And only things with destructors need cleaning up. */
- if (!TYPE_NEEDS_DESTRUCTOR (type))
- return NULL_TREE;
-
- if (TREE_CODE (decl) == VAR_DECL &&
- (DECL_EXTERNAL (decl) || TREE_STATIC (decl)))
- /* We don't clean up things that aren't defined in this
- translation unit, or that need a static cleanup. The latter
- are handled by finish_file. */
- return NULL_TREE;
-
- /* Switch to an obstack that will live until the point where the
- cleanup code is actually expanded. */
- need_pop = suspend_momentary ();
-
- /* Compute the cleanup. */
- cleanup = maybe_build_cleanup (decl);
-
- /* Pop back to the obstack we were on before. */
- resume_momentary (need_pop);
-
- return cleanup;
-}
-
/* If a local static variable is declared in an inline function, or if
we have a weak definition, we must endeavor to create only one
instance of the variable at link-time. */
cp_error ("uninitialized const `%D'", decl);
}
-/* Verify INITP (the initializer for DECL), and record the
- initialization in DECL_INITIAL, if appropriate. The initializer
- may be modified by this function. */
+/* Verify INIT (the initializer for DECL), and record the
+ initialization in DECL_INITIAL, if appropriate. Returns a new
+ value for INIT. */
-static void
-check_initializer (decl, initp)
+static tree
+check_initializer (decl, init)
tree decl;
- tree *initp;
+ tree init;
{
- tree init;
tree type;
if (TREE_CODE (decl) == FIELD_DECL)
- return;
+ return init;
type = TREE_TYPE (decl);
- init = *initp;
/* If `start_decl' didn't like having an initialization, ignore it now. */
if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
init = NULL_TREE;
- else if (DECL_EXTERNAL (decl))
- ;
- else if (TREE_CODE (type) == REFERENCE_TYPE)
- {
- if (TREE_STATIC (decl))
- make_decl_rtl (decl, NULL_PTR, toplevel_bindings_p ());
- grok_reference_init (decl, type, init);
- init = NULL_TREE;
- }
- /* Check for certain invalid initializations. */
+ /* Check the initializer. */
if (init)
{
- if (TYPE_SIZE (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
+ /* Things that are going to be initialized need to have complete
+ type. */
+ TREE_TYPE (decl) = type = complete_type (TREE_TYPE (decl));
+
+ if (type == error_mark_node)
+ /* We will have already complained. */
+ init = NULL_TREE;
+ else if (TYPE_SIZE (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
{
cp_error ("variable-sized object `%D' may not be initialized", decl);
init = NULL_TREE;
}
- if (TREE_CODE (type) == ARRAY_TYPE
- && !TYPE_SIZE (complete_type (TREE_TYPE (type))))
+ else if (TREE_CODE (type) == ARRAY_TYPE
+ && !TYPE_SIZE (TREE_TYPE (type)))
{
cp_error ("elements of array `%#D' have incomplete type", decl);
init = NULL_TREE;
}
+ else if (!TYPE_SIZE (type))
+ {
+ cp_error ("`%D' has incomplete type", decl);
+ TREE_TYPE (decl) = error_mark_node;
+ init = NULL_TREE;
+ }
}
if (TREE_CODE (decl) == CONST_DECL)
my_friendly_assert (init != NULL_TREE, 149);
init = NULL_TREE;
}
+ else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ if (TREE_STATIC (decl))
+ make_decl_rtl (decl, NULL_PTR, toplevel_bindings_p ());
+ grok_reference_init (decl, type, init);
+ init = NULL_TREE;
+ }
else if (init)
{
if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
else
check_for_uninitialized_const_var (decl);
- /* Store the modified initializer for our caller. */
- *initp = init;
+ return init;
}
/* If DECL is not a local variable, give it RTL. */
type = TREE_TYPE (decl);
toplev = toplevel_bindings_p ();
- push_obstacks_nochange ();
- if (TREE_STATIC (decl)
- && TYPE_NEEDS_DESTRUCTOR (type)
- && allocation_temporary_p ())
- end_temporary_allocation ();
- if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
+ /* Handle non-variables up front. */
+ if (TREE_CODE (decl) != VAR_DECL)
+ {
+ rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+ return;
+ }
+
+ /* Set the DECL_ASSEMBLER_NAME for the variable. */
+ if (asmspec)
+ DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
+
+ if (DECL_VIRTUAL_P (decl))
make_decl_rtl (decl, NULL_PTR, toplev);
- else if (TREE_CODE (decl) == VAR_DECL
- && TREE_READONLY (decl)
+ else if (TREE_READONLY (decl)
&& DECL_INITIAL (decl) != NULL_TREE
&& DECL_INITIAL (decl) != error_mark_node
&& ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
{
DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
- if (asmspec)
- DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
-
- if (! toplev
- && TREE_STATIC (decl)
- && ! TREE_SIDE_EFFECTS (decl)
- && ! TREE_PUBLIC (decl)
- && ! DECL_EXTERNAL (decl)
- && ! TYPE_NEEDS_DESTRUCTOR (type)
- && DECL_MODE (decl) != BLKmode)
- {
- /* If this variable is really a constant, then fill its DECL_RTL
- slot with something which won't take up storage.
- If something later should take its address, we can always give
- it legitimate RTL at that time. */
- DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
- store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
- TREE_ASM_WRITTEN (decl) = 1;
- }
- else if (toplev && ! TREE_PUBLIC (decl))
+ if (toplev && ! TREE_PUBLIC (decl))
{
/* If this is a static const, change its apparent linkage
if it belongs to a #pragma interface. */
}
make_decl_rtl (decl, asmspec, toplev);
}
- else
+ else if (toplev)
rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
}
- else if (TREE_CODE (decl) == VAR_DECL
- && DECL_LANG_SPECIFIC (decl)
- && DECL_IN_AGGR_P (decl))
+ else if (DECL_LANG_SPECIFIC (decl) && DECL_IN_AGGR_P (decl))
{
my_friendly_assert (TREE_STATIC (decl), 19990828);
else
rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
}
- else
+ else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL
+ || (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)))
rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+}
+
+/* Create RTL for the local static variable DECL. */
+
+void
+make_rtl_for_local_static (decl)
+ tree decl;
+{
+ tree type = TREE_TYPE (decl);
+ const char *asmspec = NULL;
+
+ /* If we inlined this variable, we could see it's declaration
+ again. */
+ if (DECL_RTL (decl))
+ return;
- pop_obstacks ();
+ if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
+ {
+ /* The only way this situaton can occur is if the
+ user specified a name for this DECL using the
+ `attribute' syntax. */
+ asmspec = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ DECL_ASSEMBLER_NAME (decl) = DECL_NAME (decl);
+ }
+
+ rest_of_decl_compilation (decl, asmspec, /*top_level=*/0, /*at_end=*/0);
}
/* The old ARM scoping rules injected variables declared in the
}
}
-/* Generate code to initialized DECL (a local variable). */
+/* Generate code to initialize DECL (a local variable). */
void
initialize_local_var (decl, init, flags)
tree init;
int flags;
{
- tree type;
- tree cleanup;
-
- type = TREE_TYPE (decl);
+ tree type = TREE_TYPE (decl);
- cleanup = build_cleanup_on_safe_obstack (decl);
+ /* If the type is bogus, don't bother initializing the variable. */
+ if (type == error_mark_node)
+ return;
if (DECL_SIZE (decl) == NULL_TREE && !TREE_STATIC (decl))
{
TREE_ADDRESSABLE (decl) = TREE_USED (decl);
}
- if (DECL_RTL (decl))
- /* Only a RESULT_DECL should have non-NULL RTL when arriving here.
- All other local variables are assigned RTL in this function. */
- my_friendly_assert (TREE_CODE (decl) == RESULT_DECL, 19990828);
- else
- /* Create RTL for this variable. */
- expand_decl (decl);
-
- expand_start_target_temps ();
+ /* Local statics are handled differently from ordinary automatic
+ variables. */
+ if (TREE_STATIC (decl))
+ {
+ if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
+ || TYPE_NEEDS_DESTRUCTOR (type))
+ expand_static_init (decl, init);
+ return;
+ }
if (DECL_SIZE (decl) && type != error_mark_node)
{
if (init || TYPE_NEEDS_CONSTRUCTING (type))
{
+ int saved_stmts_are_full_exprs_p;
+
emit_line_note (DECL_SOURCE_FILE (decl),
DECL_SOURCE_LINE (decl));
- /* We call push_momentary here so that when
- finish_expr_stmt clears the momentary obstack it
- doesn't destory any momentary expressions we may
- have lying around. Although cp_finish_decl is
- usually called at the end of a declaration
- statement, it may also be called for a temporary
- object in the middle of an expression. */
- push_momentary ();
+ saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p;
+ stmts_are_full_exprs_p = 1;
finish_expr_stmt (build_aggr_init (decl, init, flags));
- pop_momentary ();
+ stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
}
- else
- expand_decl_init (decl);
/* Set this to 0 so we can tell whether an aggregate which was
initialized was ever used. Don't do this if it has a
marked used. (see TREE_USED, above.) */
if (TYPE_NEEDS_CONSTRUCTING (type)
&& ! already_used
- && cleanup == NULL_TREE
+ && !TYPE_NEEDS_DESTRUCTOR (type)
&& DECL_NAME (decl))
TREE_USED (decl) = 0;
else if (already_used)
TREE_USED (decl) = 1;
}
+}
- /* Cleanup any temporaries needed for the initial value. */
- expand_end_target_temps ();
+/* Generate code to destroy DECL (a local variable). */
+
+static void
+destroy_local_var (decl)
+ tree decl;
+{
+ tree type = TREE_TYPE (decl);
+ tree cleanup;
+
+ /* Only variables get cleaned up. */
+ if (TREE_CODE (decl) != VAR_DECL)
+ return;
+
+ /* And only things with destructors need cleaning up. */
+ if (!TYPE_NEEDS_DESTRUCTOR (type))
+ return;
+
+ if (TREE_CODE (decl) == VAR_DECL &&
+ (DECL_EXTERNAL (decl) || TREE_STATIC (decl)))
+ /* We don't clean up things that aren't defined in this
+ translation unit, or that need a static cleanup. The latter
+ are handled by finish_file. */
+ return;
+
+ /* Compute the cleanup. */
+ cleanup = maybe_build_cleanup (decl);
/* Record the cleanup required for this declaration. */
- if (DECL_SIZE (decl)
- && type != error_mark_node
- && cleanup
- && !expand_decl_cleanup (decl, cleanup))
- cp_error ("parser lost in parsing declaration of `%D'", decl);
+ if (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node
+ && cleanup)
+ finish_decl_cleanup (decl, cleanup);
+}
+
+/* Let the back-end know about DECL. */
+
+void
+emit_local_var (decl)
+ tree decl;
+{
+ /* Create RTL for this variable. */
+ if (DECL_RTL (decl))
+ /* Only a RESULT_DECL should have non-NULL RTL when arriving here.
+ All other local variables are assigned RTL in this function. */
+ my_friendly_assert (TREE_CODE (decl) == RESULT_DECL,
+ 19990828);
+ else
+ {
+ if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
+ /* The user must have specified an assembler name for this
+ variable. Set that up now. */
+ rest_of_decl_compilation
+ (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ /*top_level=*/0, /*at_end=*/0);
+ else
+ expand_decl (decl);
+ }
+
+ /* Actually do the initialization. */
+ expand_start_target_temps ();
+ expand_decl_init (decl);
+ expand_end_target_temps ();
}
/* Finish processing of a declaration;
If the length of an array type is not known before,
it must be determined now, from the initial value, or it is an error.
- Call `pop_obstacks' iff NEED_POP is nonzero.
-
For C++, `cp_finish_decl' must be fairly evasive: it must keep initializers
for aggregates that have constructors alive on the permanent obstack,
so that the global initializing functions can be written at the end.
ambiguity as it goes. This can be sped up later. */
void
-cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
+cp_finish_decl (decl, init, asmspec_tree, flags)
tree decl, init;
tree asmspec_tree;
- int need_pop;
int flags;
{
register tree type;
tree ttype = NULL_TREE;
- int temporary = allocation_temporary_p ();
const char *asmspec = NULL;
int was_readonly = 0;
return;
}
+ /* Handling __FUNCTION__ and its ilk in a template-function requires
+ some special processing because we are called from
+ language-independent code. */
+ if (current_function && processing_template_decl
+ && current_function_name_declared == 2)
+ {
+ /* Since we're in a template function, we need to
+ push_template_decl. The language-independent code in
+ declare_hidden_char_array doesn't know to do this. */
+ retrofit_lang_decl (decl);
+ decl = push_template_decl (decl);
+
+ if (strcmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
+ "__PRETTY_FUNCTION__") == 0)
+ {
+ init = build (FUNCTION_NAME, const_string_type_node);
+ DECL_PRETTY_FUNCTION_P (decl) = 1;
+ }
+ }
+
/* If a name was specified, get the string. */
if (asmspec_tree)
asmspec = TREE_STRING_POINTER (asmspec_tree);
pop_decl_namespace ();
}
- type = complete_type (TREE_TYPE (decl));
+ type = TREE_TYPE (decl);
if (type == error_mark_node)
- {
- if (toplevel_bindings_p () && temporary)
- end_temporary_allocation ();
+ return;
- return;
- }
+ /* Add this declaration to the statement-tree. */
+ if (building_stmt_tree () && at_function_scope_p ())
+ add_decl_stmt (decl);
if (TYPE_HAS_MUTABLE_P (type))
TREE_READONLY (decl) = 0;
-
+
if (processing_template_decl)
{
if (init && DECL_INITIAL (decl))
- DECL_INITIAL (decl) = copy_to_permanent (init);
+ DECL_INITIAL (decl) = init;
goto finish_end0;
}
make_decl_rtl (decl, asmspec, 0);
}
- check_initializer (decl, &init);
-
- GNU_xref_decl (current_function_decl, decl);
-
- /* For top-level declaration, the initial value was read in
- the temporary obstack. MAXINDEX, rtl, etc. to be made below
- must go in the permanent obstack; but don't discard the
- temporary data yet. */
-
- if (toplevel_bindings_p () && temporary)
- end_temporary_allocation ();
-
/* Deduce size of array from initialization, if not already known. */
maybe_deduce_size_from_array_init (decl, init);
+ init = check_initializer (decl, init);
+
+ GNU_xref_decl (current_function_decl, decl);
if (TREE_CODE (decl) == VAR_DECL)
- layout_var_decl (decl, &init);
+ layout_var_decl (decl);
/* Output the assembler code and/or RTL code for variables and functions,
unless the type is an undefined structure or union.
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == RESULT_DECL)
{
- /* ??? FIXME: What about nested classes? */
- int toplev = toplevel_bindings_p ();
-
if (TREE_CODE (decl) == VAR_DECL)
maybe_commonize_var (decl);
if (init)
DECL_INITIAL (decl) = init;
}
+ else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL)
+ {
+ /* This is a local declaration. */
+ if (doing_semantic_analysis_p ())
+ maybe_inject_for_scope_var (decl);
+ /* Initialize the local variable. But, if we're building a
+ statement-tree, we'll do the initialization when we
+ expand the tree. */
+ if (processing_template_decl)
+ {
+ if (init || DECL_INITIAL (decl) == error_mark_node)
+ DECL_INITIAL (decl) = init;
+ }
+ else
+ {
+ /* If we're not building RTL, then we need to do so
+ now. */
+ if (!building_stmt_tree ())
+ emit_local_var (decl);
+ /* Initialize the variable. */
+ initialize_local_var (decl, init, flags);
+ /* Clean up the variable. */
+ destroy_local_var (decl);
+ }
+ }
else if (TREE_STATIC (decl) && type != error_mark_node)
{
/* Cleanups for static variables are handled by `finish_file'. */
|| TYPE_NEEDS_DESTRUCTOR (type))
expand_static_init (decl, init);
}
- else if (! toplev)
- {
- /* This is a local declaration. */
- maybe_inject_for_scope_var (decl);
- /* Initialize the local variable. But, if we're building a
- statement-tree, we'll do the initialization when we
- expand the tree. */
- if (!building_stmt_tree ())
- initialize_local_var (decl, init, flags);
- else if (init || DECL_INITIAL (decl) == error_mark_node)
- DECL_INITIAL (decl) = init;
- }
finish_end0:
/* Undo call to `pushclass' that was done in `start_decl'
}
}
- if (need_pop)
- /* Resume permanent allocation, if not within a function. The
- corresponding push_obstacks_nochange is in start_decl,
- start_method, groktypename, and in grokfield. */
- pop_obstacks ();
-
if (was_readonly)
TREE_READONLY (decl) = 1;
}
tree decl, init;
tree asmspec_tree;
{
- cp_finish_decl (decl, init, asmspec_tree, 1, 0);
+ cp_finish_decl (decl, init, asmspec_tree, 0);
+}
+
+/* Generate code to handle the destruction of the function-scoped
+ static variable DECL. */
+
+static void
+destroy_local_static (decl)
+ tree decl;
+{
+ tree cleanup, fcall;
+ tree compound_stmt;
+ int saved_flag_access_control;
+
+ if (atexit_node == 0)
+ {
+ tree atexit_fndecl, PFV, pfvlist;
+
+ PFV = build_pointer_type (build_function_type
+ (void_type_node, void_list_node));
+
+ pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
+
+ push_lang_context (lang_name_c);
+ /* Note that we do not call pushdecl for this function;
+ there's no reason that this declaration should be
+ accessible to anyone. */
+ atexit_fndecl
+ = define_function ("atexit",
+ build_function_type (void_type_node,
+ pfvlist),
+ /*pfn=*/0, NULL_PTR);
+ mark_used (atexit_fndecl);
+ atexit_node = default_conversion (atexit_fndecl);
+ pop_lang_context ();
+ }
+
+ /* Call build_cleanup before we enter the anonymous function so that
+ any access checks will be done relative to the current scope,
+ rather than the scope of the anonymous function. */
+ build_cleanup (decl);
+
+ /* Now start the function. */
+ cleanup = start_anon_func ();
+
+ /* Now, recompute the cleanup. It may contain SAVE_EXPRs that refer
+ to the original function, rather than the anonymous one. That
+ will make the back-end think that nested functions are in use,
+ which causes confusion. */
+ saved_flag_access_control = flag_access_control;
+ flag_access_control = 0;
+ fcall = build_cleanup (decl);
+ flag_access_control = saved_flag_access_control;
+
+ /* Create the body of the anonymous function. */
+ compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+ finish_expr_stmt (fcall);
+ finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+ end_anon_func ();
+
+ /* Call atexit with the cleanup function. */
+ mark_addressable (cleanup);
+ cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
+ fcall = build_function_call (atexit_node,
+ tree_cons (NULL_TREE,
+ cleanup,
+ NULL_TREE));
+ finish_expr_stmt (fcall);
}
void
/* Emit code to perform this initialization but once. */
tree temp;
tree if_stmt;
+ tree then_clause;
tree assignment;
tree temp_init;
- /* Remember this information until end of file. */
- push_obstacks (&permanent_obstack, &permanent_obstack);
-
/* Emit code to perform this initialization but once. This code
looks like:
finish_if_stmt_cond (build_binary_op (EQ_EXPR, temp,
integer_zero_node),
if_stmt);
+ then_clause = begin_compound_stmt (/*has_no_scope=*/0);
/* Do the initialization itself. */
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
/* Use atexit to register a function for destroying this static
variable. */
if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
- {
- tree cleanup, fcall;
- static tree Atexit = 0;
- int saved_flag_access_control;
-
- if (Atexit == 0)
- {
- tree atexit_fndecl, PFV, pfvlist;
-
- ggc_add_tree_root (&Atexit, 1);
-
- /* Remember this information until end of file. */
- push_obstacks (&permanent_obstack, &permanent_obstack);
- PFV = build_pointer_type (build_function_type
- (void_type_node, void_list_node));
-
- pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
-
- push_lang_context (lang_name_c);
- /* Note that we do not call pushdecl for this function;
- there's no reason that this declaration should be
- accessible to anyone. */
- atexit_fndecl
- = define_function ("atexit",
- build_function_type (void_type_node,
- pfvlist),
- NOT_BUILT_IN,
- /*pfn=*/0,
- NULL_PTR);
- mark_used (atexit_fndecl);
- Atexit = default_conversion (atexit_fndecl);
- pop_lang_context ();
- pop_obstacks ();
- }
-
- /* Call build_cleanup before we enter the anonymous function
- so that any access checks will be done relative to the
- current scope, rather than the scope of the anonymous
- function. */
- build_cleanup (decl);
-
- /* Now start the function. */
- cleanup = start_anon_func ();
-
- /* Now, recompute the cleanup. It may contain SAVE_EXPRs
- that refer to the original function, rather than the
- anonymous one. That will make the back-end think that
- nested functions are in use, which causes confusion. */
- saved_flag_access_control = flag_access_control;
- flag_access_control = 0;
- fcall = build_cleanup (decl);
- flag_access_control = saved_flag_access_control;
-
- /* Finish off the function. */
- expand_expr_stmt (fcall);
- end_anon_func ();
-
- /* Call atexit with the cleanup function. */
- mark_addressable (cleanup);
- cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
- fcall = build_function_call (Atexit,
- expr_tree_cons (NULL_TREE,
- cleanup,
- NULL_TREE));
- finish_expr_stmt (fcall);
- }
+ destroy_local_static (decl);
+ finish_compound_stmt (/*has_no_scope=*/0, then_clause);
finish_then_clause (if_stmt);
finish_if_stmt ();
-
- /* Resume old (possibly temporary) allocation. */
- pop_obstacks ();
}
else
{
currently in the temporary obstack. */
if (!TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
preserve_initializer ();
- static_aggregates = perm_tree_cons (init, decl, static_aggregates);
+ static_aggregates = tree_cons (init, decl, static_aggregates);
}
}
/* Finish the declaration of a catch-parameter. */
-void
+tree
start_handler_parms (declspecs, declarator)
tree declspecs;
tree declarator;
}
else
decl = NULL_TREE;
- expand_start_catch_block (decl);
+
+ return decl;
}
\f
register tree maxindex = NULL_TREE;
int value = 0;
- /* Allocate on the same obstack as TYPE. */
- push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
-
if (initial_value)
{
/* Note MAXINDEX is really the maximum index,
TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)) = domain;
}
- pop_obstacks();
-
/* Lay out the type now that we can get the real answer. */
layout_type (type);
the information in the TEMPLATE_ID_EXPR. */
SET_DECL_IMPLICIT_INSTANTIATION (decl);
DECL_TEMPLATE_INFO (decl)
- = perm_tree_cons (TREE_OPERAND (orig_declarator, 0),
- TREE_OPERAND (orig_declarator, 1),
- NULL_TREE);
+ = tree_cons (TREE_OPERAND (orig_declarator, 0),
+ TREE_OPERAND (orig_declarator, 1),
+ NULL_TREE);
if (has_default_arg)
{
if (check < 0)
return decl;
- if (check && funcdef_flag)
- DECL_INITIAL (decl) = error_mark_node;
-
if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator)
{
tree tmp;
context = NULL_TREE;
if (processing_template_decl)
- {
- /* If we're in a template, we need DECL_LANG_SPECIFIC so that
- we can call push_template_decl. */
- push_permanent_obstack ();
- decl = build_lang_decl (VAR_DECL, declarator,
- complete_type (type));
- pop_obstacks ();
- }
+ /* If we're in a template, we need DECL_LANG_SPECIFIC so that
+ we can call push_template_decl. */
+ decl = build_lang_decl (VAR_DECL, declarator, type);
else
- decl = build_decl (VAR_DECL, declarator, complete_type (type));
+ decl = build_decl (VAR_DECL, declarator, type);
if (context)
set_decl_namespace (decl, context, 0);
unqualified_variant
= build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type));
- push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
-
u = make_lang_type (UNION_TYPE);
SET_IS_AGGR_TYPE (u, 0);
fields[0] = build_lang_decl (FIELD_DECL, pfn_identifier, type);
fields[2] = build_lang_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node);
- pop_obstacks ();
-
/* Zap out the name so that the back-end will give us the debugging
information for this anonymous RECORD_TYPE. */
TYPE_NAME (t) = NULL_TREE;
return 0;
}
+/* Given the SIZE (i.e., number of elements) in an array, compute an
+ appropriate index type for the array. If non-NULL, NAME is the
+ name of the thing being declared. */
+
+tree
+compute_array_index_type (name, size)
+ tree name;
+ tree size;
+{
+ tree itype;
+
+ /* The size might be the result of a cast. */
+ STRIP_TYPE_NOPS (size);
+
+ /* It might be a const variable or enumeration constant. */
+ if (TREE_READONLY_DECL_P (size))
+ size = decl_constant_value (size);
+
+ /* If this involves a template parameter, it will be a constant at
+ instantiation time, but we don't know what the value is yet.
+ Even if no template parameters are involved, we may an expression
+ that is not a constant; we don't even simplify `1 + 2' when
+ processing a template. */
+ if (processing_template_decl)
+ {
+ /* Resolve a qualified reference to an enumerator or static
+ const data member of ours. */
+ if (TREE_CODE (size) == SCOPE_REF
+ && TREE_OPERAND (size, 0) == current_class_type)
+ {
+ tree t = lookup_field (current_class_type,
+ TREE_OPERAND (size, 1), 0, 0);
+ if (t)
+ size = t;
+ }
+
+ return build_index_type (build_min (MINUS_EXPR, sizetype,
+ size, integer_one_node));
+ }
+
+ /* The array bound must be an integer type. */
+ if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE
+ && TREE_CODE (TREE_TYPE (size)) != BOOLEAN_TYPE)
+ {
+ cp_error ("size of array `%D' has non-integer type", name);
+ size = integer_one_node;
+ }
+
+ /* Normally, the array-bound will be a constant. */
+ if (TREE_CONSTANT (size))
+ {
+ /* Check to see if the array bound overflowed. Make that an
+ error, no matter how generous we're being. */
+ int old_flag_pedantic_errors = flag_pedantic_errors;
+ int old_pedantic = pedantic;
+ pedantic = flag_pedantic_errors = 1;
+ constant_expression_warning (size);
+ pedantic = old_pedantic;
+ flag_pedantic_errors = old_flag_pedantic_errors;
+
+ /* An array must have a positive number of elements. */
+ if (INT_CST_LT (size, integer_zero_node))
+ {
+ cp_error ("size of array `%D' is negative", name);
+ size = integer_one_node;
+ }
+ /* Except that an extension we allow zero-sized arrays. We
+ always allow them in system headers because glibc uses
+ them. */
+ else if (integer_zerop (size) && pedantic && !in_system_header)
+ cp_pedwarn ("ANSI C++ forbids zero-size array `%D'", name);
+ }
+
+ /* Compute the index of the largest element in the array. It is
+ one less than the number of elements in the array. */
+ itype
+ = fold (build_binary_op (MINUS_EXPR,
+ cp_convert (ssizetype, size),
+ cp_convert (ssizetype,
+ integer_one_node)));
+
+ /* Check for variable-sized arrays. We allow such things as an
+ extension, even though they are not allowed in ANSI/ISO C++. */
+ if (!TREE_CONSTANT (itype))
+ {
+ if (pedantic)
+ {
+ if (name)
+ cp_pedwarn ("ANSI C++ forbids variable-size array `%D'",
+ name);
+ else
+ cp_pedwarn ("ANSI C++ forbids variable-size array");
+ }
+
+ /* Create a variable-sized array index type. */
+ itype = variable_size (itype);
+ }
+ /* Make sure that there was no overflow when creating to a signed
+ index type. (For example, on a 32-bit machine, an array with
+ size 2^32 - 1 is too big.) */
+ else if (TREE_OVERFLOW (itype))
+ {
+ error ("overflow in array dimension");
+ TREE_OVERFLOW (itype) = 0;
+ }
+
+ /* Create and return the appropriate index type. */
+ return build_index_type (itype);
+}
+
+/* Returns an ARRAY_TYPE for an array with SIZE elements of the
+ indicated TYPE. If non-NULL, NAME is the NAME of the declaration
+ with this type. */
+
+static tree
+create_array_type_for_decl (name, type, size)
+ tree name;
+ tree type;
+ tree size;
+{
+ tree itype = NULL_TREE;
+ const char* error_msg;
+
+ /* If things have already gone awry, bail now. */
+ if (type == error_mark_node || size == error_mark_node)
+ return error_mark_node;
+
+ /* Assume that everything will go OK. */
+ error_msg = NULL;
+
+ /* There are some types which cannot be array elements. */
+ switch (TREE_CODE (type))
+ {
+ case VOID_TYPE:
+ error_msg = "array of void";
+ break;
+
+ case FUNCTION_TYPE:
+ error_msg = "array of functions";
+ break;
+
+ case REFERENCE_TYPE:
+ error_msg = "array of references";
+ break;
+
+ case OFFSET_TYPE:
+ error_msg = "array of data members";
+ break;
+
+ case METHOD_TYPE:
+ error_msg = "array of function members";
+ break;
+
+ default:
+ break;
+ }
+
+ /* If something went wrong, issue an error-message and return. */
+ if (error_msg)
+ {
+ if (name)
+ cp_error ("declaration of `%D' as %s", name, error_msg);
+ else
+ cp_error ("creating %s", error_msg);
+
+ return error_mark_node;
+ }
+
+ /* [dcl.array]
+
+ The constant expressions that specify the bounds of the arrays
+ can be omitted only for the first member of the sequence. */
+ if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type))
+ {
+ cp_error ("declaration of `%D' as multidimensional array",
+ name);
+ cp_error ("must have bounds for all dimensions except the first");
+
+ return error_mark_node;
+ }
+
+ /* Figure out the index type for the array. */
+ if (size)
+ itype = compute_array_index_type (name, size);
+
+ return build_cplus_array_type (type, itype);
+}
+
/* Given declspecs and a declarator,
determine the name and type of the object declared
and construct a ..._DECL node for it.
is erroneous, NULL_TREE is returned.
QUALS is used only for FUNCDEF and MEMFUNCDEF cases. For a member
- function, these are the qualifiers to give to the `this' pointer.
+ function, these are the qualifiers to give to the `this' pointer. We
+ apply TYPE_QUAL_RESTRICT to the this ptr, not the object.
May return void_type_node if the declarator turned out to be a friend.
See grokfield for details. */
return 0; /* We used to do a 155 abort here. */
}
}
- if (name == NULL)
- name = "type name";
}
/* A function definition's declarator must have the form of
current_binding_level = b;
}
+ if (name == NULL)
+ name = decl_context == PARM ? "parameter" : "type name";
+
/* Look through the decl specs and record which ones appear.
Some typespecs are defined as built-in typenames.
Others, the ones that are modifiers of other types,
if (in_system_header || flag_ms_extensions)
/* Allow it, sigh. */;
else if (pedantic || ! is_main)
- cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type",
- dname);
+ cp_pedwarn ("ANSI C++ forbids declaration of `%s' with no type",
+ name);
else if (warn_return_type)
- cp_warning ("ANSI C++ forbids declaration `%D' with no type",
- dname);
+ cp_warning ("ANSI C++ forbids declaration of `%s' with no type",
+ name);
type = integer_type_node;
}
friendp = RIDBIT_SETP (RID_FRIEND, specbits);
RIDBIT_RESET (RID_FRIEND, specbits);
- /* $7.1.2, Function specifiers */
- if (friendp && explicitp)
- error ("only declarations of constructors can be `explicit'");
-
- if (RIDBIT_SETP (RID_MUTABLE, specbits))
- {
- if (decl_context == PARM)
- {
- error ("non-member `%s' cannot be declared `mutable'", name);
- RIDBIT_RESET (RID_MUTABLE, specbits);
- }
- else if (friendp || decl_context == TYPENAME)
- {
- error ("non-object member `%s' cannot be declared `mutable'", name);
- RIDBIT_RESET (RID_MUTABLE, specbits);
- }
- }
-
/* Warn if two storage classes are given. Default to `auto'. */
if (RIDBIT_ANY_SET (specbits))
error ("virtual outside class declaration");
virtualp = 0;
}
- if (current_class_name == NULL_TREE && RIDBIT_SETP (RID_MUTABLE, specbits))
- {
- error ("only members can be declared mutable");
- RIDBIT_RESET (RID_MUTABLE, specbits);
- }
/* Static anonymous unions are dealt with here. */
if (staticp && decl_context == TYPENAME
op ? operator_name_string (tmp) : name);
}
else
- error (((decl_context == PARM || decl_context == CATCHPARM)
- ? "storage class specified for parameter `%s'"
- : "storage class specified for typename"), name);
+ {
+ if (decl_context == PARM || decl_context == CATCHPARM)
+ error ("storage class specified for parameter `%s'", name);
+ else
+ error ("storage class specified for typename");
+ }
RIDBIT_RESET (RID_REGISTER, specbits);
RIDBIT_RESET (RID_AUTO, specbits);
RIDBIT_RESET (RID_EXTERN, specbits);
if (ctype != NULL_TREE)
{
tree dummy = build_decl (TYPE_DECL, NULL_TREE, type);
- ctype = grok_method_quals (ctype, dummy, quals);
+ grok_method_quals (ctype, dummy, quals);
type = TREE_TYPE (dummy);
+ ctype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)));
quals = NULL_TREE;
}
}
case ARRAY_REF:
{
- register tree itype = NULL_TREE;
- register tree size = TREE_OPERAND (declarator, 1);
- /* The index is a signed object `sizetype' bits wide. */
- tree index_type = signed_type (sizetype);
-
- declarator = TREE_OPERAND (declarator, 0);
-
- /* Check for some types that there cannot be arrays of. */
-
- if (TREE_CODE (type) == VOID_TYPE)
- {
- cp_error ("declaration of `%D' as array of voids", dname);
- type = error_mark_node;
- }
-
- if (TREE_CODE (type) == FUNCTION_TYPE)
- {
- cp_error ("declaration of `%D' as array of functions", dname);
- type = error_mark_node;
- }
-
- /* ARM $8.4.3: Since you can't have a pointer to a reference,
- you can't have arrays of references. If we allowed them,
- then we'd be saying x[i] is valid for an array x, but
- then you'd have to ask: what does `*(x + i)' mean? */
- if (TREE_CODE (type) == REFERENCE_TYPE)
- {
- if (decl_context == TYPENAME)
- cp_error ("cannot make arrays of references");
- else
- cp_error ("declaration of `%D' as array of references",
- dname);
- type = error_mark_node;
- }
-
- if (TREE_CODE (type) == OFFSET_TYPE)
- {
- cp_error ("declaration of `%D' as array of data members",
- dname);
- type = error_mark_node;
- }
-
- if (TREE_CODE (type) == METHOD_TYPE)
- {
- cp_error ("declaration of `%D' as array of function members",
- dname);
- type = error_mark_node;
- }
-
- if (size == error_mark_node)
- type = error_mark_node;
- else if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type))
- {
- /* [dcl.array]
-
- the constant expressions that specify the bounds of
- the arrays can be omitted only for the first member
- of the sequence. */
- cp_error ("declaration of `%D' as multidimensional array",
- dname);
- cp_error ("must have bounds for all dimensions except the first");
- type = error_mark_node;
- }
+ register tree size;
- if (type == error_mark_node)
- continue;
+ size = TREE_OPERAND (declarator, 1);
/* VC++ spells a zero-sized array with []. */
if (size == NULL_TREE && decl_context == FIELD && ! staticp
&& ! RIDBIT_SETP (RID_TYPEDEF, specbits))
size = integer_zero_node;
- if (size)
- {
- /* Must suspend_momentary here because the index
- type may need to live until the end of the function.
- For example, it is used in the declaration of a
- variable which requires destructing at the end of
- the function; then build_vec_delete will need this
- value. */
- int yes = suspend_momentary ();
- /* Might be a cast. */
- if (TREE_CODE (size) == NOP_EXPR
- && TREE_TYPE (size) == TREE_TYPE (TREE_OPERAND (size, 0)))
- size = TREE_OPERAND (size, 0);
- if (TREE_READONLY_DECL_P (size))
- size = decl_constant_value (size);
-
- /* If this involves a template parameter, it will be a
- constant at instantiation time, but we don't know
- what the value is yet. Even if no template
- parameters are involved, we may an expression that
- is not a constant; we don't even simplify `1 + 2'
- when processing a template. */
- if (processing_template_decl)
- {
- /* Resolve a qualified reference to an enumerator or
- static const data member of ours. */
- if (TREE_CODE (size) == SCOPE_REF
- && TREE_OPERAND (size, 0) == current_class_type)
- {
- tree t = lookup_field (current_class_type,
- TREE_OPERAND (size, 1), 0, 0);
- if (t)
- size = t;
- }
-
- itype = build_index_type (build_min
- (MINUS_EXPR, sizetype, size, integer_one_node));
- goto dont_grok_size;
- }
-
- if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE
- && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE
- && TREE_CODE (TREE_TYPE (size)) != BOOLEAN_TYPE)
- {
- cp_error ("size of array `%D' has non-integer type",
- dname);
- size = integer_one_node;
- }
- if (pedantic && integer_zerop (size))
- cp_pedwarn ("ANSI C++ forbids zero-size array `%D'", dname);
- if (TREE_CONSTANT (size))
- {
- int old_flag_pedantic_errors = flag_pedantic_errors;
- int old_pedantic = pedantic;
- pedantic = flag_pedantic_errors = 1;
- /* Always give overflow errors on array subscripts. */
- constant_expression_warning (size);
- pedantic = old_pedantic;
- flag_pedantic_errors = old_flag_pedantic_errors;
- if (INT_CST_LT (size, integer_zero_node))
- {
- cp_error ("size of array `%D' is negative", dname);
- size = integer_one_node;
- }
- }
- else
- {
- if (pedantic)
- {
- if (dname)
- cp_pedwarn ("ANSI C++ forbids variable-size array `%D'",
- dname);
- else
- cp_pedwarn ("ANSI C++ forbids variable-size array");
- }
- }
-
- itype
- = fold (build_binary_op (MINUS_EXPR,
- cp_convert (index_type, size),
- cp_convert (index_type,
- integer_one_node)));
- if (! TREE_CONSTANT (itype))
- itype = variable_size (itype);
- else if (TREE_OVERFLOW (itype))
- {
- error ("overflow in array dimension");
- TREE_OVERFLOW (itype) = 0;
- }
-
- /* If we're a parm, we need to have a permanent type so
- mangling checks for re-use will work right. If both the
- element and index types are permanent, the array type
- will be, too. */
- if (decl_context == PARM
- && allocation_temporary_p () && TREE_PERMANENT (type))
- {
- push_obstacks (&permanent_obstack, &permanent_obstack);
- itype = build_index_type (itype);
- pop_obstacks ();
- }
- else
- itype = build_index_type (itype);
-
- dont_grok_size:
- resume_momentary (yes);
- }
+ declarator = TREE_OPERAND (declarator, 0);
- type = build_cplus_array_type (type, itype);
+ type = create_array_type_for_decl (dname, type, size);
ctype = NULL_TREE;
}
break;
/* Now TYPE has the actual type. */
- if (explicitp == 1)
+ if (explicitp == 1 || (explicitp && friendp))
{
- error ("only constructors can be declared `explicit'");
+ /* [dcl.fct.spec] The explicit specifier shall only be used in
+ declarations of constructors within a class definition. */
+ error ("only declarations of constructors can be `explicit'");
explicitp = 0;
}
if (RIDBIT_SETP (RID_MUTABLE, specbits))
{
- if (type_quals & TYPE_QUAL_CONST)
+ if (current_class_name == NULL_TREE || decl_context == PARM || friendp)
+ {
+ error ("non-member `%s' cannot be declared `mutable'", name);
+ RIDBIT_RESET (RID_MUTABLE, specbits);
+ }
+ else if (decl_context == TYPENAME || RIDBIT_SETP (RID_TYPEDEF, specbits))
{
- error ("const `%s' cannot be declared `mutable'", name);
+ error ("non-object member `%s' cannot be declared `mutable'", name);
RIDBIT_RESET (RID_MUTABLE, specbits);
}
+ else if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ {
+ error ("function `%s' cannot be declared `mutable'", name);
+ RIDBIT_RESET (RID_MUTABLE, specbits);
+ }
else if (staticp)
{
error ("static `%s' cannot be declared `mutable'", name);
RIDBIT_RESET (RID_MUTABLE, specbits);
}
+ else if (type_quals & TYPE_QUAL_CONST)
+ {
+ error ("const `%s' cannot be declared `mutable'", name);
+ RIDBIT_RESET (RID_MUTABLE, specbits);
+ }
}
if (declarator == NULL_TREE
{
/* Make sure this typedef lives as long as its type,
since it might be used as a template parameter. */
- if (type != error_mark_node)
- push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
if (processing_template_decl)
decl = build_lang_decl (TYPE_DECL, declarator, type);
else
decl = build_decl (TYPE_DECL, declarator, type);
- if (type != error_mark_node)
- pop_obstacks ();
}
/* If the user declares "typedef struct {...} foo" then the
|| (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
- if (RIDBIT_SETP (RID_MUTABLE, specbits))
- error ("non-object member `%s' cannot be declared mutable", name);
-
bad_specifiers (decl, "type", virtualp, quals != NULL_TREE,
inlinep, friendp, raises != NULL_TREE);
}
}
- if (RIDBIT_SETP (RID_MUTABLE, specbits))
- {
- error ("`%s' cannot be declared mutable", name);
- }
+ my_friendly_assert (!RIDBIT_SETP (RID_MUTABLE, specbits), 19990927);
/* Record `register' declaration for warnings on &
and in case doing stupid register allocation. */
}
}
-/* Returns DECL if DECL is a local variable (or parameter). Returns
- NULL_TREE otherwise. */
+/* Returns non-zero if T is a local variable. */
-static tree
+int
local_variable_p (t)
tree t;
{
member. */
&& !TYPE_P (CP_DECL_CONTEXT (t))
/* Any other non-local variable must be at namespace scope. */
- && TREE_CODE (CP_DECL_CONTEXT (t)) != NAMESPACE_DECL)
+ && !DECL_NAMESPACE_SCOPE_P (t))
|| (TREE_CODE (t) == PARM_DECL))
- return t;
+ return 1;
- return NULL_TREE;
+ return 0;
+}
+
+/* Returns non-zero if T is an automatic local variable or a label.
+ (These are the declarations that need to be remapped when the code
+ containing them is duplicated.) */
+
+int
+nonstatic_local_decl_p (t)
+ tree t;
+{
+ return ((local_variable_p (t) && !TREE_STATIC (t))
+ || TREE_CODE (t) == LABEL_DECL
+ || TREE_CODE (t) == RESULT_DECL);
+}
+
+/* Like local_variable_p, but suitable for use as a tree-walking
+ function. */
+
+static tree
+local_variable_p_walkfn (tp, walk_subtrees, data)
+ tree *tp;
+ int *walk_subtrees ATTRIBUTE_UNUSED;
+ void *data ATTRIBUTE_UNUSED;
+{
+ return ((local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp))
+ ? *tp : NULL_TREE);
}
/* Check that ARG, which is a default-argument expression for a
The keyword `this' shall not be used in a default argument of a
member function. */
- var = search_tree (arg, local_variable_p);
+ var = walk_tree (&arg, local_variable_p_walkfn, NULL);
if (var)
{
cp_error ("default argument `%E' uses local variable `%D'",
TREE_CHAIN (last_decl) = decl;
last_decl = decl;
}
- if (! current_function_decl && TREE_PERMANENT (list_node))
- {
- TREE_PURPOSE (list_node) = init;
- TREE_VALUE (list_node) = type;
- TREE_CHAIN (list_node) = NULL_TREE;
- }
- else
- list_node = saveable_tree_cons (init, type, NULL_TREE);
+ list_node = tree_cons (init, type, NULL_TREE);
if (result == NULL_TREE)
{
result = list_node;
{
enum tag_types tag_code;
enum tree_code code;
- int temp = 0;
register tree ref, t;
struct binding_level *b = current_binding_level;
int got_type = 0;
}
}
- push_obstacks_nochange ();
-
if (! ref)
{
/* If no such tag is yet defined, create a forward-reference node
and record it as the "definition".
When a real declaration of this type is found,
the forward-reference will be altered into a real type. */
-
- /* In C++, since these migrate into the global scope, we must
- build them on the permanent obstack. */
-
- temp = allocation_temporary_p ();
- if (temp)
- end_temporary_allocation ();
-
if (code == ENUMERAL_TYPE)
{
cp_error ("use of enum `%#D' without previous declaration", name);
in global scope.
If it is not an IDENTIFIER, this is not a declaration */
if (b->namespace_p && !class_binding_level
- && TREE_CODE (name) == IDENTIFIER_NODE)
- {
- if (IDENTIFIER_NAMESPACE_VALUE (name) == NULL_TREE)
- SET_IDENTIFIER_NAMESPACE_VALUE (name, TYPE_NAME (ref));
- }
+ && TREE_CODE (name) == IDENTIFIER_NODE
+ && IDENTIFIER_NAMESPACE_VALUE (name) == NULL_TREE)
+ SET_IDENTIFIER_NAMESPACE_VALUE (name, TYPE_NAME (ref));
if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref))
redeclare_class_template (ref, current_template_parms);
CLASSTYPE_DECLARED_CLASS (ref) = 0;
}
- pop_obstacks ();
-
TREE_TYPE (ref) = attributes;
return ref;
}
len = list_length (binfo);
- push_obstacks (TYPE_OBSTACK (ref), TYPE_OBSTACK (ref));
/* First, make sure that any templates in base-classes are
instantiated. This ensures that if we call ourselves recursively
/* Now that we know all the base-classes, set up the list of virtual
bases. */
CLASSTYPE_VBASECLASSES (ref) = get_vbase_types (ref);
-
- pop_obstacks ();
}
\f
register tree enumtype = NULL_TREE;
struct binding_level *b = current_binding_level;
- /* We are wasting space here and putting these on the permanent_obstack so
- that typeid(local enum) will work correctly. */
- push_obstacks (&permanent_obstack, &permanent_obstack);
-
/* If this is the real definition for a previous forward reference,
fill in the contents in the same object that used to be the
forward reference. */
{
cp_error ("multiple definition of `%#T'", enumtype);
cp_error_at ("previous definition here", enumtype);
+ /* Clear out TYPE_VALUES, and start again. */
+ TYPE_VALUES (enumtype) = NULL_TREE;
}
else
{
if (current_class_type)
TREE_ADDRESSABLE (b->tags) = 1;
- /* We don't copy this value because build_enumerator needs to do it. */
- enum_next_value = integer_zero_node;
- enum_overflow = 0;
-
GNU_xref_decl (current_function_decl, enumtype);
return enumtype;
}
constant. */
decl = TREE_VALUE (pair);
+ /* [dcl.enum]
+
+ Following the closing brace of an enum-specifier, each
+ enumerator has the type of its enumeration. Prior to the
+ closing brace, the type of each enumerator is the type of
+ its initializing value. */
+ TREE_TYPE (decl) = enumtype;
+
/* The DECL_INITIAL will be NULL if we are processing a
template declaration and this enumeration constant had no
explicit initializer. */
rest_of_type_compilation (enumtype, namespace_bindings_p ());
}
- /* In start_enum we pushed obstacks. Here, we must pop them. */
- pop_obstacks ();
-
return enumtype;
}
/* Build and install a CONST_DECL for an enumeration constant of the
- enumeration type TYPE whose NAME and VALUE (if any) are provided.
+ enumeration type ENUMTYPE whose NAME and VALUE (if any) are provided.
Assignment of sequential values by default is handled here. */
-tree
-build_enumerator (name, value, type)
+void
+build_enumerator (name, value, enumtype)
tree name;
tree value;
- tree type;
+ tree enumtype;
{
- tree decl, result;
+ tree decl;
tree context;
+ tree type;
+ tree values;
/* Remove no-op casts from the value. */
if (value)
STRIP_TYPE_NOPS (value);
- if (! processing_template_decl)
- {
- /* Validate and default VALUE. */
- if (value != NULL_TREE)
- {
- if (TREE_READONLY_DECL_P (value))
- value = decl_constant_value (value);
-
- if (TREE_CODE (value) == INTEGER_CST)
- {
- value = default_conversion (value);
- constant_expression_warning (value);
- }
- else
- {
- cp_error ("enumerator value for `%D' not integer constant", name);
- value = NULL_TREE;
- }
- }
-
- /* Default based on previous value. */
- if (value == NULL_TREE && ! processing_template_decl)
- {
- value = enum_next_value;
- if (enum_overflow)
- cp_error ("overflow in enumeration values at `%D'", name);
- }
-
- /* Remove no-op casts from the value. */
- if (value)
- STRIP_TYPE_NOPS (value);
+ if (! processing_template_decl)
+ {
+ /* Validate and default VALUE. */
+ if (value != NULL_TREE)
+ {
+ if (TREE_READONLY_DECL_P (value))
+ value = decl_constant_value (value);
+
+ if (TREE_CODE (value) == INTEGER_CST)
+ {
+ value = default_conversion (value);
+ constant_expression_warning (value);
+ }
+ else
+ {
+ cp_error ("enumerator value for `%D' not integer constant", name);
+ value = NULL_TREE;
+ }
+ }
+
+ /* Default based on previous value. */
+ if (value == NULL_TREE && ! processing_template_decl)
+ {
+ tree prev_value;
+
+ if (TYPE_VALUES (enumtype))
+ {
+ /* The next value is the previous value ... */
+ prev_value = DECL_INITIAL (TREE_VALUE (TYPE_VALUES (enumtype)));
+ /* ... plus one. */
+ value = build_binary_op_nodefault (PLUS_EXPR,
+ prev_value,
+ integer_one_node,
+ PLUS_EXPR);
+
+ if (tree_int_cst_lt (value, prev_value))
+ cp_error ("overflow in enumeration values at `%D'", name);
+ }
+ else
+ value = integer_zero_node;
+ }
+
+ /* Remove no-op casts from the value. */
+ if (value)
+ STRIP_TYPE_NOPS (value);
#if 0
- /* To fix MAX_VAL enum consts. (bkoz) */
- TREE_TYPE (value) = integer_type_node;
+ /* To fix MAX_VAL enum consts. (bkoz) */
+ TREE_TYPE (value) = integer_type_node;
#endif
- }
+ }
- /* We always have to copy here; not all INTEGER_CSTs are unshared.
- Even in other cases, we will later (in finish_enum) be setting the
- type of VALUE. */
- if (value != NULL_TREE)
- value = copy_node (value);
+ /* We always have to copy here; not all INTEGER_CSTs are unshared.
+ Even in other cases, we will later (in finish_enum) be setting
+ the type of VALUE. But, we don't need to make a copy if this
+ VALUE is one of the enumeration constants for this same
+ enumeration type. */
+ for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values))
+ if (TREE_VALUE (values) == value)
+ break;
+ /* If we didn't break out of the loop, then we do need a copy. */
+ if (!values && value)
+ value = copy_node (value);
/* C++ associates enums with global, function, or class declarations. */
-
- context = current_scope ();
- if (context && context == current_class_type)
- /* This enum declaration is local to the class. */
- decl = build_lang_decl (CONST_DECL, name, type);
- else
- /* It's a global enum, or it's local to a function. (Note local to
+ context = current_scope ();
+
+ /* Build the actual enumeration constant. Note that the enumeration
+ constants have the type of their initializers until the
+ enumeration is complete:
+
+ [ dcl.enum ]
+
+ Following the closing brace of an enum-specifier, each enumer-
+ ator has the type of its enumeration. Prior to the closing
+ brace, the type of each enumerator is the type of its
+ initializing value.
+
+ In finish_enum we will reset the type. Of course, if we're
+ processing a template, there may be no value. */
+ type = value ? TREE_TYPE (value) : NULL_TREE;
+
+ if (context && context == current_class_type)
+ /* This enum declaration is local to the class. We need the full
+ lang_decl so that we can record DECL_CLASS_CONTEXT, for example. */
+ decl = build_lang_decl (CONST_DECL, name, type);
+ else
+ /* It's a global enum, or it's local to a function. (Note local to
a function could mean local to a class method. */
- decl = build_decl (CONST_DECL, name, type);
+ decl = build_decl (CONST_DECL, name, type);
- DECL_CONTEXT (decl) = FROB_CONTEXT (context);
- DECL_INITIAL (decl) = value;
- TREE_READONLY (decl) = 1;
+ DECL_CONTEXT (decl) = FROB_CONTEXT (context);
+ DECL_INITIAL (decl) = value;
+ TREE_READONLY (decl) = 1;
- if (context && context == current_class_type)
- /* In something like `struct S { enum E { i = 7 }; };' we put `i'
+ if (context && context == current_class_type)
+ /* In something like `struct S { enum E { i = 7 }; };' we put `i'
on the TYPE_FIELDS list for `S'. (That's so that you can say
things like `S::i' later.) */
- finish_member_declaration (decl);
- else
- {
- pushdecl (decl);
- GNU_xref_decl (current_function_decl, decl);
- }
-
- if (! processing_template_decl)
- {
- /* Set basis for default for next value. */
- enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value,
- integer_one_node, PLUS_EXPR);
- enum_overflow = tree_int_cst_lt (enum_next_value, value);
- }
-
- result = saveable_tree_cons (name, decl, NULL_TREE);
- return result;
+ finish_member_declaration (decl);
+ else
+ {
+ pushdecl (decl);
+ GNU_xref_decl (current_function_decl, decl);
+ }
+
+ /* Add this enumeration constant to the list for this type. */
+ TYPE_VALUES (enumtype) = tree_cons (name, decl, TYPE_VALUES (enumtype));
}
\f
static int function_depth;
-/* Create the FUNCTION_DECL for a function definition.
- DECLSPECS and DECLARATOR are the parts of the declaration;
- they describe the function's name and the type it returns,
- but twisted together in a fashion that parallels the syntax of C.
+/* We're defining DECL. Make sure that it's type is OK. */
- If PRE_PARSED_P is non-zero then DECLARATOR is really the DECL for
- the function we are about to process; DECLSPECS are ignored. For
- example, we set PRE_PARSED_P when processing the definition of
- inline function that was defined in-class; the definition is
- actually processed when the class is complete. In this case,
- PRE_PARSED_P is 2. We also set PRE_PARSED_P when instanting the
- body of a template function, and when constructing thunk functions
- and such; in these cases PRE_PARSED_P is 1.
-
+static void
+check_function_type (decl)
+ tree decl;
+{
+ tree fntype = TREE_TYPE (decl);
+
+ /* In a function definition, arg types must be complete. */
+ require_complete_types_for_parms (current_function_parms);
+
+ if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE)
+ {
+ cp_error ("return type `%#T' is incomplete", TREE_TYPE (fntype));
+
+ /* Make it return void instead, but don't change the
+ type of the DECL_RESULT, in case we have a named return value. */
+ if (TREE_CODE (fntype) == METHOD_TYPE)
+ {
+ tree ctype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype)));
+ TREE_TYPE (decl)
+ = build_cplus_method_type (ctype,
+ void_type_node,
+ FUNCTION_ARG_CHAIN (decl));
+ }
+ else
+ TREE_TYPE (decl)
+ = build_function_type (void_type_node,
+ TYPE_ARG_TYPES (TREE_TYPE (decl)));
+ TREE_TYPE (decl)
+ = build_exception_variant (fntype,
+ TYPE_RAISES_EXCEPTIONS (fntype));
+ }
+ else
+ abstract_virtuals_error (decl, TREE_TYPE (fntype));
+}
+
+/* Create the FUNCTION_DECL for a function definition.
+ DECLSPECS and DECLARATOR are the parts of the declaration;
+ they describe the function's name and the type it returns,
+ but twisted together in a fashion that parallels the syntax of C.
+
+ FLAGS is a bitwise or of SF_PRE_PARSED (indicating that the
+ DECLARATOR is really the DECL for the function we are about to
+ process and that DECLSPECS should be ignored), SF_INCLASS_INLINE
+ indicating that the function is an inline defined in-class, and
+ SF_EXPAND indicating that we should generate RTL for this
+ function.
+
This function creates a binding context for the function body
as well as setting up the FUNCTION_DECL in current_function_decl.
applied to it with the argument list [1, 2]. */
int
-start_function (declspecs, declarator, attrs, pre_parsed_p)
+start_function (declspecs, declarator, attrs, flags)
tree declspecs, declarator, attrs;
- int pre_parsed_p;
+ int flags;
{
tree decl1;
tree ctype = NULL_TREE;
extern int have_extern_spec;
extern int used_extern_spec;
int doing_friend = 0;
+ struct binding_level *bl;
/* Sanity check. */
my_friendly_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE, 160);
my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161);
- /* Assume, until we see it does. */
- current_function_returns_value = 0;
- current_function_returns_null = 0;
- named_labels = 0;
- current_function_assigns_this = 0;
- current_function_just_assigned_this = 0;
- current_function_parms_stored = 0;
- original_result_rtx = NULL_RTX;
- base_init_expr = NULL_TREE;
- current_base_init_list = NULL_TREE;
- current_member_init_list = NULL_TREE;
- ctor_label = dtor_label = NULL_TREE;
- static_labelno = 0;
- in_function_try_handler = 0;
-
- clear_temp_name ();
-
/* This should only be done once on the top most decl. */
if (have_extern_spec && !used_extern_spec)
{
used_extern_spec = 1;
}
- if (pre_parsed_p)
+ if (flags & SF_PRE_PARSED)
{
decl1 = declarator;
}
}
}
+
+ /* Sometimes we don't notice that a function is a static member, and
+ build a METHOD_TYPE for it. Fix that up now. */
+ if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)
+ && TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)
+ {
+ revert_static_member_fn (&decl1, NULL, NULL);
+ last_function_parms = TREE_CHAIN (last_function_parms);
+ ctype = NULL_TREE;
+ }
/* Warn if function was previously implicitly declared
(but not if we warned then). */
&& IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)) != NULL_TREE)
cp_warning_at ("`%D' implicitly declared before its definition", IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)));
- if (!building_stmt_tree ())
- announce_function (decl1);
-
/* Set up current_class_type, and enter the scope of the class, if
appropriate. */
if (ctype)
case where a template parameter has the same name as a field of
the class.) It is not until after this point that
PROCESSING_TEMPLATE_DECL is guaranteed to be set up correctly. */
- if (pre_parsed_p == 2)
+ if (flags & SF_INCLASS_INLINE)
maybe_begin_member_template_processing (decl1);
/* Effective C++ rule 15. See also c_expand_return. */
/* Make the init_value nonzero so pushdecl knows this is not tentative.
error_mark_node is replaced below (in poplevel) with the BLOCK. */
- DECL_INITIAL (decl1) = error_mark_node;
+ if (!DECL_INITIAL (decl1))
+ DECL_INITIAL (decl1) = error_mark_node;
#ifdef SET_DEFAULT_DECL_ATTRIBUTES
SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs);
current_function_parms = last_function_parms;
current_function_parm_tags = last_function_parm_tags;
+ /* Make sure the parameter and return types are reasonable. When
+ you declare a function, these types can be incomplete, but they
+ must be complete when you define the function. */
if (! processing_template_decl)
- {
- /* In a function definition, arg types must be complete. */
- require_complete_types_for_parms (current_function_parms);
+ check_function_type (decl1);
- if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE)
+ /* Build the return declaration for the function. */
+ restype = TREE_TYPE (fntype);
+ if (!processing_template_decl)
+ {
+ if (!DECL_RESULT (decl1))
{
- cp_error ("return-type `%#T' is an incomplete type",
- TREE_TYPE (fntype));
-
- /* Make it return void instead, but don't change the
- type of the DECL_RESULT, in case we have a named return value. */
- if (ctype)
- TREE_TYPE (decl1)
- = build_cplus_method_type (build_type_variant (ctype,
- TREE_READONLY (decl1),
- TREE_SIDE_EFFECTS (decl1)),
- void_type_node,
- FUNCTION_ARG_CHAIN (decl1));
- else
- TREE_TYPE (decl1)
- = build_function_type (void_type_node,
- TYPE_ARG_TYPES (TREE_TYPE (decl1)));
DECL_RESULT (decl1)
- = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (fntype)));
- TREE_READONLY (DECL_RESULT (decl1))
- = CP_TYPE_CONST_P (TREE_TYPE (fntype));
- TREE_THIS_VOLATILE (DECL_RESULT (decl1))
- = CP_TYPE_VOLATILE_P (TREE_TYPE (fntype));
+ = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype));
+ c_apply_type_quals_to_decl (CP_TYPE_QUALS (restype),
+ DECL_RESULT (decl1));
}
-
- abstract_virtuals_error (decl1, TREE_TYPE (fntype));
}
+ else
+ /* Just use `void'. Nobody will ever look at this anyhow. */
+ DECL_RESULT (decl1) = build_decl (RESULT_DECL, 0, void_type_node);
+
+ /* Initialize RTL machinery. We cannot do this until
+ CURRENT_FUNCTION_DECL and DECL_RESULT are set up. We do this
+ even when processing a template; this is how we get
+ CURRENT_FUNCTION set up, and our per-function variables
+ initialized. */
+ bl = current_binding_level;
+ init_function_start (decl1, input_filename, lineno);
+ current_binding_level = bl;
+ expanding_p = (flags & SF_EXPAND) != 0;
+
+ /* 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;
+ current_function->x_dont_save_pending_sizes_p = 1;
+
+ /* If we're building a statement-tree, start the tree now. */
+ if (processing_template_decl || !expanding_p)
+ begin_stmt_tree (&DECL_SAVED_TREE (decl1));
+
+ /* Let the user know we're compiling this function. */
+ if (processing_template_decl || !building_stmt_tree ())
+ announce_function (decl1);
/* Record the decl so that the function name is defined.
If we already have a decl for this name, and it is a FUNCTION_DECL,
use the old decl. */
- if (!processing_template_decl && pre_parsed_p == 0)
+ if (!processing_template_decl && !(flags & SF_PRE_PARSED))
{
/* A specialization is not used to guide overload resolution. */
if ((flag_guiding_decls
fntype = TREE_TYPE (decl1);
}
+ /* Reset these in case the call to pushdecl changed them. */
current_function_decl = decl1;
+ current_function->decl = decl1;
+
+ /* Initialize the per-function data. */
+ if (!DECL_PENDING_INLINE_P (decl1) && DECL_SAVED_FUNCTION_DATA (decl1))
+ {
+ /* If we already parsed this function, and we're just expanding it
+ now, restore saved state. */
+ struct binding_level *bl = current_binding_level;
+ *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (decl1);
+ current_binding_level = bl;
+
+ /* This function is being processed in whole-function mode; we
+ already did semantic analysis. */
+ current_function->x_whole_function_mode_p = 1;
+
+ /* If we decided that we didn't want to inline this function,
+ make sure the back-end knows that. */
+ if (!current_function_cannot_inline)
+ current_function_cannot_inline = cp_function_chain->cannot_inline;
+
+ /* We don't need the saved data anymore. */
+ free (DECL_SAVED_FUNCTION_DATA (decl1));
+ DECL_SAVED_FUNCTION_DATA (decl1) = NULL;
+ }
+ else if (ctype && !doing_friend && !DECL_STATIC_FUNCTION_P (decl1))
+ {
+ /* We know that this was set up by `grokclassfn'. We do not
+ wait until `store_parm_decls', since evil parse errors may
+ never get us to that point. Here we keep the consistency
+ between `current_class_type' and `current_class_ptr'. */
+ tree t = DECL_ARGUMENTS (decl1);
+
+ my_friendly_assert (t != NULL_TREE && TREE_CODE (t) == PARM_DECL,
+ 162);
+ my_friendly_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE,
+ 19990811);
+
+ cp_function_chain->x_current_class_ref
+ = build_indirect_ref (t, NULL_PTR);
+ cp_function_chain->x_current_class_ptr = t;
+
+ /* Constructors and destructors need to know whether they're "in
+ charge" of initializing virtual base classes. */
+ if (DECL_DESTRUCTOR_P (decl1))
+ current_in_charge_parm = TREE_CHAIN (t);
+ else if (DECL_CONSTRUCTOR_P (decl1)
+ && TREE_CHAIN (t)
+ && DECL_ARTIFICIAL (TREE_CHAIN (t))
+ && (DECL_NAME (TREE_CHAIN (t))
+ == in_charge_identifier))
+ current_in_charge_parm = TREE_CHAIN (t);
+ }
if (DECL_INTERFACE_KNOWN (decl1))
{
DECL_INTERFACE_KNOWN (decl1) = 1;
}
- if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1))
- {
- if (TREE_CODE (fntype) == METHOD_TYPE)
- TREE_TYPE (decl1) = fntype
- = build_function_type (TREE_TYPE (fntype),
- TREE_CHAIN (TYPE_ARG_TYPES (fntype)));
- current_function_parms = TREE_CHAIN (current_function_parms);
- DECL_ARGUMENTS (decl1) = current_function_parms;
- ctype = NULL_TREE;
- }
- restype = TREE_TYPE (fntype);
-
- if (ctype)
+ if (doing_semantic_analysis_p ())
{
- /* If we're compiling a friend function, neither of the variables
- current_class_ptr nor current_class_type will have values. */
- if (! doing_friend)
- {
- /* We know that this was set up by `grokclassfn'.
- We do not wait until `store_parm_decls', since evil
- parse errors may never get us to that point. Here
- we keep the consistency between `current_class_type'
- and `current_class_ptr'. */
- tree t = current_function_parms;
- int i;
-
- my_friendly_assert (t != NULL_TREE
- && TREE_CODE (t) == PARM_DECL, 162);
- my_friendly_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE,
- 19990811);
-
- if (! hack_decl_function_context (decl1))
- temporary_allocation ();
- i = suspend_momentary ();
-
- /* Normally, build_indirect_ref returns current_class_ref
- whenever current_class_ptr is dereferenced. This time,
- however, we want it to *create* current_class_ref, so we
- temporarily clear current_class_ptr to fool it. */
- current_class_ptr = NULL_TREE;
- current_class_ref = build_indirect_ref (t, NULL_PTR);
- current_class_ptr = t;
-
- resume_momentary (i);
- if (! hack_decl_function_context (decl1))
- end_temporary_allocation ();
- }
+ pushlevel (0);
+ current_binding_level->parm_flag = 1;
}
- else
- current_class_ptr = current_class_ref = NULL_TREE;
-
- pushlevel (0);
- current_binding_level->parm_flag = 1;
if (attrs)
cplus_decl_attributes (decl1, NULL_TREE, attrs);
TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = CP_TYPE_VOLATILE_P (restype);
}
- /* Allocate further tree nodes temporarily during compilation
- of this function only. Tiemann moved up here from bottom of fn. */
- /* If this is a nested function, then we must continue to allocate RTL
- on the permanent obstack in case we need to inline it later. */
- if (! hack_decl_function_context (decl1))
- temporary_allocation ();
-
- /* Make sure that we always have a momntary obstack while we're in a
- function body. */
- push_momentary ();
-
- if (building_stmt_tree ())
- begin_stmt_tree (decl1);
-
++function_depth;
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
&& DECL_LANGUAGE (decl1) == lang_cplusplus)
{
dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- ctor_label = NULL_TREE;
+ DECL_CONTEXT (dtor_label) = current_function_decl;
}
- else
+ else if (DECL_CONSTRUCTOR_P (decl1))
{
- dtor_label = NULL_TREE;
- if (DECL_CONSTRUCTOR_P (decl1))
- ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ DECL_CONTEXT (ctor_label) = current_function_decl;
}
return 1;
}
\f
-/* Called after store_parm_decls for a function-try-block. We need to update
- last_parm_cleanup_insn so that the base initializers for a constructor
- are run within this block, not before it. */
+/* Called after store_parm_decls for a function-try-block. */
void
expand_start_early_try_stmts ()
{
expand_start_try_stmts ();
- last_parm_cleanup_insn = get_last_insn ();
}
/* Store the parameter declarations into the current function declaration.
int parms_have_cleanups = 0;
tree cleanups = NULL_TREE;
- /* This is either a chain of PARM_DECLs (when a prototype is used). */
- tree specparms = current_function_parms;
-
/* This is a list of types declared among parms in a prototype. */
tree parmtags = current_function_parm_tags;
then CONST_DECLs for foo and bar are put here. */
tree nonparms = NULL_TREE;
- if (toplevel_bindings_p ())
- fatal ("parse errors have confused me too much");
-
- /* Initialize RTL machinery. */
- init_function_start (fndecl, input_filename, lineno);
- /* 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;
- get_pending_sizes ();
-
/* Create a binding level for the parms. */
- expand_start_bindings (0);
+ if (!building_stmt_tree ())
+ expand_start_bindings (2);
- if (specparms != NULL_TREE)
+ if (current_function_parms)
{
/* This case is when the function was defined with an ANSI prototype.
The parms already have decls, so we need not do anything here
except record them as in effect
and complain if any redundant old-style parm decls were written. */
- register tree next;
+ tree specparms = current_function_parms;
+ tree next;
- /* Must clear this because it might contain TYPE_DECLs declared
- at class level. */
- storedecls (NULL_TREE);
+ if (doing_semantic_analysis_p ())
+ {
+ /* Must clear this because it might contain TYPE_DECLs declared
+ at class level. */
+ storedecls (NULL_TREE);
+
+ /* If we're doing semantic analysis, then we'll call pushdecl
+ for each of these. We must do them in reverse order so that
+ they end in the correct forward order. */
+ specparms = nreverse (specparms);
+ }
- for (parm = nreverse (specparms); parm; parm = next)
+ for (parm = specparms; parm; parm = next)
{
next = TREE_CHAIN (parm);
if (TREE_CODE (parm) == PARM_DECL)
{
- tree cleanup;
- if (DECL_NAME (parm) == NULL_TREE)
- {
- pushdecl (parm);
- }
- else if (TREE_CODE (TREE_TYPE (parm)) == VOID_TYPE)
- cp_error ("parameter `%D' declared void", parm);
- else
- {
- /* Now fill in DECL_REFERENCE_SLOT for any of the parm decls.
- A parameter is assumed not to have any side effects.
- If this should change for any reason, then this
- will have to wrap the bashed reference type in a save_expr.
-
- Also, if the parameter type is declared to be an X
- and there is an X(X&) constructor, we cannot lay it
- into the stack (any more), so we make this parameter
- look like it is really of reference type. Functions
- which pass parameters to this function will know to
- create a temporary in their frame, and pass a reference
- to that. */
-
- if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
- && TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))))
- SET_DECL_REFERENCE_SLOT (parm, convert_from_reference (parm));
-
- pushdecl (parm);
- }
- if (! building_stmt_tree ()
- && (cleanup = maybe_build_cleanup (parm), cleanup))
+ tree type = TREE_TYPE (parm);
+
+ if (doing_semantic_analysis_p ())
{
- expand_decl (parm);
- parms_have_cleanups = 1;
+ tree cleanup;
+
+ if (DECL_NAME (parm) == NULL_TREE
+ || TREE_CODE (parm) != VOID_TYPE)
+ pushdecl (parm);
+ else
+ cp_error ("parameter `%D' declared void", parm);
- /* Keep track of the cleanups. */
- cleanups = tree_cons (parm, cleanup, cleanups);
+ cleanup = maybe_build_cleanup (parm);
+
+ if (cleanup)
+ cleanups = tree_cons (parm, cleanup, cleanups);
}
+ else if (type != error_mark_node
+ && TYPE_NEEDS_DESTRUCTOR (type))
+ parms_have_cleanups = 1;
}
else
{
}
}
- /* Get the decls in their original chain order
- and record in the function. This is all and only the
- PARM_DECLs that were pushed into scope by the loop above. */
- DECL_ARGUMENTS (fndecl) = getdecls ();
-
- storetags (chainon (parmtags, gettags ()));
+ if (doing_semantic_analysis_p ())
+ {
+ /* Get the decls in their original chain order
+ and record in the function. This is all and only the
+ PARM_DECLs that were pushed into scope by the loop above. */
+ DECL_ARGUMENTS (fndecl) = getdecls ();
+ storetags (chainon (parmtags, gettags ()));
+ }
}
else
DECL_ARGUMENTS (fndecl) = NULL_TREE;
as the decl-chain of the current lexical scope.
Put the enumerators in as well, at the front so that
DECL_ARGUMENTS is not modified. */
-
- storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
-
- /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */
- declare_function_name ();
+ if (doing_semantic_analysis_p ())
+ storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
/* Initialize the RTL code for the function. */
DECL_SAVED_INSNS (fndecl) = 0;
/* Now that we have initialized the parms, we can start their
cleanups. We cannot do this before, since expand_decl_cleanup
should not be called before the parm can be used. */
- if (cleanups && !building_stmt_tree ())
+ while (cleanups)
{
- for (cleanups = nreverse (cleanups); cleanups; cleanups = TREE_CHAIN (cleanups))
- {
- if (! expand_decl_cleanup (TREE_PURPOSE (cleanups), TREE_VALUE (cleanups)))
- cp_error ("parser lost in parsing declaration of `%D'",
- TREE_PURPOSE (cleanups));
- }
+ finish_decl_cleanup (TREE_PURPOSE (cleanups),
+ TREE_VALUE (cleanups));
+ cleanups = TREE_CHAIN (cleanups);
}
/* Create a binding contour which can be used to catch
{
pushlevel (0);
if (!building_stmt_tree ())
- expand_start_bindings (0);
+ expand_start_bindings (2);
}
- if (! building_stmt_tree () && flag_exceptions)
- {
- /* Do the starting of the exception specifications, if we have any. */
- if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
- expand_start_eh_spec ();
- }
-
- last_parm_cleanup_insn = get_last_insn ();
- last_dtor_insn = get_last_insn ();
+ /* Do the starting of the exception specifications, if we have any. */
+ if (flag_exceptions && !processing_template_decl
+ && building_stmt_tree ()
+ && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
+ current_eh_spec_try_block = expand_start_eh_spec ();
}
/* Bind a name and initialization to the return value of
}
\f
+/* We have finished doing semantic analysis on DECL, but have not yet
+ generated RTL for its body. Save away our current state, so that
+ when we want to generate RTL later we know what to do. */
+
+static void
+save_function_data (decl)
+ tree decl;
+{
+ struct language_function *f;
+
+ /* Save the language-specific per-function data so that we can
+ get it back when we really expand this function. */
+ my_friendly_assert (!DECL_PENDING_INLINE_P (decl),
+ 19990908);
+
+ /* Make a copy. */
+ f = ((struct language_function *)
+ xmalloc (sizeof (struct language_function)));
+ bcopy ((char *) cp_function_chain, (char *) f,
+ sizeof (struct language_function));
+ DECL_SAVED_FUNCTION_DATA (decl) = f;
+
+ /* Clear out the bits we don't need. */
+ f->x_base_init_list = NULL_TREE;
+ f->x_member_init_list = NULL_TREE;
+ f->x_stmt_tree.x_last_stmt = NULL_TREE;
+ f->x_stmt_tree.x_last_expr_type = NULL_TREE;
+ f->x_result_rtx = NULL_RTX;
+ f->x_named_label_uses = NULL;
+ f->bindings = NULL;
+
+ /* When we get back here again, we will be expanding. */
+ f->x_expanding_p = 1;
+
+ /* If we've already decided that we cannot inline this function, we
+ must remember that fact when we actually go to expand the
+ function. */
+ f->cannot_inline = current_function_cannot_inline;
+}
+
+/* At the end of every constructor we generate to code to return
+ `this'. Do that now. */
+
+static void
+finish_constructor_body ()
+{
+ /* Any return from a constructor will end up here. */
+ add_tree (build_min_nt (LABEL_STMT, ctor_label));
+
+ /* Clear CTOR_LABEL so that finish_return_stmt knows to really
+ generate the return, rather than a goto to CTOR_LABEL. */
+ ctor_label = NULL_TREE;
+ /* In check_return_expr we translate an empty return from a
+ constructor to a return of `this'. */
+ finish_return_stmt (NULL_TREE);
+ /* Mark the end of the constructor. */
+ add_tree (build_min_nt (CTOR_STMT));
+}
+
+/* At the end of every destructor we generate code to restore virtual
+ function tables to the values desired by base classes and to call
+ to base class destructors. Do that now. */
+
+static void
+finish_destructor_body ()
+{
+ tree compound_stmt;
+ tree in_charge;
+ tree virtual_size;
+ tree exprstmt;
+
+ /* Create a block to contain all the extra code. */
+ compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+
+ /* Any return from a destructor will end up here. */
+ add_tree (build_min_nt (LABEL_STMT, dtor_label));
+
+ /* Generate the code to call destructor on base class. If this
+ destructor belongs to a class with virtual functions, then set
+ the virtual function table pointer to represent the type of our
+ base class. */
+
+ /* This side-effect makes call to `build_delete' generate the code
+ we have to have at the end of this destructor. `build_delete'
+ will set the flag again. */
+ TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
+
+ /* These are two cases where we cannot delegate deletion. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
+ || TYPE_GETS_REG_DELETE (current_class_type))
+ in_charge = integer_zero_node;
+ else
+ in_charge = current_in_charge_parm;
+
+ exprstmt = build_delete (current_class_type,
+ current_class_ref,
+ in_charge,
+ LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
+ 0);
+
+ if (exprstmt != error_mark_node
+ && (TREE_CODE (exprstmt) != NOP_EXPR
+ || TREE_OPERAND (exprstmt, 0) != integer_zero_node
+ || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
+ {
+ if (exprstmt != void_zero_node)
+ /* Don't call `expand_expr_stmt' if we're not going to do
+ anything, since -Wall will give a diagnostic. */
+ finish_expr_stmt (exprstmt);
+
+ /* Run destructors for all virtual baseclasses. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ {
+ tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
+ tree if_stmt = begin_if_stmt ();
+ finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
+ current_in_charge_parm,
+ integer_two_node),
+ if_stmt);
+
+ while (vbases)
+ {
+ if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
+ {
+ tree vb = get_vbase
+ (BINFO_TYPE (vbases),
+ TYPE_BINFO (current_class_type));
+ finish_expr_stmt
+ (build_scoped_method_call
+ (current_class_ref, vb, dtor_identifier,
+ build_expr_list (NULL_TREE, integer_zero_node)));
+ }
+ vbases = TREE_CHAIN (vbases);
+ }
+
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
+ }
+ }
+
+ virtual_size = c_sizeof (current_class_type);
+
+ /* At the end, call delete if that's what's requested. */
+
+ /* FDIS sez: At the point of definition of a virtual destructor
+ (including an implicit definition), non-placement operator delete
+ shall be looked up in the scope of the destructor's class and if
+ found shall be accessible and unambiguous.
+
+ This is somewhat unclear, but I take it to mean that if the class
+ only defines placement deletes we don't do anything here. So we
+ pass LOOKUP_SPECULATIVELY; delete_sanity will complain for us if
+ they ever try to delete one of these. */
+ if (TYPE_GETS_REG_DELETE (current_class_type)
+ || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ {
+ tree if_stmt;
+
+ exprstmt = build_op_delete_call
+ (DELETE_EXPR, current_class_ptr, virtual_size,
+ LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
+
+ if_stmt = begin_if_stmt ();
+ finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
+ current_in_charge_parm,
+ integer_one_node),
+ if_stmt);
+ finish_expr_stmt (exprstmt);
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
+ }
+
+ /* Close the block we started above. */
+ finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+}
+
/* Finish up a function declaration and compile that function
all the way to assembler language output. The free the storage
for the function definition.
function definition. (This processing will have taken place
after the class definition is complete.) */
-void
+tree
finish_function (lineno, flags)
int lineno;
int flags;
{
register tree fndecl = current_function_decl;
tree fntype, ctype = NULL_TREE;
- rtx fn_last_parm_insn, insns;
/* Label to use if this function is supposed to return a value. */
tree no_return_label = NULL_TREE;
- tree decls = NULL_TREE;
int call_poplevel = (flags & 1) != 0;
int inclass_inline = (flags & 2) != 0;
int expand_p;
/* When we get some parse errors, we can end up without a
current_function_decl, so cope. */
if (fndecl == NULL_TREE)
- return;
+ return error_mark_node;
nested = function_depth > 1;
fntype = TREE_TYPE (fndecl);
-/* TREE_READONLY (fndecl) = 1;
- This caused &foo to be of type ptr-to-const-function
- which then got a warning when stored in a ptr-to-function variable. */
+ /* TREE_READONLY (fndecl) = 1;
+ This caused &foo to be of type ptr-to-const-function
+ which then got a warning when stored in a ptr-to-function variable. */
/* This happens on strange parse errors. */
if (! current_function_parms_stored)
if (building_stmt_tree ())
{
- if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel)
+ if (DECL_CONSTRUCTOR_P (fndecl))
+ {
+ finish_constructor_body ();
+ if (call_poplevel)
+ do_poplevel ();
+ }
+ else if (DECL_DESTRUCTOR_P (fndecl) && !processing_template_decl)
+ finish_destructor_body ();
+ else if (DECL_MAIN_P (fndecl))
{
- decls = getdecls ();
- expand_end_bindings (decls, decls != NULL_TREE, 0);
- poplevel (decls != NULL_TREE, 0, 0);
+ /* Make it so that `main' always returns 0 by default. */
+#ifdef VMS
+ finish_return_stmt (integer_one_node);
+#else
+ finish_return_stmt (integer_zero_node);
+#endif
}
- /* Because we do not call expand_function_end, we won't call
- expand_end_bindings to match the call to
- expand_start_bindings we did in store_parm_decls. Therefore,
- we explicitly call expand_end_bindings here. However, we
- really shouldn't be calling expand_start_bindings at all when
- building_stmt_tree; it's conceptually an RTL-generation
- function, rather than a front-end function. */
- expand_end_bindings (0, 0, 0);
+ /* Finish dealing with exception specifiers. */
+ if (flag_exceptions && !processing_template_decl
+ && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
+ expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS
+ (TREE_TYPE (current_function_decl)),
+ current_eh_spec_try_block);
}
else
{
+#if 0
if (write_symbols != NO_DEBUG /*&& TREE_CODE (fntype) != METHOD_TYPE*/)
{
+ /* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". (jason 1999-11-11) */
+
tree ttype = target_type (fntype);
tree parmdecl;
note_debug_info_needed (ttype);
}
}
+#endif
/* Clean house because we will need to reorder insns here. */
do_pending_stack_adjust ();
if (dtor_label)
- {
- tree binfo = TYPE_BINFO (current_class_type);
- tree cond = integer_one_node;
- tree exprstmt;
- tree in_charge_node = lookup_name (in_charge_identifier, 0);
- tree virtual_size;
- int ok_to_optimize_dtor = 0;
- int empty_dtor = get_last_insn () == last_dtor_insn;
-
- if (current_function_assigns_this)
- cond = build (NE_EXPR, boolean_type_node,
- current_class_ptr, integer_zero_node);
- else
- {
- int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
-
- /* If this destructor is empty, then we don't need to check
- whether `this' is NULL in some cases. */
- if ((flag_this_is_variable & 1) == 0)
- ok_to_optimize_dtor = 1;
- else if (empty_dtor)
- ok_to_optimize_dtor
- = (n_baseclasses == 0
- || (n_baseclasses == 1
- && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0))));
- }
-
- /* These initializations might go inline. Protect
- the binding level of the parms. */
- pushlevel (0);
- expand_start_bindings (0);
-
- if (current_function_assigns_this)
- {
- current_function_assigns_this = 0;
- current_function_just_assigned_this = 0;
- }
-
- /* Generate the code to call destructor on base class.
- If this destructor belongs to a class with virtual
- functions, then set the virtual function table
- pointer to represent the type of our base class. */
-
- /* This side-effect makes call to `build_delete' generate the
- code we have to have at the end of this destructor.
- `build_delete' will set the flag again. */
- TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
-
- /* These are two cases where we cannot delegate deletion. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
- || TYPE_GETS_REG_DELETE (current_class_type))
- exprstmt = build_delete (current_class_type, current_class_ref, integer_zero_node,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
- else
- exprstmt = build_delete (current_class_type, current_class_ref, in_charge_node,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
-
- /* If we did not assign to this, then `this' is non-zero at
- the end of a destructor. As a special optimization, don't
- emit test if this is an empty destructor. If it does nothing,
- it does nothing. If it calls a base destructor, the base
- destructor will perform the test. */
-
- if (exprstmt != error_mark_node
- && (TREE_CODE (exprstmt) != NOP_EXPR
- || TREE_OPERAND (exprstmt, 0) != integer_zero_node
- || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
- {
- expand_label (dtor_label);
- if (cond != integer_one_node)
- expand_start_cond (cond, 0);
- if (exprstmt != void_zero_node)
- /* Don't call `expand_expr_stmt' if we're not going to do
- anything, since -Wall will give a diagnostic. */
- expand_expr_stmt (exprstmt);
-
- /* Run destructor on all virtual baseclasses. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- {
- tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
- expand_start_cond (build (BIT_AND_EXPR, integer_type_node,
- in_charge_node, integer_two_node), 0);
- while (vbases)
- {
- if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
- {
- tree vb = get_vbase
- (BINFO_TYPE (vbases),
- TYPE_BINFO (current_class_type));
- expand_expr_stmt
- (build_scoped_method_call
- (current_class_ref, vb, dtor_identifier,
- build_expr_list (NULL_TREE, integer_zero_node)));
- }
- vbases = TREE_CHAIN (vbases);
- }
- expand_end_cond ();
- }
-
- do_pending_stack_adjust ();
- if (cond != integer_one_node)
- expand_end_cond ();
- }
-
- virtual_size = c_sizeof (current_class_type);
-
- /* At the end, call delete if that's what's requested. */
-
- /* FDIS sez: At the point of definition of a virtual destructor
- (including an implicit definition), non-placement operator
- delete shall be looked up in the scope of the destructor's
- class and if found shall be accessible and unambiguous.
-
- This is somewhat unclear, but I take it to mean that if the
- class only defines placement deletes we don't do anything here.
- So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain
- for us if they ever try to delete one of these. */
-
- if (TYPE_GETS_REG_DELETE (current_class_type)
- || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- exprstmt = build_op_delete_call
- (DELETE_EXPR, current_class_ptr, virtual_size,
- LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
- else
- exprstmt = NULL_TREE;
-
- if (exprstmt)
- {
- cond = build (BIT_AND_EXPR, integer_type_node,
- in_charge_node, integer_one_node);
- expand_start_cond (cond, 0);
- expand_expr_stmt (exprstmt);
- expand_end_cond ();
- }
-
- /* End of destructor. */
- expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0);
- poplevel (getdecls () != NULL_TREE, 0, 0);
-
- /* Back to the top of destructor. */
- /* Don't execute destructor code if `this' is NULL. */
-
- start_sequence ();
-
- /* If the dtor is empty, and we know there is not possible way we
- could use any vtable entries, before they are possibly set by
- a base class dtor, we don't have to setup the vtables, as we
- know that any base class dtoring will set up any vtables it
- needs. We avoid MI, because one base class dtor can do a
- virtual dispatch to an overridden function that would need to
- have a non-related vtable set up, we cannot avoid setting up
- vtables in that case. We could change this to see if there is
- just one vtable. */
- if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type))
- {
- /* Make all virtual function table pointers in non-virtual base
- classes point to CURRENT_CLASS_TYPE's virtual function
- tables. */
- expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr);
-
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr);
- }
-
- if (! ok_to_optimize_dtor)
- {
- cond = build_binary_op (NE_EXPR,
- current_class_ptr, integer_zero_node);
- expand_start_cond (cond, 0);
- }
-
- insns = get_insns ();
- end_sequence ();
-
- fn_last_parm_insn = get_first_nonparm_insn ();
- if (fn_last_parm_insn == NULL_RTX)
- fn_last_parm_insn = get_last_insn ();
- else
- fn_last_parm_insn = previous_insn (fn_last_parm_insn);
-
- emit_insns_after (insns, fn_last_parm_insn);
-
- if (! ok_to_optimize_dtor)
- expand_end_cond ();
- }
- else if (current_function_assigns_this)
- {
- /* Does not need to call emit_base_init, because
- that is done (if needed) just after assignment to this
- is seen. */
-
- if (DECL_CONSTRUCTOR_P (current_function_decl))
- {
- end_protect_partials ();
- expand_label (ctor_label);
- ctor_label = NULL_TREE;
-
- if (call_poplevel)
- {
- decls = getdecls ();
- expand_end_bindings (decls, decls != NULL_TREE, 0);
- poplevel (decls != NULL_TREE, 0, 0);
- }
- /* c_expand_return knows to return 'this' from a constructor. */
- c_expand_return (NULL_TREE);
- }
- else if (TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl))) != VOID_TYPE
- && return_label != NULL_RTX)
- no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
- current_function_assigns_this = 0;
- current_function_just_assigned_this = 0;
- base_init_expr = NULL_TREE;
- }
+ ;
else if (DECL_CONSTRUCTOR_P (fndecl))
{
- tree cond = NULL_TREE, thenclause = NULL_TREE;
- /* Allow constructor for a type to get a new instance of the object
- using `build_new'. */
- tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
- CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
-
- if (flag_this_is_variable > 0)
- {
- cond = build_binary_op (EQ_EXPR,
- current_class_ptr, integer_zero_node);
- thenclause = build_modify_expr (current_class_ptr, NOP_EXPR,
- build_new (NULL_TREE, current_class_type, void_type_node, 0));
- }
-
- CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
-
- start_sequence ();
-
- if (flag_this_is_variable > 0)
- {
- expand_start_cond (cond, 0);
- expand_expr_stmt (thenclause);
- expand_end_cond ();
- }
-
- /* Emit insns from `emit_base_init' which sets up virtual
- function table pointer(s). */
- if (base_init_expr)
- {
- expand_expr_stmt (base_init_expr);
- base_init_expr = NULL_TREE;
- }
-
- insns = get_insns ();
- end_sequence ();
-
- /* This is where the body of the constructor begins. */
-
- emit_insns_after (insns, last_parm_cleanup_insn);
-
- end_protect_partials ();
-
- /* This is where the body of the constructor ends. */
- expand_label (ctor_label);
- ctor_label = NULL_TREE;
-
if (call_poplevel)
- {
- decls = getdecls ();
- expand_end_bindings (decls, decls != NULL_TREE, 0);
- poplevel (decls != NULL_TREE, 1, 0);
- }
-
- /* c_expand_return knows to return 'this' from a constructor. */
- c_expand_return (NULL_TREE);
-
- current_function_assigns_this = 0;
- current_function_just_assigned_this = 0;
- }
- else if (DECL_MAIN_P (fndecl))
- {
- /* Make it so that `main' always returns 0 by default. */
-#ifdef VMS
- c_expand_return (integer_one_node);
-#else
- c_expand_return (integer_zero_node);
-#endif
+ do_poplevel ();
}
else if (return_label != NULL_RTX
+ && flag_this_is_variable <= 0
&& current_function_return_value == NULL_TREE
&& ! DECL_NAME (DECL_RESULT (current_function_decl)))
no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
emit_label (cleanup_label);
}
- /* Get return value into register if that's where it's supposed to be. */
+ /* Get return value into register if that's where it's supposed
+ to be. */
if (original_result_rtx)
fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx);
/* If we're saving up tree structure, tie off the function now. */
if (!expand_p)
- finish_stmt_tree (fndecl);
+ finish_stmt_tree (&DECL_SAVED_TREE (fndecl));
/* This must come after expand_function_end because cleanups might
have declarations (from inline functions) that need to go into
this function's blocks. */
- if (current_binding_level->parm_flag != 1)
- my_friendly_abort (122);
- poplevel (1, 0, 1);
-
- /* If this is a in-class inline definition, we may have to pop the
- bindings for the template parameters that we added in
- maybe_begin_member_template_processing when start_function was
- called. */
- if (inclass_inline)
- maybe_end_member_template_processing ();
-
- /* Reset scope for C++: if we were in the scope of a class,
- then when we finish this function, we are not longer so.
- This cannot be done until we know for sure that no more
- class members will ever be referenced in this function
- (i.e., calls to destructors). */
- if (current_class_name)
+ if (doing_semantic_analysis_p ())
{
- ctype = current_class_type;
- pop_nested_class ();
+ if (current_binding_level->parm_flag != 1)
+ my_friendly_abort (122);
+ poplevel (1, 0, 1);
}
+ /* Remember that we were in class scope. */
+ if (current_class_name)
+ ctype = current_class_type;
+
/* Must mark the RESULT_DECL as being in this function. */
DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
to the FUNCTION_DECL node itself. */
BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
- /* Undo the call to push_momentary in start_function. */
- pop_momentary ();
+ /* Save away current state, if appropriate. */
+ if (!expanding_p && !processing_template_decl)
+ save_function_data (fndecl);
if (expand_p)
{
+ int returns_null;
+ int returns_value;
int saved_flag_keep_inline_functions =
flag_keep_inline_functions;
function is gone. See save_tree_status. */
flag_keep_inline_functions = 1;
+ /* Before we call rest_of_compilation (which will pop the
+ CURRENT_FUNCTION), we must save these values. */
+ returns_null = current_function_returns_null;
+ returns_value = current_function_returns_value;
+
/* If this is a nested function (like a template instantiation
that we're compiling in the midst of compiling something
else), push a new GC context. That will keep local variables
mark_inline_for_output (fndecl);
}
+#if 0
+ /* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". (jason 1999-11-11) */
+
if (ctype && TREE_ASM_WRITTEN (fndecl))
note_debug_info_needed (ctype);
+#endif
- current_function_returns_null |= can_reach_end;
+ returns_null |= can_reach_end;
/* Since we don't normally go through c_expand_return for constructors,
this normally gets the wrong value.
NOTE_INSN_FUNCTION_END, confusing jump.c. */
if (DECL_CONSTRUCTOR_P (fndecl)
|| DECL_NAME (DECL_RESULT (fndecl)) != NULL_TREE)
- current_function_returns_null = 0;
+ returns_null = 0;
- if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
+ if (TREE_THIS_VOLATILE (fndecl) && returns_null)
cp_warning ("`noreturn' function `%D' does return", fndecl);
else if ((warn_return_type || pedantic)
- && current_function_returns_null
+ && returns_null
&& TREE_CODE (TREE_TYPE (fntype)) != VOID_TYPE)
{
/* If this function returns non-void and control can drop through,
}
/* 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)
+ else if (extra_warnings && returns_value && returns_null)
warning ("this function may return with or without a value");
}
+ else
+ {
+ /* Clear out memory we no longer need. */
+ free_after_parsing (current_function);
+ /* Since we never call rest_of_compilation, we never clear
+ CURRENT_FUNCTION. Do so explicitly. */
+ free_after_compilation (current_function);
+ current_function = NULL;
+ }
- --function_depth;
+ /* If this is a in-class inline definition, we may have to pop the
+ bindings for the template parameters that we added in
+ maybe_begin_member_template_processing when start_function was
+ called. */
+ if (inclass_inline)
+ maybe_end_member_template_processing ();
- /* Free all the tree nodes making up this function. */
- /* Switch back to allocating nodes permanently
- until we start another function. */
- if (! nested)
- permanent_allocation (1);
+ /* Leave the scope of the class. */
+ if (ctype)
+ pop_nested_class ();
- if (DECL_SAVED_INSNS (fndecl) == 0)
+ --function_depth;
+
+ if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl)
+ && !(flag_inline_trees && DECL_INLINE (fndecl)))
{
tree t;
}
if (DECL_STATIC_CONSTRUCTOR (fndecl))
- static_ctors = perm_tree_cons (NULL_TREE, fndecl, static_ctors);
+ static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
if (DECL_STATIC_DESTRUCTOR (fndecl))
- static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors);
+ static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
+ /* Clean up. */
if (! nested)
{
/* Let the error reporting routines know that we're outside a
function. For a nested function, this value is used in
pop_cp_function_context and then reset via pop_function_context. */
current_function_decl = NULL_TREE;
+ /* We don't really care about obstacks, but the middle-end
+ sometimes cares on what obstck things are located. */
+ permanent_allocation (1);
}
- named_label_uses = NULL;
- current_class_ptr = NULL_TREE;
- current_class_ref = NULL_TREE;
+ return fndecl;
}
\f
/* Create the FUNCTION_DECL for a function definition.
grok_op_properties (fndecl, DECL_VIRTUAL_P (fndecl), 0);
}
- cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0, 0);
+ cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
/* Make a place for the parms */
pushlevel (0);
tree type = TREE_TYPE (decl);
if (type != error_mark_node && TYPE_NEEDS_DESTRUCTOR (type))
{
- int temp = 0, flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
+ int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
tree rval;
- if (TREE_CODE (decl) != PARM_DECL)
- temp = suspend_momentary ();
-
if (TREE_CODE (type) == ARRAY_TYPE)
rval = decl;
else
if (TYPE_USES_VIRTUAL_BASECLASSES (type)
&& ! TYPE_HAS_DESTRUCTOR (type))
- rval = build_compound_expr (expr_tree_cons (NULL_TREE, rval,
+ rval = build_compound_expr (tree_cons (NULL_TREE, rval,
build_expr_list (NULL_TREE, build_vbase_delete (type, decl))));
- if (TREE_CODE (decl) != PARM_DECL)
- resume_momentary (temp);
-
return rval;
}
return 0;
cplus_expand_expr_stmt (exp)
tree exp;
{
- exp = require_complete_type_in_void (exp);
+ if (stmts_are_full_exprs_p)
+ exp = convert_to_void (exp, "statement");
- if (TREE_CODE (exp) == FUNCTION_DECL)
- {
- cp_warning ("reference, not call, to function `%D'", exp);
- warning ("at this point in file");
- }
-
#if 0
/* We should do this eventually, but right now this causes regex.o from
libg++ to miscompile, and tString to core dump. */
exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
#endif
- /* Strip unused implicit INDIRECT_REFs of references. */
- if (TREE_CODE (exp) == INDIRECT_REF
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
- exp = TREE_OPERAND (exp, 0);
-
/* If we don't do this, we end up down inside expand_expr
trying to do TYPE_MODE on the ERROR_MARK, and really
go outside the bounds of the type. */
if (exp != error_mark_node)
- expand_expr_stmt (break_out_cleanups (exp));
+ expand_expr_stmt (exp);
}
/* When a stmt has been parsed, this function is called. */
void
finish_stmt ()
{
- if (!current_function_assigns_this
- && current_function_just_assigned_this)
- {
- if (DECL_CONSTRUCTOR_P (current_function_decl))
- {
- /* Constructors must wait until we are out of control
- zones before calling base constructors. */
- if (in_control_zone_p ())
- return;
- expand_expr_stmt (base_init_expr);
- check_base_init (current_class_type);
- }
- current_function_assigns_this = 1;
- }
-
/* Always assume this statement was not an expression statement. If
it actually was an expression statement, its our callers
responsibility to fix this up. */
*argtypes = args;
}
-/* Save and reinitialize the variables
- used during compilation of a C++ function. */
+/* Initialize the variables used during compilation of a C++
+ function. */
static void
push_cp_function_context (f)
{
struct language_function *p
= ((struct language_function *)
- xmalloc (sizeof (struct language_function)));
+ xcalloc (1, sizeof (struct language_function)));
f->language = p;
- if (f->next)
- *p = *f->next->language;
- else
- bzero (p, sizeof (struct language_function));
- /* For now, we always assume we're expanding all the way to RTL
- unless we're explicitly doing otherwise. */
- expanding_p = 1;
+ /* It takes an explicit call to expand_body to generate RTL for a
+ function. */
+ expanding_p = 0;
/* Whenever we start a new function, we destroy temporaries in the
usual way. */
stmts_are_full_exprs_p = 1;
}
-/* Restore the variables used during compilation of a C++ function. */
+/* Free the language-specific parts of F, now that we've finished
+ compiling the function. */
static void
pop_cp_function_context (f)
struct function *f;
{
- free (f->language);
+ if (f->language)
+ free (f->language);
f->language = 0;
}
-void
-mark_cp_function_context (f)
- struct function *f;
-{
- struct language_function *p = f->language;
+/* Mark P for GC. */
+static void
+mark_lang_function (p)
+ struct language_function *p;
+{
if (!p)
return;
ggc_mark_tree (p->x_dtor_label);
ggc_mark_tree (p->x_base_init_list);
ggc_mark_tree (p->x_member_init_list);
- ggc_mark_tree (p->x_base_init_expr);
ggc_mark_tree (p->x_current_class_ptr);
ggc_mark_tree (p->x_current_class_ref);
- ggc_mark_tree (p->x_last_tree);
- ggc_mark_tree (p->x_last_expr_type);
+ ggc_mark_tree (p->x_eh_spec_try_block);
+ ggc_mark_tree (p->x_scope_stmt_stack);
- ggc_mark_rtx (p->x_last_dtor_insn);
- ggc_mark_rtx (p->x_last_parm_cleanup_insn);
ggc_mark_rtx (p->x_result_rtx);
- mark_binding_level (&p->binding_level);
+ mark_stmt_tree (&p->x_stmt_tree);
+ mark_binding_level (&p->bindings);
}
+/* Mark the language-specific data in F for GC. */
+
+static void
+mark_cp_function_context (f)
+ struct function *f;
+{
+ mark_lang_function (f->language);
+}
int
in_function_p ()
struct lang_identifier *li = (struct lang_identifier *) t;
struct lang_id2 *li2 = li->x;
ggc_mark_tree (li->namespace_bindings);
+ ggc_mark_tree (li->bindings);
ggc_mark_tree (li->class_value);
ggc_mark_tree (li->class_template_info);
if (ld)
{
- ggc_mark_tree (ld->decl_flags.access);
+ ggc_mark (ld);
+ if (!DECL_GLOBAL_CTOR_P (t) && !DECL_GLOBAL_DTOR_P (t))
+ ggc_mark_tree (ld->decl_flags.u2.access);
ggc_mark_tree (ld->decl_flags.context);
if (TREE_CODE (t) != NAMESPACE_DECL)
ggc_mark_tree (ld->decl_flags.u.template_info);
+ else
+ mark_binding_level (&NAMESPACE_LEVEL (t));
if (CAN_HAVE_FULL_LANG_DECL_P (t))
{
ggc_mark_tree (ld->main_decl_variant);
ggc_mark_tree (ld->saved_tree);
if (TREE_CODE (t) == TYPE_DECL)
ggc_mark_tree (ld->u.sorted_fields);
+ else if (TREE_CODE (t) == FUNCTION_DECL
+ && !DECL_PENDING_INLINE_P (t))
+ mark_lang_function (DECL_SAVED_FUNCTION_DATA (t));
}
}
}
if (lt && !(TREE_CODE (t) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE))
{
+ ggc_mark (lt);
ggc_mark_tree (lt->vfields);
ggc_mark_tree (lt->vbases);
ggc_mark_tree (lt->tags);
}
}
-void
-lang_cleanup_tree (t)
- tree t;
-{
- if (TREE_CODE_CLASS (TREE_CODE (t)) == 't'
- && TYPE_LANG_SPECIFIC (t) != NULL
- && !(TREE_CODE (t) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE))
- free (TYPE_LANG_SPECIFIC (t));
-}