diff options
Diffstat (limited to 'gnu/usr.bin/cc/cc1plus/cp-decl.c')
| -rw-r--r-- | gnu/usr.bin/cc/cc1plus/cp-decl.c | 11551 |
1 files changed, 11551 insertions, 0 deletions
diff --git a/gnu/usr.bin/cc/cc1plus/cp-decl.c b/gnu/usr.bin/cc/cc1plus/cp-decl.c new file mode 100644 index 000000000000..b888baa16b73 --- /dev/null +++ b/gnu/usr.bin/cc/cc1plus/cp-decl.c @@ -0,0 +1,11551 @@ +/* Process declarations and variables for C compiler. + Copyright (C) 1988, 1992, 1993 Free Software Foundation, Inc. + Hacked by Michael Tiemann (tiemann@cygnus.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Process declarations and symbol lookup for C front end. + Also constructs types; the standard scalar types at initialization, + and structure, union, array and enum types when they are declared. */ + +/* ??? not all decl nodes are given the most useful possible + line numbers. For example, the CONST_DECLs for enum values. */ + +#include <stdio.h> +#include "config.h" +#include "tree.h" +#include "rtl.h" +#include "flags.h" +#include "cp-tree.h" +#include "cp-decl.h" +#include "cp-lex.h" +#include <sys/types.h> +#include <signal.h> +#include "obstack.h" + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +extern struct obstack permanent_obstack; + +/* Stack of places to restore the search obstack back to. */ + +/* Obstack used for remembering local class declarations (like + enums and static (const) members. */ +#include "stack.h" +static struct obstack decl_obstack; +static struct stack_level *decl_stack; + +#undef NULL +#define NULL (char *)0 + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif + +#ifndef SHORT_TYPE_SIZE +#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2)) +#endif + +#ifndef INT_TYPE_SIZE +#define INT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_TYPE_SIZE +#define LONG_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_LONG_TYPE_SIZE +#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +#ifndef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 0 +#endif + +#ifndef FLOAT_TYPE_SIZE +#define FLOAT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef DOUBLE_TYPE_SIZE +#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +#ifndef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +/* We let tm.h override the types used here, to handle trivial differences + such as the choice of unsigned int or long unsigned int for size_t. + When machines start needing nontrivial differences in the size type, + it would be best to do something here to figure out automatically + from other information what type to use. */ + +#ifndef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" +#endif + +#ifndef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" +#endif + +#ifndef WCHAR_TYPE +#define WCHAR_TYPE "int" +#endif + +#define builtin_function(NAME, TYPE, CODE, LIBNAME) \ + define_function (NAME, TYPE, CODE, (void (*)())pushdecl, LIBNAME) +#define auto_function(NAME, TYPE, CODE) \ + do { \ + tree __name = NAME; \ + tree __type = TYPE; \ + define_function (IDENTIFIER_POINTER (__name), __type, CODE, \ + (void (*)())push_overloaded_decl_1, \ + IDENTIFIER_POINTER (build_decl_overload (__name, TYPE_ARG_TYPES (__type), 0)));\ + } while (0) + +static tree grokparms PROTO((tree, int)); +static tree lookup_nested_type PROTO((tree, tree)); +static char *redeclaration_error_message PROTO((tree, tree)); +static int parmlist_is_random PROTO((tree)); +static void grok_op_properties PROTO((tree, int)); +static void expand_static_init PROTO((tree, tree)); +static void deactivate_exception_cleanups PROTO((void)); + +tree define_function PROTO((char *, tree, enum built_in_function, void (*)(), char *)); + +/* a node which has tree code ERROR_MARK, and whose type is itself. + All erroneous expressions are replaced with this node. All functions + that accept nodes as arguments should avoid generating error messages + if this node is one of the arguments, since it is undesirable to get + multiple error messages from one error in the input. */ + +tree error_mark_node; + +/* Erroneous argument lists can use this *IFF* they do not modify it. */ +tree error_mark_list; + +/* INTEGER_TYPE and REAL_TYPE nodes for the standard data types */ + +tree short_integer_type_node; +tree integer_type_node; +tree long_integer_type_node; +tree long_long_integer_type_node; + +tree short_unsigned_type_node; +tree unsigned_type_node; +tree long_unsigned_type_node; +tree long_long_unsigned_type_node; + +tree ptrdiff_type_node; + +tree unsigned_char_type_node; +tree signed_char_type_node; +tree char_type_node; +tree wchar_type_node; +tree signed_wchar_type_node; +tree unsigned_wchar_type_node; + +tree float_type_node; +tree double_type_node; +tree long_double_type_node; + +tree intQI_type_node; +tree intHI_type_node; +tree intSI_type_node; +tree intDI_type_node; + +tree unsigned_intQI_type_node; +tree unsigned_intHI_type_node; +tree unsigned_intSI_type_node; +tree unsigned_intDI_type_node; + +/* a VOID_TYPE node, and the same, packaged in a TREE_LIST. */ + +tree void_type_node, void_list_node; +tree void_zero_node; + +/* Nodes for types `void *' and `const void *'. */ + +tree ptr_type_node, const_ptr_type_node; + +/* Nodes for types `char *' and `const char *'. */ + +tree string_type_node, const_string_type_node; + +/* Type `char[256]' or something like it. + Used when an array of char is needed and the size is irrelevant. */ + +tree char_array_type_node; + +/* Type `int[256]' or something like it. + Used when an array of int needed and the size is irrelevant. */ + +tree int_array_type_node; + +/* Type `wchar_t[256]' or something like it. + Used when a wide string literal is created. */ + +tree wchar_array_type_node; + +/* type `int ()' -- used for implicit declaration of functions. */ + +tree default_function_type; + +/* function types `double (double)' and `double (double, double)', etc. */ + +tree double_ftype_double, double_ftype_double_double; +tree int_ftype_int, long_ftype_long; + +/* Function type `void (void *, void *, int)' and similar ones. */ + +tree void_ftype_ptr_ptr_int, int_ftype_ptr_ptr_int, void_ftype_ptr_int_int; + +/* Function type `char *(char *, char *)' and similar ones */ +tree string_ftype_ptr_ptr, int_ftype_string_string; + +/* Function type `size_t (const char *)' */ +tree sizet_ftype_string; + +/* Function type `int (const void *, const void *, size_t)' */ +tree int_ftype_cptr_cptr_sizet; + +/* C++ extensions */ +tree vtable_entry_type; +tree __t_desc_type_node, __i_desc_type_node, __m_desc_type_node; +tree __t_desc_array_type, __i_desc_array_type, __m_desc_array_type; +tree class_star_type_node; +tree class_type_node, record_type_node, union_type_node, enum_type_node; +tree exception_type_node, unknown_type_node; +tree maybe_gc_cleanup; + +/* Used for virtual function tables. */ +tree vtbl_mask; + +/* Array type `(void *)[]' */ +tree vtbl_type_node; + +/* Static decls which do not have static initializers have no + initializers as far as GNU C is concerned. EMPTY_INIT_NODE + is a static initializer which makes varasm code place the decl + in data rather than in bss space. Such gymnastics are necessary + to avoid the problem that the linker will not include a library + file if all the library appears to contribute are bss variables. */ + +tree empty_init_node; + +/* In a destructor, the point at which all derived class destroying + has been done, just before any base class destroying will be done. */ + +tree dtor_label; + +/* In a constructor, the point at which we are ready to return + the pointer to the initialized object. */ + +tree ctor_label; + +/* A FUNCTION_DECL which can call `unhandled_exception'. + Not necessarily the one that the user will declare, + but sufficient to be called by routines that want to abort the program. */ + +tree unhandled_exception_fndecl; + +/* A FUNCTION_DECL which can call `abort'. Not necessarily the + one that the user will declare, but sufficient to be called + by routines that want to abort the program. */ + +tree abort_fndecl; + +extern rtx cleanup_label, return_label; + +/* 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 + original location. */ +rtx original_result_rtx; + +/* Sequence of insns which represents base initialization. */ +rtx base_init_insns; + +/* C++: Keep these around to reduce calls to `get_identifier'. + Identifiers for `this' in member functions and the auto-delete + parameter for destructors. */ +tree this_identifier, in_charge_identifier; + +/* A list (chain of TREE_LIST nodes) of named label uses. + The TREE_PURPOSE field is the list of variables defined + the the label's scope defined at the point of use. + The TREE_VALUE field is the LABEL_DECL used. + The TREE_TYPE field holds `current_binding_level' at the + point of the label's use. + + Used only for jumps to as-yet undefined labels, since + jumps to defined labels can have their validity checked + by stmt.c. */ + +static tree named_label_uses; + +/* A list of objects which have constructors or destructors + which reside in the global scope. The decl is stored in + the TREE_VALUE slot and the initializer is stored + in the TREE_PURPOSE slot. */ +tree static_aggregates; + +/* A list of functions which were declared inline, but later had their + address taken. Used only for non-virtual member functions, since we can + find other functions easily enough. */ +tree pending_addressable_inlines; + +/* A list of overloaded functions which we should forget ever + existed, such as functions declared in a function's scope, + once we leave that function's scope. */ +static tree overloads_to_forget; + +/* -- end of C++ */ + +/* Two expressions that are constants with value zero. + The first is of type `int', the second of type `void *'. */ + +tree integer_zero_node; +tree null_pointer_node; + +/* A node for the integer constants 1, 2, and 3. */ + +tree integer_one_node, integer_two_node, integer_three_node; + +/* Nonzero if we have seen an invalid cross reference + to a struct, union, or enum, but not yet printed the message. */ + +tree pending_invalid_xref; +/* File and line to appear in the eventual error message. */ +char *pending_invalid_xref_file; +int pending_invalid_xref_line; + +/* While defining an enum type, this is 1 plus the last enumerator + constant value. */ + +static tree enum_next_value; + +/* Parsing a function declarator leaves a list of parameter names + or a chain or parameter decls here. */ + +tree last_function_parms; + +/* Parsing a function declarator leaves here a chain of structure + and enum types declared in the parmlist. */ + +static tree last_function_parm_tags; + +/* After parsing the declarator that starts a function definition, + `start_function' puts here the list of parameter names or chain of decls. + `store_parm_decls' finds it here. */ + +static tree current_function_parms; + +/* Similar, for last_function_parm_tags. */ +static tree current_function_parm_tags; + +/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function + that have names. Here so we can clear out their names' definitions + at the end of the function. */ + +static tree named_labels; + +/* A list of LABEL_DECLs from outer contexts that are currently shadowed. */ + +static tree shadowed_labels; + +#if 0 /* Not needed by C++ */ +/* Nonzero when store_parm_decls is called indicates a varargs function. + Value not meaningful after store_parm_decls. */ + +static int c_function_varargs; +#endif + +/* The FUNCTION_DECL for the function currently being compiled, + or 0 if between functions. */ +tree current_function_decl; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement that specifies a return value is seen. */ + +int current_function_returns_value; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement with no argument is seen. */ + +int current_function_returns_null; + +/* Set to 0 at beginning of a function definition, and whenever + a label (case or named) is defined. Set to value of expression + returned from function when that value can be transformed into + a named return value. */ + +tree current_function_return_value; + +/* Nonzero means warn about multiple (redundant) decls for the same single + variable or function. */ + +extern int warn_redundant_decls; + +/* Set to nonzero by `grokdeclarator' for a function + whose return type is defaulted, if warnings for this are desired. */ + +static int warn_about_return_type; + +/* Nonzero when starting a function declared `extern inline'. */ + +static int current_extern_inline; + +/* Nonzero means give `double' the same size as `float'. */ + +extern int flag_short_double; + +/* Nonzero means don't recognize any builtin functions. */ + +extern int flag_no_builtin; + +/* Nonzero means do emit exported implementations of functions even if + they can be inlined. */ + +extern int flag_implement_inlines; + +/* Nonzero means handle things in ANSI, instead of GNU fashion. This + flag should be tested for language behavior that's different between + ANSI and GNU, but not so horrible as to merit a PEDANTIC label. */ + +extern int flag_ansi; + +/* Pointers to the base and current top of the language name stack. */ + +extern tree *current_lang_base, *current_lang_stack; + +/* C and C++ flags are in cp-decl2.c. */ + +/* Set to 0 at beginning of a constructor, set to 1 + if that function does an allocation before referencing its + instance variable. */ +int current_function_assigns_this; +int current_function_just_assigned_this; + +/* Set to 0 at beginning of a function. Set non-zero when + store_parm_decls is called. Don't call store_parm_decls + if this flag is non-zero! */ +int current_function_parms_stored; + +/* Current end of entries in the gc obstack for stack pointer variables. */ + +int current_function_obstack_index; + +/* Flag saying whether we have used the obstack in this function or not. */ + +int current_function_obstack_usage; + +/* Flag used when debugging cp-spew.c */ + +extern int spew_debug; + +/* Allocate a level of searching. */ +struct stack_level * +push_decl_level (stack, obstack) + struct stack_level *stack; + struct obstack *obstack; +{ + struct stack_level tem; + tem.prev = stack; + + return push_stack_level (obstack, (char *)&tem, sizeof (tem)); +} + +/* Discard a level of decl allocation. */ + +static struct stack_level * +pop_decl_level (stack) + struct stack_level *stack; +{ + tree *bp, *tp; + struct obstack *obstack = stack->obstack; + bp = stack->first; + tp = (tree *)obstack_next_free (obstack); + while (tp != bp) + { + --tp; + if (*tp != NULL_TREE) + IDENTIFIER_CLASS_VALUE (DECL_NAME (*tp)) = NULL_TREE; + } + return pop_stack_level (stack); +} + +/* For each binding contour we allocate a binding_level structure + * which records the names defined in that contour. + * Contours include: + * 0) the global one + * 1) one for each function definition, + * where internal declarations of the parameters appear. + * 2) one for each compound statement, + * to record its declarations. + * + * The current meaning of a name can be found by searching the levels from + * the current one out to the global one. + * + * Off to the side, may be the class_binding_level. This exists + * only to catch class-local declarations. It is otherwise + * nonexistent. + * + * Also there may be binding levels that catch cleanups that + * must be run when exceptions occur. + */ + +/* Note that the information in the `names' component of the global contour + is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */ + +struct binding_level + { + /* A chain of _DECL nodes for all variables, constants, functions, + * and typedef types. These are in the reverse of the order supplied. + */ + tree names; + + /* A list of structure, union and enum definitions, + * for looking up tag names. + * It is a chain of TREE_LIST nodes, each of whose TREE_PURPOSE is a name, + * or NULL_TREE; and whose TREE_VALUE is a RECORD_TYPE, UNION_TYPE, + * or ENUMERAL_TYPE node. + * + * C++: the TREE_VALUE nodes can be simple types for component_bindings. + * + */ + tree tags; + + /* For each level, a list of shadowed outer-level local definitions + to be restored when this level is popped. + Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and + whose TREE_VALUE is its old definition (a kind of ..._DECL node). */ + tree shadowed; + + /* Same, for IDENTIFIER_CLASS_VALUE. */ + tree class_shadowed; + + /* Same, for IDENTIFIER_TYPE_VALUE. */ + tree type_shadowed; + + /* For each level (except not the global one), + a chain of BLOCK nodes for all the levels + that were entered and exited one level down. */ + tree blocks; + + /* The BLOCK node for this level, if one has been preallocated. + If 0, the BLOCK is allocated (if needed) when the level is popped. */ + tree this_block; + + /* The binding level which this one is contained in (inherits from). */ + struct binding_level *level_chain; + + /* Number of decls in `names' that have incomplete + structure or union types. */ + unsigned short n_incomplete; + + /* 1 for the level that holds the parameters of a function. + 2 for the level that holds a class declaration. + 3 for levels that hold parameter declarations. */ + unsigned parm_flag : 4; + + /* 1 means make a BLOCK for this level regardless of all else. + 2 for temporary binding contours created by the compiler. */ + unsigned keep : 3; + + /* Nonzero if this level "doesn't exist" for tags. */ + unsigned tag_transparent : 1; + + /* Nonzero if this level can safely have additional + cleanup-needing variables added to it. */ + unsigned more_cleanups_ok : 1; + unsigned have_cleanups : 1; + + /* Nonzero if this level can safely have additional + exception-raising statements added to it. */ + unsigned more_exceptions_ok : 1; + unsigned have_exceptions : 1; + + /* Nonzero if we should accept any name as an identifier in + this scope. This happens in some template definitions. */ + unsigned accept_any : 1; + + /* Nonzero if this level is for completing a template class definition + inside a binding level that temporarily binds the parameters. This + means that definitions here should not be popped off when unwinding + this binding level. (Not actually implemented this way, + unfortunately.) */ + unsigned pseudo_global : 1; + + /* Two bits left for this word. */ + +#if PARANOID + unsigned char depth; +#endif + }; + +#define NULL_BINDING_LEVEL (struct binding_level *) NULL + +/* The binding level currently in effect. */ + +static struct binding_level *current_binding_level; + +/* The binding level of the current class, if any. */ + +static struct binding_level *class_binding_level; + +/* A chain of binding_level structures awaiting reuse. */ + +static struct binding_level *free_binding_level; + +/* The outermost binding level, for names of file scope. + This is created when the compiler is started and exists + through the entire run. */ + +static struct binding_level *global_binding_level; + +/* Binding level structures are initialized by copying this one. */ + +static struct binding_level clear_binding_level; + +/* Nonzero means unconditionally make a BLOCK for the next level pushed. */ + +static int keep_next_level_flag; + +#if PARANOID +/* Perform sanity checking on binding levels. Normally not needed. */ +void +binding_levels_sane () +{ + struct binding_level *b = current_binding_level; + static int n; + if (++n < 3) + return; + my_friendly_assert (global_binding_level != 0, 126); + my_friendly_assert (current_binding_level != 0, 127); + for (b = current_binding_level; b != global_binding_level; b = b->level_chain) + { + my_friendly_assert (b->level_chain != 0, 128); + my_friendly_assert (b->depth == 1 + b->level_chain->depth, 129); + } + if (class_binding_level) + for (b = class_binding_level; + b != global_binding_level && b != current_binding_level; + b = b->level_chain) + { + my_friendly_assert (b->level_chain != 0, 130); + my_friendly_assert (b->depth == 1 + b->level_chain->depth, 131); + } + my_friendly_assert (global_binding_level->depth == 0, 132); + my_friendly_assert (global_binding_level->level_chain == 0, 133); + return; +} + +#else +#define binding_levels_sane() ((void)(1)) +#endif + +#ifdef DEBUG_CP_BINDING_LEVELS +int debug_bindings_indentation; +#endif + +static void +#if !PARANOID && defined (__GNUC__) +__inline +#endif +push_binding_level (newlevel, tag_transparent, keep) + struct binding_level *newlevel; + int tag_transparent, keep; +{ + binding_levels_sane(); + /* Add this level to the front of the chain (stack) of levels that + are active. */ +#ifdef DEBUG_CP_BINDING_LEVELS + indent_to (stderr, debug_bindings_indentation); + fprintf (stderr, "pushing binding level "); + fprintf (stderr, HOST_PTR_PRINTF, newlevel); + fprintf (stderr, "\n"); +#endif + *newlevel = clear_binding_level; + if (class_binding_level) + { + newlevel->level_chain = class_binding_level; + class_binding_level = (struct binding_level *)0; + } + else + { + newlevel->level_chain = current_binding_level; + } + current_binding_level = newlevel; + newlevel->tag_transparent = tag_transparent; + newlevel->more_cleanups_ok = 1; + newlevel->more_exceptions_ok = 1; + newlevel->keep = keep; +#if PARANOID + newlevel->depth = (newlevel->level_chain + ? newlevel->level_chain->depth + 1 + : 0); +#endif + binding_levels_sane(); +} + +static void +#if !PARANOID && defined (__GNUC__) +__inline +#endif +pop_binding_level () +{ + binding_levels_sane(); +#ifdef DEBUG_CP_BINDING_LEVELS + indent_to (stderr, debug_bindings_indentation); + fprintf (stderr, "popping binding level "); + fprintf (stderr, HOST_PTR_PRINTF, current_binding_level); + fprintf (stderr, "\n"); +#endif + if (global_binding_level) + { + /* cannot pop a level, if there are none left to pop. */ + if (current_binding_level == global_binding_level) + my_friendly_abort (123); + } + /* Pop the current level, and free the structure for reuse. */ + { + register struct binding_level *level = current_binding_level; + current_binding_level = current_binding_level->level_chain; + level->level_chain = free_binding_level; +#ifdef DEBUG_CP_BINDING_LEVELS + memset (level, 0x69, sizeof (*level)); +#else + free_binding_level = level; +#if PARANOID + level->depth = ~0; /* ~0 assumes that the depth is unsigned. */ +#endif +#endif + if (current_binding_level->parm_flag == 2) + { + class_binding_level = current_binding_level; + do + { + current_binding_level = current_binding_level->level_chain; + } + while (current_binding_level->parm_flag == 2); + } + } + binding_levels_sane(); +} + +/* Nonzero if we are currently in the global binding level. */ + +int +global_bindings_p () +{ + return current_binding_level == global_binding_level; +} + +void +keep_next_level () +{ + keep_next_level_flag = 1; +} + +/* Nonzero if the current level needs to have a BLOCK made. */ + +int +kept_level_p () +{ + return (current_binding_level->blocks != NULL_TREE + || current_binding_level->keep + || current_binding_level->names != NULL_TREE + || (current_binding_level->tags != NULL_TREE + && !current_binding_level->tag_transparent)); +} + +/* Identify this binding level as a level of parameters. */ + +void +declare_parm_level () +{ + current_binding_level->parm_flag = 1; +} + +/* Identify this binding level as a level of a default exception handler. */ + +void +declare_implicit_exception () +{ + current_binding_level->parm_flag = 3; +} + +/* Nonzero if current binding contour contains expressions + that might raise exceptions. */ + +int +have_exceptions_p () +{ + return current_binding_level->have_exceptions; +} + +void +declare_uninstantiated_type_level () +{ + current_binding_level->accept_any = 1; +} + +int +uninstantiated_type_level_p () +{ + return current_binding_level->accept_any; +} + +void +declare_pseudo_global_level () +{ + current_binding_level->pseudo_global = 1; +} + +int +pseudo_global_level_p () +{ + return current_binding_level->pseudo_global; +} + +/* Enter a new binding level. + If TAG_TRANSPARENT is nonzero, do so only for the name space of variables, + not for that of tags. */ + +void +pushlevel (tag_transparent) + int tag_transparent; +{ + register struct binding_level *newlevel = NULL_BINDING_LEVEL; + +#ifdef DEBUG_CP_BINDING_LEVELS + indent_to (stderr, debug_bindings_indentation); + fprintf (stderr, "pushlevel"); + debug_bindings_indentation += 4; +#endif + + /* If this is the top level of a function, + just make sure that NAMED_LABELS is 0. + They should have been set to 0 at the end of the previous function. */ + + if (current_binding_level == global_binding_level) + my_friendly_assert (named_labels == NULL_TREE, 134); + + /* Reuse or create a struct for this binding level. */ + + if (free_binding_level) + { + newlevel = free_binding_level; + free_binding_level = free_binding_level->level_chain; + } + else + { + /* Create a new `struct binding_level'. */ + newlevel = (struct binding_level *) xmalloc (sizeof (struct binding_level)); + } + push_binding_level (newlevel, tag_transparent, keep_next_level_flag); + GNU_xref_start_scope ((int) newlevel); + keep_next_level_flag = 0; + +#ifdef DEBUG_CP_BINDING_LEVELS + debug_bindings_indentation -= 4; +#endif +} + +void +pushlevel_temporary (tag_transparent) + int tag_transparent; +{ + pushlevel (tag_transparent); + current_binding_level->keep = 2; + clear_last_expr (); + + /* Note we don't call push_momentary() here. Otherwise, it would cause + cleanups to be allocated on the momentary obstack, and they will be + overwritten by the next statement. */ + + expand_start_bindings (0); +} + +/* Exit a binding level. + Pop the level off, and restore the state of the identifier-decl mappings + that were in effect when this level was entered. + + If KEEP == 1, this level had explicit declarations, so + and create a "block" (a BLOCK node) for the level + to record its declarations and subblocks for symbol table output. + + If KEEP == 2, this level's subblocks go to the front, + not the back of the current binding level. This happens, + for instance, when code for constructors and destructors + need to generate code at the end of a function which must + be moved up to the front of the function. + + If FUNCTIONBODY is nonzero, this level is the body of a function, + so create a block as if KEEP were set and also clear out all + label names. + + If REVERSE is nonzero, reverse the order of decls before putting + them into the BLOCK. */ + +tree +poplevel (keep, reverse, functionbody) + int keep; + int reverse; + int functionbody; +{ + register tree link; + /* The chain of decls was accumulated in reverse order. + Put it into forward order, just for cleanliness. */ + tree decls; + int tmp = functionbody; + int implicit_try_block = current_binding_level->parm_flag == 3; + int real_functionbody = current_binding_level->keep == 2 + ? ((functionbody = 0), tmp) : functionbody; + tree tags = functionbody >= 0 ? current_binding_level->tags : 0; + tree subblocks = functionbody >= 0 ? current_binding_level->blocks : 0; + tree block = NULL_TREE; + tree decl; + int block_previously_created; + +#ifdef DEBUG_CP_BINDING_LEVELS + indent_to (stderr, debug_bindings_indentation); + fprintf (stderr, "poplevel"); + debug_bindings_indentation += 4; +#endif + + binding_levels_sane(); + GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level, + (HOST_WIDE_INT) current_binding_level->level_chain, + current_binding_level->parm_flag, + current_binding_level->keep, + current_binding_level->tag_transparent); + + if (current_binding_level->keep == 1) + keep = 1; + + /* This warning is turned off because it causes warnings for + declarations like `extern struct foo *x'. */ +#if 0 + /* Warn about incomplete structure types in this level. */ + for (link = tags; link; link = TREE_CHAIN (link)) + if (TYPE_SIZE (TREE_VALUE (link)) == NULL_TREE) + { + tree type = TREE_VALUE (link); + char *errmsg; + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + errmsg = "`struct %s' incomplete in scope ending here"; + break; + case UNION_TYPE: + errmsg = "`union %s' incomplete in scope ending here"; + break; + case ENUMERAL_TYPE: + errmsg = "`enum %s' incomplete in scope ending here"; + break; + } + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + error (errmsg, IDENTIFIER_POINTER (TYPE_NAME (type))); + else + /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */ + error (errmsg, TYPE_NAME_STRING (type)); + } +#endif /* 0 */ + + /* Get the decls in the order they were written. + Usually current_binding_level->names is in reverse order. + But parameter decls were previously put in forward order. */ + + if (reverse) + current_binding_level->names + = decls = nreverse (current_binding_level->names); + else + decls = current_binding_level->names; + + /* 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) + && DECL_INITIAL (decl) != NULL_TREE + && TREE_ADDRESSABLE (decl)) + { + /* If this decl was copied from a file-scope decl + on account of a block-scope extern decl, + propagate TREE_ADDRESSABLE to the file-scope decl. */ + if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE) + TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; + else + output_inline_function (decl); + } + + /* 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) + block = current_binding_level->this_block; + else if (keep == 1 || functionbody) + block = make_node (BLOCK); + if (block != NULL_TREE) + { + BLOCK_VARS (block) = decls; + BLOCK_TYPE_TAGS (block) = tags; + BLOCK_SUBBLOCKS (block) = subblocks; + 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; + + /* Clear out the meanings of the local variables of this level. */ + + for (link = decls; link; link = TREE_CHAIN (link)) + { + if (DECL_NAME (link) != NULL_TREE) + { + /* 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; + } + } + + /* 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); + for (link = current_binding_level->class_shadowed; + link; link = TREE_CHAIN (link)) + IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + for (link = current_binding_level->type_shadowed; + link; link = TREE_CHAIN (link)) + IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + + /* If the level being exited is the top level of a function, + check over all the labels. */ + + if (functionbody) + { + /* If this is the top level block of a function, + the vars are the function's parameters. + Don't leave them in the BLOCK because they are + found in the FUNCTION_DECL instead. */ + + BLOCK_VARS (block) = 0; + + /* Clear out the definitions of all label names, + since their scopes end here. */ + + for (link = named_labels; link; link = TREE_CHAIN (link)) + { + register tree label = TREE_VALUE (link); + + if (DECL_INITIAL (label) == NULL_TREE) + { + error_with_decl (label, "label `%s' used but not defined"); + /* Avoid crashing later. */ + define_label (input_filename, 1, DECL_NAME (label)); + } + else if (warn_unused && !TREE_USED (label)) + warning_with_decl (label, + "label `%s' defined but not used"); + SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), 0); + + /* Put the labels into the "variables" of the + top-level block, so debugger can see them. */ + TREE_CHAIN (label) = BLOCK_VARS (block); + BLOCK_VARS (block) = label; + } + + named_labels = NULL_TREE; + } + + /* Any uses of undefined labels now operate under constraints + of next binding contour. */ + { + struct binding_level *level_chain; + level_chain = current_binding_level->level_chain; + if (level_chain) + { + tree labels; + for (labels = named_label_uses; labels; labels = TREE_CHAIN (labels)) + if (TREE_TYPE (labels) == (tree)current_binding_level) + { + TREE_TYPE (labels) = (tree)level_chain; + TREE_PURPOSE (labels) = level_chain->names; + } + } + } + + tmp = current_binding_level->keep; + + pop_binding_level (); + if (functionbody) + DECL_INITIAL (current_function_decl) = block; + else if (block) + { + if (!block_previously_created) + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); + } + + /* If we did not make a block for the level just exited, + any blocks made for inner levels + (since they cannot be recorded as subblocks in that level) + must be carried forward so they will later become subblocks + of something else. */ + else if (subblocks) + if (keep == 2) + current_binding_level->blocks = chainon (subblocks, current_binding_level->blocks); + else + current_binding_level->blocks + = chainon (current_binding_level->blocks, subblocks); + + /* Take care of compiler's internal binding structures. */ + if (tmp == 2 && !implicit_try_block) + { +#if 0 + /* We did not call push_momentary for this + binding contour, so there is nothing to pop. */ + pop_momentary (); +#endif + expand_end_bindings (getdecls (), keep, 1); + block = poplevel (keep, reverse, real_functionbody); + } + if (block) + TREE_USED (block) = 1; + binding_levels_sane(); +#ifdef DEBUG_CP_BINDING_LEVELS + debug_bindings_indentation -= 4; +#endif + return block; +} + +/* Delete the node BLOCK from the current binding level. + This is used for the block inside a stmt expr ({...}) + so that the block can be reinserted where appropriate. */ + +void +delete_block (block) + tree block; +{ + tree t; + if (current_binding_level->blocks == block) + current_binding_level->blocks = TREE_CHAIN (block); + for (t = current_binding_level->blocks; t;) + { + if (TREE_CHAIN (t) == block) + TREE_CHAIN (t) = TREE_CHAIN (block); + else + t = TREE_CHAIN (t); + } + TREE_CHAIN (block) = NULL_TREE; + /* Clear TREE_USED which is always set by poplevel. + The flag is set again if insert_block is called. */ + TREE_USED (block) = 0; +} + +/* Insert BLOCK at the end of the list of subblocks of the + current binding level. This is used when a BIND_EXPR is expanded, + to handle the BLOCK node inside the BIND_EXPR. */ + +void +insert_block (block) + tree block; +{ + TREE_USED (block) = 1; + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); +} + +/* Add BLOCK to the current list of blocks for this binding contour. */ +void +add_block_current_level (block) + tree block; +{ + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); +} + +/* Set the BLOCK node for the innermost scope + (the one we are currently in). */ + +void +set_block (block) + register tree block; +{ + current_binding_level->this_block = block; +} + +/* Do a pushlevel for class declarations. */ +void +pushlevel_class () +{ + binding_levels_sane(); +#ifdef DEBUG_CP_BINDING_LEVELS + indent_to (stderr, debug_bindings_indentation); + fprintf (stderr, "pushlevel_class"); + debug_bindings_indentation += 4; +#endif + pushlevel (0); + decl_stack = push_decl_level (decl_stack, &decl_obstack); + class_binding_level = current_binding_level; + class_binding_level->parm_flag = 2; + do + { + current_binding_level = current_binding_level->level_chain; + } + while (current_binding_level->parm_flag == 2); + binding_levels_sane(); +#ifdef DEBUG_CP_BINDING_LEVELS + debug_bindings_indentation -= 4; +#endif +} + +/* ...and a poplevel for class declarations. */ +tree +poplevel_class () +{ + register struct binding_level *level = class_binding_level; + tree block = NULL_TREE; + tree shadowed; + +#ifdef DEBUG_CP_BINDING_LEVELS + indent_to (stderr, debug_bindings_indentation); + fprintf (stderr, "poplevel_class"); + debug_bindings_indentation += 4; +#endif + binding_levels_sane(); + if (level == (struct binding_level *)0) + { + while (current_binding_level && class_binding_level == (struct binding_level *)0) + block = poplevel (0, 0, 0); + if (current_binding_level == (struct binding_level *)0) + fatal ("syntax error too serious"); + level = class_binding_level; + } + decl_stack = pop_decl_level (decl_stack); + for (shadowed = level->shadowed; shadowed; shadowed = TREE_CHAIN (shadowed)) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed); + for (shadowed = level->class_shadowed; shadowed; shadowed = TREE_CHAIN (shadowed)) + IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed); + for (shadowed = level->type_shadowed; shadowed; shadowed = TREE_CHAIN (shadowed)) + IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed); + + GNU_xref_end_scope ((HOST_WIDE_INT) class_binding_level, + (HOST_WIDE_INT) class_binding_level->level_chain, + class_binding_level->parm_flag, + class_binding_level->keep, + class_binding_level->tag_transparent); + + class_binding_level = level->level_chain; + if (class_binding_level->parm_flag != 2) + class_binding_level = (struct binding_level *)0; + +#ifdef DEBUG_CP_BINDING_LEVELS + indent_to (stderr, debug_bindings_indentation); + fprintf (stderr, "popping class binding level "); + fprintf (stderr, HOST_PTR_PRINTF, level); + fprintf (stderr, "\n"); + memset (level, 0x69, sizeof (*level)); + debug_bindings_indentation -= 4; +#else + level->level_chain = free_binding_level; + free_binding_level = level; +#endif + binding_levels_sane(); + + return block; +} + +/* For debugging. */ +int no_print_functions = 0; +int no_print_builtins = 0; + +void +print_binding_level (lvl) + struct binding_level *lvl; +{ + tree t; + int i = 0, len; + 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); + if (lvl->tag_transparent) + fprintf (stderr, " tag-transparent"); + if (lvl->more_cleanups_ok) + fprintf (stderr, " more-cleanups-ok"); + if (lvl->have_cleanups) + fprintf (stderr, " have-cleanups"); + if (lvl->more_exceptions_ok) + fprintf (stderr, " more-exceptions-ok"); + if (lvl->have_exceptions) + fprintf (stderr, " have-exceptions"); + fprintf (stderr, "\n"); + if (lvl->names) + { + fprintf (stderr, " names:\t"); + /* We can probably fit 3 names to a line? */ + for (t = lvl->names; t; t = TREE_CHAIN (t)) + { + if (no_print_functions && (TREE_CODE(t) == FUNCTION_DECL)) + continue; + if (no_print_builtins + && (TREE_CODE(t) == TYPE_DECL) + && (!strcmp(DECL_SOURCE_FILE(t),"<built-in>"))) + continue; + + /* Function decls tend to have longer names. */ + if (TREE_CODE (t) == FUNCTION_DECL) + len = 3; + else + len = 2; + i += len; + if (i > 6) + { + fprintf (stderr, "\n\t"); + i = len; + } + print_node_brief (stderr, "", t, 0); + if (TREE_CODE (t) == ERROR_MARK) + break; + } + if (i) + fprintf (stderr, "\n"); + } + if (lvl->tags) + { + fprintf (stderr, " tags:\t"); + i = 0; + for (t = lvl->tags; t; t = TREE_CHAIN (t)) + { + if (TREE_PURPOSE (t) == NULL_TREE) + len = 3; + else if (TREE_PURPOSE (t) == TYPE_IDENTIFIER (TREE_VALUE (t))) + len = 2; + else + len = 4; + i += len; + if (i > 5) + { + fprintf (stderr, "\n\t"); + i = len; + } + if (TREE_PURPOSE (t) == NULL_TREE) + { + print_node_brief (stderr, "<unnamed-typedef", TREE_VALUE (t), 0); + fprintf (stderr, ">"); + } + else if (TREE_PURPOSE (t) == TYPE_IDENTIFIER (TREE_VALUE (t))) + print_node_brief (stderr, "", TREE_VALUE (t), 0); + else + { + print_node_brief (stderr, "<typedef", TREE_PURPOSE (t), 0); + print_node_brief (stderr, "", TREE_VALUE (t), 0); + fprintf (stderr, ">"); + } + } + if (i) + fprintf (stderr, "\n"); + } + if (lvl->shadowed) + { + fprintf (stderr, " shadowed:"); + for (t = lvl->shadowed; t; t = TREE_CHAIN (t)) + { + fprintf (stderr, " %s ", IDENTIFIER_POINTER (TREE_PURPOSE (t))); + } + fprintf (stderr, "\n"); + } + if (lvl->class_shadowed) + { + fprintf (stderr, " class-shadowed:"); + for (t = lvl->class_shadowed; t; t = TREE_CHAIN (t)) + { + fprintf (stderr, " %s ", IDENTIFIER_POINTER (TREE_PURPOSE (t))); + } + fprintf (stderr, "\n"); + } + if (lvl->type_shadowed) + { + fprintf (stderr, " type-shadowed:"); + for (t = lvl->type_shadowed; t; t = TREE_CHAIN (t)) + { +#if 0 + fprintf (stderr, "\n\t"); + print_node_brief (stderr, "<", TREE_PURPOSE (t), 0); + if (TREE_VALUE (t)) + print_node_brief (stderr, " ", TREE_VALUE (t), 0); + else + fprintf (stderr, " (none)"); + fprintf (stderr, ">"); +#else + fprintf (stderr, " %s ", IDENTIFIER_POINTER (TREE_PURPOSE (t))); +#endif + } + fprintf (stderr, "\n"); + } +} + +void +print_other_binding_stack (stack) + struct binding_level *stack; +{ + struct binding_level *level; + for (level = stack; level != global_binding_level; level = level->level_chain) + { + fprintf (stderr, "binding level "); + fprintf (stderr, HOST_PTR_PRINTF, level); + fprintf (stderr, "\n"); + print_binding_level (level); + } +} + +void +print_binding_stack () +{ + struct binding_level *b; + fprintf (stderr, "current_binding_level="); + fprintf (stderr, HOST_PTR_PRINTF, current_binding_level); + fprintf (stderr, "\nclass_binding_level="); + fprintf (stderr, HOST_PTR_PRINTF, class_binding_level); + fprintf (stderr, "\nglobal_binding_level="); + fprintf (stderr, HOST_PTR_PRINTF, global_binding_level); + fprintf (stderr, "\n"); + if (class_binding_level) + { + for (b = class_binding_level; b; b = b->level_chain) + if (b == current_binding_level) + break; + if (b) + b = class_binding_level; + else + b = current_binding_level; + } + else + b = current_binding_level; + print_other_binding_stack (b); + fprintf (stderr, "global:\n"); + print_binding_level (global_binding_level); +} + +/* Subroutines for reverting temporarily to top-level for instantiation + of templates and such. We actually need to clear out the class- and + local-value slots of all identifiers, so that only the global values + are at all visible. Simply setting current_binding_level to the global + scope isn't enough, because more binding levels may be pushed. */ +struct saved_scope { + struct binding_level *old_binding_level; + tree old_bindings; + struct saved_scope *prev; + tree class_name, class_type, class_decl, function_decl; + struct binding_level *class_bindings; +}; +static struct saved_scope *current_saved_scope; +extern tree prev_class_type; + +void +push_to_top_level () +{ + struct saved_scope *s = + (struct saved_scope *) xmalloc (sizeof (struct saved_scope)); + struct binding_level *b = current_binding_level; + tree old_bindings = NULL_TREE; + +#ifdef DEBUG_CP_BINDING_LEVELS + fprintf (stderr, "PUSH_TO_TOP_LEVEL\n"); +#endif + + /* Have to include global_binding_level, because class-level decls + aren't listed anywhere useful. */ + for (; b; b = b->level_chain) + { + tree t; + for (t = b->names; t; t = TREE_CHAIN (t)) + if (b != global_binding_level) + { + tree binding, t1, t2 = t; + tree id = DECL_ASSEMBLER_NAME (t2); + + if (!id + || (!IDENTIFIER_LOCAL_VALUE (id) + && !IDENTIFIER_CLASS_VALUE (id))) + continue; + + for (t1 = old_bindings; t1; t1 = TREE_CHAIN (t1)) + if (TREE_VEC_ELT (t1, 0) == id) + goto skip_it; + + binding = make_tree_vec (4); + if (id) + { + my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 135); + TREE_VEC_ELT (binding, 0) = id; + TREE_VEC_ELT (binding, 1) = IDENTIFIER_TYPE_VALUE (id); + TREE_VEC_ELT (binding, 2) = IDENTIFIER_LOCAL_VALUE (id); + TREE_VEC_ELT (binding, 3) = IDENTIFIER_CLASS_VALUE (id); + IDENTIFIER_LOCAL_VALUE (id) = NULL_TREE; + IDENTIFIER_CLASS_VALUE (id) = NULL_TREE; + adjust_type_value (id); + } + TREE_CHAIN (binding) = old_bindings; + old_bindings = binding; + skip_it: + ; + } + /* Unwind type-value slots back to top level. */ + if (b != global_binding_level) + for (t = b->type_shadowed; t; t = TREE_CHAIN (t)) + SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (t), TREE_VALUE (t)); + } + + s->old_binding_level = current_binding_level; + current_binding_level = global_binding_level; + + s->class_name = current_class_name; + s->class_type = current_class_type; + s->class_decl = current_class_decl; + s->function_decl = current_function_decl; + s->class_bindings = class_binding_level; + current_class_name = current_class_type = current_class_decl = NULL_TREE; + current_function_decl = NULL_TREE; + class_binding_level = (struct binding_level *)0; + + s->prev = current_saved_scope; + s->old_bindings = old_bindings; + current_saved_scope = s; + binding_levels_sane(); +} + +void +pop_from_top_level () +{ + struct saved_scope *s = current_saved_scope; + tree t; + +#ifdef DEBUG_CP_BINDING_LEVELS + fprintf (stderr, "POP_FROM_TOP_LEVEL\n"); +#endif + + binding_levels_sane(); + current_binding_level = s->old_binding_level; + current_saved_scope = s->prev; + for (t = s->old_bindings; t; t = TREE_CHAIN (t)) + { + tree id = TREE_VEC_ELT (t, 0); + if (id) + { + IDENTIFIER_TYPE_VALUE (id) = TREE_VEC_ELT (t, 1); + IDENTIFIER_LOCAL_VALUE (id) = TREE_VEC_ELT (t, 2); + IDENTIFIER_CLASS_VALUE (id) = TREE_VEC_ELT (t, 3); + } + } + current_class_name = s->class_name; + current_class_type = s->class_type; + current_class_decl = s->class_decl; + if (current_class_type) + C_C_D = CLASSTYPE_INST_VAR (current_class_type); + else + C_C_D = NULL_TREE; + current_function_decl = s->function_decl; + class_binding_level = s->class_bindings; + free (s); + binding_levels_sane(); +} + +/* Push a definition of struct, union or enum tag "name". + "type" should be the type node. + We assume that the tag "name" is not already defined. + + Note that the definition may really be just a forward reference. + In that case, the TYPE_SIZE will be a NULL_TREE. + + C++ gratuitously puts all these tags in the name space. */ + +/* When setting the IDENTIFIER_TYPE_VALUE field of an identifier ID, + record the shadowed value for this binding contour. TYPE is + the type that ID maps to. */ +void +set_identifier_type_value (id, type) + tree id; + tree type; +{ + if (current_binding_level != global_binding_level) + { + tree old_type_value = IDENTIFIER_TYPE_VALUE (id); + current_binding_level->type_shadowed + = tree_cons (id, old_type_value, current_binding_level->type_shadowed); + } + else if (class_binding_level) + { + tree old_type_value = IDENTIFIER_TYPE_VALUE (id); + class_binding_level->type_shadowed + = tree_cons (id, old_type_value, class_binding_level->type_shadowed); + } + SET_IDENTIFIER_TYPE_VALUE (id, type); +} + +/* + * local values can need to be shadowed too, but it only happens + * explicitly from pushdecl, in support of nested enums. + */ +void +set_identifier_local_value (id, type) + tree id; + tree type; +{ + if (current_binding_level != global_binding_level) + { + tree old_local_value = IDENTIFIER_LOCAL_VALUE (id); + current_binding_level->shadowed + = tree_cons (id, old_local_value, current_binding_level->shadowed); + } + else if (class_binding_level) + { + tree old_local_value = IDENTIFIER_LOCAL_VALUE (id); + class_binding_level->shadowed + = tree_cons (id, old_local_value, class_binding_level->shadowed); + } + IDENTIFIER_LOCAL_VALUE (id) = type; +} + +/* Subroutine "set_nested_typename" builds the nested-typename of + the type decl in question. (Argument CLASSNAME can actually be + a function as well, if that's the smallest containing scope.) */ + +static void +set_nested_typename (decl, classname, name, type) + tree decl, classname, name, type; +{ + my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 136); + if (classname != NULL_TREE) + { + char *buf; + my_friendly_assert (TREE_CODE (classname) == IDENTIFIER_NODE, 137); + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 138); + buf = (char *) alloca (4 + IDENTIFIER_LENGTH (classname) + + IDENTIFIER_LENGTH (name)); + sprintf (buf, "%s::%s", IDENTIFIER_POINTER (classname), + IDENTIFIER_POINTER (name)); + DECL_NESTED_TYPENAME (decl) = get_identifier (buf); + SET_IDENTIFIER_TYPE_VALUE (DECL_NESTED_TYPENAME (decl), type); + } + else + DECL_NESTED_TYPENAME (decl) = name; +} + +#if 0 /* not yet, should get fixed properly later */ +/* Create a TYPE_DECL node with the correct DECL_ASSEMBLER_NAME. + Other routines shouldn't use build_decl directly; they'll produce + incorrect results with `-g' unless they duplicate this code. + + This is currently needed mainly for dbxout.c, but we can make + use of it in cp-method.c later as well. */ +tree +make_type_decl (name, type) + tree name, type; +{ + tree decl, id; + decl = build_decl (TYPE_DECL, name, type); + if (TYPE_NAME (type) == name) + /* Class/union/enum definition, or a redundant typedef for same. */ + { + id = get_identifier (build_overload_name (type, 1, 1)); + DECL_ASSEMBLER_NAME (decl) = id; + } + else if (TYPE_NAME (type) != NULL_TREE) + /* Explicit typedef, or implicit typedef for template expansion. */ + DECL_ASSEMBLER_NAME (decl) = DECL_ASSEMBLER_NAME (TYPE_NAME (type)); + else + { + /* Typedef for unnamed struct; some other situations. + TYPE_NAME is null; what's right here? */ + } + return decl; +} + +#endif +void +pushtag (name, type) + tree name, type; +{ + register struct binding_level *b; + + if (class_binding_level) + b = class_binding_level; + else + { + b = current_binding_level; + while (b->tag_transparent) b = b->level_chain; + } + + if (b == global_binding_level) + b->tags = perm_tree_cons (name, type, b->tags); + else + b->tags = saveable_tree_cons (name, type, b->tags); + + if (name) + { + /* Record the identifier as the type's name if it has none. */ + + if (TYPE_NAME (type) == NULL_TREE) + TYPE_NAME (type) = name; + + /* Do C++ gratuitous typedefing. */ + if (IDENTIFIER_TYPE_VALUE (name) != type + && (TREE_CODE (type) != RECORD_TYPE + || class_binding_level == (struct binding_level *)0 + || !CLASSTYPE_DECLARED_EXCEPTION (type))) + { + register tree d; + if (current_class_type == NULL_TREE + || TYPE_SIZE (current_class_type) != NULL_TREE) + { + if (current_lang_name == lang_name_cplusplus) + d = lookup_nested_type (type, current_class_type ? TYPE_NAME (current_class_type) : NULL_TREE); + else + d = NULL_TREE; + + if (d == NULL_TREE) + { +#if 0 /* not yet, should get fixed properly later */ + d = make_type_decl (name, type); + DECL_ASSEMBLER_NAME (d) = get_identifier (build_overload_name (type, 1, 1)); +#else + d = build_decl (TYPE_DECL, name, type); + DECL_ASSEMBLER_NAME (d) = get_identifier (build_overload_name (type, 1, 1)); +#endif + /* mark the binding layer marker as internal. (mrs) */ + DECL_SOURCE_LINE (d) = 0; + set_identifier_type_value (name, type); + } + else + d = TYPE_NAME (d); + + /* If it is anonymous, then we are called from pushdecl, + and we don't want to infinitely recurse. Also, if the + name is already in scope, we don't want to push it + again--pushdecl is only for pushing new decls. */ + if (! ANON_AGGRNAME_P (name) + && TYPE_NAME (type) + && (TREE_CODE (TYPE_NAME (type)) != TYPE_DECL + || lookup_name (name, 1) != TYPE_NAME (type))) + { + if (class_binding_level) + d = pushdecl_class_level (d); + else + d = pushdecl (d); + } + } + else + { + /* Make nested declarations go into class-level scope. */ + d = build_lang_field_decl (TYPE_DECL, name, type); + set_identifier_type_value (name, type); + d = pushdecl_class_level (d); + } + if (ANON_AGGRNAME_P (name)) + DECL_IGNORED_P (d) = 1; + TYPE_NAME (type) = d; + + if ((current_class_type == NULL_TREE + && current_function_decl == NULL_TREE) + || current_lang_name != lang_name_cplusplus) + /* Non-nested class. */ + DECL_NESTED_TYPENAME (d) = name; + else if (current_function_decl != NULL_TREE) + { + /* Function-nested class. */ + set_nested_typename (d, DECL_ASSEMBLER_NAME (current_function_decl), + name, type); + /* This builds the links for classes nested in fn scope. */ + DECL_CONTEXT (d) = current_function_decl; + } + else if (TYPE_SIZE (current_class_type) == NULL_TREE) + { + /* Class-nested class. */ + set_nested_typename (d, DECL_NESTED_TYPENAME (TYPE_NAME (current_class_type)), + name, type); + /* This builds the links for classes nested in type scope. */ + DECL_CONTEXT (d) = current_class_type; + DECL_CLASS_CONTEXT (d) = current_class_type; + } + } + if (b->parm_flag == 2) + { + TREE_NONLOCAL_FLAG (type) = 1; + IDENTIFIER_CLASS_VALUE (name) = TYPE_NAME (type); + if (TYPE_SIZE (current_class_type) == NULL_TREE) + CLASSTYPE_TAGS (current_class_type) = b->tags; + } + } + + if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) + /* Use the canonical TYPE_DECL for this node. */ + TYPE_STUB_DECL (type) = TYPE_NAME (type); + else + { + /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE + will be the tagged type we just added to the current + binding level. This fake NULL-named TYPE_DECL node helps + dwarfout.c to know when it needs to output a + representation of a tagged type, and it also gives us a + convenient place to record the "scope start" address for + the tagged type. */ + +#if 0 /* not yet, should get fixed properly later */ + TYPE_STUB_DECL (type) = pushdecl (make_type_decl (NULL, type)); +#else + TYPE_STUB_DECL (type) = pushdecl (build_decl (TYPE_DECL, NULL_TREE, type)); +#endif + } +} + +/* Counter used to create anonymous type names. */ +static int anon_cnt = 0; + +/* Return an IDENTIFIER which can be used as a name for + anonymous structs and unions. */ +tree +make_anon_name () +{ + char buf[32]; + + sprintf (buf, ANON_AGGRNAME_FORMAT, anon_cnt++); + return get_identifier (buf); +} + +/* Clear the TREE_PURPOSE slot of tags which have anonymous typenames. + This keeps dbxout from getting confused. */ +void +clear_anon_tags () +{ + register struct binding_level *b; + register tree tags; + static int last_cnt = 0; + + /* Fast out if no new anon names were declared. */ + if (last_cnt == anon_cnt) + return; + + b = current_binding_level; + while (b->tag_transparent) + b = b->level_chain; + tags = b->tags; + while (tags) + { + /* A NULL purpose means we have already processed all tags + from here to the end of the list. */ + if (TREE_PURPOSE (tags) == NULL_TREE) + break; + if (ANON_AGGRNAME_P (TREE_PURPOSE (tags))) + TREE_PURPOSE (tags) = NULL_TREE; + tags = TREE_CHAIN (tags); + } + last_cnt = anon_cnt; +} + +/* Subroutine of duplicate_decls: return truthvalue of whether + or not types of these decls match. */ +static int +decls_match (newdecl, olddecl) + tree newdecl, olddecl; +{ + int types_match; + + if (TREE_CODE (newdecl) == FUNCTION_DECL && TREE_CODE (olddecl) == FUNCTION_DECL) + { + tree f1 = TREE_TYPE (newdecl); + tree f2 = TREE_TYPE (olddecl); + tree p1 = TYPE_ARG_TYPES (f1); + tree p2 = TYPE_ARG_TYPES (f2); + + /* When we parse a static member function definition, + we put together a FUNCTION_DECL which thinks its type + is METHOD_TYPE. Change that to FUNCTION_TYPE, and + proceed. */ + if (TREE_CODE (f1) == METHOD_TYPE && DECL_STATIC_FUNCTION_P (olddecl)) + revert_static_member_fn (&f1, &newdecl, &p1); + else if (TREE_CODE (f2) == METHOD_TYPE + && DECL_STATIC_FUNCTION_P (newdecl)) + revert_static_member_fn (&f2, &olddecl, &p2); + + /* Here we must take care of the case where new default + parameters are specified. Also, warn if an old + declaration becomes ambiguous because default + parameters may cause the two to be ambiguous. */ + if (TREE_CODE (f1) != TREE_CODE (f2)) + { + if (TREE_CODE (f1) == OFFSET_TYPE) + compiler_error_with_decl (newdecl, "`%s' redeclared as member function"); + else + compiler_error_with_decl (newdecl, "`%s' redeclared as non-member function"); + return 0; + } + + if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (f1)), + TYPE_MAIN_VARIANT (TREE_TYPE (f2)), 1)) + types_match = compparms (p1, p2, 1); + else types_match = 0; + } + else + { + if (TREE_TYPE (newdecl) == error_mark_node) + types_match = TREE_TYPE (olddecl) == error_mark_node; + else if (TREE_TYPE (olddecl) == NULL_TREE) + types_match = TREE_TYPE (newdecl) == NULL_TREE; + else + types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 1); + } + + return types_match; +} + +/* Handle when a new declaration NEWDECL has the same name as an old + one OLDDECL in the same binding contour. Prints an error message + if appropriate. + + If safely possible, alter OLDDECL to look like NEWDECL, and return 1. + Otherwise, return 0. */ + +static int +duplicate_decls (newdecl, olddecl) + register tree newdecl, olddecl; +{ + extern struct obstack permanent_obstack; + unsigned olddecl_uid = DECL_UID (olddecl); + int olddecl_friend = 0, types_match; + int new_defines_function; + register unsigned saved_old_decl_uid; + register int saved_old_decl_friend_p; + + if (TREE_CODE (olddecl) == TREE_LIST + && TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* If a new decl finds a list of old decls, then + we assume that the new decl has C linkage, and + that the old decls have C++ linkage. In this case, + we must look through the list to see whether + there is an ambiguity or not. */ + tree olddecls = olddecl; + + /* If the overload list is empty, just install the decl. */ + if (TREE_VALUE (olddecls) == NULL_TREE) + { + TREE_VALUE (olddecls) = newdecl; + return 1; + } + + while (olddecls) + { + if (decls_match (newdecl, TREE_VALUE (olddecls))) + { + if (TREE_CODE (newdecl) == VAR_DECL) + ; + else if (DECL_LANGUAGE (newdecl) + != DECL_LANGUAGE (TREE_VALUE (olddecls))) + { + error_with_decl (newdecl, "declaration of `%s' with different language linkage"); + error_with_decl (TREE_VALUE (olddecls), "previous declaration here"); + } + types_match = 1; + break; + } + olddecls = TREE_CHAIN (olddecls); + } + if (olddecls) + olddecl = TREE_VALUE (olddecl); + else + return 1; + } + else + { + if (TREE_CODE (olddecl) != TREE_LIST) + olddecl_friend = DECL_LANG_SPECIFIC (olddecl) && DECL_FRIEND_P (olddecl); + types_match = decls_match (newdecl, olddecl); + } + + if ((TREE_TYPE (newdecl) && TREE_CODE (TREE_TYPE (newdecl)) == ERROR_MARK) + || (TREE_TYPE (olddecl) && TREE_CODE (TREE_TYPE (olddecl)) == ERROR_MARK)) + types_match = 0; + + /* If this decl has linkage, and the old one does too, maybe no error. */ + if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) + { + error_with_decl (newdecl, "`%s' redeclared as different kind of symbol"); + if (TREE_CODE (olddecl) == TREE_LIST) + olddecl = TREE_VALUE (olddecl); + error_with_decl (olddecl, "previous declaration of `%s'"); + + /* New decl is completely inconsistent with the old one => + tell caller to replace the old one. */ + + return 0; + } + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* Now that functions must hold information normally held + by field decls, there is extra work to do so that + declaration information does not get destroyed during + definition. */ + if (DECL_VINDEX (olddecl)) + DECL_VINDEX (newdecl) = DECL_VINDEX (olddecl); + if (DECL_CONTEXT (olddecl)) + DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl); + if (DECL_CLASS_CONTEXT (olddecl)) + DECL_CLASS_CONTEXT (newdecl) = DECL_CLASS_CONTEXT (olddecl); + if (DECL_CHAIN (newdecl) == NULL_TREE) + DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl); + if (DECL_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0) + DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl); + } + + if (flag_traditional && TREE_CODE (newdecl) == FUNCTION_DECL + && IDENTIFIER_IMPLICIT_DECL (DECL_ASSEMBLER_NAME (newdecl)) == olddecl) + /* If -traditional, avoid error for redeclaring fcn + after implicit decl. */ + ; + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_BUILT_IN (olddecl)) + { + if (!types_match) + { + error_with_decl (newdecl, "declaration of `%s'"); + error_with_decl (olddecl, "conflicts with built-in declaration `%s'"); + } + } + else if (!types_match) + { + tree oldtype = TREE_TYPE (olddecl); + tree newtype = TREE_TYPE (newdecl); + int give_error = 0; + + /* Already complained about this, so don't do so again. */ + if (current_class_type == NULL_TREE + || IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (newdecl)) != current_class_type) + { + give_error = 1; + error_with_decl (newdecl, "conflicting types for `%s'"); + } + + /* Check for function type mismatch + involving an empty arglist vs a nonempty one. */ + if (TREE_CODE (olddecl) == FUNCTION_DECL + && comptypes (TREE_TYPE (oldtype), + TREE_TYPE (newtype), 1) + && ((TYPE_ARG_TYPES (oldtype) == NULL_TREE + && DECL_INITIAL (olddecl) == NULL_TREE) + || (TYPE_ARG_TYPES (newtype) == NULL_TREE + && DECL_INITIAL (newdecl) == NULL_TREE))) + { + /* Classify the problem further. */ + register tree t = TYPE_ARG_TYPES (oldtype); + if (t == NULL_TREE) + t = TYPE_ARG_TYPES (newtype); + for (; t; t = TREE_CHAIN (t)) + { + register tree type = TREE_VALUE (t); + + if (TREE_CHAIN (t) == NULL_TREE && type != void_type_node) + { + error ("A parameter list with an ellipsis can't match"); + error ("an empty parameter name list declaration."); + break; + } + + if (TYPE_MAIN_VARIANT (type) == float_type_node + || C_PROMOTING_INTEGER_TYPE_P (type)) + { + error ("An argument type that has a default promotion"); + error ("can't match an empty parameter name list declaration."); + break; + } + } + } + if (give_error) + error_with_decl (olddecl, "previous declaration of `%s'"); + + /* There is one thing GNU C++ cannot tolerate: a constructor + which takes the type of object being constructed. + Farm that case out here. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_CONSTRUCTOR_P (newdecl)) + { + tree tmp = TREE_CHAIN (TYPE_ARG_TYPES (newtype)); + + if (tmp != NULL_TREE + && (TYPE_MAIN_VARIANT (TREE_VALUE (tmp)) + == TYPE_METHOD_BASETYPE (newtype))) + { + tree parm = TREE_CHAIN (DECL_ARGUMENTS (newdecl)); + tree argtypes + = hash_tree_chain (build_reference_type (TREE_VALUE (tmp)), + TREE_CHAIN (tmp)); + + DECL_ARG_TYPE (parm) + = TREE_TYPE (parm) + = TYPE_REFERENCE_TO (TREE_VALUE (tmp)); + + TREE_TYPE (newdecl) = newtype + = build_cplus_method_type (TYPE_METHOD_BASETYPE (newtype), + TREE_TYPE (newtype), argtypes); + error ("constructor cannot take as argument the type being constructed"); + SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (newdecl), current_class_type); + } + } + } + else + { + char *errmsg = redeclaration_error_message (newdecl, olddecl); + if (errmsg) + { + error_with_decl (newdecl, errmsg); + if (DECL_NAME (olddecl) != NULL_TREE) + error_with_decl (olddecl, + (DECL_INITIAL (olddecl) + && current_binding_level == global_binding_level) + ? "`%s' previously defined here" + : "`%s' previously declared here"); + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_INITIAL (olddecl) != NULL_TREE + && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) == NULL_TREE + && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != NULL_TREE) + { + /* Prototype decl follows defn w/o prototype. */ + warning_with_decl (newdecl, "prototype for `%s'"); + warning_with_decl (olddecl, + "follows non-prototype definition here"); + } + + /* These bits are logically part of the type. */ + if (pedantic + && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl) + || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))) + error_with_decl (newdecl, "type qualifiers for `%s' conflict with previous decl"); + } + + /* Deal with C++: must preserve virtual function table size. */ + if (TREE_CODE (olddecl) == TYPE_DECL) + { + if (TYPE_LANG_SPECIFIC (TREE_TYPE (newdecl)) + && TYPE_LANG_SPECIFIC (TREE_TYPE (olddecl))) + { + CLASSTYPE_VSIZE (TREE_TYPE (newdecl)) + = CLASSTYPE_VSIZE (TREE_TYPE (olddecl)); + CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (newdecl)) + = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (olddecl)); + } + /* why assert here? Just because debugging information is + messed up? (mrs) */ + /* it happens on something like: + typedef struct Thing { + Thing(); + int x; + } Thing; + */ +#if 0 + my_friendly_assert (DECL_IGNORED_P (olddecl) == DECL_IGNORED_P (newdecl), 139); +#endif + } + + /* Special handling ensues if new decl is a function definition. */ + new_defines_function = (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) != NULL_TREE); + + /* Optionally warn about more than one declaration for the same name, + but don't warn about a function declaration followed by a definition. */ + if (warn_redundant_decls + && DECL_SOURCE_LINE (olddecl) != 0 + && !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE)) + { + warning_with_decl (newdecl, "redundant redeclaration of `%s' in same scope"); + warning_with_decl (olddecl, "previous declaration of `%s'"); + } + + /* Copy all the DECL_... slots specified in the new decl + except for any that we copy here from the old type. */ + + if (types_match) + { + /* Automatically handles default parameters. */ + tree oldtype = TREE_TYPE (olddecl); + /* Merge the data types specified in the two decls. */ + tree newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); + + if (TREE_CODE (newdecl) == VAR_DECL) + DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl); + /* Do this after calling `common_type' so that default + parameters don't confuse us. */ + else if (TREE_CODE (newdecl) == FUNCTION_DECL + && (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)) + != TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)))) + { + tree ctype = NULL_TREE; + ctype = DECL_CLASS_CONTEXT (newdecl); + TREE_TYPE (newdecl) = build_exception_variant (ctype, newtype, + TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl))); + TREE_TYPE (olddecl) = build_exception_variant (ctype, newtype, + TYPE_RAISES_EXCEPTIONS (oldtype)); + + if (! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE(olddecl), 0)) + { + error_with_decl (newdecl, "declaration of `%s' raises different exceptions..."); + error_with_decl (olddecl, "...from previous declaration here"); + } + } + TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype; + + /* Lay the type out, unless already done. */ + if (oldtype != TREE_TYPE (newdecl)) + { + if (TREE_TYPE (newdecl) != error_mark_node) + layout_type (TREE_TYPE (newdecl)); + if (TREE_CODE (newdecl) != FUNCTION_DECL + && TREE_CODE (newdecl) != TYPE_DECL + && TREE_CODE (newdecl) != CONST_DECL) + layout_decl (newdecl, 0); + } + else + { + /* Since the type is OLDDECL's, make OLDDECL's size go with. */ + DECL_SIZE (newdecl) = DECL_SIZE (olddecl); + } + + /* Merge the type qualifiers. */ + if (TREE_READONLY (newdecl)) + TREE_READONLY (olddecl) = 1; + if (TREE_THIS_VOLATILE (newdecl)) + TREE_THIS_VOLATILE (olddecl) = 1; + + /* Merge the initialization information. */ + if (DECL_INITIAL (newdecl) == NULL_TREE) + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + /* Keep the old rtl since we can safely use it, unless it's the + call to abort() used for abstract virtuals. */ + if ((DECL_LANG_SPECIFIC (olddecl) + && !DECL_ABSTRACT_VIRTUAL_P (olddecl)) + || DECL_RTL (olddecl) != DECL_RTL (abort_fndecl)) + DECL_RTL (newdecl) = DECL_RTL (olddecl); + } + /* If cannot merge, then use the new type and qualifiers, + and don't preserve the old rtl. */ + else + { + /* Clean out any memory we had of the old declaration. */ + tree oldstatic = value_member (olddecl, static_aggregates); + if (oldstatic) + TREE_VALUE (oldstatic) = error_mark_node; + + TREE_TYPE (olddecl) = TREE_TYPE (newdecl); + TREE_READONLY (olddecl) = TREE_READONLY (newdecl); + TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); + TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl); + } + + /* Merge the storage class information. */ + if (DECL_EXTERNAL (newdecl)) + { + TREE_STATIC (newdecl) = TREE_STATIC (olddecl); + DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl); + + /* For functions, static overrides non-static. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl); + /* This is since we don't automatically + copy the attributes of NEWDECL into OLDDECL. */ + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + /* If this clears `static', clear it in the identifier too. */ + if (! TREE_PUBLIC (olddecl)) + TREE_PUBLIC (DECL_ASSEMBLER_NAME (olddecl)) = 0; + } + else + TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); + } + else + { + TREE_STATIC (olddecl) = TREE_STATIC (newdecl); + /* A `const' which was not declared `extern' and is + in static storage is invisible. */ + if (TREE_CODE (newdecl) == VAR_DECL + && TREE_READONLY (newdecl) && TREE_STATIC (newdecl) + && ! DECL_THIS_EXTERN (newdecl)) + TREE_PUBLIC (newdecl) = 0; + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + } + + /* If either decl says `inline', this fn is inline, + unless its definition was passed already. */ + if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == NULL_TREE) + DECL_INLINE (olddecl) = 1; + DECL_INLINE (newdecl) = DECL_INLINE (olddecl); + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + if (new_defines_function) + /* If defining a function declared with other language + linkage, use the previously declared language linkage. */ + DECL_LANGUAGE (newdecl) = DECL_LANGUAGE (olddecl); + else + { + /* If redeclaring a builtin function, and not a definition, + it stays built in. */ + if (DECL_BUILT_IN (olddecl)) + { + DECL_BUILT_IN (newdecl) = 1; + DECL_SET_FUNCTION_CODE (newdecl, DECL_FUNCTION_CODE (olddecl)); + /* If we're keeping the built-in definition, keep the rtl, + regardless of declaration matches. */ + DECL_RTL (newdecl) = DECL_RTL (olddecl); + } + else + DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl); + + DECL_RESULT (newdecl) = DECL_RESULT (olddecl); + if (DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl)) + /* Previously saved insns go together with + the function's previous definition. */ + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + /* Don't clear out the arguments if we're redefining a function. */ + if (DECL_ARGUMENTS (olddecl)) + DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); + } + } + + /* Now preserve various other info from the definition. */ + TREE_ADDRESSABLE (newdecl) = TREE_ADDRESSABLE (olddecl); + TREE_ASM_WRITTEN (newdecl) = TREE_ASM_WRITTEN (olddecl); + + /* Don't really know how much of the language-specific + values we should copy from old to new. */ +#if 1 + if (DECL_LANG_SPECIFIC (olddecl)) + DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl); +#endif + + /* We are about to copy the contexts of newdecl into olddecl, so save a + few tidbits of information from olddecl that we may need to restore + after the copying takes place. */ + + saved_old_decl_uid = DECL_UID (olddecl); + saved_old_decl_friend_p + = DECL_LANG_SPECIFIC (olddecl) ? DECL_FRIEND_P (olddecl) : 0; + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + int function_size; + struct lang_decl *ol = DECL_LANG_SPECIFIC (olddecl); + struct lang_decl *nl = DECL_LANG_SPECIFIC (newdecl); + + function_size = sizeof (struct tree_decl); + + bcopy ((char *) newdecl + sizeof (struct tree_common), + (char *) olddecl + sizeof (struct tree_common), + function_size - sizeof (struct tree_common)); + + if ((char *)newdecl + ((function_size + sizeof (struct lang_decl) + + obstack_alignment_mask (&permanent_obstack)) + & ~ obstack_alignment_mask (&permanent_obstack)) + == obstack_next_free (&permanent_obstack)) + { + DECL_MAIN_VARIANT (newdecl) = olddecl; + DECL_LANG_SPECIFIC (olddecl) = ol; + bcopy ((char *)nl, (char *)ol, sizeof (struct lang_decl)); + + obstack_free (&permanent_obstack, newdecl); + } + else if (LANG_DECL_PERMANENT (ol)) + { + if (DECL_MAIN_VARIANT (olddecl) == olddecl) + { + /* Save these lang_decls that would otherwise be lost. */ + extern tree free_lang_decl_chain; + tree free_lang_decl = (tree) ol; + TREE_CHAIN (free_lang_decl) = free_lang_decl_chain; + free_lang_decl_chain = free_lang_decl; + } + else + { + /* Storage leak. */ + } + } + } + else + { + bcopy ((char *) newdecl + sizeof (struct tree_common), + (char *) olddecl + sizeof (struct tree_common), + sizeof (struct tree_decl) - sizeof (struct tree_common) + + tree_code_length [(int)TREE_CODE (newdecl)] * sizeof (char *)); + } + + DECL_UID (olddecl) = olddecl_uid; + if (olddecl_friend) + DECL_FRIEND_P (olddecl) = 1; + + /* Restore some pieces of information which were originally in olddecl. */ + + DECL_UID (olddecl) = saved_old_decl_uid; + if (DECL_LANG_SPECIFIC (olddecl)) + DECL_FRIEND_P (olddecl) |= saved_old_decl_friend_p; + + return 1; +} + +void +adjust_type_value (id) + tree id; +{ + tree t; + + if (current_binding_level != global_binding_level) + { + if (current_binding_level != class_binding_level) + { + t = IDENTIFIER_LOCAL_VALUE (id); + if (t && TREE_CODE (t) == TYPE_DECL) + { + set_it: + SET_IDENTIFIER_TYPE_VALUE (id, TREE_TYPE (t)); + return; + } + } + else + my_friendly_abort (7); + + if (current_class_type) + { + t = IDENTIFIER_CLASS_VALUE (id); + if (t && TREE_CODE (t) == TYPE_DECL) + goto set_it; + } + } + + t = IDENTIFIER_GLOBAL_VALUE (id); + if (t && TREE_CODE (t) == TYPE_DECL) + goto set_it; + if (t && TREE_CODE (t) == TEMPLATE_DECL) + SET_IDENTIFIER_TYPE_VALUE (id, NULL_TREE); +} + +/* Record a decl-node X as belonging to the current lexical scope. + Check for errors (such as an incompatible declaration for the same + name already seen in the same scope). + + Returns either X or an old decl for the same name. + If an old decl is returned, it may have been smashed + to agree with what X says. */ + +tree +pushdecl (x) + tree x; +{ + register tree t; +#if 0 /* not yet, should get fixed properly later */ + register tree name; +#else + register tree name = DECL_ASSEMBLER_NAME (x); +#endif + register struct binding_level *b = current_binding_level; + +#if 0 + static int nglobals; int len; + + len = list_length (global_binding_level->names); + if (len < nglobals) + my_friendly_abort (8); + else if (len > nglobals) + nglobals = len; +#endif + + /* Don't change DECL_CONTEXT of virtual methods. */ + if (x != current_function_decl + && (TREE_CODE (x) != FUNCTION_DECL + || !DECL_VIRTUAL_P (x))) + DECL_CONTEXT (x) = current_function_decl; + /* A local declaration for a function doesn't constitute nesting. */ + if (TREE_CODE (x) == FUNCTION_DECL && DECL_INITIAL (x) == 0) + DECL_CONTEXT (x) = 0; + +#if 0 /* not yet, should get fixed properly later */ + /* For functions and class static data, we currently look up the encoded + form of the name. For types, we want the real name. The former will + probably be changed soon, according to MDT. */ + if (TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL) + name = DECL_ASSEMBLER_NAME (x); + else + name = DECL_NAME (x); +#else + /* Type are looked up using the DECL_NAME, as that is what the rest of the + compiler wants to use. */ + if (TREE_CODE (x) == TYPE_DECL) + name = DECL_NAME (x); +#endif + + if (name) + { + char *file; + int line; + + t = lookup_name_current_level (name); + if (t == error_mark_node) + { + /* error_mark_node is 0 for a while during initialization! */ + t = NULL_TREE; + error_with_decl (x, "`%s' used prior to declaration"); + } + + if (t != NULL_TREE) + { + 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 (t != NULL_TREE && TREE_CODE (t) != TREE_CODE (x)) + { + if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (x) == TYPE_DECL) + { + /* We do nothing special here, because C++ does such nasty + things with TYPE_DECLs. Instead, just let the TYPE_DECL + get shadowed, and know that if we need to find a TYPE_DECL + for a given name, we can look in the IDENTIFIER_TYPE_VALUE + slot of the identifier. */ + ; + } + else if (duplicate_decls (x, t)) + return t; + } + else if (t != NULL_TREE && duplicate_decls (x, t)) + { + /* If this decl is `static' and an `extern' was seen previously, + that is erroneous. But don't complain if -traditional, + since traditional compilers don't complain. + + Note that this does not apply to the C++ case of declaring + a variable `extern const' and then later `const'. */ + if (!flag_traditional && TREE_PUBLIC (name) + && ! TREE_PUBLIC (x) && ! DECL_EXTERNAL (x) && ! DECL_INLINE (x)) + { + /* Due to interference in memory reclamation (X may be + obstack-deallocated at this point), we must guard against + one really special case. */ + if (current_function_decl == x) + current_function_decl = t; + if (IDENTIFIER_IMPLICIT_DECL (name)) + warning ("`%s' was declared implicitly `extern' and later `static'", + lang_printable_name (t)); + else + warning ("`%s' was declared `extern' and later `static'", + lang_printable_name (t)); + warning_with_file_and_line (file, line, + "previous declaration of `%s'", + lang_printable_name (t)); + } + return t; + } + + /* If declaring a type as a typedef, and the type has no known + typedef name, install this TYPE_DECL as its typedef name. + + C++: If it had an anonymous aggregate or enum name, + give it a `better' one. */ + if (TREE_CODE (x) == TYPE_DECL) + { + tree name = TYPE_NAME (TREE_TYPE (x)); + + if (name == NULL_TREE || TREE_CODE (name) != TYPE_DECL) + { + /* If these are different names, and we're at the global + binding level, make two equivalent definitions. */ + name = x; + if (global_bindings_p ()) + TYPE_NAME (TREE_TYPE (x)) = x; + } + else + { + tree tname = DECL_NAME (name); + if (global_bindings_p () && ANON_AGGRNAME_P (tname)) + { + /* do gratuitous C++ typedefing, and make sure that + we access this type either through TREE_TYPE field + or via the tags list. */ + TYPE_NAME (TREE_TYPE (x)) = x; + pushtag (tname, TREE_TYPE (x)); + } + } + my_friendly_assert (TREE_CODE (name) == TYPE_DECL, 140); + if (DECL_NAME (name) && !DECL_NESTED_TYPENAME (name)) + set_nested_typename (x, current_class_name, DECL_NAME (name), + TREE_TYPE (x)); + if (TYPE_NAME (TREE_TYPE (x)) && TYPE_IDENTIFIER (TREE_TYPE (x))) + set_identifier_type_value (DECL_NAME (x), TREE_TYPE (x)); +/* was using TYPE_IDENTIFIER (TREE_TYPE (x)) */ + } + + /* Multiple external decls of the same identifier ought to match. */ + + if (DECL_EXTERNAL (x) && IDENTIFIER_GLOBAL_VALUE (name) != NULL_TREE + && (DECL_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name)) + || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name))) + /* We get warnings about inline functions where they are defined. + Avoid duplicate warnings where they are used. */ + && !DECL_INLINE (x)) + { + if (! comptypes (TREE_TYPE (x), + TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)), 1)) + { + warning_with_decl (x, + "type mismatch with previous external decl"); + warning_with_decl (IDENTIFIER_GLOBAL_VALUE (name), + "previous external decl of `%s'"); + } + } + + /* In PCC-compatibility mode, extern decls of vars with no current decl + take effect at top level no matter where they are. */ + if (flag_traditional && DECL_EXTERNAL (x) + && lookup_name (name, 0) == NULL_TREE) + b = global_binding_level; + + /* This name is new in its binding level. + Install the new declaration and return it. */ + if (b == global_binding_level) + { + /* Install a global value. */ + + /* Rule for VAR_DECLs, but not for other kinds of _DECLs: + A `const' which was not declared `extern' is invisible. */ + if (TREE_CODE (x) == VAR_DECL + && TREE_READONLY (x) && ! DECL_THIS_EXTERN (x)) + TREE_PUBLIC (x) = 0; + + /* If the first global decl has external linkage, + warn if we later see static one. */ + if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && TREE_PUBLIC (x)) + TREE_PUBLIC (name) = 1; + + /* Don't install a TYPE_DECL if we already have another + sort of _DECL with that name. */ + if (TREE_CODE (x) != TYPE_DECL + || t == NULL_TREE + || TREE_CODE (t) == TYPE_DECL) +#if 0 + /* This has not be thoroughly tested yet. */ + /* It allows better dwarf debugging. */ + IDENTIFIER_GLOBAL_VALUE (name) + = TREE_CODE_CLASS (TREE_CODE (x)) == 'd' + ? x : build_decl (TYPE_DECL, NULL, TREE_TYPE (x)); +#else + IDENTIFIER_GLOBAL_VALUE (name) = x; +#endif + + /* Don't forget if the function was used via an implicit decl. */ + if (IDENTIFIER_IMPLICIT_DECL (name) + && TREE_USED (IDENTIFIER_IMPLICIT_DECL (name))) + TREE_USED (x) = 1; + + /* Don't forget if its address was taken in that way. */ + if (IDENTIFIER_IMPLICIT_DECL (name) + && TREE_ADDRESSABLE (IDENTIFIER_IMPLICIT_DECL (name))) + TREE_ADDRESSABLE (x) = 1; + + /* Warn about mismatches against previous implicit decl. */ + if (IDENTIFIER_IMPLICIT_DECL (name) != NULL_TREE + /* If this real decl matches the implicit, don't complain. */ + && ! (TREE_CODE (x) == FUNCTION_DECL + && TREE_TYPE (TREE_TYPE (x)) == integer_type_node)) + warning ("`%s' was previously implicitly declared to return `int'", + lang_printable_name (x)); + + /* If this decl is `static' and an `extern' was seen previously, + that is erroneous. Don't do this for TYPE_DECLs. */ + if (TREE_PUBLIC (name) + && TREE_CODE (x) != TYPE_DECL + && ! TREE_PUBLIC (x) && ! DECL_EXTERNAL (x)) + { + if (IDENTIFIER_IMPLICIT_DECL (name)) + warning ("`%s' was declared implicitly `extern' and later `static'", + lang_printable_name (x)); + else + warning ("`%s' was declared `extern' and later `static'", + lang_printable_name (x)); + } + } + else + { + /* Here to install a non-global value. */ + tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); + tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name); + set_identifier_local_value (name, x); + + /* If this is an extern function declaration, see if we + have a global definition or declaration for the function. */ + if (oldlocal == NULL_TREE + && DECL_EXTERNAL (x) && !DECL_INLINE (x) + && oldglobal != NULL_TREE + && TREE_CODE (x) == FUNCTION_DECL + && TREE_CODE (oldglobal) == FUNCTION_DECL) + { + /* We have one. Their types must agree. */ + if (! comptypes (TREE_TYPE (x), TREE_TYPE (oldglobal), 1)) + warning_with_decl (x, "extern declaration of `%s' doesn't match global one"); + else + { + /* Inner extern decl is inline if global one is. + Copy enough to really inline it. */ + if (DECL_INLINE (oldglobal)) + { + DECL_INLINE (x) = DECL_INLINE (oldglobal); + DECL_INITIAL (x) = (current_function_decl == oldglobal + ? NULL_TREE : DECL_INITIAL (oldglobal)); + DECL_SAVED_INSNS (x) = DECL_SAVED_INSNS (oldglobal); + DECL_ARGUMENTS (x) = DECL_ARGUMENTS (oldglobal); + DECL_RESULT (x) = DECL_RESULT (oldglobal); + TREE_ASM_WRITTEN (x) = TREE_ASM_WRITTEN (oldglobal); + DECL_ABSTRACT_ORIGIN (x) = oldglobal; + } + /* Inner extern decl is built-in if global one is. */ + if (DECL_BUILT_IN (oldglobal)) + { + DECL_BUILT_IN (x) = DECL_BUILT_IN (oldglobal); + DECL_SET_FUNCTION_CODE (x, DECL_FUNCTION_CODE (oldglobal)); + } + /* Keep the arg types from a file-scope fcn defn. */ + if (TYPE_ARG_TYPES (TREE_TYPE (oldglobal)) != NULL_TREE + && DECL_INITIAL (oldglobal) + && TYPE_ARG_TYPES (TREE_TYPE (x)) == NULL_TREE) + TREE_TYPE (x) = TREE_TYPE (oldglobal); + } + } + /* If we have a local external declaration, + and no file-scope declaration has yet been seen, + then if we later have a file-scope decl it must not be static. */ + if (oldlocal == NULL_TREE + && oldglobal == NULL_TREE + && DECL_EXTERNAL (x) + && TREE_PUBLIC (x)) + { + TREE_PUBLIC (name) = 1; + } + + if (DECL_FROM_INLINE (x)) + /* Inline decls shadow nothing. */; + + /* Warn if shadowing an argument at the top level of the body. */ + else if (oldlocal != NULL_TREE && !DECL_EXTERNAL (x) + && TREE_CODE (oldlocal) == PARM_DECL + && TREE_CODE (x) != PARM_DECL) + { + /* Go to where the parms should be and see if we + find them there. */ + struct binding_level *b = current_binding_level->level_chain; + + if (cleanup_label) + b = b->level_chain; + + /* ARM $8.3 */ + if (b->parm_flag == 1) + pedwarn ("declaration of `%s' shadows a parameter", + IDENTIFIER_POINTER (name)); + } + /* Maybe warn if shadowing something else. */ + else if (warn_shadow && !DECL_EXTERNAL (x) + /* No shadow warnings for internally generated vars. */ + && DECL_SOURCE_LINE (x) != 0 + /* No shadow warnings for vars made for inlining. */ + && ! DECL_FROM_INLINE (x)) + { + char *warnstring = NULL; + + if (oldlocal != NULL_TREE && TREE_CODE (oldlocal) == PARM_DECL) + warnstring = "declaration of `%s' shadows a parameter"; + else if (IDENTIFIER_CLASS_VALUE (name) != NULL_TREE) + warnstring = "declaration of `%s' shadows a member of `this'"; + else if (oldlocal != NULL_TREE) + warnstring = "declaration of `%s' shadows previous local"; + else if (oldglobal != NULL_TREE) + warnstring = "declaration of `%s' shadows global declaration"; + + if (warnstring) + warning (warnstring, IDENTIFIER_POINTER (name)); + } + + /* If storing a local value, there may already be one (inherited). + If so, record it for restoration when this binding level ends. */ + if (oldlocal != NULL_TREE) + b->shadowed = tree_cons (name, oldlocal, b->shadowed); + } + + /* Keep count of variables in this level with incomplete type. */ + if (TREE_CODE (x) != TEMPLATE_DECL + && TREE_CODE (x) != CPLUS_CATCH_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"); + } + } + + if (TREE_CODE (x) == TYPE_DECL && name != NULL_TREE) + { + adjust_type_value (name); + if (current_class_name) + { + if (!DECL_NESTED_TYPENAME (x)) + set_nested_typename (x, current_class_name, DECL_NAME (x), + TREE_TYPE (x)); + adjust_type_value (DECL_NESTED_TYPENAME (x)); + } + } + + /* Put decls on list in reverse order. + We will reverse them later if necessary. */ + TREE_CHAIN (x) = b->names; + b->names = x; + if (! (b != global_binding_level || TREE_PERMANENT (x))) + my_friendly_abort (124); + + return x; +} + +/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, + if appropriate. */ +tree +pushdecl_top_level (x) + tree x; +{ + register tree t; + register struct binding_level *b = current_binding_level; + + current_binding_level = global_binding_level; + t = pushdecl (x); + current_binding_level = b; + if (class_binding_level) + b = class_binding_level; + /* Now, the type_shadowed stack may screw us. Munge it so it does + what we want. */ + if (TREE_CODE (x) == TYPE_DECL) + { + tree name = DECL_NAME (x); + tree newval; + tree *ptr = (tree *)0; + for (; b != global_binding_level; b = b->level_chain) + { + tree shadowed = b->type_shadowed; + for (; shadowed; shadowed = TREE_CHAIN (shadowed)) + if (TREE_PURPOSE (shadowed) == name) + { + ptr = &TREE_VALUE (shadowed); + /* Can't break out of the loop here because sometimes + a binding level will have duplicate bindings for + PT names. It's gross, but I haven't time to fix it. */ + } + } + newval = TREE_TYPE (x); + if (ptr == (tree *)0) + { + /* @@ This shouldn't be needed. My test case "zstring.cc" trips + up here if this is changed to an assertion. --KR */ + SET_IDENTIFIER_TYPE_VALUE (name, newval); + } + else + { +#if 0 + /* Disabled this 11/10/92, since there are many cases which + behave just fine when *ptr doesn't satisfy either of these. + For example, nested classes declared as friends of their enclosing + class will not meet this criteria. (bpk) */ + my_friendly_assert (*ptr == NULL_TREE || *ptr == newval, 141); +#endif + *ptr = newval; + } + } + return t; +} + +/* Like push_overloaded_decl, only it places X in GLOBAL_BINDING_LEVEL, + if appropriate. */ +void +push_overloaded_decl_top_level (x, forget) + tree x; + int forget; +{ + struct binding_level *b = current_binding_level; + + current_binding_level = global_binding_level; + push_overloaded_decl (x, forget); + current_binding_level = b; +} + +/* Make the declaration of X appear in CLASS scope. */ +tree +pushdecl_class_level (x) + tree x; +{ + /* Don't use DECL_ASSEMBLER_NAME here! Everything that looks in class + scope looks for the pre-mangled name. */ + register tree name = DECL_NAME (x); + + if (name) + { + tree oldclass = IDENTIFIER_CLASS_VALUE (name); + if (oldclass) + class_binding_level->class_shadowed + = tree_cons (name, oldclass, class_binding_level->class_shadowed); + IDENTIFIER_CLASS_VALUE (name) = x; + obstack_ptr_grow (&decl_obstack, x); + if (TREE_CODE (x) == TYPE_DECL && !DECL_NESTED_TYPENAME (x)) + set_nested_typename (x, current_class_name, name, TREE_TYPE (x)); + } + return x; +} + +/* Tell caller how to interpret a TREE_LIST which contains + chains of FUNCTION_DECLS. */ +int +overloaded_globals_p (list) + tree list; +{ + my_friendly_assert (TREE_CODE (list) == TREE_LIST, 142); + + /* Don't commit caller to seeing them as globals. */ + if (TREE_NONLOCAL_FLAG (list)) + return -1; + /* Do commit caller to seeing them as globals. */ + if (TREE_CODE (TREE_PURPOSE (list)) == IDENTIFIER_NODE) + return 1; + /* Do commit caller to not seeing them as globals. */ + return 0; +} + +/* DECL is a FUNCTION_DECL which may have other definitions already in place. + We get around this by making IDENTIFIER_GLOBAL_VALUE (DECL_NAME (DECL)) + point to a list of all the things that want to be referenced by that name. + It is then up to the users of that name to decide what to do with that + list. + + DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its DECL_RESULT + slot. It is dealt with the same way. + + The value returned may be a previous declaration if we guessed wrong + about what language DECL should belong to (C or C++). Otherwise, + it's always DECL (and never something that's not a _DECL). */ +tree +push_overloaded_decl (decl, forgettable) + tree decl; + int forgettable; +{ + tree orig_name = DECL_NAME (decl); + tree glob = IDENTIFIER_GLOBAL_VALUE (orig_name); + + DECL_OVERLOADED (decl) = 1; + if (glob) + { + if (TREE_CODE (glob) != TREE_LIST) + { + if (DECL_LANGUAGE (decl) == lang_c) + { + if (TREE_CODE (glob) == FUNCTION_DECL) + { + if (DECL_LANGUAGE (glob) == lang_c) + { + error_with_decl (decl, "C-language function `%s' overloaded here"); + error_with_decl (glob, "Previous C-language version of this function was `%s'"); + } + } + else + my_friendly_abort (9); + } + if (forgettable + && ! flag_traditional + && TREE_PERMANENT (glob) == 1 + && !global_bindings_p ()) + overloads_to_forget = tree_cons (orig_name, glob, overloads_to_forget); + /* We cache the value of builtin functions as ADDR_EXPRs + in the name space. Convert it to some kind of _DECL after + remembering what to forget. */ + if (TREE_CODE (glob) == ADDR_EXPR) + glob = TREE_OPERAND (glob, 0); + + if (TREE_CODE (glob) == FUNCTION_DECL + && DECL_LANGUAGE (glob) != DECL_LANGUAGE (decl) + && comptypes (TREE_TYPE (glob), TREE_TYPE (decl), 1)) + { + if (current_lang_stack == current_lang_base) + { + DECL_LANGUAGE (decl) = DECL_LANGUAGE (glob); + return glob; + } + else + { + error_with_decl (decl, "conflicting language contexts for declaration of `%s';"); + error_with_decl (glob, "conflicts with previous declaration here"); + } + } + if (pedantic && TREE_CODE (glob) == VAR_DECL) + { + my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (glob)) == 'd', 143); + error_with_decl (glob, "non-function declaration `%s'"); + error_with_decl (decl, "conflicts with function declaration `%s'"); + } + glob = tree_cons (orig_name, glob, NULL_TREE); + glob = tree_cons (TREE_PURPOSE (glob), decl, glob); + IDENTIFIER_GLOBAL_VALUE (orig_name) = glob; + TREE_TYPE (glob) = unknown_type_node; + return decl; + } + + if (TREE_VALUE (glob) == NULL_TREE) + { + TREE_VALUE (glob) = decl; + return decl; + } + if (TREE_CODE (decl) != TEMPLATE_DECL) + { + tree name = DECL_ASSEMBLER_NAME (decl); + tree tmp; + + for (tmp = glob; tmp; tmp = TREE_CHAIN (tmp)) + { + if (TREE_CODE (TREE_VALUE (tmp)) == FUNCTION_DECL + && DECL_LANGUAGE (TREE_VALUE (tmp)) != DECL_LANGUAGE (decl) + && comptypes (TREE_TYPE (TREE_VALUE (tmp)), TREE_TYPE (decl), + 1)) + { + error_with_decl (decl, + "conflicting language contexts for declaration of `%s';"); + error_with_decl (TREE_VALUE (tmp), + "conflicts with previous declaration here"); + } + if (TREE_CODE (TREE_VALUE (tmp)) != TEMPLATE_DECL + && DECL_ASSEMBLER_NAME (TREE_VALUE (tmp)) == name) + return decl; + } + } + } + if (DECL_LANGUAGE (decl) == lang_c) + { + tree decls = glob; + while (decls && DECL_LANGUAGE (TREE_VALUE (decls)) == lang_cplusplus) + decls = TREE_CHAIN (decls); + if (decls) + { + error_with_decl (decl, "C-language function `%s' overloaded here"); + error_with_decl (TREE_VALUE (decls), "Previous C-language version of this function was `%s'"); + } + } + + if (forgettable + && ! flag_traditional + && (glob == NULL_TREE || TREE_PERMANENT (glob) == 1) + && !global_bindings_p () + && !pseudo_global_level_p ()) + overloads_to_forget = tree_cons (orig_name, glob, overloads_to_forget); + glob = tree_cons (orig_name, decl, glob); + IDENTIFIER_GLOBAL_VALUE (orig_name) = glob; + TREE_TYPE (glob) = unknown_type_node; + return decl; +} + +/* Generate an implicit declaration for identifier FUNCTIONID + as a function of type int (). Print a warning if appropriate. */ + +tree +implicitly_declare (functionid) + 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 && (flag_traditional || !warn_implicit + || current_binding_level == global_binding_level)) + end_temporary_allocation (); + + /* We used to reuse an old implicit decl here, + but this loses with inline functions because it can clobber + the saved decl chains. */ + decl = build_lang_decl (FUNCTION_DECL, functionid, default_function_type); + + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + + /* ANSI standard says implicit declarations are in the innermost block. + So we record the decl in the standard fashion. + If flag_traditional is set, pushdecl does it top-level. */ + pushdecl (decl); + rest_of_decl_compilation (decl, NULL_PTR, 0, 0); + + if (warn_implicit + /* Only one warning per identifier. */ + && IDENTIFIER_IMPLICIT_DECL (functionid) == NULL_TREE) + { + pedwarn ("implicit declaration of function `%s'", + IDENTIFIER_POINTER (functionid)); + } + + SET_IDENTIFIER_IMPLICIT_DECL (functionid, decl); + + pop_obstacks (); + + return decl; +} + +/* Return zero if the declaration NEWDECL is valid + when the declaration OLDDECL (assumed to be for the same name) + has already been seen. + Otherwise return an error message format string with a %s + where the identifier should go. */ + +static char * +redeclaration_error_message (newdecl, olddecl) + tree newdecl, olddecl; +{ + if (TREE_CODE (newdecl) == TYPE_DECL) + { + /* Because C++ can put things into name space for free, + constructs like "typedef struct foo { ... } foo" + would look like an erroneous redeclaration. */ + if (TREE_TYPE (olddecl) == TREE_TYPE (newdecl)) + return 0; + else + return "redefinition of `%s'"; + } + else if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* If this is a pure function, its olddecl will actually be + the original initialization to `0' (which we force to call + abort()). Don't complain about redefinition in this case. */ + if (DECL_LANG_SPECIFIC (olddecl) && DECL_ABSTRACT_VIRTUAL_P (olddecl)) + return 0; + + /* Declarations of functions can insist on internal linkage + but they can't be inconsistent with internal linkage, + so there can be no error on that account. + However defining the same name twice is no good. */ + if (DECL_INITIAL (olddecl) != NULL_TREE + && DECL_INITIAL (newdecl) != NULL_TREE + /* However, defining once as extern inline and a second + time in another way is ok. */ + && !(DECL_INLINE (olddecl) && DECL_EXTERNAL (olddecl) + && !(DECL_INLINE (newdecl) && DECL_EXTERNAL (newdecl)))) + { + if (DECL_NAME (olddecl) == NULL_TREE) + return "`%s' not declared in class"; + else + return "redefinition of `%s'"; + } + return 0; + } + else if (current_binding_level == global_binding_level) + { + /* Objects declared at top level: */ + /* If at least one is a reference, it's ok. */ + if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl)) + return 0; + /* Reject two definitions. */ + if (DECL_INITIAL (olddecl) != NULL_TREE + && DECL_INITIAL (newdecl) != NULL_TREE) + return "redefinition of `%s'"; + /* Now we have two tentative defs, or one tentative and one real def. */ + /* Insist that the linkage match. */ + if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl)) + return "conflicting declarations of `%s'"; + return 0; + } + else + { + /* Objects declared with block scope: */ + /* Reject two definitions, and reject a definition + together with an external reference. */ + if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl))) + return "redeclaration of `%s'"; + return 0; + } +} + +/* Get the LABEL_DECL corresponding to identifier ID as a label. + Create one if none exists so far for the current function. + This function is called for both label definitions and label references. */ + +tree +lookup_label (id) + tree id; +{ + register tree decl = IDENTIFIER_LABEL_VALUE (id); + + if ((decl == NULL_TREE + || DECL_SOURCE_LINE (decl) == 0) + && (named_label_uses == 0 + || TREE_PURPOSE (named_label_uses) != current_binding_level->names + || TREE_VALUE (named_label_uses) != decl)) + { + named_label_uses + = tree_cons (current_binding_level->names, decl, named_label_uses); + TREE_TYPE (named_label_uses) = (tree)current_binding_level; + } + + /* Use a label already defined or ref'd with this name. */ + if (decl != NULL_TREE) + { + /* But not if it is inherited and wasn't declared to be inheritable. */ + if (DECL_CONTEXT (decl) != current_function_decl + && ! C_DECLARED_LABEL_FLAG (decl)) + return shadow_label (id); + return decl; + } + + decl = build_decl (LABEL_DECL, id, void_type_node); + + /* A label not explicitly declared must be local to where it's ref'd. */ + DECL_CONTEXT (decl) = current_function_decl; + + DECL_MODE (decl) = VOIDmode; + + /* Say where one reference is to the label, + for the sake of the error if it is not defined. */ + DECL_SOURCE_LINE (decl) = lineno; + DECL_SOURCE_FILE (decl) = input_filename; + + SET_IDENTIFIER_LABEL_VALUE (id, decl); + + named_labels = tree_cons (NULL_TREE, decl, named_labels); + TREE_VALUE (named_label_uses) = decl; + + return decl; +} + +/* Make a label named NAME in the current function, + shadowing silently any that may be inherited from containing functions + or containing scopes. + + Note that valid use, if the label being shadowed + comes from another scope in the same function, + requires calling declare_nonlocal_label right away. */ + +tree +shadow_label (name) + tree name; +{ + register tree decl = IDENTIFIER_LABEL_VALUE (name); + + if (decl != NULL_TREE) + { + shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels); + SET_IDENTIFIER_LABEL_VALUE (name, 0); + SET_IDENTIFIER_LABEL_VALUE (decl, 0); + } + + return lookup_label (name); +} + +/* Define a label, specifying the location in the source file. + Return the LABEL_DECL node for the label, if the definition is valid. + Otherwise return 0. */ + +tree +define_label (filename, line, name) + char *filename; + int line; + tree name; +{ + tree decl = lookup_label (name); + + /* After labels, make any new cleanups go into their + own new (temporary) binding contour. */ + current_binding_level->more_cleanups_ok = 0; + + /* If label with this name is known from an outer context, shadow it. */ + if (decl != NULL_TREE && DECL_CONTEXT (decl) != current_function_decl) + { + shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels); + SET_IDENTIFIER_LABEL_VALUE (name, 0); + decl = lookup_label (name); + } + + if (DECL_INITIAL (decl) != NULL_TREE) + { + error_with_decl (decl, "duplicate label `%s'"); + return 0; + } + else + { + tree uses, prev; + + /* Mark label as having been defined. */ + DECL_INITIAL (decl) = error_mark_node; + /* Say where in the source. */ + DECL_SOURCE_FILE (decl) = filename; + DECL_SOURCE_LINE (decl) = line; + + for (prev = NULL_TREE, uses = named_label_uses; + uses; + prev = uses, uses = TREE_CHAIN (uses)) + if (TREE_VALUE (uses) == decl) + { + struct binding_level *b = current_binding_level; + while (b) + { + tree new_decls = b->names; + tree old_decls = ((tree)b == TREE_TYPE (uses) + ? TREE_PURPOSE (uses) : NULL_TREE); + while (new_decls != old_decls) + { + if (TREE_CODE (new_decls) == VAR_DECL + /* Don't complain about crossing initialization + of internal entities. They can't be accessed, + and they should be cleaned up + by the time we get to the label. */ + && DECL_SOURCE_LINE (new_decls) != 0 + && ((DECL_INITIAL (new_decls) != NULL_TREE + && DECL_INITIAL (new_decls) != error_mark_node) + || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls)))) + { + if (IDENTIFIER_ERROR_LOCUS (decl) == NULL_TREE) + error_with_decl (decl, "invalid jump to label `%s'"); + SET_IDENTIFIER_ERROR_LOCUS (decl, current_function_decl); + error_with_decl (new_decls, "crosses initialization of `%s'"); + } + new_decls = TREE_CHAIN (new_decls); + } + if ((tree)b == TREE_TYPE (uses)) + break; + b = b->level_chain; + } + + if (prev) + TREE_CHAIN (prev) = TREE_CHAIN (uses); + else + named_label_uses = TREE_CHAIN (uses); + } + current_function_return_value = NULL_TREE; + return decl; + } +} + +/* Same, but for CASE labels. If DECL is NULL_TREE, it's the default. */ +/* XXX Note decl is never actually used. (bpk) */ +void +define_case_label (decl) + tree decl; +{ + tree cleanup = last_cleanup_this_contour (); + if (cleanup) + { + static int explained = 0; + error_with_decl (TREE_PURPOSE (cleanup), "destructor needed for `%s'"); + error ("where case label appears here"); + if (!explained) + { + error ("(enclose actions of previous case statements requiring"); + error ("destructors in their own binding contours.)"); + explained = 1; + } + } + + /* After labels, make any new cleanups go into their + own new (temporary) binding contour. */ + + current_binding_level->more_cleanups_ok = 0; + current_function_return_value = NULL_TREE; +} + +/* Return the list of declarations of the current level. + Note that this list is in reverse order unless/until + you nreverse it; and when you do nreverse it, you must + store the result back using `storedecls' or you will lose. */ + +tree +getdecls () +{ + return current_binding_level->names; +} + +/* Return the list of type-tags (for structs, etc) of the current level. */ + +tree +gettags () +{ + return current_binding_level->tags; +} + +/* Store the list of declarations of the current level. + This is done for the parameter declarations of a function being defined, + after they are modified in the light of any missing parameters. */ + +static void +storedecls (decls) + tree decls; +{ + current_binding_level->names = decls; +} + +/* Similarly, store the list of tags of the current level. */ + +static void +storetags (tags) + tree tags; +{ + current_binding_level->tags = tags; +} + +/* Given NAME, an IDENTIFIER_NODE, + return the structure (or union or enum) definition for that name. + Searches binding levels from BINDING_LEVEL up to the global level. + If THISLEVEL_ONLY is nonzero, searches only the specified context + (but skips any tag-transparent contexts to find one that is + meaningful for tags). + FORM says which kind of type the caller wants; + it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. + If the wrong kind of type is found, and it's not a template, an error is + reported. */ + +static tree +lookup_tag (form, name, binding_level, thislevel_only) + enum tree_code form; + struct binding_level *binding_level; + tree name; + int thislevel_only; +{ + register struct binding_level *level; + + for (level = binding_level; level; level = level->level_chain) + { + register tree tail; + if (ANON_AGGRNAME_P (name)) + for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) + { + /* There's no need for error checking here, because + anon names are unique throughout the compilation. */ + if (TYPE_IDENTIFIER (TREE_VALUE (tail)) == name) + return TREE_VALUE (tail); + } + else + for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) + { + if (TREE_PURPOSE (tail) == name) + { + enum tree_code code = TREE_CODE (TREE_VALUE (tail)); + /* Should tighten this up; it'll probably permit + UNION_TYPE and a struct template, for example. */ + if (code != form + && !(form != ENUMERAL_TYPE + && (code == TEMPLATE_DECL + || code == UNINSTANTIATED_P_TYPE))) + + { + /* Definition isn't the kind we were looking for. */ + error ("`%s' defined as wrong kind of tag", + IDENTIFIER_POINTER (name)); + } + return TREE_VALUE (tail); + } + } + if (thislevel_only && ! level->tag_transparent) + return NULL_TREE; + if (current_class_type && level->level_chain == global_binding_level) + { + /* Try looking in this class's tags before heading into + global binding level. */ + tree context = current_class_type; + while (context) + { + switch (TREE_CODE_CLASS (TREE_CODE (context))) + { + case 't': + { + tree these_tags = CLASSTYPE_TAGS (context); + if (ANON_AGGRNAME_P (name)) + while (these_tags) + { + if (TYPE_IDENTIFIER (TREE_VALUE (these_tags)) + == name) + return TREE_VALUE (tail); + these_tags = TREE_CHAIN (these_tags); + } + else + while (these_tags) + { + if (TREE_PURPOSE (these_tags) == name) + { + if (TREE_CODE (TREE_VALUE (these_tags)) != form) + { + error ("`%s' defined as wrong kind of tag in class scope", + IDENTIFIER_POINTER (name)); + } + return TREE_VALUE (tail); + } + these_tags = TREE_CHAIN (these_tags); + } + /* If this type is not yet complete, then don't + look at its context. */ + if (TYPE_SIZE (context) == NULL_TREE) + goto no_context; + /* Go to next enclosing type, if any. */ + context = DECL_CONTEXT (TYPE_NAME (context)); + break; + case 'd': + context = DECL_CONTEXT (context); + break; + default: + my_friendly_abort (10); + } + continue; + } + no_context: + break; + } + } + } + return NULL_TREE; +} + +void +set_current_level_tags_transparency (tags_transparent) + int tags_transparent; +{ + current_binding_level->tag_transparent = tags_transparent; +} + +/* Given a type, find the tag that was defined for it and return the tag name. + Otherwise return 0. However, the value can never be 0 + in the cases in which this is used. + + C++: If NAME is non-zero, this is the new name to install. This is + done when replacing anonymous tags with real tag names. */ + +static tree +lookup_tag_reverse (type, name) + tree type; + tree name; +{ + register struct binding_level *level; + + for (level = current_binding_level; level; level = level->level_chain) + { + register tree tail; + for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) + { + if (TREE_VALUE (tail) == type) + { + if (name) + TREE_PURPOSE (tail) = name; + return TREE_PURPOSE (tail); + } + } + } + return NULL_TREE; +} + +/* Given type TYPE which was not declared in C++ language context, + attempt to find a name by which it is referred. */ +tree +typedecl_for_tag (tag) + tree tag; +{ + struct binding_level *b = current_binding_level; + + if (TREE_CODE (TYPE_NAME (tag)) == TYPE_DECL) + return TYPE_NAME (tag); + + while (b) + { + tree decls = b->names; + while (decls) + { + if (TREE_CODE (decls) == TYPE_DECL && TREE_TYPE (decls) == tag) + break; + decls = TREE_CHAIN (decls); + } + if (decls) + return decls; + b = b->level_chain; + } + return NULL_TREE; +} + +/* Called when we must retroactively globalize a type we previously + thought needed to be nested. This happens, for example, when + a `friend class' declaration is seen for an undefined type. */ + +static void +globalize_nested_type (type) + tree type; +{ + tree t, prev = NULL_TREE, d = TYPE_NAME (type); + struct binding_level *b; + + my_friendly_assert (TREE_CODE (d) == TYPE_DECL, 144); + /* If the type value has already been globalized, then we're set. */ + if (IDENTIFIER_GLOBAL_VALUE (DECL_NAME (d)) == d) + return; + if (IDENTIFIER_HAS_TYPE_VALUE (DECL_NAME (d))) + { + /* If this type already made it into the global tags, + silently return. */ + if (value_member (type, global_binding_level->tags)) + return; + } + + set_identifier_type_value (DECL_NESTED_TYPENAME (d), NULL_TREE); + DECL_NESTED_TYPENAME (d) = DECL_NAME (d); + DECL_CONTEXT (d) = NULL_TREE; + if (class_binding_level) + b = class_binding_level; + else + b = current_binding_level; + while (b != global_binding_level) + { + prev = NULL_TREE; + if (b->parm_flag == 2) + for (t = b->tags; t != NULL_TREE; prev = t, t = TREE_CHAIN (t)) + if (TREE_VALUE (t) == type) + goto found; + b = b->level_chain; + } + /* We failed to find this tag anywhere up the binding chains. + B is now the global binding level... check there. */ + prev = NULL_TREE; + if (b->parm_flag == 2) + for (t = b->tags; t != NULL_TREE; prev = t, t = TREE_CHAIN (t)) + if (TREE_VALUE (t) == type) + goto foundglobal; + /* It wasn't in global scope either, so this is an anonymous forward ref + of some kind; let it happen. */ + return; + +foundglobal: + print_node_brief (stderr, "Tried to globalize already-global type ", + type, 0); + my_friendly_abort (11); + +found: + /* Pull the tag out of the nested binding contour. */ + if (prev) + TREE_CHAIN (prev) = TREE_CHAIN (t); + else + b->tags = TREE_CHAIN (t); + + set_identifier_type_value (TREE_PURPOSE (t), TREE_VALUE (t)); + global_binding_level->tags + = perm_tree_cons (TREE_PURPOSE (t), TREE_VALUE (t), + global_binding_level->tags); + + /* Pull the tag out of the class's tags (if there). + It won't show up if it appears e.g. in a parameter declaration + or definition of a member function of this type. */ + if (current_class_type != NULL_TREE) + { + for (t = CLASSTYPE_TAGS (current_class_type), prev = NULL_TREE; + t != NULL_TREE; + prev = t, t = TREE_CHAIN (t)) + if (TREE_VALUE (t) == type) + break; + + if (t != NULL_TREE) + { + if (prev) + TREE_CHAIN (prev) = TREE_CHAIN (t); + else + CLASSTYPE_TAGS (current_class_type) = TREE_CHAIN (t); + } + } + + pushdecl_top_level (d); +} + +static void +maybe_globalize_type (type) + tree type; +{ + if ((((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + && ! TYPE_BEING_DEFINED (type)) + || TREE_CODE (type) == ENUMERAL_TYPE) + && TYPE_SIZE (type) == NULL_TREE + /* This part is gross. We keep calling here with types that + are instantiations of templates, when that type should is + global, or doesn't have the type decl established yet, + so globalizing will fail (because it won't find the type in any + non-global scope). So we short-circuit that path. */ + && !(TYPE_NAME (type) != NULL_TREE + && TYPE_IDENTIFIER (type) != NULL_TREE + && ! IDENTIFIER_HAS_TYPE_VALUE (TYPE_IDENTIFIER (type))) + ) + globalize_nested_type (type); +} + +/* Lookup TYPE in CONTEXT (a chain of nested types or a FUNCTION_DECL). + Return the type value, or NULL_TREE if not found. */ +static tree +lookup_nested_type (type, context) + tree type; + tree context; +{ + if (context == NULL_TREE) + return NULL_TREE; + while (context) + { + switch (TREE_CODE (context)) + { + case TYPE_DECL: + { + tree ctype = TREE_TYPE (context); + tree match = value_member (type, CLASSTYPE_TAGS (ctype)); + if (match) + return TREE_VALUE (match); + context = DECL_CONTEXT (context); + + /* When we have a nested class whose member functions have + local types (e.g., a set of enums), we'll arrive here + with the DECL_CONTEXT as the actual RECORD_TYPE node for + the enclosing class. Instead, we want to make sure we + come back in here with the TYPE_DECL, not the RECORD_TYPE. */ + if (context && TREE_CODE (context) == RECORD_TYPE) + context = TREE_CHAIN (context); + } + break; + case FUNCTION_DECL: + return TYPE_IDENTIFIER (type) ? lookup_name (TYPE_IDENTIFIER (type), 1) : NULL_TREE; + break; + default: + my_friendly_abort (12); + } + } + return NULL_TREE; +} + +/* Look up NAME in the current binding level and its superiors in the + namespace of variables, functions and typedefs. Return a ..._DECL + node of some kind representing its definition if there is only one + such declaration, or return a TREE_LIST with all the overloaded + definitions if there are many, or return 0 if it is undefined. + + If PREFER_TYPE is > 0, we prefer TYPE_DECLs. + If PREFER_TYPE is = 0, we prefer non-TYPE_DECLs. + If PREFER_TYPE is < 0, we arbitrate according to lexical context. */ + +tree +lookup_name (name, prefer_type) + tree name; + int prefer_type; +{ + register tree val; + + if (current_binding_level != global_binding_level + && IDENTIFIER_LOCAL_VALUE (name)) + val = IDENTIFIER_LOCAL_VALUE (name); + /* In C++ class fields are between local and global scope, + just before the global scope. */ + else if (current_class_type) + { + val = IDENTIFIER_CLASS_VALUE (name); + if (val == NULL_TREE + && TYPE_SIZE (current_class_type) == NULL_TREE + && CLASSTYPE_LOCAL_TYPEDECLS (current_class_type)) + { + /* Try to find values from base classes + if we are presently defining a type. + We are presently only interested in TYPE_DECLs. */ + val = lookup_field (current_class_type, name, 0, prefer_type < 0); + if (val == error_mark_node) + return val; + if (val && TREE_CODE (val) != TYPE_DECL) + val = NULL_TREE; + } + + /* yylex() calls this with -2, since we should never start digging for + the nested name at the point where we haven't even, for example, + created the COMPONENT_REF or anything like that. */ + if (val == NULL_TREE) + val = lookup_nested_field (name, prefer_type != -2); + + if (val == NULL_TREE) + val = IDENTIFIER_GLOBAL_VALUE (name); + } + else + val = IDENTIFIER_GLOBAL_VALUE (name); + + if (val) + { + extern int looking_for_typename; + + /* Arbitrate between finding a TYPE_DECL and finding + other kinds of _DECLs. */ + if (TREE_CODE (val) == TYPE_DECL || looking_for_typename < 0) + return val; + + if (IDENTIFIER_HAS_TYPE_VALUE (name)) + { + register tree val_as_type = TYPE_NAME (IDENTIFIER_TYPE_VALUE (name)); + + if (val == val_as_type || prefer_type > 0 + || looking_for_typename > 0) + return val_as_type; + if (prefer_type == 0) + return val; + return arbitrate_lookup (name, val, val_as_type); + } + if (TREE_TYPE (val) == error_mark_node) + return error_mark_node; + } + + return val; +} + +/* Similar to `lookup_name' but look only at current binding level. */ + +tree +lookup_name_current_level (name) + tree name; +{ + register tree t; + + if (current_binding_level == global_binding_level) + return IDENTIFIER_GLOBAL_VALUE (name); + + if (IDENTIFIER_LOCAL_VALUE (name) == NULL_TREE) + return 0; + + for (t = current_binding_level->names; t; t = TREE_CHAIN (t)) + if (DECL_NAME (t) == name) + break; + + return t; +} + +/* Arrange for the user to get a source line number, even when the + compiler is going down in flames, so that she at least has a + chance of working around problems in the compiler. We used to + call error(), but that let the segmentation fault continue + through; now, it's much more passive by asking them to send the + maintainers mail about the problem. */ + +static void +sigsegv (sig) + int sig; +{ + signal (SIGSEGV, SIG_DFL); +#ifdef SIGIOT + signal (SIGIOT, SIG_DFL); +#endif +#ifdef SIGILL + signal (SIGILL, SIG_DFL); +#endif +#ifdef SIGABRT + signal (SIGABRT, SIG_DFL); +#endif + my_friendly_abort (0); +} + +/* Array for holding types considered "built-in". These types + are output in the module in which `main' is defined. */ +static tree *builtin_type_tdescs_arr; +static int builtin_type_tdescs_len, builtin_type_tdescs_max; + +/* Push the declarations of builtin types into the namespace. + RID_INDEX, if < RID_MAX is the index of the builtin type + in the array RID_POINTERS. NAME is the name used when looking + up the builtin type. TYPE is the _TYPE node for the builtin type. */ + +static void +record_builtin_type (rid_index, name, type) + enum rid rid_index; + char *name; + tree type; +{ + tree rname = NULL_TREE, tname = NULL_TREE; + tree tdecl; + + if ((int) rid_index < (int) RID_MAX) + rname = ridpointers[(int) rid_index]; + if (name) + tname = get_identifier (name); + + if (tname) + { +#if 0 /* not yet, should get fixed properly later */ + tdecl = pushdecl (make_type_decl (tname, type)); +#else + tdecl = pushdecl (build_decl (TYPE_DECL, tname, type)); +#endif + set_identifier_type_value (tname, NULL_TREE); + if ((int) rid_index < (int) RID_MAX) + IDENTIFIER_GLOBAL_VALUE (tname) = tdecl; + } + if (rname != NULL_TREE) + { + if (tname != NULL_TREE) + { + set_identifier_type_value (rname, NULL_TREE); + IDENTIFIER_GLOBAL_VALUE (rname) = tdecl; + } + else + { +#if 0 /* not yet, should get fixed properly later */ + tdecl = pushdecl (make_type_decl (rname, type)); +#else + tdecl = pushdecl (build_decl (TYPE_DECL, rname, type)); +#endif + set_identifier_type_value (rname, NULL_TREE); + } + } + + if (flag_dossier) + { + if (builtin_type_tdescs_len+5 >= builtin_type_tdescs_max) + { + builtin_type_tdescs_max *= 2; + builtin_type_tdescs_arr + = (tree *)xrealloc (builtin_type_tdescs_arr, + builtin_type_tdescs_max * sizeof (tree)); + } + builtin_type_tdescs_arr[builtin_type_tdescs_len++] = type; + if (TREE_CODE (type) != POINTER_TYPE) + { + builtin_type_tdescs_arr[builtin_type_tdescs_len++] + = build_pointer_type (type); + builtin_type_tdescs_arr[builtin_type_tdescs_len++] + = build_type_variant (TYPE_POINTER_TO (type), 1, 0); + } + if (TREE_CODE (type) != VOID_TYPE) + { + builtin_type_tdescs_arr[builtin_type_tdescs_len++] + = build_reference_type (type); + builtin_type_tdescs_arr[builtin_type_tdescs_len++] + = build_type_variant (TYPE_REFERENCE_TO (type), 1, 0); + } + } +} + +static void +output_builtin_tdesc_entries () +{ + extern struct obstack permanent_obstack; + + /* If there's more than one main in this file, don't crash. */ + if (builtin_type_tdescs_arr == 0) + return; + + push_obstacks (&permanent_obstack, &permanent_obstack); + while (builtin_type_tdescs_len > 0) + { + tree type = builtin_type_tdescs_arr[--builtin_type_tdescs_len]; + tree tdesc = build_t_desc (type, 0); + TREE_ASM_WRITTEN (tdesc) = 0; + build_t_desc (type, 2); + } + free (builtin_type_tdescs_arr); + builtin_type_tdescs_arr = 0; + pop_obstacks (); +} + +/* Push overloaded decl, in global scope, with one argument so it + can be used as a callback from define_function. */ +static void +push_overloaded_decl_1 (x) + tree x; +{ + push_overloaded_decl (x, 0); +} + +/* Create the predefined scalar types of C, + and some nodes representing standard constants (0, 1, (void *)0). + Initialize the global binding level. + Make definitions for built-in primitive functions. */ + +void +init_decl_processing () +{ + tree decl; + register tree endlink, int_endlink, double_endlink, ptr_endlink; + tree fields[20]; + /* Either char* or void*. */ + tree traditional_ptr_type_node; + /* Data type of memcpy. */ + tree memcpy_ftype; + int wchar_type_size; + + /* Have to make these distinct before we try using them. */ + lang_name_cplusplus = get_identifier ("C++"); + lang_name_c = get_identifier ("C"); + + /* Initially, C. */ + current_lang_name = lang_name_c; + + current_function_decl = NULL_TREE; + named_labels = NULL_TREE; + named_label_uses = NULL_TREE; + current_binding_level = NULL_BINDING_LEVEL; + free_binding_level = NULL_BINDING_LEVEL; + + /* Because most segmentation signals can be traced back into user + code, catch them and at least give the user a chance of working + around compiler bugs. */ + signal (SIGSEGV, sigsegv); + + /* We will also catch aborts in the back-end through sigsegv and give the + user a chance to see where the error might be, and to defeat aborts in + the back-end when there have been errors previously in their code. */ +#ifdef SIGIOT + signal (SIGIOT, sigsegv); +#endif +#ifdef SIGILL + signal (SIGILL, sigsegv); +#endif +#ifdef SIGABRT + signal (SIGABRT, sigsegv); +#endif + + gcc_obstack_init (&decl_obstack); + if (flag_dossier) + { + builtin_type_tdescs_max = 100; + builtin_type_tdescs_arr = (tree *)xmalloc (100 * sizeof (tree)); + } + + /* Must lay these out before anything else gets laid out. */ + error_mark_node = make_node (ERROR_MARK); + TREE_PERMANENT (error_mark_node) = 1; + TREE_TYPE (error_mark_node) = error_mark_node; + error_mark_list = build_tree_list (error_mark_node, error_mark_node); + TREE_TYPE (error_mark_list) = error_mark_node; + + pushlevel (0); /* make the binding_level structure for global names. */ + global_binding_level = current_binding_level; + + this_identifier = get_identifier (THIS_NAME); + in_charge_identifier = get_identifier (IN_CHARGE_NAME); + + /* Define `int' and `char' first so that dbx will output them first. */ + + integer_type_node = make_signed_type (INT_TYPE_SIZE); + record_builtin_type (RID_INT, NULL_PTR, integer_type_node); + + /* Define `char', which is like either `signed char' or `unsigned char' + but not the same as either. */ + + char_type_node = + (flag_signed_char + ? make_signed_type (CHAR_TYPE_SIZE) + : make_unsigned_type (CHAR_TYPE_SIZE)); + record_builtin_type (RID_CHAR, "char", char_type_node); + + long_integer_type_node = make_signed_type (LONG_TYPE_SIZE); + record_builtin_type (RID_LONG, "long int", long_integer_type_node); + + unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE); + record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node); + + long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE); + record_builtin_type (RID_MAX, "long unsigned int", long_unsigned_type_node); + record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node); + + /* `unsigned long' is the standard type for sizeof. + Traditionally, use a signed type. + Note that stddef.h uses `unsigned long', + and this must agree, even of long and int are the same size. */ + if (flag_traditional) + sizetype = long_integer_type_node; + else + sizetype + = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))); + + ptrdiff_type_node + = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE))); + + TREE_TYPE (TYPE_SIZE (integer_type_node)) = sizetype; + TREE_TYPE (TYPE_SIZE (char_type_node)) = sizetype; + TREE_TYPE (TYPE_SIZE (unsigned_type_node)) = sizetype; + TREE_TYPE (TYPE_SIZE (long_unsigned_type_node)) = sizetype; + TREE_TYPE (TYPE_SIZE (long_integer_type_node)) = sizetype; + + short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE); + record_builtin_type (RID_SHORT, "short int", short_integer_type_node); + long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE); + record_builtin_type (RID_MAX, "long long int", long_long_integer_type_node); + short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE); + record_builtin_type (RID_MAX, "short unsigned int", short_unsigned_type_node); + record_builtin_type (RID_MAX, "unsigned short", short_unsigned_type_node); + long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE); + record_builtin_type (RID_MAX, "long long unsigned int", long_long_unsigned_type_node); + record_builtin_type (RID_MAX, "long long unsigned", long_long_unsigned_type_node); + + /* Define both `signed char' and `unsigned char'. */ + signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE); + record_builtin_type (RID_MAX, "signed char", signed_char_type_node); + unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE); + record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node); + + /* These are types that type_for_size and type_for_mode use. */ + intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node)); + intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node)); + intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node)); + intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node)); + unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node)); + unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node)); + unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node)); + unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node)); + + float_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE; + record_builtin_type (RID_FLOAT, NULL, float_type_node); + layout_type (float_type_node); + + double_type_node = make_node (REAL_TYPE); + if (flag_short_double) + TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE; + else + TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE; + record_builtin_type (RID_DOUBLE, NULL, double_type_node); + layout_type (double_type_node); + + long_double_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE; + record_builtin_type (RID_MAX, "long double", long_double_type_node); + layout_type (long_double_type_node); + + integer_zero_node = build_int_2 (0, 0); + TREE_TYPE (integer_zero_node) = integer_type_node; + integer_one_node = build_int_2 (1, 0); + TREE_TYPE (integer_one_node) = integer_type_node; + integer_two_node = build_int_2 (2, 0); + TREE_TYPE (integer_two_node) = integer_type_node; + integer_three_node = build_int_2 (3, 0); + TREE_TYPE (integer_three_node) = integer_type_node; + empty_init_node = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE); + + /* These are needed by stor-layout.c. */ + size_zero_node = size_int (0); + size_one_node = size_int (1); + + void_type_node = make_node (VOID_TYPE); + record_builtin_type (RID_VOID, NULL, void_type_node); + layout_type (void_type_node); /* Uses integer_zero_node. */ + void_list_node = build_tree_list (NULL_TREE, void_type_node); + TREE_PARMLIST (void_list_node) = 1; + + null_pointer_node = build_int_2 (0, 0); + TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node); + layout_type (TREE_TYPE (null_pointer_node)); + + /* Used for expressions that do nothing, but are not errors. */ + void_zero_node = build_int_2 (0, 0); + TREE_TYPE (void_zero_node) = void_type_node; + + string_type_node = build_pointer_type (char_type_node); + const_string_type_node = build_pointer_type (build_type_variant (char_type_node, 1, 0)); + record_builtin_type (RID_MAX, NULL, string_type_node); + + /* make a type for arrays of 256 characters. + 256 is picked randomly because we have a type for integers from 0 to 255. + With luck nothing will ever really depend on the length of this + array type. */ + char_array_type_node + = build_array_type (char_type_node, unsigned_char_type_node); + /* Likewise for arrays of ints. */ + int_array_type_node + = build_array_type (integer_type_node, unsigned_char_type_node); + + /* This is just some anonymous class type. Nobody should ever + need to look inside this envelope. */ + class_star_type_node = build_pointer_type (make_lang_type (RECORD_TYPE)); + + default_function_type + = build_function_type (integer_type_node, NULL_TREE); + build_pointer_type (default_function_type); + + ptr_type_node = build_pointer_type (void_type_node); + const_ptr_type_node = build_pointer_type (build_type_variant (void_type_node, 1, 0)); + record_builtin_type (RID_MAX, NULL, ptr_type_node); + endlink = void_list_node; + int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink); + double_endlink = tree_cons (NULL_TREE, double_type_node, endlink); + ptr_endlink = tree_cons (NULL_TREE, ptr_type_node, endlink); + + double_ftype_double + = build_function_type (double_type_node, double_endlink); + + double_ftype_double_double + = build_function_type (double_type_node, + tree_cons (NULL_TREE, double_type_node, double_endlink)); + + int_ftype_int + = build_function_type (integer_type_node, int_endlink); + + long_ftype_long + = build_function_type (long_integer_type_node, + tree_cons (NULL_TREE, long_integer_type_node, endlink)); + + void_ftype_ptr_ptr_int + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + int_endlink))); + + int_ftype_cptr_cptr_sizet + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)))); + + void_ftype_ptr_int_int + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + int_endlink))); + + string_ftype_ptr_ptr /* strcpy prototype */ + = build_function_type (string_type_node, + tree_cons (NULL_TREE, string_type_node, + tree_cons (NULL_TREE, + const_string_type_node, + endlink))); + + int_ftype_string_string /* strcmp prototype */ + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, const_string_type_node, + tree_cons (NULL_TREE, + const_string_type_node, + endlink))); + + sizet_ftype_string /* strlen prototype */ + = build_function_type (sizetype, + tree_cons (NULL_TREE, const_string_type_node, + endlink)); + + traditional_ptr_type_node + = (flag_traditional ? string_type_node : ptr_type_node); + + memcpy_ftype /* memcpy prototype */ + = build_function_type (traditional_ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)))); + +#ifdef VTABLE_USES_MASK + /* This is primarily for virtual function definition. We + declare an array of `void *', which can later be + converted to the appropriate function pointer type. + To do pointers to members, we need a mask which can + distinguish an index value into a virtual function table + from an address. */ + vtbl_mask = build_int_2 (~((HOST_WIDE_INT) VINDEX_MAX - 1), -1); +#endif + + vtbl_type_node + = build_array_type (ptr_type_node, NULL_TREE); + layout_type (vtbl_type_node); + vtbl_type_node = build_type_variant (vtbl_type_node, 1, 0); + record_builtin_type (RID_MAX, NULL, vtbl_type_node); + + builtin_function ("__builtin_constant_p", int_ftype_int, + BUILT_IN_CONSTANT_P, NULL_PTR); + + builtin_function ("__builtin_alloca", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)), + BUILT_IN_ALLOCA, "alloca"); +#if 0 + builtin_function ("alloca", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)), + BUILT_IN_ALLOCA, NULL_PTR); +#endif + + builtin_function ("__builtin_abs", int_ftype_int, + BUILT_IN_ABS, NULL_PTR); + builtin_function ("__builtin_fabs", double_ftype_double, + BUILT_IN_FABS, NULL_PTR); + builtin_function ("__builtin_labs", long_ftype_long, + BUILT_IN_LABS, NULL_PTR); + builtin_function ("__builtin_ffs", int_ftype_int, + BUILT_IN_FFS, NULL_PTR); + builtin_function ("__builtin_fsqrt", double_ftype_double, + BUILT_IN_FSQRT, NULL_PTR); + builtin_function ("__builtin_sin", double_ftype_double, + BUILT_IN_SIN, "sin"); + builtin_function ("__builtin_cos", double_ftype_double, + BUILT_IN_COS, "cos"); + builtin_function ("__builtin_saveregs", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_SAVEREGS, NULL_PTR); +/* EXPAND_BUILTIN_VARARGS is obsolete. */ +#if 0 + builtin_function ("__builtin_varargs", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)), + BUILT_IN_VARARGS, NULL_PTR); +#endif + builtin_function ("__builtin_classify_type", default_function_type, + BUILT_IN_CLASSIFY_TYPE, NULL_PTR); + builtin_function ("__builtin_next_arg", + build_function_type (ptr_type_node, endlink), + BUILT_IN_NEXT_ARG, NULL_PTR); + builtin_function ("__builtin_args_info", + build_function_type (integer_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)), + BUILT_IN_ARGS_INFO, NULL_PTR); + + /* Currently under experimentation. */ + builtin_function ("__builtin_memcpy", memcpy_ftype, + BUILT_IN_MEMCPY, "memcpy"); + builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet, + BUILT_IN_MEMCMP, "memcmp"); + builtin_function ("__builtin_strcmp", int_ftype_string_string, + BUILT_IN_STRCMP, "strcmp"); + builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr, + BUILT_IN_STRCPY, "strcpy"); + builtin_function ("__builtin_strlen", sizet_ftype_string, + BUILT_IN_STRLEN, "strlen"); + + if (!flag_no_builtin) + { +#if 0 /* These do not work well with libg++. */ + builtin_function ("abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR); + builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS, NULL_PTR); + builtin_function ("labs", long_ftype_long, BUILT_IN_LABS, NULL_PTR); +#endif + builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR); + builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP, + NULL_PTR); + builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP, NULL_PTR); + builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY, NULL_PTR); + builtin_function ("strlen", sizet_ftype_string, BUILT_IN_STRLEN, NULL_PTR); + builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR); + builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR); + } + +#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_ffloor", double_ftype_double, BUILT_IN_FFLOOR, 0); + builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, 0); + builtin_function ("__builtin_fmod", double_ftype_double_double, BUILT_IN_FMOD, 0); + builtin_function ("__builtin_frem", double_ftype_double_double, BUILT_IN_FREM, 0); + builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int, BUILT_IN_MEMSET, 0); + builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP, 0); + builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN, 0); +#endif + + /* C++ extensions */ + + unknown_type_node = make_node (UNKNOWN_TYPE); +#if 0 /* not yet, should get fixed properly later */ + pushdecl (make_type_decl (get_identifier ("unknown type"), + unknown_type_node)); +#else + decl = pushdecl (build_decl (TYPE_DECL, get_identifier ("unknown type"), + unknown_type_node)); + /* Make sure the "unknown type" typedecl gets ignored for debug info. */ + DECL_IGNORED_P (decl) = 1; +#endif + TYPE_SIZE (unknown_type_node) = TYPE_SIZE (void_type_node); + TYPE_ALIGN (unknown_type_node) = 1; + TYPE_MODE (unknown_type_node) = TYPE_MODE (void_type_node); + /* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node. */ + TREE_TYPE (unknown_type_node) = unknown_type_node; + /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same result. */ + TYPE_POINTER_TO (unknown_type_node) = unknown_type_node; + TYPE_REFERENCE_TO (unknown_type_node) = unknown_type_node; + + /* This is special for C++ so functions can be overloaded. */ + wchar_type_node + = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE))); + wchar_type_size = TYPE_PRECISION (wchar_type_node); + signed_wchar_type_node = make_signed_type (wchar_type_size); + unsigned_wchar_type_node = make_unsigned_type (wchar_type_size); + wchar_type_node + = TREE_UNSIGNED (wchar_type_node) + ? unsigned_wchar_type_node + : signed_wchar_type_node; + record_builtin_type (RID_WCHAR, "__wchar_t", wchar_type_node); + + /* This is for wide string constants. */ + wchar_array_type_node + = build_array_type (wchar_type_node, unsigned_char_type_node); + + /* This is a hack that should go away when we deliver the + real gc code. */ + if (flag_gc) + { + builtin_function ("__gc_main", default_function_type, NOT_BUILT_IN, 0); + pushdecl (lookup_name (get_identifier ("__gc_main"), 0)); + } + + /* Simplify life by making a "vtable_entry_type". Give its + fields names so that the debugger can use them. */ + + vtable_entry_type = make_lang_type (RECORD_TYPE); + fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier (VTABLE_DELTA_NAME), short_integer_type_node); + fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier (VTABLE_INDEX_NAME), short_integer_type_node); + fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier (VTABLE_PFN_NAME), ptr_type_node); + finish_builtin_type (vtable_entry_type, VTBL_PTR_TYPE, fields, 2, + double_type_node); + + /* Make this part of an invisible union. */ + fields[3] = copy_node (fields[2]); + TREE_TYPE (fields[3]) = short_integer_type_node; + DECL_NAME (fields[3]) = get_identifier (VTABLE_DELTA2_NAME); + DECL_MODE (fields[3]) = TYPE_MODE (short_integer_type_node); + DECL_SIZE (fields[3]) = TYPE_SIZE (short_integer_type_node); + TREE_UNSIGNED (fields[3]) = 0; + TREE_CHAIN (fields[2]) = fields[3]; + vtable_entry_type = build_type_variant (vtable_entry_type, 1, 0); + record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type); + + if (flag_dossier) + { + /* Must build __t_desc type. Currently, type descriptors look like this: + + struct __t_desc + { + const char *name; + int size; + int bits; + struct __t_desc *points_to; + int ivars_count, meths_count; + struct __i_desc *ivars[]; + struct __m_desc *meths[]; + struct __t_desc *parents[]; + struct __t_desc *vbases[]; + int offsets[]; + }; + + ...as per Linton's paper. */ + + __t_desc_type_node = make_lang_type (RECORD_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); + __i_desc_array_type = build_array_type (TYPE_POINTER_TO (__i_desc_type_node), NULL_TREE); + __m_desc_array_type = build_array_type (TYPE_POINTER_TO (__m_desc_type_node), NULL_TREE); + + fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("name"), + string_type_node); + fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("size"), + unsigned_type_node); + fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("bits"), + unsigned_type_node); + fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("points_to"), + TYPE_POINTER_TO (__t_desc_type_node)); + fields[4] = build_lang_field_decl (FIELD_DECL, + get_identifier ("ivars_count"), + integer_type_node); + fields[5] = build_lang_field_decl (FIELD_DECL, + get_identifier ("meths_count"), + integer_type_node); + fields[6] = build_lang_field_decl (FIELD_DECL, get_identifier ("ivars"), + build_pointer_type (__i_desc_array_type)); + fields[7] = build_lang_field_decl (FIELD_DECL, get_identifier ("meths"), + build_pointer_type (__m_desc_array_type)); + fields[8] = build_lang_field_decl (FIELD_DECL, get_identifier ("parents"), + build_pointer_type (__t_desc_array_type)); + fields[9] = build_lang_field_decl (FIELD_DECL, get_identifier ("vbases"), + build_pointer_type (__t_desc_array_type)); + fields[10] = build_lang_field_decl (FIELD_DECL, get_identifier ("offsets"), + build_pointer_type (integer_type_node)); + finish_builtin_type (__t_desc_type_node, "__t_desc", fields, 10, integer_type_node); + + /* ivar descriptors look like this: + + struct __i_desc + { + const char *name; + int offset; + struct __t_desc *type; + }; + */ + + fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("name"), + string_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)); + finish_builtin_type (__i_desc_type_node, "__i_desc", fields, 2, integer_type_node); + + /* method descriptors look like this: + + struct __m_desc + { + const char *name; + int vindex; + struct __t_desc *vcontext; + struct __t_desc *return_type; + void (*address)(); + short parm_count; + short required_parms; + struct __t_desc *parm_types[]; + }; + */ + + fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("name"), + string_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)); + fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("return_type"), + TYPE_POINTER_TO (__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"), + short_integer_type_node); + 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))); + finish_builtin_type (__m_desc_type_node, "__m_desc", fields, 7, integer_type_node); + } + + /* Now, C++. */ + current_lang_name = lang_name_cplusplus; + if (flag_dossier) + { + int i = builtin_type_tdescs_len; + while (i > 0) + { + tree tdesc = build_t_desc (builtin_type_tdescs_arr[--i], 0); + TREE_ASM_WRITTEN (tdesc) = 1; + TREE_PUBLIC (TREE_OPERAND (tdesc, 0)) = 1; + } + } + + auto_function (ansi_opname[(int) NEW_EXPR], + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, sizetype, + void_list_node)), + NOT_BUILT_IN); + auto_function (ansi_opname[(int) DELETE_EXPR], + build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + void_list_node)), + NOT_BUILT_IN); + + abort_fndecl + = define_function ("abort", + build_function_type (void_type_node, void_list_node), + NOT_BUILT_IN, 0, 0); + + unhandled_exception_fndecl + = define_function ("__unhandled_exception", + build_function_type (void_type_node, NULL_TREE), + NOT_BUILT_IN, 0, 0); + + /* Perform other language dependent initializations. */ + init_class_processing (); + init_init_processing (); + init_search_processing (); + + if (flag_handle_exceptions) + { + if (flag_handle_exceptions == 2) + /* Too much trouble to inline all the trys needed for this. */ + flag_this_is_variable = 2; + init_exception_processing (); + } + if (flag_gc) + init_gc_processing (); + if (flag_no_inline) + flag_inline_functions = 0, flag_default_inline = 0; + if (flag_cadillac) + init_cadillac (); + + /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */ + declare_function_name (); + + /* Warnings about failure to return values are too valuable to forego. */ + warn_return_type = 1; +} + +/* Make a definition for a builtin function named NAME and whose data type + is TYPE. TYPE should be a function type with argument types. + FUNCTION_CODE tells later passes how to compile calls to this function. + See tree.h for its possible values. + + If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME, + the name to be called if we can't opencode the function. */ + +tree +define_function (name, type, function_code, pfn, library_name) + char *name; + tree type; + enum built_in_function function_code; + void (*pfn)(); + char *library_name; +{ + tree decl = build_lang_decl (FUNCTION_DECL, get_identifier (name), type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + + /* Since `pushdecl' relies on DECL_ASSEMBLER_NAME instead of DECL_NAME, + we cannot change DECL_ASSEMBLER_NAME until we have installed this + function in the namespace. */ + if (pfn) (*pfn) (decl); + if (library_name) + DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name); + make_function_rtl (decl); + if (function_code != NOT_BUILT_IN) + { + DECL_BUILT_IN (decl) = 1; + DECL_SET_FUNCTION_CODE (decl, function_code); + } + return decl; +} + +/* Called when a declaration is seen that contains no names to declare. + If its type is a reference to a structure, union or enum inherited + from a containing scope, shadow that tag name for the current scope + with a forward reference. + If its type defines a new named structure or union + or defines an enum, it is valid but we need not do anything here. + Otherwise, it is an error. + + C++: may have to grok the declspecs to learn about static, + complain for anonymous unions. */ + +void +shadow_tag (declspecs) + tree declspecs; +{ + int found_tag = 0; + int warned = 0; + register tree link; + register enum tree_code code, ok_code = ERROR_MARK; + register tree t = NULL_TREE; + + for (link = declspecs; link; link = TREE_CHAIN (link)) + { + register tree value = TREE_VALUE (link); + + code = TREE_CODE (value); + if (IS_AGGR_TYPE_CODE (code) || code == ENUMERAL_TYPE) + /* Used to test also that TYPE_SIZE (value) != 0. + That caused warning for `struct foo;' at top level in the file. */ + { + register tree name = TYPE_NAME (value); + + if (name == NULL_TREE) + name = lookup_tag_reverse (value, NULL_TREE); + + if (name && TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + + if (class_binding_level) + t = lookup_tag (code, name, class_binding_level, 1); + else + t = lookup_tag (code, name, current_binding_level, 1); + + if (t == NULL_TREE) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + if (IS_AGGR_TYPE_CODE (code)) + t = make_lang_type (code); + else + t = make_node (code); + pushtag (name, t); + pop_obstacks (); + ok_code = code; + break; + } + else if (name != NULL_TREE || code == ENUMERAL_TYPE) + ok_code = code; + + if (ok_code != ERROR_MARK) + found_tag++; + else + { + if (!warned) + pedwarn ("useless keyword or type name in declaration"); + warned = 1; + } + } + } + + /* This is where the variables in an anonymous union are + declared. An anonymous union declaration looks like: + union { ... } ; + because there is no declarator after the union, the parser + sends that declaration here. */ + if (ok_code == UNION_TYPE + && t != NULL_TREE + && ((TREE_CODE (TYPE_NAME (t)) == IDENTIFIER_NODE + && ANON_AGGRNAME_P (TYPE_NAME (t))) + || (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL + && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))))) + { + /* ANSI C++ June 5 1992 WP 9.5.3. Anonymous unions may not have + function members. */ + if (TYPE_FIELDS (t)) + { + tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0, NULL_TREE); + finish_anon_union (decl); + } + else + error ("anonymous union cannot have a function member"); + } + else if (ok_code == RECORD_TYPE + && found_tag == 1 + && TYPE_LANG_SPECIFIC (t) + && CLASSTYPE_DECLARED_EXCEPTION (t)) + { + if (TYPE_SIZE (t)) + error_with_aggr_type (t, "redeclaration of exception `%s'"); + else + { + tree ename, decl; + + push_obstacks (&permanent_obstack, &permanent_obstack); + + pushclass (t, 0); + finish_exception (t, NULL_TREE); + + ename = TYPE_NAME (t); + if (TREE_CODE (ename) == TYPE_DECL) + ename = DECL_NAME (ename); + decl = build_lang_field_decl (VAR_DECL, ename, t); + finish_exception_decl (current_class_name, decl); + end_exception_decls (); + + pop_obstacks (); + } + } + else if (!warned && found_tag > 1) + warning ("multiple types in one declaration"); +} + +/* Decode a "typename", such as "int **", returning a ..._TYPE node. */ + +tree +groktypename (typename) + tree typename; +{ + if (TREE_CODE (typename) != TREE_LIST) + return typename; + return grokdeclarator (TREE_VALUE (typename), + TREE_PURPOSE (typename), + TYPENAME, 0, NULL_TREE); +} + +/* Decode a declarator in an ordinary declaration or data definition. + This is called as soon as the type information and variable name + have been parsed, before parsing the initializer if any. + Here we create the ..._DECL node, fill in its type, + and put it on the list of decls for the current context. + The ..._DECL node is returned as the value. + + Exception: for arrays where the length is not specified, + the type is left null, to be filled in by `finish_decl'. + + Function definitions do not come here; they go to start_function + instead. However, external and forward declarations of functions + do go through here. Structure field declarations are done by + grokfield and not through here. */ + +/* Set this to zero to debug not using the temporary obstack + to parse initializers. */ +int debug_temp_inits = 1; + +tree +start_decl (declarator, declspecs, initialized, raises) + tree declspecs, declarator; + int initialized; + tree raises; +{ + register tree decl; + register tree type, tem; + tree context; + extern int have_extern_spec; + extern int used_extern_spec; + + int init_written = initialized; + + /* This should only be done once on the top most decl. */ + if (have_extern_spec && !used_extern_spec) + { + declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), declspecs); + used_extern_spec = 1; + } + + decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, raises); + if (decl == NULL_TREE || decl == void_type_node) + return NULL_TREE; + + type = TREE_TYPE (decl); + + /* Don't lose if destructors must be executed at file-level. */ + if (TREE_STATIC (decl) + && TYPE_NEEDS_DESTRUCTOR (type) + && !TREE_PERMANENT (decl)) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + decl = copy_node (decl); + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree itype = TYPE_DOMAIN (type); + if (itype && ! TREE_PERMANENT (itype)) + { + itype = build_index_type (copy_to_permanent (TYPE_MAX_VALUE (itype))); + type = build_cplus_array_type (TREE_TYPE (type), itype); + TREE_TYPE (decl) = type; + } + } + pop_obstacks (); + } + + /* Interesting work for this is done in `finish_exception_decl'. */ + if (TREE_CODE (type) == RECORD_TYPE + && CLASSTYPE_DECLARED_EXCEPTION (type)) + return decl; + + /* Corresponding pop_obstacks is done in `finish_decl'. */ + push_obstacks_nochange (); + + context + = (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl)) + ? DECL_CLASS_CONTEXT (decl) + : DECL_CONTEXT (decl); + + if (processing_template_decl) + { + tree d; + if (TREE_CODE (decl) == FUNCTION_DECL) + { + /* Declarator is a call_expr; extract arguments from it, since + grokdeclarator didn't do it. */ + tree args; + args = copy_to_permanent (last_function_parms); + if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) + { + tree t = TREE_TYPE (decl); + tree decl; + + t = TYPE_METHOD_BASETYPE (t); /* type method belongs to */ + if (TREE_CODE (t) != UNINSTANTIATED_P_TYPE) + { + t = build_pointer_type (t); /* base type of `this' */ +#if 1 + /* I suspect this is wrong. */ + t = build_type_variant (t, flag_this_is_variable <= 0, + 0); /* type of `this' */ +#else + t = build_type_variant (t, 0, 0); /* type of `this' */ +#endif + t = build (PARM_DECL, t, this_identifier); + TREE_CHAIN (t) = args; + args = t; + } + } + DECL_ARGUMENTS (decl) = args; + } + d = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), TREE_TYPE (decl)); + TREE_PUBLIC (d) = TREE_PUBLIC (decl) = 0; + TREE_STATIC (d) = TREE_STATIC (decl); + DECL_EXTERNAL (d) = (DECL_EXTERNAL (decl) + && !(context && !DECL_THIS_EXTERN (decl))); + DECL_TEMPLATE_RESULT (d) = decl; + DECL_OVERLOADED (d) = 1; + decl = d; + } + + if (context && TYPE_SIZE (context) != NULL_TREE) + { + /* If it was not explicitly declared `extern', + revoke any previous claims of DECL_EXTERNAL. */ + if (DECL_THIS_EXTERN (decl) == 0) + DECL_EXTERNAL (decl) = 0; + if (DECL_LANG_SPECIFIC (decl)) + DECL_IN_AGGR_P (decl) = 0; + pushclass (context, 2); + } + + /* If this type of object needs a cleanup, and control may + jump past it, make a new binding level so that it is cleaned + up only when it is initialized first. */ + if (TYPE_NEEDS_DESTRUCTOR (type) + && current_binding_level->more_cleanups_ok == 0) + pushlevel_temporary (1); + + if (initialized) + /* Is it valid for this decl to have an initializer at all? + If not, set INITIALIZED to zero, which will indirectly + tell `finish_decl' to ignore the initializer once it is parsed. */ + switch (TREE_CODE (decl)) + { + case TYPE_DECL: + /* typedef foo = bar means give foo the same type as bar. + We haven't parsed bar yet, so `finish_decl' will fix that up. + Any other case of an initialization in a TYPE_DECL is an error. */ + if (pedantic || list_length (declspecs) > 1) + { + error ("typedef `%s' is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + break; + + case FUNCTION_DECL: + error ("function `%s' is initialized like a variable", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + break; + + default: + /* Don't allow initializations for incomplete types + except for arrays which might be completed by the initialization. */ + if (TYPE_SIZE (type) != NULL_TREE) + ; /* A complete type is ok. */ + else if (TREE_CODE (type) != ARRAY_TYPE) + { + error ("variable `%s' has initializer but incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + else if (TYPE_SIZE (TREE_TYPE (type)) == NULL_TREE) + { + error ("elements of array `%s' have incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + } + + if (!initialized + && TREE_CODE (decl) != TYPE_DECL + && TREE_CODE (decl) != TEMPLATE_DECL + && IS_AGGR_TYPE (type) && ! DECL_EXTERNAL (decl)) + { + if (TYPE_SIZE (type) == NULL_TREE) + { + error ("aggregate `%s' has incomplete type and cannot be initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); + /* Change the type so that assemble_variable will give + DECL an rtl we can live with: (mem (const_int 0)). */ + TREE_TYPE (decl) = error_mark_node; + type = error_mark_node; + } + else + { + /* If any base type in the hierarchy of TYPE needs a constructor, + then we set initialized to 1. This way any nodes which are + created for the purposes of initializing this aggregate + will live as long as it does. This is necessary for global + aggregates which do not have their initializers processed until + the end of the file. */ + initialized = TYPE_NEEDS_CONSTRUCTING (type); + } + } + + if (initialized) + { + if (current_binding_level != global_binding_level + && DECL_EXTERNAL (decl)) + warning ("declaration of `%s' has `extern' and is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); + DECL_EXTERNAL (decl) = 0; + if (current_binding_level == global_binding_level) + TREE_STATIC (decl) = 1; + + /* Tell `pushdecl' this is an initialized decl + even though we don't yet have the initializer expression. + Also tell `finish_decl' it may store the real initializer. */ + DECL_INITIAL (decl) = error_mark_node; + } + + /* Add this decl to the current binding level, but not if it + comes from another scope, e.g. a static member variable. + TEM may equal DECL or it may be a previous decl of the same name. */ + if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE) + || (TREE_CODE (decl) == TEMPLATE_DECL && !global_bindings_p ()) + || TREE_CODE (type) == LANG_TYPE) + tem = decl; + else + { + tem = pushdecl (decl); + if (TREE_CODE (tem) == TREE_LIST) + { + tree tem2 = value_member (decl, tem); + if (tem2 != NULL_TREE) + tem = TREE_VALUE (tem2); + else + { + while (tem && ! decls_match (decl, TREE_VALUE (tem))) + tem = TREE_CHAIN (tem); + if (tem == NULL_TREE) + tem = decl; + else + tem = TREE_VALUE (tem); + } + } + } + +#if 0 + /* We don't do this yet for GNU C++. */ + /* For a local variable, define the RTL now. */ + if (current_binding_level != global_binding_level + /* But not if this is a duplicate decl + and we preserved the rtl from the previous one + (which may or may not happen). */ + && DECL_RTL (tem) == NULL_RTX) + { + if (TYPE_SIZE (TREE_TYPE (tem)) != NULL_TREE) + expand_decl (tem); + else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE + && DECL_INITIAL (tem) != NULL_TREE) + expand_decl (tem); + } +#endif + + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_OVERLOADED (decl)) + /* @@ Also done in start_function. */ + tem = push_overloaded_decl (tem, 1); + else if (TREE_CODE (decl) == TEMPLATE_DECL) + { + tree result = DECL_TEMPLATE_RESULT (decl); + if (DECL_CONTEXT (result) != NULL_TREE) + { + tree type; + type = DECL_CONTEXT (result); + my_friendly_assert (TREE_CODE (type) == UNINSTANTIATED_P_TYPE, 145); + if (/* TREE_CODE (result) == VAR_DECL */ 1) + { +#if 0 + tree tmpl = UPT_TEMPLATE (type); + + fprintf (stderr, "%s:%d: adding ", __FILE__, __LINE__); + print_node_brief (stderr, "", DECL_NAME (tem), 0); + fprintf (stderr, " to class %s\n", + IDENTIFIER_POINTER (DECL_NAME (tmpl))); + DECL_TEMPLATE_MEMBERS (tmpl) + = perm_tree_cons (DECL_NAME (tem), tem, + DECL_TEMPLATE_MEMBERS (tmpl)); +#endif + return tem; + } + my_friendly_abort (13); + } + else if (TREE_CODE (result) == FUNCTION_DECL) + tem = push_overloaded_decl (tem, 0); + else if (TREE_CODE (result) == VAR_DECL + || TREE_CODE (result) == TYPE_DECL) + { + error ("invalid template `%s'", + IDENTIFIER_POINTER (DECL_NAME (result))); + return NULL_TREE; + } + else + my_friendly_abort (14); + } + + if (init_written + && ! (TREE_CODE (tem) == PARM_DECL + || (TREE_READONLY (tem) + && (TREE_CODE (tem) == VAR_DECL + || TREE_CODE (tem) == FIELD_DECL)))) + { + /* When parsing and digesting the initializer, + use temporary storage. Do this even if we will ignore the value. */ + if (current_binding_level == global_binding_level && debug_temp_inits) + { + if (TYPE_NEEDS_CONSTRUCTING (type) || TREE_CODE (type) == REFERENCE_TYPE) + /* In this case, the initializer must lay down in permanent + storage, since it will be saved until `finish_file' is run. */ + ; + else + temporary_allocation (); + } + } + + if (flag_cadillac) + cadillac_start_decl (tem); + + return tem; +} + +static void +make_temporary_for_reference (decl, ctor_call, init, cleanupp) + tree decl, ctor_call, init; + tree *cleanupp; +{ + tree type = TREE_TYPE (decl); + tree target_type = TREE_TYPE (type); + tree tmp, tmp_addr; + + if (ctor_call) + { + tmp_addr = TREE_VALUE (TREE_OPERAND (ctor_call, 1)); + if (TREE_CODE (tmp_addr) == NOP_EXPR) + tmp_addr = TREE_OPERAND (tmp_addr, 0); + my_friendly_assert (TREE_CODE (tmp_addr) == ADDR_EXPR, 146); + tmp = TREE_OPERAND (tmp_addr, 0); + } + else + { + tmp = get_temp_name (target_type, + current_binding_level == global_binding_level); + tmp_addr = build_unary_op (ADDR_EXPR, tmp, 0); + } + + TREE_TYPE (tmp_addr) = build_pointer_type (target_type); + DECL_INITIAL (decl) = convert (TYPE_POINTER_TO (target_type), tmp_addr); + TREE_TYPE (DECL_INITIAL (decl)) = type; + if (TYPE_NEEDS_CONSTRUCTING (target_type)) + { + if (current_binding_level == global_binding_level) + { + /* lay this variable out now. Otherwise `output_addressed_constants' + gets confused by its initializer. */ + make_decl_rtl (tmp, NULL_PTR, 1); + static_aggregates = perm_tree_cons (init, tmp, static_aggregates); + } + else + { + if (ctor_call != NULL_TREE) + init = ctor_call; + else + init = build_method_call (tmp, constructor_name (target_type), + build_tree_list (NULL_TREE, init), + NULL_TREE, LOOKUP_NORMAL); + DECL_INITIAL (decl) = build (COMPOUND_EXPR, type, init, + DECL_INITIAL (decl)); + *cleanupp = maybe_build_cleanup (tmp); + } + } + else + { + DECL_INITIAL (tmp) = init; + TREE_STATIC (tmp) = current_binding_level == global_binding_level; + finish_decl (tmp, init, 0, 0); + } + if (TREE_STATIC (tmp)) + preserve_initializer (); +} + +/* Handle initialization of references. + These three arguments from from `finish_decl', and have the + same meaning here that they do there. */ +/* quotes on semantics can be found in ARM 8.4.3. */ +static void +grok_reference_init (decl, type, init, cleanupp) + tree decl, type, init; + tree *cleanupp; +{ + char *errstr = NULL; + int is_reference; + tree tmp; + tree this_ptr_type, actual_init; + + if (init == NULL_TREE) + { + if (DECL_LANG_SPECIFIC (decl) == 0 + || DECL_IN_AGGR_P (decl) == 0) + { + error ("variable declared as reference not initialized"); + if (TREE_CODE (decl) == VAR_DECL) + SET_DECL_REFERENCE_SLOT (decl, error_mark_node); + } + return; + } + + if (TREE_CODE (init) == TREE_LIST) + init = build_compound_expr (init); + is_reference = TREE_CODE (TREE_TYPE (init)) == REFERENCE_TYPE; + tmp = is_reference ? convert_from_reference (init) : init; + + if (is_reference) + { + if (! comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (type)), + TYPE_MAIN_VARIANT (TREE_TYPE (tmp)), 0)) + errstr = "initialization of `%s' from dissimilar reference type"; + else if (TYPE_READONLY (TREE_TYPE (type)) + >= TYPE_READONLY (TREE_TYPE (TREE_TYPE (init)))) + { + is_reference = 0; + init = tmp; + } + } + else + { + if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE + && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE) + { + /* Note: default conversion is only called in very + special cases. */ + init = default_conversion (init); + } + if (TREE_CODE (TREE_TYPE (type)) == TREE_CODE (TREE_TYPE (init))) + { + if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (type)), + TYPE_MAIN_VARIANT (TREE_TYPE (init)), 0)) + { + /* This section implements ANSI C++ June 5 1992 WP 8.4.3.5. */ + + /* A reference to a volatile T cannot be initialized with + a const T, and vice-versa. */ + if (TYPE_VOLATILE (TREE_TYPE (type)) && TREE_READONLY (init)) + errstr = "cannot initialize a reference to a volatile T with a const T"; + else if (TYPE_READONLY (TREE_TYPE (type)) && TREE_THIS_VOLATILE (init)) + errstr = "cannot initialize a reference to a const T with a volatile T"; + /* A reference to a plain T can be initialized only with + a plain T. */ + else if (!TYPE_VOLATILE (TREE_TYPE (type)) + && !TYPE_READONLY (TREE_TYPE (type))) + { + if (TREE_READONLY (init)) + errstr = "cannot initialize a reference to T with a const T"; + else if (TREE_THIS_VOLATILE (init)) + errstr = "cannot initialize a reference to T with a volatile T"; + } + } + else + init = convert (TREE_TYPE (type), init); + } + else if (init != error_mark_node + && ! comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (type)), + TYPE_MAIN_VARIANT (TREE_TYPE (init)), 0)) + errstr = "invalid type conversion for reference"; + } + + if (errstr) + { + /* Things did not go smoothly; look for operator& type conversion. */ + if (IS_AGGR_TYPE (TREE_TYPE (tmp))) + { + tmp = build_type_conversion (CONVERT_EXPR, type, init, 0); + if (tmp != NULL_TREE) + { + init = tmp; + if (tmp == error_mark_node) + errstr = "ambiguous pointer conversion"; + else + errstr = NULL; + is_reference = 1; + } + else + { + tmp = build_type_conversion (CONVERT_EXPR, TREE_TYPE (type), init, 0); + if (tmp != NULL_TREE) + { + init = tmp; + if (tmp == error_mark_node) + errstr = "ambiguous pointer conversion"; + else + errstr = NULL; + is_reference = 0; + } + } + } + /* Look for constructor. */ + else if (IS_AGGR_TYPE (TREE_TYPE (type)) + && TYPE_HAS_CONSTRUCTOR (TREE_TYPE (type))) + { + tmp = get_temp_name (TREE_TYPE (type), + current_binding_level == global_binding_level); + tmp = build_method_call (tmp, constructor_name (TREE_TYPE (type)), + build_tree_list (NULL_TREE, init), + NULL_TREE, LOOKUP_NORMAL); + if (tmp == NULL_TREE || tmp == error_mark_node) + { + if (TREE_CODE (decl) == VAR_DECL) + SET_DECL_REFERENCE_SLOT (decl, error_mark_node); + error_with_decl (decl, "constructor failed to build reference initializer"); + return; + } + make_temporary_for_reference (decl, tmp, init, cleanupp); + goto done; + } + } + + if (errstr) + { + error_with_decl (decl, errstr); + if (TREE_CODE (decl) == VAR_DECL) + SET_DECL_REFERENCE_SLOT (decl, error_mark_node); + return; + } + + /* In the case of initialization, it is permissible + to assign one reference to another. */ + this_ptr_type = build_pointer_type (TREE_TYPE (type)); + + if (is_reference) + { + if (TREE_SIDE_EFFECTS (init)) + DECL_INITIAL (decl) = save_expr (init); + else + DECL_INITIAL (decl) = init; + } + else if (lvalue_p (init)) + { + tmp = build_unary_op (ADDR_EXPR, init, 0); + if (TREE_CODE (tmp) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (tmp, 0)) == WITH_CLEANUP_EXPR) + { + /* Associate the cleanup with the reference so that we + don't get burned by "aggressive" cleanup policy. */ + *cleanupp = TREE_OPERAND (TREE_OPERAND (tmp, 0), 2); + TREE_OPERAND (TREE_OPERAND (tmp, 0), 2) = error_mark_node; + } + if (IS_AGGR_TYPE (TREE_TYPE (this_ptr_type))) + DECL_INITIAL (decl) = convert_pointer_to (TREE_TYPE (this_ptr_type), tmp); + else + DECL_INITIAL (decl) = convert (this_ptr_type, tmp); + + DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl)); + if (DECL_INITIAL (decl) == current_class_decl) + DECL_INITIAL (decl) = copy_node (current_class_decl); + TREE_TYPE (DECL_INITIAL (decl)) = type; + } + else if ((actual_init = unary_complex_lvalue (ADDR_EXPR, init))) + { + /* The initializer for this decl goes into its + DECL_REFERENCE_SLOT. Make sure that we can handle + multiple evaluations without ill effect. */ + if (TREE_CODE (actual_init) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (actual_init, 0)) == TARGET_EXPR) + actual_init = save_expr (actual_init); + DECL_INITIAL (decl) = convert_pointer_to (TREE_TYPE (this_ptr_type), actual_init); + DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl)); + TREE_TYPE (DECL_INITIAL (decl)) = type; + } + else if (TYPE_READONLY (TREE_TYPE (type))) + /* Section 8.4.3 allows us to make a temporary for + the initialization of const&. */ + make_temporary_for_reference (decl, NULL_TREE, init, cleanupp); + else + { + error_with_decl (decl, "type mismatch in initialization of `%s' (use `const')"); + DECL_INITIAL (decl) = error_mark_node; + } + + done: + /* ?? Can this be optimized in some cases to + hand back the DECL_INITIAL slot?? */ + if (TYPE_SIZE (TREE_TYPE (type))) + { + init = convert_from_reference (decl); + if (TREE_PERMANENT (decl)) + init = copy_to_permanent (init); + SET_DECL_REFERENCE_SLOT (decl, init); + } + + if (TREE_STATIC (decl) && ! TREE_CONSTANT (DECL_INITIAL (decl))) + { + expand_static_init (decl, DECL_INITIAL (decl)); + DECL_INITIAL (decl) = NULL_TREE; + } +} + +/* Finish processing of a declaration; + install its line number and initial value. + 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++, `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. + + INIT0 holds the value of an initializer that should be allowed to escape + the normal rules. + + For functions that take default parameters, DECL points to its + "maximal" instantiation. `finish_decl' must then also declared its + subsequently lower and lower forms of instantiation, checking for + ambiguity as it goes. This can be sped up later. */ + +void +finish_decl (decl, init, asmspec_tree, need_pop) + tree decl, init; + tree asmspec_tree; + int need_pop; +{ + register tree type; + tree cleanup = NULL_TREE, ttype; + int was_incomplete; + int temporary = allocation_temporary_p (); + char *asmspec = NULL; + int was_readonly = 0; + + /* If this is 0, then we did not change obstacks. */ + if (! decl) + { + if (init) + error ("assignment (not initialization) in declaration"); + return; + } + + if (asmspec_tree) + { + asmspec = TREE_STRING_POINTER (asmspec_tree); + /* Zero out old RTL, since we will rewrite it. */ + DECL_RTL (decl) = NULL_RTX; + } + + /* If the type of the thing we are declaring either has + a constructor, or has a virtual function table pointer, + AND its initialization was accepted by `start_decl', + then we stayed on the permanent obstack through the + declaration, otherwise, changed obstacks as GCC would. */ + + type = TREE_TYPE (decl); + + was_incomplete = (DECL_SIZE (decl) == NULL_TREE); + + /* Take care of TYPE_DECLs up front. */ + if (TREE_CODE (decl) == TYPE_DECL) + { + if (init && DECL_INITIAL (decl)) + { + /* typedef foo = bar; store the type of bar as the type of foo. */ + TREE_TYPE (decl) = type = TREE_TYPE (init); + DECL_INITIAL (decl) = init = NULL_TREE; + } + if (IS_AGGR_TYPE (type) && DECL_NAME (decl)) + { + if (TREE_TYPE (DECL_NAME (decl)) && TREE_TYPE (decl) != type) + warning ("shadowing previous type declaration of `%s'", + IDENTIFIER_POINTER (DECL_NAME (decl))); + set_identifier_type_value (DECL_NAME (decl), type); + CLASSTYPE_GOT_SEMICOLON (type) = 1; + } + GNU_xref_decl (current_function_decl, decl); + rest_of_decl_compilation (decl, NULL_PTR, + DECL_CONTEXT (decl) == NULL_TREE, 0); + goto finish_end; + } + if (type != error_mark_node && IS_AGGR_TYPE (type) + && CLASSTYPE_DECLARED_EXCEPTION (type)) + { + finish_exception_decl (NULL_TREE, decl); + CLASSTYPE_GOT_SEMICOLON (type) = 1; + goto finish_end; + } + if (TREE_CODE (decl) != FUNCTION_DECL) + { + ttype = target_type (type); +#if 0 /* WTF? -KR + Leave this out until we can figure out why it was + needed/desirable in the first place. Then put a comment + here explaining why. Or just delete the code if no ill + effects arise. */ + if (TYPE_NAME (ttype) + && TREE_CODE (TYPE_NAME (ttype)) == TYPE_DECL + && ANON_AGGRNAME_P (TYPE_IDENTIFIER (ttype))) + { + tree old_id = TYPE_IDENTIFIER (ttype); + char *newname = (char *)alloca (IDENTIFIER_LENGTH (old_id) + 2); + /* Need to preserve template data for UPT nodes. */ + tree old_template = IDENTIFIER_TEMPLATE (old_id); + newname[0] = '_'; + bcopy (IDENTIFIER_POINTER (old_id), newname + 1, + IDENTIFIER_LENGTH (old_id) + 1); + old_id = get_identifier (newname); + lookup_tag_reverse (ttype, old_id); + TYPE_IDENTIFIER (ttype) = old_id; + IDENTIFIER_TEMPLATE (old_id) = old_template; + } +#endif + } + + if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl) + && TYPE_NEEDS_CONSTRUCTING (type)) + { + + /* Currently, GNU C++ puts constants in text space, making them + impossible to initialize. In the future, one would hope for + an operating system which understood the difference between + initialization and the running of a program. */ + was_readonly = 1; + TREE_READONLY (decl) = 0; + } + + if (TREE_CODE (decl) == FIELD_DECL) + { + if (init && init != error_mark_node) + my_friendly_assert (TREE_PERMANENT (init), 147); + + if (asmspec) + { + /* This must override the asm specifier which was placed + by grokclassfn. Lay this out fresh. + + @@ Should emit an error if this redefines an asm-specified + @@ name, or if we have already used the function's name. */ + DECL_RTL (TREE_TYPE (decl)) = NULL_RTX; + DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec); + make_decl_rtl (decl, asmspec, 0); + } + } + /* If `start_decl' didn't like having an initialization, ignore it now. */ + else if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE) + init = NULL_TREE; + else if (DECL_EXTERNAL (decl)) + ; + else if (TREE_CODE (type) == REFERENCE_TYPE) + { + grok_reference_init (decl, type, init, &cleanup); + init = NULL_TREE; + } + + GNU_xref_decl (current_function_decl, decl); + + if (TREE_CODE (decl) == FIELD_DECL || DECL_EXTERNAL (decl)) + ; + else if (TREE_CODE (decl) == CONST_DECL) + { + my_friendly_assert (TREE_CODE (decl) != REFERENCE_TYPE, 148); + + DECL_INITIAL (decl) = init; + + /* This will keep us from needing to worry about our obstacks. */ + my_friendly_assert (init != NULL_TREE, 149); + init = NULL_TREE; + } + else if (init) + { + if (TYPE_NEEDS_CONSTRUCTING (type)) + { + if (TREE_CODE (type) == ARRAY_TYPE) + init = digest_init (type, init, (tree *) 0); + else if (TREE_CODE (init) == CONSTRUCTOR + && CONSTRUCTOR_ELTS (init) != NULL_TREE) + { + error_with_decl (decl, "`%s' must be initialized by constructor, not by `{...}'"); + init = error_mark_node; + } +#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 + + /* We must hide the initializer so that expand_decl + won't try to do something it does not understand. */ + if (current_binding_level == global_binding_level) + { + tree value = digest_init (type, empty_init_node, (tree *) 0); + DECL_INITIAL (decl) = value; + } + else + DECL_INITIAL (decl) = error_mark_node; + } + else + { + if (TREE_CODE (init) != TREE_VEC) + init = store_init_value (decl, init); + + if (init) + /* Don't let anyone try to initialize this variable + until we are ready to do so. */ + DECL_INITIAL (decl) = error_mark_node; + } + } + else if (TREE_CODE_CLASS (TREE_CODE (type)) == 't' + && (IS_AGGR_TYPE (type) || TYPE_NEEDS_CONSTRUCTING (type))) + { + tree ctype = type; + while (TREE_CODE (ctype) == ARRAY_TYPE) + ctype = TREE_TYPE (ctype); + if (! TYPE_NEEDS_CONSTRUCTOR (ctype)) + { + if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (ctype)) + error_with_decl (decl, "structure `%s' with uninitialized const members"); + if (CLASSTYPE_REF_FIELDS_NEED_INIT (ctype)) + error_with_decl (decl, "structure `%s' with uninitialized reference members"); + } + + if (TREE_CODE (decl) == VAR_DECL + && !TYPE_NEEDS_CONSTRUCTING (type) + && (TYPE_READONLY (type) || TREE_READONLY (decl))) + error_with_decl (decl, "uninitialized const `%s'"); + + /* Initialize variables in need of static initialization + with `empty_init_node' to keep assemble_variable from putting them + in the wrong program space. (Common storage is okay for non-public + uninitialized data; the linker can't match it with storage from other + files, and we may save some disk space.) */ + if (flag_pic == 0 + && TREE_STATIC (decl) + && TREE_PUBLIC (decl) + && ! DECL_EXTERNAL (decl) + && TREE_CODE (decl) == VAR_DECL + && TYPE_NEEDS_CONSTRUCTING (type) + && (DECL_INITIAL (decl) == NULL_TREE + || DECL_INITIAL (decl) == error_mark_node)) + { + tree value = digest_init (type, empty_init_node, (tree *) 0); + DECL_INITIAL (decl) = value; + } + } + else if (TREE_CODE (decl) == VAR_DECL + && TREE_CODE (type) != REFERENCE_TYPE + && (TYPE_READONLY (type) || TREE_READONLY (decl))) + { + /* ``Unless explicitly declared extern, a const object does not have + external linkage and must be initialized. ($8.4; $12.1)'' ARM 7.1.6 + However, if it's `const int foo = 1; const int foo;', don't complain + about the second decl, since it does have an initializer before. */ + if (! DECL_INITIAL (decl) && (!pedantic || !current_class_type)) + error_with_decl (decl, "uninitialized const `%s'"); + } + + /* 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 (current_binding_level == global_binding_level && temporary) + end_temporary_allocation (); + + /* Deduce size of array from initialization, if not already known. */ + + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) == NULL_TREE + && TREE_CODE (decl) != TYPE_DECL) + { + int do_default + = (TREE_STATIC (decl) + /* Even if pedantic, an external linkage array + may have incomplete type at first. */ + ? pedantic && DECL_EXTERNAL (decl) + : !DECL_EXTERNAL (decl)); + tree initializer = init ? init : DECL_INITIAL (decl); + int failure = complete_array_type (type, initializer, do_default); + + if (failure == 1) + error_with_decl (decl, "initializer fails to determine size of `%s'"); + + if (failure == 2) + { + if (do_default) + error_with_decl (decl, "array size missing in `%s'"); + else if (!pedantic && TREE_STATIC (decl)) + DECL_EXTERNAL (decl) = 1; + } + + if (pedantic && TYPE_DOMAIN (type) != NULL_TREE + && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + integer_zero_node)) + error_with_decl (decl, "zero-size array `%s'"); + + layout_decl (decl, 0); + } + + if (TREE_CODE (decl) == VAR_DECL) + { + if (TREE_STATIC (decl) && DECL_SIZE (decl) == NULL_TREE) + { + /* A static variable with an incomplete type: + that is an error if it is initialized or `static'. + Otherwise, let it through, but if it is not `extern' + then it may cause an error message later. */ + if (!DECL_EXTERNAL (decl) || DECL_INITIAL (decl) != NULL_TREE) + error_with_decl (decl, "storage size of `%s' isn't known"); + init = NULL_TREE; + } + else if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE) + { + /* An automatic variable with an incomplete type: that is an error. + Don't talk about array types here, since we took care of that + message in grokdeclarator. */ + error_with_decl (decl, "storage size of `%s' isn't known"); + TREE_TYPE (decl) = error_mark_node; + } + 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 ((DECL_EXTERNAL (decl) || TREE_STATIC (decl)) + && DECL_SIZE (decl) != NULL_TREE + && ! TREE_CONSTANT (DECL_SIZE (decl))) + error_with_decl (decl, "storage size of `%s' isn't constant"); + + if (!DECL_EXTERNAL (decl) && TYPE_NEEDS_DESTRUCTOR (type)) + { + int yes = suspend_momentary (); + + /* If INIT comes from a functional cast, use the cleanup + we built for that. Otherwise, make our own cleanup. */ + if (init && TREE_CODE (init) == WITH_CLEANUP_EXPR + && comptypes (TREE_TYPE (decl), TREE_TYPE (init), 1)) + { + cleanup = TREE_OPERAND (init, 2); + init = TREE_OPERAND (init, 0); + current_binding_level->have_cleanups = 1; + current_binding_level->more_exceptions_ok = 0; + } + else + cleanup = maybe_build_cleanup (decl); + resume_momentary (yes); + } + } + /* PARM_DECLs get cleanups, too. */ + else if (TREE_CODE (decl) == PARM_DECL && TYPE_NEEDS_DESTRUCTOR (type)) + { + if (temporary) + end_temporary_allocation (); + cleanup = maybe_build_cleanup (decl); + if (temporary) + resume_temporary_allocation (); + } + + /* Output the assembler code and/or RTL code for variables and functions, + unless the type is an undefined structure or union. + If not, it will get done when the type is completed. */ + + if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == RESULT_DECL) + { + int toplev = current_binding_level == global_binding_level; + int was_temp + = ((flag_traditional + || (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type))) + && allocation_temporary_p ()); + + if (was_temp) + end_temporary_allocation (); + + /* If we are in need of a cleanup, get out of any implicit + handlers that have been established so far. */ + if (cleanup && current_binding_level->parm_flag == 3) + { + pop_implicit_try_blocks (decl); + current_binding_level->more_exceptions_ok = 0; + } + + if (TREE_CODE (decl) == VAR_DECL + && current_binding_level != global_binding_level + && ! TREE_STATIC (decl) + && type_needs_gc_entry (type)) + DECL_GC_OFFSET (decl) = size_int (++current_function_obstack_index); + + if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl)) + make_decl_rtl (decl, NULL_PTR, toplev); + else if (TREE_CODE (decl) == VAR_DECL + && TREE_READONLY (decl) + && DECL_INITIAL (decl) != NULL_TREE + && DECL_INITIAL (decl) != error_mark_node + && DECL_INITIAL (decl) != empty_init_node) + { + DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl)); + + if (asmspec) + DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec); + + if (! toplev + && TREE_STATIC (decl) + && ! TREE_SIDE_EFFECTS (decl) + && ! TREE_PUBLIC (decl) + && ! DECL_EXTERNAL (decl) + && ! TYPE_NEEDS_DESTRUCTOR (type) + && DECL_MODE (decl) != BLKmode) + { + /* If this variable is really a constant, then fill its DECL_RTL + slot with something which won't take up storage. + If something later should take its address, we can always give + it legitimate RTL at that time. */ + DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl)); + store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0); + TREE_ASM_WRITTEN (decl) = 1; + } + else if (toplev) + { + /* Keep GCC from complaining that this variable + is defined but never used. */ + TREE_USED (decl) = 1; + /* If this is a static const, change its apparent linkage + if it belongs to a #pragma interface. */ + if (TREE_STATIC (decl) && !interface_unknown) + { + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = interface_only; + } + make_decl_rtl (decl, asmspec, toplev); + } + else + rest_of_decl_compilation (decl, asmspec, toplev, 0); + } + else if (TREE_CODE (decl) == VAR_DECL + && DECL_LANG_SPECIFIC (decl) + && DECL_IN_AGGR_P (decl)) + { + if (TREE_STATIC (decl)) + if (init == NULL_TREE +#ifdef DEFAULT_STATIC_DEFS + /* If this code is dead, then users must + explicitly declare static member variables + outside the class def'n as well. */ + && TYPE_NEEDS_CONSTRUCTING (type) +#endif + ) + { + DECL_EXTERNAL (decl) = 1; + make_decl_rtl (decl, asmspec, 1); + } + else + rest_of_decl_compilation (decl, asmspec, toplev, 0); + else + /* Just a constant field. Should not need any rtl. */ + goto finish_end0; + } + else + rest_of_decl_compilation (decl, asmspec, toplev, 0); + + if (was_temp) + resume_temporary_allocation (); + + if (type != error_mark_node + && TYPE_LANG_SPECIFIC (type) + && CLASSTYPE_ABSTRACT_VIRTUALS (type)) + abstract_virtuals_error (decl, type); + else if ((TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE) + && TYPE_LANG_SPECIFIC (TREE_TYPE (type)) + && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (type))) + abstract_virtuals_error (decl, TREE_TYPE (type)); + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + /* C++: Handle overloaded functions with default parameters. */ + if (DECL_OVERLOADED (decl)) + { + tree parmtypes = TYPE_ARG_TYPES (type); + tree prev = NULL_TREE; + tree original_name = DECL_NAME (decl); + struct lang_decl *tmp_lang_decl = DECL_LANG_SPECIFIC (decl); + /* All variants will share an uncollectible lang_decl. */ + copy_decl_lang_specific (decl); + + while (parmtypes && parmtypes != void_list_node) + { + if (TREE_PURPOSE (parmtypes)) + { + tree fnname, fndecl; + tree *argp = prev + ? & TREE_CHAIN (prev) + : & TYPE_ARG_TYPES (type); + + *argp = NULL_TREE; + fnname = build_decl_overload (original_name, TYPE_ARG_TYPES (type), 0); + *argp = parmtypes; + fndecl = build_decl (FUNCTION_DECL, fnname, type); + DECL_EXTERNAL (fndecl) = DECL_EXTERNAL (decl); + TREE_PUBLIC (fndecl) = TREE_PUBLIC (decl); + DECL_INLINE (fndecl) = DECL_INLINE (decl); + /* Keep G++ from thinking this function is unused. + It is only used to speed up search in name space. */ + TREE_USED (fndecl) = 1; + TREE_ASM_WRITTEN (fndecl) = 1; + DECL_INITIAL (fndecl) = NULL_TREE; + DECL_LANG_SPECIFIC (fndecl) = DECL_LANG_SPECIFIC (decl); + fndecl = pushdecl (fndecl); + DECL_INITIAL (fndecl) = error_mark_node; + DECL_RTL (fndecl) = DECL_RTL (decl); + } + prev = parmtypes; + parmtypes = TREE_CHAIN (parmtypes); + } + DECL_LANG_SPECIFIC (decl) = tmp_lang_decl; + } + } + else if (DECL_EXTERNAL (decl)) + ; + 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) + 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)) + build_static_gc_entry (decl, type); + } + else if (current_binding_level != global_binding_level) + { + /* This is a declared decl which must live until the + end of the binding contour. It may need a cleanup. */ + + /* Recompute the RTL of a local array now + if it used to be an incomplete type. */ + if (was_incomplete && ! TREE_STATIC (decl)) + { + /* If we used it already as memory, it must stay in memory. */ + TREE_ADDRESSABLE (decl) = TREE_USED (decl); + /* If it's still incomplete now, no init will save it. */ + if (DECL_SIZE (decl) == NULL_TREE) + DECL_INITIAL (decl) = NULL_TREE; + expand_decl (decl); + } + else if (! TREE_ASM_WRITTEN (decl) + && (TYPE_SIZE (type) != NULL_TREE + || TREE_CODE (type) == ARRAY_TYPE)) + { + /* Do this here, because we did not expand this decl's + rtl in start_decl. */ + if (DECL_RTL (decl) == NULL_RTX) + expand_decl (decl); + else if (cleanup) + { + expand_decl_cleanup (NULL_TREE, cleanup); + /* Cleanup used up here. */ + cleanup = NULL_TREE; + } + } + + if (DECL_SIZE (decl) && type != error_mark_node) + { + /* Compute and store the initial value. */ + expand_decl_init (decl); + + if (init || TYPE_NEEDS_CONSTRUCTING (type)) + { + emit_line_note (DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); + expand_aggr_init (decl, init, 0); + } + + /* Set this to 0 so we can tell whether an aggregate + which was initialized was ever used. */ + if (TYPE_NEEDS_CONSTRUCTING (type)) + TREE_USED (decl) = 0; + + /* Store the cleanup, if there was one. */ + if (cleanup) + { + if (! expand_decl_cleanup (decl, cleanup)) + error_with_decl (decl, "parser lost in parsing declaration of `%s'"); + } + } + } + finish_end0: + + /* Undo call to `pushclass' that was done in `start_decl' + due to initialization of qualified member variable. + I.e., Foo::x = 10; */ + { + tree context = DECL_CONTEXT (decl); + if (context + && TREE_CODE_CLASS (TREE_CODE (context)) == 't' + && (TREE_CODE (decl) == VAR_DECL + /* We also have a pushclass done that we need to undo here + if we're at top level and declare a method. */ + || (TREE_CODE (decl) == FUNCTION_DECL + /* If size hasn't been set, we're still defining it, + and therefore inside the class body; don't pop + the binding level.. */ + && TYPE_SIZE (context) != NULL_TREE + /* The binding level gets popped elsewhere for a + friend declaration inside another class. */ + && TYPE_IDENTIFIER (context) == current_class_name + ))) + popclass (1); + } + } + + finish_end: + + 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; + + if (flag_cadillac) + cadillac_finish_decl (decl); +} + +static void +expand_static_init (decl, init) + tree decl; + tree init; +{ + tree oldstatic = value_member (decl, static_aggregates); + if (oldstatic) + { + if (TREE_PURPOSE (oldstatic)) + error_with_decl (decl, "multiple initializations given for `%s'"); + } + else if (current_binding_level != global_binding_level) + { + /* Emit code to perform this initialization but once. */ + tree temp; + + /* Remember this information until end of file. */ + push_obstacks (&permanent_obstack, &permanent_obstack); + + /* Emit code to perform this initialization but once. */ + temp = get_temp_name (integer_type_node, 1); + rest_of_decl_compilation (temp, NULL_PTR, 0, 0); + expand_start_cond (build_binary_op (EQ_EXPR, temp, + integer_zero_node, 1), 0); + expand_assignment (temp, integer_one_node, 0, 0); + if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) + { + expand_aggr_init (decl, init, 0); + do_pending_stack_adjust (); + } + else + expand_assignment (decl, init, 0, 0); + expand_end_cond (); + if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) + { + static_aggregates = perm_tree_cons (temp, decl, static_aggregates); + TREE_STATIC (static_aggregates) = 1; + } + + /* Resume old (possibly temporary) allocation. */ + pop_obstacks (); + } + else + { + /* This code takes into account memory allocation + policy of `start_decl'. Namely, if TYPE_NEEDS_CONSTRUCTING + does not hold for this object, then we must make permanent + the storage currently in the temporary obstack. */ + if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) + preserve_initializer (); + static_aggregates = perm_tree_cons (init, decl, static_aggregates); + } +} + +/* Make TYPE a complete type based on INITIAL_VALUE. + Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered, + 2 if there was no information (in which case assume 1 if DO_DEFAULT). */ + +int +complete_array_type (type, initial_value, do_default) + tree type, initial_value; + int do_default; +{ + register tree maxindex = NULL_TREE; + int value = 0; + + if (initial_value) + { + /* Note MAXINDEX is really the maximum index, + one less than the size. */ + if (TREE_CODE (initial_value) == STRING_CST) + maxindex = build_int_2 (TREE_STRING_LENGTH (initial_value) - 1, 0); + else if (TREE_CODE (initial_value) == CONSTRUCTOR) + { + register int nelts + = list_length (CONSTRUCTOR_ELTS (initial_value)); + maxindex = build_int_2 (nelts - 1, 0); + } + else + { + /* Make an error message unless that happened already. */ + if (initial_value != error_mark_node) + value = 1; + + /* Prevent further error messages. */ + maxindex = build_int_2 (1, 0); + } + } + + if (!maxindex) + { + if (do_default) + maxindex = build_int_2 (1, 0); + value = 2; + } + + if (maxindex) + { + TYPE_DOMAIN (type) = build_index_type (maxindex); + if (!TREE_TYPE (maxindex)) + TREE_TYPE (maxindex) = TYPE_DOMAIN (type); + } + + /* Lay out the type now that we can get the real answer. */ + + layout_type (type); + + return value; +} + +/* Return zero if something is declared to be a member of type + CTYPE when in the context of CUR_TYPE. STRING is the error + message to print in that case. Otherwise, quietly return 1. */ +static int +member_function_or_else (ctype, cur_type, string) + tree ctype, cur_type; + char *string; +{ + if (ctype && ctype != cur_type) + { + error (string, TYPE_NAME_STRING (ctype)); + return 0; + } + return 1; +} + +/* Subroutine of `grokdeclarator'. */ + +/* CTYPE is class type, or null if non-class. + TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE + or METHOD_TYPE. + DECLARATOR is the function's name. + VIRTUALP is truthvalue of whether the function is virtual or not. + FLAGS are to be passed through to `grokclassfn'. + QUALS are qualifiers indicating whether the function is `const' + or `volatile'. + RAISES is a list of exceptions that this function can raise. + CHECK is 1 if we must find this method in CTYPE, 0 if we should + not look, and -1 if we should not call `grokclassfn' at all. */ +static tree +grokfndecl (ctype, type, declarator, virtualp, flags, quals, raises, check, publicp) + tree ctype, type; + tree declarator; + int virtualp; + enum overload_flags flags; + tree quals, raises; + int check, publicp; +{ + tree cname, decl; + int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; + + if (ctype) + cname = TREE_CODE (TYPE_NAME (ctype)) == TYPE_DECL + ? TYPE_IDENTIFIER (ctype) : TYPE_NAME (ctype); + else + cname = NULL_TREE; + + if (raises) + { + type = build_exception_variant (ctype, type, raises); + raises = TYPE_RAISES_EXCEPTIONS (type); + } + decl = build_lang_decl (FUNCTION_DECL, declarator, type); + /* propagate volatile out from type to decl */ + if (TYPE_VOLATILE (type)) + TREE_THIS_VOLATILE (decl) = 1; + + /* Should probably propagate const out from type to decl I bet (mrs). */ + if (staticp) + { + DECL_STATIC_FUNCTION_P (decl) = 1; + DECL_CONTEXT (decl) = ctype; + DECL_CLASS_CONTEXT (decl) = ctype; + } + + if (publicp) + TREE_PUBLIC (decl) = 1; + + DECL_EXTERNAL (decl) = 1; + if (quals != NULL_TREE && TREE_CODE (type) == FUNCTION_TYPE) + { + error ("functions cannot have method qualifiers"); + quals = NULL_TREE; + } + + /* Only two styles of delete's are valid. */ + if (declarator == ansi_opname[(int) DELETE_EXPR]) + { + tree args = TYPE_ARG_TYPES (type); + int style1, style2; + + if (ctype && args && TREE_CODE (type) == METHOD_TYPE) + /* remove this */ + args = TREE_CHAIN (args); + + style1 = type_list_equal (args, + tree_cons (NULL_TREE, ptr_type_node, + void_list_node)); + style2 = style1 != 0 ? 0 : + type_list_equal (args, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, sizetype, + void_list_node))); + + if (ctype == NULL_TREE) + { + if (! style1) + /* ANSI C++ June 5 1992 WP 12.5.5.2 */ + error ("global operator delete must be declared as taking a single argument of type void*"); + } + else + if (! style1 && ! style2) + /* ANSI C++ June 5 1992 WP 12.5.4.1 */ + error ("operator delete cannot be overloaded"); + } + else if (DECL_NAME (decl) == ansi_opname[(int) POSTINCREMENT_EXPR] + || DECL_NAME (decl) == ansi_opname[(int) POSTDECREMENT_EXPR]) + { + /* According to ARM $13.4.7, postfix operator++ must take an int as + its second argument. */ + tree parmtypes, argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); + + if (argtypes) + { + parmtypes = TREE_CHAIN (argtypes); + if (parmtypes != NULL_TREE + && TREE_VALUE (parmtypes) != void_type_node + && TREE_VALUE (parmtypes) != integer_type_node) + error ("postfix operator%s may only take `int' as its argument", + POSTINCREMENT_EXPR ? "++" : "--"); + } + } + + /* Caller will do the rest of this. */ + if (check < 0) + return decl; + + if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator) + { + tree tmp; + /* Just handle constructors here. We could do this + inside the following if stmt, but I think + that the code is more legible by breaking this + case out. See comments below for what each of + the following calls is supposed to do. */ + DECL_CONSTRUCTOR_P (decl) = 1; + + grokclassfn (ctype, declarator, decl, flags, quals); + if (check) + check_classfn (ctype, declarator, decl); + grok_ctor_properties (ctype, decl); + if (check == 0) + { + /* FIXME: this should only need to look at IDENTIFIER_GLOBAL_VALUE. */ + tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0); + if (tmp == NULL_TREE) + IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl; + else if (TREE_CODE (tmp) != TREE_CODE (decl)) + error_with_decl (decl, "inconsistent declarations for `%s'"); + else + { + duplicate_decls (decl, tmp); + decl = tmp; + /* avoid creating circularities. */ + DECL_CHAIN (decl) = NULL_TREE; + } + make_decl_rtl (decl, NULL_PTR, 1); + } + } + else + { + tree tmp; + + /* Function gets the ugly name, field gets the nice one. + This call may change the type of the function (because + of default parameters)! */ + if (ctype != NULL_TREE) + grokclassfn (ctype, cname, decl, flags, quals); + + if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))) + grok_op_properties (decl, virtualp); + + if (ctype != NULL_TREE && check) + check_classfn (ctype, cname, decl); + + if (ctype == NULL_TREE || check) + return decl; + + /* Now install the declaration of this function so that + others may find it (esp. its DECL_FRIENDLIST). + Pretend we are at top level, we will get true + reference later, perhaps. + + FIXME: This should only need to look at IDENTIFIER_GLOBAL_VALUE. */ + tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0); + if (tmp == NULL_TREE) + IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl; + else if (TREE_CODE (tmp) != TREE_CODE (decl)) + error_with_decl (decl, "inconsistent declarations for `%s'"); + else + { + duplicate_decls (decl, tmp); + decl = tmp; + /* avoid creating circularities. */ + DECL_CHAIN (decl) = NULL_TREE; + } + make_decl_rtl (decl, NULL_PTR, 1); + + /* If this declaration supersedes the declaration of + a method declared virtual in the base class, then + mark this field as being virtual as well. */ + { + tree binfos = BINFO_BASETYPES (TYPE_BINFO (ctype)); + int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; + + for (i = 0; i < n_baselinks; i++) + { + tree base_binfo = TREE_VEC_ELT (binfos, i); + if (TYPE_VIRTUAL_P (BINFO_TYPE (base_binfo)) || flag_all_virtual == 1) + { + tmp = get_first_matching_virtual (base_binfo, decl, + flags == DTOR_FLAG); + if (tmp) + { + /* The TMP we really want is the one from the deepest + baseclass on this path, taking care not to + duplicate if we have already found it (via another + path to its virtual baseclass. */ + if (staticp) + { + error_with_decl (decl, "method `%s' may not be declared static"); + error_with_decl (tmp, "(since `%s' declared virtual in base class.)"); + break; + } + virtualp = 1; + + if ((TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (base_binfo)) + || TYPE_USES_MULTIPLE_INHERITANCE (ctype)) + && BINFO_TYPE (base_binfo) != DECL_CONTEXT (tmp)) + tmp = get_first_matching_virtual (TYPE_BINFO (DECL_CONTEXT (tmp)), + decl, flags == DTOR_FLAG); + if (value_member (tmp, DECL_VINDEX (decl)) == NULL_TREE) + { + /* The argument types may have changed... */ + tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); + tree base_variant = TREE_TYPE (TREE_VALUE (argtypes)); + + argtypes = commonparms (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (tmp))), + TREE_CHAIN (argtypes)); + /* But the return type has not. */ + type = build_cplus_method_type (base_variant, TREE_TYPE (type), argtypes); + if (raises) + { + type = build_exception_variant (ctype, type, raises); + raises = TYPE_RAISES_EXCEPTIONS (type); + } + TREE_TYPE (decl) = type; + DECL_VINDEX (decl) + = tree_cons (NULL_TREE, tmp, DECL_VINDEX (decl)); + } + } + } + } + } + if (virtualp) + { + if (DECL_VINDEX (decl) == NULL_TREE) + DECL_VINDEX (decl) = error_mark_node; + IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1; + if (ctype && CLASSTYPE_VTABLE_NEEDS_WRITING (ctype) + /* If this function is derived from a template, don't + make it public. This shouldn't be here, but there's + no good way to override the interface pragmas for one + function or class only. Bletch. */ + && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (ctype)) == NULL_TREE + && (write_virtuals == 2 + || (write_virtuals == 3 + && ! CLASSTYPE_INTERFACE_UNKNOWN (ctype)))) + TREE_PUBLIC (decl) = 1; + } + } + return decl; +} + +static tree +grokvardecl (type, declarator, specbits, initialized) + tree type; + tree declarator; + RID_BIT_TYPE specbits; + int initialized; +{ + tree decl; + + /* This implements the "one definition rule" for global variables. + Note that declarator can come in as null when we're doing work + on an anonymous union. */ + if (declarator && IDENTIFIER_GLOBAL_VALUE (declarator) + && current_binding_level == global_binding_level + && TREE_STATIC (IDENTIFIER_GLOBAL_VALUE (declarator)) + && (! (specbits & RIDBIT (RID_EXTERN)) + || initialized)) + { + error ("redefinition of `%s'", IDENTIFIER_POINTER (declarator)); + error_with_decl (IDENTIFIER_GLOBAL_VALUE (declarator), + "previously defined here"); + } + + if (TREE_CODE (type) == OFFSET_TYPE) + { + /* If you declare a static member so that it + can be initialized, the code will reach here. */ + tree field = lookup_field (TYPE_OFFSET_BASETYPE (type), + declarator, 0, 0); + if (field == NULL_TREE || TREE_CODE (field) != VAR_DECL) + { + tree basetype = TYPE_OFFSET_BASETYPE (type); + error ("`%s' is not a static member of class `%s'", + IDENTIFIER_POINTER (declarator), + TYPE_NAME_STRING (basetype)); + type = TREE_TYPE (type); + decl = build_lang_field_decl (VAR_DECL, declarator, type); + DECL_CONTEXT (decl) = basetype; + DECL_CLASS_CONTEXT (decl) = basetype; + } + else + { + tree f_type = TREE_TYPE (field); + tree o_type = TREE_TYPE (type); + + if (TYPE_SIZE (f_type) == NULL_TREE) + { + if (TREE_CODE (f_type) != TREE_CODE (o_type) + || (TREE_CODE (f_type) == ARRAY_TYPE + && TREE_TYPE (f_type) != TREE_TYPE (o_type))) + error ("redeclaration of type for `%s'", + IDENTIFIER_POINTER (declarator)); + else if (TYPE_SIZE (o_type) != NULL_TREE) + TREE_TYPE (field) = type; + } + else if (f_type != o_type) + error ("redeclaration of type for `%s'", + IDENTIFIER_POINTER (declarator)); + decl = field; + if (initialized && DECL_INITIAL (decl) + /* Complain about multiply-initialized + member variables, but don't be faked + out if initializer is faked up from `empty_init_node'. */ + && (TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR + || CONSTRUCTOR_ELTS (DECL_INITIAL (decl)) != NULL_TREE)) + error_with_aggr_type (DECL_CONTEXT (decl), + "multiple initializations of static member `%s::%s'", + IDENTIFIER_POINTER (DECL_NAME (decl))); + } + } + else decl = build_decl (VAR_DECL, declarator, type); + + if (specbits & RIDBIT (RID_EXTERN)) + { + DECL_THIS_EXTERN (decl) = 1; + DECL_EXTERNAL (decl) = !initialized; + } + + /* In class context, static means one per class, + public visibility, and static storage. */ + if (DECL_FIELD_CONTEXT (decl) != NULL_TREE + && IS_AGGR_TYPE (DECL_FIELD_CONTEXT (decl))) + { + TREE_PUBLIC (decl) = 1; + TREE_STATIC (decl) = 1; + DECL_EXTERNAL (decl) = !initialized; + } + /* At top level, either `static' or no s.c. makes a definition + (perhaps tentative), and absence of `static' makes it public. */ + else if (current_binding_level == global_binding_level) + { + TREE_PUBLIC (decl) = ! (specbits & RIDBIT (RID_STATIC)); + TREE_STATIC (decl) = ! DECL_EXTERNAL (decl); + } + /* Not at top level, only `static' makes a static definition. */ + else + { + TREE_STATIC (decl) = !! (specbits & RIDBIT (RID_STATIC)); + TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); + } + return decl; +} + +/* Given declspecs and a declarator, + determine the name and type of the object declared + and construct a ..._DECL node for it. + (In one case we can return a ..._TYPE node instead. + For invalid input we sometimes return 0.) + + DECLSPECS is a chain of tree_list nodes whose value fields + are the storage classes and type specifiers. + + DECL_CONTEXT says which syntactic context this declaration is in: + NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL. + FUNCDEF for a function definition. Like NORMAL but a few different + error messages in each case. Return value may be zero meaning + this definition is too screwy to try to parse. + MEMFUNCDEF for a function definition. Like FUNCDEF but prepares to + handle member functions (which have FIELD context). + Return value may be zero meaning this definition is too screwy to + try to parse. + PARM for a parameter declaration (either within a function prototype + or before a function body). Make a PARM_DECL, or return void_type_node. + TYPENAME if for a typename (in a cast or sizeof). + Don't make a DECL node; just return the ..._TYPE node. + FIELD for a struct or union field; make a FIELD_DECL. + BITFIELD for a field with specified width. + INITIALIZED is 1 if the decl has an initializer. + + In the TYPENAME case, DECLARATOR is really an absolute declarator. + It may also be so in the PARM case, for a prototype where the + argument type is specified but not the name. + + This function is where the complicated C meanings of `static' + and `extern' are interpreted. + + For C++, if there is any monkey business to do, the function which + calls this one must do it, i.e., prepending instance variables, + renaming overloaded function names, etc. + + Note that for this C++, it is an error to define a method within a class + which does not belong to that class. + + Except in the case where SCOPE_REFs are implicitly known (such as + methods within a class being redundantly qualified), + declarations which involve SCOPE_REFs are returned as SCOPE_REFs + (class_name::decl_name). The caller must also deal with this. + + If a constructor or destructor is seen, and the context is FIELD, + then the type gains the attribute TREE_HAS_x. If such a declaration + 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. + + May return void_type_node if the declarator turned out to be a friend. + See grokfield for details. */ + +enum return_types { return_normal, return_ctor, return_dtor, return_conversion }; + +tree +grokdeclarator (declarator, declspecs, decl_context, initialized, raises) + tree declspecs; + tree declarator; + enum decl_context decl_context; + int initialized; + tree raises; +{ + extern int current_class_depth; + + RID_BIT_TYPE specbits = 0; + int nclasses = 0; + tree spec; + tree type = NULL_TREE; + int longlong = 0; + int constp; + int volatilep; + int virtualp, friendp, inlinep, staticp; + int explicit_int = 0; + int explicit_char = 0; + tree typedef_decl = NULL_TREE; + char *name; + tree typedef_type = NULL_TREE; + int funcdef_flag = 0; + enum tree_code innermost_code = ERROR_MARK; + int bitfield = 0; + int size_varies = 0; + /* Set this to error_mark_node for FIELD_DECLs we could not handle properly. + All FIELD_DECLs we build here have `init' put into their DECL_INITIAL. */ + tree init = NULL_TREE; + + /* Keep track of what sort of function is being processed + so that we can warn about default return values, or explicit + return values which do not match prescribed defaults. */ + enum return_types return_type = return_normal; + + tree dname = NULL_TREE; + tree ctype = current_class_type; + tree ctor_return_type = NULL_TREE; + enum overload_flags flags = NO_SPECIAL; + int seen_scope_ref = 0; + tree quals = NULL_TREE; + + if (decl_context == FUNCDEF) + funcdef_flag = 1, decl_context = NORMAL; + else if (decl_context == MEMFUNCDEF) + funcdef_flag = -1, decl_context = FIELD; + else if (decl_context == BITFIELD) + bitfield = 1, decl_context = FIELD; + + if (flag_traditional && allocation_temporary_p ()) + end_temporary_allocation (); + + /* Look inside a declarator for the name being declared + and get it as a string, for an error message. */ + { + tree type, last = NULL_TREE; + register tree decl = declarator; + name = NULL; + + /* If we see something of the form `aggr_type xyzzy (a, b, c)' + it is either an old-style function declaration or a call to + a constructor. The following conditional makes recognizes this + case as being a call to a constructor. Too bad if it is not. */ + + /* For Doug Lea, also grok `aggr_type xyzzy (a, b, c)[10][10][10]'. */ + while (decl && TREE_CODE (decl) == ARRAY_REF) + { + last = decl; + decl = TREE_OPERAND (decl, 0); + } + + if (decl && declspecs + && TREE_CODE (decl) == CALL_EXPR + && TREE_OPERAND (decl, 0) + && (TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE + || TREE_CODE (TREE_OPERAND (decl, 0)) == SCOPE_REF)) + { + type = TREE_CODE (TREE_VALUE (declspecs)) == IDENTIFIER_NODE + ? lookup_name (TREE_VALUE (declspecs), 1) : + (IS_AGGR_TYPE (TREE_VALUE (declspecs)) + ? TYPE_NAME (TREE_VALUE (declspecs)) : NULL_TREE); + + if (type && TREE_CODE (type) == TYPE_DECL + && IS_AGGR_TYPE (TREE_TYPE (type)) + && parmlist_is_exprlist (TREE_OPERAND (decl, 1))) + { + if (decl_context == FIELD + && TREE_CHAIN (TREE_OPERAND (decl, 1))) + { + /* That was an initializer list. */ + sorry ("initializer lists for field declarations"); + decl = TREE_OPERAND (decl, 0); + if (last) + { + TREE_OPERAND (last, 0) = decl; + decl = declarator; + } + declarator = decl; + init = error_mark_node; + goto bot; + } + else + { + init = TREE_OPERAND (decl, 1); + if (last) + { + TREE_OPERAND (last, 0) = TREE_OPERAND (decl, 0); + if (pedantic && init) + { + error ("arrays cannot take initializers"); + init = error_mark_node; + } + } + else + declarator = TREE_OPERAND (declarator, 0); + decl = start_decl (declarator, declspecs, 1, NULL_TREE); + finish_decl (decl, init, NULL_TREE, 1); + return 0; + } + } + + if (parmlist_is_random (TREE_OPERAND (decl, 1))) + { + decl = TREE_OPERAND (decl, 0); + if (TREE_CODE (decl) == SCOPE_REF) + { + if (TREE_COMPLEXITY (decl)) + my_friendly_abort (15); + decl = TREE_OPERAND (decl, 1); + } + if (TREE_CODE (decl) == IDENTIFIER_NODE) + name = IDENTIFIER_POINTER (decl); + if (name) + error ("bad parameter list specification for function `%s'", + name); + else + error ("bad parameter list specification for function"); + return void_type_node; + } + bot: + ; + } + else + /* It didn't look like we thought it would, leave the ARRAY_REFs on. */ + decl = declarator; + + 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! */ + { + 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); + decl = TREE_OPERAND (decl, 0); + break; + + case CALL_EXPR: + innermost_code = TREE_CODE (decl); + decl = TREE_OPERAND (decl, 0); + if (decl_context == FIELD && ctype == NULL_TREE) + ctype = current_class_type; + 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; + name = IDENTIFIER_POINTER (decl); + decl = NULL_TREE; + 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 TYPE_EXPR: + if (ctype == NULL_TREE) + { + /* ANSI C++ June 5 1992 WP 12.3.2 only describes + conversion functions in terms of being declared + as a member function. */ + error ("operator `%s' must be declared as a member", + IDENTIFIER_POINTER (TREE_VALUE (TREE_TYPE (decl)))); + return NULL_TREE; + } + + ctype = NULL_TREE; + my_friendly_assert (flags == NO_SPECIAL, 154); + flags = TYPENAME_FLAG; + name = "operator <typename>"; + /* Go to the absdcl. */ + decl = TREE_OPERAND (decl, 0); + return_type = return_conversion; + break; + + /* C++ extension */ + case SCOPE_REF: + if (seen_scope_ref == 1) + error ("multiple `::' terms in declarator invalid"); + seen_scope_ref += 1; + { + /* 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)) + { + 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) + { + TREE_OPERAND (decl, 0) = IDENTIFIER_TYPE_VALUE (cname); + } + else if (ctype == NULL_TREE) + { + ctype = IDENTIFIER_TYPE_VALUE (cname); + TREE_OPERAND (decl, 0) = ctype; + } + else if (TREE_COMPLEXITY (decl) == current_class_depth) + TREE_OPERAND (decl, 0) = ctype; + else + { + if (! UNIQUELY_DERIVED_FROM_P (IDENTIFIER_TYPE_VALUE (cname), ctype)) + { + error ("type `%s' is not derived from type `%s'", + IDENTIFIER_POINTER (cname), + TYPE_NAME_STRING (ctype)); + TREE_OPERAND (decl, 0) = NULL_TREE; + } + else + { + ctype = IDENTIFIER_TYPE_VALUE (cname); + TREE_OPERAND (decl, 0) = ctype; + } + } + + decl = TREE_OPERAND (decl, 1); + 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)) + { + return_type = return_dtor; + ctor_return_type = ctype; + flags = DTOR_FLAG; + decl = TREE_OPERAND (decl, 0); + } + } + } + break; + + case ERROR_MARK: + decl = NULL_TREE; + break; + + default: + my_friendly_abort (155); + } + if (name == NULL) + name = "type name"; + } + + /* A function definition's declarator must have the form of + a function declarator. */ + + if (funcdef_flag && innermost_code != CALL_EXPR) + return 0; + + /* Anything declared one level down from the top level + must be one of the parameters of a function + (because the body is at least two levels down). */ + + /* This heuristic cannot be applied to C++ nodes! Fixed, however, + by not allowing C++ class definitions to specify their parameters + with xdecls (must be spec.d in the parmlist). + + Since we now wait to push a class scope until we are sure that + we are in a legitimate method context, we must set oldcname + explicitly (since current_class_name is not yet alive). */ + + if (decl_context == NORMAL + && current_binding_level->level_chain == global_binding_level) + decl_context = PARM; + + /* Look through the decl specs and record which ones appear. + Some typespecs are defined as built-in typenames. + Others, the ones that are modifiers of other types, + are represented by bits in SPECBITS: set the bits for + the modifiers that appear. Storage class keywords are also in SPECBITS. + + If there is a typedef name or a type, store the type in TYPE. + This includes builtin typedefs such as `int'. + + Set EXPLICIT_INT if the type is `int' or `char' and did not + come from a user typedef. + + Set LONGLONG if `long' is mentioned twice. + + For C++, constructors and destructors have their own fast treatment. */ + + for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) + { + register int i; + register tree id = TREE_VALUE (spec); + + /* Certain parse errors slip through. For example, + `int class;' is not caught by the parser. Try + weakly to recover here. */ + if (TREE_CODE (spec) != TREE_LIST) + return 0; + + if (TREE_CODE (id) == IDENTIFIER_NODE) + { + if (id == ridpointers[(int) RID_INT]) + { + if (type) + error ("extraneous `int' ignored"); + else + { + explicit_int = 1; + type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id)); + } + goto found; + } + if (id == ridpointers[(int) RID_CHAR]) + { + if (type) + error ("extraneous `char' ignored"); + else + { + explicit_char = 1; + type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id)); + } + goto found; + } + if (id == ridpointers[(int) RID_WCHAR]) + { + if (type) + error ("extraneous `__wchar_t' ignored"); + else + { + type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id)); + } + goto found; + } + /* C++ aggregate types. */ + if (IDENTIFIER_HAS_TYPE_VALUE (id)) + { + if (type) + error ("multiple declarations `%s' and `%s'", + IDENTIFIER_POINTER (type), + IDENTIFIER_POINTER (id)); + else + type = IDENTIFIER_TYPE_VALUE (id); + goto found; + } + + for (i = (int) RID_FIRST_MODIFIER; i < (int) RID_MAX; i++) + { + if (ridpointers[i] == id) + { + if (i == (int) RID_LONG && (specbits & RIDBIT (i))) + { + if (pedantic) + pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id)); + else if (longlong) + error ("`long long long' is too long for GCC"); + else + longlong = 1; + } + else if (specbits & RIDBIT (i)) + warning ("duplicate `%s'", IDENTIFIER_POINTER (id)); + specbits |= RIDBIT (i); + goto found; + } + } + } + if (type) + error ("two or more data types in declaration of `%s'", name); + else if (TREE_CODE (id) == IDENTIFIER_NODE) + { + register tree t = lookup_name (id, 1); + if (!t || TREE_CODE (t) != TYPE_DECL) + error ("`%s' fails to be a typedef or built in type", + IDENTIFIER_POINTER (id)); + else + { + type = TREE_TYPE (t); + typedef_decl = t; + } + } + else if (TREE_CODE (id) != ERROR_MARK) + /* Can't change CLASS nodes into RECORD nodes here! */ + type = id; + + found: {} + } + + typedef_type = type; + + /* No type at all: default to `int', and set EXPLICIT_INT + because it was not a user-defined typedef. */ + + if (type == NULL_TREE) + { + explicit_int = -1; + if (return_type == return_dtor) + type = void_type_node; + else if (return_type == return_ctor) + type = TYPE_POINTER_TO (ctor_return_type); + else + { + if (funcdef_flag && explicit_warn_return_type + && return_type == return_normal + && ! (specbits & (RIDBIT (RID_SIGNED) | RIDBIT (RID_UNSIGNED) + | RIDBIT (RID_LONG) | RIDBIT (RID_SHORT)))) + warn_about_return_type = 1; + /* Save warning until we know what is really going on. */ + type = integer_type_node; + } + } + else if (return_type == return_dtor) + { + error ("return type specification for destructor invalid"); + type = void_type_node; + } + else if (return_type == return_ctor) + { + error ("return type specification for constructor invalid"); + type = TYPE_POINTER_TO (ctor_return_type); + } + else if ((specbits & RIDBIT (RID_FRIEND)) + && IS_AGGR_TYPE (type) + && ! TYPE_BEING_DEFINED (type) + && TYPE_SIZE (type) == NULL_TREE + && ! ANON_AGGRNAME_P (TYPE_IDENTIFIER (type)) + && current_function_decl == NULL_TREE + && decl_context != PARM) + { + /* xref_tag will make friend class declarations look like + nested class declarations. Retroactively change that + if the type has not yet been defined. + + ??? ANSI C++ doesn't say what to do in this case yet. */ + globalize_nested_type (type); + } + + ctype = NULL_TREE; + + /* Now process the modifiers that were specified + and check for invalid combinations. */ + + /* Long double is a special combination. */ + + if ((specbits & RIDBIT (RID_LONG)) + && TYPE_MAIN_VARIANT (type) == double_type_node) + { + specbits &= ~ RIDBIT (RID_LONG); + type = build_type_variant (long_double_type_node, TYPE_READONLY (type), + TYPE_VOLATILE (type)); + } + + /* Check all other uses of type modifiers. */ + + if (specbits & (RIDBIT (RID_UNSIGNED) | RIDBIT (RID_SIGNED) + | RIDBIT (RID_LONG) | RIDBIT (RID_SHORT))) + { + int ok = 0; + + if (TREE_CODE (type) == REAL_TYPE) + error ("short, signed or unsigned invalid for `%s'", name); + else if (TREE_CODE (type) != INTEGER_TYPE || type == wchar_type_node) + error ("long, short, signed or unsigned invalid for `%s'", name); + else if ((specbits & RIDBIT (RID_LONG)) + && (specbits & RIDBIT (RID_SHORT))) + error ("long and short specified together for `%s'", name); + else if (((specbits & RIDBIT (RID_LONG)) + || (specbits & RIDBIT (RID_SHORT))) + && explicit_char) + error ("long or short specified with char for `%s'", name); + else if (((specbits & RIDBIT (RID_LONG)) + || (specbits & RIDBIT (RID_SHORT))) + && TREE_CODE (type) == REAL_TYPE) + error ("long or short specified with floating type for `%s'", name); + else if ((specbits & RIDBIT (RID_SIGNED)) + && (specbits & RIDBIT (RID_UNSIGNED))) + error ("signed and unsigned given together for `%s'", name); + else + { + ok = 1; + if (!explicit_int && !explicit_char && pedantic) + { + pedwarn ("long, short, signed or unsigned used invalidly for `%s'", + name); + if (flag_pedantic_errors) + ok = 0; + } + } + + /* Discard the type modifiers if they are invalid. */ + if (! ok) + { + specbits &= ~ (RIDBIT (RID_UNSIGNED) | RIDBIT (RID_SIGNED) + | RIDBIT (RID_LONG) | RIDBIT (RID_SHORT)); + longlong = 0; + } + } + + /* Decide whether an integer type is signed or not. + Optionally treat bitfields as signed by default. */ + if ((specbits & RIDBIT (RID_UNSIGNED)) + /* Traditionally, all bitfields are unsigned. */ + || (bitfield && flag_traditional) + || (bitfield && ! flag_signed_bitfields + && (explicit_int || explicit_char + /* A typedef for plain `int' without `signed' + can be controlled just like plain `int'. */ + || ! (typedef_decl != NULL_TREE + && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) + && TREE_CODE (type) != ENUMERAL_TYPE + && !(specbits & RIDBIT (RID_SIGNED)))) + { + if (longlong) + type = long_long_unsigned_type_node; + else if (specbits & RIDBIT (RID_LONG)) + type = long_unsigned_type_node; + else if (specbits & RIDBIT (RID_SHORT)) + type = short_unsigned_type_node; + else if (type == char_type_node) + type = unsigned_char_type_node; + else if (typedef_decl) + type = unsigned_type (type); + else + type = unsigned_type_node; + } + else if ((specbits & RIDBIT (RID_SIGNED)) + && type == char_type_node) + type = signed_char_type_node; + else if (longlong) + type = long_long_integer_type_node; + else if (specbits & RIDBIT (RID_LONG)) + type = long_integer_type_node; + else if (specbits & RIDBIT (RID_SHORT)) + type = short_integer_type_node; + + /* Set CONSTP if this declaration is `const', whether by + explicit specification or via a typedef. + Likewise for VOLATILEP. */ + + constp = !! (specbits & RIDBIT (RID_CONST)) + TYPE_READONLY (type); + volatilep = !! (specbits & RIDBIT (RID_VOLATILE)) + TYPE_VOLATILE (type); + staticp = 0; + inlinep = !! (specbits & RIDBIT (RID_INLINE)); + if (constp > 1) + warning ("duplicate `const'"); + if (volatilep > 1) + warning ("duplicate `volatile'"); + virtualp = specbits & RIDBIT (RID_VIRTUAL); + if (specbits & RIDBIT (RID_STATIC)) + staticp = 1 + (decl_context == FIELD); + + if (virtualp && staticp == 2) + { + error ("member `%s' cannot be declared both virtual and static", name); + staticp = 0; + } + friendp = specbits & RIDBIT (RID_FRIEND); + specbits &= ~ (RIDBIT (RID_VIRTUAL) | RIDBIT (RID_FRIEND)); + + /* Warn if two storage classes are given. Default to `auto'. */ + + if (specbits) + { + if (specbits & RIDBIT (RID_STATIC)) nclasses++; + if (specbits & RIDBIT (RID_EXTERN)) nclasses++; + if (decl_context == PARM && nclasses > 0) + error ("storage class specifiers invalid in parameter declarations"); + if (specbits & RIDBIT (RID_TYPEDEF)) + { + if (decl_context == PARM) + error ("typedef declaration invalid in parameter declaration"); + nclasses++; + } + if (specbits & RIDBIT (RID_AUTO)) nclasses++; + if (specbits & RIDBIT (RID_REGISTER)) nclasses++; + } + + /* Give error if `virtual' is used outside of class declaration. */ + if (virtualp && current_class_name == NULL_TREE) + { + error ("virtual outside class declaration"); + virtualp = 0; + } + + /* Warn about storage classes that are invalid for certain + kinds of declarations (parameters, typenames, etc.). */ + + if (nclasses > 1) + error ("multiple storage classes in declaration of `%s'", name); + else if (decl_context != NORMAL && nclasses > 0) + { + if (decl_context == PARM + && ((specbits & RIDBIT (RID_REGISTER)) | RIDBIT (RID_AUTO))) + ; + else if ((decl_context == FIELD + || decl_context == TYPENAME) + && (specbits & RIDBIT (RID_TYPEDEF))) + { + /* A typedef which was made in a class's scope. */ + tree loc_typedecl; + register int i = sizeof (struct lang_decl_flags) / sizeof (int); + register int *pi; + struct binding_level *local_binding_level; + + /* keep `grokdeclarator' from thinking we are in PARM context. */ + pushlevel (0); + /* poplevel_class may be called by grokdeclarator which is called in + start_decl which is called below. In this case, our pushed level + may vanish and poplevel mustn't be called. So remember what we + have pushed and pop only if that is matched by + current_binding_level later. mnl@dtro.e-technik.th-darmstadt.de */ + local_binding_level = current_binding_level; + + loc_typedecl = start_decl (declarator, declspecs, initialized, NULL_TREE); + + pi = (int *) permalloc (sizeof (struct lang_decl_flags)); + while (i > 0) + pi[--i] = 0; + DECL_LANG_SPECIFIC (loc_typedecl) = (struct lang_decl *) pi; + /* This poplevel conflicts with the popclass over in + grokdeclarator. See ``This popclass conflicts'' */ + if (current_binding_level == local_binding_level) + poplevel (0, 0, 0); + +#if 0 + if (TREE_CODE (TREE_TYPE (loc_typedecl)) == ENUMERAL_TYPE) + { + tree ref = lookup_tag (ENUMERAL_TYPE, DECL_NAME (loc_typedecl), current_binding_level, 0); + if (! ref) + pushtag (DECL_NAME (loc_typedecl), TREE_TYPE (loc_typedecl)); + } +#endif + + /* We used to check for a typedef hiding a previous decl in + class scope, but delete_duplicate_fields_1 will now do + that for us in the proper place. */ + + /* We reset loc_typedecl because the IDENTIFIER_CLASS_NAME is + set by pushdecl_class_level. */ + loc_typedecl = pushdecl_class_level (loc_typedecl); + + return loc_typedecl; + } + else if (decl_context == FIELD + /* C++ allows static class elements */ + && (specbits & RIDBIT (RID_STATIC))) + /* C++ also allows inlines and signed and unsigned elements, + but in those cases we don't come in here. */ + ; + else + { + if (decl_context == FIELD) + { + tree tmp = TREE_OPERAND (declarator, 0); + register int op = IDENTIFIER_OPNAME_P (tmp); + error ("storage class specified for %s `%s'", + op ? "member operator" : "structure field", + op ? operator_name_string (tmp) : name); + } + else + error ((decl_context == PARM + ? "storage class specified for parameter `%s'" + : "storage class specified for typename"), name); + specbits &= ~ (RIDBIT (RID_REGISTER) | RIDBIT (RID_AUTO) + | RIDBIT (RID_EXTERN)); + } + } + else if ((specbits & RIDBIT (RID_EXTERN)) && initialized && !funcdef_flag) + { + if (current_binding_level == global_binding_level) + { + /* It's common practice (and completely legal) to have a const + be initialized and declared extern. */ + if (! constp) + warning ("`%s' initialized and declared `extern'", name); + } + else + error ("`%s' has both `extern' and initializer", name); + } + else if ((specbits & RIDBIT (RID_EXTERN)) && funcdef_flag + && current_binding_level != global_binding_level) + error ("nested function `%s' declared `extern'", name); + else if (current_binding_level == global_binding_level) + { + if (specbits & RIDBIT (RID_AUTO)) + error ("top-level declaration of `%s' specifies `auto'", name); +#if 0 + if (specbits & RIDBIT (RID_REGISTER)) + error ("top-level declaration of `%s' specifies `register'", name); +#endif +#if 0 + /* I'm not sure under what circumstances we should turn + on the extern bit, and under what circumstances we should + warn if other bits are turned on. */ + if (decl_context == NORMAL + && ! (specbits & RIDBIT (RID_EXTERN)) + && ! root_lang_context_p ()) + { + specbits |= RIDBIT (RID_EXTERN); + } +#endif + } + + /* Now figure out the structure of the declarator proper. + Descend through it, creating more complex types, until we reach + the declared identifier (or NULL_TREE, in an absolute declarator). */ + + while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE) + { + /* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]), + an INDIRECT_REF (for *...), + a CALL_EXPR (for ...(...)), + an identifier (for the name being declared) + or a null pointer (for the place in an absolute declarator + where the name was omitted). + For the last two cases, we have just exited the loop. + + For C++ it could also be + a SCOPE_REF (for class :: ...). In this case, we have converted + sensible names to types, and those are the values we use to + qualify the member name. + an ADDR_EXPR (for &...), + a BIT_NOT_EXPR (for destructors) + a TYPE_EXPR (for operator typenames) + + At this point, TYPE is the type of elements of an array, + or for a function to return, or for a pointer to point to. + After this sequence of ifs, TYPE is the type of the + array or function or pointer, and DECLARATOR has had its + outermost layer removed. */ + + if (TREE_CODE (type) == ERROR_MARK) + { + if (TREE_CODE (declarator) == SCOPE_REF) + declarator = TREE_OPERAND (declarator, 1); + else + declarator = TREE_OPERAND (declarator, 0); + continue; + } + if (quals != NULL_TREE + && (declarator == NULL_TREE + || TREE_CODE (declarator) != SCOPE_REF)) + { + if (ctype == NULL_TREE && TREE_CODE (type) == METHOD_TYPE) + ctype = TYPE_METHOD_BASETYPE (type); + if (ctype != NULL_TREE) + { +#if 0 /* not yet, should get fixed properly later */ + tree dummy = make_type_decl (NULL_TREE, type); +#else + tree dummy = build_decl (TYPE_DECL, NULL_TREE, type); +#endif + ctype = grok_method_quals (ctype, dummy, quals); + type = TREE_TYPE (dummy); + quals = NULL_TREE; + } + } + switch (TREE_CODE (declarator)) + { + case ARRAY_REF: + maybe_globalize_type (type); + { + register tree itype = NULL_TREE; + register tree size = TREE_OPERAND (declarator, 1); + + declarator = TREE_OPERAND (declarator, 0); + + /* Check for some types that there cannot be arrays of. */ + + if (TYPE_MAIN_VARIANT (type) == void_type_node) + { + error ("declaration of `%s' as array of voids", name); + type = error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("declaration of `%s' as array of functions", name); + 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 legal for an array x, but + then you'd have to ask: what does `*(x + i)' mean? */ + if (TREE_CODE (type) == REFERENCE_TYPE) + error ("declaration of `%s' as array of references", name); + + if (size == error_mark_node) + type = error_mark_node; + + if (type == error_mark_node) + continue; + + 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 this is a template parameter, it'll be constant, but + we don't know what the value is yet. */ + if (TREE_CODE (size) == TEMPLATE_CONST_PARM) + goto dont_grok_size; + + if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE + && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE) + { + error ("size of array `%s' has non-integer type", name); + size = integer_one_node; + } + if (TREE_READONLY_DECL_P (size)) + size = decl_constant_value (size); + if (pedantic && integer_zerop (size)) + pedwarn ("ANSI C++ forbids zero-size array `%s'", name); + if (TREE_CONSTANT (size)) + { + if (INT_CST_LT (size, integer_zero_node)) + { + error ("size of array `%s' is negative", name); + size = integer_one_node; + } + itype = build_index_type (size_binop (MINUS_EXPR, size, + integer_one_node)); + } + else + { + if (pedantic) + pedwarn ("ANSI C++ forbids variable-size array `%s'", name); + dont_grok_size: + itype = + build_binary_op (MINUS_EXPR, size, integer_one_node, 1); + /* Make sure the array size remains visibly nonconstant + even if it is (eg) a const variable with known value. */ + size_varies = 1; + itype = variable_size (itype); + itype = build_index_type (itype); + } + resume_momentary (yes); + } + + /* Build the array type itself. + Merge any constancy or volatility into the target type. */ + + if (constp || volatilep) + type = build_type_variant (type, constp, volatilep); + + type = build_cplus_array_type (type, itype); + ctype = NULL_TREE; + } + break; + + case CALL_EXPR: + maybe_globalize_type (type); + { + tree arg_types; + + /* Declaring a function type. + Make sure we have a valid type for the function to return. */ +#if 0 + /* Is this an error? Should they be merged into TYPE here? */ + if (pedantic && (constp || volatilep)) + pedwarn ("function declared to return const or volatile result"); +#else + /* Merge any constancy or volatility into the target type + for the pointer. */ + + if (constp || volatilep) + { + type = build_type_variant (type, constp, volatilep); + if (IS_AGGR_TYPE (type)) + build_pointer_type (type); + constp = 0; + volatilep = 0; + } +#endif + + /* Warn about some types functions can't return. */ + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("`%s' declared as function returning a function", name); + type = integer_type_node; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + error ("`%s' declared as function returning an array", name); + type = integer_type_node; + } + + if (ctype == NULL_TREE + && decl_context == FIELD + && (friendp == 0 || dname == current_class_name)) + ctype = current_class_type; + + if (ctype && flags == TYPENAME_FLAG) + TYPE_HAS_CONVERSION (ctype) = 1; + if (ctype && constructor_name (ctype) == dname) + { + /* We are within a class's scope. If our declarator name + is the same as the class name, and we are defining + a function, then it is a constructor/destructor, and + therefore returns a void type. */ + + if (flags == DTOR_FLAG) + { + /* ANSI C++ June 5 1992 WP 12.4.1. A destructor may + not be declared const or volatile. A destructor + may not be static. */ + if (staticp == 2) + error ("destructor cannot be static member function"); + if (TYPE_READONLY (type)) + { + error ("destructors cannot be declared `const'"); + return void_type_node; + } + if (TYPE_VOLATILE (type)) + { + error ("destructors cannot be declared `volatile'"); + return void_type_node; + } + if (decl_context == FIELD) + { + if (! member_function_or_else (ctype, current_class_type, + "destructor for alien class `%s' cannot be a member")) + return void_type_node; + } + } + else /* it's a constructor. */ + { + /* ANSI C++ June 5 1992 WP 12.1.2. A constructor may + not be declared const or volatile. A constructor may + not be virtual. A constructor may not be static. */ + if (staticp == 2) + error ("constructor cannot be static member function"); + if (virtualp) + { + pedwarn ("constructors cannot be declared virtual"); + virtualp = 0; + } + if (TYPE_READONLY (type)) + { + error ("constructors cannot be declared `const'"); + return void_type_node; + } + if (TYPE_VOLATILE (type)) + { + error ("constructors cannot be declared `volatile'"); + return void_type_node; + } + if (specbits & ~(RIDBIT (RID_INLINE)|RIDBIT (RID_STATIC))) + error ("return value type specifier for constructor ignored"); + type = TYPE_POINTER_TO (ctype); + if (decl_context == FIELD) + { + if (! member_function_or_else (ctype, current_class_type, + "constructor for alien class `%s' cannot be member")) + return void_type_node; + TYPE_HAS_CONSTRUCTOR (ctype) = 1; + if (return_type != return_ctor) + return NULL_TREE; + } + } + if (decl_context == FIELD) + staticp = 0; + } + else if (friendp && virtualp) + { + /* Cannot be both friend and virtual. */ + error ("virtual functions cannot be friends"); + specbits &= ~ RIDBIT (RID_FRIEND); + } + + if (decl_context == NORMAL && friendp) + error ("friend declaration not in class definition"); + + /* Pick up type qualifiers which should be applied to `this'. */ + quals = TREE_OPERAND (declarator, 2); + + /* Traditionally, declaring return type float means double. */ + + if (flag_traditional + && TYPE_MAIN_VARIANT (type) == float_type_node) + { + type = build_type_variant (double_type_node, + TYPE_READONLY (type), + TYPE_VOLATILE (type)); + } + + /* Construct the function type and go to the next + inner layer of declarator. */ + + { + int funcdef_p; + tree inner_parms = TREE_OPERAND (declarator, 1); + tree inner_decl = TREE_OPERAND (declarator, 0); + + declarator = TREE_OPERAND (declarator, 0); + + if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF) + inner_decl = TREE_OPERAND (inner_decl, 1); + + /* Say it's a definition only for the CALL_EXPR + closest to the identifier. */ + funcdef_p = + (inner_decl && + (TREE_CODE (inner_decl) == IDENTIFIER_NODE + || TREE_CODE (inner_decl) == TYPE_EXPR)) ? funcdef_flag : 0; + + arg_types = grokparms (inner_parms, funcdef_p); + } + + if (declarator) + { + /* Get past destructors, etc. + We know we have one because FLAGS will be non-zero. + + Complain about improper parameter lists here. */ + if (TREE_CODE (declarator) == BIT_NOT_EXPR) + { + declarator = TREE_OPERAND (declarator, 0); + + if (strict_prototype == 0 && arg_types == NULL_TREE) + arg_types = void_list_node; + else if (arg_types == NULL_TREE + || arg_types != void_list_node) + { + error ("destructors cannot be specified with parameters"); + arg_types = void_list_node; + } + } + } + /* the top level const or volatile is attached semantically only + to the function not the actual type. */ + if (TYPE_READONLY (type) || TYPE_VOLATILE (type)) + { + int constp = TYPE_READONLY (type); + int volatilep = TYPE_VOLATILE (type); + type = build_function_type (TYPE_MAIN_VARIANT (type), + flag_traditional + ? 0 + : arg_types); + type = build_type_variant (type, constp, volatilep); + } + else + type = build_function_type (type, + flag_traditional + ? 0 + : arg_types); + } + break; + + case ADDR_EXPR: + case INDIRECT_REF: + maybe_globalize_type (type); + + /* Filter out pointers-to-references and references-to-references. + We can get these if a TYPE_DECL is used. */ + + if (TREE_CODE (type) == REFERENCE_TYPE) + { + error ("cannot declare %s to references", + TREE_CODE (declarator) == ADDR_EXPR + ? "references" : "pointers"); + declarator = TREE_OPERAND (declarator, 0); + continue; + } + + /* Merge any constancy or volatility into the target type + for the pointer. */ + + if (constp || volatilep) + { + type = build_type_variant (type, constp, volatilep); + if (IS_AGGR_TYPE (type)) + build_pointer_type (type); + constp = 0; + volatilep = 0; + } + + if (TREE_CODE (declarator) == ADDR_EXPR) + { + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("cannot declare references to functions; use pointer to function instead"); + type = build_pointer_type (type); + } + else + { + if (TYPE_MAIN_VARIANT (type) == void_type_node) + error ("invalid type: `void &'"); + else + type = build_reference_type (type); + } + } + else + type = build_pointer_type (type); + + /* Process a list of type modifier keywords (such as + const or volatile) that were given inside the `*' or `&'. */ + + if (TREE_TYPE (declarator)) + { + register tree typemodlist; + int erred = 0; + for (typemodlist = TREE_TYPE (declarator); typemodlist; + typemodlist = TREE_CHAIN (typemodlist)) + { + if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_CONST]) + constp++; + else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_VOLATILE]) + volatilep++; + else if (!erred) + { + erred = 1; + error ("invalid type modifier within %s declarator", + TREE_CODE (declarator) == ADDR_EXPR + ? "reference" : "pointer"); + } + } + if (constp > 1) + warning ("duplicate `const'"); + if (volatilep > 1) + warning ("duplicate `volatile'"); + } + declarator = TREE_OPERAND (declarator, 0); + ctype = NULL_TREE; + break; + + case SCOPE_REF: + { + /* We have converted type names to NULL_TREE if the + name was bogus, or to a _TYPE node, if not. + + The variable CTYPE holds the type we will ultimately + resolve to. The code here just needs to build + up appropriate member types. */ + tree sname = TREE_OPERAND (declarator, 1); + /* Destructors can have their visibilities changed as well. */ + if (TREE_CODE (sname) == BIT_NOT_EXPR) + sname = TREE_OPERAND (sname, 0); + + if (TREE_COMPLEXITY (declarator) == 0) + /* This needs to be here, in case we are called + multiple times. */ ; + else if (friendp && (TREE_COMPLEXITY (declarator) < 2)) + /* don't fall out into global scope. Hides real bug? --eichin */ ; + else if (TREE_COMPLEXITY (declarator) == current_class_depth) + { + TREE_COMPLEXITY (declarator) -= 1; + /* This popclass conflicts with the poplevel over in + grokdeclarator. See ``This poplevel conflicts'' */ + popclass (1); + } + else + my_friendly_abort (16); + + if (TREE_OPERAND (declarator, 0) == NULL_TREE) + { + /* We had a reference to a global decl, or + perhaps we were given a non-aggregate typedef, + in which case we cleared this out, and should just + keep going as though it wasn't there. */ + declarator = sname; + continue; + } + ctype = TREE_OPERAND (declarator, 0); + + if (sname == NULL_TREE) + goto done_scoping; + + if (TREE_CODE (sname) == IDENTIFIER_NODE) + { + /* This is the `standard' use of the scoping operator: + basetype :: member . */ + + if (TYPE_MAIN_VARIANT (ctype) == current_class_type || friendp) + { + if (TREE_CODE (type) == FUNCTION_TYPE) + type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), + TREE_TYPE (type), TYPE_ARG_TYPES (type)); + else + { + if (TYPE_MAIN_VARIANT (ctype) != current_class_type) + { + error ("cannot declare member `%s::%s' within this class", + TYPE_NAME_STRING (ctype), name); + return void_type_node; + } + else if (extra_warnings) + warning ("extra qualification `%s' on member `%s' ignored", + TYPE_NAME_STRING (ctype), name); + type = build_offset_type (ctype, type); + } + } + else if (TYPE_SIZE (ctype) != NULL_TREE + || (specbits & RIDBIT (RID_TYPEDEF))) + { + tree t; + /* have to move this code elsewhere in this function. + this code is used for i.e., typedef int A::M; M *pm; */ + + if (explicit_int == -1 && decl_context == FIELD + && funcdef_flag == 0) + { + /* The code in here should only be used to build + stuff that will be grokked as visibility decls. */ + t = lookup_field (ctype, sname, 0, 0); + if (t) + { + t = build_lang_field_decl (FIELD_DECL, build_nt (SCOPE_REF, ctype, t), type); + DECL_INITIAL (t) = init; + return t; + } + /* No such field, try member functions. */ + t = lookup_fnfields (TYPE_BINFO (ctype), sname, 0); + if (t) + { + if (flags == DTOR_FLAG) + t = TREE_VALUE (t); + else if (CLASSTYPE_METHOD_VEC (ctype) + && TREE_VALUE (t) == TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (ctype), 0)) + { + /* Don't include destructor with constructors. */ + t = DECL_CHAIN (TREE_VALUE (t)); + if (t == NULL_TREE) + error ("class `%s' does not have any constructors", IDENTIFIER_POINTER (sname)); + t = build_tree_list (NULL_TREE, t); + } + t = build_lang_field_decl (FIELD_DECL, build_nt (SCOPE_REF, ctype, t), type); + DECL_INITIAL (t) = init; + return t; + } + + if (flags == TYPENAME_FLAG) + error_with_aggr_type (ctype, "type conversion is not a member of structure `%s'"); + else + error ("field `%s' is not a member of structure `%s'", + IDENTIFIER_POINTER (sname), + TYPE_NAME_STRING (ctype)); + } + if (TREE_CODE (type) == FUNCTION_TYPE) + type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), + TREE_TYPE (type), TYPE_ARG_TYPES (type)); + else + { + if (current_class_type) + { + if (TYPE_MAIN_VARIANT (ctype) != current_class_type) + { + error ("cannot declare member `%s::%s' within this class", + TYPE_NAME_STRING (ctype), name); + return void_type_node; + } + else if (extra_warnings) + warning ("extra qualification `%s' on member `%s' ignored", + TYPE_NAME_STRING (ctype), name); + } + type = build_offset_type (ctype, type); + } + } + else if (uses_template_parms (ctype)) + { + enum tree_code c; + if (TREE_CODE (type) == FUNCTION_TYPE) + { + type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), + TREE_TYPE (type), + TYPE_ARG_TYPES (type)); + c = FUNCTION_DECL; + } + } + else + sorry ("structure `%s' not yet defined", + TYPE_NAME_STRING (ctype)); + declarator = sname; + } + else if (TREE_CODE (sname) == TYPE_EXPR) + { + /* A TYPE_EXPR will change types out from under us. + So do the TYPE_EXPR now, and make this SCOPE_REF + inner to the TYPE_EXPR's CALL_EXPR. + + This does not work if we don't get a CALL_EXPR back. + I did not think about error recovery, hence the + my_friendly_abort. */ + + /* Get the CALL_EXPR. */ + sname = grokoptypename (sname, 0); + my_friendly_assert (TREE_CODE (sname) == CALL_EXPR, 157); + type = TREE_TYPE (TREE_OPERAND (sname, 0)); + /* Scope the CALL_EXPR's name. */ + TREE_OPERAND (declarator, 1) = TREE_OPERAND (sname, 0); + /* Put the SCOPE_EXPR in the CALL_EXPR's innermost position. */ + TREE_OPERAND (sname, 0) = declarator; + /* Now work from the CALL_EXPR. */ + declarator = sname; + continue; + } + else if (TREE_CODE (sname) == SCOPE_REF) + my_friendly_abort (17); + else + { + done_scoping: + declarator = TREE_OPERAND (declarator, 1); + if (declarator && TREE_CODE (declarator) == CALL_EXPR) + /* In this case, we will deal with it later. */ + ; + else + { + if (TREE_CODE (type) == FUNCTION_TYPE) + type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), TREE_TYPE (type), TYPE_ARG_TYPES (type)); + else + type = build_offset_type (ctype, type); + } + } + } + break; + + case BIT_NOT_EXPR: + declarator = TREE_OPERAND (declarator, 0); + break; + + case TYPE_EXPR: + declarator = grokoptypename (declarator, 0); + if (explicit_int != -1) + if (comp_target_types (type, + TREE_TYPE (TREE_OPERAND (declarator, 0)), + 1) == 0) + error ("type conversion function declared to return incongruent type"); + else + pedwarn ("return type specified for type conversion function"); + type = TREE_TYPE (TREE_OPERAND (declarator, 0)); + maybe_globalize_type (type); + break; + + case RECORD_TYPE: + case UNION_TYPE: + case ENUMERAL_TYPE: + declarator = NULL_TREE; + break; + + case ERROR_MARK: + declarator = NULL_TREE; + break; + + default: + my_friendly_abort (158); + } + } + + /* Now TYPE has the actual type. */ + + /* If this is declaring a typedef name, return a TYPE_DECL. */ + + if (specbits & RIDBIT (RID_TYPEDEF)) + { + tree decl; + + /* Note that the grammar rejects storage classes + in typenames, fields or parameters. */ + if (constp || volatilep) + type = build_type_variant (type, constp, volatilep); + + /* If the user declares "struct {...} foo" then `foo' will have + an anonymous name. Fill that name in now. Nothing can + refer to it, so nothing needs know about the name change. + The TYPE_NAME field was filled in by build_struct_xref. */ + if (TYPE_NAME (type) + && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && ANON_AGGRNAME_P (TYPE_IDENTIFIER (type))) + { + /* replace the anonymous name with the real name everywhere. */ + lookup_tag_reverse (type, declarator); + TYPE_IDENTIFIER (type) = declarator; + } + +#if 0 /* not yet, should get fixed properly later */ + decl = make_type_decl (declarator, type); +#else + decl = build_decl (TYPE_DECL, declarator, type); +#endif + if (quals) + { + if (ctype == NULL_TREE) + { + if (TREE_CODE (type) != METHOD_TYPE) + error_with_decl (decl, "invalid type qualifier for non-method type"); + else + ctype = TYPE_METHOD_BASETYPE (type); + } + if (ctype != NULL_TREE) + grok_method_quals (ctype, decl, quals); + } + + if ((specbits & RIDBIT (RID_SIGNED)) + || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) + C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; + + return decl; + } + + /* Detect the case of an array type of unspecified size + which came, as such, direct from a typedef name. + We must copy the type, so that each identifier gets + a distinct type, so that each identifier's size can be + controlled separately by its own initializer. */ + + if (type == typedef_type && TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) == NULL_TREE) + { + type = build_cplus_array_type (TREE_TYPE (type), TYPE_DOMAIN (type)); + } + + /* If this is a type name (such as, in a cast or sizeof), + compute the type and return it now. */ + + if (decl_context == TYPENAME) + { + /* Note that the grammar rejects storage classes + in typenames, fields or parameters. */ + if (constp || volatilep) + type = build_type_variant (type, constp, volatilep); + + /* Special case: "friend class foo" looks like a TYPENAME context. */ + if (friendp) + { + /* A friendly class? */ + if (current_class_type) + make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type)); + else + error("trying to make class `%s' a friend of global scope", + TYPE_NAME_STRING (type)); + type = void_type_node; + } + else if (quals) + { +#if 0 /* not yet, should get fixed properly later */ + tree dummy = make_type_decl (declarator, type); +#else + tree dummy = build_decl (TYPE_DECL, declarator, type); +#endif + if (ctype == NULL_TREE) + { + my_friendly_assert (TREE_CODE (type) == METHOD_TYPE, 159); + ctype = TYPE_METHOD_BASETYPE (type); + } + grok_method_quals (ctype, dummy, quals); + type = TREE_TYPE (dummy); + } + + return type; + } + + /* `void' at top level (not within pointer) + is allowed only in typedefs or type names. + We don't complain about parms either, but that is because + a better error message can be made later. */ + + if (TYPE_MAIN_VARIANT (type) == void_type_node && decl_context != PARM) + { + if (declarator != NULL_TREE + && TREE_CODE (declarator) == IDENTIFIER_NODE) + { + if (IDENTIFIER_OPNAME_P (declarator)) + error ("operator `%s' declared void", + operator_name_string (declarator)); + else + error ("variable or field `%s' declared void", name); + } + else + error ("variable or field declared void"); + type = integer_type_node; + } + + /* Now create the decl, which may be a VAR_DECL, a PARM_DECL + or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ + + { + register tree decl; + + if (decl_context == PARM) + { + tree parmtype = type; + + if (ctype) + error ("cannot use `::' in parameter declaration"); + bad_specifiers ("parameter", virtualp, quals != NULL_TREE, + friendp, raises != NULL_TREE); + + /* A parameter declared as an array of T is really a pointer to T. + One declared as a function is really a pointer to a function. + One declared as a member is really a pointer to member. + + Don't be misled by references. */ + + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (parmtype == type) + { + /* Transfer const-ness of array into that of type + pointed to. */ + type = build_pointer_type + (build_type_variant (TREE_TYPE (type), constp, volatilep)); + volatilep = constp = 0; + } + else + type = build_pointer_type (TREE_TYPE (type)); + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + type = build_pointer_type (type); + else if (TREE_CODE (type) == OFFSET_TYPE) + type = build_pointer_type (type); + + if (TREE_CODE (parmtype) == REFERENCE_TYPE) + { + /* Transfer const-ness of reference into that of type pointed to. */ + type = build_type_variant (build_reference_type (type), constp, volatilep); + constp = volatilep = 0; + } + + decl = build_decl (PARM_DECL, declarator, type); + + /* Compute the type actually passed in the parmlist, + for the case where there is no prototype. + (For example, shorts and chars are passed as ints.) + When there is a prototype, this is overridden later. */ + + DECL_ARG_TYPE (decl) = type; + if (TYPE_MAIN_VARIANT (type) == float_type_node) + DECL_ARG_TYPE (decl) = build_type_variant (double_type_node, + TYPE_READONLY (type), + TYPE_VOLATILE (type)); + else if (C_PROMOTING_INTEGER_TYPE_P (type)) + { + tree argtype; + + /* Retain unsignedness if traditional or if not really + getting wider. */ + if (TREE_UNSIGNED (type) + && (flag_traditional + || TYPE_PRECISION (type) + == TYPE_PRECISION (integer_type_node))) + argtype = unsigned_type_node; + else + argtype = integer_type_node; + DECL_ARG_TYPE (decl) = build_type_variant (argtype, + TYPE_READONLY (type), + TYPE_VOLATILE (type)); + } + } + else if (decl_context == FIELD) + { + if (type == error_mark_node) + { + /* Happens when declaring arrays of sizes which + are error_mark_node, for example. */ + decl = NULL_TREE; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + int publicp = 0; + + if (friendp == 0) + { + if (ctype == NULL_TREE) + ctype = current_class_type; + + if (ctype == NULL_TREE) + { + register int op = IDENTIFIER_OPNAME_P (declarator); + error ("can't make %s `%s' into a method -- not in a class", + op ? "operator" : "function", + op ? operator_name_string (declarator) : IDENTIFIER_POINTER (declarator)); + return void_type_node; + } + + /* ``A union may [ ... ] not [ have ] virtual functions.'' + ARM 9.5 */ + if (virtualp && TREE_CODE (ctype) == UNION_TYPE) + { + error ("function `%s' declared virtual inside a union", + IDENTIFIER_POINTER (declarator)); + return void_type_node; + } + + /* Don't convert type of operators new and delete to + METHOD_TYPE; they remain FUNCTION_TYPEs. */ + if (staticp < 2 + && declarator != ansi_opname[(int) NEW_EXPR] + && declarator != ansi_opname[(int) DELETE_EXPR]) + type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), + TREE_TYPE (type), TYPE_ARG_TYPES (type)); + } + + /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */ + publicp = ((specbits & RIDBIT (RID_EXTERN)) + || (ctype != NULL_TREE && funcdef_flag >= 0) +#if 0 + /* These are replicated in each object, so we shouldn't + set TREE_PUBLIC. */ + || (friendp + && !(specbits & RIDBIT (RID_STATIC)) + && !(specbits & RIDBIT (RID_INLINE))) +#endif + ); + decl = grokfndecl (ctype, type, declarator, + virtualp, flags, quals, + raises, friendp ? -1 : 0, publicp); + DECL_INLINE (decl) = inlinep; + } + else if (TREE_CODE (type) == METHOD_TYPE) + { + /* 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); + DECL_INLINE (decl) = inlinep; + } + else if (TREE_CODE (type) == RECORD_TYPE + && CLASSTYPE_DECLARED_EXCEPTION (type)) + { + /* Handle a class-local exception declaration. */ + decl = build_lang_field_decl (VAR_DECL, declarator, type); + if (ctype == NULL_TREE) + ctype = current_class_type; + finish_exception_decl (TREE_CODE (TYPE_NAME (ctype)) == TYPE_DECL + ? TYPE_IDENTIFIER (ctype) : TYPE_NAME (ctype), decl); + return void_type_node; + } + else if (TYPE_SIZE (type) == NULL_TREE && !staticp + && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0)) + { + if (declarator) + error ("field `%s' has incomplete type", + IDENTIFIER_POINTER (declarator)); + else + error ("field has incomplete type"); + + /* If we're instantiating a template, tell them which + instantiation made the field's type be incomplete. */ + if (current_class_type + && IDENTIFIER_TEMPLATE (current_class_type) + && declspecs && TREE_VALUE (declspecs) + && TREE_TYPE (TREE_VALUE (declspecs)) == type) + error (" in instantiation of template `%s'", + TYPE_NAME_STRING (current_class_type)); + + type = error_mark_node; + decl = NULL_TREE; + } + else + { + if (friendp) + { + if (declarator) + error ("`%s' is neither function nor method; cannot be declared friend", + IDENTIFIER_POINTER (declarator)); + else + { + error ("invalid friend declaration"); + return void_type_node; + } + friendp = 0; + } + decl = NULL_TREE; + } + + if (friendp) + { + tree t; + + /* Friends are treated specially. */ + if (ctype == current_class_type) + warning ("member functions are implicitly friends of their class"); + else if (decl && (t = DECL_NAME (decl))) + { + /* ARM $13.4.3 */ + if (t == ansi_opname[(int) MODIFY_EXPR]) + pedwarn ("operator `=' must be a member function"); + else + return do_friend (ctype, declarator, decl, + last_function_parms, flags, quals); + } + else return void_type_node; + } + + /* Structure field. It may not be a function, except for C++ */ + + if (decl == NULL_TREE) + { + bad_specifiers ("field", virtualp, quals != NULL_TREE, + friendp, raises != NULL_TREE); + + /* ANSI C++ June 5 1992 WP 9.2.2 and 9.4.2. A member-declarator + cannot have an initializer, and a static member declaration must + be defined elsewhere. */ + if (initialized) + { + if (staticp) + error ("static member `%s' must be defined separately from its declaration", + IDENTIFIER_POINTER (declarator)); + /* Note that initialization of const members is not + mentioned in the ARM or draft ANSI standard explicitly, + and it appears to be in common practice. However, + reading the draft section 9.2.2, it does say that a + member declarator can't have an initializer--it does + not except constant members, which also qualify as + member-declarators. */ + else if (!pedantic && (!constp || flag_ansi)) + warning ("ANSI C++ forbids initialization of %s `%s'", + constp ? "const member" : "member", + IDENTIFIER_POINTER (declarator)); + } + + if (staticp || (constp && initialized)) + { + /* C++ allows static class members. + All other work for this is done by grokfield. + This VAR_DECL is built by build_lang_field_decl. + All other VAR_DECLs are built by build_decl. */ + decl = build_lang_field_decl (VAR_DECL, declarator, type); + if (staticp || TREE_CODE (type) == ARRAY_TYPE) + TREE_STATIC (decl) = 1; + /* In class context, static means public visibility. */ + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = !initialized; + } + else + decl = build_lang_field_decl (FIELD_DECL, declarator, type); + } + } + else if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) + { + int was_overloaded = 0; + tree original_name = declarator; + int publicp = 0; + + if (! declarator) return NULL_TREE; + + if (specbits & (RIDBIT (RID_AUTO) | RIDBIT (RID_REGISTER))) + error ("invalid storage class for function `%s'", name); + /* Function declaration not at top level. + Storage classes other than `extern' are not allowed + and `extern' makes no difference. */ + if (current_binding_level != global_binding_level + && (specbits & (RIDBIT (RID_STATIC) | RIDBIT (RID_INLINE))) + && pedantic) + pedwarn ("invalid storage class for function `%s'", name); + + if (ctype == NULL_TREE) + { + if (virtualp) + { + error ("virtual non-class function `%s'", name); + virtualp = 0; + } + + /* ARM $13.4.3 */ + /* XXX: It's likely others should also be forbidden. (bpk) */ + if (declarator == ansi_opname[(int) MODIFY_EXPR]) + warning ("operator `=' must be a member function"); + + if (current_lang_name == lang_name_cplusplus + && ! (IDENTIFIER_LENGTH (original_name) == 4 + && IDENTIFIER_POINTER (original_name)[0] == 'm' + && strcmp (IDENTIFIER_POINTER (original_name), "main") == 0) + && ! (IDENTIFIER_LENGTH (original_name) > 10 + && IDENTIFIER_POINTER (original_name)[0] == '_' + && IDENTIFIER_POINTER (original_name)[1] == '_' + && strncmp (IDENTIFIER_POINTER (original_name)+2, "builtin_", 8) == 0)) + { + /* Plain overloading: will not be grok'd by grokclassfn. */ + declarator = build_decl_overload (dname, TYPE_ARG_TYPES (type), 0); + was_overloaded = 1; + } + } + else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2) + type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), + TREE_TYPE (type), TYPE_ARG_TYPES (type)); + + /* Record presence of `static'. In C++, `inline' is like `static'. + Methods of classes should be public, unless we're dropping them + into some other file, so we don't clear TREE_PUBLIC for them. */ + publicp + = ((ctype + && ! CLASSTYPE_INTERFACE_UNKNOWN (ctype) + && ! CLASSTYPE_INTERFACE_ONLY (ctype)) + || !(specbits & (RIDBIT (RID_STATIC) + | RIDBIT (RID_INLINE)))); + + decl = grokfndecl (ctype, type, original_name, + virtualp, flags, quals, + raises, + processing_template_decl ? 0 : friendp ? 2 : 1, + publicp); + + if (ctype == NULL_TREE) + DECL_ASSEMBLER_NAME (decl) = declarator; + + if (staticp == 1) + { + int illegal_static = 0; + + /* Don't allow a static member function in a class, and forbid + declaring main to be static. */ + if (TREE_CODE (type) == METHOD_TYPE) + { + error_with_decl (decl, + "cannot declare member function `%s' to have static linkage"); + illegal_static = 1; + } + else if (! was_overloaded + && ! ctype + && IDENTIFIER_LENGTH (original_name) == 4 + && IDENTIFIER_POINTER (original_name)[0] == 'm' + && ! strcmp (IDENTIFIER_POINTER (original_name), "main")) + { + error ("cannot declare function `main' to have static linkage"); + illegal_static = 1; + } + + if (illegal_static) + { + staticp = 0; + specbits &= ~ RIDBIT (RID_STATIC); + } + } + + /* Record presence of `inline', if it is reasonable. */ + if (inlinep) + { + tree last = tree_last (TYPE_ARG_TYPES (type)); + + if (! was_overloaded + && ! ctype + && ! strcmp (IDENTIFIER_POINTER (original_name), "main")) + warning ("cannot inline function `main'"); + else if (last && last != void_list_node) + warning ("inline declaration ignored for function with `...'"); + else + /* Assume that otherwise the function can be inlined. */ + DECL_INLINE (decl) = 1; + + if (specbits & RIDBIT (RID_EXTERN)) + { + current_extern_inline = 1; + if (pedantic) + error ("ANSI C++ does not permit `extern inline'"); + else if (flag_ansi) + warning ("ANSI C++ does not permit `extern inline'"); + } + } + if (was_overloaded) + DECL_OVERLOADED (decl) = 1; + } + else + { + /* It's a variable. */ + + bad_specifiers ("variable", virtualp, quals != NULL_TREE, + friendp, raises != NULL_TREE); + if (inlinep) + warning ("variable declared `inline'"); + + /* An uninitialized decl with `extern' is a reference. */ + decl = grokvardecl (type, declarator, specbits, initialized); + if (ctype) + { + if (staticp == 1) + { + error ("cannot declare member `%s' to have static linkage", + lang_printable_name (decl)); + staticp = 0; + specbits &= ~ RIDBIT (RID_STATIC); + } + if (specbits & RIDBIT (RID_EXTERN)) + { + error ("cannot explicitly declare member `%s' to have extern linkage", + lang_printable_name (decl)); + specbits &= ~ RIDBIT (RID_EXTERN); + } + } + } + + /* Record `register' declaration for warnings on & + and in case doing stupid register allocation. */ + + if (specbits & RIDBIT (RID_REGISTER)) + DECL_REGISTER (decl) = 1; + + /* Record constancy and volatility. */ + + if (constp) + TREE_READONLY (decl) = TREE_CODE (type) != REFERENCE_TYPE; + if (volatilep) + { + TREE_SIDE_EFFECTS (decl) = 1; + TREE_THIS_VOLATILE (decl) = 1; + } + + return decl; + } +} + +/* Tell if a parmlist/exprlist looks like an exprlist or a parmlist. + An empty exprlist is a parmlist. An exprlist which + contains only identifiers at the global level + is a parmlist. Otherwise, it is an exprlist. */ +int +parmlist_is_exprlist (exprs) + tree exprs; +{ + if (exprs == NULL_TREE || TREE_PARMLIST (exprs)) + return 0; + + if (current_binding_level == global_binding_level) + { + /* At the global level, if these are all identifiers, + then it is a parmlist. */ + while (exprs) + { + if (TREE_CODE (TREE_VALUE (exprs)) != IDENTIFIER_NODE) + return 1; + exprs = TREE_CHAIN (exprs); + } + return 0; + } + return 1; +} + +/* Make sure that the this list of PARMS has a chance of being + grokked by `grokparms'. + + @@ This is really weak, but the grammar does not allow us + @@ to easily reject things that this has to catch as syntax errors. */ +static int +parmlist_is_random (parms) + tree parms; +{ + if (parms == NULL_TREE) + return 0; + + if (TREE_CODE (parms) != TREE_LIST) + return 1; + + while (parms) + { + if (parms == void_list_node) + return 0; + + if (TREE_CODE (TREE_VALUE (parms)) != TREE_LIST) + return 1; + /* Don't get faked out by overloaded functions, which + masquerade as TREE_LISTs! */ + if (TREE_TYPE (TREE_VALUE (parms)) == unknown_type_node) + return 1; + parms = TREE_CHAIN (parms); + } + return 0; +} + +/* Subroutine of `grokparms'. In a fcn definition, arg types must + be complete. + + C++: also subroutine of `start_function'. */ +static void +require_complete_types_for_parms (parms) + tree parms; +{ + while (parms) + { + tree type = TREE_TYPE (parms); + if (TYPE_SIZE (type) == NULL_TREE) + { + if (DECL_NAME (parms)) + error ("parameter `%s' has incomplete type", + IDENTIFIER_POINTER (DECL_NAME (parms))); + else + error ("parameter has incomplete type"); + TREE_TYPE (parms) = error_mark_node; + } +#if 0 + /* If the arg types are incomplete in a declaration, + they must include undefined tags. + These tags can never be defined in the scope of the declaration, + so the types can never be completed, + and no call can be compiled successfully. */ + /* This is not the right behavior for C++, but not having + it is also probably wrong. */ + else + { + /* Now warn if is a pointer to an incomplete type. */ + while (TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + type = TYPE_MAIN_VARIANT (type); + if (TYPE_SIZE (type) == NULL_TREE) + { + if (DECL_NAME (parm) != NULL_TREE) + warning ("parameter `%s' points to incomplete type", + IDENTIFIER_POINTER (DECL_NAME (parm))); + else + warning ("parameter points to incomplete type"); + } + } +#endif + parms = TREE_CHAIN (parms); + } +} + +/* Decode the list of parameter types for a function type. + Given the list of things declared inside the parens, + return a list of types. + + The list we receive can have three kinds of elements: + an IDENTIFIER_NODE for names given without types, + a TREE_LIST node for arguments given as typespecs or names with typespecs, + or void_type_node, to mark the end of an argument list + when additional arguments are not permitted (... was not used). + + FUNCDEF_FLAG is nonzero for a function definition, 0 for + a mere declaration. A nonempty identifier-list gets an error message + when FUNCDEF_FLAG is zero. + If FUNCDEF_FLAG is 1, then parameter types must be complete. + If FUNCDEF_FLAG is -1, then parameter types may be incomplete. + + If all elements of the input list contain types, + we return a list of the types. + If all elements contain no type (except perhaps a void_type_node + at the end), we return a null list. + If some have types and some do not, it is an error, and we + return a null list. + + Also set last_function_parms to either + a list of names (IDENTIFIER_NODEs) or a chain of PARM_DECLs. + A list of names is converted to a chain of PARM_DECLs + by store_parm_decls so that ultimately it is always a chain of decls. + + Note that in C++, parameters can take default values. These default + values are in the TREE_PURPOSE field of the TREE_LIST. It is + an error to specify default values which are followed by parameters + that have no default values, or an ELLIPSES. For simplicities sake, + only parameters which are specified with their types can take on + default values. */ + +static tree +grokparms (first_parm, funcdef_flag) + tree first_parm; + int funcdef_flag; +{ + tree result = NULL_TREE; + tree decls = NULL_TREE; + + if (first_parm != NULL_TREE + && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE) + { + if (! funcdef_flag) + warning ("parameter names (without types) in function declaration"); + last_function_parms = first_parm; + return NULL_TREE; + } + else + { + /* Types were specified. This is a list of declarators + each represented as a TREE_LIST node. */ + register tree parm, chain; + int any_init = 0, any_error = 0, saw_void = 0; + + if (first_parm != NULL_TREE) + { + tree last_result = NULL_TREE; + tree last_decl = NULL_TREE; + + for (parm = first_parm; parm != NULL_TREE; parm = chain) + { + tree type, list_node = parm; + register tree decl = TREE_VALUE (parm); + tree init = TREE_PURPOSE (parm); + + chain = TREE_CHAIN (parm); + /* @@ weak defense against parse errors. */ + if (decl != void_type_node && TREE_CODE (decl) != TREE_LIST) + { + /* Give various messages as the need arises. */ + if (TREE_CODE (decl) == STRING_CST) + error ("invalid string constant `%s'", + TREE_STRING_POINTER (decl)); + else if (TREE_CODE (decl) == INTEGER_CST) + error ("invalid integer constant in parameter list, did you forget to give parameter name?"); + continue; + } + + if (decl != void_type_node) + { + /* @@ May need to fetch out a `raises' here. */ + decl = grokdeclarator (TREE_VALUE (decl), + TREE_PURPOSE (decl), + PARM, init != NULL_TREE, NULL_TREE); + if (! decl) + continue; + type = TREE_TYPE (decl); + if (TYPE_MAIN_VARIANT (type) == void_type_node) + decl = void_type_node; + else if (TREE_CODE (type) == METHOD_TYPE) + { + if (DECL_NAME (decl)) + /* Cannot use `error_with_decl' here because + we don't have DECL_CONTEXT set up yet. */ + error ("parameter `%s' invalidly declared method type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + else + error ("parameter invalidly declared method type"); + type = build_pointer_type (type); + TREE_TYPE (decl) = type; + } + else if (TREE_CODE (type) == OFFSET_TYPE) + { + if (DECL_NAME (decl)) + error ("parameter `%s' invalidly declared offset type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + else + error ("parameter invalidly declared offset type"); + type = build_pointer_type (type); + TREE_TYPE (decl) = type; + } + else if (TREE_CODE (type) == RECORD_TYPE + && TYPE_LANG_SPECIFIC (type) + && CLASSTYPE_ABSTRACT_VIRTUALS (type)) + { + abstract_virtuals_error (decl, type); + any_error = 1; /* seems like a good idea */ + } + } + + if (decl == void_type_node) + { + if (result == NULL_TREE) + { + result = void_list_node; + last_result = result; + } + else + { + TREE_CHAIN (last_result) = void_list_node; + last_result = void_list_node; + } + saw_void = 1; + if (chain + && (chain != void_list_node || TREE_CHAIN (chain))) + error ("`void' in parameter list must be entire list"); + break; + } + + /* Since there is a prototype, args are passed in their own types. */ + DECL_ARG_TYPE (decl) = TREE_TYPE (decl); +#ifdef PROMOTE_PROTOTYPES + if (C_PROMOTING_INTEGER_TYPE_P (type)) + DECL_ARG_TYPE (decl) = integer_type_node; +#endif + if (!any_error) + { + if (init) + { + any_init++; + if (TREE_CODE (init) == SAVE_EXPR) + PARM_DECL_EXPR (init) = 1; + else if (TREE_CODE (init) == VAR_DECL) + { + if (IDENTIFIER_LOCAL_VALUE (DECL_NAME (init))) + { + /* ``Local variables may not be used in default + argument expressions.'' dpANSI C++ 8.2.6 */ + /* If extern int i; within a function is not + considered a local variable, then this code is + wrong. */ + error_with_decl (init, "local variable `%s' may not be used as a default argument"); + any_error = 1; + } + else if (TREE_READONLY_DECL_P (init)) + init = decl_constant_value (init); + } + else + init = require_instantiated_type (type, init, integer_zero_node); + } + else if (any_init) + { + error ("all trailing parameters must have default arguments"); + any_error = 1; + } + } + else + init = NULL_TREE; + + if (decls == NULL_TREE) + { + decls = decl; + last_decl = decls; + } + else + { + TREE_CHAIN (last_decl) = decl; + last_decl = decl; + } + if (TREE_PERMANENT (list_node)) + { + TREE_PURPOSE (list_node) = init; + TREE_VALUE (list_node) = type; + TREE_CHAIN (list_node) = NULL_TREE; + } + else + list_node = saveable_tree_cons (init, type, NULL_TREE); + if (result == NULL_TREE) + { + result = list_node; + last_result = result; + } + else + { + TREE_CHAIN (last_result) = list_node; + last_result = list_node; + } + } + if (last_result) + TREE_CHAIN (last_result) = NULL_TREE; + /* If there are no parameters, and the function does not end + with `...', then last_decl will be NULL_TREE. */ + if (last_decl != NULL_TREE) + TREE_CHAIN (last_decl) = NULL_TREE; + } + } + + last_function_parms = decls; + + /* In a fcn definition, arg types must be complete. */ + if (funcdef_flag > 0) + require_complete_types_for_parms (last_function_parms); + + return result; +} + +/* These memoizing functions keep track of special properties which + a class may have. `grok_ctor_properties' notices whether a class + has a constructor of the for X(X&), and also complains + if the class has a constructor of the form X(X). + `grok_op_properties' takes notice of the various forms of + operator= which are defined, as well as what sorts of type conversion + may apply. Both functions take a FUNCTION_DECL as an argument. */ +void +grok_ctor_properties (ctype, decl) + tree ctype, decl; +{ + tree parmtypes = FUNCTION_ARG_CHAIN (decl); + tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node; + + if (parmtypes && TREE_CHAIN (parmtypes) + && TREE_CODE (TREE_VALUE (TREE_CHAIN (parmtypes))) == REFERENCE_TYPE + && TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (TREE_VALUE (TREE_CHAIN (parmtypes))))) + { + parmtypes = TREE_CHAIN (parmtypes); + parmtype = TREE_VALUE (parmtypes); + } + + if (TREE_CODE (parmtype) == REFERENCE_TYPE + && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype) + { + if (TREE_CHAIN (parmtypes) == NULL_TREE + || TREE_CHAIN (parmtypes) == void_list_node + || TREE_PURPOSE (TREE_CHAIN (parmtypes))) + { + TYPE_HAS_INIT_REF (ctype) = 1; + TYPE_GETS_INIT_REF (ctype) = 1; + if (TYPE_READONLY (TREE_TYPE (parmtype))) + TYPE_GETS_CONST_INIT_REF (ctype) = 1; + } + else + TYPE_GETS_INIT_AGGR (ctype) = 1; + } + else if (TYPE_MAIN_VARIANT (parmtype) == ctype) + { + if (TREE_CHAIN (parmtypes) != NULL_TREE + && TREE_CHAIN (parmtypes) == void_list_node) + error ("invalid constructor; you probably meant `%s (%s&)'", + TYPE_NAME_STRING (ctype), + TYPE_NAME_STRING (ctype)); + SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype); + TYPE_GETS_INIT_AGGR (ctype) = 1; + } + else if (TREE_CODE (parmtype) == VOID_TYPE + || TREE_PURPOSE (parmtypes) != NULL_TREE) + TYPE_HAS_DEFAULT_CONSTRUCTOR (ctype) = 1; +} + +/* Do a little sanity-checking on how they declared their operator. */ +static void +grok_op_properties (decl, virtualp) + tree decl; + int virtualp; +{ + tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); + + if (DECL_STATIC_FUNCTION_P (decl)) + { + if (DECL_NAME (decl) == ansi_opname[(int) NEW_EXPR]) + { + if (virtualp) + error ("`operator new' cannot be declared virtual"); + + /* Take care of function decl if we had syntax errors. */ + if (argtypes == NULL_TREE) + TREE_TYPE (decl) = + build_function_type (ptr_type_node, + hash_tree_chain (integer_type_node, + void_list_node)); + else + decl = coerce_new_type (TREE_TYPE (decl)); + } + else if (DECL_NAME (decl) == ansi_opname[(int) DELETE_EXPR]) + { + if (virtualp) + error ("`operator delete' cannot be declared virtual"); + + if (argtypes == NULL_TREE) + TREE_TYPE (decl) = + build_function_type (void_type_node, + hash_tree_chain (ptr_type_node, + void_list_node)); + else + decl = coerce_delete_type (TREE_TYPE (decl)); + } + else + error_with_decl (decl, "`%s' cannot be a static member function"); + } + else if (DECL_NAME (decl) == ansi_opname[(int) MODIFY_EXPR]) + { + tree parmtypes; + tree parmtype; + + if (argtypes == NULL_TREE) + { + error_with_decl (decl, "too few arguments to `%s'"); + return; + } + parmtypes = TREE_CHAIN (argtypes); + parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node; + + if (TREE_CODE (parmtype) == REFERENCE_TYPE + && TREE_TYPE (parmtype) == current_class_type) + { + TYPE_HAS_ASSIGN_REF (current_class_type) = 1; + TYPE_GETS_ASSIGN_REF (current_class_type) = 1; + if (TYPE_READONLY (TREE_TYPE (parmtype))) + TYPE_GETS_CONST_INIT_REF (current_class_type) = 1; + } + } +} + +/* Get the struct, enum or union (CODE says which) with tag NAME. + Define the tag as a forward-reference if it is not defined. + + C++: If a class derivation is given, process it here, and report + an error if multiple derivation declarations are not identical. + + If this is a definition, come in through xref_tag and only look in + the current frame for the name (since C++ allows new names in any + scope.) */ + +/* avoid rewriting all callers of xref_tag */ +static int xref_next_defn = 0; + +tree +xref_defn_tag (code_type_node, name, binfo) + tree code_type_node; + tree name, binfo; +{ + tree rv, ncp; + xref_next_defn = 1; + + if (class_binding_level) + { + tree n1; + char *buf; + /* we need to build a new IDENTIFIER_NODE for name which nukes + * the pieces... */ + n1 = IDENTIFIER_LOCAL_VALUE (current_class_name); + if (n1) + n1 = DECL_NAME (n1); + else + n1 = current_class_name; + + buf = (char *) alloca (4 + IDENTIFIER_LENGTH (n1) + + IDENTIFIER_LENGTH (name)); + + sprintf (buf, "%s::%s", IDENTIFIER_POINTER (n1), + IDENTIFIER_POINTER (name)); + ncp = get_identifier (buf); +#ifdef SPEW_DEBUG + if (spew_debug) + printf("*** %s ***\n", IDENTIFIER_POINTER (ncp)); +#endif +#if 0 + IDENTIFIER_LOCAL_VALUE (name) = + build_lang_decl (TYPE_DECL, ncp, NULL_TREE); +#endif + rv = xref_tag (code_type_node, name, binfo); + pushdecl_top_level (build_lang_decl (TYPE_DECL, ncp, rv)); + } + else + { + rv = xref_tag (code_type_node, name, binfo); + } + xref_next_defn = 0; + return rv; +} + +tree +xref_tag (code_type_node, name, binfo) + tree code_type_node; + tree name, binfo; +{ + enum tag_types tag_code; + enum tree_code code; + int temp = 0; + int i, len; + register tree ref; + struct binding_level *b + = (class_binding_level ? class_binding_level : current_binding_level); + + tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node); + switch (tag_code) + { + case record_type: + case class_type: + case exception_type: + code = RECORD_TYPE; + len = list_length (binfo); + break; + case union_type: + code = UNION_TYPE; + if (binfo) + { + error ("derived union `%s' invalid", IDENTIFIER_POINTER (name)); + binfo = NULL_TREE; + } + len = 0; + break; + case enum_type: + code = ENUMERAL_TYPE; + break; + default: + my_friendly_abort (18); + } + + /* If a cross reference is requested, look up the type + already defined for this tag and return it. */ + if (xref_next_defn) + { + /* If we know we are defining this tag, only look it up in this scope + * and don't try to find it as a type. */ + xref_next_defn = 0; + ref = lookup_tag (code, name, b, 1); + } + else + { + ref = lookup_tag (code, name, b, 0); + + if (! ref) + { + /* Try finding it as a type declaration. If that wins, use it. */ + ref = lookup_name (name, 1); + if (ref && TREE_CODE (ref) == TYPE_DECL + && TREE_CODE (TREE_TYPE (ref)) == code) + ref = TREE_TYPE (ref); + else + ref = NULL_TREE; + } + } + + 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) + { + ref = make_node (ENUMERAL_TYPE); + + /* Give the type a default layout like unsigned int + to avoid crashing if it does not get defined. */ + TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node); + TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node); + TREE_UNSIGNED (ref) = 1; + TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); + TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node); + TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); + + /* Enable us to recognize when a type is created in class context. + To do nested classes correctly, this should probably be cleared + out when we leave this classes scope. Currently this in only + done in `start_enum'. */ + + pushtag (name, ref); + if (flag_cadillac) + cadillac_start_enum (ref); + } + else if (tag_code == exception_type) + { + ref = make_lang_type (code); + /* Enable us to recognize when an exception type is created in + class context. To do nested classes correctly, this should + probably be cleared out when we leave this class's scope. */ + CLASSTYPE_DECLARED_EXCEPTION (ref) = 1; + pushtag (name, ref); + if (flag_cadillac) + cadillac_start_struct (ref); + } + else + { + extern tree pending_vtables; + struct binding_level *old_b = class_binding_level; + int needs_writing; + + ref = make_lang_type (code); + + /* Record how to set the visibility of this class's + virtual functions. If write_virtuals == 2 or 3, then + inline virtuals are ``extern inline''. */ + switch (write_virtuals) + { + case 0: + case 1: + needs_writing = 1; + break; + case 2: + needs_writing = !! value_member (name, pending_vtables); + break; + case 3: + needs_writing + = ! (CLASSTYPE_INTERFACE_ONLY (ref) || CLASSTYPE_INTERFACE_UNKNOWN (ref)); + break; + default: + needs_writing = 0; + } + + CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = needs_writing; + +#ifdef NONNESTED_CLASSES + /* Class types don't nest the way enums do. */ + class_binding_level = (struct binding_level *)0; +#endif + pushtag (name, ref); + class_binding_level = old_b; + + if (flag_cadillac) + cadillac_start_struct (ref); + } + } + else + { + if (IS_AGGR_TYPE_CODE (code)) + { + if (IS_AGGR_TYPE (ref) + && ((tag_code == exception_type) + != (CLASSTYPE_DECLARED_EXCEPTION (ref) == 1))) + { + error ("type `%s' is both exception and aggregate type", + IDENTIFIER_POINTER (name)); + CLASSTYPE_DECLARED_EXCEPTION (ref) = (tag_code == exception_type); + } + } + + /* If it no longer looks like a nested type, make sure it's + in global scope. */ + if (b == global_binding_level && !class_binding_level + && IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE) + IDENTIFIER_GLOBAL_VALUE (name) = TYPE_NAME (ref); + + if (binfo) + { + tree tt1 = binfo; + tree tt2 = TYPE_BINFO_BASETYPES (ref); + + if (TYPE_BINFO_BASETYPES (ref)) + for (i = 0; tt1; i++, tt1 = TREE_CHAIN (tt1)) + if (TREE_VALUE (tt1) != TYPE_IDENTIFIER (BINFO_TYPE (TREE_VEC_ELT (tt2, i)))) + { + error ("redeclaration of derivation chain of type `%s'", + IDENTIFIER_POINTER (name)); + break; + } + + if (tt1 == NULL_TREE) + /* The user told us something we already knew. */ + goto just_return; + + /* In C++, since these migrate into the global scope, we must + build them on the permanent obstack. */ + end_temporary_allocation (); + } + } + + if (binfo) + { + /* In the declaration `A : X, Y, ... Z' we mark all the types + (A, X, Y, ..., Z) so we can check for duplicates. */ + tree binfos; + + SET_CLASSTYPE_MARKED (ref); + BINFO_BASETYPES (TYPE_BINFO (ref)) = binfos = make_tree_vec (len); + + for (i = 0; binfo; binfo = TREE_CHAIN (binfo)) + { + /* The base of a derived struct is public. */ + int via_public = (tag_code != class_type + || TREE_PURPOSE (binfo) == (tree)visibility_public + || TREE_PURPOSE (binfo) == (tree)visibility_public_virtual); + int via_protected = TREE_PURPOSE (binfo) == (tree)visibility_protected; + int via_virtual = (TREE_PURPOSE (binfo) == (tree)visibility_private_virtual + || TREE_PURPOSE (binfo) == (tree)visibility_public_virtual + || TREE_PURPOSE (binfo) == (tree)visibility_default_virtual); + tree basetype = TREE_TYPE (TREE_VALUE (binfo)); + tree base_binfo; + + GNU_xref_hier (IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (TREE_VALUE (binfo)), + via_public, via_virtual, 0); + + if (basetype && TREE_CODE (basetype) == TYPE_DECL) + basetype = TREE_TYPE (basetype); + if (!basetype || TREE_CODE (basetype) != RECORD_TYPE) + { + error ("base type `%s' fails to be a struct or class type", + IDENTIFIER_POINTER (TREE_VALUE (binfo))); + continue; + } +#if 1 + /* This code replaces similar code in layout_basetypes. */ + else if (TYPE_SIZE (basetype) == NULL_TREE) + { + error_with_aggr_type (basetype, "base class `%s' has incomplete type"); + continue; + } +#endif + else + { + if (CLASSTYPE_MARKED (basetype)) + { + if (basetype == ref) + error_with_aggr_type (basetype, "recursive type `%s' undefined"); + else + error_with_aggr_type (basetype, "duplicate base type `%s' invalid"); + continue; + } + + /* Note that the BINFO records which describe individual + inheritances are *not* shared in the lattice! They + cannot be shared because a given baseclass may be + inherited with different `accessibility' by different + derived classes. (Each BINFO record describing an + individual inheritance contains flags which say what + the `accessibility' of that particular inheritance is.) */ + + base_binfo = make_binfo (integer_zero_node, basetype, + TYPE_BINFO_VTABLE (basetype), + TYPE_BINFO_VIRTUALS (basetype), 0); + + TREE_VEC_ELT (binfos, i) = base_binfo; + TREE_VIA_PUBLIC (base_binfo) = via_public; + TREE_VIA_PROTECTED (base_binfo) = via_protected; + TREE_VIA_VIRTUAL (base_binfo) = via_virtual; + + SET_CLASSTYPE_MARKED (basetype); +#if 0 +/* XYZZY TEST VIRTUAL BASECLASSES */ +if (CLASSTYPE_N_BASECLASSES (basetype) == NULL_TREE + && TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype) + && via_virtual == 0) + { + warning ("making type `%s' a virtual baseclass", + TYPE_NAME_STRING (basetype)); + via_virtual = 1; + } +#endif + /* We are free to modify these bits because they are meaningless + at top level, and BASETYPE is a top-level type. */ + if (via_virtual || TYPE_USES_VIRTUAL_BASECLASSES (basetype)) + { + TYPE_USES_VIRTUAL_BASECLASSES (ref) = 1; + TYPE_USES_COMPLEX_INHERITANCE (ref) = 1; + } + + TYPE_GETS_ASSIGNMENT (ref) |= TYPE_GETS_ASSIGNMENT (basetype); + TYPE_OVERLOADS_METHOD_CALL_EXPR (ref) |= TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype); + TREE_GETS_NEW (ref) |= TREE_GETS_NEW (basetype); + TREE_GETS_DELETE (ref) |= TREE_GETS_DELETE (basetype); + CLASSTYPE_LOCAL_TYPEDECLS (ref) |= CLASSTYPE_LOCAL_TYPEDECLS (basetype); + i += 1; + } + } + if (i) + TREE_VEC_LENGTH (binfos) = i; + else + BINFO_BASETYPES (TYPE_BINFO (ref)) = NULL_TREE; + + if (i > 1) + TYPE_USES_MULTIPLE_INHERITANCE (ref) = 1; + else if (i == 1) + TYPE_USES_MULTIPLE_INHERITANCE (ref) + = TYPE_USES_MULTIPLE_INHERITANCE (BINFO_TYPE (TREE_VEC_ELT (binfos, 0))); + if (TYPE_USES_MULTIPLE_INHERITANCE (ref)) + TYPE_USES_COMPLEX_INHERITANCE (ref) = 1; + + /* Unmark all the types. */ + while (--i >= 0) + CLEAR_CLASSTYPE_MARKED (BINFO_TYPE (TREE_VEC_ELT (binfos, i))); + CLEAR_CLASSTYPE_MARKED (ref); + } + + just_return: + + /* Until the type is defined, tentatively accept whatever + structure tag the user hands us. */ + if (TYPE_SIZE (ref) == NULL_TREE + && ref != current_class_type + /* Have to check this, in case we have contradictory tag info. */ + && IS_AGGR_TYPE_CODE (TREE_CODE (ref))) + { + if (tag_code == class_type) + CLASSTYPE_DECLARED_CLASS (ref) = 1; + else if (tag_code == record_type) + CLASSTYPE_DECLARED_CLASS (ref) = 0; + } + + pop_obstacks (); + + return ref; +} + +static tree current_local_enum = NULL_TREE; + +/* Begin compiling the definition of an enumeration type. + NAME is its name (or null if anonymous). + Returns the type object, as yet incomplete. + Also records info about it so that build_enumerator + may be used to declare the individual values as they are read. */ + +tree +start_enum (name) + tree name; +{ + register tree enumtype = NULL_TREE; + struct binding_level *b + = (class_binding_level ? class_binding_level : current_binding_level); + + /* 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. */ + + if (name != NULL_TREE) + enumtype = lookup_tag (ENUMERAL_TYPE, name, b, 1); + + if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE) + { + enumtype = make_node (ENUMERAL_TYPE); + pushtag (name, enumtype); + } + + if (current_class_type) + TREE_ADDRESSABLE (b->tags) = 1; + current_local_enum = NULL_TREE; + + if (TYPE_VALUES (enumtype) != NULL_TREE) + { + /* This enum is a named one that has been declared already. */ + error ("redeclaration of `enum %s'", IDENTIFIER_POINTER (name)); + + /* Completely replace its old definition. + The old enumerators remain defined, however. */ + TYPE_VALUES (enumtype) = NULL_TREE; + } + + /* Initially, set up this enum as like `int' + so that we can create the enumerators' declarations and values. + Later on, the precision of the type may be changed and + it may be laid out again. */ + + TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node); + TYPE_SIZE (enumtype) = NULL_TREE; + fixup_unsigned_type (enumtype); + + /* We copy this value because enumerated type constants + are really of the type of the enumerator, not integer_type_node. */ + enum_next_value = copy_node (integer_zero_node); + + GNU_xref_decl (current_function_decl, enumtype); + return enumtype; +} + +/* After processing and defining all the values of an enumeration type, + install their decls in the enumeration type and finish it off. + ENUMTYPE is the type object and VALUES a list of name-value pairs. + Returns ENUMTYPE. */ + +tree +finish_enum (enumtype, values) + register tree enumtype, values; +{ + register tree pair; + register HOST_WIDE_INT maxvalue = 0; + register HOST_WIDE_INT minvalue = 0; + register HOST_WIDE_INT i; + + TYPE_VALUES (enumtype) = values; + + /* Calculate the maximum value of any enumerator in this type. */ + + if (values) + { + /* Speed up the main loop by performing some precalculations */ + + HOST_WIDE_INT value = TREE_INT_CST_LOW (TREE_VALUE (values)); + TREE_TYPE (TREE_VALUE (values)) = enumtype; + minvalue = maxvalue = value; + + for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair)) + { + value = TREE_INT_CST_LOW (TREE_VALUE (pair)); + if (value > maxvalue) + maxvalue = value; + else if (value < minvalue) + minvalue = value; + TREE_TYPE (TREE_VALUE (pair)) = enumtype; + } + } + + if (flag_short_enums) + { + /* Determine the precision this type needs, lay it out, and define it. */ + + for (i = maxvalue; i; i >>= 1) + TYPE_PRECISION (enumtype)++; + + if (!TYPE_PRECISION (enumtype)) + TYPE_PRECISION (enumtype) = 1; + + /* Cancel the laying out previously done for the enum type, + so that fixup_unsigned_type will do it over. */ + TYPE_SIZE (enumtype) = NULL_TREE; + + fixup_unsigned_type (enumtype); + } + + TREE_INT_CST_LOW (TYPE_MAX_VALUE (enumtype)) = maxvalue; + + /* An enum can have some negative values; then it is signed. */ + if (minvalue < 0) + { + TREE_INT_CST_LOW (TYPE_MIN_VALUE (enumtype)) = minvalue; + TREE_INT_CST_HIGH (TYPE_MIN_VALUE (enumtype)) = -1; + TREE_UNSIGNED (enumtype) = 0; + } + if (flag_cadillac) + cadillac_finish_enum (enumtype); + + /* Finish debugging output for this type. */ +#if 0 + /* @@ Do we ever generate generate ENUMERAL_TYPE nodes for which debugging + information should *not* be generated? I think not. */ + if (! DECL_IGNORED_P (TYPE_NAME (enumtype))) +#endif + rest_of_type_compilation (enumtype, global_bindings_p ()); + + return enumtype; +} + +/* Build and install a CONST_DECL for one value of the + current enumeration type (one that was begun with start_enum). + Return a tree-list containing the name and its value. + Assignment of sequential values by default is handled here. */ + +tree +build_enumerator (name, value) + tree name, value; +{ + tree decl, result; + /* Change this to zero if we find VALUE is not shareable. */ + int shareable = 1; + + /* Remove no-op casts from the value. */ + if (value) + STRIP_TYPE_NOPS (value); + + /* Validate and default VALUE. */ + if (value != NULL_TREE) + { + if (TREE_READONLY_DECL_P (value)) + { + value = decl_constant_value (value); + shareable = 0; + } + + if (TREE_CODE (value) != INTEGER_CST) + { + error ("enumerator value for `%s' not integer constant", + IDENTIFIER_POINTER (name)); + value = NULL_TREE; + } + } + /* The order of things is reversed here so that we + can check for possible sharing of enum values, + to keep that from happening. */ + /* Default based on previous value. */ + if (value == NULL_TREE) + value = enum_next_value; + + /* Remove no-op casts from the value. */ + if (value) + STRIP_TYPE_NOPS (value); + + /* Make up for hacks in cp-lex.c. */ + if (value == integer_zero_node) + value = build_int_2 (0, 0); + else if (value == integer_one_node) + value = build_int_2 (1, 0); + else if (TREE_CODE (value) == INTEGER_CST + && (shareable == 0 + || TREE_CODE (TREE_TYPE (value)) == ENUMERAL_TYPE)) + { + value = copy_node (value); + TREE_TYPE (value) = integer_type_node; + } + + result = saveable_tree_cons (name, value, NULL_TREE); + + /* C++ associates enums with global, function, or class declarations. */ + if (current_class_type == NULL_TREE || current_function_decl != NULL_TREE) + { + /* Create a declaration for the enum value name. */ + + decl = build_decl (CONST_DECL, name, integer_type_node); + DECL_INITIAL (decl) = value; + + pushdecl (decl); + GNU_xref_decl (current_function_decl, decl); + } + + if (current_class_type) + { + /* class-local enum declaration */ + decl = build_lang_field_decl (CONST_DECL, name, integer_type_node); + DECL_INITIAL (decl) = value; + TREE_READONLY (decl) = 1; + pushdecl_class_level (decl); + TREE_CHAIN (decl) = current_local_enum; + current_local_enum = decl; + } + + /* Set basis for default for next value. */ + enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value, + integer_one_node, PLUS_EXPR); + if (enum_next_value == integer_one_node) + enum_next_value = copy_node (enum_next_value); + + return result; +} + +tree +grok_enum_decls (type, decl) + tree type, decl; +{ + tree d = current_local_enum; + + if (d == NULL_TREE) + return decl; + + while (1) + { + TREE_TYPE (d) = type; + if (TREE_CHAIN (d) == NULL_TREE) + { + TREE_CHAIN (d) = decl; + break; + } + d = TREE_CHAIN (d); + } + + decl = current_local_enum; + current_local_enum = NULL_TREE; + + return decl; +} + +/* Create the FUNCTION_DECL for a function definition. + DECLSPECS and DECLARATOR are the parts of the declaration; + they describe the function's name and the type it returns, + but twisted together in a fashion that parallels the syntax of C. + + This function creates a binding context for the function body + as well as setting up the FUNCTION_DECL in current_function_decl. + + Returns 1 on success. If the DECLARATOR is not suitable for a function + (it defines a datum instead), we return 0, which tells + yyparse to report a parse error. + + For C++, we must first check whether that datum makes any sense. + For example, "class A local_a(1,2);" means that variable local_a + is an aggregate of type A, which should have a constructor + applied to it with the argument list [1, 2]. + + @@ There is currently no way to retrieve the storage + @@ allocated to FUNCTION (or all of its parms) if we return + @@ something we had previously. */ + +int +start_function (declspecs, declarator, raises, pre_parsed_p) + tree declarator, declspecs, raises; + int pre_parsed_p; +{ + extern tree EHS_decl; + tree decl1, olddecl; + tree ctype = NULL_TREE; + tree fntype; + tree restype; + extern int have_extern_spec; + extern int used_extern_spec; + int doing_friend = 0; + + if (flag_handle_exceptions && EHS_decl == NULL_TREE) + init_exception_processing_1 (); + + /* Sanity check. */ + my_friendly_assert (TREE_VALUE (void_list_node) == void_type_node, 160); + my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161); + + /* Assume, until we see it does. */ + current_function_returns_value = 0; + current_function_returns_null = 0; + warn_about_return_type = 0; + current_extern_inline = 0; + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + current_function_parms_stored = 0; + original_result_rtx = NULL_RTX; + current_function_obstack_index = 0; + current_function_obstack_usage = 0; + + clear_temp_name (); + + /* This should only be done once on the top most decl. */ + if (have_extern_spec && !used_extern_spec) + { + declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), declspecs); + used_extern_spec = 1; + } + + if (pre_parsed_p) + { + decl1 = declarator; + last_function_parms = DECL_ARGUMENTS (decl1); + last_function_parm_tags = NULL_TREE; + fntype = TREE_TYPE (decl1); + if (TREE_CODE (fntype) == METHOD_TYPE) + ctype = TYPE_METHOD_BASETYPE (fntype); + + /* ANSI C++ June 5 1992 WP 11.4.5. A friend function defined in a + class is in the (lexical) scope of the class in which it is + defined. */ + if (!ctype && DECL_FRIEND_P (decl1)) + { + ctype = TREE_TYPE (TREE_CHAIN (decl1)); + + /* CTYPE could be null here if we're dealing with a template; + for example, `inline friend float foo()' inside a template + will have no CTYPE set. */ + if (ctype && TREE_CODE (ctype) != RECORD_TYPE) + ctype = NULL_TREE; + else + doing_friend = 1; + } + + if ( !(DECL_VINDEX (decl1) + && write_virtuals >= 2 + && CLASSTYPE_VTABLE_NEEDS_WRITING (ctype))) + current_extern_inline = TREE_PUBLIC (decl1) && DECL_INLINE (decl1); + + raises = TYPE_RAISES_EXCEPTIONS (fntype); + + /* In a fcn definition, arg types must be complete. */ + require_complete_types_for_parms (last_function_parms); + } + else + { + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, raises); + /* 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; + + fntype = TREE_TYPE (decl1); + + restype = TREE_TYPE (fntype); + if (IS_AGGR_TYPE (restype) + && ! CLASSTYPE_GOT_SEMICOLON (restype)) + { + error_with_aggr_type (restype, "semicolon missing after declaration of `%s'"); + shadow_tag (build_tree_list (NULL_TREE, restype)); + CLASSTYPE_GOT_SEMICOLON (restype) = 1; + if (TREE_CODE (fntype) == FUNCTION_TYPE) + fntype = build_function_type (integer_type_node, + TYPE_ARG_TYPES (fntype)); + else + fntype = build_cplus_method_type (build_type_variant (TYPE_METHOD_BASETYPE (fntype), TREE_READONLY (decl1), TREE_SIDE_EFFECTS (decl1)), + integer_type_node, + TYPE_ARG_TYPES (fntype)); + TREE_TYPE (decl1) = fntype; + } + + if (TREE_CODE (fntype) == METHOD_TYPE) + ctype = TYPE_METHOD_BASETYPE (fntype); + else if (IDENTIFIER_LENGTH (DECL_NAME (decl1)) == 4 + && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (decl1)), "main") + && DECL_CONTEXT (decl1) == NULL_TREE) + { + /* If this doesn't return integer_type, complain. */ + if (TREE_TYPE (TREE_TYPE (decl1)) != integer_type_node) + { + warning ("return type for `main' changed to integer type"); + TREE_TYPE (decl1) = fntype = default_function_type; + } + warn_about_return_type = 0; + } + } + + /* Warn if function was previously implicitly declared + (but not if we warned then). */ + if (! warn_implicit + && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)) != NULL_TREE) + warning_with_decl (IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)), + "`%s' implicitly declared before its definition"); + + current_function_decl = decl1; + + if (flag_cadillac) + cadillac_start_function (decl1); + else + announce_function (decl1); + + if (TYPE_SIZE (TREE_TYPE (fntype)) == NULL_TREE) + { + if (IS_AGGR_TYPE (TREE_TYPE (fntype))) + error_with_aggr_type (TREE_TYPE (fntype), + "return-type `%s' is an incomplete type"); + else + error ("return-type is an incomplete type"); + + /* Make it return void instead, but don't change the + type of the DECL_RESULT, in case we have a named return value. */ + if (ctype) + TREE_TYPE (decl1) + = build_cplus_method_type (build_type_variant (ctype, + TREE_READONLY (decl1), + TREE_SIDE_EFFECTS (decl1)), + void_type_node, + FUNCTION_ARG_CHAIN (decl1)); + else + TREE_TYPE (decl1) + = build_function_type (void_type_node, + TYPE_ARG_TYPES (TREE_TYPE (decl1))); + DECL_RESULT (decl1) = build_decl (RESULT_DECL, 0, TREE_TYPE (fntype)); + } + + if (warn_about_return_type) + warning ("return-type defaults to `int'"); + + /* Make the init_value nonzero so pushdecl knows this is not tentative. + error_mark_node is replaced below (in poplevel) with the BLOCK. */ + DECL_INITIAL (decl1) = error_mark_node; + + /* Didn't get anything from C. */ + olddecl = NULL_TREE; + + /* This function exists in static storage. + (This does not mean `static' in the C sense!) */ + TREE_STATIC (decl1) = 1; + + /* If this function belongs to an interface, it is public. + If it belongs to someone else's interface, it is also external. + It doesn't matter whether it's inline or not. */ + if (interface_unknown == 0) + { + TREE_PUBLIC (decl1) = 1; + DECL_EXTERNAL (decl1) = (interface_only + || (DECL_INLINE (decl1) + && ! flag_implement_inlines)); + } + else + /* This is a definition, not a reference. + So normally clear DECL_EXTERNAL. + However, `extern inline' acts like a declaration except for + defining how to inline. So set DECL_EXTERNAL in that case. */ + DECL_EXTERNAL (decl1) = current_extern_inline; + + /* Now see if this is the implementation of a function + declared with "C" linkage. */ + if (ctype == NULL_TREE && current_lang_name == lang_name_cplusplus + && !DECL_CONTEXT (decl1)) + { + olddecl = lookup_name_current_level (DECL_NAME (decl1)); + if (olddecl && TREE_CODE (olddecl) != FUNCTION_DECL) + olddecl = NULL_TREE; + if (olddecl && DECL_NAME (decl1) != DECL_NAME (olddecl)) + { + /* Collision between user and internal naming scheme. */ + olddecl = lookup_name_current_level (DECL_ASSEMBLER_NAME (decl1)); + if (olddecl == NULL_TREE) + olddecl = decl1; + } + if (olddecl && olddecl != decl1 + && DECL_NAME (decl1) == DECL_NAME (olddecl)) + { + if (TREE_CODE (olddecl) == FUNCTION_DECL + && decls_match (decl1, olddecl)) + { + olddecl = DECL_MAIN_VARIANT (olddecl); + /* The following copy is needed to handle forcing a function's + linkage to obey the linkage of the original decl. */ + DECL_ASSEMBLER_NAME (decl1) = DECL_ASSEMBLER_NAME (olddecl); + DECL_OVERLOADED (decl1) = DECL_OVERLOADED (olddecl); + if (DECL_INITIAL (olddecl)) + redeclaration_error_message (decl1, olddecl); + if (! duplicate_decls (decl1, olddecl)) + my_friendly_abort (19); + decl1 = olddecl; + } + else + olddecl = NULL_TREE; + } + } + + /* Record the decl so that the function name is defined. + If we already have a decl for this name, and it is a FUNCTION_DECL, + use the old decl. */ + + if (olddecl) + current_function_decl = olddecl; + else if (pre_parsed_p == 0) + { + current_function_decl = pushdecl (decl1); + if (TREE_CODE (current_function_decl) == TREE_LIST) + { + /* @@ revert to modified original declaration. */ + decl1 = DECL_MAIN_VARIANT (decl1); + current_function_decl = decl1; + } + else + { + decl1 = current_function_decl; + DECL_MAIN_VARIANT (decl1) = decl1; + } + fntype = TREE_TYPE (decl1); + } + else + current_function_decl = decl1; + + if (DECL_OVERLOADED (decl1)) + decl1 = push_overloaded_decl (decl1, 1); + + if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)) + { + if (TREE_CODE (fntype) == METHOD_TYPE) + TREE_TYPE (decl1) = fntype + = build_function_type (TREE_TYPE (fntype), + TREE_CHAIN (TYPE_ARG_TYPES (fntype))); + last_function_parms = TREE_CHAIN (last_function_parms); + DECL_ARGUMENTS (decl1) = last_function_parms; + ctype = NULL_TREE; + } + restype = TREE_TYPE (fntype); + + pushlevel (0); + current_binding_level->parm_flag = 1; + + /* Save the parm names or decls from this function's declarator + where store_parm_decls will find them. */ + current_function_parms = last_function_parms; + current_function_parm_tags = last_function_parm_tags; + + GNU_xref_function (decl1, current_function_parms); + + make_function_rtl (decl1); + + if (ctype) + { + pushclass (ctype, 1); + + /* If we're compiling a friend function, neither of the variables + current_class_decl nor current_class_type will have values. */ + if (! doing_friend) + { + /* We know that this was set up by `grokclassfn'. + We do not wait until `store_parm_decls', since evil + parse errors may never get us to that point. Here + we keep the consistency between `current_class_type' + and `current_class_decl'. */ + current_class_decl = last_function_parms; + my_friendly_assert (current_class_decl != NULL_TREE + && TREE_CODE (current_class_decl) == PARM_DECL, 162); + if (TREE_CODE (TREE_TYPE (current_class_decl)) == POINTER_TYPE) + { + tree variant = TREE_TYPE (TREE_TYPE (current_class_decl)); + if (CLASSTYPE_INST_VAR (ctype) == NULL_TREE) + { + /* Can't call build_indirect_ref here, because it has special + logic to return C_C_D given this argument. */ + C_C_D = build1 (INDIRECT_REF, current_class_type, current_class_decl); + CLASSTYPE_INST_VAR (ctype) = C_C_D; + } + else + { + C_C_D = CLASSTYPE_INST_VAR (ctype); + /* `current_class_decl' is different for every + function we compile. */ + TREE_OPERAND (C_C_D, 0) = current_class_decl; + } + TREE_READONLY (C_C_D) = TYPE_READONLY (variant); + TREE_SIDE_EFFECTS (C_C_D) = TYPE_VOLATILE (variant); + TREE_THIS_VOLATILE (C_C_D) = TYPE_VOLATILE (variant); + } + else + C_C_D = current_class_decl; + } + } + else + { + if (DECL_STATIC_FUNCTION_P (decl1)) + pushclass (DECL_CONTEXT (decl1), 2); + else + push_memoized_context (0, 1); + } + + /* Allocate further tree nodes temporarily during compilation + of this function only. Tiemann moved up here from bottom of fn. */ + temporary_allocation (); + + /* Promote the value to int before returning it. */ + if (C_PROMOTING_INTEGER_TYPE_P (restype)) + { + /* It retains unsignedness if traditional or if it isn't + really getting wider. */ + if (TREE_UNSIGNED (restype) + && (flag_traditional + || TYPE_PRECISION (restype) + == TYPE_PRECISION (integer_type_node))) + restype = unsigned_type_node; + else + restype = integer_type_node; + } + if (DECL_RESULT (decl1) == NULL_TREE) + DECL_RESULT (decl1) = build_decl (RESULT_DECL, 0, restype); + + if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))) + { + dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + ctor_label = NULL_TREE; + } + else + { + dtor_label = NULL_TREE; + if (DECL_CONSTRUCTOR_P (decl1)) + ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + } + + /* If this fcn was already referenced via a block-scope `extern' decl + (or an implicit decl), propagate certain information about the usage. */ + if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (decl1))) + TREE_ADDRESSABLE (decl1) = 1; + + return 1; +} + +/* Store the parameter declarations into the current function declaration. + This is called after parsing the parameter declarations, before + digesting the body of the function. + + Also install to binding contour return value identifier, if any. */ + +void +store_parm_decls () +{ + register tree fndecl = current_function_decl; + register tree parm; + int parms_have_cleanups = 0; + tree eh_decl; + + /* This is either a chain of PARM_DECLs (when a prototype is used). */ + tree specparms = current_function_parms; + + /* This is a list of types declared among parms in a prototype. */ + tree parmtags = current_function_parm_tags; + + /* This is a chain of any other decls that came in among the parm + declarations. If a parm is declared with enum {foo, bar} x; + then CONST_DECLs for foo and bar are put here. */ + tree nonparms = NULL_TREE; + + if (current_binding_level == global_binding_level) + fatal ("parse errors have confused me too much"); + + /* Initialize RTL machinery. */ + init_function_start (fndecl, input_filename, lineno); + + /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */ + declare_function_name (); + + /* Create a binding level for the parms. */ + expand_start_bindings (0); + + /* Prepare to catch raises, if appropriate. */ + if (flag_handle_exceptions) + { + /* Get this cleanup to be run last, since it + is a call to `longjmp'. */ + setup_exception_throw_decl (); + eh_decl = current_binding_level->names; + current_binding_level->names = TREE_CHAIN (current_binding_level->names); + } + if (flag_handle_exceptions) + expand_start_try (integer_one_node, 0, 1); + + if (specparms != NULL_TREE) + { + /* This case is when the function was defined with an ANSI prototype. + The parms already have decls, so we need not do anything here + except record them as in effect + and complain if any redundant old-style parm decls were written. */ + + register tree next; + + /* Must clear this because it might contain TYPE_DECLs declared + at class level. */ + storedecls (NULL_TREE); + for (parm = nreverse (specparms); parm; parm = next) + { + next = TREE_CHAIN (parm); + if (TREE_CODE (parm) == PARM_DECL) + { + tree cleanup = maybe_build_cleanup (parm); + if (DECL_NAME (parm) == NULL_TREE) + { +#if 0 + error_with_decl (parm, "parameter name omitted"); +#else + /* for C++, this is not an error. */ + pushdecl (parm); +#endif + } + else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node) + error_with_decl (parm, "parameter `%s' declared void"); + else + { + /* Now fill in DECL_REFERENCE_SLOT for any of the parm decls. + A parameter is assumed not to have any side effects. + If this should change for any reason, then this + will have to wrap the bashed reference type in a save_expr. + + Also, if the parameter type is declared to be an X + and there is an X(X&) constructor, we cannot lay it + into the stack (any more), so we make this parameter + look like it is really of reference type. Functions + which pass parameters to this function will know to + create a temporary in their frame, and pass a reference + to that. */ + + if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE + && TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm)))) + SET_DECL_REFERENCE_SLOT (parm, convert_from_reference (parm)); + + pushdecl (parm); + } + if (cleanup) + { + expand_decl (parm); + expand_decl_cleanup (parm, cleanup); + parms_have_cleanups = 1; + } + } + else + { + /* If we find an enum constant or a type tag, + put it aside for the moment. */ + TREE_CHAIN (parm) = NULL_TREE; + nonparms = chainon (nonparms, parm); + } + } + + /* Get the decls in their original chain order + and record in the function. This is all and only the + PARM_DECLs that were pushed into scope by the loop above. */ + DECL_ARGUMENTS (fndecl) = getdecls (); + + storetags (chainon (parmtags, gettags ())); + } + else + DECL_ARGUMENTS (fndecl) = NULL_TREE; + + /* Now store the final chain of decls for the arguments + as the decl-chain of the current lexical scope. + Put the enumerators in as well, at the front so that + DECL_ARGUMENTS is not modified. */ + + storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl))); + + /* Initialize the RTL code for the function. */ + DECL_SAVED_INSNS (fndecl) = NULL_RTX; + expand_function_start (fndecl, parms_have_cleanups); + + if (flag_handle_exceptions) + { + /* Make the throw decl visible at this level, just + not in the way of the parameters. */ + pushdecl (eh_decl); + expand_decl_init (eh_decl); + } + + /* Create a binding contour which can be used to catch + cleanup-generated temporaries. Also, if the return value needs or + has initialization, deal with that now. */ + if (parms_have_cleanups) + { + pushlevel (0); + expand_start_bindings (0); + } + + current_function_parms_stored = 1; + + if (flag_gc) + { + maybe_gc_cleanup = build_tree_list (NULL_TREE, error_mark_node); + expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup); + } + + /* If this function is `main', emit a call to `__main' + to run global initializers, etc. */ + if (DECL_NAME (fndecl) + && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 4 + && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0 + && DECL_CONTEXT (fndecl) == NULL_TREE) + { + expand_main_function (); + + if (flag_gc) + expand_expr (build_function_call (lookup_name (get_identifier ("__gc_main"), 0), NULL_TREE), + 0, VOIDmode, 0); + + if (flag_dossier) + output_builtin_tdesc_entries (); + } +} + +/* Bind a name and initialization to the return value of + the current function. */ +void +store_return_init (return_id, init) + tree return_id, init; +{ + tree decl = DECL_RESULT (current_function_decl); + + if (pedantic) + /* Give this error as many times as there are occurrences, + so that users can use Emacs compilation buffers to find + and fix all such places. */ + error ("ANSI C++ does not permit named return values"); + + if (return_id != NULL_TREE) + { + if (DECL_NAME (decl) == NULL_TREE) + { + DECL_NAME (decl) = return_id; + DECL_ASSEMBLER_NAME (decl) = return_id; + } + else + error ("return identifier `%s' already in place", + IDENTIFIER_POINTER (DECL_NAME (decl))); + } + + /* Can't let this happen for constructors. */ + if (DECL_CONSTRUCTOR_P (current_function_decl)) + { + error ("can't redefine default return value for constructors"); + return; + } + + /* If we have a named return value, put that in our scope as well. */ + if (DECL_NAME (decl) != NULL_TREE) + { + /* If this named return value comes in a register, + put it in a pseudo-register. */ + if (DECL_REGISTER (decl)) + { + original_result_rtx = DECL_RTL (decl); + DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl)); + } + + /* Let `finish_decl' know that this initializer is ok. */ + DECL_INITIAL (decl) = init; + pushdecl (decl); + finish_decl (decl, init, 0, 0); + } +} + +/* Generate code for default X(X&) constructor. */ +static void +build_default_constructor (fndecl) + tree fndecl; +{ + int i = CLASSTYPE_N_BASECLASSES (current_class_type); + tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); + tree fields = TYPE_FIELDS (current_class_type); + tree binfos = TYPE_BINFO_BASETYPES (current_class_type); + + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + parm = TREE_CHAIN (parm); + parm = DECL_REFERENCE_SLOT (parm); + + while (--i >= 0) + { + tree basetype = TREE_VEC_ELT (binfos, i); + if (TYPE_GETS_INIT_REF (basetype)) + { + tree name = TYPE_NAME (basetype); + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + current_base_init_list = tree_cons (name, parm, current_base_init_list); + } + } + for (; fields; fields = TREE_CHAIN (fields)) + { + tree name, init; + if (TREE_STATIC (fields)) + continue; + if (TREE_CODE (fields) != FIELD_DECL) + continue; + if (DECL_NAME (fields)) + { + if (VFIELD_NAME_P (DECL_NAME (fields))) + continue; + if (VBASE_NAME_P (DECL_NAME (fields))) + continue; + + /* True for duplicate members. */ + if (IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) != fields) + continue; + } + + init = build (COMPONENT_REF, TREE_TYPE (fields), parm, fields); + + if (TREE_ANON_UNION_ELEM (fields)) + name = build (COMPONENT_REF, TREE_TYPE (fields), C_C_D, fields); + else + { + name = DECL_NAME (fields); + init = build_tree_list (NULL_TREE, init); + } + + current_member_init_list + = tree_cons (name, init, current_member_init_list); + } +} + + +/* Finish up a function declaration and compile that function + all the way to assembler language output. The free the storage + for the function definition. + + This is called after parsing the body of the function definition. + LINENO is the current line number. + + C++: CALL_POPLEVEL is non-zero if an extra call to poplevel + (and expand_end_bindings) must be made to take care of the binding + contour for the base initializers. This is only relevant for + constructors. */ + +void +finish_function (lineno, call_poplevel) + int lineno; + int call_poplevel; +{ + register tree fndecl = current_function_decl; + tree fntype, ctype = NULL_TREE; + rtx head, last_parm_insn, mark; + extern int sets_exception_throw_decl; + /* Label to use if this function is supposed to return a value. */ + tree no_return_label = NULL_TREE; + + /* When we get some parse errors, we can end up without a + current_function_decl, so cope. */ + if (fndecl == NULL_TREE) + return; + + fntype = TREE_TYPE (fndecl); + +/* TREE_READONLY (fndecl) = 1; + This caused &foo to be of type ptr-to-const-function + which then got a warning when stored in a ptr-to-function variable. */ + + /* This happens on strange parse errors. */ + if (! current_function_parms_stored) + { + call_poplevel = 0; + store_parm_decls (); + } + + if (write_symbols != NO_DEBUG && TREE_CODE (fntype) != METHOD_TYPE) + { + tree ttype = target_type (fntype); + tree parmdecl; + + if (IS_AGGR_TYPE (ttype)) + /* Let debugger know it should output info for this type. */ + note_debug_info_needed (ttype); + + for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl)) + { + ttype = target_type (TREE_TYPE (parmdecl)); + if (IS_AGGR_TYPE (ttype)) + /* Let debugger know it should output info for this type. */ + note_debug_info_needed (ttype); + } + } + + /* Clean house because we will need to reorder insns here. */ + do_pending_stack_adjust (); + + if (dtor_label) + { + tree binfo = TYPE_BINFO (current_class_type); + tree cond = integer_one_node; + tree exprstmt, vfields; + tree in_charge_node = lookup_name (in_charge_identifier, 0); + tree virtual_size; + int ok_to_optimize_dtor = 0; + + if (current_function_assigns_this) + cond = build (NE_EXPR, integer_type_node, + current_class_decl, integer_zero_node); + else + { + int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type); + + /* If this destructor is empty, then we don't need to check + whether `this' is NULL in some cases. */ + 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) + ok_to_optimize_dtor + = (n_baseclasses == 0 + || (n_baseclasses == 1 + && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0)))); + } + + /* These initializations might go inline. Protect + the binding level of the parms. */ + pushlevel (0); + + if (current_function_assigns_this) + { + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + } + + /* Generate the code to call destructor on base class. + If this destructor belongs to a class with virtual + functions, then set the virtual function table + pointer to represent the type of our base class. */ + + /* This side-effect makes call to `build_delete' generate the + code we have to have at the end of this destructor. */ + TYPE_HAS_DESTRUCTOR (current_class_type) = 0; + + /* These are two cases where we cannot delegate deletion. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type) + || TREE_GETS_DELETE (current_class_type)) + exprstmt = build_delete (current_class_type, C_C_D, integer_zero_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0, 0); + else + exprstmt = build_delete (current_class_type, C_C_D, in_charge_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0, 0); + + /* If we did not assign to this, then `this' is non-zero at + the end of a destructor. As a special optimization, don't + emit test if this is an empty destructor. If it does nothing, + it does nothing. If it calls a base destructor, the base + destructor will perform the test. */ + + if (exprstmt != error_mark_node + && (TREE_CODE (exprstmt) != NOP_EXPR + || TREE_OPERAND (exprstmt, 0) != integer_zero_node + || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))) + { + expand_label (dtor_label); + if (cond != integer_one_node) + expand_start_cond (cond, 0); + if (exprstmt != void_zero_node) + /* Don't call `expand_expr_stmt' if we're not going to do + anything, since -Wall will give a diagnostic. */ + expand_expr_stmt (exprstmt); + + /* Run destructor on all virtual baseclasses. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + { + tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type))); + expand_start_cond (build (BIT_AND_EXPR, integer_type_node, + in_charge_node, integer_two_node), 0); + while (vbases) + { + if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases))) + { + tree ptr = convert_pointer_to_vbase (vbases, current_class_decl); + expand_expr_stmt (build_delete (TYPE_POINTER_TO (BINFO_TYPE (vbases)), + ptr, integer_zero_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_HAS_IN_CHARGE, 0, 0)); + } + vbases = TREE_CHAIN (vbases); + } + expand_end_cond (); + } + + do_pending_stack_adjust (); + if (cond != integer_one_node) + expand_end_cond (); + } + + TYPE_HAS_DESTRUCTOR (current_class_type) = 1; + + virtual_size = c_sizeof (current_class_type); + + /* At the end, call delete if that's what's requested. */ + if (TREE_GETS_DELETE (current_class_type)) + /* This NOP_EXPR means we are in a static call context. */ + exprstmt = + build_method_call + (build1 (NOP_EXPR, + TYPE_POINTER_TO (current_class_type), error_mark_node), + ansi_opname[(int) DELETE_EXPR], + tree_cons (NULL_TREE, current_class_decl, + build_tree_list (NULL_TREE, virtual_size)), + NULL_TREE, LOOKUP_NORMAL); + else if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + exprstmt = build_x_delete (ptr_type_node, current_class_decl, 0, + virtual_size); + else + exprstmt = NULL_TREE; + + if (exprstmt) + { + cond = build (BIT_AND_EXPR, integer_type_node, + in_charge_node, integer_one_node); + expand_start_cond (cond, 0); + expand_expr_stmt (exprstmt); + expand_end_cond (); + } + + /* End of destructor. */ + poplevel (2, 0, 0); + + /* 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 point to CURRENT_CLASS_TYPE's + virtual function tables. */ + if (CLASSTYPE_VFIELDS (current_class_type)) + { + for (vfields = CLASSTYPE_VFIELDS (current_class_type); + TREE_CHAIN (vfields); + vfields = TREE_CHAIN (vfields)) + { + tree vf_decl = current_class_decl; + /* ??? This may need to be a loop if there are multiple + levels of replication. */ + if (VF_BINFO_VALUE (vfields)) + vf_decl = convert_pointer_to (VF_BINFO_VALUE (vfields), vf_decl); + if (vf_decl != error_mark_node) + { + /* It is one of these two, or a combination... */ + /* basically speaking, I want to get down to the right + VF_BASETYPE_VALUE (vfields) */ +#if 0 + if (VF_NORMAL_VALUE (vfields) != VF_DERIVED_VALUE (vfields)) + warning ("hum, wonder if I am doing the right thing"); +#endif + expand_expr_stmt (build_virtual_init (binfo, + get_binfo (VF_BASETYPE_VALUE (vfields), + get_binfo (VF_DERIVED_VALUE (vfields), binfo, 0), 0), + vf_decl)); + } + } + expand_expr_stmt (build_virtual_init (binfo, binfo, + current_class_decl)); + } + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + expand_expr_stmt (build_vbase_vtables_init (binfo, 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); + if (! ok_to_optimize_dtor) + expand_end_cond (); + } + else if (current_function_assigns_this) + { + /* Does not need to call emit_base_init, because + that is done (if needed) just after assignment to this + is seen. */ + + if (DECL_CONSTRUCTOR_P (current_function_decl)) + { + expand_label (ctor_label); + ctor_label = NULL_TREE; + + if (call_poplevel) + { + tree decls = getdecls (); + if (flag_handle_exceptions == 2) + deactivate_exception_cleanups (); + expand_end_bindings (decls, decls != NULL_TREE, 0); + poplevel (decls != NULL_TREE, 0, 0); + } + c_expand_return (current_class_decl); + } + else if (TYPE_MAIN_VARIANT (TREE_TYPE ( + DECL_RESULT (current_function_decl))) != void_type_node + && return_label != NULL_RTX) + no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + base_init_insns = NULL_RTX; + } + else if (DECL_CONSTRUCTOR_P (fndecl)) + { + tree allocated_this; + tree cond, thenclause; + /* Allow constructor for a type to get a new instance of the object + using `build_new'. */ + tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type); + CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE; + + DECL_RETURNS_FIRST_ARG (fndecl) = 1; + + if (flag_this_is_variable > 0) + { + cond = build_binary_op (EQ_EXPR, + current_class_decl, integer_zero_node, 1); + thenclause = build_modify_expr (current_class_decl, NOP_EXPR, + build_new (NULL_TREE, current_class_type, void_type_node, 0)); + if (flag_handle_exceptions == 2) + { + tree cleanup, cleanup_deallocate; + tree virtual_size; + + /* This is the size of the virtual object pointed to by + allocated_this. In this case, it is simple. */ + virtual_size = c_sizeof (current_class_type); + + allocated_this = build_decl (VAR_DECL, NULL_TREE, ptr_type_node); + DECL_REGISTER (allocated_this) = 1; + DECL_INITIAL (allocated_this) = error_mark_node; + expand_decl (allocated_this); + expand_decl_init (allocated_this); + /* How we cleanup `this' if an exception was raised before + we are ready to bail out. */ + cleanup = TREE_GETS_DELETE (current_class_type) + ? build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, allocated_this, virtual_size, NULL_TREE) + /* The size of allocated_this is wrong, and hence the + second argument to operator delete will be wrong. */ + : build_delete (TREE_TYPE (allocated_this), allocated_this, + integer_three_node, + LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE, 1, 0); + cleanup_deallocate + = build_modify_expr (current_class_decl, NOP_EXPR, integer_zero_node); + cleanup = tree_cons (NULL_TREE, cleanup, + build_tree_list (NULL_TREE, cleanup_deallocate)); + + expand_decl_cleanup (allocated_this, + build (COND_EXPR, integer_type_node, + build (NE_EXPR, integer_type_node, + allocated_this, integer_zero_node), + build_compound_expr (cleanup), + integer_zero_node)); + } + } + else if (TREE_GETS_NEW (current_class_type)) + /* Just check visibility here. */ + build_method_call (build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type), error_mark_node), + ansi_opname[(int) NEW_EXPR], + build_tree_list (NULL_TREE, integer_zero_node), + NULL_TREE, LOOKUP_NORMAL); + + 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 (); + + if (flag_this_is_variable > 0) + { + expand_start_cond (cond, 0); + expand_expr_stmt (thenclause); + if (flag_handle_exceptions == 2) + expand_assignment (allocated_this, current_class_decl, 0, 0); + expand_end_cond (); + } + + if (DECL_NAME (fndecl) == NULL_TREE + && TREE_CHAIN (DECL_ARGUMENTS (fndecl)) != NULL_TREE) + build_default_constructor (fndecl); + + /* Emit insns from `emit_base_init' which sets up virtual + function table pointer(s). */ + emit_insns (base_init_insns); + base_init_insns = NULL_RTX; + + /* 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. + + If optimization is enabled, last_parm_insn may move, so + 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; + 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); + + /* This is where the body of the constructor ends. */ + expand_label (ctor_label); + ctor_label = NULL_TREE; + if (flag_handle_exceptions == 2) + { + expand_assignment (allocated_this, integer_zero_node, 0, 0); + if (call_poplevel) + deactivate_exception_cleanups (); + } + + pop_implicit_try_blocks (NULL_TREE); + + if (call_poplevel) + { + expand_end_bindings (getdecls (), 1, 0); + poplevel (1, 1, 0); + } + + c_expand_return (current_class_decl); + + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + } + else if (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 4 + && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") + && DECL_CONTEXT (fndecl) == NULL_TREE) + { + /* Make it so that `main' always returns 0 by default. */ +#ifdef VMS + c_expand_return (integer_one_node); +#else + c_expand_return (integer_zero_node); +#endif + } + else if (return_label != NULL_RTX + && current_function_return_value == NULL_TREE + && ! DECL_NAME (DECL_RESULT (current_function_decl))) + no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + if (flag_gc) + expand_gc_prologue_and_epilogue (); + + /* That's the end of the vtable decl's life. Need to mark it such + if doing stupid register allocation. + + Note that current_vtable_decl is really an INDIRECT_REF + on top of a VAR_DECL here. */ + if (obey_regdecls && current_vtable_decl) + use_variable (DECL_RTL (TREE_OPERAND (current_vtable_decl, 0))); + + /* If this function is supposed to return a value, ensure that + we do not fall into the cleanups by mistake. The end of our + function will look like this: + + user code (may have return stmt somewhere) + goto no_return_label + cleanup_label: + cleanups + goto return_label + no_return_label: + NOTE_INSN_FUNCTION_END + return_label: + things for return + + If the user omits a return stmt in the USER CODE section, we + will have a control path which reaches NOTE_INSN_FUNCTION_END. + Otherwise, we won't. */ + if (no_return_label) + { + DECL_CONTEXT (no_return_label) = fndecl; + DECL_INITIAL (no_return_label) = error_mark_node; + DECL_SOURCE_FILE (no_return_label) = input_filename; + DECL_SOURCE_LINE (no_return_label) = lineno; + expand_goto (no_return_label); + } + + if (cleanup_label) + { + /* remove the binding contour which is used + to catch cleanup-generated temporaries. */ + expand_end_bindings (0, 0, 0); + poplevel (0, 0, 0); + } + + if (cleanup_label) + /* Emit label at beginning of cleanup code for parameters. */ + emit_label (cleanup_label); + +#if 1 + /* Cheap hack to get better code from GNU C++. Remove when cse is fixed. */ + if (exception_throw_decl && sets_exception_throw_decl == 0) + expand_assignment (exception_throw_decl, integer_zero_node, 0, 0); +#endif + + if (flag_handle_exceptions) + { + expand_end_try (); + expand_start_except (0, 0); + expand_end_except (); + } + expand_end_bindings (0, 0, 0); + + /* Get return value into register if that's where it's supposed to be. */ + if (original_result_rtx) + fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx); + + /* Finish building code that will trigger warnings if users forget + to make their functions return values. */ + if (no_return_label || cleanup_label) + emit_jump (return_label); + if (no_return_label) + { + /* We don't need to call `expand_*_return' here because we + don't need any cleanups here--this path of code is only + for error checking purposes. */ + expand_label (no_return_label); + } + + /* reset scope for C++: if we were in the scope of a class, + then when we finish this function, we are not longer so. + This cannot be done until we know for sure that no more + class members will ever be referenced in this function + (i.e., calls to destructors). */ + if (current_class_name) + { + ctype = current_class_type; + popclass (1); + } + else + pop_memoized_context (1); + + /* Forget about all overloaded functions defined in + this scope which go away. */ + while (overloads_to_forget) + { + IDENTIFIER_GLOBAL_VALUE (TREE_PURPOSE (overloads_to_forget)) + = TREE_VALUE (overloads_to_forget); + overloads_to_forget = TREE_CHAIN (overloads_to_forget); + } + + /* Generate rtl for function exit. */ + expand_function_end (input_filename, lineno); + + /* This must come after expand_function_end because cleanups might + have declarations (from inline functions) that need to go into + this function's blocks. */ + if (current_binding_level->parm_flag != 1) + my_friendly_abort (122); + poplevel (1, 0, 1); + + /* Must mark the RESULT_DECL as being in this function. */ + DECL_CONTEXT (DECL_RESULT (fndecl)) = DECL_INITIAL (fndecl); + + /* Obey `register' declarations if `setjmp' is called in this fn. */ + if (flag_traditional && current_function_calls_setjmp) + setjmp_protect (DECL_INITIAL (fndecl)); + + /* Set the BLOCK_SUPERCONTEXT of the outermost function scope to point + to the FUNCTION_DECL node itself. */ + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + /* So we can tell if jump_optimize sets it to 1. */ + can_reach_end = 0; + + /* ??? Compensate for Sun brain damage in dealing with data segments + of PIC code. */ + if (flag_pic + && (DECL_CONSTRUCTOR_P (fndecl) + || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl))) + && CLASSTYPE_NEEDS_VIRTUAL_REINIT (TYPE_METHOD_BASETYPE (fntype))) + DECL_INLINE (fndecl) = 0; + + if (DECL_EXTERNAL (fndecl) + /* This function is just along for the ride. If we can make + it inline, that's great. Otherwise, just punt it. */ + && (DECL_INLINE (fndecl) == 0 + || flag_no_inline + || function_cannot_inline_p (fndecl))) + { + extern int rtl_dump_and_exit; + int old_rtl_dump_and_exit = rtl_dump_and_exit; + int inline_spec = DECL_INLINE (fndecl); + + /* This throws away the code for FNDECL. */ + rtl_dump_and_exit = 1; + /* This throws away the memory of the code for FNDECL. */ + if (flag_no_inline) + DECL_INLINE (fndecl) = 0; + rest_of_compilation (fndecl); + rtl_dump_and_exit = old_rtl_dump_and_exit; + DECL_INLINE (fndecl) = inline_spec; + } + else + { + /* Run the optimizers and output the assembler code for this function. */ + rest_of_compilation (fndecl); + } + + if (ctype && TREE_ASM_WRITTEN (fndecl)) + note_debug_info_needed (ctype); + + current_function_returns_null |= can_reach_end; + + /* Since we don't normally go through c_expand_return for constructors, + this normally gets the wrong value. + Also, named return values have their return codes emitted after + NOTE_INSN_FUNCTION_END, confusing jump.c. */ + if (DECL_CONSTRUCTOR_P (fndecl) + || DECL_NAME (DECL_RESULT (fndecl)) != NULL_TREE) + current_function_returns_null = 0; + + if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null) + warning ("`volatile' function does return"); + else if (warn_return_type && current_function_returns_null + && TYPE_MAIN_VARIANT (TREE_TYPE (fntype)) != void_type_node) + { + /* If this function returns non-void and control can drop through, + complain. */ + pedwarn ("control reaches end of non-void function"); + } + /* With just -W, complain only if function returns both with + and without a value. */ + else if (extra_warnings + && current_function_returns_value && current_function_returns_null) + warning ("this function may return with or without a value"); + + /* Free all the tree nodes making up this function. */ + /* Switch back to allocating nodes permanently + until we start another function. */ + permanent_allocation (); + + if (flag_cadillac) + cadillac_finish_function (fndecl); + + if (DECL_SAVED_INSNS (fndecl) == NULL_RTX) + { + /* Stop pointing to the local nodes about to be freed. */ + /* But DECL_INITIAL must remain nonzero so we know this + was an actual function definition. */ + DECL_INITIAL (fndecl) = error_mark_node; + if (! DECL_CONSTRUCTOR_P (fndecl) + || !TYPE_USES_VIRTUAL_BASECLASSES (TYPE_METHOD_BASETYPE (fntype))) + DECL_ARGUMENTS (fndecl) = NULL_TREE; + } + + /* Let the error reporting routines know that we're outside a function. */ + current_function_decl = NULL_TREE; + named_label_uses = NULL_TREE; + clear_anon_parm_name (); +} + +/* Create the FUNCTION_DECL for a function definition. + LINE1 is the line number that the definition absolutely begins on. + LINE2 is the line number that the name of the function appears on. + DECLSPECS and DECLARATOR are the parts of the declaration; + they describe the function's name and the type it returns, + but twisted together in a fashion that parallels the syntax of C. + + This function creates a binding context for the function body + as well as setting up the FUNCTION_DECL in current_function_decl. + + Returns a FUNCTION_DECL on success. + + If the DECLARATOR is not suitable for a function (it defines a datum + instead), we return 0, which tells yyparse to report a parse error. + + May return void_type_node indicating that this method is actually + a friend. See grokfield for more details. + + Came here with a `.pushlevel' . + + DO NOT MAKE ANY CHANGES TO THIS CODE WITHOUT MAKING CORRESPONDING + CHANGES TO CODE IN `grokfield'. */ +tree +start_method (declspecs, declarator, raises) + tree declarator, declspecs, raises; +{ + tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, raises); + + /* Something too ugly to handle. */ + if (fndecl == NULL_TREE) + return NULL_TREE; + + /* Pass friends other than inline friend functions back. */ + if (TYPE_MAIN_VARIANT (fndecl) == void_type_node) + return fndecl; + + if (TREE_CODE (fndecl) != FUNCTION_DECL) + /* Not a function, tell parser to report parse error. */ + return NULL_TREE; + + if (DECL_IN_AGGR_P (fndecl)) + { + if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type) + { + if (DECL_CONTEXT (fndecl)) + error_with_decl (fndecl, "`%s' is already defined in class %s", + TYPE_NAME_STRING (DECL_CONTEXT (fndecl))); + } + return void_type_node; + } + + /* If we're expanding a template, a function must be explicitly declared + inline if we're to compile it now. If it isn't, we have to wait to see + whether it's needed, and whether an override exists. */ + if (flag_default_inline && !processing_template_defn) + DECL_INLINE (fndecl) = 1; + + /* We read in the parameters on the maybepermanent_obstack, + but we won't be getting back to them until after we + may have clobbered them. So the call to preserve_data + will keep them safe. */ + preserve_data (); + + if (! DECL_FRIEND_P (fndecl)) + { + if (DECL_CHAIN (fndecl) != NULL_TREE) + { + /* Need a fresh node here so that we don't get circularity + when we link these together. If FNDECL was a friend, then + `pushdecl' does the right thing, which is nothing wrt its + current value of DECL_CHAIN. */ + fndecl = copy_node (fndecl); + } + if (TREE_CHAIN (fndecl)) + { + fndecl = copy_node (fndecl); + TREE_CHAIN (fndecl) = NULL_TREE; + } + + if (DECL_CONSTRUCTOR_P (fndecl)) + grok_ctor_properties (current_class_type, fndecl); + else if (IDENTIFIER_OPNAME_P (DECL_NAME (fndecl))) + grok_op_properties (fndecl, DECL_VIRTUAL_P (fndecl)); + } + + finish_decl (fndecl, NULL_TREE, NULL_TREE, 0); + + /* Make a place for the parms */ + pushlevel (0); + current_binding_level->parm_flag = 1; + + DECL_IN_AGGR_P (fndecl) = 1; + return fndecl; +} + +/* Go through the motions of finishing a function definition. + We don't compile this method until after the whole class has + been processed. + + FINISH_METHOD must return something that looks as though it + came from GROKFIELD (since we are defining a method, after all). + + This is called after parsing the body of the function definition. + STMTS is the chain of statements that makes up the function body. + + DECL is the ..._DECL that `start_method' provided. */ + +tree +finish_method (decl) + tree decl; +{ + register tree fndecl = decl; + tree old_initial; + tree context = DECL_CONTEXT (fndecl); + + register tree link; + + if (TYPE_MAIN_VARIANT (decl) == void_type_node) + return decl; + +#ifdef DEBUG_CP_BINDING_LEVELS + indent_to (stderr, debug_bindings_indentation); + fprintf (stderr, "finish_method"); + debug_bindings_indentation += 4; +#endif + + old_initial = DECL_INITIAL (fndecl); + + /* Undo the level for the parms (from start_method). + This is like poplevel, but it causes nothing to be + saved. Saving information here confuses symbol-table + output routines. Besides, this information will + be correctly output when this method is actually + compiled. */ + + /* Clear out the meanings of the local variables of this level; + also record in each decl which block it belongs to. */ + + for (link = current_binding_level->names; link; link = TREE_CHAIN (link)) + { + if (DECL_NAME (link) != NULL_TREE) + IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0; + my_friendly_assert (TREE_CODE (link) != FUNCTION_DECL, 163); + DECL_CONTEXT (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); + for (link = current_binding_level->class_shadowed; + link; link = TREE_CHAIN (link)) + IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + for (link = current_binding_level->type_shadowed; + link; link = TREE_CHAIN (link)) + IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + + GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level, + (HOST_WIDE_INT) current_binding_level->level_chain, + current_binding_level->parm_flag, + current_binding_level->keep, + current_binding_level->tag_transparent); + + pop_binding_level (); + + DECL_INITIAL (fndecl) = old_initial; +#if 0 + /* tiemann would like this, but is causes String.cc to not compile. */ + if (DECL_FRIEND_P (fndecl) || DECL_CONTEXT (fndecl) != current_class_type) +#else + if (DECL_FRIEND_P (fndecl)) +#endif + { + CLASSTYPE_INLINE_FRIENDS (current_class_type) + = tree_cons (NULL_TREE, fndecl, CLASSTYPE_INLINE_FRIENDS (current_class_type)); + decl = void_type_node; + } +#if 0 + /* Work in progress, 9/17/92. */ + else if (context != current_class_type + && TREE_CHAIN (context) != NULL_TREE + && !DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl))) + { + /* Don't allow them to declare a function like this: + class A { + public: + class B { + public: + int f(); + }; + int B::f() {} + }; + + Note we can get in here if it's a friend (in which case we'll + avoid lots of nasty cruft), or it's a destructor. Compensate. + */ + tree tmp = DECL_ARGUMENTS (TREE_CHAIN (context)); + if (tmp + && TREE_CODE (tmp) == IDENTIFIER_NODE + && TREE_CHAIN (IDENTIFIER_GLOBAL_VALUE (tmp)) + && TREE_CODE (TREE_CHAIN (IDENTIFIER_GLOBAL_VALUE (tmp))) == TYPE_DECL) + { + error_with_decl (decl, + "qualified name used in declaration of `%s'"); + /* Make this node virtually unusable in the end. */ + TREE_CHAIN (decl) = NULL_TREE; + } + } +#endif + +#ifdef DEBUG_CP_BINDING_LEVELS + debug_bindings_indentation -= 4; +#endif + + return decl; +} + +/* Called when a new struct TYPE is defined. + If this structure or union completes the type of any previous + variable declaration, lay it out and output its rtl. */ + +void +hack_incomplete_structures (type) + tree type; +{ + tree decl; + + if (current_binding_level->n_incomplete == 0) + 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 = global_binding_level == current_binding_level; + 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) + { + expand_decl (decl); + expand_decl_cleanup (decl, maybe_build_cleanup (decl)); + expand_decl_init (decl); + } + } + my_friendly_assert (current_binding_level->n_incomplete > 0, 164); + --current_binding_level->n_incomplete; + } +} + +/* 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. + + Don't build these on the momentary obstack; they must live + the life of the binding contour. */ +tree +maybe_build_cleanup (decl) + tree decl; +{ + tree type = TREE_TYPE (decl); + if (TYPE_NEEDS_DESTRUCTOR (type)) + { + 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 (); + + if (TREE_CODE (type) == ARRAY_TYPE) + rval = decl; + else + { + mark_addressable (decl); + rval = build_unary_op (ADDR_EXPR, decl, 0); + } + + /* Optimize for space over speed here. */ + if (! TYPE_USES_VIRTUAL_BASECLASSES (type) + || flag_expensive_optimizations) + flags |= LOOKUP_NONVIRTUAL; + + /* Use TYPE_MAIN_VARIANT so we don't get a warning about + calling delete on a `const' variable. */ + if (TYPE_READONLY (TREE_TYPE (TREE_TYPE (rval)))) + rval = build1 (NOP_EXPR, TYPE_POINTER_TO (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (rval)))), rval); + + rval = build_delete (TREE_TYPE (rval), rval, integer_two_node, flags, 0, 0); + + if (TYPE_USES_VIRTUAL_BASECLASSES (type) + && ! TYPE_HAS_DESTRUCTOR (type)) + rval = build_compound_expr (tree_cons (NULL_TREE, rval, + build_tree_list (NULL_TREE, build_vbase_delete (type, decl)))); + + current_binding_level->have_cleanups = 1; + current_binding_level->more_exceptions_ok = 0; + + if (TREE_CODE (decl) != PARM_DECL) + resume_momentary (temp); + + building_cleanup = old_building_cleanup; + + return rval; + } + return 0; +} + +/* Expand a C++ expression at the statement level. + This is needed to ferret out nodes which have UNKNOWN_TYPE. + The C++ type checker should get all of these out when + expressions are combined with other, type-providing, expressions, + leaving only orphan expressions, such as: + + &class::bar; / / takes its address, but does nothing with it. + + */ +void +cplus_expand_expr_stmt (exp) + tree exp; +{ + if (TREE_TYPE (exp) == unknown_type_node) + { + if (TREE_CODE (exp) == ADDR_EXPR || TREE_CODE (exp) == TREE_LIST) + error ("address of overloaded function with no contextual type information"); + else if (TREE_CODE (exp) == COMPONENT_REF) + warning ("useless reference to a member function name, did you forget the ()?"); + } + else + { + int remove_implicit_immediately = 0; + + if (TREE_CODE (exp) == FUNCTION_DECL) + { + warning_with_decl (exp, "reference, not call, to function `%s'"); + warning ("at this point in file"); + } + if (TREE_RAISES (exp)) + { + my_friendly_assert (flag_handle_exceptions, 165); + if (flag_handle_exceptions == 2) + { + if (! current_binding_level->more_exceptions_ok) + { + extern struct nesting *nesting_stack, *block_stack; + + remove_implicit_immediately + = (nesting_stack != block_stack); + cplus_expand_start_try (1); + } + current_binding_level->have_exceptions = 1; + } + } + + expand_expr_stmt (break_out_cleanups (exp)); + + if (remove_implicit_immediately) + pop_implicit_try_blocks (NULL_TREE); + } + + /* Clean up any pending cleanups. This happens when a function call + returns a cleanup-needing value that nobody uses. */ + expand_cleanups_to (NULL_TREE); +} + +/* When a stmt has been parsed, this function is called. + + Currently, this function only does something within a + constructor's scope: if a stmt has just assigned to this, + and we are in a derived class, we call `emit_base_init'. */ + +void +finish_stmt () +{ + extern struct nesting *cond_stack, *loop_stack, *case_stack; + + + if (current_function_assigns_this + || ! current_function_just_assigned_this) + return; + if (DECL_CONSTRUCTOR_P (current_function_decl)) + { + /* Constructors must wait until we are out of control + zones before calling base constructors. */ + if (cond_stack || loop_stack || case_stack) + return; + emit_insns (base_init_insns); + check_base_init (current_class_type); + } + current_function_assigns_this = 1; + + if (flag_cadillac) + cadillac_finish_stmt (); +} + +void +pop_implicit_try_blocks (decl) + tree decl; +{ + if (decl) + { + my_friendly_assert (current_binding_level->parm_flag == 3, 166); + current_binding_level->names = TREE_CHAIN (decl); + } + + while (current_binding_level->parm_flag == 3) + { + tree name = get_identifier ("(compiler error)"); + tree orig_ex_type = current_exception_type; + tree orig_ex_decl = current_exception_decl; + tree orig_ex_obj = current_exception_object; + tree decl = cplus_expand_end_try (2); + + /* @@ It would be nice to make all these point + to exactly the same handler. */ + /* Start hidden EXCEPT. */ + cplus_expand_start_except (name, decl); + /* reraise ALL. */ + cplus_expand_reraise (NULL_TREE); + current_exception_type = orig_ex_type; + current_exception_decl = orig_ex_decl; + current_exception_object = orig_ex_obj; + /* This will reraise for us. */ + cplus_expand_end_except (error_mark_node); + } + + if (decl) + { + TREE_CHAIN (decl) = current_binding_level->names; + current_binding_level->names = decl; + } +} + +/* Push a cleanup onto the current binding contour that will cause + ADDR to be cleaned up, in the case that an exception propagates + through its binding contour. */ + +void +push_exception_cleanup (addr) + tree addr; +{ + tree decl = build_decl (VAR_DECL, get_identifier (EXCEPTION_CLEANUP_NAME), ptr_type_node); + tree cleanup; + + decl = pushdecl (decl); + DECL_REGISTER (decl) = 1; + store_init_value (decl, addr); + expand_decl (decl); + expand_decl_init (decl); + + cleanup = build (COND_EXPR, integer_type_node, + build (NE_EXPR, integer_type_node, + decl, integer_zero_node), + build_delete (TREE_TYPE (addr), decl, + lookup_name (in_charge_identifier, 0), + LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0, 0), + integer_zero_node); + expand_decl_cleanup (decl, cleanup); +} + +/* For each binding contour, emit code that deactivates the + exception cleanups. All other cleanups are left as they were. */ + +static void +deactivate_exception_cleanups () +{ + struct binding_level *b = current_binding_level; + tree xyzzy = get_identifier (EXCEPTION_CLEANUP_NAME); + while (b != class_binding_level) + { + if (b->parm_flag == 3) + { + tree decls = b->names; + while (decls) + { + if (DECL_NAME (decls) == xyzzy) + expand_assignment (decls, integer_zero_node, 0, 0); + decls = TREE_CHAIN (decls); + } + } + b = b->level_chain; + } +} + +/* Change a static member function definition into a FUNCTION_TYPE, instead + of the METHOD_TYPE that we create when it's originally parsed. */ +void +revert_static_member_fn (fn, decl, argtypes) + tree *fn, *decl, *argtypes; +{ + tree tmp, function = *fn; + + *argtypes = TREE_CHAIN (*argtypes); + tmp = build_function_type (TREE_TYPE (function), *argtypes); + tmp = build_type_variant (tmp, TYPE_READONLY (function), + TYPE_VOLATILE (function)); + tmp = build_exception_variant (TYPE_METHOD_BASETYPE (function), tmp, + TYPE_RAISES_EXCEPTIONS (function)); + TREE_TYPE (*decl) = tmp; + *fn = tmp; + DECL_STATIC_FUNCTION_P (*decl) = 1; +} |
