diff options
Diffstat (limited to 'gnu/usr.bin/cc/cc1plus/decl.c')
-rw-r--r-- | gnu/usr.bin/cc/cc1plus/decl.c | 12030 |
1 files changed, 12030 insertions, 0 deletions
diff --git a/gnu/usr.bin/cc/cc1plus/decl.c b/gnu/usr.bin/cc/cc1plus/decl.c new file mode 100644 index 0000000..0690340 --- /dev/null +++ b/gnu/usr.bin/cc/cc1plus/decl.c @@ -0,0 +1,12030 @@ +/* Process declarations and variables for C compiler. + Copyright (C) 1988, 1992, 1993, 1994 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 "decl.h" +#include "lex.h" +#include <sys/types.h> +#include <signal.h> +#include "obstack.h" + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +extern tree builtin_return_address_fndecl; + +extern struct obstack permanent_obstack; + +extern int current_class_depth; + +extern tree cleanups_this_call; + +/* 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; + +#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 void grok_op_properties PROTO((tree, int, int)); + +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; + +/* The bool data type, and constants */ +tree bool_type_node, true_node, false_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 delta_type_node; +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 opaque_type_node, signature_type_node; +tree sigtable_entry_type; +tree maybe_gc_cleanup; + +/* Array type `vtable_entry_type[]' */ +tree vtbl_type_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 `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; +/* Used in pointer to member functions, and in vtables. */ +tree pfn_identifier, index_identifier, delta_identifier, delta2_identifier; +tree pfn_or_delta2_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; + +/* -- 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; + +/* Nonzero means that there was overflow computing enum_next_value. */ + +static int enum_overflow; + +/* 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; + +/* 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 disable GNU extensions. */ + +extern int flag_ansi; + +/* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes) + objects. */ +extern int flag_huge_objects; + +/* Nonzero if we want to conserve space in the .o files. We do this + by putting uninitialized data and runtime initialized data into + .common instead of .data at the expense of not flaging multiple + definitions. */ +extern int flag_conserve_space; + +/* 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 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 spew.c */ + +extern int spew_debug; + +/* This is a copy of the class_shadowed list of the previous class binding + contour when at global scope. It's used to reset IDENTIFIER_CLASS_VALUEs + when entering another class scope (i.e. a cache miss). */ +extern tree previous_class_values; + + +/* 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)); +} + +/* 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 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 defined(DEBUG_CP_BINDING_LEVELS) + /* Binding depth at which this level began. */ + unsigned binding_depth; +#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ + }; + +#define NULL_BINDING_LEVEL ((struct binding_level *) NULL) + +/* The (non-class) 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; + +/* The current (class or non-class) binding level currently in effect. */ + +#define inner_binding_level \ + (class_binding_level ? class_binding_level : current_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 defined(DEBUG_CP_BINDING_LEVELS) +static int binding_depth = 0; +static int is_class_level = 0; + +static void +indent () +{ + register unsigned i; + + for (i = 0; i < binding_depth*2; i++) + putc (' ', stderr); +} +#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ + +static tree pushdecl_with_scope PROTO((tree, struct binding_level *)); + +static void +push_binding_level (newlevel, tag_transparent, keep) + struct binding_level *newlevel; + int tag_transparent, keep; +{ + /* Add this level to the front of the chain (stack) of levels that + are active. */ + *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->keep = keep; +#if defined(DEBUG_CP_BINDING_LEVELS) + newlevel->binding_depth = binding_depth; + indent (); + fprintf (stderr, "push %s level 0x%08x line %d\n", + (is_class_level) ? "class" : "block", newlevel, lineno); + is_class_level = 0; + binding_depth++; +#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ +} + +static void +pop_binding_level () +{ + if (class_binding_level) + current_binding_level = class_binding_level; + + 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. */ +#if defined(DEBUG_CP_BINDING_LEVELS) + binding_depth--; + indent (); + fprintf (stderr, "pop %s level 0x%08x line %d\n", + (is_class_level) ? "class" : "block", + current_binding_level, lineno); + if (is_class_level != (current_binding_level == class_binding_level)) +#if 0 /* XXX Don't abort when we're watching how things are being managed. */ + abort (); +#else + { + indent (); + fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n"); + } +#endif + is_class_level = 0; +#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ + { + register struct binding_level *level = current_binding_level; + current_binding_level = current_binding_level->level_chain; + level->level_chain = free_binding_level; +#if 0 /* defined(DEBUG_CP_BINDING_LEVELS) */ + if (level->binding_depth != binding_depth) + abort (); +#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ + free_binding_level = level; + + class_binding_level = current_binding_level; + if (class_binding_level->parm_flag != 2) + class_binding_level = 0; + while (current_binding_level->parm_flag == 2) + current_binding_level = current_binding_level->level_chain; + } +} + +/* 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; +} + +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; +} + +void +set_class_shadows (shadows) + tree shadows; +{ + class_binding_level->class_shadowed = shadows; +} + +/* 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; + + /* 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 defined(DEBUG_CP_BINDING_LEVELS) + if (0) +#else /* !defined(DEBUG_CP_BINDING_LEVELS) */ + if (free_binding_level) +#endif /* !defined(DEBUG_CP_BINDING_LEVELS) */ + { + 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 ((HOST_WIDE_INT) newlevel); + keep_next_level_flag = 0; +} + +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; + + 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 + { + push_function_context (); + output_inline_function (decl); + pop_function_context (); + } + } + + /* 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; + /* If we created the block earlier on, and we are just diddling it now, + then it already should have a proper BLOCK_END_NOTE value associated + with it, so avoid trashing that. Otherwise, for a new block, install + a new BLOCK_END_NOTE value. */ + if (! block_previously_created) + remember_end_note (block); + } + + /* 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) + { + cp_error_at ("label `%D' used but not defined", label); + /* Avoid crashing later. */ + define_label (input_filename, 1, DECL_NAME (label)); + } + else if (warn_unused && !TREE_USED (label)) + cp_warning_at ("label `%D' defined but not used", label); + SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), NULL_TREE); + + /* 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) + { +#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); + /* Each and every BLOCK node created here in `poplevel' is important + (e.g. for proper debugging information) so if we created one + earlier, mark it as "used". */ + if (block) + TREE_USED (block) = 1; + block = poplevel (keep, reverse, real_functionbody); + } + + /* Each and every BLOCK node created here in `poplevel' is important + (e.g. for proper debugging information) so if we created one + earlier, mark it as "used". */ + if (block) + TREE_USED (block) = 1; + return block; +} + +/* 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 () +{ + register struct binding_level *newlevel; + + /* Reuse or create a struct for this binding level. */ +#if defined(DEBUG_CP_BINDING_LEVELS) + if (0) +#else /* !defined(DEBUG_CP_BINDING_LEVELS) */ + if (free_binding_level) +#endif /* !defined(DEBUG_CP_BINDING_LEVELS) */ + { + 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)); + } + +#if defined(DEBUG_CP_BINDING_LEVELS) + is_class_level = 1; +#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ + + push_binding_level (newlevel, 0, 0); + + decl_stack = push_decl_level (decl_stack, &decl_obstack); + class_binding_level = current_binding_level; + class_binding_level->parm_flag = 2; + /* We have just pushed into a new binding level. Now, fake out the rest + of the compiler. Set the `current_binding_level' back to point to + the most closely containing non-class binding level. */ + do + { + current_binding_level = current_binding_level->level_chain; + } + while (current_binding_level->parm_flag == 2); +} + +/* ...and a poplevel for class declarations. FORCE is used to force + clearing out of CLASS_VALUEs after a class definition. */ +tree +poplevel_class (force) + int force; +{ + register struct binding_level *level = class_binding_level; + tree block = NULL_TREE; + tree shadowed; + + my_friendly_assert (level != 0, 354); + + decl_stack = pop_stack_level (decl_stack); + for (shadowed = level->shadowed; shadowed; shadowed = TREE_CHAIN (shadowed)) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed); + /* If we're leaving a toplevel class, don't bother to do the setting + of IDENTIFER_CLASS_VALUE to NULL_TREE, since first of all this slot + shouldn't even be used when current_class_type isn't set, and second, + if we don't touch it here, we're able to use the caching effect if the + next time we're entering a class scope, it is the same class. */ + if (current_class_depth != 1 || force) + for (shadowed = level->class_shadowed; + shadowed; + shadowed = TREE_CHAIN (shadowed)) + IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed); + else + /* Remember to save what IDENTIFIER's were bound in this scope so we + can recover from cache misses. */ + previous_class_values = class_binding_level->class_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); + + if (class_binding_level->parm_flag != 2) + class_binding_level = (struct binding_level *)0; + + /* Now, pop out of the the binding level which we created up in the + `pushlevel_class' routine. */ +#if defined(DEBUG_CP_BINDING_LEVELS) + is_class_level = 1; +#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ + + pop_binding_level (); + + 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"); + 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; + tree previous_class_type; + tree *lang_base, *lang_stack, lang_name; + int lang_stacksize; + tree named_labels; +}; +static struct saved_scope *current_saved_scope; +extern tree prev_class_type; + +void +push_to_top_level () +{ + extern int current_lang_stacksize; + struct saved_scope *s = + (struct saved_scope *) xmalloc (sizeof (struct saved_scope)); + struct binding_level *b = current_binding_level; + tree old_bindings = NULL_TREE; + + /* Have to include global_binding_level, because class-level decls + aren't listed anywhere useful. */ + for (; b; b = b->level_chain) + { + tree t; + + if (b == global_binding_level) + continue; + + for (t = b->names; t; t = TREE_CHAIN (t)) + { + 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; + } + TREE_CHAIN (binding) = old_bindings; + old_bindings = binding; + skip_it: + ; + } + /* Unwind type-value slots back to top level. */ + for (t = b->type_shadowed; t; t = TREE_CHAIN (t)) + SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (t), TREE_VALUE (t)); + } + /* Clear out class-level bindings cache. */ + if (current_binding_level == global_binding_level + && previous_class_type != NULL_TREE) + { + popclass (-1); + previous_class_type = NULL_TREE; + } + + 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; + s->previous_class_type = previous_class_type; + s->lang_stack = current_lang_stack; + s->lang_base = current_lang_base; + s->lang_stacksize = current_lang_stacksize; + s->lang_name = current_lang_name; + s->named_labels = named_labels; + current_class_name = current_class_type = current_class_decl = NULL_TREE; + current_function_decl = NULL_TREE; + class_binding_level = (struct binding_level *)0; + previous_class_type = NULL_TREE; + current_lang_stacksize = 10; + current_lang_stack = current_lang_base + = (tree *) xmalloc (current_lang_stacksize * sizeof (tree)); + current_lang_name = lang_name_cplusplus; + strict_prototype = strict_prototypes_lang_cplusplus; + named_labels = NULL_TREE; + + s->prev = current_saved_scope; + s->old_bindings = old_bindings; + current_saved_scope = s; +} + +void +pop_from_top_level () +{ + extern int current_lang_stacksize; + struct saved_scope *s = current_saved_scope; + tree t; + + if (previous_class_type) + previous_class_type = NULL_TREE; + + 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; + previous_class_type = s->previous_class_type; + free (current_lang_base); + current_lang_base = s->lang_base; + current_lang_stack = s->lang_stack; + current_lang_name = s->lang_name; + current_lang_stacksize = s->lang_stacksize; + if (current_lang_name == lang_name_cplusplus) + strict_prototype = strict_prototypes_lang_cplusplus; + else if (current_lang_name == lang_name_c) + strict_prototype = strict_prototypes_lang_c; + named_labels = s->named_labels; + + free (s); +} + +/* Push a definition of struct, union or enum tag "name". + into binding_level "b". "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. */ + +static void +set_identifier_type_value_with_scope (id, type, b) + tree id; + tree type; + struct binding_level *b; +{ + if (b != global_binding_level) + { + tree old_type_value = IDENTIFIER_TYPE_VALUE (id); + b->type_shadowed + = tree_cons (id, old_type_value, b->type_shadowed); + } + SET_IDENTIFIER_TYPE_VALUE (id, type); +} + +/* As set_identifier_type_value_with_scope, but using inner_binding_level. */ + +void +set_identifier_type_value (id, type) + tree id; + tree type; +{ + set_identifier_type_value_with_scope (id, type, inner_binding_level); +} + +/* 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); + TREE_MANGLED (DECL_NESTED_TYPENAME (decl)) = 1; + + /* This is a special usage of IDENTIFIER_TYPE_VALUE which have no + correspondence in any binding_level. This is ok since the + DECL_NESTED_TYPENAME is just a convenience identifier whose + IDENTIFIER_TYPE_VALUE will remain constant from now on. */ + SET_IDENTIFIER_TYPE_VALUE (DECL_NESTED_TYPENAME (decl), type); + } + else + DECL_NESTED_TYPENAME (decl) = name; +} + +/* Pop off extraneous binding levels left over due to syntax errors. */ +void +pop_everything () +{ +#ifdef DEBUG_CP_BINDING_LEVELS + fprintf (stderr, "XXX entering pop_everything ()\n"); +#endif + while (current_binding_level != global_binding_level + && ! current_binding_level->pseudo_global) + { + if (class_binding_level) + pop_nested_class (1); + else + poplevel (0, 0, 0); + } +#ifdef DEBUG_CP_BINDING_LEVELS + fprintf (stderr, "XXX leaving pop_everything ()\n"); +#endif +} + +#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 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 + { + /* XXX: Typedef for unnamed struct; some other situations. + TYPE_NAME is null; what's right here? */ + } + return decl; +} +#endif + +/* Push a tag name NAME for struct/class/union/enum type TYPE. + Normally put into into the inner-most non-tag-tranparent scope, + but if GLOBALIZE is true, put it in the inner-most non-class scope. + The latter is needed for implicit declarations. */ + +void +pushtag (name, type, globalize) + tree name, type; + int globalize; +{ + register struct binding_level *b; + tree context = 0; + tree c_decl = 0; + + b = inner_binding_level; + while (b->tag_transparent + || (globalize && b->parm_flag == 2)) + 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) + { + context = type ? TYPE_CONTEXT (type) : NULL_TREE; + if (! context && ! globalize) + context = current_scope (); + if (context) + c_decl = TREE_CODE (context) == FUNCTION_DECL + ? context : TYPE_NAME (context); + + /* 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 + || b->parm_flag != 2 + || !CLASSTYPE_DECLARED_EXCEPTION (type))) + { + register tree d; + int newdecl = 0; + + if (b->parm_flag != 2 + || TYPE_SIZE (current_class_type) != NULL_TREE) + { + d = lookup_nested_type (type, c_decl); + + if (d == NULL_TREE) + { + newdecl = 1; +#if 0 /* not yet, should get fixed properly later */ + d = make_type_decl (name, type); +#else + d = build_decl (TYPE_DECL, name, type); +#endif +#ifdef DWARF_DEBUGGING_INFO + if (write_symbols == DWARF_DEBUG) + { + /* Mark the TYPE_DECL node we created just above as an + gratuitous one. We need to do this so that dwarfout.c + will understand that it is not supposed to output a + TAG_typedef DIE for it. */ + DECL_IGNORED_P (d) = 1; + } +#endif /* DWARF_DEBUGGING_INFO */ + set_identifier_type_value_with_scope (name, type, b); + } + 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 (b->parm_flag == 2) + d = pushdecl_class_level (d); + else + d = pushdecl_with_scope (d, b); + } + } + else + { + /* Make nested declarations go into class-level scope. */ + newdecl = 1; + d = build_decl (TYPE_DECL, name, type); +#ifdef DWARF_DEBUGGING_INFO + if (write_symbols == DWARF_DEBUG) + { + /* Mark the TYPE_DECL node we created just above as an + gratuitous one. We need to do this so that dwarfout.c + will understand that it is not supposed to output a + TAG_typedef DIE for it. */ + DECL_IGNORED_P (d) = 1; + } +#endif /* DWARF_DEBUGGING_INFO */ + /* Make sure we're in this type's scope when we push the + decl for a template, otherwise class_binding_level will + be NULL and we'll end up dying inside of + push_class_level_binding. */ + if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE) + pushclass (type, 0); + d = pushdecl_class_level (d); + if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE) + popclass (0); + } + if (write_symbols != DWARF_DEBUG) + { + if (ANON_AGGRNAME_P (name)) + DECL_IGNORED_P (d) = 1; + } + TYPE_NAME (type) = d; + + if (context == NULL_TREE) + /* Non-nested class. */ + DECL_NESTED_TYPENAME (d) = name; + else if (context && TREE_CODE (context) == FUNCTION_DECL) + { + /* Function-nested class. */ + set_nested_typename (d, DECL_ASSEMBLER_NAME (c_decl), + name, type); + /* This builds the links for classes nested in fn scope. */ + DECL_CONTEXT (d) = context; + } +/* else if (TYPE_SIZE (current_class_type) == NULL_TREE) +*/ + else if (context && IS_AGGR_TYPE (context)) + { + /* Class-nested class. */ + set_nested_typename (d, DECL_NESTED_TYPENAME (c_decl), + name, type); + /* This builds the links for classes nested in type scope. */ + DECL_CONTEXT (d) = context; + } + TYPE_CONTEXT (type) = DECL_CONTEXT (d); + if (newdecl) + DECL_ASSEMBLER_NAME (d) + = get_identifier (build_overload_name (type, 1, 1)); + } + if (b->parm_flag == 2) + { + TREE_NONLOCAL_FLAG (type) = 1; + 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 */ + tree d = make_type_decl (NULL_TREE, type); +#else + tree d = build_decl (TYPE_DECL, NULL_TREE, type); +#endif + TYPE_STUB_DECL (type) = pushdecl_with_scope (d, b); + } +} + +/* 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. + + For C++, we must compare the parameter list so that `int' can match + `int&' in a parameter position, but `int&' is not confused with + `const int&'. */ +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 (&newdecl, &f1, &p1); + else if (TREE_CODE (f2) == METHOD_TYPE + && DECL_STATIC_FUNCTION_P (newdecl)) + revert_static_member_fn (&olddecl, &f2, &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) + cp_compiler_error ("`%D' redeclared as member function", newdecl); + else + cp_compiler_error ("`%D' redeclared as non-member function", newdecl); + return 0; + } + + if (comptypes (TREE_TYPE (f1), TREE_TYPE (f2), 1)) + { + if (! strict_prototypes_lang_c && DECL_LANGUAGE (olddecl) == lang_c + && p2 == NULL_TREE) + { + types_match = self_promoting_args_p (p1); + if (p1 == void_list_node) + TREE_TYPE (newdecl) = TREE_TYPE (olddecl); + } + else if (!strict_prototypes_lang_c && DECL_LANGUAGE (olddecl)==lang_c + && DECL_LANGUAGE (newdecl) == lang_c && p1 == NULL_TREE) + { + types_match = self_promoting_args_p (p2); + TREE_TYPE (newdecl) = TREE_TYPE (olddecl); + } + else + types_match = compparms (p1, p2, 3); + } + else + types_match = 0; + } + else if (TREE_CODE (newdecl) == TEMPLATE_DECL + && TREE_CODE (olddecl) == TEMPLATE_DECL) + { + tree newargs = DECL_TEMPLATE_PARMS (newdecl); + tree oldargs = DECL_TEMPLATE_PARMS (olddecl); + int i, len = TREE_VEC_LENGTH (newargs); + + if (TREE_VEC_LENGTH (oldargs) != len) + return 0; + + for (i = 0; i < len; i++) + { + tree newarg = TREE_VEC_ELT (newargs, i); + tree oldarg = TREE_VEC_ELT (oldargs, i); + if (TREE_CODE (newarg) != TREE_CODE (oldarg)) + return 0; + else if (TREE_CODE (newarg) == IDENTIFIER_NODE) + /* continue */; + else if (! comptypes (TREE_TYPE (newarg), TREE_TYPE (oldarg), 1)) + return 0; + } + + if (DECL_TEMPLATE_IS_CLASS (newdecl) + != DECL_TEMPLATE_IS_CLASS (olddecl)) + types_match = 0; + else if (DECL_TEMPLATE_IS_CLASS (newdecl)) + types_match = 1; + else + types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl), + DECL_TEMPLATE_RESULT (newdecl)); + } + 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 if (TREE_TYPE (newdecl) == NULL_TREE) + types_match = 0; + else + types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 1); + } + + return types_match; +} + +/* If NEWDECL is `static' and an `extern' was seen previously, + warn about it. (OLDDECL may be NULL_TREE; NAME contains + information about previous usage as an `extern'.) + + Note that this does not apply to the C++ case of declaring + a variable `extern const' and then later `const'. + + Don't complain if -traditional, since traditional compilers + don't complain. + + Don't complain about built-in functions, since they are beyond + the user's control. */ + +static void +warn_extern_redeclared_static (newdecl, olddecl) + tree newdecl, olddecl; +{ + tree name; + + static char *explicit_extern_static_warning + = "`%D' was declared `extern' and later `static'"; + static char *implicit_extern_static_warning + = "`%D' was declared implicitly `extern' and later `static'"; + + if (flag_traditional + || TREE_CODE (newdecl) == TYPE_DECL + || (! warn_extern_inline + && DECL_INLINE (newdecl))) + return; + + name = DECL_ASSEMBLER_NAME (newdecl); + if (TREE_PUBLIC (name) && ! TREE_PUBLIC (newdecl)) + { + /* It's okay to redeclare an ANSI built-in function as static, + or to declare a non-ANSI built-in function as anything. */ + if (! (TREE_CODE (newdecl) == FUNCTION_DECL + && olddecl != NULL_TREE + && TREE_CODE (olddecl) == FUNCTION_DECL + && (DECL_BUILT_IN (olddecl) + || DECL_BUILT_IN_NONANSI (olddecl)))) + { + cp_warning (IDENTIFIER_IMPLICIT_DECL (name) + ? implicit_extern_static_warning + : explicit_extern_static_warning, newdecl); + if (olddecl != NULL_TREE) + cp_warning_at ("previous declaration of `%D'", olddecl); + } + } +} + +/* 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. */ + +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 = 0; + int new_defines_function; + tree previous_c_decl = NULL_TREE; + + types_match = decls_match (newdecl, olddecl); + + if (TREE_CODE (olddecl) != TREE_LIST) + olddecl_friend = DECL_LANG_SPECIFIC (olddecl) && DECL_FRIEND_P (olddecl); + + /* If either the type of the new decl or the type of the old decl is an + error_mark_node, then that implies that we have already issued an + error (earlier) for some bogus type specification, and in that case, + it is rather pointless to harass the user with yet more error message + about the same declaration, so well just pretent the types match here. */ + if ((TREE_TYPE (newdecl) + && TREE_CODE (TREE_TYPE (newdecl)) == ERROR_MARK) + || (TREE_TYPE (olddecl) + && TREE_CODE (TREE_TYPE (olddecl)) == ERROR_MARK)) + types_match = 1; + + 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) || DECL_BUILT_IN_NONANSI (olddecl))) + { + /* If you declare a built-in or predefined function name as static, + the old definition is overridden, but optionally warn this was a + bad choice of name. Ditto for overloads. */ + if (! TREE_PUBLIC (newdecl) + || (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl))) + { + if (warn_shadow) + cp_warning ("shadowing %s function `%#D'", + DECL_BUILT_IN (olddecl) ? "built-in" : "library", + olddecl); + /* Discard the old built-in function. */ + return 0; + } + else if (! types_match) + { + if (TREE_CODE (newdecl) != FUNCTION_DECL) + { + /* If the built-in is not ansi, then programs can override + it even globally without an error. */ + if (! DECL_BUILT_IN (olddecl)) + cp_warning ("library function `%#D' redeclared as non-function `%#D'", + olddecl, newdecl); + else + { + cp_error ("declaration of `%#D'", newdecl); + cp_error ("conflicts with built-in declaration `%#D'", + olddecl); + } + return 0; + } + + cp_warning ("declaration of `%#D'", newdecl); + cp_warning ("conflicts with built-in declaration `%#D'", + olddecl); + } + } + else if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) + { + if ((TREE_CODE (newdecl) == FUNCTION_DECL + && TREE_CODE (olddecl) == TEMPLATE_DECL + && ! DECL_TEMPLATE_IS_CLASS (olddecl)) + || (TREE_CODE (olddecl) == FUNCTION_DECL + && TREE_CODE (newdecl) == TEMPLATE_DECL + && ! DECL_TEMPLATE_IS_CLASS (newdecl))) + return 0; + + cp_error ("`%#D' redeclared as different kind of symbol", newdecl); + if (TREE_CODE (olddecl) == TREE_LIST) + olddecl = TREE_VALUE (olddecl); + cp_error_at ("previous declaration of `%#D'", olddecl); + + /* New decl is completely inconsistent with the old one => + tell caller to replace the old one. */ + + return 0; + } + else if (!types_match) + { + if (TREE_CODE (newdecl) == TEMPLATE_DECL) + { + /* The name of a class template may not be declared to refer to + any other template, class, function, object, namespace, value, + or type in the same scope. */ + if (DECL_TEMPLATE_IS_CLASS (olddecl) + || DECL_TEMPLATE_IS_CLASS (newdecl)) + { + cp_error ("declaration of template `%#D'", newdecl); + cp_error_at ("conflicts with previous declaration `%#D'", + olddecl); + } + return 0; + } + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + if (DECL_LANGUAGE (newdecl) == lang_c + && DECL_LANGUAGE (olddecl) == lang_c) + { + cp_error ("declaration of C function `%#D' conflicts with", + newdecl); + cp_error_at ("previous declaration `%#D' here", olddecl); + } + + if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), + TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 2)) + { + cp_error ("new declaration `%#D'", newdecl); + cp_error_at ("ambiguates old declaration `%#D'", olddecl); + } + else + return 0; + } + + /* Already complained about this, so don't do so again. */ + else if (current_class_type == NULL_TREE + || IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (newdecl)) != current_class_type) + { + /* Since we're doing this before finish_struct can set the + line number on NEWDECL, we just do a regular error here. */ + if (DECL_SOURCE_LINE (newdecl) == 0) + cp_error ("conflicting types for `%#D'", newdecl); + else + cp_error_at ("conflicting types for `%#D'", newdecl); + cp_error_at ("previous declaration as `%#D'", olddecl); + } + } + else + { + char *errmsg = redeclaration_error_message (newdecl, olddecl); + if (errmsg) + { + cp_error (errmsg, newdecl); + if (DECL_NAME (olddecl) != NULL_TREE) + cp_error_at ((DECL_INITIAL (olddecl) + && current_binding_level == global_binding_level) + ? "`%#D' previously defined here" + : "`%#D' previously declared here", olddecl); + } + 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. */ + cp_warning_at ("prototype for `%#D'", newdecl); + cp_warning_at ("follows non-prototype definition here", olddecl); + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl)) + { + /* extern "C" int foo (); + int foo () { bar (); } + is OK. */ + if (current_lang_stack == current_lang_base) + DECL_LANGUAGE (newdecl) = DECL_LANGUAGE (olddecl); + else + { + cp_error_at ("previous declaration of `%#D' with %L linkage", + olddecl, DECL_LANGUAGE (olddecl)); + cp_error ("conflicts with new declaration with %L linkage", + DECL_LANGUAGE (newdecl)); + } + } + + /* These bits are logically part of the type. */ + if (pedantic + && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl) + || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))) + cp_error_at ("type qualifiers for `%D' conflict with previous decl", + newdecl); + } + + /* If new decl is `static' and an `extern' was seen previously, + warn about it. */ + warn_extern_redeclared_static (newdecl, olddecl); + + /* We have committed to returning 1 at this point. */ + 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_NEXT_METHOD (newdecl) == NULL_TREE) + DECL_NEXT_METHOD (newdecl) = DECL_NEXT_METHOD (olddecl); + if (DECL_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0) + DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl); + } + + /* Deal with C++: must preserve virtual function table size. */ + if (TREE_CODE (olddecl) == TYPE_DECL) + { + register tree newtype = TREE_TYPE (newdecl); + register tree oldtype = TREE_TYPE (olddecl); + + if (newtype != error_mark_node && oldtype != error_mark_node + && TYPE_LANG_SPECIFIC (newtype) && TYPE_LANG_SPECIFIC (oldtype)) + { + CLASSTYPE_VSIZE (newtype) = CLASSTYPE_VSIZE (oldtype); + CLASSTYPE_FRIEND_CLASSES (newtype) + = CLASSTYPE_FRIEND_CLASSES (oldtype); + } +#if 0 + /* why assert here? Just because debugging information is + messed up? (mrs) */ + /* it happens on something like: + typedef struct Thing { + Thing(); + int x; + } Thing; + */ + 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_ARTIFICIAL (olddecl) + && !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE) + /* Don't warn about extern decl followed by (tentative) definition. */ + && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))) + { + cp_warning ("redundant redeclaration of `%D' in same scope", newdecl); + cp_warning ("previous declaration of `%D'", olddecl); + } + + /* 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)); + + /* Make sure we put the new type in the same obstack as the old ones. + If the old types are not both in the same obstack, use the permanent + one. */ + if (oldtype && TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype)) + push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype)); + else + { + push_obstacks_nochange (); + end_temporary_allocation (); + } + + 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)) + { + cp_error ("declaration of `%D' raises different exceptions...", + newdecl); + cp_error_at ("...from previous declaration here", olddecl); + } + } + 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 + && TREE_CODE (newdecl) != TEMPLATE_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 (olddecl) != NULL_TREE) + { + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl); + DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl); + } + + /* Merge the section attribute. + We want to issue an error if the sections conflict but that must be + done later in decl_attributes since we are called before attributes + are assigned. */ + if (DECL_SECTION_NAME (newdecl) == NULL_TREE) + DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); + + /* Keep the old rtl since we can safely use it, unless it's the + call to abort() used for abstract virtuals. */ + if ((DECL_LANG_SPECIFIC (olddecl) + && !DECL_ABSTRACT_VIRTUAL_P (olddecl)) + || DECL_RTL (olddecl) != DECL_RTL (abort_fndecl)) + DECL_RTL (newdecl) = DECL_RTL (olddecl); + + pop_obstacks (); + } + /* 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); + + if (TREE_CODE (newdecl) != FUNCTION_DECL) + 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; + else if (TREE_CODE (newdecl) != FUNCTION_DECL) + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + } + + /* 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; + } + + /* 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 (! types_match) + { + DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl); + DECL_ASSEMBLER_NAME (olddecl) = DECL_ASSEMBLER_NAME (newdecl); + DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl); + DECL_RESULT (olddecl) = DECL_RESULT (newdecl); + DECL_RTL (olddecl) = DECL_RTL (newdecl); + } + 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_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); + } + } + + if (TREE_CODE (newdecl) == TEMPLATE_DECL) + { + if (DECL_TEMPLATE_INFO (olddecl)->length) + DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); + DECL_TEMPLATE_MEMBERS (newdecl) = DECL_TEMPLATE_MEMBERS (olddecl); + DECL_TEMPLATE_INSTANTIATIONS (newdecl) + = DECL_TEMPLATE_INSTANTIATIONS (olddecl); + } + + /* Now preserve various other info from the definition. */ + TREE_ADDRESSABLE (newdecl) = TREE_ADDRESSABLE (olddecl); + TREE_ASM_WRITTEN (newdecl) = TREE_ASM_WRITTEN (olddecl); + DECL_COMMON (newdecl) = DECL_COMMON (olddecl); + + /* Don't really know how much of the language-specific + values we should copy from old to new. */ + if (DECL_LANG_SPECIFIC (olddecl)) + { + DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl); + DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl); + } + + 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)); + + /* Can we safely free the storage used by newdecl? */ + +#define ROUND(x) ((x + obstack_alignment_mask (&permanent_obstack)) \ + & ~ obstack_alignment_mask (&permanent_obstack)) + + if ((char *)newdecl + ROUND (function_size) + + ROUND (sizeof (struct lang_decl)) + == 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; + + return 1; +} + +/* 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 + + if (x != current_function_decl + /* Don't change DECL_CONTEXT of virtual methods. */ + && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x)) + && ! DECL_CONTEXT (x)) + DECL_CONTEXT (x) = current_function_decl; + /* 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; + cp_error_at ("`%#D' used prior to declaration", x); + } + + else 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 (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c) + || (TREE_CODE (x) == TEMPLATE_DECL + && ! DECL_TEMPLATE_IS_CLASS (x))) + && is_overloaded_fn (t)) + /* don't do anything just yet */; + else if (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 (duplicate_decls (x, t)) + { +#if 0 + /* This is turned off until I have time to do it right (bpk). */ + + /* Also warn if they did a prototype with `static' on it, but + then later left the `static' off. */ + if (! TREE_PUBLIC (name) && TREE_PUBLIC (x)) + { + if (DECL_LANG_SPECIFIC (t) && DECL_FRIEND_P (t)) + return t; + + if (extra_warnings) + { + cp_warning ("`static' missing from declaration of `%D'", + t); + warning_with_file_and_line (file, line, + "previous declaration of `%s'", + decl_as_string (t, 0)); + } + + /* Now fix things so it'll do what they expect. */ + if (current_function_decl) + TREE_PUBLIC (current_function_decl) = 0; + } + /* Due to interference in memory reclamation (X may be + obstack-deallocated at this point), we must guard against + one really special case. [jason: This should be handled + by start_function] */ + if (current_function_decl == x) + current_function_decl = t; +#endif + if (TREE_CODE (t) == TYPE_DECL) + SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (t)); + + return t; + } + } + + if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x)) + { + t = push_overloaded_decl (x, 1); + if (t != x || DECL_LANGUAGE (x) == lang_c) + return t; + } + else if (TREE_CODE (x) == TEMPLATE_DECL && ! DECL_TEMPLATE_IS_CLASS (x)) + return push_overloaded_decl (x, 0); + + /* If declaring a type as a typedef, and the type has no known + typedef name, install this TYPE_DECL as its typedef name. */ + if (TREE_CODE (x) == TYPE_DECL) + { + tree type = TREE_TYPE (x); + tree name = (type != error_mark_node) ? TYPE_NAME (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 (type) = 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), 0); + } + } + 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), type); + + if (type != error_mark_node + && TYPE_NAME (type) + && TYPE_IDENTIFIER (type)) + set_identifier_type_value_with_scope (DECL_NAME (x), type, b); + } + + /* Multiple external decls of the same identifier ought to match. + + We get warnings about inline functions where they are defined. + We get warnings about other functions from push_overloaded_decl. + + Avoid duplicate warnings where they are used. */ + if (TREE_PUBLIC (x) && TREE_CODE (x) != FUNCTION_DECL) + { + tree decl; + + if (IDENTIFIER_GLOBAL_VALUE (name) != NULL_TREE + && (DECL_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name)) + || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name)))) + decl = IDENTIFIER_GLOBAL_VALUE (name); + else + decl = NULL_TREE; + + if (decl + /* If different sort of thing, we already gave an error. */ + && TREE_CODE (decl) == TREE_CODE (x) + && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl), 1)) + { + cp_pedwarn ("type mismatch with previous external decl", x); + cp_pedwarn_at ("previous external decl of `%#D'", decl); + } + } + + /* 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) + IDENTIFIER_GLOBAL_VALUE (name) = x; + + /* 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)) + cp_warning + ("`%D' was previously implicitly declared to return `int'", x); + + /* If new decl is `static' and an `extern' was seen previously, + warn about it. */ + if (x != NULL_TREE && t != NULL_TREE && decls_match (x, t)) + warn_extern_redeclared_static (x, t); + } + else + { + /* Here to install a non-global value. */ + tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); + tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name); + + b->shadowed = tree_cons (name, oldlocal, b->shadowed); + IDENTIFIER_LOCAL_VALUE (name) = x; + + /* If this is a TYPE_DECL, push it into the type value slot. */ + if (TREE_CODE (x) == TYPE_DECL) + set_identifier_type_value_with_scope (name, TREE_TYPE (x), b); + + /* 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)) + { + cp_warning ("extern declaration of `%#D' doesn't match", x); + cp_warning_at ("global declaration `%#D'", oldglobal); + } + 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_FRAME_SIZE (x) = DECL_FRAME_SIZE (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_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) + cp_error ("declaration of `%#D' shadows a parameter", name); + } + /* Maybe warn if shadowing something else. */ + else if (warn_shadow && !DECL_EXTERNAL (x) + /* No shadow warnings for internally generated vars. */ + && ! DECL_ARTIFICIAL (x) + /* 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 + && !TREE_STATIC (name)) + 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 + && 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) + { + if (current_class_name) + { + if (! TREE_MANGLED (name)) + set_nested_typename (x, current_class_name, DECL_NAME (x), + TREE_TYPE (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; +} + +/* Same as pushdecl, but define X in binding-level LEVEL. */ + +static tree +pushdecl_with_scope (x, level) + tree x; + struct binding_level *level; +{ + register struct binding_level *b = current_binding_level; + + current_binding_level = level; + x = pushdecl (x); + current_binding_level = b; + return x; +} + +/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, + if appropriate. */ +tree +pushdecl_top_level (x) + tree x; +{ + register struct binding_level *b = inner_binding_level; + register tree t = pushdecl_with_scope (x, global_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) + { + if (TYPE_BEING_DEFINED (current_class_type)) + { + /* Check for inconsistent use of this name in the class body. + Types, enums, and static vars are checked here; other + members are checked in finish_struct. */ + tree icv = IDENTIFIER_CLASS_VALUE (name); + + if (icv + /* Don't complain about inherited names. */ + && id_in_current_class (name) + /* Or shadowed tags. */ + && !(TREE_CODE (icv) == TYPE_DECL + && DECL_CONTEXT (icv) == current_class_type)) + { + cp_error ("declaration of identifier `%D' as `%#D'", name, x); + cp_error_at ("conflicts with previous use in class as `%#D'", + icv); + } + } + + push_class_level_binding (name, x); + if (TREE_CODE (x) == TYPE_DECL) + { + set_identifier_type_value (name, TREE_TYPE (x)); + if (!DECL_NESTED_TYPENAME (x)) + set_nested_typename (x, current_class_name, name, TREE_TYPE (x)); + } + } + return x; +} + +/* This function is used to push the mangled decls for nested types into + the appropriate scope. Previously pushdecl_top_level was used, but that + is incorrect for members of local classes. */ +tree +pushdecl_nonclass_level (x) + tree x; +{ + struct binding_level *b = current_binding_level; + +#if 0 + /* Get out of class scope -- this isn't necessary, because class scope + doesn't make it into current_binding_level. */ + while (b->parm_flag == 2) + b = b->level_chain; +#else + my_friendly_assert (b->parm_flag != 2, 180); +#endif + + /* Get out of template binding levels */ + while (b->pseudo_global) + b = b->level_chain; + + pushdecl_with_scope (x, b); +} + +/* Make the declaration(s) of X appear in CLASS scope + under the name NAME. */ +void +push_class_level_binding (name, x) + tree name; + tree x; +{ + maybe_push_cache_obstack (); + class_binding_level->class_shadowed + = tree_cons (name, IDENTIFIER_CLASS_VALUE (name), + class_binding_level->class_shadowed); + pop_obstacks (); + IDENTIFIER_CLASS_VALUE (name) = x; + obstack_ptr_grow (&decl_obstack, 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 the value of the identifier 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 old; + int doing_global = (global_bindings_p () || ! forgettable + || flag_traditional || pseudo_global_level_p ()); + + if (doing_global) + { + old = IDENTIFIER_GLOBAL_VALUE (orig_name); + if (old && TREE_CODE (old) == FUNCTION_DECL + && DECL_ARTIFICIAL (old) + && (DECL_BUILT_IN (old) || DECL_BUILT_IN_NONANSI (old))) + { + if (duplicate_decls (decl, old)) + return old; + old = NULL_TREE; + } + } + else + { + old = IDENTIFIER_LOCAL_VALUE (orig_name); + + if (! purpose_member (orig_name, current_binding_level->shadowed)) + { + current_binding_level->shadowed + = tree_cons (orig_name, old, current_binding_level->shadowed); + old = NULL_TREE; + } + } + + if (old) + { +#if 0 + /* 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 (old) == ADDR_EXPR) + old = TREE_OPERAND (old, 0); + else +#endif + if (TREE_CODE (old) == VAR_DECL) + { + cp_error_at ("previous non-function declaration `%#D'", old); + cp_error ("conflicts with function declaration `%#D'", decl); + return error_mark_node; + } + else if (TREE_CODE (old) == TYPE_DECL) + { + tree t = TREE_TYPE (old); + if (IS_AGGR_TYPE (t) && warn_shadow) + cp_warning ("`%#D' hides constructor for `%#T'", decl, t); + old = NULL_TREE; + } + else if (is_overloaded_fn (old)) + { + tree tmp; + + for (tmp = get_first_fn (old); tmp; tmp = DECL_CHAIN (tmp)) + if (decl == tmp || duplicate_decls (decl, tmp)) + return tmp; + } + } + + if (old || TREE_CODE (decl) == TEMPLATE_DECL) + { + if (old && is_overloaded_fn (old)) + DECL_CHAIN (decl) = get_first_fn (old); + else + DECL_CHAIN (decl) = NULL_TREE; + old = tree_cons (orig_name, decl, NULL_TREE); + TREE_TYPE (old) = unknown_type_node; + } + else + /* orig_name is not ambiguous. */ + old = decl; + + if (doing_global) + IDENTIFIER_GLOBAL_VALUE (orig_name) = old; + else + IDENTIFIER_LOCAL_VALUE (orig_name) = old; + + 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) + { + cp_pedwarn ("implicit declaration of function `%#D'", decl); + } + + 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 (comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0)) + return 0; + else + return "redefinition of `%#D'"; + } + 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 "`%#D' not declared in class"; + else + return "redefinition of `%#D'"; + } + + { + tree t1 = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); + tree t2 = TYPE_ARG_TYPES (TREE_TYPE (newdecl)); + + if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE) + t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2); + + for (; t1; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) + if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2)) + return "duplicate default arguments given for `%#D'"; + } + return 0; + } + else if (TREE_CODE (newdecl) == TEMPLATE_DECL) + { + if (DECL_INITIAL (olddecl) && DECL_INITIAL (newdecl)) + return "redefinition of `%#D'"; + 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; + /* 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 `%#D'"; + /* Reject two definitions. */ + return "redefinition of `%#D'"; + } + 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 `%#D'"; + 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 (current_function_decl == NULL_TREE) + { + error ("label `%s' referenced outside of any function", + IDENTIFIER_POINTER (id)); + return NULL_TREE; + } + + if ((decl == NULL_TREE + || DECL_SOURCE_LINE (decl) == 0) + && (named_label_uses == NULL_TREE + || 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, NULL_TREE); + SET_IDENTIFIER_LABEL_VALUE (decl, NULL_TREE); + } + + 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, NULL_TREE); + decl = lookup_label (name); + } + + if (DECL_INITIAL (decl) != NULL_TREE) + { + cp_error ("duplicate label `%D'", decl); + 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_ARTIFICIAL (new_decls) + && ((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) + cp_error ("invalid jump to label `%D'", decl); + SET_IDENTIFIER_ERROR_LOCUS (decl, current_function_decl); + cp_error ("crosses initialization of `%D'", new_decls); + } + 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; + cp_error_at ("destructor needed for `%#D'", TREE_PURPOSE (cleanup)); + 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. */ + cp_error ("`%#D' redeclared as %C", TREE_VALUE (tail), + form); + } + 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))) + { + tree these_tags; + case 't': + 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) + { + cp_error ("`%#D' redeclared as %C in class scope", + TREE_VALUE (tail), form); + } + 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; +} + +/* 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 -2, we're being called from yylex(). (UGLY) + Otherwise we prefer non-TYPE_DECLs. */ + +tree +lookup_name_real (name, prefer_type, nonclass) + tree name; + int prefer_type, nonclass; +{ + register tree val; + int yylex = 0; + + if (prefer_type == -2) + { + extern int looking_for_typename; + + yylex = 1; + prefer_type = looking_for_typename; + + if (got_scope != NULL_TREE) + { + if (got_scope == void_type_node) + val = IDENTIFIER_GLOBAL_VALUE (name); + else if (TREE_CODE (got_scope) == TEMPLATE_TYPE_PARM + /* TFIXME -- don't do this for UPTs in new model. */ + || TREE_CODE (got_scope) == UNINSTANTIATED_P_TYPE) + { + if (prefer_type > 0) + val = create_nested_upt (got_scope, name); + else + val = NULL_TREE; + } + else if (! IS_AGGR_TYPE (got_scope)) + /* Someone else will give an error about this if needed. */ + val = NULL_TREE; + else if (TYPE_BEING_DEFINED (got_scope)) + { + val = IDENTIFIER_CLASS_VALUE (name); + if (val && DECL_CONTEXT (val) != got_scope) + { + struct binding_level *b = class_binding_level; + for (val = NULL_TREE; b; b = b->level_chain) + { + tree t = purpose_member (name, b->class_shadowed); + if (t && TREE_VALUE (t) + && DECL_CONTEXT (TREE_VALUE (t)) == got_scope) + { + val = TREE_VALUE (t); + break; + } + } + } + if (val == NULL_TREE + && CLASSTYPE_LOCAL_TYPEDECLS (got_scope)) + val = lookup_field (got_scope, name, 0, 1); + } + else if (got_scope == current_class_type) + val = IDENTIFIER_CLASS_VALUE (name); + else + val = lookup_field (got_scope, name, 0, 0); + + goto done; + } + } + + 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 && ! nonclass) + { + val = IDENTIFIER_CLASS_VALUE (name); + if (val == NULL_TREE + && TYPE_BEING_DEFINED (current_class_type) + && 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, 1); + + /* 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, ! yylex); + + if (val == NULL_TREE) + val = IDENTIFIER_GLOBAL_VALUE (name); + } + else + val = IDENTIFIER_GLOBAL_VALUE (name); + + done: + if (val) + { + if ((TREE_CODE (val) == TEMPLATE_DECL && looking_for_template) + || TREE_CODE (val) == TYPE_DECL || prefer_type <= 0) + return val; + + if (IDENTIFIER_HAS_TYPE_VALUE (name)) + return TYPE_NAME (IDENTIFIER_TYPE_VALUE (name)); + + if (TREE_TYPE (val) == error_mark_node) + return error_mark_node; + } + + return val; +} + +tree +lookup_name_nonclass (name) + tree name; +{ + return lookup_name_real (name, 0, 1); +} + +tree +lookup_name (name, prefer_type) + tree name; + int prefer_type; +{ + return lookup_name_real (name, prefer_type, 0); +} + +/* Similar to `lookup_name' but look only at current binding level. */ + +tree +lookup_name_current_level (name) + tree name; +{ + register tree t = NULL_TREE; + + if (current_binding_level == global_binding_level) + { + t = IDENTIFIER_GLOBAL_VALUE (name); + + /* extern "C" function() */ + if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST) + t = TREE_VALUE (t); + } + else if (IDENTIFIER_LOCAL_VALUE (name) != NULL_TREE) + { + struct binding_level *b = current_binding_level; + while (1) + { + for (t = b->names; t; t = TREE_CHAIN (t)) + if (DECL_NAME (t) == name) + goto out; + if (b->keep == 2) + b = b->level_chain; + else + break; + } + out: + ; + } + + 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 +signal_catch (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 +#ifdef SIGBUS + signal (SIGBUS, 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); + + TYPE_BUILT_IN (type) = 1; + + 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_pointer_type (build_type_variant (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_reference_type (build_type_variant (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; +#if 0 /* Not yet. */ + /* Data type of strncpy. */ + tree strncpy_ftype; +#endif + int wchar_type_size; + tree temp; + tree array_domain_type; + + /* Have to make these distinct before we try using them. */ + lang_name_cplusplus = get_identifier ("C++"); + lang_name_c = get_identifier ("C"); + + if (flag_ansi || pedantic) + strict_prototypes_lang_c = strict_prototypes_lang_cplusplus; + + /* 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, signal_catch); + + /* We will also catch aborts in the back-end through signal_catch 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, signal_catch); +#endif +#ifdef SIGILL + signal (SIGILL, signal_catch); +#endif +#ifdef SIGABRT + signal (SIGABRT, signal_catch); +#endif +#ifdef SIGBUS + signal (SIGBUS, signal_catch); +#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; + + /* Make the binding_level structure for global names. */ + pushlevel (0); + global_binding_level = current_binding_level; + + this_identifier = get_identifier (THIS_NAME); + in_charge_identifier = get_identifier (IN_CHARGE_NAME); + pfn_identifier = get_identifier (VTABLE_PFN_NAME); + index_identifier = get_identifier (VTABLE_INDEX_NAME); + delta_identifier = get_identifier (VTABLE_DELTA_NAME); + delta2_identifier = get_identifier (VTABLE_DELTA2_NAME); + pfn_or_delta2_identifier = get_identifier ("__pfn_or_delta2"); + + /* Define `int' and `char' first so that dbx will output them first. */ + + integer_type_node = make_signed_type (INT_TYPE_SIZE); + record_builtin_type (RID_INT, NULL_PTR, integer_type_node); + + /* Define `char', which is like either `signed char' or `unsigned char' + but not the same as either. */ + + char_type_node = + (flag_signed_char + ? make_signed_type (CHAR_TYPE_SIZE) + : make_unsigned_type (CHAR_TYPE_SIZE)); + record_builtin_type (RID_CHAR, "char", char_type_node); + + long_integer_type_node = make_signed_type (LONG_TYPE_SIZE); + record_builtin_type (RID_LONG, "long int", long_integer_type_node); + + unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE); + record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node); + + long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE); + record_builtin_type (RID_MAX, "long unsigned int", long_unsigned_type_node); + record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node); + + long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE); + record_builtin_type (RID_MAX, "long long int", long_long_integer_type_node); + + long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE); + record_builtin_type (RID_MAX, "long long unsigned int", + long_long_unsigned_type_node); + record_builtin_type (RID_MAX, "long long unsigned", + long_long_unsigned_type_node); + + /* `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. */ + sizetype + = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))); + if (flag_traditional && TREE_UNSIGNED (sizetype)) + sizetype = signed_type (sizetype); + + 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; + TREE_TYPE (TYPE_SIZE (long_long_integer_type_node)) = sizetype; + TREE_TYPE (TYPE_SIZE (long_long_unsigned_type_node)) = sizetype; + + short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE); + record_builtin_type (RID_SHORT, "short int", short_integer_type_node); + short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE); + record_builtin_type (RID_MAX, "short unsigned int", short_unsigned_type_node); + record_builtin_type (RID_MAX, "unsigned short", short_unsigned_type_node); + + /* 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_PTR, float_type_node); + layout_type (float_type_node); + + double_type_node = make_node (REAL_TYPE); + if (flag_short_double) + TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE; + else + TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE; + record_builtin_type (RID_DOUBLE, NULL_PTR, double_type_node); + layout_type (double_type_node); + + long_double_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE; + record_builtin_type (RID_MAX, "long double", long_double_type_node); + layout_type (long_double_type_node); + + 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; + + bool_type_node = make_unsigned_type (CHAR_TYPE_SIZE); + TREE_SET_CODE (bool_type_node, BOOLEAN_TYPE); + record_builtin_type (RID_BOOL, "bool", bool_type_node); + false_node = build_int_2 (0, 0); + TREE_TYPE (false_node) = bool_type_node; + true_node = build_int_2 (1, 0); + TREE_TYPE (true_node) = bool_type_node; + + /* 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_PTR, void_type_node); + layout_type (void_type_node); /* Uses integer_zero_node. */ + void_list_node = build_tree_list (NULL_TREE, void_type_node); + TREE_PARMLIST (void_list_node) = 1; + + null_pointer_node = build_int_2 (0, 0); + TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node); + layout_type (TREE_TYPE (null_pointer_node)); + + /* Used for expressions that do nothing, but are not errors. */ + void_zero_node = build_int_2 (0, 0); + TREE_TYPE (void_zero_node) = void_type_node; + + 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_PTR, string_type_node); + + /* Make a type to be the domain of a few array types + whose domains don't really matter. + 200 is small enough that it always fits in size_t + and large enough that it can hold most function names for the + initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */ + array_domain_type = build_index_type (build_int_2 (200, 0)); + + /* make a type for arrays of characters. + With luck nothing will ever really depend on the length of this + array type. */ + char_array_type_node + = build_array_type (char_type_node, array_domain_type); + /* Likewise for arrays of ints. */ + int_array_type_node + = build_array_type (integer_type_node, array_domain_type); + + /* 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, 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))); + +#if 0 + /* Not yet. */ + strncpy_ftype /* strncpy prototype */ + = build_function_type (string_type_node, + tree_cons (NULL_TREE, string_type_node, + tree_cons (NULL_TREE, const_string_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)))); +#endif + + 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)))); + + if (flag_huge_objects) + delta_type_node = long_integer_type_node; + else + delta_type_node = short_integer_type_node; + + builtin_function ("__builtin_constant_p", int_ftype_int, + BUILT_IN_CONSTANT_P, NULL_PTR); + + builtin_return_address_fndecl = + builtin_function ("__builtin_return_address", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + unsigned_type_node, + endlink)), + BUILT_IN_RETURN_ADDRESS, NULL_PTR); + + builtin_function ("__builtin_frame_address", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + unsigned_type_node, + endlink)), + BUILT_IN_FRAME_ADDRESS, 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, NULL_TREE), + 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); + + /* Untyped call and return. */ + builtin_function ("__builtin_apply_args", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_APPLY_ARGS, NULL_PTR); + + temp = tree_cons (NULL_TREE, + build_pointer_type (build_function_type (void_type_node, + NULL_TREE)), + tree_cons (NULL_TREE, + ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink))); + builtin_function ("__builtin_apply", + build_function_type (ptr_type_node, temp), + BUILT_IN_APPLY, NULL_PTR); + builtin_function ("__builtin_return", + build_function_type (void_type_node, + tree_cons (NULL_TREE, + ptr_type_node, + endlink)), + BUILT_IN_RETURN, 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"); +#if 0 + /* Not yet. */ + builtin_function ("__builtin_strncpy", strncpy_ftype, + BUILT_IN_STRNCPY, "strncpy"); +#endif + 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); +#if 0 + /* Not yet. */ + builtin_function ("strncpy", strncpy_ftype, BUILT_IN_STRNCPY, NULL_PTR); +#endif + 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; + TYPE_DECL_SUPPRESS_DEBUG (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 for handling opaque types in signatures. */ + opaque_type_node = copy_node (ptr_type_node); + TYPE_MAIN_VARIANT (opaque_type_node) = opaque_type_node; + record_builtin_type (RID_MAX, 0, opaque_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, array_domain_type); + + /* 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)); + } + + if (flag_vtable_thunks) + { + /* Make sure we get a unique function type, so we can give + its pointer type a name. (This wins for gdb.) */ + tree vfunc_type = make_node (FUNCTION_TYPE); + TREE_TYPE (vfunc_type) = integer_type_node; + TYPE_ARG_TYPES (vfunc_type) = NULL_TREE; + layout_type (vfunc_type); + + vtable_entry_type = build_pointer_type (vfunc_type); + } + else + { + vtable_entry_type = make_lang_type (RECORD_TYPE); + fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier, + delta_type_node); + fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier, + delta_type_node); + fields[2] = build_lang_field_decl (FIELD_DECL, pfn_identifier, + 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]) = delta_type_node; + DECL_NAME (fields[3]) = delta2_identifier; + DECL_MODE (fields[3]) = TYPE_MODE (delta_type_node); + DECL_SIZE (fields[3]) = TYPE_SIZE (delta_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); + + vtbl_type_node + = build_array_type (vtable_entry_type, NULL_TREE); + layout_type (vtbl_type_node); + vtbl_type_node = c_build_type_variant (vtbl_type_node, 1, 0); + record_builtin_type (RID_MAX, NULL_PTR, vtbl_type_node); + + /* Simplify life by making a "sigtable_entry_type". Give its + fields names so that the debugger can use them. */ + + if (flag_handle_signatures) + { + sigtable_entry_type = make_lang_type (RECORD_TYPE); + fields[0] = build_lang_field_decl (FIELD_DECL, + get_identifier (SIGTABLE_CODE_NAME), + short_integer_type_node); + fields[1] = build_lang_field_decl (FIELD_DECL, + get_identifier (SIGTABLE_OFFSET_NAME), + short_integer_type_node); + fields[2] = build_lang_field_decl (FIELD_DECL, + get_identifier (SIGTABLE_PFN_NAME), + ptr_type_node); + finish_builtin_type (sigtable_entry_type, SIGTABLE_PTR_TYPE, fields, 2, + double_type_node); + sigtable_entry_type = build_type_variant (sigtable_entry_type, 1, 0); + record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_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) VEC_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); + auto_function (ansi_opname[(int) VEC_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); + + /* Perform other language dependent initializations. */ + init_class_processing (); + init_init_processing (); + init_search_processing (); + + if (flag_handle_exceptions) + init_exception_processing (); + if (flag_gc) + init_gc_processing (); + if (flag_no_inline) + { + flag_inline_functions = 0; +#if 0 + /* This causes uneccessary emission of inline functions. */ + flag_default_inline = 0; +#endif + } + if (flag_cadillac) + init_cadillac (); + + /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */ + declare_function_name (); + + /* Prepare to check format strings against argument lists. */ + init_function_format_info (); +} + +/* 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_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; + tree ob_modifier = NULL_TREE; + 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) + { + register tree name = TYPE_NAME (value); + + if (code == ENUMERAL_TYPE && TYPE_SIZE (value) == 0) + cp_error ("forward declaration of `%#T'", value); + + if (name == NULL_TREE) + name = lookup_tag_reverse (value, NULL_TREE); + + if (name && TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + + t = lookup_tag (code, name, inner_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, 0); + pop_obstacks (); + ok_code = code; + } + 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; + } + } + else if (value == ridpointers[(int) RID_STATIC] + || value == ridpointers[(int) RID_EXTERN] + || value == ridpointers[(int) RID_AUTO] + || value == ridpointers[(int) RID_REGISTER]) + ob_modifier = value; + } + + /* 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 + { + /* Anonymous unions are objects, that's why we only check for + inappropriate specifiers in this branch. */ + if (ob_modifier) + cp_error ("`%D' can only be specified for objects and functions", + ob_modifier); + + if (ok_code == RECORD_TYPE + && found_tag == 1 + && TYPE_LANG_SPECIFIC (t) + && CLASSTYPE_DECLARED_EXCEPTION (t)) + { + if (TYPE_SIZE (t)) + cp_error ("redeclaration of exception `%T'", t); + else + { + tree ename, decl; + + push_obstacks (&permanent_obstack, &permanent_obstack); + + pushclass (t, 0); + + ename = TYPE_NAME (t); + if (TREE_CODE (ename) == TYPE_DECL) + ename = DECL_NAME (ename); + decl = build_lang_field_decl (VAR_DECL, ename, t); + + pop_obstacks (); + } + } + else if (found_tag == 0) + pedwarn ("abstract declarator used as declaration"); + else if (!warned && found_tag > 1) + pedwarn ("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 declarator, declspecs; + 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); + + 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)); + if (interface_unknown && flag_external_templates + && ! DECL_IN_SYSTEM_HEADER (decl)) + warn_if_unknown_interface (); + TREE_PUBLIC (d) = TREE_PUBLIC (decl) = + flag_external_templates && !interface_unknown; + TREE_STATIC (d) = TREE_STATIC (decl); + DECL_EXTERNAL (d) = (DECL_EXTERNAL (decl) + && !(context && !DECL_THIS_EXTERN (decl))); + DECL_TEMPLATE_RESULT (d) = decl; + decl = d; + } + + /* 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) + { + cp_error ("typedef `%D' is initialized", decl); + initialized = 0; + } + break; + + case FUNCTION_DECL: + cp_error ("function `%#D' is initialized like a variable", decl); + initialized = 0; + break; + + default: + /* Don't allow initializations for incomplete types except for + arrays which might be completed by the initialization. */ + if (type == error_mark_node) + ; /* Don't complain again. */ + else if (TYPE_SIZE (type) != NULL_TREE) + ; /* A complete type is ok. */ + else if (TREE_CODE (type) != ARRAY_TYPE) + { + cp_error ("variable `%#D' has initializer but incomplete type", + decl); + initialized = 0; + } + else if (TYPE_SIZE (TREE_TYPE (type)) == NULL_TREE) + { + cp_error ("elements of array `%#D' have incomplete type", 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) + { + cp_error ("aggregate `%#D' has incomplete type and cannot be initialized", + 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)) + cp_warning ("declaration of `%#D' has `extern' and is initialized", + 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; + } + + if (context && TYPE_SIZE (context) != NULL_TREE) + { + if (TREE_CODE (decl) == VAR_DECL) + { + tree field = lookup_field (context, DECL_NAME (decl), 0, 0); + if (field == NULL_TREE || TREE_CODE (field) != VAR_DECL) + cp_error ("`%#D' is not a static member of `%#T'", decl, context); + else if (duplicate_decls (decl, field)) + decl = field; + } + + /* If it was not explicitly declared `extern', + revoke any previous claims of DECL_EXTERNAL. */ + if (DECL_THIS_EXTERN (decl) == 0) + DECL_EXTERNAL (decl) = 0; + if (DECL_LANG_SPECIFIC (decl)) + DECL_IN_AGGR_P (decl) = 0; + pushclass (context, 2); + } + + /* 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); + + /* Tell the back-end to use or not use .common as appropriate. If we say + -fconserve-space, we want this to save space, at the expense of wrong + semantics. If we say -fno-conserve-space, we want this to produce + errors about redefs; to do this we force variables into the data + segment. 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. */ + DECL_COMMON (tem) = flag_conserve_space || ! TREE_PUBLIC (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) == TEMPLATE_DECL) + { + tree result = DECL_TEMPLATE_RESULT (decl); + if (DECL_CONTEXT (result) != NULL_TREE) + { + tree type; + type = DECL_CONTEXT (result); + + if (TREE_CODE (type) != UNINSTANTIATED_P_TYPE) + { + cp_error ("declaration of `%D' in non-template type `%T'", + decl, type); + return NULL_TREE; + } + + if (TREE_CODE (result) == FUNCTION_DECL) + return tem; + else if (TREE_CODE (result) == VAR_DECL) + { +#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)); + return tem; +#else + sorry ("static data member templates"); + return NULL_TREE; +#endif + } + else + my_friendly_abort (13); + } + else if (TREE_CODE (result) == FUNCTION_DECL) + /*tem = push_overloaded_decl (tem, 0)*/; + else if (TREE_CODE (result) == VAR_DECL) + { + cp_error ("data template `%#D' must be member of a class template", + result); + return NULL_TREE; + } + else if (TREE_CODE (result) == TYPE_DECL) + { + cp_error ("invalid template `%#D'", 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; +} + +#if 0 /* unused */ +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_full (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 (); +} +#endif + +/* 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; +{ + tree tmp; + + if (init == NULL_TREE) + { + if (DECL_LANG_SPECIFIC (decl) == 0 + || DECL_IN_AGGR_P (decl) == 0) + { + cp_error ("`%D' declared as reference but not initialized", decl); + if (TREE_CODE (decl) == VAR_DECL) + SET_DECL_REFERENCE_SLOT (decl, error_mark_node); + } + return; + } + + if (init == error_mark_node) + return; + + if (TREE_CODE (type) == REFERENCE_TYPE + && TREE_CODE (init) == CONSTRUCTOR) + { + cp_error ("ANSI C++ forbids use of initializer list to initialize reference `%D'", decl); + return; + } + + if (TREE_CODE (init) == TREE_LIST) + init = build_compound_expr (init); + + 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); + } + + tmp = convert_to_reference + (type, init, CONV_IMPLICIT, LOOKUP_SPECULATIVELY|LOOKUP_NORMAL, decl); + + if (tmp == error_mark_node) + goto fail; + else if (tmp != NULL_TREE) + { + tree subtype = TREE_TYPE (type); + init = tmp; + + /* Associate the cleanup with the reference so that we + don't get burned by "aggressive" cleanup policy. */ + if (TYPE_NEEDS_DESTRUCTOR (subtype)) + { + if (TREE_CODE (init) == WITH_CLEANUP_EXPR) + { + *cleanupp = TREE_OPERAND (init, 2); + TREE_OPERAND (init, 2) = error_mark_node; + } + else + { + if (TREE_CODE (tmp) == ADDR_EXPR) + tmp = TREE_OPERAND (tmp, 0); + if (TREE_CODE (tmp) == TARGET_EXPR) + { + *cleanupp = build_delete + (TYPE_POINTER_TO (subtype), + build_unary_op (ADDR_EXPR, TREE_OPERAND (tmp, 0), 0), + integer_two_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0); + TREE_OPERAND (tmp, 2) = error_mark_node; + } + } + } + + DECL_INITIAL (decl) = save_expr (init); + } + else + { + cp_error ("cannot initialize `%T' from `%T'", type, TREE_TYPE (init)); + goto fail; + } + + /* ?? Can this be optimized in some cases to + hand back the DECL_INITIAL slot?? */ + if (TYPE_SIZE (TREE_TYPE (type))) + { + init = convert_from_reference (decl); + if (TREE_PERMANENT (decl)) + init = copy_to_permanent (init); + SET_DECL_REFERENCE_SLOT (decl, init); + } + + if (TREE_STATIC (decl) && ! TREE_CONSTANT (DECL_INITIAL (decl))) + { + expand_static_init (decl, DECL_INITIAL (decl)); + DECL_INITIAL (decl) = NULL_TREE; + } + return; + + fail: + if (TREE_CODE (decl) == VAR_DECL) + SET_DECL_REFERENCE_SLOT (decl, error_mark_node); + return; +} + +/* 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 a name was specified, get the string. */ + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + /* 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 (type != error_mark_node + && IS_AGGR_TYPE (type) && DECL_NAME (decl)) + { + if (TREE_TYPE (DECL_NAME (decl)) && TREE_TYPE (decl) != type) + cp_warning ("shadowing previous type declaration of `%#D'", 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)) + { + 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 + || (TYPE_LANG_SPECIFIC (type) && IS_SIGNATURE_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) + ; + 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_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type)) + { + if (TREE_CODE (type) == ARRAY_TYPE) + init = digest_init (type, init, (tree *) 0); + else if (TREE_CODE (init) == CONSTRUCTOR) + { + if (TYPE_NEEDS_CONSTRUCTING (type)) + { + cp_error ("`%D' must be initialized by constructor, not by `{...}'", + decl); + init = error_mark_node; + } + else + goto dont_use_constructor; + } +#if 0 + /* fix this in `build_functional_cast' instead. + Here's the trigger code: + + struct ostream + { + ostream (); + ostream (int, char *); + ostream (char *); + operator char *(); + ostream (void *); + operator void *(); + operator << (int); + }; + int buf_size = 1024; + static char buf[buf_size]; + const char *debug(int i) { + char *b = &buf[0]; + ostream o = ostream(buf_size, b); + o << i; + return buf; + } + */ + + else if (TREE_CODE (init) == TARGET_EXPR + && TREE_CODE (TREE_OPERAND (init, 1) == NEW_EXPR)) + { + /* User wrote something like `foo x = foo (args)' */ + my_friendly_assert (TREE_CODE (TREE_OPERAND (init, 0)) == VAR_DECL, 150); + my_friendly_assert (DECL_NAME (TREE_OPERAND (init, 0)) == NULL_TREE, 151); + + /* User wrote exactly `foo x = foo (args)' */ + if (TYPE_MAIN_VARIANT (type) == TREE_TYPE (init)) + { + init = build (CALL_EXPR, TREE_TYPE (init), + TREE_OPERAND (TREE_OPERAND (init, 1), 0), + TREE_OPERAND (TREE_OPERAND (init, 1), 1), 0); + TREE_SIDE_EFFECTS (init) = 1; + } + } +#endif + + /* 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; + if (DECL_COMMON (decl)) + /* Should this be a NULL_TREE? */ + value = error_mark_node; + else + value = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE); + DECL_INITIAL (decl) = value; + } + else + DECL_INITIAL (decl) = error_mark_node; + } + else + { + dont_use_constructor: + if (TREE_CODE (init) != TREE_VEC) + init = store_init_value (decl, init); + + /* Don't let anyone try to initialize this variable + until we are ready to do so. */ + if (init) + { + tree value; + if (DECL_COMMON (decl)) + value = error_mark_node; + else + value = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE); + DECL_INITIAL (decl) = value; + } + } + } + else if (DECL_EXTERNAL (decl)) + ; + 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_CONSTRUCTING (ctype)) + { + if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (ctype)) + cp_error ("structure `%D' with uninitialized const members", decl); + if (CLASSTYPE_REF_FIELDS_NEED_INIT (ctype)) + cp_error ("structure `%D' with uninitialized reference members", + decl); + } + + if (TREE_CODE (decl) == VAR_DECL + && !DECL_INITIAL (decl) + && !TYPE_NEEDS_CONSTRUCTING (type) + && (TYPE_READONLY (type) || TREE_READONLY (decl))) + cp_error ("uninitialized const `%D'", decl); + + /* Initialize variables in need of static initialization with + an empty CONSTRUCTOR to keep assemble_variable from putting them in + the wrong program 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) + && ! DECL_COMMON (decl)) + DECL_INITIAL (decl) = build (CONSTRUCTOR, type, NULL_TREE, + NULL_TREE); + } + 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. + We deliberately don't complain about arrays, because they're + supposed to be initialized by a constructor. */ + if (! DECL_INITIAL (decl) + && TREE_CODE (type) != ARRAY_TYPE + && (!pedantic || !current_class_type)) + cp_error ("uninitialized const `%#D'", decl); + } + + /* For top-level declaration, the initial value was read in + the temporary obstack. MAXINDEX, rtl, etc. to be made below + must go in the permanent obstack; but don't discard the + temporary data yet. */ + + if (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) + cp_error ("initializer fails to determine size of `%D'", decl); + + if (failure == 2) + { + if (do_default) + cp_error ("array size missing in `%D'", decl); + /* If a `static' var's size isn't known, make it extern as + well as static, so it does not get allocated. If it's not + `static', then don't mark it extern; finish_incomplete_decl + will give it a default size and it will get allocated. */ + else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (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)) + cp_error ("zero-size array `%D'", decl); + + layout_decl (decl, 0); + } + + if (TREE_CODE (decl) == VAR_DECL) + { + if (DECL_SIZE (decl) == NULL_TREE + && TYPE_SIZE (TREE_TYPE (decl)) != NULL_TREE) + layout_decl (decl, 0); + + if (TREE_STATIC (decl) && DECL_SIZE (decl) == NULL_TREE) + { + /* A static variable with an incomplete type: + that is an error if it is initialized. + Otherwise, let it through, but if it is not `extern' + then it may cause an error message later. */ + if (DECL_INITIAL (decl) != NULL_TREE) + cp_error ("storage size of `%D' isn't known", decl); + 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. */ + cp_error ("storage size of `%D' isn't known", decl); + 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))) + { + if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) + constant_expression_warning (DECL_SIZE (decl)); + else + cp_error ("storage size of `%D' isn't constant", decl); + } + + 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; + } + 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) + { + /* ??? FIXME: What about nested classes? */ + int toplev = (current_binding_level == global_binding_level + || pseudo_global_level_p ()); + int was_temp + = ((flag_traditional + || (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type))) + && allocation_temporary_p ()); + + if (was_temp) + end_temporary_allocation (); + + 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 + && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))) + { + DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl)); + + if (asmspec) + DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec); + + if (! toplev + && TREE_STATIC (decl) + && ! TREE_SIDE_EFFECTS (decl) + && ! TREE_PUBLIC (decl) + && ! DECL_EXTERNAL (decl) + && ! TYPE_NEEDS_DESTRUCTOR (type) + && DECL_MODE (decl) != BLKmode) + { + /* If this variable is really a constant, then fill its DECL_RTL + slot with something which won't take up storage. + If something later should take its address, we can always give + it legitimate RTL at that time. */ + DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl)); + store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0); + TREE_ASM_WRITTEN (decl) = 1; + } + else if (toplev && ! TREE_PUBLIC (decl)) + { + /* If this is a static const, change its apparent linkage + if it belongs to a #pragma interface. */ + if (!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 (TYPE_LANG_SPECIFIC (type) && IS_SIGNATURE (type)) + signature_error (decl, type); + else if ((TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE) + && TYPE_LANG_SPECIFIC (TREE_TYPE (type)) + && IS_SIGNATURE (TREE_TYPE (type))) + signature_error (decl, TREE_TYPE (type)); + + if (TREE_CODE (decl) == FUNCTION_DECL) + { +#if 0 + /* 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) + { + /* The default value for the parameter in parmtypes is + stored in the TREE_PURPOSE of the TREE_LIST. */ + if (TREE_PURPOSE (parmtypes)) + { + tree fnname, fndecl; + tree *argp; + + 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; + } +#endif + } + 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 (! toplev) + { + tree old_cleanups = cleanups_this_call; + /* 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) + { + /* XXX: Why don't we use decl here? */ + /* Ans: Because it was already expanded? */ + if (! expand_decl_cleanup (NULL_TREE, cleanup)) + cp_error ("parser lost in parsing declaration of `%D'", + decl); + /* 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)) + cp_error ("parser lost in parsing declaration of `%D'", + decl); + } + } + /* Cleanup any temporaries needed for the initial value. */ + expand_cleanups_to (old_cleanups); + } + 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 + */ + && context == current_class_type + ))) + popclass (1); + } + } + + finish_end: + + /* If requested, warn about definitions of large data objects. */ + + if (warn_larger_than + && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) + && !DECL_EXTERNAL (decl)) + { + register tree decl_size = DECL_SIZE (decl); + + if (decl_size && TREE_CODE (decl_size) == INTEGER_CST) + { + unsigned units = TREE_INT_CST_LOW (decl_size) / BITS_PER_UNIT; + + if (units > larger_than_size) + warning_with_decl (decl, "size of `%s' is %u bytes", units); + } + } + + 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); +} + +void +expand_static_init (decl, init) + tree decl; + tree init; +{ + tree oldstatic = value_member (decl, static_aggregates); + tree old_cleanups; + + if (oldstatic) + { + if (TREE_PURPOSE (oldstatic) && init != NULL_TREE) + cp_error ("multiple initializations given for `%D'", decl); + } + else if (current_binding_level != global_binding_level + && current_binding_level->pseudo_global == 0) + { + /* 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); + old_cleanups = cleanups_this_call; + 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); + /* Cleanup any temporaries needed for the initial value. */ + expand_cleanups_to (old_cleanups); + 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, - (nelts == 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 (0, 0); + } + } + + if (!maxindex) + { + if (do_default) + maxindex = build_int_2 (0, 0); + value = 2; + } + + if (maxindex) + { + tree itype; + + TYPE_DOMAIN (type) = build_index_type (maxindex); + if (!TREE_TYPE (maxindex)) + TREE_TYPE (maxindex) = TYPE_DOMAIN (type); + if (initial_value) + itype = TREE_TYPE (initial_value); + else + itype = NULL; + if (itype && !TYPE_DOMAIN (itype)) + TYPE_DOMAIN (itype) = 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'. */ + +/* Generate errors possibly applicable for a given set of specifiers. + This is for ARM $7.1.2. */ +static void +bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises) + tree object; + char *type; + int virtualp, quals, friendp, raises, inlinep; +{ + if (virtualp) + cp_error ("`%D' declared as a `virtual' %s", object, type); + if (inlinep) + cp_error ("`%D' declared as an `inline' %s", object, type); + if (quals) + cp_error ("`const' and `volatile' function specifiers on `%D' invalid in %s declaration", + object, type); + if (friendp) + cp_error_at ("invalid friend declaration", object); + if (raises) + cp_error_at ("invalid raises declaration", object); +} + +/* 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) + { + cp_error ("%smember function `%D' cannot have `%T' method qualifier", + (ctype ? "static " : "non-"), decl, TREE_VALUE (quals)); + quals = NULL_TREE; + } + + if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))) + grok_op_properties (decl, virtualp, check < 0); + + /* 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); + if (! grok_ctor_properties (ctype, decl)) + return NULL_TREE; + + if (check == 0 && ! current_function_decl) + { + /* 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)) + cp_error ("inconsistent declarations for `%D'", decl); + 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 (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). Don't do this for local class + methods, though. */ + if (! current_function_decl) + { + /* 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)) + cp_error ("inconsistent declarations for `%D'", decl); + 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_matching_virtual (base_binfo, decl, + flags == DTOR_FLAG); + if (tmp) + { + /* If this function overrides some virtual in some base + class, then the function itself is also necessarily + virtual, even if the user didn't explicitly say so. */ + DECL_VIRTUAL_P (decl) = 1; + + /* 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) + { + cp_error ("method `%D' may not be declared static", + decl); + cp_error_at ("(since `%D' declared virtual in base class.)", + tmp); + break; + } + virtualp = 1; + + { + /* 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)); + } + break; + } + } + } + } + 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_KNOWN (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; + + if (TREE_CODE (type) == OFFSET_TYPE) + { + /* If you declare a static member so that it + can be initialized, the code will reach here. */ + tree basetype = TYPE_OFFSET_BASETYPE (type); + type = TREE_TYPE (type); + decl = build_lang_field_decl (VAR_DECL, declarator, type); + DECL_CONTEXT (decl) = basetype; + DECL_CLASS_CONTEXT (decl) = basetype; + } + else + decl = build_decl (VAR_DECL, declarator, type); + + if (RIDBIT_SETP (RID_EXTERN, specbits)) + { + DECL_THIS_EXTERN (decl) = 1; + DECL_EXTERNAL (decl) = !initialized; + } + + /* In class context, static means one per class, + public access, 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) = 0; + } + /* 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) = RIDBIT_NOTSETP (RID_STATIC, specbits); + TREE_STATIC (decl) = ! DECL_EXTERNAL (decl); + } + /* Not at top level, only `static' makes a static definition. */ + else + { + TREE_STATIC (decl) = !! RIDBIT_SETP (RID_STATIC, specbits); + TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); + } + return decl; +} + +/* Create a canonical pointer to member function type. */ + +tree +build_ptrmemfunc_type (type) + tree type; +{ + tree fields[4]; + tree t; + tree u; + + /* If a canonical type already exists for this type, use it. We use + this method instead of type_hash_canon, because it only does a + simple equality check on the list of field members. */ + + if ((t = TYPE_GET_PTRMEMFUNC_TYPE (type))) + return t; + + push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type)); + + u = make_lang_type (UNION_TYPE); + fields[0] = build_lang_field_decl (FIELD_DECL, pfn_identifier, type); + fields[1] = build_lang_field_decl (FIELD_DECL, delta2_identifier, + delta_type_node); + finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node); + TYPE_NAME (u) = NULL_TREE; + + t = make_lang_type (RECORD_TYPE); + + /* Let the front-end know this is a pointer to member function. */ + TYPE_PTRMEMFUNC_FLAG(t) = 1; + + fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier, + delta_type_node); + fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier, + delta_type_node); + fields[2] = build_lang_field_decl (FIELD_DECL, pfn_or_delta2_identifier, u); + finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node); + + pop_obstacks (); + + /* Zap out the name so that the back-end will give us the debugging + information for this anonymous RECORD_TYPE. */ + TYPE_NAME (t) = NULL_TREE; + + TYPE_SET_PTRMEMFUNC_TYPE (type, t); + + /* Seems to be wanted. */ + CLASSTYPE_GOT_SEMICOLON (t) = 1; + return t; +} + +/* 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; +{ + RID_BIT_TYPE specbits; + 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; + int opaque_typedef = 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; + tree quals = NULL_TREE; + + RIDBIT_RESET_ALL (specbits); + 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 last = NULL_TREE; + register tree decl = declarator; + name = NULL; + + while (decl) + switch (TREE_CODE (decl)) + { + case COND_EXPR: + ctype = NULL_TREE; + decl = TREE_OPERAND (decl, 0); + break; + + case BIT_NOT_EXPR: /* for C++ destructors! */ + { + tree name = TREE_OPERAND (decl, 0); + tree rename = NULL_TREE; + + my_friendly_assert (flags == NO_SPECIAL, 152); + flags = DTOR_FLAG; + return_type = return_dtor; + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153); + if (ctype == NULL_TREE) + { + if (current_class_type == NULL_TREE) + { + error ("destructors must be member functions"); + flags = NO_SPECIAL; + } + else + { + tree t = constructor_name (current_class_name); + if (t != name) + rename = t; + } + } + else + { + tree t = constructor_name (ctype); + if (t != name) + rename = t; + } + + if (rename) + { + error ("destructor `%s' must match class name `%s'", + IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (rename)); + TREE_OPERAND (decl, 0) = rename; + } + decl = name; + } + break; + + case ADDR_EXPR: /* C++ reference declaration */ + /* fall through */ + case ARRAY_REF: + case INDIRECT_REF: + ctype = NULL_TREE; + innermost_code = TREE_CODE (decl); + last = decl; + decl = TREE_OPERAND (decl, 0); + break; + + case CALL_EXPR: + if (parmlist_is_exprlist (TREE_OPERAND (decl, 1))) + { + /* This is actually a variable declaration using constructor + syntax. We need to call start_decl and finish_decl so we + can get the variable initialized... */ + + if (last) + /* We need to insinuate ourselves into the declarator in place + of the CALL_EXPR. */ + TREE_OPERAND (last, 0) = TREE_OPERAND (decl, 0); + else + declarator = TREE_OPERAND (decl, 0); + + init = TREE_OPERAND (decl, 1); + + decl = start_decl (declarator, declspecs, 1, NULL_TREE); + finish_decl (decl, init, NULL_TREE, 1); + return 0; + } + 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; + decl = NULL_TREE; + + if (IDENTIFIER_OPNAME_P (dname)) + { + if (IDENTIFIER_TYPENAME_P (dname)) + { + my_friendly_assert (flags == NO_SPECIAL, 154); + flags = TYPENAME_FLAG; + ctor_return_type = TREE_TYPE (dname); + return_type = return_conversion; + } + name = operator_name_string (dname); + } + else + name = IDENTIFIER_POINTER (dname); + 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; + + /* C++ extension */ + case SCOPE_REF: + { + /* Perform error checking, and convert class names to types. + We may call grokdeclarator multiple times for the same + tree structure, so only do the conversion once. In this + case, we have exactly what we want for `ctype'. */ + tree cname = TREE_OPERAND (decl, 0); + if (cname == NULL_TREE) + ctype = NULL_TREE; + /* Can't use IS_AGGR_TYPE because CNAME might not be a type. */ + else if (IS_AGGR_TYPE_CODE (TREE_CODE (cname)) + || TREE_CODE (cname) == UNINSTANTIATED_P_TYPE) + ctype = cname; + else if (! is_aggr_typedef (cname, 1)) + { + 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)) + { + cp_error ("type `%T' is not derived from type `%T'", + IDENTIFIER_TYPE_VALUE (cname), ctype); + TREE_OPERAND (decl, 0) = NULL_TREE; + } + else + { + ctype = IDENTIFIER_TYPE_VALUE (cname); + TREE_OPERAND (decl, 0) = ctype; + } + } + + 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: + return 0; /* We used to do a 155 abort here. */ + } + if (name == NULL) + name = "type name"; + } + + /* A function definition's declarator must have the form of + 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; + + /* 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; + + id = TREE_VALUE (spec); + + if (TREE_CODE (id) == IDENTIFIER_NODE) + { + if (id == ridpointers[(int) RID_INT] + || id == ridpointers[(int) RID_CHAR] + || id == ridpointers[(int) RID_BOOL] + || id == ridpointers[(int) RID_WCHAR]) + { + if (type) + error ("extraneous `%T' ignored", id); + else + { + if (id == ridpointers[(int) RID_INT]) + explicit_int = 1; + else if (id == ridpointers[(int) RID_CHAR]) + explicit_char = 1; + type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id)); + } + goto found; + } + /* C++ aggregate types. */ + if (IDENTIFIER_HAS_TYPE_VALUE (id)) + { + if (type) + cp_error ("multiple declarations `%T' and `%T'", type, 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 && RIDBIT_SETP (i, specbits)) + { + if (pedantic && flag_ansi) + pedwarn ("duplicate `long'"); + else if (longlong) + error ("`long long long' is too long for GCC"); + else + longlong = 1; + } + else if (RIDBIT_SETP (i, specbits)) + pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id)); + RIDBIT_SET (i, specbits); + 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. + Except when we have a `typedef' inside a signature, in + which case the type defaults to `unknown type' and is + instantiated when assigning to a signature pointer or ref. */ + + if (type == NULL_TREE + && (RIDBIT_SETP (RID_SIGNED, specbits) + || RIDBIT_SETP (RID_UNSIGNED, specbits) + || RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits))) + { + /* These imply 'int'. */ + type = integer_type_node; + explicit_int = 1; + } + + 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 (return_type == return_conversion) + type = ctor_return_type; + else if (current_class_type + && IS_SIGNATURE (current_class_type) + && (RIDBIT_SETP (RID_TYPEDEF, specbits) + || SIGNATURE_GROKKING_TYPEDEF (current_class_type)) + && (decl_context == FIELD || decl_context == NORMAL)) + { + explicit_int = 0; + opaque_typedef = 1; + type = copy_node (opaque_type_node); + } + /* access declaration */ + else if (decl_context == FIELD && declarator + && TREE_CODE (declarator) == SCOPE_REF) + type = void_type_node; + else + { + if (funcdef_flag) + { + if (warn_return_type + && return_type == return_normal) + /* Save warning until we know what is really going on. */ + warn_about_return_type = 1; + } + else if (RIDBIT_SETP (RID_TYPEDEF, specbits)) + pedwarn ("ANSI C++ forbids typedef which does not specify a type"); + else if (declspecs == NULL_TREE && + (innermost_code != CALL_EXPR || pedantic)) + cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type or storage class", + dname); + 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 (return_type == return_conversion) + { + if (comp_target_types (type, ctor_return_type, 1) == 0) + cp_error ("operator `%T' declared to return `%T'", + ctor_return_type, type); + else + cp_pedwarn ("return type specified for `operator %T'", + ctor_return_type); + + type = ctor_return_type; + } + /* Catch typedefs that only specify a type, like 'typedef int;'. */ + else if (RIDBIT_SETP (RID_TYPEDEF, specbits) && declarator == NULL_TREE) + { + /* Template "this is a type" syntax; just ignore for now. */ + if (processing_template_defn) + return void_type_node; + } + + ctype = NULL_TREE; + + /* Now process the modifiers that were specified + and check for invalid combinations. */ + + /* Long double is a special combination. */ + + if (RIDBIT_SETP (RID_LONG, specbits) + && TYPE_MAIN_VARIANT (type) == double_type_node) + { + RIDBIT_RESET (RID_LONG, specbits); + type = build_type_variant (long_double_type_node, TYPE_READONLY (type), + TYPE_VOLATILE (type)); + } + + /* Check all other uses of type modifiers. */ + + if (RIDBIT_SETP (RID_UNSIGNED, specbits) + || RIDBIT_SETP (RID_SIGNED, specbits) + || RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits)) + { + 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 (RIDBIT_SETP (RID_LONG, specbits) + && RIDBIT_SETP (RID_SHORT, specbits)) + error ("long and short specified together for `%s'", name); + else if ((RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits)) + && explicit_char) + error ("long or short specified with char for `%s'", name); + else if ((RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits)) + && TREE_CODE (type) == REAL_TYPE) + error ("long or short specified with floating type for `%s'", name); + else if (RIDBIT_SETP (RID_SIGNED, specbits) + && RIDBIT_SETP (RID_UNSIGNED, specbits)) + 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) + { + RIDBIT_RESET (RID_UNSIGNED, specbits); + RIDBIT_RESET (RID_SIGNED, specbits); + RIDBIT_RESET (RID_LONG, specbits); + RIDBIT_RESET (RID_SHORT, specbits); + longlong = 0; + } + } + + /* Decide whether an integer type is signed or not. + Optionally treat bitfields as signed by default. */ + if (RIDBIT_SETP (RID_UNSIGNED, specbits) + /* 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 + && RIDBIT_NOTSETP (RID_SIGNED, specbits))) + { + if (longlong) + type = long_long_unsigned_type_node; + else if (RIDBIT_SETP (RID_LONG, specbits)) + type = long_unsigned_type_node; + else if (RIDBIT_SETP (RID_SHORT, specbits)) + 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 (RIDBIT_SETP (RID_SIGNED, specbits) + && type == char_type_node) + type = signed_char_type_node; + else if (longlong) + type = long_long_integer_type_node; + else if (RIDBIT_SETP (RID_LONG, specbits)) + type = long_integer_type_node; + else if (RIDBIT_SETP (RID_SHORT, specbits)) + type = short_integer_type_node; + + /* Set CONSTP if this declaration is `const', whether by + explicit specification or via a typedef. + Likewise for VOLATILEP. */ + + constp = !! RIDBIT_SETP (RID_CONST, specbits) + TYPE_READONLY (type); + volatilep = !! RIDBIT_SETP (RID_VOLATILE, specbits) + TYPE_VOLATILE (type); + staticp = 0; + inlinep = !! RIDBIT_SETP (RID_INLINE, specbits); + if (constp > 1) + warning ("duplicate `const'"); + if (volatilep > 1) + warning ("duplicate `volatile'"); + virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits); + + if (RIDBIT_SETP (RID_STATIC, specbits)) + staticp = 1 + (decl_context == FIELD); + + if (virtualp && staticp == 2) + { + cp_error ("member `%D' cannot be declared both virtual and static", + dname); + staticp = 0; + } + friendp = RIDBIT_SETP (RID_FRIEND, specbits); + RIDBIT_RESET (RID_VIRTUAL, specbits); + RIDBIT_RESET (RID_FRIEND, specbits); + + if (RIDBIT_SETP (RID_MUTABLE, specbits)) + { + if (decl_context == PARM) + { + error ("non-member `%s' cannot be declared mutable", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } + else if (friendp || decl_context == TYPENAME) + { + error ("non-object member `%s' cannot be declared mutable", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } + else if (staticp) + { + error ("static `%s' cannot be declared mutable", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } +#if 0 + if (RIDBIT_SETP (RID_TYPEDEF, specbits)) + { + error ("non-object member `%s' cannot be declared mutable", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } + /* Because local typedefs are parsed twice, we don't want this + message here. */ + else if (decl_context != FIELD) + { + error ("non-member `%s' cannot be declared mutable", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } +#endif + } + + /* Warn if two storage classes are given. Default to `auto'. */ + + if (RIDBIT_ANY_SET (specbits)) + { + if (RIDBIT_SETP (RID_STATIC, specbits)) nclasses++; + if (RIDBIT_SETP (RID_EXTERN, specbits)) nclasses++; + if (decl_context == PARM && nclasses > 0) + error ("storage class specifiers invalid in parameter declarations"); + if (RIDBIT_SETP (RID_TYPEDEF, specbits)) + { + if (decl_context == PARM) + error ("typedef declaration invalid in parameter declaration"); + nclasses++; + } + if (RIDBIT_SETP (RID_AUTO, specbits)) nclasses++; + if (RIDBIT_SETP (RID_REGISTER, specbits)) 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; + } + if (current_class_name == NULL_TREE && RIDBIT_SETP (RID_MUTABLE, specbits)) + { + error ("only members can be declared mutable"); + RIDBIT_RESET (RID_MUTABLE, specbits); + } + + /* Static anonymous unions are dealt with here. */ + if (staticp && decl_context == TYPENAME + && TREE_CODE (declspecs) == TREE_LIST + && TREE_CODE (TREE_VALUE (declspecs)) == UNION_TYPE + && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_VALUE (declspecs)))) + decl_context = FIELD; + + /* Give error if `const,' `volatile,' `inline,' `friend,' or `virtual' + is used in a signature member function declaration. */ + if (decl_context == FIELD + && IS_SIGNATURE (current_class_type) + && RIDBIT_NOTSETP(RID_TYPEDEF, specbits) + && !SIGNATURE_GROKKING_TYPEDEF (current_class_type)) + { + if (constp) + { + error ("`const' specified for signature member function `%s'", name); + constp = 0; + } + if (volatilep) + { + error ("`volatile' specified for signature member function `%s'", + name); + volatilep = 0; + } + if (inlinep) + { + error ("`inline' specified for signature member function `%s'", name); + /* Later, we'll make signature member functions inline. */ + inlinep = 0; + } + if (friendp) + { + error ("`friend' declaration in signature definition"); + friendp = 0; + } + if (virtualp) + { + error ("`virtual' specified for signature member function `%s'", + name); + /* Later, we'll make signature member functions virtual. */ + 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 + && (RIDBIT_SETP (RID_REGISTER, specbits) + || RIDBIT_SETP (RID_AUTO, specbits))) + ; + else if (decl_context == FIELD + && RIDBIT_SETP (RID_TYPEDEF, specbits)) + { + /* Processing a typedef declaration nested within a class type + definition. */ + register tree scanner; + register tree previous_declspec; + tree loc_typedecl; + + if (initialized) + error ("typedef declaration includes an initializer"); + + /* To process a class-local typedef declaration, we descend down + the chain of declspecs looking for the `typedef' spec. When + we find it, we replace it with `static', and then recursively + call `grokdeclarator' with the original declarator and with + the newly adjusted declspecs. This call should return a + FIELD_DECL node with the TREE_TYPE (and other parts) set + appropriately. We can then just change the TREE_CODE on that + from FIELD_DECL to TYPE_DECL and we're done. */ + + for (previous_declspec = NULL_TREE, scanner = declspecs; + scanner; + previous_declspec = scanner, scanner = TREE_CHAIN (scanner)) + { + if (TREE_VALUE (scanner) == ridpointers[(int) RID_TYPEDEF]) + break; + } + + if (scanner == IDENTIFIER_AS_LIST (ridpointers [(int) RID_TYPEDEF])) + { + if (previous_declspec) + TREE_CHAIN (previous_declspec) + = IDENTIFIER_AS_LIST (ridpointers [(int) RID_STATIC]); + else + declspecs + = IDENTIFIER_AS_LIST (ridpointers [(int) RID_STATIC]); + } + else + TREE_VALUE (scanner) = ridpointers[(int) RID_STATIC]; + + /* In the recursive call to grokdeclarator we need to know + whether we are working on a signature-local typedef. */ + if (IS_SIGNATURE (current_class_type)) + SIGNATURE_GROKKING_TYPEDEF (current_class_type) = 1; + + loc_typedecl = + grokdeclarator (declarator, declspecs, FIELD, 0, NULL_TREE); + + if (loc_typedecl != error_mark_node) + { + register int i = sizeof (struct lang_decl_flags) / sizeof (int); + register int *pi; + + TREE_SET_CODE (loc_typedecl, TYPE_DECL); + + pi = (int *) permalloc (sizeof (struct lang_decl_flags)); + while (i > 0) + pi[--i] = 0; + DECL_LANG_SPECIFIC (loc_typedecl) = (struct lang_decl *) pi; + } + + if (IS_SIGNATURE (current_class_type)) + { + SIGNATURE_GROKKING_TYPEDEF (current_class_type) = 0; + if (loc_typedecl != error_mark_node && opaque_typedef) + SIGNATURE_HAS_OPAQUE_TYPEDECLS (current_class_type) = 1; + } + + return loc_typedecl; + } + else if (decl_context == FIELD + && (! IS_SIGNATURE (current_class_type) + || SIGNATURE_GROKKING_TYPEDEF (current_class_type)) + /* C++ allows static class elements */ + && RIDBIT_SETP (RID_STATIC, specbits)) + /* 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'", + IS_SIGNATURE (current_class_type) + ? (op + ? "signature member operator" + : "signature member function") + : (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); + RIDBIT_RESET (RID_REGISTER, specbits); + RIDBIT_RESET (RID_AUTO, specbits); + RIDBIT_RESET (RID_EXTERN, specbits); + + if (decl_context == FIELD && IS_SIGNATURE (current_class_type)) + { + RIDBIT_RESET (RID_STATIC, specbits); + staticp = 0; + } + } + } + else if (RIDBIT_SETP (RID_EXTERN, specbits) && 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 (RIDBIT_SETP (RID_EXTERN, specbits) && funcdef_flag + && current_binding_level != global_binding_level) + error ("nested function `%s' declared `extern'", name); + else if (current_binding_level == global_binding_level) + { + if (RIDBIT_SETP (RID_AUTO, specbits)) + error ("top-level declaration of `%s' specifies `auto'", name); +#if 0 + if (RIDBIT_SETP (RID_REGISTER, specbits)) + 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 + && RIDBIT_NOSETP (RID_EXTERN, specbits) + && ! root_lang_context_p ()) + { + RIDBIT_SET (RID_EXTERN, specbits); + } +#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) + + 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: + { + 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) + { + cp_error ("declaration of `%D' as array of voids", dname); + type = error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + cp_error ("declaration of `%D' as array of functions", dname); + type = error_mark_node; + } + + /* ARM $8.4.3: Since you can't have a pointer to a reference, + you can't have arrays of references. If we allowed them, + then we'd be saying x[i] is legal for an array x, but + then you'd have to ask: what does `*(x + i)' mean? */ + if (TREE_CODE (type) == REFERENCE_TYPE) + { + if (decl_context == TYPENAME) + cp_error ("cannot make arrays of references"); + else + cp_error ("declaration of `%D' as array of references", + dname); + type = error_mark_node; + } + + if (TREE_CODE (type) == OFFSET_TYPE) + { + cp_error ("declaration of `%D' as array of data members", + dname); + type = error_mark_node; + } + + if (TREE_CODE (type) == METHOD_TYPE) + { + cp_error ("declaration of `%D' as array of function members", + dname); + type = error_mark_node; + } + + if (size == error_mark_node) + type = error_mark_node; + + 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) + { + cp_error ("size of array `%D' has non-integer type", + dname); + size = integer_one_node; + } + if (TREE_READONLY_DECL_P (size)) + size = decl_constant_value (size); + if (flag_ansi && integer_zerop (size)) + cp_pedwarn ("ANSI C++ forbids zero-size array `%D'", dname); + if (TREE_CONSTANT (size)) + { + constant_expression_warning (size); + if (INT_CST_LT (size, integer_zero_node)) + { + cp_error ("size of array `%D' is negative", dname); + size = integer_one_node; + } + itype = build_index_type (size_binop (MINUS_EXPR, size, + integer_one_node)); + } + else + { + if (flag_ansi) + { + if (dname) + cp_pedwarn ("ANSI C++ forbids variable-size array `%D'", + dname); + else + cp_pedwarn ("ANSI C++ forbids variable-size array"); + } + 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, then merge any constancy or + volatility into the target type. We must do it in this order + to ensure that the TYPE_MAIN_VARIANT field of the array type + is set correctly. */ + + type = build_cplus_array_type (type, itype); + if (constp || volatilep) + type = c_build_type_variant (type, constp, volatilep); + + ctype = NULL_TREE; + } + break; + + case CALL_EXPR: + { + 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 function return + type. */ + + if (constp || volatilep) + { + type = c_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 && return_type == return_conversion) + 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; + } + { + RID_BIT_TYPE tmp_bits; + bcopy ((void*)&specbits, (void*)&tmp_bits, sizeof(RID_BIT_TYPE)); + RIDBIT_RESET (RID_INLINE, tmp_bits); + RIDBIT_RESET (RID_STATIC, tmp_bits); + if (RIDBIT_ANY_SET (tmp_bits)) + error ("return value type specifier for constructor ignored"); + } + type = TYPE_POINTER_TO (ctype); + if (decl_context == FIELD && + IS_SIGNATURE (current_class_type)) + { + error ("constructor not allowed in signature"); + return void_type_node; + } + else 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"); + RIDBIT_RESET (RID_FRIEND, specbits); + friendp = 0; + } + + 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) + ? funcdef_flag : 0; + + /* FIXME: This is where default args should be fully + processed. */ + + 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; + } + } + } + + /* ANSI seems to say that `const int foo ();' + does not make the function foo const. */ + type = build_function_type (type, + flag_traditional ? 0 : arg_types); + } + break; + + case ADDR_EXPR: + case INDIRECT_REF: + /* 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) + { + /* A const or volatile signature pointer/reference is + pointing to a const or volatile object, i.e., the + `optr' is const or volatile, respectively, not the + signature pointer/reference itself. */ + if (! IS_SIGNATURE (type)) + { + type = c_build_type_variant (type, constp, volatilep); + if (IS_AGGR_TYPE (type)) + build_pointer_type (type); + constp = 0; + volatilep = 0; + } + } + + if (IS_SIGNATURE (type)) + { + if (TREE_CODE (declarator) == ADDR_EXPR) + { + if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE + && TYPE_SIZE (type)) + cp_warning ("empty signature `%T' used in signature reference declaration", + type); +#if 0 + type = build_signature_reference_type (type, + constp, volatilep); +#else + sorry ("signature reference"); + return NULL_TREE; +#endif + } + else + { + if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE + && TYPE_SIZE (type)) + cp_warning ("empty signature `%T' used in signature pointer declaration", + type); + type = build_signature_pointer_type (type, + constp, volatilep); + } + constp = 0; + volatilep = 0; + } + else 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 if (TREE_CODE (type) == METHOD_TYPE) + { + type = build_ptrmemfunc_type (build_pointer_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) + pedwarn ("duplicate `const'"); + if (volatilep > 1) + pedwarn ("duplicate `volatile'"); + if (TREE_CODE (declarator) == ADDR_EXPR + && (constp || volatilep)) + { + if (constp) + warning ("discarding `const' applied to a reference"); + if (volatilep) + warning ("discarding `volatile' applied to a reference"); + constp = volatilep = 0; + } + } + 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) + { + /* This pop_nested_class corresponds to the + push_nested_class used to push into class scope for + parsing the argument list of a function decl, in + qualified_id. */ + pop_nested_class (1); + TREE_COMPLEXITY (declarator) = current_class_depth; + } + 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 (TREE_CODE (type) == FUNCTION_TYPE) + { + if (current_class_type == NULL_TREE + || TYPE_MAIN_VARIANT (ctype) == current_class_type + || friendp) + type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), + TREE_TYPE (type), TYPE_ARG_TYPES (type)); + else + { + cp_error ("cannot declare member function `%T::%s' within `%T'", + ctype, name, current_class_type); + return void_type_node; + } + } + else if (TYPE_MAIN_VARIANT (ctype) == current_class_type) + { + if (extra_warnings) + cp_warning ("redundant qualification `%T' on member `%s' ignored", + ctype, name); + type = build_offset_type (ctype, type); + } + else if (TYPE_SIZE (ctype) != NULL_TREE + || (RIDBIT_SETP (RID_TYPEDEF, specbits))) + { + 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 access 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; + } + + cp_error + ("field `%D' is not a member of structure `%T'", + sname, ctype); + } + + if (current_class_type) + { + if (TYPE_MAIN_VARIANT (ctype) != current_class_type) + { + cp_error ("cannot declare member `%T::%s' within `%T'", + ctype, name, current_class_type); + return void_type_node; + } + else if (extra_warnings) + cp_warning ("extra qualification `%T' on member `%s' ignored", + 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 + { + cp_error ("structure `%T' not yet defined", ctype); + return error_mark_node; + } + + declarator = sname; + } + 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 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 (RIDBIT_SETP (RID_TYPEDEF, specbits)) + { + tree decl; + + /* Note that the grammar rejects storage classes + in typenames, fields or parameters. */ + if (constp || volatilep) + type = c_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 != error_mark_node + && 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 (TYPE_LANG_SPECIFIC (type)) + TYPE_WAS_ANONYMOUS (type) = 1; + + { + tree d = TYPE_NAME (type), c = DECL_CONTEXT (d); + + if (!c) + set_nested_typename (d, 0, declarator, type); + else if (TREE_CODE (c) == FUNCTION_DECL) + set_nested_typename (d, DECL_ASSEMBLER_NAME (c), + declarator, type); + else + set_nested_typename (d, TYPE_NESTED_NAME (c), declarator, type); + } + } + +#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 (TREE_CODE (type) == OFFSET_TYPE || TREE_CODE (type) == METHOD_TYPE) + { + cp_error_at ("typedef name may not be class-qualified", decl); + return NULL_TREE; + } + else if (quals) + { + if (ctype == NULL_TREE) + { + if (TREE_CODE (type) != METHOD_TYPE) + cp_error_at ("invalid type qualifier for non-method type", decl); + else + ctype = TYPE_METHOD_BASETYPE (type); + } + if (ctype != NULL_TREE) + grok_method_quals (ctype, decl, quals); + } + + if (RIDBIT_SETP (RID_SIGNED, specbits) + || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) + C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; + + if (RIDBIT_SETP (RID_MUTABLE, specbits)) + { + error ("non-object member `%s' cannot be declared mutable", name); + } + + 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) + if (IS_SIGNATURE (type)) + error ("`const' or `volatile' specified with signature type"); + else + type = c_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; + } + else if (declarator == NULL_TREE && decl_context != PARM + && TREE_CODE (type) != UNION_TYPE + && ! bitfield) + { + cp_error ("abstract declarator `%T' used as declaration", type); + declarator = make_anon_name (); + } + + /* `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 (TREE_CODE (declarator) == IDENTIFIER_NODE) + { + if (IDENTIFIER_OPNAME_P (declarator)) +#if 0 /* How could this happen? */ + error ("operator `%s' declared void", + operator_name_string (declarator)); +#else + my_friendly_abort (356); +#endif + 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) + { + if (ctype) + error ("cannot use `::' in parameter declaration"); + + /* 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. */ + + if (TREE_CODE (type) == ARRAY_TYPE) + { + /* Transfer const-ness of array into that of type pointed to. */ + type = build_pointer_type + (c_build_type_variant (TREE_TYPE (type), constp, volatilep)); + volatilep = constp = 0; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + type = build_pointer_type (type); + else if (TREE_CODE (type) == OFFSET_TYPE) + type = build_pointer_type (type); + + decl = build_decl (PARM_DECL, declarator, type); + + bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE, + inlinep, friendp, raises != NULL_TREE); + if (current_class_type + && IS_SIGNATURE (current_class_type)) + { + if (inlinep) + error ("parameter of signature member function declared `inline'"); + if (RIDBIT_SETP (RID_AUTO, specbits)) + error ("parameter of signature member function declared `auto'"); + if (RIDBIT_SETP (RID_REGISTER, specbits)) + error ("parameter of signature member function declared `register'"); + } + + /* 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_promotes_to (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) + { + cp_error ("can't make `%D' into a method -- not in a class", + declarator); + return void_type_node; + } + + /* ``A union may [ ... ] not [ have ] virtual functions.'' + ARM 9.5 */ + if (virtualp && TREE_CODE (ctype) == UNION_TYPE) + { + cp_error ("function `%D' declared virtual inside a union", + declarator); + return void_type_node; + } + + if (declarator == ansi_opname[(int) NEW_EXPR] + || declarator == ansi_opname[(int) VEC_NEW_EXPR] + || declarator == ansi_opname[(int) DELETE_EXPR] + || declarator == ansi_opname[(int) VEC_DELETE_EXPR]) + { + if (virtualp) + { + cp_error ("`%D' cannot be declared virtual, since it is always static", + declarator); + virtualp = 0; + } + } + else if (staticp < 2) + 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 = (RIDBIT_SETP (RID_EXTERN, specbits) + || (ctype != NULL_TREE + && funcdef_flag >= 0 + && RIDBIT_NOTSETP (RID_INLINE, specbits)) + || (friendp + && ! funcdef_flag + && RIDBIT_NOTSETP (RID_STATIC, specbits) + && RIDBIT_NOTSETP (RID_INLINE, specbits))); + decl = grokfndecl (ctype, type, declarator, + virtualp, flags, quals, + raises, friendp ? -1 : 0, publicp); + if (decl == NULL_TREE) + return NULL_TREE; + + 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); + if (decl == NULL_TREE) + return NULL_TREE; + + 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; + return void_type_node; + } + else if (TYPE_SIZE (type) == NULL_TREE && !staticp + && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0)) + { + error ("field `%s' has incomplete type", + IDENTIFIER_POINTER (declarator)); + + /* If we're instantiating a template, tell them which + instantiation made the field's type be incomplete. */ + if (current_class_type + && TYPE_NAME (current_class_type) + && IDENTIFIER_TEMPLATE (DECL_NAME (TYPE_NAME (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) + { + error ("`%s' is neither function nor method; cannot be declared friend", + IDENTIFIER_POINTER (declarator)); + friendp = 0; + } + decl = NULL_TREE; + } + + if (friendp) + { + /* Friends are treated specially. */ + if (ctype == current_class_type) + warning ("member functions are implicitly friends of their class"); + else + { + tree t = NULL_TREE; + if (decl && DECL_NAME (decl)) + t = do_friend (ctype, declarator, decl, + last_function_parms, flags, quals); + if (t && funcdef_flag) + return t; + + return void_type_node; + } + } + + /* Structure field. It may not be a function, except for C++ */ + + if (decl == NULL_TREE) + { + if (initialized) + { + /* Motion 10 at San Diego: If a static const integral data + member is initialized with an integral constant + expression, the initializer may appear either in the + declaration (within the class), or in the definition, + but not both. If it appears in the class, the member is + a member constant. The file-scope definition is always + required. */ + if (staticp) + { + if (pedantic) + { + if (! constp) + cp_pedwarn ("ANSI C++ forbids in-class initialization of non-const static member `%D'", + declarator); + + else if (! INTEGRAL_TYPE_P (type)) + cp_pedwarn ("ANSI C++ forbids member constant `%D' of non-integral type `%T'", declarator, type); + } + } + + /* Note that initialization of const members is prohibited + by the draft ANSI standard, though it appears to be in + common practice. 12.6.2: The argument list is used to + initialize the named nonstatic member.... This (or an + initializer list) is the only way to initialize + nonstatic const and reference members. */ + else if (flag_ansi || ! constp) + cp_pedwarn ("ANSI C++ forbids initialization of %s `%D'", + constp ? "const member" : "member", 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); + TREE_STATIC (decl) = 1; + /* In class context, 'static' means public access. */ + TREE_PUBLIC (decl) = DECL_EXTERNAL (decl) = !!staticp; + } + else + { + decl = build_lang_field_decl (FIELD_DECL, declarator, type); + if (RIDBIT_SETP (RID_MUTABLE, specbits)) + { + DECL_MUTABLE_P (decl) = 1; + RIDBIT_RESET (RID_MUTABLE, specbits); + } + } + + bad_specifiers (decl, "field", virtualp, quals != NULL_TREE, + inlinep, friendp, raises != NULL_TREE); + } + } + else if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) + { + tree original_name = declarator; + int publicp = 0; + + if (! declarator) + return NULL_TREE; + + if (RIDBIT_SETP (RID_AUTO, specbits)) + error ("storage class `auto' invalid for function `%s'", name); + else if (RIDBIT_SETP (RID_REGISTER, specbits)) + error ("storage class `register' invalid 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 + && ! processing_template_decl + && (RIDBIT_SETP (RID_STATIC, specbits) + || RIDBIT_SETP (RID_INLINE, specbits)) + && pedantic) + { + if (RIDBIT_SETP (RID_STATIC, specbits)) + pedwarn ("storage class `static' invalid for function `%s' declared out of global scope", name); + else + pedwarn ("storage class `inline' invalid for function `%s' declared out of global scope", name); + } + + if (ctype == NULL_TREE) + { + if (virtualp) + { + error ("virtual non-class function `%s'", name); + virtualp = 0; + } + + 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); + } + 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_KNOWN (ctype)) + || !(RIDBIT_SETP (RID_STATIC, specbits) + || RIDBIT_SETP (RID_INLINE, specbits))); + + decl = grokfndecl (ctype, type, original_name, + virtualp, flags, quals, + raises, + processing_template_decl ? 0 : friendp ? 2 : 1, + publicp); + if (decl == NULL_TREE) + return NULL_TREE; + + if (ctype == NULL_TREE && DECL_LANGUAGE (decl) != lang_c) + 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) + { + cp_error_at ("cannot declare member function `%D' to have static linkage", decl); + illegal_static = 1; + } + else if (! 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; + } + else if (current_function_decl) + { + /* FIXME need arm citation */ + error ("cannot declare static function inside another function"); + illegal_static = 1; + } + + if (illegal_static) + { + staticp = 0; + RIDBIT_RESET (RID_STATIC, specbits); + } + } + + /* Record presence of `inline', if it is reasonable. */ + if (inlinep) + { + tree last = tree_last (TYPE_ARG_TYPES (type)); + + if (! ctype + && ! strcmp (IDENTIFIER_POINTER (original_name), "main")) + error ("cannot inline function `main'"); + else if (last && last != void_list_node) + cp_warning ("cannot inline function `%D' which takes `...'", original_name); + else + /* Assume that otherwise the function can be inlined. */ + DECL_INLINE (decl) = 1; + + if (RIDBIT_SETP (RID_EXTERN, specbits)) + { + current_extern_inline = 1; + if (flag_ansi) + pedwarn ("ANSI C++ does not permit `extern inline'"); + } + } + } + else + { + /* It's a variable. */ + + /* An uninitialized decl with `extern' is a reference. */ + decl = grokvardecl (type, declarator, specbits, initialized); + bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE, + inlinep, friendp, raises != NULL_TREE); + + if (ctype) + { + DECL_CONTEXT (decl) = ctype; + if (staticp == 1) + { + cp_error ("static member `%D' re-declared as static", + decl); + staticp = 0; + RIDBIT_RESET (RID_STATIC, specbits); + } + if (RIDBIT_SETP (RID_EXTERN, specbits)) + { + cp_error ("cannot explicitly declare member `%#D' to have extern linkage", + decl); + RIDBIT_RESET (RID_EXTERN, specbits); + } + } + } + + if (RIDBIT_SETP (RID_MUTABLE, specbits)) + { + error ("`%s' cannot be declared mutable", name); + } + + /* Record `register' declaration for warnings on & + and in case doing stupid register allocation. */ + + if (RIDBIT_SETP (RID_REGISTER, specbits)) + DECL_REGISTER (decl) = 1; + + if (RIDBIT_SETP (RID_EXTERN, specbits)) + DECL_THIS_EXTERN (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; +} + +/* 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) + pedwarn ("parameter names (without types) in function declaration"); + last_function_parms = first_parm; + return NULL_TREE; + } + else if (first_parm != NULL_TREE + && TREE_CODE (TREE_VALUE (first_parm)) != TREE_LIST + && TREE_VALUE (first_parm) != void_type_node) + my_friendly_abort (145); + 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 */ + } + else if (TREE_CODE (type) == RECORD_TYPE + && TYPE_LANG_SPECIFIC (type) + && IS_SIGNATURE (type)) + { + signature_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 ((TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + 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. */ + cp_error ("local variable `%D' may not be used as a default argument", init); + 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 form 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. */ +int +grok_ctor_properties (ctype, decl) + tree ctype, decl; +{ + tree parmtypes = FUNCTION_ARG_CHAIN (decl); + tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node; + + /* When a type has virtual baseclasses, a magical first int argument is + added to any ctor so we can tell if the class has been initialized + yet. This could screw things up in this function, so we deliberately + ignore the leading int if we're in that situation. */ + if (parmtypes + && TREE_VALUE (parmtypes) == integer_type_node + && TYPE_USES_VIRTUAL_BASECLASSES (ctype)) + { + 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; + if (TYPE_READONLY (TREE_TYPE (parmtype))) + TYPE_HAS_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) + { + cp_error ("invalid constructor; you probably meant `%T (%T&)'", + ctype, ctype); + SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype); + + return 0; + } + else + TYPE_GETS_INIT_AGGR (ctype) = 1; + } + else if (TREE_CODE (parmtype) == VOID_TYPE + || TREE_PURPOSE (parmtypes) != NULL_TREE) + TYPE_HAS_DEFAULT_CONSTRUCTOR (ctype) = 1; + + return 1; +} + +/* An operator with this name can be either unary or binary. */ +static int +ambi_op_p (name) + tree name; +{ + return (name == ansi_opname [(int) INDIRECT_REF] + || name == ansi_opname [(int) ADDR_EXPR] + || name == ansi_opname [(int) NEGATE_EXPR] + || name == ansi_opname[(int) POSTINCREMENT_EXPR] + || name == ansi_opname[(int) POSTDECREMENT_EXPR] + || name == ansi_opname [(int) CONVERT_EXPR]); +} + +/* An operator with this name can only be unary. */ +static int +unary_op_p (name) + tree name; +{ + return (name == ansi_opname [(int) TRUTH_NOT_EXPR] + || name == ansi_opname [(int) BIT_NOT_EXPR] + || name == ansi_opname [(int) COMPONENT_REF] + || OPERATOR_TYPENAME_P (name)); +} + +/* Do a little sanity-checking on how they declared their operator. */ +static void +grok_op_properties (decl, virtualp, friendp) + tree decl; + int virtualp, friendp; +{ + tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); + int methodp = (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE); + tree name = DECL_NAME (decl); + + if (current_class_type == NULL_TREE) + friendp = 1; + + if (! friendp) + { + if (name == ansi_opname[(int) MODIFY_EXPR]) + TYPE_HAS_ASSIGNMENT (current_class_type) = 1; + else if (name == ansi_opname[(int) CALL_EXPR]) + TYPE_OVERLOADS_CALL_EXPR (current_class_type) = 1; + else if (name == ansi_opname[(int) ARRAY_REF]) + TYPE_OVERLOADS_ARRAY_REF (current_class_type) = 1; + else if (name == ansi_opname[(int) COMPONENT_REF] + || name == ansi_opname[(int) MEMBER_REF]) + TYPE_OVERLOADS_ARROW (current_class_type) = 1; + else if (name == ansi_opname[(int) NEW_EXPR]) + TYPE_GETS_NEW (current_class_type) |= 1; + else if (name == ansi_opname[(int) DELETE_EXPR]) + TYPE_GETS_DELETE (current_class_type) |= 1; + else if (name == ansi_opname[(int) VEC_NEW_EXPR]) + TYPE_GETS_NEW (current_class_type) |= 2; + else if (name == ansi_opname[(int) VEC_DELETE_EXPR]) + TYPE_GETS_DELETE (current_class_type) |= 2; + } + + if (name == ansi_opname[(int) NEW_EXPR] + || name == ansi_opname[(int) VEC_NEW_EXPR]) + { + /* When the compiler encounters the definition of A::operator new, it + doesn't look at the class declaration to find out if it's static. */ + if (methodp) + revert_static_member_fn (&decl, NULL, NULL); + + /* 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 + TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl)); + } + else if (name == ansi_opname[(int) DELETE_EXPR] + || name == ansi_opname[(int) VEC_DELETE_EXPR]) + { + if (methodp) + revert_static_member_fn (&decl, NULL, NULL); + + if (argtypes == NULL_TREE) + TREE_TYPE (decl) = + build_function_type (void_type_node, + hash_tree_chain (ptr_type_node, + void_list_node)); + else + { + TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl)); + + if (! friendp && name == ansi_opname[(int) VEC_DELETE_EXPR] + && (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl))) + != void_list_node)) + TYPE_VEC_DELETE_TAKES_SIZE (current_class_type) = 1; + } + } + else + { + /* An operator function must either be a non-static member function + or have at least one parameter of a class, a reference to a class, + an enumeration, or a reference to an enumeration. 13.4.0.6 */ + if (! methodp || DECL_STATIC_FUNCTION_P (decl)) + { + if (OPERATOR_TYPENAME_P (name) + || name == ansi_opname[(int) CALL_EXPR] + || name == ansi_opname[(int) MODIFY_EXPR] + || name == ansi_opname[(int) COMPONENT_REF] + || name == ansi_opname[(int) ARRAY_REF]) + cp_error ("`%D' must be a nonstatic member function", decl); + else + { + tree p = argtypes; + + if (DECL_STATIC_FUNCTION_P (decl)) + cp_error ("`%D' must be either a non-static member function or a non-member function", decl); + + if (p) + for (; TREE_VALUE (p) != void_type_node ; p = TREE_CHAIN (p)) + { + tree arg = TREE_VALUE (p); + if (TREE_CODE (arg) == REFERENCE_TYPE) + arg = TREE_TYPE (arg); + + /* This lets bad template code slip through. */ + if (IS_AGGR_TYPE (arg) + || TREE_CODE (arg) == ENUMERAL_TYPE + || TREE_CODE (arg) == TEMPLATE_TYPE_PARM) + goto foundaggr; + } + cp_error + ("`%D' must have an argument of class or enumerated type", + decl); + foundaggr: + ; + } + } + + if (name == ansi_opname[(int) CALL_EXPR] + || name == ansi_opname[(int) METHOD_CALL_EXPR]) + return; /* no restrictions on args */ + + if (IDENTIFIER_TYPENAME_P (name)) + { + tree t = TREE_TYPE (name); + if (TREE_CODE (t) == VOID_TYPE) + pedwarn ("void is not a valid type conversion operator"); + else if (! friendp) + { + int ref = (TREE_CODE (t) == REFERENCE_TYPE); + char *what = 0; + if (ref) + t = TYPE_MAIN_VARIANT (TREE_TYPE (t)); + + if (t == current_class_type) + what = "the same type"; + else if (IS_AGGR_TYPE (t) + && DERIVED_FROM_P (t, current_class_type)) + what = "a base class"; + + if (what) + warning ("conversion to %s%s will never use a type conversion operator", + ref ? "a reference to " : "", what); + } + } + + if (name == ansi_opname[(int) MODIFY_EXPR]) + { + tree parmtype; + + if (list_length (argtypes) != 3 && methodp) + { + cp_error ("`%D' must take exactly one argument", decl); + return; + } + parmtype = TREE_VALUE (TREE_CHAIN (argtypes)); + + if (copy_assignment_arg_p (parmtype, virtualp) + && ! friendp) + { + TYPE_HAS_ASSIGN_REF (current_class_type) = 1; + if (TREE_CODE (parmtype) != REFERENCE_TYPE + || TYPE_READONLY (TREE_TYPE (parmtype))) + TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1; +#if 0 /* Too soon; done in grok_function_init */ + if (DECL_ABSTRACT_VIRTUAL_P (decl)) + TYPE_HAS_ABSTRACT_ASSIGN_REF (current_class_type) = 1; +#endif + } + } + else if (name == ansi_opname[(int) COND_EXPR]) + { + /* 13.4.0.3 */ + pedwarn ("ANSI C++ prohibits overloading operator ?:"); + if (list_length (argtypes) != 4) + cp_error ("`%D' must take exactly three arguments", decl); + } + else if (ambi_op_p (name)) + { + if (list_length (argtypes) == 2) + /* prefix */; + else if (list_length (argtypes) == 3) + { + if ((name == ansi_opname[(int) POSTINCREMENT_EXPR] + || name == ansi_opname[(int) POSTDECREMENT_EXPR]) + && TREE_VALUE (TREE_CHAIN (argtypes)) != integer_type_node) + { + if (methodp) + cp_error ("postfix `%D' must take `int' as its argument", + decl); + else + cp_error + ("postfix `%D' must take `int' as its second argument", + decl); + } + } + else + { + if (methodp) + cp_error ("`%D' must take either zero or one argument", decl); + else + cp_error ("`%D' must take either one or two arguments", decl); + } + } + else if (unary_op_p (name)) + { + if (list_length (argtypes) != 2) + { + if (methodp) + cp_error ("`%D' must take `void'", decl); + else + cp_error ("`%D' must take exactly one argument", decl); + } + } + else /* if (binary_op_p (name)) */ + { + if (list_length (argtypes) != 3) + { + if (methodp) + cp_error ("`%D' must take exactly one argument", decl); + else + cp_error ("`%D' must take exactly two arguments", decl); + } + } + + /* 13.4.0.8 */ + if (argtypes) + for (; argtypes != void_list_node ; argtypes = TREE_CHAIN (argtypes)) + if (TREE_PURPOSE (argtypes)) + { + TREE_PURPOSE (argtypes) = NULL_TREE; + if (name == ansi_opname[(int) POSTINCREMENT_EXPR] + || name == ansi_opname[(int) POSTDECREMENT_EXPR]) + { + if (pedantic) + cp_pedwarn ("`%D' cannot have default arguments", decl); + } + else + cp_error ("`%D' cannot have default arguments", decl); + } + } +} + +/* 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; +*/ + n1 = TYPE_NAME (current_class_type); + if (n1) + n1 = DECL_NESTED_TYPENAME(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_decl (TYPE_DECL, ncp, NULL_TREE); +#endif + rv = xref_tag (code_type_node, name, binfo, 0); + if (! ANON_AGGRNAME_P (name)) + { + register tree type_decl = build_decl (TYPE_DECL, ncp, rv); +#ifdef DWARF_DEBUGGING_INFO + /* Mark the TYPE_DECL node created just above as a gratuitous one + so that dwarfout.c will know not to generate a TAG_typedef DIE + for it. */ + if (write_symbols == DWARF_DEBUG) + DECL_IGNORED_P (type_decl) = 1; +#endif /* DWARF_DEBUGGING_INFO */ + pushdecl_nonclass_level (type_decl); + } + } + else + { + rv = xref_tag (code_type_node, name, binfo, 0); + } + xref_next_defn = 0; + return rv; +} + +tree +xref_tag (code_type_node, name, binfo, globalize) + tree code_type_node; + tree name, binfo; + int globalize; +{ + enum tag_types tag_code; + enum tree_code code; + int temp = 0; + int i, len; + register tree ref, t; + struct binding_level *b = inner_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: + case signature_type: + code = RECORD_TYPE; + len = list_length (binfo); + break; + case union_type: + code = UNION_TYPE; + if (binfo) + { + cp_error ("derived union `%T' invalid", 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. */ + t = IDENTIFIER_TYPE_VALUE (name); + if (t && TREE_CODE (t) != code) + t = NULL_TREE; + + 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; + if (t && TYPE_CONTEXT(t)) + { + if (TREE_MANGLED (name)) + ref = t; + else + ref = lookup_tag (code, name, b, 1); + } + else + ref = lookup_tag (code, name, b, 1); + } + else + { + if (t) + ref = t; + 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, globalize); + 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, globalize); + 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); + + /* A signature type will contain the fields of the signature + table. Therefore, it's not only an interface. */ + if (tag_code == signature_type) + { + SET_SIGNATURE (ref); + CLASSTYPE_INTERFACE_ONLY (ref) = 0; + CLASSTYPE_INTERFACE_UNKNOWN (ref) = 0; + } + + /* Record how to set the access 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_KNOWN (ref); + break; + default: + needs_writing = 0; + } + + /* Signatures don't have a vtable. As long as we don't have default + implementations, they behave as if `write_virtuals' were 3. */ + if (tag_code == signature_type) + CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = 0; + else + 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, globalize); + 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))) + { + cp_error ("type `%T' is both exception and aggregate type", ref); + 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)))) + { + cp_error ("redeclaration of derivation chain of type `%#T'", + ref); + 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 by default. */ + int via_public + = (TREE_PURPOSE (binfo) == (tree)access_public + || TREE_PURPOSE (binfo) == (tree)access_public_virtual + || (tag_code != class_type + && (TREE_PURPOSE (binfo) == (tree)access_default + || TREE_PURPOSE (binfo) == (tree)access_default_virtual))); + int via_protected = TREE_PURPOSE (binfo) == (tree)access_protected; + int via_virtual + = (TREE_PURPOSE (binfo) == (tree)access_private_virtual + || TREE_PURPOSE (binfo) == (tree)access_public_virtual + || TREE_PURPOSE (binfo) == (tree)access_default_virtual); + tree basetype = TREE_TYPE (TREE_VALUE (binfo)); + tree 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) + { + cp_error ("base class `%T' has incomplete type", basetype); + continue; + } +#endif + else + { + if (CLASSTYPE_MARKED (basetype)) + { + if (basetype == ref) + cp_error ("recursive type `%T' undefined", basetype); + else + cp_error ("duplicate base type `%T' invalid", basetype); + 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), NULL_TREE); + + 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_OVERLOADS_METHOD_CALL_EXPR (ref) |= TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype); + TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype); + TYPE_GETS_DELETE (ref) |= TYPE_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 || tag_code == signature_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 = inner_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) + cp_error ("multiple definition of enum `%T'", enumtype); + else + { + enumtype = make_node (ENUMERAL_TYPE); + pushtag (name, enumtype, 0); + } + + if (current_class_type) + TREE_ADDRESSABLE (b->tags) = 1; + current_local_enum = NULL_TREE; + + if (TYPE_VALUES (enumtype) != NULL_TREE) + /* 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); + enum_overflow = 0; + + 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, tem; + register HOST_WIDE_INT maxvalue = 0; + register HOST_WIDE_INT minvalue = 0; + register HOST_WIDE_INT i; + + /* 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_TYPE (TREE_VALUE (values)) = enumtype; + TREE_TYPE (DECL_INITIAL (TREE_VALUE (values))) = enumtype; + TREE_VALUE (values) = DECL_INITIAL (TREE_VALUE (values)); + value = TREE_INT_CST_LOW (TREE_VALUE (values)); + minvalue = maxvalue = value; + + for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair)) + { + TREE_TYPE (TREE_VALUE (pair)) = enumtype; + TREE_TYPE (DECL_INITIAL (TREE_VALUE (pair))) = enumtype; + TREE_VALUE (pair) = DECL_INITIAL (TREE_VALUE (pair)); + value = TREE_INT_CST_LOW (TREE_VALUE (pair)); + if (value > maxvalue) + maxvalue = value; + else if (value < minvalue) + minvalue = value; + } + } + + TYPE_VALUES (enumtype) = values; + + if (flag_short_enums) + { + /* Determine the precision this type needs, lay it out, and define + it. */ + + /* First reset precision */ + TYPE_PRECISION (enumtype) = 0; + + 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); + + /* Fix up all variant types of this enum type. */ + for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) + { + TYPE_VALUES (tem) = TYPE_VALUES (enumtype); + TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype); + TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype); + TYPE_SIZE (tem) = TYPE_SIZE (enumtype); + TYPE_MODE (tem) = TYPE_MODE (enumtype); + TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); + TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype); + TREE_UNSIGNED (tem) = TREE_UNSIGNED (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) + { + value = default_conversion (value); + constant_expression_warning (value); + } + else + { + cp_error ("enumerator value for `%D' not integer constant", 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; + if (enum_overflow) + cp_error ("overflow in enumeration values at `%D'", name); + } + + /* Remove no-op casts from the value. */ + if (value) + STRIP_TYPE_NOPS (value); + + /* Make up for hacks in 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; + } + + /* C++ associates enums with global, function, or class declarations. */ + + decl = current_scope (); + if (decl && decl == current_class_type) + { + /* This enum declaration is local to the class, so we must put + it in that class's list of decls. */ + 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; + } + else + { + /* It's a global enum, or it's local to a function. (Note local to + a function could mean local to a class method. */ + decl = build_decl (CONST_DECL, name, integer_type_node); + DECL_INITIAL (decl) = value; + + pushdecl (decl); + GNU_xref_decl (current_function_decl, decl); + } + + /* Set basis for default for next value. */ + enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value, + integer_one_node, PLUS_EXPR); + enum_overflow = tree_int_cst_lt (enum_next_value, value); + + if (enum_next_value == integer_one_node) + enum_next_value = copy_node (enum_next_value); + + result = saveable_tree_cons (name, decl, NULL_TREE); + 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; +{ + 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; + + /* 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; + + if (! DECL_ARGUMENTS (decl1) + && !DECL_STATIC_FUNCTION_P (decl1) + && DECL_CONTEXT (decl1) + && DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl1))) + && IDENTIFIER_TEMPLATE (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl1))))) + { + cp_error ("redeclaration of `%#D'", decl1); + if (IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1))) + cp_error_at ("previous declaration here", IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1))); + else if (IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl1))) + cp_error_at ("previous declaration here", IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl1))); + } + + 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 = DECL_CLASS_CONTEXT (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 = DECL_THIS_EXTERN (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) && ! TYPE_PTRMEMFUNC_P (restype) + && ! CLASSTYPE_GOT_SEMICOLON (restype)) + { + cp_error ("semicolon missing after declaration of `%#T'", restype); + 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) + { + if (pedantic || warn_return_type) + 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) + cp_warning_at ("`%D' implicitly declared before its definition", IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1))); + + 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; + + /* 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 (pre_parsed_p == 0) + { + current_function_decl = decl1 = pushdecl (decl1); + DECL_MAIN_VARIANT (decl1) = decl1; + fntype = TREE_TYPE (decl1); + } + else + current_function_decl = decl1; + + /* 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 if (DECL_EXPLICIT_INSTANTIATION (decl1)) + /* PUBLIC and EXTERNAL set by do_*_instantiation */; + 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; + + DECL_DEFER_OUTPUT (decl1) = DECL_INLINE (decl1); + } + + 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) + { + push_nested_class (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)) + push_nested_class (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; + + /* 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); + + 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 + cp_error_at ("parameter name omitted", parm); +#else + /* for C++, this is not an error. */ + pushdecl (parm); +#endif + } + else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node) + cp_error ("parameter `%D' declared void", parm); + else + { + /* Now fill in DECL_REFERENCE_SLOT for any of the parm decls. + A parameter is assumed not to have any side effects. + If this should change for any reason, then this + will have to wrap the bashed reference type in a save_expr. + + Also, if the parameter type is declared to be an X + and there is an X(X&) constructor, we cannot lay it + into the stack (any more), so we make this parameter + look like it is really of reference type. Functions + which pass parameters to this function will know to + create a temporary in their frame, and pass a reference + to that. */ + + if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE + && TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm)))) + SET_DECL_REFERENCE_SLOT (parm, convert_from_reference (parm)); + + pushdecl (parm); + } + if (cleanup) + { + expand_decl (parm); + if (! expand_decl_cleanup (parm, cleanup)) + cp_error ("parser lost in parsing declaration of `%D'", + parm); + 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); + + /* 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); + if (! expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup)) + cp_error ("parser lost in parsing declaration of `%D'", fndecl); + } + + /* 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 (flag_ansi) + /* 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. */ + pedwarn ("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); + } +} + +#if 0 +/* Generate code for default 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_HAS_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); + init = build_tree_list (NULL_TREE, init); + + current_member_init_list + = tree_cons (DECL_NAME (fields), init, current_member_init_list); + } +} +#endif + +/* 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; + /* Label to use if this function is supposed to return a value. */ + tree no_return_label = NULL_TREE; + tree decls = 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); + expand_start_bindings (0); + + if (current_function_assigns_this) + { + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + } + + /* Generate the code to call destructor on base class. + If this destructor belongs to a class with virtual + functions, then set the virtual function table + pointer to represent the type of our base class. */ + + /* This side-effect makes call to `build_delete' generate the + code we have to have at the end of this destructor. */ + TYPE_HAS_DESTRUCTOR (current_class_type) = 0; + + /* These are two cases where we cannot delegate deletion. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type) + || TYPE_GETS_REG_DELETE (current_class_type)) + exprstmt = build_delete (current_class_type, C_C_D, integer_zero_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); + else + exprstmt = build_delete (current_class_type, C_C_D, in_charge_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 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)); + } + 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 (TYPE_GETS_REG_DELETE (current_class_type)) + /* This NOP_EXPR means we are in a static call context. */ + exprstmt = + build_method_call + (build_indirect_ref + (build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type), + error_mark_node), + NULL_PTR), + 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. */ + expand_end_bindings (NULL_TREE, getdecls() != NULL_TREE, 0); + poplevel (2, 0, 0); /* XXX change to 1 */ + + /* Back to the top of destructor. */ + /* Dont execute destructor code if `this' is NULL. */ + mark = get_last_insn (); + last_parm_insn = get_first_nonparm_insn (); + if (last_parm_insn == NULL_RTX) + last_parm_insn = mark; + else + last_parm_insn = previous_insn (last_parm_insn); + + /* Make all virtual function table pointers in non-virtual base + classes point to CURRENT_CLASS_TYPE's virtual function + tables. */ + expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_decl); + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + expand_indirect_vtbls_init (binfo, C_C_D, current_class_decl, 0); + 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) + { + decls = getdecls (); + 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)); + } + + 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); + expand_end_cond (); + } + +#if 0 + if (DECL_NAME (fndecl) == NULL_TREE + && TREE_CHAIN (DECL_ARGUMENTS (fndecl)) != NULL_TREE) + build_default_constructor (fndecl); +#endif + + /* 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 (call_poplevel) + { + expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0); + poplevel (decls != NULL_TREE, 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); + + /* 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; + pop_nested_class (1); + } + else + pop_memoized_context (1); + + /* Generate rtl for function exit. */ + expand_function_end (input_filename, lineno, 1); + + if (flag_handle_exceptions) + expand_exception_blocks(); + + /* 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 (DECL_INLINE (fndecl) + && !TREE_ASM_WRITTEN (fndecl) && DECL_FUNCTION_MEMBER_P (fndecl)) + { + mark_inline_for_output (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) + cp_warning ("`noreturn' function `%D' does return", fndecl); + else if ((warn_return_type || pedantic) + && 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. */ + cp_pedwarn ("control reaches end of non-void function `%D'", fndecl); + } + /* 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 (1); + + 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; +} + +/* 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 return type and the name of the function, + 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 (IS_SIGNATURE (current_class_type)) + { + IS_DEFAULT_IMPLEMENTATION (fndecl) = 1; + /* In case we need this info later. */ + HAS_DEFAULT_IMPLEMENTATION (current_class_type) = 1; + } + + if (DECL_IN_AGGR_P (fndecl)) + { + if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type) + { + if (DECL_CONTEXT (fndecl)) + cp_error ("`%D' is already defined in class %s", fndecl, + TYPE_NAME_STRING (DECL_CONTEXT (fndecl))); + } + return void_type_node; + } + + if (flag_default_inline) + DECL_INLINE (fndecl) = 1; + + if (processing_template_defn) + SET_DECL_IMPLICIT_INSTANTIATION (fndecl); + + /* 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)) + { + if (! grok_ctor_properties (current_class_type, fndecl)) + return void_type_node; + } + else if (IDENTIFIER_OPNAME_P (DECL_NAME (fndecl))) + grok_op_properties (fndecl, DECL_VIRTUAL_P (fndecl), 0); + } + + 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; + + register tree link; + + if (TYPE_MAIN_VARIANT (decl) == void_type_node) + return decl; + + 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); + + poplevel (0, 0, 0); + + DECL_INITIAL (fndecl) = old_initial; + + /* We used to check if the context of FNDECL was different from + current_class_type as another way to get inside here. This didn't work + for String.cc in libg++. */ + if (DECL_FRIEND_P (fndecl)) + { + CLASSTYPE_INLINE_FRIENDS (current_class_type) + = tree_cons (NULL_TREE, fndecl, CLASSTYPE_INLINE_FRIENDS (current_class_type)); + decl = void_type_node; + } + + 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) + { + tree cleanup; + expand_decl (decl); + cleanup = maybe_build_cleanup (decl); + expand_decl_init (decl); + if (! expand_decl_cleanup (decl, cleanup)) + cp_error ("parser lost in parsing declaration of `%D'", + decl); + } + } + my_friendly_assert (current_binding_level->n_incomplete > 0, 164); + --current_binding_level->n_incomplete; + } +} + +/* 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); + + 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)))); + + 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) + { + cp_warning ("reference, not call, to function `%D'", exp); + warning ("at this point in file"); + } + +#if 0 + /* We should do this eventually, but right now this causes regex.o from + libg++ to miscompile, and tString to core dump. */ + exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); +#endif + expand_expr_stmt (break_out_cleanups (exp)); + } + + /* 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 (); +} + +/* Change a static member function definition into a FUNCTION_TYPE, instead + of the METHOD_TYPE that we create when it's originally parsed. + + WARNING: DO NOT pass &TREE_TYPE (decl) to FN or &TYPE_ARG_TYPES + (TREE_TYPE (decl)) to ARGTYPES, as doing so will corrupt the types of + other decls. Either pass the addresses of local variables or NULL. */ + +void +revert_static_member_fn (decl, fn, argtypes) + tree *decl, *fn, *argtypes; +{ + tree tmp; + tree function = fn ? *fn : TREE_TYPE (*decl); + tree args = argtypes ? *argtypes : TYPE_ARG_TYPES (function); + + args = TREE_CHAIN (args); + tmp = build_function_type (TREE_TYPE (function), args); + tmp = build_type_variant (tmp, TYPE_READONLY (function), + TYPE_VOLATILE (function)); + tmp = build_exception_variant (TYPE_METHOD_BASETYPE (function), tmp, + TYPE_RAISES_EXCEPTIONS (function)); + TREE_TYPE (*decl) = tmp; + DECL_STATIC_FUNCTION_P (*decl) = 1; + if (fn) + *fn = tmp; + if (argtypes) + *argtypes = args; +} + +int +id_in_current_class (id) + tree id; +{ + return !!purpose_member (id, class_binding_level->class_shadowed); +} |