#include <sys/types.h>
#include <signal.h>
#include "obstack.h"
+#include "defaults.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
#ifndef BOOL_TYPE_SIZE
#ifdef SLOW_BYTE_ACCESS
-#define BOOL_TYPE_SIZE BITS_PER_WORD
+#define BOOL_TYPE_SIZE ((SLOW_BYTE_ACCESS) ? (BITS_PER_WORD) : (BITS_PER_UNIT))
#else
#define BOOL_TYPE_SIZE BITS_PER_UNIT
#endif
static tree lookup_nested_type PROTO((tree, tree));
static char *redeclaration_error_message PROTO((tree, tree));
static void grok_op_properties PROTO((tree, int, int));
+extern void* push_eh_context PROTO(());
+extern void pop_eh_context PROTO((void *));
tree define_function
PROTO((char *, tree, enum built_in_function, void (*)(), char *));
tree dtor_label;
+/* In a destructor, the last insn emitted after the start of the
+ function and the parms. */
+
+rtx last_dtor_insn;
+
/* In a constructor, the point at which we are ready to return
the pointer to the initialized object. */
Identifiers for `this' in member functions and the auto-delete
parameter for destructors. */
tree this_identifier, in_charge_identifier;
-/* Used in pointer to member functions, and in vtables. */
+/* Used in pointer to member functions, in vtables, and in sigtables. */
tree pfn_identifier, index_identifier, delta_identifier, delta2_identifier;
-tree pfn_or_delta2_identifier;
+tree pfn_or_delta2_identifier, tag_identifier;
+tree vb_off_identifier, vt_off_identifier;
/* A list (chain of TREE_LIST nodes) of named label uses.
The TREE_PURPOSE field is the list of variables defined
/* The binding level which this one is contained in (inherits from). */
struct binding_level *level_chain;
- /* Number of decls in `names' that have incomplete
+ /* List of decls in `names' that have incomplete
structure or union types. */
- unsigned int n_incomplete;
+ tree incomplete;
+
+ /* List of VAR_DECLS saved from a previous for statement.
+ These would be dead in ANSI-conforming code, but might
+ be referenced in traditional code. */
+ tree dead_vars_from_for;
/* 1 for the level that holds the parameters of a function.
2 for the level that holds a class declaration.
/* This is set for a namespace binding level. */
unsigned namespace_p : 1;
+ /* True if this level is that of a for-statement. */
+ unsigned is_for_scope : 1;
+
/* One bit left for this word. */
#if defined(DEBUG_CP_BINDING_LEVELS)
keep_next_level_flag = 0;
}
+int
+note_level_for_for ()
+{
+ current_binding_level->is_for_scope = 1;
+}
+
void
pushlevel_temporary (tag_transparent)
int tag_transparent;
block = make_node (BLOCK);
if (block != NULL_TREE)
{
- BLOCK_VARS (block) = decls;
- BLOCK_TYPE_TAGS (block) = tags;
- 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, so avoid trashing that. Otherwise, for a new block, install
- a new BLOCK_END_NOTE value. */
- if (! block_previously_created)
- remember_end_note (block);
+ if (block_previously_created)
+ {
+ if (decls || tags || subblocks)
+ {
+ if (BLOCK_VARS (block) || BLOCK_TYPE_TAGS (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
+ subblocks onto the end of any pre-existing subblocks. */
+ 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. */
/* Clear out the meanings of the local variables of this level. */
- for (link = decls; link; link = TREE_CHAIN (link))
+ for (link = current_binding_level->dead_vars_from_for;
+ link != NULL_TREE; link = TREE_CHAIN (link))
{
- if (DECL_NAME (link) != NULL_TREE)
+ if (DECL_DEAD_FOR_LOCAL (link))
{
- /* If the ident. was used or addressed via a local extern decl,
- don't forget that fact. */
- if (DECL_EXTERNAL (link))
+ tree id = DECL_NAME (link);
+ if (IDENTIFIER_LOCAL_VALUE (id) == link)
+ IDENTIFIER_LOCAL_VALUE (id) = DECL_SHADOWED_FOR_VAR (link);
+ }
+ }
+
+ if (current_binding_level->is_for_scope && flag_new_for_scope == 1)
+ {
+ for (link = decls; link; link = TREE_CHAIN (link))
+ {
+ if (TREE_CODE (link) == VAR_DECL)
+ DECL_DEAD_FOR_LOCAL (link) = 1;
+ }
+ }
+ else
+ {
+ for (link = decls; link; link = TREE_CHAIN (link))
+ {
+ if (DECL_NAME (link) != NULL_TREE)
{
- if (TREE_USED (link))
- TREE_USED (DECL_ASSEMBLER_NAME (link)) = 1;
- if (TREE_ADDRESSABLE (link))
- TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1;
+ /* If the ident. was used or addressed via a local extern decl,
+ don't forget that fact. */
+ if (DECL_EXTERNAL (link))
+ {
+ if (TREE_USED (link))
+ TREE_USED (DECL_ASSEMBLER_NAME (link)) = 1;
+ if (TREE_ADDRESSABLE (link))
+ TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1;
+ }
+ IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE;
}
- IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE;
}
}
/* Restore all name-meanings of the outer levels
that were shadowed by this level. */
- for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
- IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+ if (current_binding_level->is_for_scope && flag_new_for_scope == 1)
+ {
+ struct binding_level *outer = current_binding_level->level_chain;
+ for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
+ {
+ tree id = TREE_PURPOSE (link);
+ tree decl = IDENTIFIER_LOCAL_VALUE (id);
+ if (DECL_DEAD_FOR_LOCAL (decl))
+ DECL_SHADOWED_FOR_VAR (decl) = TREE_VALUE (link);
+ else
+ IDENTIFIER_LOCAL_VALUE (id) = TREE_VALUE (link);
+ }
+
+ /* Save declarations made in a 'for' statement so we can support pre-ANSI
+ 'for' scoping semantics. */
+
+ /* We append the current names of for-variables to those from previous
+ declarations, so that when we get around to do an poplevel
+ on the OUTER level, we restore the any shadowed readl bindings.
+ Note that the new names are put first on the combined list,
+ so they get to be restored first. This is important if there are
+ two for-loops using the same for-variable in the same block.
+ The binding we really want restored is whatever binding was shadowed
+ by the *first* for-variable, not the binding shadowed by the
+ second for-variable (which would be the first for-variable). */
+ outer->dead_vars_from_for
+ = chainon (current_binding_level->names, outer->dead_vars_from_for);
+ }
+ else
+ {
+ for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
+ IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+ }
for (link = current_binding_level->class_shadowed;
link; link = TREE_CHAIN (link))
IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
fprintf (stderr, " blocks=");
fprintf (stderr, HOST_PTR_PRINTF, lvl->blocks);
fprintf (stderr, " n_incomplete=%d parm_flag=%d keep=%d",
- lvl->n_incomplete, lvl->parm_flag, lvl->keep);
+ list_length (lvl->incomplete), lvl->parm_flag, lvl->keep);
if (lvl->tag_transparent)
fprintf (stderr, " tag-transparent");
if (lvl->more_cleanups_ok)
print_binding_level (global_binding_level);
}
-/* Push into the scope of the NAME namespace. */
+extern char * first_global_object_name;
+
+/* Get a unique name for each call to this routine for unnamed namespaces.
+ Mostly copied from get_file_function_name. */
+static tree
+get_unique_name ()
+{
+ static int temp_name_counter = 0;
+ char *buf;
+ register char *p;
+
+ if (first_global_object_name)
+ p = first_global_object_name;
+ else if (main_input_filename)
+ p = main_input_filename;
+ else
+ p = input_filename;
+
+#define UNNAMED_NAMESPACE_FORMAT "__%s_%d"
+
+ buf = (char *) alloca (sizeof (UNNAMED_NAMESPACE_FORMAT) + strlen (p));
+
+ sprintf (buf, UNNAMED_NAMESPACE_FORMAT, p, temp_name_counter++);
+
+ /* Don't need to pull weird characters out of global names. */
+ if (p != first_global_object_name)
+ {
+ for (p = buf+11; *p; p++)
+ if (! ((*p >= '0' && *p <= '9')
+#if 0 /* we always want labels, which are valid C++ identifiers (+ `$') */
+#ifndef ASM_IDENTIFY_GCC /* this is required if `.' is invalid -- k. raeburn */
+ || *p == '.'
+#endif
+#endif
+#ifndef NO_DOLLAR_IN_LABEL /* this for `$'; unlikely, but... -- kr */
+ || *p == '$'
+#endif
+#ifndef NO_DOT_IN_LABEL /* this for `.'; unlikely, but... */
+ || *p == '.'
+#endif
+ || (*p >= 'A' && *p <= 'Z')
+ || (*p >= 'a' && *p <= 'z')))
+ *p = '_';
+ }
+
+ return get_identifier (buf);
+}
+
+/* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we
+ select a name that is unique to this compilation unit. */
void
push_namespace (name)
tree name;
extern tree current_namespace;
tree old_id = get_namespace_id ();
char *buf;
- tree d = make_node (NAMESPACE_DECL);
+ tree d;
+
+ if (! name)
+ {
+ /* Create a truly ugly name! */
+ name = get_unique_name ();
+ }
+
+ d = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
- DECL_NAME (d) = name;
- DECL_ASSEMBLER_NAME (d) = name;
- /* pushdecl wants to check the size of it to see if it is incomplete... */
- TREE_TYPE (d) = void_type_node;
/* Mark them as external, so redeclaration_error_message doesn't think
they are duplicates. */
+
DECL_EXTERNAL (d) = 1;
d = pushdecl (d);
/* This is new for this compilation unit. */
pushlevel (0);
declare_namespace_level ();
- NAMESPACE_LEVEL (d) = (tree)current_binding_level;
+ NAMESPACE_LEVEL (d) = current_binding_level;
}
else
- {
- resume_level ((struct binding_level*)NAMESPACE_LEVEL (d));
- }
+ resume_level (NAMESPACE_LEVEL (d));
/* This code is just is bit old now... */
current_namespace = tree_cons (NULL_TREE, name, current_namespace);
d = make_type_decl (name, type);
#else
d = build_decl (TYPE_DECL, name, type);
+ DECL_ASSEMBLER_NAME (d) = current_namespace_id (DECL_ASSEMBLER_NAME (d));
#endif
SET_DECL_ARTIFICIAL (d);
#ifdef DWARF_DEBUGGING_INFO
types_match = TREE_TYPE (newdecl) == NULL_TREE;
else if (TREE_TYPE (newdecl) == NULL_TREE)
types_match = 0;
+ /* Qualifiers must match, and they may be present on either, the type
+ or the decl. */
+ else if ((TREE_READONLY (newdecl)
+ || TYPE_READONLY (TREE_TYPE (newdecl)))
+ == (TREE_READONLY (olddecl)
+ || TYPE_READONLY (TREE_TYPE (olddecl)))
+ && (TREE_THIS_VOLATILE (newdecl)
+ || TYPE_VOLATILE (TREE_TYPE (newdecl)))
+ == (TREE_THIS_VOLATILE (olddecl)
+ || TYPE_VOLATILE (TREE_TYPE (olddecl))))
+ types_match = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (newdecl)),
+ TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)), 1);
else
- types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 1);
+ types_match = 0;
}
return types_match;
}
}
- if (DECL_THIS_INLINE (newdecl) && ! DECL_THIS_INLINE (olddecl)
- && TREE_ADDRESSABLE (olddecl))
- cp_pedwarn ("`%#D' was used before it was declared inline",
- newdecl);
+ if (DECL_THIS_INLINE (newdecl) && ! DECL_THIS_INLINE (olddecl))
+ {
+#if 0 /* I think this will be correct, but it's really annoying. We should
+ fix the compiler to find vtables by indirection so it isn't
+ necessary. (jason 8/25/95) */
+ if (DECL_VINDEX (olddecl) && ! DECL_ABSTRACT_VIRTUAL_P (olddecl))
+ {
+ cp_pedwarn ("virtual function `%#D' redeclared inline",
+ newdecl);
+ cp_pedwarn_at ("previous non-inline declaration here",
+ olddecl);
+ }
+ else
+#endif
+ if (TREE_ADDRESSABLE (olddecl))
+ {
+ cp_pedwarn ("`%#D' was used before it was declared inline",
+ newdecl);
+ cp_pedwarn_at ("previous non-inline declaration here",
+ olddecl);
+ }
+ }
}
/* These bits are logically part of the type for non-functions. */
else if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
DECL_CLASS_CONTEXT (newdecl) = DECL_CLASS_CONTEXT (olddecl);
if (DECL_CHAIN (newdecl) == NULL_TREE)
DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
- if (DECL_NEXT_METHOD (newdecl) == NULL_TREE)
- DECL_NEXT_METHOD (newdecl) = DECL_NEXT_METHOD (olddecl);
if (DECL_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0)
DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl);
DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl);
{
tree ctype = NULL_TREE;
ctype = DECL_CLASS_CONTEXT (newdecl);
- TREE_TYPE (newdecl) = build_exception_variant (ctype, newtype,
+ TREE_TYPE (newdecl) = build_exception_variant (newtype,
TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)));
- TREE_TYPE (olddecl) = build_exception_variant (ctype, newtype,
+ TREE_TYPE (olddecl) = build_exception_variant (newtype,
TYPE_RAISES_EXCEPTIONS (oldtype));
if (! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0))
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
- DECL_C_STATIC (newdecl) = DECL_C_STATIC (olddecl);
+ DECL_C_STATIC (newdecl) |= DECL_C_STATIC (olddecl);
DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl);
DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl);
}
else if (t != NULL_TREE)
{
- if (TREE_CODE (t) == PARM_DECL)
+ file = DECL_SOURCE_FILE (t);
+ line = DECL_SOURCE_LINE (t);
+ if (TREE_CODE (x) == VAR_DECL && DECL_DEAD_FOR_LOCAL (x))
+ ; /* This is OK. */
+ else if (TREE_CODE (t) == PARM_DECL)
{
if (DECL_CONTEXT (t) == NULL_TREE)
fatal ("parse errors have confused me too much");
- }
- file = DECL_SOURCE_FILE (t);
- line = DECL_SOURCE_LINE (t);
- if (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c)
+ /* Check for duplicate params. */
+ if (duplicate_decls (x, t))
+ return t;
+ }
+ else if (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c)
|| (TREE_CODE (x) == TEMPLATE_DECL
&& ! DECL_TEMPLATE_IS_CLASS (x)))
&& is_overloaded_fn (t))
#endif
if (TREE_CODE (t) == TYPE_DECL)
SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (t));
+ else if (TREE_CODE (t) == FUNCTION_DECL)
+ check_default_args (t);
return t;
}
if (b->parm_flag == 1)
cp_error ("declaration of `%#D' shadows a parameter", name);
}
+ else if (warn_shadow && oldlocal != NULL_TREE && b->is_for_scope
+ && !DECL_DEAD_FOR_LOCAL (oldlocal))
+ {
+ warning ("variable `%s' shadows local",
+ IDENTIFIER_POINTER (name));
+ cp_warning_at (" this is the shadowed declaration", oldlocal);
+ }
/* Maybe warn if shadowing something else. */
else if (warn_shadow && !DECL_EXTERNAL (x)
/* No shadow warnings for internally generated vars. */
if (oldlocal != NULL_TREE && TREE_CODE (oldlocal) == PARM_DECL)
warnstring = "declaration of `%s' shadows a parameter";
else if (IDENTIFIER_CLASS_VALUE (name) != NULL_TREE
+ && current_class_decl
&& !TREE_STATIC (name))
warnstring = "declaration of `%s' shadows a member of `this'";
else if (oldlocal != NULL_TREE)
}
if (TREE_CODE (x) == FUNCTION_DECL)
- {
- /* This is probably the wrong place to check this, but it has to
- come after the call to duplicate_decls. */
- tree arg = TYPE_ARG_TYPES (TREE_TYPE (x));
- int saw_def = 0, i = 1;
- for (; arg && arg != void_list_node; arg = TREE_CHAIN (arg), ++i)
- {
- if (TREE_PURPOSE (arg))
- saw_def = 1;
- else if (saw_def)
- {
- cp_error ("default argument missing for parameter %d of `%#D'",
- i, x);
- break;
- }
- }
- }
+ check_default_args (x);
/* Keep count of variables in this level with incomplete type. */
- if (TREE_CODE (x) != TEMPLATE_DECL
- && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
- && PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE))
- {
- if (++b->n_incomplete == 0)
- error ("too many incomplete variables at this point");
- }
-
- /* Keep count of variables in this level with incomplete type. */
- /* RTTI TD entries are created while defining the type_info. */
if (TREE_CODE (x) == VAR_DECL
&& TREE_TYPE (x) != error_mark_node
- && TYPE_LANG_SPECIFIC (TREE_TYPE (x))
- && TYPE_BEING_DEFINED (TREE_TYPE (x)))
- {
- if (++b->n_incomplete == 0)
- error ("too many incomplete variables at this point");
- }
+ && ((TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
+ && PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE))
+ /* RTTI TD entries are created while defining the type_info. */
+ || (TYPE_LANG_SPECIFIC (TREE_TYPE (x))
+ && TYPE_BEING_DEFINED (TREE_TYPE (x)))))
+ b->incomplete = tree_cons (NULL_TREE, x, b->incomplete);
}
/* Put decls on list in reverse order.
/* Definition isn't the kind we were looking for. */
cp_error ("`%#D' redeclared as %C", TREE_VALUE (tail),
form);
+ return NULL_TREE;
}
return TREE_VALUE (tail);
}
{
cp_error ("`%#D' redeclared as %C in class scope",
TREE_VALUE (tail), form);
+ return NULL_TREE;
}
return TREE_VALUE (tail);
}
if (got_scope)
type = got_scope;
- else
+ else if (got_object != error_mark_node)
type = got_object;
if (type)
push_overloaded_decl (x, 0);
}
-#define builtin_function(NAME, TYPE, CODE, LIBNAME) \
- define_function (NAME, TYPE, CODE, (void (*)())pushdecl, LIBNAME)
-
#ifdef __GNUC__
__inline
#endif
delta_identifier = get_identifier (VTABLE_DELTA_NAME);
delta2_identifier = get_identifier (VTABLE_DELTA2_NAME);
pfn_or_delta2_identifier = get_identifier ("__pfn_or_delta2");
+ if (flag_handle_signatures)
+ {
+ tag_identifier = get_identifier (SIGTABLE_TAG_NAME);
+ vb_off_identifier = get_identifier (SIGTABLE_VB_OFF_NAME);
+ vt_off_identifier = get_identifier (SIGTABLE_VT_OFF_NAME);
+ }
/* Define `int' and `char' first so that dbx will output them first. */
#if 0
/* Support for these has not been written in either expand_builtin
or build_function_call. */
- builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, 0);
- builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, 0);
+ builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, NULL_PTR);
+ builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR);
builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR,
- 0);
- builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, 0);
+ NULL_PTR);
+ builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, NULL_PTR);
builtin_function ("__builtin_fmod", double_ftype_double_double,
- BUILT_IN_FMOD, 0);
+ BUILT_IN_FMOD, NULL_PTR);
builtin_function ("__builtin_frem", double_ftype_double_double,
- BUILT_IN_FREM, 0);
+ BUILT_IN_FREM, NULL_PTR);
builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int, BUILT_IN_MEMSET,
- 0);
+ NULL_PTR);
builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
- 0);
+ NULL_PTR);
builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
- 0);
+ NULL_PTR);
#endif
/* C++ extensions */
real gc code. */
if (flag_gc)
{
- builtin_function ("__gc_main", default_function_type, NOT_BUILT_IN, 0);
+ builtin_function ("__gc_main", default_function_type, NOT_BUILT_IN, NULL_PTR);
pushdecl (lookup_name (get_identifier ("__gc_main"), 0));
}
if (flag_handle_signatures)
{
sigtable_entry_type = make_lang_type (RECORD_TYPE);
- fields[0] = build_lang_field_decl (FIELD_DECL,
- get_identifier (SIGTABLE_CODE_NAME),
- short_integer_type_node);
- fields[1] = build_lang_field_decl (FIELD_DECL,
- get_identifier (SIGTABLE_OFFSET_NAME),
- short_integer_type_node);
- fields[2] = build_lang_field_decl (FIELD_DECL,
- get_identifier (SIGTABLE_PFN_NAME),
+ fields[0] = build_lang_field_decl (FIELD_DECL, tag_identifier,
+ delta_type_node);
+ fields[1] = build_lang_field_decl (FIELD_DECL, vb_off_identifier,
+ delta_type_node);
+ fields[2] = build_lang_field_decl (FIELD_DECL, delta_identifier,
+ delta_type_node);
+ fields[3] = build_lang_field_decl (FIELD_DECL, index_identifier,
+ delta_type_node);
+ fields[4] = build_lang_field_decl (FIELD_DECL, pfn_identifier,
ptr_type_node);
- finish_builtin_type (sigtable_entry_type, SIGTABLE_PTR_TYPE, fields, 2,
- double_type_node);
+
+ /* Set the alignment to the max of the alignment of ptr_type_node and
+ delta_type_node. Double alignment wastes a word on the Sparc. */
+ finish_builtin_type (sigtable_entry_type, SIGTABLE_PTR_TYPE, fields, 4,
+ (TYPE_ALIGN (ptr_type_node) > TYPE_ALIGN (delta_type_node))
+ ? ptr_type_node
+ : delta_type_node);
+
+ /* Make this part of an invisible union. */
+ fields[5] = copy_node (fields[4]);
+ TREE_TYPE (fields[5]) = delta_type_node;
+ DECL_NAME (fields[5]) = vt_off_identifier;
+ DECL_MODE (fields[5]) = TYPE_MODE (delta_type_node);
+ DECL_SIZE (fields[5]) = TYPE_SIZE (delta_type_node);
+ TREE_UNSIGNED (fields[5]) = 0;
+ TREE_CHAIN (fields[4]) = fields[5];
+
sigtable_entry_type = build_type_variant (sigtable_entry_type, 1, 0);
record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_entry_type);
}
__i_desc_type_node = make_lang_type (RECORD_TYPE);
__m_desc_type_node = make_lang_type (RECORD_TYPE);
__t_desc_array_type =
- build_array_type (TYPE_POINTER_TO (__t_desc_type_node), NULL_TREE);
+ build_array_type (build_pointer_type (__t_desc_type_node), NULL_TREE);
__i_desc_array_type =
- build_array_type (TYPE_POINTER_TO (__i_desc_type_node), NULL_TREE);
+ build_array_type (build_pointer_type (__i_desc_type_node), NULL_TREE);
__m_desc_array_type =
- build_array_type (TYPE_POINTER_TO (__m_desc_type_node), NULL_TREE);
+ build_array_type (build_pointer_type (__m_desc_type_node), NULL_TREE);
fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
string_type_node);
unsigned_type_node);
fields[3] = build_lang_field_decl (FIELD_DECL,
get_identifier ("points_to"),
- TYPE_POINTER_TO (__t_desc_type_node));
+ build_pointer_type (__t_desc_type_node));
fields[4] = build_lang_field_decl (FIELD_DECL,
get_identifier ("ivars_count"),
integer_type_node);
fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("offset"),
integer_type_node);
fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
- TYPE_POINTER_TO (__t_desc_type_node));
+ build_pointer_type (__t_desc_type_node));
finish_builtin_type (__i_desc_type_node, "__i_desc", fields, 2,
integer_type_node);
fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("vindex"),
integer_type_node);
fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("vcontext"),
- TYPE_POINTER_TO (__t_desc_type_node));
+ build_pointer_type (__t_desc_type_node));
fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("return_type"),
- TYPE_POINTER_TO (__t_desc_type_node));
+ build_pointer_type (__t_desc_type_node));
fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("address"),
build_pointer_type (default_function_type));
fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("parm_count"),
fields[6] = build_lang_field_decl (FIELD_DECL, get_identifier ("required_parms"),
short_integer_type_node);
fields[7] = build_lang_field_decl (FIELD_DECL, get_identifier ("parm_types"),
- build_pointer_type (build_array_type (TYPE_POINTER_TO (__t_desc_type_node), NULL_TREE)));
+ build_pointer_type (build_array_type (build_pointer_type (__t_desc_type_node), NULL_TREE)));
finish_builtin_type (__m_desc_type_node, "__m_desc", fields, 7,
integer_type_node);
}
}
if (flag_cadillac)
init_cadillac ();
+ if (! SUPPORTS_WEAK)
+ flag_weak = 0;
/* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
declare_function_name ();
if (TYPE_FIELDS (t))
{
tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0,
- NULL_TREE);
+ NULL_TREE, NULL_TREE);
finish_anon_union (decl);
}
else
return typename;
return grokdeclarator (TREE_VALUE (typename),
TREE_PURPOSE (typename),
- TYPENAME, 0, NULL_TREE);
+ TYPENAME, 0, NULL_TREE, NULL_TREE);
}
/* Decode a declarator in an ordinary declaration or data definition.
used_extern_spec = 1;
}
- decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, raises);
+ decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, raises,
+ NULL_TREE);
if (decl == NULL_TREE || decl == void_type_node)
return NULL_TREE;
else if (duplicate_decls (decl, field))
decl = field;
}
-
- /* If it was not explicitly declared `extern',
- revoke any previous claims of DECL_EXTERNAL. */
- if (DECL_THIS_EXTERN (decl) == 0)
- DECL_EXTERNAL (decl) = 0;
+ else
+ {
+ tree field = check_classfn (context, NULL_TREE, decl);
+ if (field && duplicate_decls (decl, field))
+ decl = field;
+ }
+
+ /* cp_finish_decl sets DECL_EXTERNAL if DECL_IN_AGGR_P is set. */
if (DECL_LANG_SPECIFIC (decl))
DECL_IN_AGGR_P (decl) = 0;
+ if (DECL_USE_TEMPLATE (decl) || CLASSTYPE_USE_TEMPLATE (context))
+ SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+
+ /* Stupid stupid stupid stupid (jason 7/21/95) */
+ if (pedantic && DECL_EXTERNAL (decl)
+ && ! DECL_TEMPLATE_SPECIALIZATION (decl))
+ cp_pedwarn ("declaration of `%#D' outside of class is not definition",
+ decl);
+
pushclass (context, 2);
}
}
TREE_TYPE (tmp_addr) = build_pointer_type (target_type);
- DECL_INITIAL (decl) = convert (TYPE_POINTER_TO (target_type), tmp_addr);
+ DECL_INITIAL (decl) = convert (build_pointer_type (target_type), tmp_addr);
TREE_TYPE (DECL_INITIAL (decl)) = type;
if (TYPE_NEEDS_CONSTRUCTING (target_type))
{
if (TREE_CODE (tmp) == TARGET_EXPR)
{
*cleanupp = build_delete
- (TYPE_POINTER_TO (subtype),
+ (build_pointer_type (subtype),
build_unary_op (ADDR_EXPR, TREE_OPERAND (tmp, 0), 0),
integer_two_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
TREE_OPERAND (tmp, 2) = error_mark_node;
init = digest_init (type, init, (tree *) 0);
else if (TREE_CODE (init) == CONSTRUCTOR)
{
- if (TYPE_NEEDS_CONSTRUCTING (type))
+ if (TYPE_NON_AGGREGATE_CLASS (type))
{
cp_error ("`%D' must be initialized by constructor, not by `{...}'",
decl);
else
goto dont_use_constructor;
}
-#if 0
- /* fix this in `build_functional_cast' instead.
- Here's the trigger code:
-
- struct ostream
- {
- ostream ();
- ostream (int, char *);
- ostream (char *);
- operator char *();
- ostream (void *);
- operator void *();
- operator << (int);
- };
- int buf_size = 1024;
- static char buf[buf_size];
- const char *debug(int i) {
- char *b = &buf[0];
- ostream o = ostream(buf_size, b);
- o << i;
- return buf;
- }
- */
-
- else if (TREE_CODE (init) == TARGET_EXPR
- && TREE_CODE (TREE_OPERAND (init, 1) == NEW_EXPR))
- {
- /* User wrote something like `foo x = foo (args)' */
- my_friendly_assert (TREE_CODE (TREE_OPERAND (init, 0)) == VAR_DECL, 150);
- my_friendly_assert (DECL_NAME (TREE_OPERAND (init, 0)) == NULL_TREE, 151);
-
- /* User wrote exactly `foo x = foo (args)' */
- if (TYPE_MAIN_VARIANT (type) == TREE_TYPE (init))
- {
- init = build (CALL_EXPR, TREE_TYPE (init),
- TREE_OPERAND (TREE_OPERAND (init, 1), 0),
- TREE_OPERAND (TREE_OPERAND (init, 1), 1), 0);
- TREE_SIDE_EFFECTS (init) = 1;
- }
- }
-#endif
}
else
{
else if (TREE_STATIC (decl) && type != error_mark_node)
{
/* Cleanups for static variables are handled by `finish_file'. */
- if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE)
+ if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
+ || TYPE_NEEDS_DESTRUCTOR (type))
expand_static_init (decl, init);
- else if (TYPE_NEEDS_DESTRUCTOR (type))
- static_aggregates = perm_tree_cons (NULL_TREE, decl,
- static_aggregates);
/* Make entry in appropriate vector. */
if (flag_gc && type_needs_gc_entry (type))
}
else if (! toplev)
{
+ extern int temp_slot_level;
+ extern int target_temp_slot_level;
tree old_cleanups = cleanups_this_call;
+ int old_temp_level = target_temp_slot_level;
+
/* This is a declared decl which must live until the
end of the binding contour. It may need a cleanup. */
{
/* XXX: Why don't we use decl here? */
/* Ans: Because it was already expanded? */
- if (! expand_decl_cleanup (NULL_TREE, cleanup))
+ if (! cp_expand_decl_cleanup (NULL_TREE, cleanup))
cp_error ("parser lost in parsing declaration of `%D'",
decl);
/* Cleanup used up here. */
}
}
+ push_temp_slots ();
+ push_temp_slots ();
+ target_temp_slot_level = temp_slot_level;
+
if (DECL_SIZE (decl) && type != error_mark_node)
{
/* Compute and store the initial value. */
was initialized was ever used. Don't do this if it has a
destructor, so we don't complain about the 'resource
allocation is initialization' idiom. */
- if (TYPE_NEEDS_CONSTRUCTING (type) && cleanup == NULL_TREE)
+ if (TYPE_NEEDS_CONSTRUCTING (type)
+ && cleanup == NULL_TREE
+ && DECL_NAME (decl))
TREE_USED (decl) = 0;
/* Store the cleanup, if there was one. */
if (cleanup)
{
- if (! expand_decl_cleanup (decl, cleanup))
+ if (! cp_expand_decl_cleanup (decl, cleanup))
cp_error ("parser lost in parsing declaration of `%D'",
decl);
}
}
/* Cleanup any temporaries needed for the initial value. */
expand_cleanups_to (old_cleanups);
+ pop_temp_slots ();
+ pop_temp_slots ();
+ target_temp_slot_level = old_temp_level;
}
finish_end0:
due to initialization of qualified member variable.
I.e., Foo::x = 10; */
{
- tree context = DECL_CONTEXT (decl);
+ tree context = DECL_REAL_CONTEXT (decl);
if (context
&& TREE_CODE_CLASS (TREE_CODE (context)) == 't'
&& (TREE_CODE (decl) == VAR_DECL
tree init;
{
tree oldstatic = value_member (decl, static_aggregates);
- tree old_cleanups;
if (oldstatic)
{
/* Emit code to perform this initialization but once. */
tree temp;
+ extern int temp_slot_level;
+ extern int target_temp_slot_level;
+ tree old_cleanups;
+ int old_temp_level;
+
/* Remember this information until end of file. */
push_obstacks (&permanent_obstack, &permanent_obstack);
expand_start_cond (build_binary_op (EQ_EXPR, temp,
integer_zero_node, 1), 0);
old_cleanups = cleanups_this_call;
+ old_temp_level = target_temp_slot_level;
+ push_temp_slots ();
+ push_temp_slots ();
+ target_temp_slot_level = temp_slot_level;
+
expand_assignment (temp, integer_one_node, 0, 0);
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
- || TREE_CODE (init) == TREE_LIST)
+ || (init && TREE_CODE (init) == TREE_LIST))
{
expand_aggr_init (decl, init, 0, 0);
do_pending_stack_adjust ();
}
- else
+ else if (init)
expand_assignment (decl, init, 0, 0);
+
/* Cleanup any temporaries needed for the initial value. */
expand_cleanups_to (old_cleanups);
+ pop_temp_slots ();
+ pop_temp_slots ();
+ target_temp_slot_level = old_temp_level;
+
+ if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
+ {
+ tree cleanup, fcall;
+ static tree Atexit = 0;
+ if (Atexit == 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));
+
+ pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
+
+ push_lang_context (lang_name_c);
+ atexit_fndecl =
+ builtin_function ("atexit",
+ build_function_type (void_type_node,
+ pfvlist),
+ NOT_BUILT_IN, NULL_PTR);
+ assemble_external (atexit_fndecl);
+ Atexit = default_conversion (atexit_fndecl);
+ pop_lang_context ();
+ pop_obstacks ();
+ }
+
+ cleanup = start_anon_func ();
+ expand_expr_stmt (build_cleanup (decl));
+ end_anon_func ();
+ mark_addressable (cleanup);
+ cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
+ fcall = build_function_call (Atexit, tree_cons (NULL_TREE, cleanup, NULL_TREE));
+ expand_expr_stmt (fcall);
+ }
+
expand_end_cond ();
if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
{
tree itype;
TYPE_DOMAIN (type) = build_index_type (maxindex);
- if (!TREE_TYPE (maxindex))
+ if (! TREE_TYPE (maxindex))
TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
if (initial_value)
itype = TREE_TYPE (initial_value);
itype = NULL;
if (itype && !TYPE_DOMAIN (itype))
TYPE_DOMAIN (itype) = TYPE_DOMAIN (type);
+ /* The type of the main variant should never be used for arrays
+ of different sizes. It should only ever be completed with the
+ size of the array. */
+ if (! TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)))
+ TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)) = TYPE_DOMAIN (type);
}
/* Lay out the type now that we can get the real answer. */
not look, and -1 if we should not call `grokclassfn' at all. */
static tree
grokfndecl (ctype, type, declarator, virtualp, flags, quals,
- raises, check, publicp, inlinep)
+ raises, attrlist, check, publicp, inlinep)
tree ctype, type;
tree declarator;
int virtualp;
enum overload_flags flags;
- tree quals, raises;
+ tree quals, raises, attrlist;
int check, publicp, inlinep;
{
tree cname, decl;
if (raises)
{
- type = build_exception_variant (ctype, type, raises);
+ type = build_exception_variant (type, raises);
raises = TYPE_RAISES_EXCEPTIONS (type);
}
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
/* avoid creating circularities. */
DECL_CHAIN (decl) = NULL_TREE;
}
+
+ if (attrlist)
+ cplus_decl_attributes (decl, TREE_PURPOSE (attrlist),
+ TREE_VALUE (attrlist));
make_decl_rtl (decl, NULL_PTR, 1);
}
type = build_cplus_method_type (base_variant, TREE_TYPE (type), argtypes);
if (raises)
{
- type = build_exception_variant (ctype, type, raises);
+ type = build_exception_variant (type, raises);
raises = TYPE_RAISES_EXCEPTIONS (type);
}
TREE_TYPE (decl) = type;
else if (toplevel_bindings_p ())
{
TREE_PUBLIC (decl) = (RIDBIT_NOTSETP (RID_STATIC, specbits)
- && (DECL_EXTERNAL (decl) || ! constp));
+ && (DECL_THIS_EXTERN (decl) || ! constp));
TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
}
/* Not at top level, only `static' makes a static definition. */
push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
u = make_lang_type (UNION_TYPE);
+ IS_AGGR_TYPE (u) = 0;
fields[0] = build_lang_field_decl (FIELD_DECL, pfn_identifier, type);
fields[1] = build_lang_field_decl (FIELD_DECL, delta2_identifier,
delta_type_node);
enum return_types { return_normal, return_ctor, return_dtor, return_conversion };
tree
-grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
+grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrlist)
tree declspecs;
tree declarator;
enum decl_context decl_context;
int initialized;
- tree raises;
+ tree raises, attrlist;
{
RID_BIT_TYPE specbits;
int nclasses = 0;
/* Look inside a declarator for the name being declared
and get it as a string, for an error message. */
{
- tree last = NULL_TREE;
- register tree decl = declarator;
+ tree *next = &declarator;
+ register tree decl;
name = NULL;
- while (decl)
- switch (TREE_CODE (decl))
- {
- case COND_EXPR:
- ctype = NULL_TREE;
- decl = TREE_OPERAND (decl, 0);
- break;
-
- case BIT_NOT_EXPR: /* for C++ destructors! */
+ while (next && *next)
+ {
+ decl = *next;
+ switch (TREE_CODE (decl))
{
- tree name = TREE_OPERAND (decl, 0);
- tree rename = NULL_TREE;
-
- my_friendly_assert (flags == NO_SPECIAL, 152);
- flags = DTOR_FLAG;
- return_type = return_dtor;
- my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153);
- if (ctype == NULL_TREE)
- {
- if (current_class_type == NULL_TREE)
- {
- error ("destructors must be member functions");
- flags = NO_SPECIAL;
- }
- else
- {
- tree t = constructor_name (current_class_name);
- if (t != name)
- rename = t;
- }
- }
- else
- {
- tree t = constructor_name (ctype);
- if (t != name)
- rename = t;
- }
-
- if (rename)
- {
- error ("destructor `%s' must match class name `%s'",
- IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (rename));
- TREE_OPERAND (decl, 0) = rename;
- }
- decl = name;
- }
- break;
-
- case ADDR_EXPR: /* C++ reference declaration */
- /* fall through */
- case ARRAY_REF:
- case INDIRECT_REF:
- ctype = NULL_TREE;
- innermost_code = TREE_CODE (decl);
- last = decl;
- decl = TREE_OPERAND (decl, 0);
- break;
+ case COND_EXPR:
+ ctype = NULL_TREE;
+ next = &TREE_OPERAND (decl, 0);
+ break;
- case CALL_EXPR:
- if (parmlist_is_exprlist (TREE_OPERAND (decl, 1)))
+ case BIT_NOT_EXPR: /* for C++ destructors! */
{
- /* This is actually a variable declaration using constructor
- syntax. We need to call start_decl and cp_finish_decl so we
- can get the variable initialized... */
-
- if (last)
- /* We need to insinuate ourselves into the declarator in place
- of the CALL_EXPR. */
- TREE_OPERAND (last, 0) = TREE_OPERAND (decl, 0);
+ tree name = TREE_OPERAND (decl, 0);
+ tree rename = NULL_TREE;
+
+ my_friendly_assert (flags == NO_SPECIAL, 152);
+ flags = DTOR_FLAG;
+ return_type = return_dtor;
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153);
+ if (ctype == NULL_TREE)
+ {
+ if (current_class_type == NULL_TREE)
+ {
+ error ("destructors must be member functions");
+ flags = NO_SPECIAL;
+ }
+ else
+ {
+ tree t = constructor_name (current_class_name);
+ if (t != name)
+ rename = t;
+ }
+ }
else
- declarator = TREE_OPERAND (decl, 0);
-
- init = TREE_OPERAND (decl, 1);
-
- decl = start_decl (declarator, declspecs, 1, NULL_TREE);
- finish_decl (decl, init, NULL_TREE);
- return 0;
- }
- innermost_code = TREE_CODE (decl);
- if (decl_context == FIELD && ctype == NULL_TREE)
- ctype = current_class_type;
- if (ctype
- && TREE_OPERAND (decl, 0) == constructor_name_full (ctype))
- TREE_OPERAND (decl, 0) = constructor_name (ctype);
- decl = TREE_OPERAND (decl, 0);
- if (ctype != NULL_TREE
- && decl != NULL_TREE && flags != DTOR_FLAG
- && decl == constructor_name (ctype))
- {
- return_type = return_ctor;
- ctor_return_type = ctype;
- }
- ctype = NULL_TREE;
- break;
-
- case IDENTIFIER_NODE:
- dname = decl;
- decl = NULL_TREE;
+ {
+ tree t = constructor_name (ctype);
+ if (t != name)
+ rename = t;
+ }
- if (! IDENTIFIER_OPNAME_P (dname)
- /* Linux headers use '__op'. Arrgh. */
- || IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname))
- name = IDENTIFIER_POINTER (dname);
- else
- {
- if (IDENTIFIER_TYPENAME_P (dname))
+ if (rename)
{
- my_friendly_assert (flags == NO_SPECIAL, 154);
- flags = TYPENAME_FLAG;
- ctor_return_type = TREE_TYPE (dname);
- return_type = return_conversion;
+ error ("destructor `%s' must match class name `%s'",
+ IDENTIFIER_POINTER (name),
+ IDENTIFIER_POINTER (rename));
+ TREE_OPERAND (decl, 0) = rename;
}
- name = operator_name_string (dname);
+ next = &name;
}
- break;
+ break;
- case RECORD_TYPE:
- case UNION_TYPE:
- case ENUMERAL_TYPE:
- /* Parse error puts this typespec where
- a declarator should go. */
- error ("declarator name missing");
- dname = TYPE_NAME (decl);
- if (dname && TREE_CODE (dname) == TYPE_DECL)
- dname = DECL_NAME (dname);
- name = dname ? IDENTIFIER_POINTER (dname) : "<nameless>";
- declspecs = temp_tree_cons (NULL_TREE, decl, declspecs);
- decl = NULL_TREE;
- break;
+ case ADDR_EXPR: /* C++ reference declaration */
+ /* fall through */
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ ctype = NULL_TREE;
+ innermost_code = TREE_CODE (decl);
+ next = &TREE_OPERAND (decl, 0);
+ break;
- /* C++ extension */
- case SCOPE_REF:
- {
- /* Perform error checking, and convert class names to types.
- We may call grokdeclarator multiple times for the same
- tree structure, so only do the conversion once. In this
- case, we have exactly what we want for `ctype'. */
- tree cname = TREE_OPERAND (decl, 0);
- if (cname == NULL_TREE)
- ctype = NULL_TREE;
- /* Can't use IS_AGGR_TYPE because CNAME might not be a type. */
- else if (IS_AGGR_TYPE_CODE (TREE_CODE (cname))
- || TREE_CODE (cname) == UNINSTANTIATED_P_TYPE)
- ctype = cname;
- else if (! is_aggr_typedef (cname, 1))
+ case CALL_EXPR:
+ if (parmlist_is_exprlist (TREE_OPERAND (decl, 1)))
{
- TREE_OPERAND (decl, 0) = NULL_TREE;
+ /* This is actually a variable declaration using constructor
+ syntax. We need to call start_decl and cp_finish_decl so we
+ can get the variable initialized... */
+
+ *next = TREE_OPERAND (decl, 0);
+ init = TREE_OPERAND (decl, 1);
+
+ decl = start_decl (declarator, declspecs, 1, NULL_TREE);
+ finish_decl (decl, init, NULL_TREE);
+ return 0;
}
- /* Must test TREE_OPERAND (decl, 1), in case user gives
- us `typedef (class::memfunc)(int); memfunc *memfuncptr;' */
- else if (TREE_OPERAND (decl, 1)
- && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF)
+ innermost_code = TREE_CODE (decl);
+ if (decl_context == FIELD && ctype == NULL_TREE)
+ ctype = current_class_type;
+ if (ctype && TREE_OPERAND (decl, 0) == ctype)
+ TREE_OPERAND (decl, 0) = constructor_name (ctype);
+ next = &TREE_OPERAND (decl, 0);
+ decl = *next;
+ if (ctype != NULL_TREE
+ && decl != NULL_TREE && flags != DTOR_FLAG
+ && decl == constructor_name (ctype))
{
- TREE_OPERAND (decl, 0) = IDENTIFIER_TYPE_VALUE (cname);
+ return_type = return_ctor;
+ ctor_return_type = ctype;
}
- else if (ctype == NULL_TREE)
+ ctype = NULL_TREE;
+ break;
+
+ case IDENTIFIER_NODE:
+ dname = decl;
+ next = 0;
+
+ if (is_rid (dname))
{
- ctype = IDENTIFIER_TYPE_VALUE (cname);
- TREE_OPERAND (decl, 0) = ctype;
+ cp_error ("declarator-id missing; using reserved word `%D'",
+ dname);
+ name = IDENTIFIER_POINTER (dname);
}
- else if (TREE_COMPLEXITY (decl) == current_class_depth)
- TREE_OPERAND (decl, 0) = ctype;
+ if (! IDENTIFIER_OPNAME_P (dname)
+ /* Linux headers use '__op'. Arrgh. */
+ || IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname))
+ name = IDENTIFIER_POINTER (dname);
else
{
- if (! UNIQUELY_DERIVED_FROM_P (IDENTIFIER_TYPE_VALUE (cname),
- ctype))
+ if (IDENTIFIER_TYPENAME_P (dname))
{
- cp_error ("type `%T' is not derived from type `%T'",
- IDENTIFIER_TYPE_VALUE (cname), ctype);
- TREE_OPERAND (decl, 0) = NULL_TREE;
- }
- else
- {
- ctype = IDENTIFIER_TYPE_VALUE (cname);
- TREE_OPERAND (decl, 0) = ctype;
+ my_friendly_assert (flags == NO_SPECIAL, 154);
+ flags = TYPENAME_FLAG;
+ ctor_return_type = TREE_TYPE (dname);
+ return_type = return_conversion;
}
+ name = operator_name_string (dname);
}
+ break;
- if (ctype
- && TREE_OPERAND (decl, 1) == constructor_name_full (ctype))
- TREE_OPERAND (decl, 1) = constructor_name (ctype);
- decl = TREE_OPERAND (decl, 1);
- if (ctype)
+ /* C++ extension */
+ case SCOPE_REF:
+ {
+ /* Perform error checking, and decide on a ctype. */
+ tree cname = TREE_OPERAND (decl, 0);
+ if (cname == NULL_TREE)
+ ctype = NULL_TREE;
+ else if (! is_aggr_type (cname, 1))
+ TREE_OPERAND (decl, 0) = NULL_TREE;
+ /* Must test TREE_OPERAND (decl, 1), in case user gives
+ us `typedef (class::memfunc)(int); memfunc *memfuncptr;' */
+ else if (TREE_OPERAND (decl, 1)
+ && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF)
+ ctype = cname;
+ else if (ctype == NULL_TREE)
+ ctype = cname;
+ else if (TREE_COMPLEXITY (decl) == current_class_depth)
+ TREE_OPERAND (decl, 0) = ctype;
+ else
+ {
+ if (! UNIQUELY_DERIVED_FROM_P (cname, ctype))
+ {
+ cp_error ("type `%T' is not derived from type `%T'",
+ cname, ctype);
+ TREE_OPERAND (decl, 0) = NULL_TREE;
+ }
+ else
+ ctype = cname;
+ }
+
+ if (ctype
+ && TREE_OPERAND (decl, 1) == constructor_name_full (ctype))
+ TREE_OPERAND (decl, 1) = constructor_name (ctype);
+ next = &TREE_OPERAND (decl, 1);
+ decl = *next;
+ if (ctype)
+ {
+ if (TREE_CODE (decl) == IDENTIFIER_NODE
+ && constructor_name (ctype) == decl)
+ {
+ return_type = return_ctor;
+ ctor_return_type = ctype;
+ }
+ else if (TREE_CODE (decl) == BIT_NOT_EXPR
+ && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
+ && (constructor_name (ctype) == TREE_OPERAND (decl, 0)
+ || constructor_name_full (ctype) == TREE_OPERAND (decl, 0)))
+ {
+ return_type = return_dtor;
+ ctor_return_type = ctype;
+ flags = DTOR_FLAG;
+ TREE_OPERAND (decl, 0) = constructor_name (ctype);
+ next = &TREE_OPERAND (decl, 0);
+ }
+ }
+ }
+ break;
+
+ case ERROR_MARK:
+ next = 0;
+ break;
+
+ default:
+ if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't')
{
- if (TREE_CODE (decl) == IDENTIFIER_NODE
- && constructor_name (ctype) == decl)
- {
- return_type = return_ctor;
- ctor_return_type = ctype;
- }
- else if (TREE_CODE (decl) == BIT_NOT_EXPR
- && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
- && (constructor_name (ctype) == TREE_OPERAND (decl, 0)
- || constructor_name_full (ctype) == TREE_OPERAND (decl, 0)))
- {
- return_type = return_dtor;
- ctor_return_type = ctype;
- flags = DTOR_FLAG;
- decl = TREE_OPERAND (decl, 0) = constructor_name (ctype);
- }
+ /* Parse error puts this typespec where
+ a declarator should go. */
+ error ("typename specified as declarator-id");
+ if (current_class_type)
+ cp_error (" perhaps you want `%T' for a constructor",
+ current_class_name);
+ dname = TYPE_IDENTIFIER (decl);
+ name = dname ? IDENTIFIER_POINTER (dname) : "<nameless>";
+ declspecs = temp_tree_cons (NULL_TREE, integer_type_node,
+ declspecs);
+ *next = dname;
+ next = 0;
+ break;
}
+ cp_compiler_error ("`%D' as declarator", decl);
+ return 0; /* We used to do a 155 abort here. */
}
- break;
-
- case ERROR_MARK:
- decl = NULL_TREE;
- break;
-
- default:
- return 0; /* We used to do a 155 abort here. */
- }
+ }
if (name == NULL)
name = "type name";
}
if (return_type == return_dtor)
type = void_type_node;
else if (return_type == return_ctor)
- type = TYPE_POINTER_TO (ctor_return_type);
+ type = build_pointer_type (ctor_return_type);
else if (return_type == return_conversion)
type = ctor_return_type;
else if (current_class_type
else if (return_type == return_ctor)
{
error ("return type specification for constructor invalid");
- type = TYPE_POINTER_TO (ctor_return_type);
+ type = build_pointer_type (ctor_return_type);
}
else if (return_type == return_conversion)
{
error ("non-object member `%s' cannot be declared `mutable'", name);
RIDBIT_RESET (RID_MUTABLE, specbits);
}
- else if (constp)
- {
- error ("const `%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);
- }
#if 0
if (RIDBIT_SETP (RID_TYPEDEF, specbits))
{
SIGNATURE_GROKKING_TYPEDEF (current_class_type) = 1;
loc_typedecl =
- grokdeclarator (declarator, declspecs, FIELD, 0, NULL_TREE);
+ grokdeclarator (declarator, declspecs, FIELD, 0, NULL_TREE, NULL_TREE);
if (previous_declspec)
TREE_CHAIN (previous_declspec) = scanner;
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);
if (RIDBIT_ANY_SET (tmp_bits))
error ("return value type specifier for constructor ignored");
}
- type = TYPE_POINTER_TO (ctype);
+ type = build_pointer_type (ctype);
if (decl_context == FIELD &&
IS_SIGNATURE (current_class_type))
{
/* If this is declaring a typedef name, return a TYPE_DECL. */
+ if (RIDBIT_SETP (RID_MUTABLE, specbits))
+ {
+ if (constp)
+ {
+ error ("const `%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);
+ }
+ }
+
if (RIDBIT_SETP (RID_TYPEDEF, specbits))
{
tree decl;
{
int publicp = 0;
+ /* We catch the others as conflicts with the builtin
+ typedefs. */
+ if (friendp && declarator == ridpointers[(int) RID_SIGNED])
+ {
+ cp_error ("function `%D' cannot be declared friend",
+ declarator);
+ friendp = 0;
+ }
+
if (friendp == 0)
{
if (ctype == NULL_TREE)
|| RIDBIT_SETP (RID_EXTERN, specbits)
|| ! (funcdef_flag < 0 || inlinep));
decl = grokfndecl (ctype, type, declarator,
- virtualp, flags, quals,
- raises, friendp ? -1 : 0, publicp, inlinep);
+ virtualp, flags, quals, raises, attrlist,
+ friendp ? -1 : 0, publicp, inlinep);
if (decl == NULL_TREE)
return NULL_TREE;
decl = build_decl_attribute_variant (decl, decl_machine_attr);
/* All method decls are public, so tell grokfndecl to set
TREE_PUBLIC, also. */
decl = grokfndecl (ctype, type, declarator,
- virtualp, flags, quals,
- raises, friendp ? -1 : 0, 1, 0);
+ virtualp, flags, quals, raises, attrlist,
+ friendp ? -1 : 0, 1, 0);
if (decl == NULL_TREE)
return NULL_TREE;
}
if (staticp || (constp && initialized))
{
+ /* ANSI C++ Apr '95 wp 9.2 */
+ if (staticp && declarator == current_class_name)
+ cp_pedwarn ("ANSI C++ forbids static member `%D' with same name as enclosing class",
+ declarator);
+
/* C++ allows static class members.
All other work for this is done by grokfield.
This VAR_DECL is built by build_lang_field_decl.
&& !RIDBIT_SETP (RID_INLINE, specbits)));
decl = grokfndecl (ctype, type, original_name,
- virtualp, flags, quals,
- raises,
+ virtualp, flags, quals, raises, attrlist,
processing_template_decl ? 0 : friendp ? 2 : 1,
publicp, inlinep);
if (decl == NULL_TREE)
DECL_CONTEXT (decl) = ctype;
if (staticp == 1)
{
- cp_error ("static member `%D' re-declared as static",
- decl);
+ cp_pedwarn ("static member `%D' re-declared as static", decl);
staticp = 0;
RIDBIT_RESET (RID_STATIC, specbits);
}
cp_error ("static member `%D' declared `register'", decl);
RIDBIT_RESET (RID_REGISTER, specbits);
}
- if (RIDBIT_SETP (RID_EXTERN, specbits))
+ if (RIDBIT_SETP (RID_EXTERN, specbits) && pedantic)
{
- cp_error ("cannot explicitly declare member `%#D' to have extern linkage",
- decl);
+ cp_pedwarn ("cannot explicitly declare member `%#D' to have extern linkage",
+ decl);
RIDBIT_RESET (RID_EXTERN, specbits);
}
}
/* @@ May need to fetch out a `raises' here. */
decl = grokdeclarator (TREE_VALUE (decl),
TREE_PURPOSE (decl),
- PARM, init != NULL_TREE, NULL_TREE);
+ PARM, init != NULL_TREE,
+ NULL_TREE, NULL_TREE);
if (! decl)
continue;
type = TREE_TYPE (decl);
/* If a cross reference is requested, look up the type
already defined for this tag and return it. */
- t = IDENTIFIER_TYPE_VALUE (name);
+ if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
+ {
+ t = name;
+ name = TYPE_NESTED_NAME (t);
+ }
+ else
+ t = IDENTIFIER_TYPE_VALUE (name);
if (t && TREE_CODE (t) != code)
t = NULL_TREE;
{
/* The base of a derived struct is public by default. */
int via_public
- = (TREE_PURPOSE (binfo) == (tree)access_public
- || TREE_PURPOSE (binfo) == (tree)access_public_virtual
+ = (TREE_PURPOSE (binfo) == access_public_node
+ || TREE_PURPOSE (binfo) == access_public_virtual_node
|| (tag_code != class_type
- && (TREE_PURPOSE (binfo) == (tree)access_default
- || TREE_PURPOSE (binfo) == (tree)access_default_virtual)));
- int via_protected = TREE_PURPOSE (binfo) == (tree)access_protected;
+ && (TREE_PURPOSE (binfo) == access_default_node
+ || TREE_PURPOSE (binfo) == access_default_virtual_node)));
+ int via_protected = TREE_PURPOSE (binfo) == access_protected_node;
int via_virtual
- = (TREE_PURPOSE (binfo) == (tree)access_private_virtual
- || TREE_PURPOSE (binfo) == (tree)access_public_virtual
- || TREE_PURPOSE (binfo) == (tree)access_default_virtual);
- tree basetype = TREE_TYPE (TREE_VALUE (binfo));
+ = (TREE_PURPOSE (binfo) == access_private_virtual_node
+ || TREE_PURPOSE (binfo) == access_public_virtual_node
+ || TREE_PURPOSE (binfo) == access_default_virtual_node);
+ tree basetype = TREE_VALUE (binfo);
tree base_binfo;
GNU_xref_hier (IDENTIFIER_POINTER (name),
@@ something we had previously. */
int
-start_function (declspecs, declarator, raises, pre_parsed_p)
- tree declarator, declspecs, raises;
+start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
+ tree declspecs, declarator, raises, attrs;
int pre_parsed_p;
{
tree decl1, olddecl;
protect_list = NULL_TREE;
current_base_init_list = NULL_TREE;
current_member_init_list = NULL_TREE;
+ ctor_label = dtor_label = NULL_TREE;
clear_temp_name ();
cp_error_at ("previous declaration here", IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl1)));
}
+ /* This can happen if a template class is instantiated as part of the
+ specialization of a member function which is defined in the class
+ template. We should just use the specialization, but for now give an
+ error. */
+ if (DECL_INITIAL (decl1) != NULL_TREE)
+ {
+ cp_error_at ("specialization of `%#D' not supported", decl1);
+ cp_error ("when defined in the class template body", decl1);
+ }
+
last_function_parms = DECL_ARGUMENTS (decl1);
last_function_parm_tags = NULL_TREE;
fntype = TREE_TYPE (decl1);
/* In a fcn definition, arg types must be complete. */
require_complete_types_for_parms (last_function_parms);
+
+ /* In case some arg types were completed since the declaration was
+ parsed, fix up the decls. */
+ {
+ tree t = last_function_parms;
+ for (; t; t = TREE_CHAIN (t))
+ layout_decl (t, 0);
+ }
}
else
{
- decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, raises);
+ decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, raises,
+ NULL_TREE);
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) return 0;
TREE_TYPE (decl1)
= build_function_type (void_type_node,
TYPE_ARG_TYPES (TREE_TYPE (decl1)));
- DECL_RESULT (decl1) = build_decl (RESULT_DECL, 0, TREE_TYPE (fntype));
+ DECL_RESULT (decl1)
+ = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (fntype)));
+ TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (TREE_TYPE (fntype));
+ TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (TREE_TYPE (fntype));
}
if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype))
GNU_xref_function (decl1, current_function_parms);
+ if (attrs)
+ cplus_decl_attributes (decl1, NULL_TREE, attrs);
make_function_rtl (decl1);
/* Allocate further tree nodes temporarily during compilation
restype = integer_type_node;
}
if (DECL_RESULT (decl1) == NULL_TREE)
- DECL_RESULT (decl1) = build_decl (RESULT_DECL, 0, restype);
+ {
+ DECL_RESULT (decl1)
+ = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype));
+ TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (restype);
+ TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (restype);
+ }
- if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1)))
+ 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;
return 1;
}
\f
+void
+expand_start_early_try_stmts ()
+{
+ rtx insns;
+ start_sequence ();
+ expand_start_try_stmts ();
+ insns = get_insns ();
+ end_sequence ();
+ store_in_parms (insns);
+}
+
+void
+store_in_parms (insns)
+ rtx insns;
+{
+ rtx last_parm_insn;
+
+ last_parm_insn = get_first_nonparm_insn ();
+ if (last_parm_insn == NULL_RTX)
+ emit_insns (insns);
+ else
+ emit_insns_before (insns, previous_insn (last_parm_insn));
+}
+
/* Store the parameter declarations into the current function declaration.
This is called after parsing the parameter declarations, before
digesting the body of the function.
if (cleanup)
{
expand_decl (parm);
- if (! expand_decl_cleanup (parm, cleanup))
+ if (! cp_expand_decl_cleanup (parm, cleanup))
cp_error ("parser lost in parsing declaration of `%D'",
parm);
parms_have_cleanups = 1;
if (flag_gc)
{
maybe_gc_cleanup = build_tree_list (NULL_TREE, error_mark_node);
- if (! expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup))
+ if (! cp_expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup))
cp_error ("parser lost in parsing declaration of `%D'", fndecl);
}
output_builtin_tdesc_entries ();
#endif
}
+
+ /* Take care of exception handling things. */
+ if (flag_handle_exceptions)
+ {
+ rtx insns;
+ start_sequence ();
+
+ /* Mark the start of a stack unwinder if we need one. */
+ start_eh_unwinder ();
+
+ /* Do the starting of the exception specifications, if we have any. */
+ if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
+ expand_start_eh_spec ();
+
+ insns = get_insns ();
+ end_sequence ();
+
+ if (insns)
+ store_in_parms (insns);
+ }
+ last_dtor_insn = get_last_insn ();
}
/* Bind a name and initialization to the return value of
{
register tree fndecl = current_function_decl;
tree fntype, ctype = NULL_TREE;
- rtx head, last_parm_insn, mark;
+ rtx 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;
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,
/* If this destructor is empty, then we don't need to check
whether `this' is NULL in some cases. */
- mark = get_last_insn ();
- last_parm_insn = get_first_nonparm_insn ();
-
if ((flag_this_is_variable & 1) == 0)
ok_to_optimize_dtor = 1;
- else if (mark == last_parm_insn)
+ else if (empty_dtor)
ok_to_optimize_dtor
= (n_baseclasses == 0
|| (n_baseclasses == 1
{
if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
{
- tree ptr = convert_pointer_to_vbase (vbases, current_class_decl);
- expand_expr_stmt (build_delete (TYPE_POINTER_TO (BINFO_TYPE (vbases)),
+ tree ptr = convert_pointer_to_vbase (BINFO_TYPE (vbases), current_class_decl);
+ expand_expr_stmt (build_delete (build_pointer_type (BINFO_TYPE (vbases)),
ptr, integer_zero_node,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_HAS_IN_CHARGE, 0));
}
exprstmt =
build_method_call
(build_indirect_ref
- (build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type),
+ (build1 (NOP_EXPR, build_pointer_type (current_class_type),
error_mark_node),
NULL_PTR),
ansi_opname[(int) DELETE_EXPR],
/* Back to the top of destructor. */
/* Dont execute destructor code if `this' is NULL. */
- mark = get_last_insn ();
- last_parm_insn = get_first_nonparm_insn ();
- if (last_parm_insn == NULL_RTX)
- last_parm_insn = mark;
- else
- last_parm_insn = previous_insn (last_parm_insn);
- /* 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_decl);
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- expand_indirect_vtbls_init (binfo, C_C_D, current_class_decl, 0);
+ 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_decl);
+
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ expand_indirect_vtbls_init (binfo, C_C_D, current_class_decl, 0);
+ }
+
if (! ok_to_optimize_dtor)
{
cond = build_binary_op (NE_EXPR,
current_class_decl, integer_zero_node, 1);
expand_start_cond (cond, 0);
}
- if (mark != get_last_insn ())
- reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
+
+ insns = get_insns ();
+ end_sequence ();
+
+ last_parm_insn = get_first_nonparm_insn ();
+ if (last_parm_insn == NULL_RTX)
+ last_parm_insn = get_last_insn ();
+ else
+ last_parm_insn = previous_insn (last_parm_insn);
+
+ emit_insns_after (insns, last_parm_insn);
+
if (! ok_to_optimize_dtor)
expand_end_cond ();
}
CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
- /* must keep the first insn safe. */
- head = get_insns ();
-
- /* this note will come up to the top with us. */
- mark = get_last_insn ();
+ start_sequence ();
if (flag_this_is_variable > 0)
{
base_init_expr = NULL_TREE;
}
+ insns = get_insns ();
+ end_sequence ();
+
/* This is where the body of the constructor begins.
If there were no insns in this function body, then the
last_parm_insn is also the last insn.
we don't hold on to it (across emit_base_init). */
last_parm_insn = get_first_nonparm_insn ();
if (last_parm_insn == NULL_RTX)
- last_parm_insn = mark;
+ last_parm_insn = get_last_insn ();
else
last_parm_insn = previous_insn (last_parm_insn);
- if (mark != get_last_insn ())
- reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
+ emit_insns_after (insns, last_parm_insn);
end_protect_partials ();
expand_function_end (input_filename, lineno, 1);
if (flag_handle_exceptions)
- expand_exception_blocks();
+ expand_exception_blocks ();
/* This must come after expand_function_end because cleanups might
have declarations (from inline functions) that need to go into
}
named_label_uses = NULL_TREE;
+ current_class_decl = NULL_TREE;
}
\f
/* Create the FUNCTION_DECL for a function definition.
start_method (declspecs, declarator, raises)
tree declarator, declspecs, raises;
{
- tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, raises);
+ tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, raises,
+ NULL_TREE);
/* Something too ugly to handle. */
if (fndecl == NULL_TREE)
hack_incomplete_structures (type)
tree type;
{
- tree decl;
+ tree *list;
- if (current_binding_level->n_incomplete == 0)
+ if (current_binding_level->incomplete == NULL_TREE)
return;
if (!type) /* Don't do this for class templates. */
return;
- for (decl = current_binding_level->names; decl; decl = TREE_CHAIN (decl))
- if (TREE_TYPE (decl) == type
- || (TREE_TYPE (decl)
- && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
- && TREE_TYPE (TREE_TYPE (decl)) == type))
- {
- if (TREE_CODE (decl) == TYPE_DECL)
- layout_type (TREE_TYPE (decl));
- else
- {
- int toplevel = toplevel_bindings_p ();
- if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
- && TREE_TYPE (TREE_TYPE (decl)) == type)
- layout_type (TREE_TYPE (decl));
- layout_decl (decl, 0);
- rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0);
- if (! toplevel)
- {
- tree cleanup;
- expand_decl (decl);
- cleanup = maybe_build_cleanup (decl);
- expand_decl_init (decl);
- if (! expand_decl_cleanup (decl, cleanup))
- cp_error ("parser lost in parsing declaration of `%D'",
- decl);
- }
- }
- /*
- my_friendly_assert (current_binding_level->n_incomplete > 0, 164);
- */
- --current_binding_level->n_incomplete;
- }
+ for (list = ¤t_binding_level->incomplete; *list; )
+ {
+ tree decl = TREE_VALUE (*list);
+ if (decl && TREE_TYPE (decl) == type
+ || (TREE_TYPE (decl)
+ && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+ && TREE_TYPE (TREE_TYPE (decl)) == type))
+ {
+ int toplevel = toplevel_bindings_p ();
+ if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+ && TREE_TYPE (TREE_TYPE (decl)) == type)
+ layout_type (TREE_TYPE (decl));
+ layout_decl (decl, 0);
+ rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0);
+ if (! toplevel)
+ {
+ tree cleanup;
+ expand_decl (decl);
+ cleanup = maybe_build_cleanup (decl);
+ expand_decl_init (decl);
+ if (! cp_expand_decl_cleanup (decl, cleanup))
+ cp_error ("parser lost in parsing declaration of `%D'",
+ decl);
+ }
+ *list = TREE_CHAIN (*list);
+ }
+ else
+ list = &TREE_CHAIN (*list);
+ }
}
-/* Nonzero if presently building a cleanup. Needed because
- SAVE_EXPRs are not the right things to use inside of cleanups.
- They are only ever evaluated once, where the cleanup
- might be evaluated several times. In this case, a later evaluation
- of the cleanup might fill in the SAVE_EXPR_RTL, and it will
- not be valid for an earlier cleanup. */
-
-int building_cleanup;
-
/* If DECL is of a type which needs a cleanup, build that cleanup here.
We don't build cleanups if just going for syntax checking, since
fixup_cleanups does not know how to not handle them.
{
int temp = 0, flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
tree rval;
- int old_building_cleanup = building_cleanup;
- building_cleanup = 1;
if (TREE_CODE (decl) != PARM_DECL)
temp = suspend_momentary ();
rval = build_compound_expr (tree_cons (NULL_TREE, rval,
build_tree_list (NULL_TREE, build_vbase_delete (type, decl))));
+ /* Since this is a cleanup, UNSAVE it now. */
+ rval = unsave_expr (rval);
+
if (TREE_CODE (decl) != PARM_DECL)
resume_momentary (temp);
- building_cleanup = old_building_cleanup;
-
return rval;
}
return 0;
cplus_expand_expr_stmt (exp)
tree exp;
{
+ extern int temp_slot_level;
+ extern int target_temp_slot_level;
+ tree old_cleanups = cleanups_this_call;
+ int old_temp_level = target_temp_slot_level;
+ push_temp_slots ();
+ push_temp_slots ();
+ target_temp_slot_level = temp_slot_level;
+
if (TREE_TYPE (exp) == unknown_type_node)
{
if (TREE_CODE (exp) == ADDR_EXPR || TREE_CODE (exp) == TREE_LIST)
/* Clean up any pending cleanups. This happens when a function call
returns a cleanup-needing value that nobody uses. */
- expand_cleanups_to (NULL_TREE);
+ expand_cleanups_to (old_cleanups);
+ pop_temp_slots ();
+ pop_temp_slots ();
+ target_temp_slot_level = old_temp_level;
+ /* There might something left from building the trees. */
+ if (cleanups_this_call)
+ {
+ expand_cleanups_to (NULL_TREE);
+ }
+ free_temp_slots ();
}
/* When a stmt has been parsed, this function is called.
tree function = fn ? *fn : TREE_TYPE (*decl);
tree args = argtypes ? *argtypes : TYPE_ARG_TYPES (function);
+ if (TYPE_READONLY (TREE_TYPE (TREE_VALUE (args))))
+ cp_error ("static member function `%#D' declared const", *decl);
+ if (TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (args))))
+ cp_error ("static member function `%#D' declared volatile", *decl);
+
args = TREE_CHAIN (args);
tmp = build_function_type (TREE_TYPE (function), args);
tmp = build_type_variant (tmp, TYPE_READONLY (function),
TYPE_VOLATILE (function));
- tmp = build_exception_variant (TYPE_METHOD_BASETYPE (function), tmp,
+ tmp = build_exception_variant (tmp,
TYPE_RAISES_EXCEPTIONS (function));
TREE_TYPE (*decl) = tmp;
+ if (DECL_ARGUMENTS (*decl))
+ DECL_ARGUMENTS (*decl) = TREE_CHAIN (DECL_ARGUMENTS (*decl));
DECL_STATIC_FUNCTION_P (*decl) = 1;
if (fn)
*fn = tmp;
tree shadowed_labels;
tree ctor_label;
tree dtor_label;
+ rtx last_dtor_insn;
tree protect_list;
tree base_init_list;
tree member_init_list;
rtx result_rtx;
struct cp_function *next;
struct binding_level *binding_level;
+ void* eh_context;
};
+
+
struct cp_function *cp_function_chain;
extern int temp_name_counter;
p->binding_level = current_binding_level;
p->ctor_label = ctor_label;
p->dtor_label = dtor_label;
+ p->last_dtor_insn = last_dtor_insn;
p->assigns_this = current_function_assigns_this;
p->just_assigned_this = current_function_just_assigned_this;
p->parms_stored = current_function_parms_stored;
p->member_init_list = current_member_init_list;
p->class_decl = current_class_decl;
p->C_C_D = C_C_D;
+
+ p->eh_context = push_eh_context ();
}
/* Restore the variables used during compilation of a C++ function. */
current_binding_level = p->binding_level;
ctor_label = p->ctor_label;
dtor_label = p->dtor_label;
+ last_dtor_insn = p->last_dtor_insn;
protect_list = p->protect_list;
current_function_assigns_this = p->assigns_this;
current_function_just_assigned_this = p->just_assigned_this;
current_class_decl = p->class_decl;
C_C_D = p->C_C_D;
+ pop_eh_context (p->eh_context);
+
free (p);
}
+
+/* FSF LOCAL dje prefix attributes */
+/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
+ lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
+
+ The head of the declspec list is stored in DECLSPECS.
+ The head of the attribute list is stored in PREFIX_ATTRIBUTES.
+
+ Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
+ the list elements. We drop the containing TREE_LIST nodes and link the
+ resulting attributes together the way decl_attributes expects them. */
+
+void
+split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
+ tree specs_attrs;
+ tree *declspecs, *prefix_attributes;
+{
+ tree t, s, a, next, specs, attrs;
+
+ /* This can happen in c++ (eg: decl: typespec initdecls ';'). */
+ if (specs_attrs != NULL_TREE
+ && TREE_CODE (specs_attrs) != TREE_LIST)
+ {
+ *declspecs = specs_attrs;
+ *prefix_attributes = NULL_TREE;
+ return;
+ }
+
+ /* Remember to keep the lists in the same order, element-wise. */
+
+ specs = s = NULL_TREE;
+ attrs = a = NULL_TREE;
+ for (t = specs_attrs; t; t = next)
+ {
+ next = TREE_CHAIN (t);
+ /* Declspecs have a non-NULL TREE_VALUE. */
+ if (TREE_VALUE (t) != NULL_TREE)
+ {
+ if (specs == NULL_TREE)
+ specs = s = t;
+ else
+ {
+ TREE_CHAIN (s) = t;
+ s = t;
+ }
+ }
+ else
+ {
+ if (attrs == NULL_TREE)
+ attrs = a = TREE_PURPOSE (t);
+ else
+ {
+ TREE_CHAIN (a) = TREE_PURPOSE (t);
+ a = TREE_PURPOSE (t);
+ }
+ }
+ }
+
+ /* Terminate the lists. */
+ if (s != NULL_TREE)
+ TREE_CHAIN (s) = NULL_TREE;
+ if (a != NULL_TREE)
+ TREE_CHAIN (a) = NULL_TREE;
+
+ /* All done. */
+ *declspecs = specs;
+ *prefix_attributes = attrs;
+}
+
+/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
+ This function is used by the parser when a rule will accept attributes
+ in a particular position, but we don't want to support that just yet.
+
+ A warning is issued for every ignored attribute. */
+
+tree
+strip_attrs (specs_attrs)
+ tree specs_attrs;
+{
+ tree specs, attrs;
+
+ split_specs_attrs (specs_attrs, &specs, &attrs);
+
+ while (attrs)
+ {
+ warning ("`%s' attribute ignored",
+ IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
+ attrs = TREE_CHAIN (attrs);
+ }
+
+ return specs;
+}
+/* END FSF LOCAL */
+