#define obstack_chunk_free free
extern struct obstack permanent_obstack;
-extern struct obstack* saveable_obstack;
extern int current_class_depth;
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 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));
/* 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
tree 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;
-
/* 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;
/* 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;
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)
{
- add_scope_stmt (/*begin_p=*/0, /*partial_p=*/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;
+ {
+ 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;
}
}
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;
}
current_lang_name = lang_name_cplusplus;
strict_prototype = strict_prototypes_lang_cplusplus;
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;
tree name;
- if (TREE_CODE (newdecl) == TYPE_DECL)
+ if (TREE_CODE (newdecl) == TYPE_DECL
+ || TREE_CODE (newdecl) == TEMPLATE_DECL)
return;
/* Don't get confused by static member functions; that's a different
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;
/* 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))
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
&& (!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
/* 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));
}
}
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;
}
static struct hash_table ht;
- push_obstacks (&permanent_obstack, &permanent_obstack);
-
if (!ht.table)
{
static struct hash_table *h = &ht;
/* 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;
}
push_overloaded_decl_1 (x)
tree x;
{
- push_overloaded_decl (x, PUSH_GLOBAL);
+ pushdecl (x);
}
-#ifdef __GNUC__
-__inline
-#endif
-tree
+inline tree
auto_function (name, type)
tree name, type;
{
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);
tem = maybe_push_decl (decl);
if (processing_template_decl)
- {
- if (at_function_scope_p ())
- push_permanent_obstack ();
- tem = push_template_decl (tem);
- if (at_function_scope_p ())
- 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;
}
tree decl;
{
tree type = TREE_TYPE (decl);
+#if 0
tree ttype = target_type (type);
+#endif
/* If we haven't already layed out this declaration, do so now.
Note that we must not call complete type for an external object
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
tree type = TREE_TYPE (decl);
const char *asmspec = NULL;
- if (TREE_READONLY (decl)
- && DECL_INITIAL (decl) != NULL_TREE
- && DECL_INITIAL (decl) != error_mark_node
- && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))
- && ! TREE_SIDE_EFFECTS (decl)
- && ! TREE_PUBLIC (decl)
- && ! DECL_EXTERNAL (decl)
- && ! TYPE_NEEDS_DESTRUCTOR (type)
- && ! TREE_ADDRESSABLE (decl)
- && DECL_MODE (decl) != BLKmode)
- {
- /* As an optimization, we try to put register-sized static
- constants in a register, rather than writing them out. If we
- take the address of the constant later, we'll make RTL for it
- at that point. */
- DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
- store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
- TREE_ASM_WRITTEN (decl) = 1;
- return;
- }
+ /* If we inlined this variable, we could see it's declaration
+ again. */
+ if (DECL_RTL (decl))
+ return;
if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
{
/* Generate code to destroy DECL (a local variable). */
-void
+static void
destroy_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. */
+ /* 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 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);
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 ()
- && TREE_CODE (current_scope ()) == FUNCTION_DECL)
+ if (building_stmt_tree () && at_function_scope_p ())
add_decl_stmt (decl);
if (TYPE_HAS_MUTABLE_P (type))
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 ();
-
if (TREE_CODE (decl) == VAR_DECL)
layout_var_decl (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
if (atexit_node == 0)
{
tree atexit_fndecl, PFV, pfvlist;
- /* 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));
mark_used (atexit_fndecl);
atexit_node = default_conversion (atexit_fndecl);
pop_lang_context ();
- pop_obstacks ();
}
/* Call build_cleanup before we enter the anonymous function so that
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_compound_stmt (/*has_no_scope=*/0, then_clause);
finish_then_clause (if_stmt);
finish_if_stmt ();
-
- /* Resume old (possibly temporary) allocation. */
- pop_obstacks ();
}
else
{
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);
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, 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, type);
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. */
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);
+ register tree size;
- 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;
- }
-
- 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 && !in_system_header && 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;
- }
-
- 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;
{
/* 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
}
}
-/* Returns *TP if *TP is a local variable (or parameter). Returns
- NULL_TREE otherwise. */
+/* Returns non-zero if T is a local variable. */
-static tree
-local_variable_p (tp)
- tree *tp;
+int
+local_variable_p (t)
+ tree t;
{
- tree t = *tp;
-
if ((TREE_CODE (t) == VAR_DECL
/* A VAR_DECL with a context that is a _TYPE is a static data
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'",
{
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);
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 = 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
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 ();
-
++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);
+ {
+ dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ DECL_CONTEXT (dtor_label) = current_function_decl;
+ }
else 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.
next = TREE_CHAIN (parm);
if (TREE_CODE (parm) == PARM_DECL)
{
- tree cleanup;
-
+ tree type = TREE_TYPE (parm);
+
if (doing_semantic_analysis_p ())
{
+ tree cleanup;
+
if (DECL_NAME (parm) == NULL_TREE
- || TREE_CODE (TREE_TYPE (parm)) != VOID_TYPE)
+ || TREE_CODE (parm) != VOID_TYPE)
pushdecl (parm);
else
cp_error ("parameter `%D' declared void", parm);
- }
-
- if (! building_stmt_tree ()
- && (cleanup = maybe_build_cleanup (parm), cleanup))
- {
- expand_decl (parm);
- parms_have_cleanups = 1;
- /* 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
{
PARM_DECLs that were pushed into scope by the loop above. */
DECL_ARGUMENTS (fndecl) = getdecls ();
storetags (chainon (parmtags, gettags ()));
-
- /* We built up the cleanups in reversed order. */
- cleanups = nreverse (cleanups);
}
}
else
/* 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)
- {
- if (! expand_decl_cleanup (TREE_PURPOSE (cleanups),
- TREE_VALUE (cleanups)))
- cp_error ("parser lost in parsing declaration of `%D'",
- TREE_PURPOSE (cleanups));
-
- cleanups = TREE_CHAIN (cleanups);
- }
+ while (cleanups)
+ {
+ finish_decl_cleanup (TREE_PURPOSE (cleanups),
+ TREE_VALUE (cleanups));
+ cleanups = TREE_CHAIN (cleanups);
+ }
/* Create a binding contour which can be used to catch
cleanup-generated temporaries. Also, if the return value needs or
&& building_stmt_tree ()
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
current_eh_spec_try_block = expand_start_eh_spec ();
-
- last_parm_cleanup_insn = get_last_insn ();
- last_dtor_insn = get_last_insn ();
}
/* Bind a name and initialization to the return value of
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_last_dtor_insn = NULL_RTX;
- f->x_last_parm_cleanup_insn = NULL_RTX;
f->x_result_rtx = NULL_RTX;
f->x_named_label_uses = NULL;
f->bindings = NULL;
/* 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
}
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 ();
;
else if (DECL_CONSTRUCTOR_P (fndecl))
{
- /* All subobjects have been fully constructed at this point. */
- end_protect_partials ();
-
if (call_poplevel)
do_poplevel ();
}
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);
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
returns_null |= can_reach_end;
}
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);
--function_depth;
- /* 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);
-
- if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl))
+ if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl)
+ && !(flag_inline_trees && DECL_INLINE (fndecl)))
{
tree t;
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);
}
return fndecl;
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
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;
}
-/* Build a TARGET_EXPR, initializing the DECL with the VALUE. */
-
-tree
-build_target_expr (decl, value)
- tree decl;
- tree value;
-{
- tree t;
-
- t = build (TARGET_EXPR, TREE_TYPE (decl), decl, value,
- maybe_build_cleanup (decl), NULL_TREE);
- /* We always set TREE_SIDE_EFFECTS so that expand_expr does not
- ignore the TARGET_EXPR. If there really turn out to be no
- side-effects, then the optimizer should be able to get rid of
- whatever code is generated anyhow. */
- TREE_SIDE_EFFECTS (t) = 1;
-
- return t;
-}
-
/* If DECL is of a type which needs a cleanup, build that cleanup
here. The cleanup does free the storage with a call to delete. */
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. */
pop_cp_function_context (f)
struct function *f;
{
- free (f->language);
+ if (f->language)
+ free (f->language);
f->language = 0;
}
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_stmt_tree (&p->x_stmt_tree);
/* Mark the language-specific data in F for GC. */
-void
+static void
mark_cp_function_context (f)
struct function *f;
{