diff options
author | YamaArashi <shadow962@live.com> | 2016-01-06 01:47:28 -0800 |
---|---|---|
committer | YamaArashi <shadow962@live.com> | 2016-01-06 01:47:28 -0800 |
commit | be8b04496302184c6e8f04d6179f9c3afc50aeb6 (patch) | |
tree | 726e2468c0c07add773c0dbd86ab6386844259ae /gcc/cp/decl.c |
initial commit
Diffstat (limited to 'gcc/cp/decl.c')
-rwxr-xr-x | gcc/cp/decl.c | 14623 |
1 files changed, 14623 insertions, 0 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c new file mode 100755 index 0000000..b023a2f --- /dev/null +++ b/gcc/cp/decl.c @@ -0,0 +1,14623 @@ +/* Process declarations and variables for C compiler. + Copyright (C) 1988, 92-98, 1999 Free Software Foundation, Inc. + Contributed 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 "config.h" +#include "system.h" +#include "tree.h" +#include "rtl.h" +#include "flags.h" +#include "cp-tree.h" +#include "decl.h" +#include "lex.h" +#include <signal.h> +#include "obstack.h" +#include "defaults.h" +#include "output.h" +#include "except.h" +#include "toplev.h" +#include "../hash.h" + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +extern tree builtin_return_address_fndecl; + +extern struct obstack permanent_obstack; +extern struct obstack* saveable_obstack; + +extern int current_class_depth; + +extern tree static_ctors, static_dtors; + +extern int static_labelno; + +extern tree current_namespace; +extern tree global_namespace; + +extern void (*print_error_function) PROTO((char *)); + +/* 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" +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 + +#ifndef BOOL_TYPE_SIZE +#ifdef SLOW_BYTE_ACCESS +#define BOOL_TYPE_SIZE ((SLOW_BYTE_ACCESS) ? (POINTER_SIZE) : (CHAR_TYPE_SIZE)) +#else +#define BOOL_TYPE_SIZE CHAR_TYPE_SIZE +#endif +#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 + +static tree grokparms PROTO((tree, int)); +static tree lookup_nested_type PROTO((tree, tree)); +static char *redeclaration_error_message PROTO((tree, tree)); + +static struct stack_level *push_decl_level PROTO((struct stack_level *, + struct obstack *)); +static void push_binding_level PROTO((struct binding_level *, int, + int)); +static void pop_binding_level PROTO((void)); +static void suspend_binding_level PROTO((void)); +static void resume_binding_level PROTO((struct binding_level *)); +static struct binding_level *make_binding_level PROTO((void)); +static void declare_namespace_level PROTO((void)); +static void signal_catch PROTO((int)) ATTRIBUTE_NORETURN; +static void storedecls PROTO((tree)); +static void storetags PROTO((tree)); +static void require_complete_types_for_parms PROTO((tree)); +static void push_overloaded_decl_1 PROTO((tree)); +static int ambi_op_p PROTO((tree)); +static int unary_op_p PROTO((tree)); +static tree store_bindings PROTO((tree, tree)); +static tree lookup_tag_reverse PROTO((tree, tree)); +static tree obscure_complex_init PROTO((tree, tree)); +static tree maybe_build_cleanup_1 PROTO((tree, tree)); +static tree lookup_name_real PROTO((tree, int, int, int)); +static void warn_extern_redeclared_static PROTO((tree, tree)); +static void grok_reference_init PROTO((tree, tree, tree)); +static tree grokfndecl PROTO((tree, tree, tree, tree, int, + enum overload_flags, tree, + tree, tree, int, int, int, int, int, int, tree)); +static tree grokvardecl PROTO((tree, tree, RID_BIT_TYPE *, int, int, tree)); +static tree lookup_tag PROTO((enum tree_code, tree, + struct binding_level *, int)); +static void set_identifier_type_value_with_scope + PROTO((tree, tree, struct binding_level *)); +static void record_builtin_type PROTO((enum rid, char *, tree)); +static void record_unknown_type PROTO((tree, char *)); +static int member_function_or_else PROTO((tree, tree, char *)); +static void bad_specifiers PROTO((tree, char *, int, int, int, int, + int)); +static void lang_print_error_function PROTO((char *)); +static tree maybe_process_template_type_declaration PROTO((tree, int, struct binding_level*)); +static void check_for_uninitialized_const_var PROTO((tree)); +static unsigned long typename_hash PROTO((hash_table_key)); +static boolean typename_compare PROTO((hash_table_key, hash_table_key)); +static void push_binding PROTO((tree, tree, struct binding_level*)); +static void add_binding PROTO((tree, tree)); +static void pop_binding PROTO((tree, tree)); +static tree local_variable_p PROTO((tree)); + +#if defined (DEBUG_CP_BINDING_LEVELS) +static void indent PROTO((void)); +#endif + +/* A node which has tree code ERROR_MARK, and whose type is itself. + All erroneous expressions are replaced with this node. All functions + that accept nodes as arguments should avoid generating error messages + if this node is one of the arguments, since it is undesirable to get + multiple error messages from one error in the input. */ + +tree error_mark_node; + +/* Erroneous argument lists can use this *IFF* they do not modify it. */ +tree error_mark_list; + +/* 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 wchar_decl_node; + +tree float_type_node; +tree double_type_node; +tree long_double_type_node; + +tree complex_integer_type_node; +tree complex_float_type_node; +tree complex_double_type_node; +tree complex_long_double_type_node; + +tree intQI_type_node; +tree intHI_type_node; +tree intSI_type_node; +tree intDI_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 +tree intTI_type_node; +#endif + +tree unsigned_intQI_type_node; +tree unsigned_intHI_type_node; +tree unsigned_intSI_type_node; +tree unsigned_intDI_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 +tree unsigned_intTI_type_node; +#endif + +tree java_byte_type_node; +tree java_short_type_node; +tree java_int_type_node; +tree java_long_type_node; +tree java_float_type_node; +tree java_double_type_node; +tree java_char_type_node; +tree java_boolean_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; +tree 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 boolean_type_node, boolean_true_node, boolean_false_node; + +/* Type `int ()' -- used for implicit declaration of functions. */ + +tree default_function_type; + +/* Function types `double (double)' and `double (double, double)', etc. */ + +static tree double_ftype_double, double_ftype_double_double; +static tree int_ftype_int, long_ftype_long; +static tree float_ftype_float; +static tree ldouble_ftype_ldouble; + +/* Function type `int (const void *, const void *, size_t)' */ +static tree int_ftype_cptr_cptr_sizet; + +/* C++ extensions */ +tree vtable_entry_type; +tree delta_type_node; +#if 0 +/* Old rtti stuff. */ +tree __baselist_desc_type_node; +tree __i_desc_type_node, __m_desc_type_node; +tree __t_desc_array_type, __i_desc_array_type, __m_desc_array_type; +#endif +tree __t_desc_type_node; +#if 0 +tree __tp_desc_type_node; +#endif +tree __access_mode_type_node; +tree __bltn_desc_type_node, __user_desc_type_node, __class_desc_type_node; +tree __ptr_desc_type_node, __attr_desc_type_node, __func_desc_type_node; +tree __ptmf_desc_type_node, __ptmd_desc_type_node; +#if 0 +/* Not needed yet? May be needed one day? */ +tree __bltn_desc_array_type, __user_desc_array_type, __class_desc_array_type; +tree __ptr_desc_array_type, __attr_dec_array_type, __func_desc_array_type; +tree __ptmf_desc_array_type, __ptmd_desc_array_type; +#endif + +/* Indicates that there is a type value in some namespace, although + that is not necessarily in scope at the moment. */ + +static tree global_type_node; + +tree class_star_type_node; +tree class_type_node, record_type_node, union_type_node, enum_type_node; +tree unknown_type_node; +tree opaque_type_node, signature_type_node; +tree sigtable_entry_type; + +/* Array type `vtable_entry_type[]' */ +tree vtbl_type_node; +tree vtbl_ptr_type_node; + +/* namespace std */ +tree std_node; +int in_std = 0; + +/* Expect only namespace names now. */ +static int only_namespace_names; + +/* 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 destructor, the last insn emitted after the start of the + function and the parms. */ + +static rtx last_dtor_insn; + +/* In a constructor, the last insn emitted after the start of the + function and the parms, the exception specification and any + function-try-block. The constructor initializers are emitted after + this insn. */ + +static rtx last_parm_cleanup_insn; + +/* 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; + +/* A FUNCTION_DECL for the default `::operator delete'. */ + +tree global_delete_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. */ +static rtx original_result_rtx; + +/* Sequence of insns which represents base initialization. */ +tree base_init_expr; + +/* 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; +tree ctor_identifier, dtor_identifier; +/* Used in pointer to member functions, in vtables, and in sigtables. */ +tree pfn_identifier, index_identifier, delta_identifier, delta2_identifier; +tree pfn_or_delta2_identifier, tag_identifier; +tree vt_off_identifier; + +struct named_label_list +{ + struct binding_level *binding_level; + tree names_in_scope; + tree label_decl; + char *filename_o_goto; + int lineno_o_goto; + struct named_label_list *next; +}; + +/* A list (chain of TREE_LIST nodes) of named label uses. + The TREE_PURPOSE field is the list of variables defined + in the label's scope defined at the point of use. + The TREE_VALUE field is the LABEL_DECL used. + The TREE_TYPE field holds `current_binding_level' at the + point of the label's use. + + BWAHAHAAHAHahhahahahaah. No, no, no, said the little chicken. + + Look at the pretty struct named_label_list. See the pretty struct + with the pretty named fields that describe what they do. See the + pretty lack of gratuitous casts. Notice the code got a lot cleaner. + + Used only for jumps to as-yet undefined labels, since + jumps to defined labels can have their validity checked + by stmt.c. */ + +static struct named_label_list *named_label_uses = NULL; + +/* 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; + +/* The value for __null (NULL), namely, a zero of an integer type with + the same number of bits as a pointer. */ +tree null_node; + +/* A node for the integer constants 1, 2, and 3. */ + +tree integer_one_node, integer_two_node, integer_three_node; + +/* While defining an enum type, this is 1 plus the last enumerator + constant value. */ + +static tree enum_next_value; + +/* Nonzero means that there was overflow computing enum_next_value. */ + +static int enum_overflow; + +/* 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; + +/* The FUNCTION_DECL for the function currently being compiled, + or 0 if between functions. */ +tree current_function_decl; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement that specifies a return value is seen. */ + +int current_function_returns_value; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement with no argument is seen. */ + +int current_function_returns_null; + +/* Set to 0 at beginning of a function definition, and whenever + a label (case or named) is defined. Set to value of expression + returned from function when that value can be transformed into + a named return value. */ + +tree current_function_return_value; + +/* Nonzero means 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 don't recognize the non-ANSI builtin functions. + -ansi sets this. */ + +extern int flag_no_nonansi_builtin; + +/* Nonzero means enable obscure ANSI features and disable GNU extensions + that might cause ANSI-compliant code to be miscompiled. */ + +extern int flag_ansi; + +/* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes) + objects. */ +extern int flag_huge_objects; + +/* 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 flagging 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. */ +static 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; + +/* 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; + +/* A expression of value 0 with the same precision as a sizetype + node, but signed. */ +tree signed_size_zero_node; + +/* The name of the anonymous namespace, throughout this translation + unit. */ +tree anonymous_namespace_name; + + +/* Allocate a level of searching. */ + +static +struct stack_level * +push_decl_level (stack, obstack) + struct stack_level *stack; + struct obstack *obstack; +{ + struct stack_level tem; + tem.prev = stack; + + return push_stack_level (obstack, (char *)&tem, sizeof (tem)); +} + +/* 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. Thus, to see whether a name is bound in + the current scope, it is not enough to look in the + CURRENT_BINDING_LEVEL. You should use lookup_name_current_level + instead. */ + +/* 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. There may be OVERLOADs on this list, too, but they + are wrapped in TREE_LISTs; the TREE_VALUE is the OVERLOAD. */ + 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; + + /* A list of USING_DECL nodes. */ + tree usings; + + /* A list of used namespaces. PURPOSE is the namespace, + VALUE the common ancestor with this binding_level's namespace. */ + tree using_directives; + + /* If this binding level is the binding level for a class, then + class_shadowed is a TREE_LIST. The TREE_PURPOSE of each node + is the name of an entity bound in the class; the TREE_VALUE is + the IDENTIFIER_CLASS_VALUE before we entered the class. Thus, + when leaving class scope, we can restore the + IDENTIFIER_CLASS_VALUE by walking this list. The TREE_TYPE is + the DECL bound by this name in the class. */ + tree class_shadowed; + + /* Similar to class_shadowed, but for IDENTIFIER_TYPE_VALUE, and + is used for all binding levels. */ + 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; + + /* List of decls in `names' that have incomplete + structure or union types. */ + tree incomplete; + + /* List of VAR_DECLS saved from a previous for statement. + These would be dead in ANSI-conforming code, but might + be referenced in ARM-era code. These are stored in a + TREE_LIST; the TREE_VALUE is the actual declaration. */ + tree dead_vars_from_for; + + /* 1 for the level that holds the parameters of a function. + 2 for the level that holds a class declaration. + 3 for levels that hold parameter declarations. */ + unsigned parm_flag : 4; + + /* 1 means make a BLOCK for this level regardless of all else. + 2 for temporary binding contours created by the compiler. */ + unsigned keep : 3; + + /* Nonzero if this level "doesn't exist" for tags. */ + unsigned tag_transparent : 1; + + /* Nonzero if this level can safely have additional + cleanup-needing variables added to it. */ + unsigned more_cleanups_ok : 1; + unsigned have_cleanups : 1; + + /* Nonzero if this level is for storing the decls for template + parameters and generic decls; these decls will be discarded and + replaced with a TEMPLATE_DECL. */ + unsigned pseudo_global : 1; + + /* This is set for a namespace binding level. */ + unsigned namespace_p : 1; + + /* True if this level is that of a for-statement where we need to + worry about ambiguous (ARM or ANSI) scope rules. */ + unsigned is_for_scope : 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)) + { + indent (); + fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n"); + } + 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; + } +} + +static void +suspend_binding_level () +{ + if (class_binding_level) + current_binding_level = class_binding_level; + + if (global_binding_level) + { + /* Cannot suspend a level, if there are none left to suspend. */ + if (current_binding_level == global_binding_level) + my_friendly_abort (123); + } + /* Suspend the current level. */ +#if defined(DEBUG_CP_BINDING_LEVELS) + binding_depth--; + indent (); + fprintf (stderr, "suspend %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)) + { + indent (); + fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n"); + } + is_class_level = 0; +#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ + { + current_binding_level = current_binding_level->level_chain; + 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; + } +} + +static void +resume_binding_level (b) + struct binding_level *b; +{ + /* Resuming binding levels is meant only for namespaces, + and those cannot nest into classes. */ + my_friendly_assert(!class_binding_level, 386); + /* Also, resuming a non-directly nested namespace is a no-no. */ + my_friendly_assert(b->level_chain == current_binding_level, 386); + current_binding_level = b; +#if defined(DEBUG_CP_BINDING_LEVELS) + b->binding_depth = binding_depth; + indent (); + fprintf (stderr, "resume %s level 0x%08x line %d\n", + (is_class_level) ? "class" : "block", b, lineno); + is_class_level = 0; + binding_depth++; +#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ +} + +/* Create a new `struct binding_level'. */ + +static +struct binding_level * +make_binding_level () +{ + /* NOSTRICT */ + return (struct binding_level *) xmalloc (sizeof (struct binding_level)); +} + +/* Nonzero if we are currently in the global binding level. */ + +int +global_bindings_p () +{ + return current_binding_level == global_binding_level; +} + +/* Nonzero if we are currently in a toplevel binding level. This + means either the global binding level or a namespace in a toplevel + binding level. + Since there are no non-toplevel namespace levels, this really + means any namespace or pseudo-global level. */ + +int +toplevel_bindings_p () +{ + return current_binding_level->namespace_p + || current_binding_level->pseudo_global; +} + +/* Nonzero if this is a namespace scope. */ + +int +namespace_bindings_p () +{ + return current_binding_level->namespace_p; +} + +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_pseudo_global_level () +{ + current_binding_level->pseudo_global = 1; +} + +static void +declare_namespace_level () +{ + current_binding_level->namespace_p = 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 + { + newlevel = make_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 +note_level_for_for () +{ + current_binding_level->is_for_scope = 1; +} + +void +pushlevel_temporary (tag_transparent) + int tag_transparent; +{ + pushlevel (tag_transparent); + current_binding_level->keep = 2; + clear_last_expr (); + + /* Note we don't call push_momentary() here. Otherwise, it would cause + cleanups to be allocated on the momentary obstack, and they will be + overwritten by the next statement. */ + + expand_start_bindings (0); +} + +/* For a binding between a name and an entity at a block scope, + this is the `struct binding_level' for the block. */ +#define BINDING_LEVEL(NODE) \ + (((struct tree_binding*)NODE)->scope.level) + +/* These are currently unused, but permanent, CPLUS_BINDING nodes. + They are kept here because they are allocated from the permanent + obstack and cannot be easily freed. */ +static tree free_binding_nodes; + +/* Make DECL the innermost binding for ID. The LEVEL is the binding + level at which this declaration is being bound. */ + +static void +push_binding (id, decl, level) + tree id; + tree decl; + struct binding_level* level; +{ + tree binding; + + if (!free_binding_nodes) + { + /* There are no free nodes, so we must build one here. */ + push_obstacks_nochange (); + end_temporary_allocation (); + binding = make_node (CPLUS_BINDING); + pop_obstacks (); + } + else + { + /* There are nodes on the free list. Grab the first one. */ + binding = free_binding_nodes; + + /* And update the free list. */ + free_binding_nodes = TREE_CHAIN (free_binding_nodes); + } + + /* Now, fill in the binding information. */ + BINDING_VALUE (binding) = decl; + BINDING_TYPE (binding) = NULL_TREE; + BINDING_LEVEL (binding) = level; + LOCAL_BINDING_P (binding) = (level != class_binding_level); + + /* And put it on the front of the ilst of bindings for ID. */ + TREE_CHAIN (binding) = IDENTIFIER_BINDING (id); + IDENTIFIER_BINDING (id) = binding; +} + +/* ID is already bound in the current scope. But, DECL is an + additional binding for ID in the same scope. This is the `struct + stat' hack whereby a non-typedef class-name or enum-name can be + bound at the same level as some other kind of entity. It's the + responsibility of the caller to check that inserting this name is + legal here. */ +static void +add_binding (id, decl) + tree id; + tree decl; +{ + tree binding = IDENTIFIER_BINDING (id); + + if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + /* The new name is the type name. */ + BINDING_TYPE (binding) = decl; + else + { + /* The old name must be the type name. It was placed in + IDENTIFIER_VALUE because it was thought, at the point it + was declared, to be the only entity with such a name. */ + my_friendly_assert (TREE_CODE (BINDING_VALUE (binding)) == TYPE_DECL + && DECL_ARTIFICIAL (BINDING_VALUE (binding)), + 0); + + /* Move the type name into the type slot; it is now hidden by + the new binding. */ + BINDING_TYPE (binding) = BINDING_VALUE (binding); + BINDING_VALUE (binding) = decl; + } +} + +/* Bind DECL to ID in the current_binding_level. + If PUSH_USING is set in FLAGS, we know that DECL doesn't really belong + to this binding level, that it got here through a using-declaration. */ + +void +push_local_binding (id, decl, flags) + tree id; + tree decl; + int flags; +{ + tree d = decl; + + if (lookup_name_current_level (id)) + /* Supplement the existing binding. */ + add_binding (id, d); + else + /* Create a new binding. */ + push_binding (id, d, current_binding_level); + + if (TREE_CODE (decl) == OVERLOAD || (flags & PUSH_USING)) + /* We must put the OVERLOAD into a TREE_LIST since the + TREE_CHAIN of an OVERLOAD is already used. Similarly for + decls that got here through a using-declaration. */ + decl = build_tree_list (NULL_TREE, decl); + + /* And put DECL on the list of things declared by the current + binding level. */ + TREE_CHAIN (decl) = current_binding_level->names; + current_binding_level->names = decl; +} + +/* Bind DECL to ID in the class_binding_level. */ + +void +push_class_binding (id, decl) + tree id; + tree decl; +{ + if (IDENTIFIER_BINDING (id) + && BINDING_LEVEL (IDENTIFIER_BINDING (id)) == class_binding_level) + /* Supplement the existing binding. */ + add_binding (id, decl); + else + /* Create a new binding. */ + push_binding (id, decl, class_binding_level); + + /* Update the IDENTIFIER_CLASS_VALUE for this ID to be the + class-level declaration. Note that we do not use DECL here + because of the possibility of the `struct stat' hack; if DECL is + a class-name or enum-name we might prefer a field-name, or some + such. */ + IDENTIFIER_CLASS_VALUE (id) = BINDING_VALUE (IDENTIFIER_BINDING (id)); +} + +/* Remove the binding for DECL which should be the innermost binding + for ID. */ + +static void +pop_binding (id, decl) + tree id; + tree decl; +{ + tree binding; + + if (id == NULL_TREE) + /* It's easiest to write the loops that call this function without + checking whether or not the entities involved have names. We + get here for such an entity. */ + return; + + /* Get the innermost binding for ID. */ + binding = IDENTIFIER_BINDING (id); + + /* The name should be bound. */ + my_friendly_assert (binding != NULL_TREE, 0); + + /* The DECL will be either the ordinary binding or the type + binding for this identifier. Remove that binding. */ + if (BINDING_VALUE (binding) == decl) + BINDING_VALUE (binding) = NULL_TREE; + else if (BINDING_TYPE (binding) == decl) + BINDING_TYPE (binding) = NULL_TREE; + else + my_friendly_abort (0); + + if (!BINDING_VALUE (binding) && !BINDING_TYPE (binding)) + { + /* We're completely done with the innermost binding for this + identifier. Unhook it from the list of bindings. */ + IDENTIFIER_BINDING (id) = TREE_CHAIN (binding); + + /* And place it on the free list. */ + TREE_CHAIN (binding) = free_binding_nodes; + free_binding_nodes = binding; + } +} + +/* 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 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 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; + int leaving_for_scope; + + if (current_binding_level->parm_flag == 2 + || current_binding_level->class_shadowed) + /* We should not be using poplevel to pop a class binding level. + Use poplevel_class instead. */ + my_friendly_abort (0); + + /* We used to use KEEP == 2 to indicate that the new block should go + at the beginning of the list of blocks at this binding level, + rather than the end. This hack is no longer used. */ + my_friendly_assert (keep == 0 || keep == 1, 0); + + 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); + + if (current_binding_level->keep == 1) + keep = 1; + + /* 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) + && decl_function_context (decl) == current_function_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) + { + if (block_previously_created) + { + if (decls || tags || subblocks) + { + if (BLOCK_VARS (block) || BLOCK_TYPE_TAGS (block)) + warning ("internal compiler error: debugging info corrupted"); + + BLOCK_VARS (block) = decls; + BLOCK_TYPE_TAGS (block) = tags; + + /* We can have previous subblocks and new subblocks when + doing fixup_gotos with complex cleanups. We chain the new + subblocks onto the end of any pre-existing subblocks. */ + BLOCK_SUBBLOCKS (block) = chainon (BLOCK_SUBBLOCKS (block), + subblocks); + } + /* If we created the block earlier on, and we are just + diddling it now, then it already should have a proper + BLOCK_END_NOTE value associated with it. */ + } + else + { + BLOCK_VARS (block) = decls; + BLOCK_TYPE_TAGS (block) = tags; + BLOCK_SUBBLOCKS (block) = subblocks; + /* Otherwise, for a new block, install a new BLOCK_END_NOTE + value. */ + remember_end_note (block); + } + } + + /* In each subblock, record that this is its superior. */ + + if (keep >= 0) + for (link = subblocks; link; link = TREE_CHAIN (link)) + BLOCK_SUPERCONTEXT (link) = block; + + /* We still support the old for-scope rules, whereby the variables + in a for-init statement were in scope after the for-statement + ended. We only use the new rules in flag_new_for_scope is + nonzero. */ + leaving_for_scope + = current_binding_level->is_for_scope && flag_new_for_scope == 1; + + /* Remove declarations for all the DECLs in this level. */ + for (link = decls; link; link = TREE_CHAIN (link)) + { + if (leaving_for_scope && TREE_CODE (link) == VAR_DECL) + { + tree outer_binding + = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (link))); + tree ns_binding; + + if (!outer_binding) + ns_binding = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (link)); + else + ns_binding = NULL_TREE; + + if (outer_binding + && (BINDING_LEVEL (outer_binding) + == current_binding_level->level_chain)) + /* We have something like: + + int i; + for (int i; ;); + + and we are leaving the `for' scope. There's no reason to + keep the binding of the inner `i' in this case. */ + pop_binding (DECL_NAME (link), link); + else if ((outer_binding + && (TREE_CODE (BINDING_VALUE (outer_binding)) + == TYPE_DECL)) + || (ns_binding + && TREE_CODE (ns_binding) == TYPE_DECL)) + /* Here, we have something like: + + typedef int I; + + void f () { + for (int I; ;); + } + + We must pop the for-scope binding so we know what's a + type and what isn't. */ + pop_binding (DECL_NAME (link), link); + else + { + /* Mark this VAR_DECL as dead so that we can tell we left it + there only for backward compatibility. */ + DECL_DEAD_FOR_LOCAL (link) = 1; + + /* Keep track of what should of have happenned when we + popped the binding. */ + if (outer_binding && BINDING_VALUE (outer_binding)) + DECL_SHADOWED_FOR_VAR (link) + = BINDING_VALUE (outer_binding); + + /* Add it to the list of dead variables in the next + outermost binding to that we can remove these when we + leave that binding. */ + current_binding_level->level_chain->dead_vars_from_for + = tree_cons (NULL_TREE, link, + current_binding_level->level_chain-> + dead_vars_from_for); + + /* Although we don't pop the CPLUS_BINDING, we do clear + its BINDING_LEVEL since the level is going away now. */ + BINDING_LEVEL (IDENTIFIER_BINDING (DECL_NAME (link))) + = 0; + } + } + else + { + /* Remove the binding. */ + decl = link; + if (TREE_CODE (decl) == TREE_LIST) + decl = TREE_VALUE (decl); + if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd') + pop_binding (DECL_NAME (decl), decl); + else if (TREE_CODE (decl) == OVERLOAD) + pop_binding (DECL_NAME (OVL_FUNCTION (decl)), decl); + else + my_friendly_abort (0); + } + } + + /* Remove declarations for any `for' variables from inner scopes + that we kept around. */ + for (link = current_binding_level->dead_vars_from_for; + link; link = TREE_CHAIN (link)) + pop_binding (DECL_NAME (TREE_VALUE (link)), TREE_VALUE (link)); + + /* Restore the IDENTIFIER_TYPE_VALUEs. */ + for (link = current_binding_level->type_shadowed; + link; link = TREE_CHAIN (link)) + SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link)); + + /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs + list if a `using' declaration put them there. The debugging + back-ends won't understand OVERLOAD, so we remove them here. + Because the BLOCK_VARS are (temporarily) shared with + CURRENT_BINDING_LEVEL->NAMES we must do this fixup after we have + popped all the bindings. */ + if (block) + { + tree* d; + + for (d = &BLOCK_VARS (block); *d; ) + { + if (TREE_CODE (*d) == TREE_LIST) + *d = TREE_CHAIN (*d); + else + d = &TREE_CHAIN (*d); + } + } + + /* 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) + { + struct named_label_list *labels; + for (labels = named_label_uses; labels; labels = labels->next) + if (labels->binding_level == current_binding_level) + { + labels->binding_level = level_chain; + labels->names_in_scope = level_chain->names; + } + } + } + + tmp = current_binding_level->keep; + + 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) + current_binding_level->blocks + = chainon (current_binding_level->blocks, subblocks); + + /* Take care of compiler's internal binding structures. */ + if (tmp == 2) + { + expand_end_bindings (getdecls (), keep, 1); + /* Each and every BLOCK node created here in `poplevel' is important + (e.g. for proper debugging information) so if we created one + earlier, mark it as "used". */ + 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); +} + +/* 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 + newlevel = make_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); + /* If we're leaving a toplevel class, don't bother to do the setting + of IDENTIFIER_CLASS_VALUE to NULL_TREE, since first of all this slot + shouldn't even be used when current_class_type isn't set, and second, + if we don't touch it here, we're able to use the cache 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_type = current_class_type; + previous_class_values = class_binding_level->class_shadowed; + } + for (shadowed = level->type_shadowed; + shadowed; + shadowed = TREE_CHAIN (shadowed)) + SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed), TREE_VALUE (shadowed)); + + /* Remove the bindings for all of the class-level declarations. */ + for (shadowed = level->class_shadowed; + shadowed; + shadowed = TREE_CHAIN (shadowed)) + pop_binding (TREE_PURPOSE (shadowed), TREE_TYPE (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); + + if (class_binding_level->parm_flag != 2) + class_binding_level = (struct binding_level *)0; + + /* Now, pop out of 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. */ +static int no_print_functions = 0; +static 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", + list_length (lvl->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 (t == error_mark_node) + 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->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)) + { + fprintf (stderr, " %s ", IDENTIFIER_POINTER (TREE_PURPOSE (t))); + } + 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); +} + +/* Namespace binding access routines: The namespace_bindings field of + the identifier is polymorphic, with three possible values: + NULL_TREE, a list of CPLUS_BINDINGS, or any other tree_node + indicating the BINDING_VALUE of global_namespace. */ + +/* Check whether the a binding for the name to scope is known. + Assumes that the bindings of the name are already a list + of bindings. Returns the binding found, or NULL_TREE. */ + +static tree +find_binding (name, scope) + tree name; + tree scope; +{ + tree iter, prev = NULL_TREE; + + scope = ORIGINAL_NAMESPACE (scope); + + for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name); iter; + iter = TREE_CHAIN (iter)) + { + my_friendly_assert (TREE_CODE (iter) == CPLUS_BINDING, 374); + if (BINDING_SCOPE (iter) == scope) + { + /* Move binding found to the fron of the list, so + subsequent lookups will find it faster. */ + if (prev) + { + TREE_CHAIN (prev) = TREE_CHAIN (iter); + TREE_CHAIN (iter) = IDENTIFIER_NAMESPACE_BINDINGS (name); + IDENTIFIER_NAMESPACE_BINDINGS (name) = iter; + } + return iter; + } + prev = iter; + } + return NULL_TREE; +} + +/* Always returns a binding for name in scope. If the + namespace_bindings is not a list, convert it to one first. + If no binding is found, make a new one. */ + +tree +binding_for_name (name, scope) + tree name; + tree scope; +{ + tree b = IDENTIFIER_NAMESPACE_BINDINGS (name); + tree result; + + scope = ORIGINAL_NAMESPACE (scope); + + if (b && TREE_CODE (b) != CPLUS_BINDING) + { + /* Get rid of optimization for global scope. */ + IDENTIFIER_NAMESPACE_BINDINGS (name) = NULL_TREE; + BINDING_VALUE (binding_for_name (name, global_namespace)) = b; + b = IDENTIFIER_NAMESPACE_BINDINGS (name); + } + if (b && (result = find_binding (name, scope))) + return result; + /* Not found, make a new permanent one. */ + push_obstacks (&permanent_obstack, &permanent_obstack); + result = make_node (CPLUS_BINDING); + TREE_CHAIN (result) = b; + IDENTIFIER_NAMESPACE_BINDINGS (name) = result; + BINDING_SCOPE (result) = scope; + BINDING_TYPE (result) = NULL_TREE; + BINDING_VALUE (result) = NULL_TREE; + pop_obstacks (); + return result; +} + +/* Return the binding value for name in scope, considering that + namespace_binding may or may not be a list of CPLUS_BINDINGS. */ + +tree +namespace_binding (name, scope) + tree name; + tree scope; +{ + tree b = IDENTIFIER_NAMESPACE_BINDINGS (name); + if (b == NULL_TREE) + return NULL_TREE; + if (scope == NULL_TREE) + scope = global_namespace; + if (TREE_CODE (b) != CPLUS_BINDING) + return (scope == global_namespace) ? b : NULL_TREE; + name = find_binding (name,scope); + if (name == NULL_TREE) + return name; + return BINDING_VALUE (name); +} + +/* Set the binding value for name in scope. If modifying the binding + of global_namespace is attempted, try to optimize it. */ + +void +set_namespace_binding (name, scope, val) + tree name; + tree scope; + tree val; +{ + tree b; + + if (scope == NULL_TREE) + scope = global_namespace; + + if (scope == global_namespace) + { + b = IDENTIFIER_NAMESPACE_BINDINGS (name); + if (b == NULL_TREE || TREE_CODE (b) != CPLUS_BINDING) + { + IDENTIFIER_NAMESPACE_BINDINGS (name) = val; + return; + } + } + b = binding_for_name (name, scope); + BINDING_VALUE (b) = val; +} + +/* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we + select a name that is unique to this compilation unit. */ + +void +push_namespace (name) + tree name; +{ + tree d = NULL_TREE; + int need_new = 1; + int implicit_use = 0; + int global = 0; + if (!global_namespace) + { + /* This must be ::. */ + my_friendly_assert (name == get_identifier ("::"), 377); + global = 1; + } + else if (!name) + { + /* The name of anonymous namespace is unique for the translation + unit. */ + if (!anonymous_namespace_name) + anonymous_namespace_name = get_file_function_name ('N'); + name = anonymous_namespace_name; + d = IDENTIFIER_NAMESPACE_VALUE (name); + if (d) + /* Reopening anonymous namespace. */ + need_new = 0; + implicit_use = 1; + } + else if (current_namespace == global_namespace + && name == DECL_NAME (std_node)) + { + in_std++; + return; + } + else + { + /* Check whether this is an extended namespace definition. */ + d = IDENTIFIER_NAMESPACE_VALUE (name); + if (d != NULL_TREE && TREE_CODE (d) == NAMESPACE_DECL) + { + need_new = 0; + if (DECL_NAMESPACE_ALIAS (d)) + { + cp_error ("namespace alias `%D' not allowed here, assuming `%D'", + d, DECL_NAMESPACE_ALIAS (d)); + d = DECL_NAMESPACE_ALIAS (d); + } + } + } + + if (need_new) + { + /* Make a new namespace, binding the name to it. */ + d = build_lang_decl (NAMESPACE_DECL, name, void_type_node); + /* The global namespace is not pushed, and the global binding + level is set elsewhere. */ + if (!global) + { + d = pushdecl (d); + pushlevel (0); + declare_namespace_level (); + NAMESPACE_LEVEL (d) = current_binding_level; + } + } + else + resume_binding_level (NAMESPACE_LEVEL (d)); + + if (implicit_use) + do_using_directive (d); + /* Enter the name space. */ + current_namespace = d; +} + +/* Pop from the scope of the current namespace. */ + +void +pop_namespace () +{ + if (current_namespace == global_namespace) + { + my_friendly_assert (in_std>0, 980421); + in_std--; + return; + } + current_namespace = CP_DECL_CONTEXT (current_namespace); + /* The binding level is not popped, as it might be re-opened later. */ + suspend_binding_level (); +} + +/* Concatenate the binding levels of all namespaces. */ + +void +cat_namespace_levels() +{ + tree current; + tree last; + struct binding_level *b; + + last = NAMESPACE_LEVEL (global_namespace) -> names; + /* The nested namespaces appear in the names list of their ancestors. */ + for (current = last; current; current = TREE_CHAIN (current)) + { + /* Catch simple infinite loops. */ + if (TREE_CHAIN (current) == current) + my_friendly_abort (990126); + + if (TREE_CODE (current) != NAMESPACE_DECL + || DECL_NAMESPACE_ALIAS (current)) + continue; + if (!DECL_LANG_SPECIFIC (current)) + { + /* Hmm. std. */ + my_friendly_assert (current == std_node, 393); + continue; + } + b = NAMESPACE_LEVEL (current); + while (TREE_CHAIN (last)) + last = TREE_CHAIN (last); + TREE_CHAIN (last) = NAMESPACE_LEVEL (current) -> names; + } +} + +/* 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; + tree old_namespace; + struct saved_scope *prev; + tree class_name, class_type; + tree access_specifier; + tree function_decl; + struct binding_level *class_bindings; + tree *lang_base, *lang_stack, lang_name; + int lang_stacksize; + int minimal_parse_mode; + tree last_function_parms; + tree template_parms; + HOST_WIDE_INT processing_template_decl; + tree previous_class_type, previous_class_values; + int processing_specialization; + int processing_explicit_instantiation; +}; +static struct saved_scope *current_saved_scope; + +/* A chain of the binding vecs created by store_bindings. We create a + whole bunch of these during compilation, on permanent_obstack, so we + can't just throw them away. */ +static tree free_binding_vecs; + +static tree +store_bindings (names, old_bindings) + tree names, old_bindings; +{ + tree t; + for (t = names; t; t = TREE_CHAIN (t)) + { + tree binding, t1, id; + + if (TREE_CODE (t) == TREE_LIST) + id = TREE_PURPOSE (t); + else + id = DECL_NAME (t); + + if (!id + /* Note that we may have an IDENTIFIER_CLASS_VALUE even when + we have no IDENTIFIER_BINDING if we have left the class + scope, but cached the class-level declarations. */ + || !(IDENTIFIER_BINDING (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; + + if (free_binding_vecs) + { + binding = free_binding_vecs; + free_binding_vecs = TREE_CHAIN (free_binding_vecs); + } + else + 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) = REAL_IDENTIFIER_TYPE_VALUE (id); + TREE_VEC_ELT (binding, 2) = IDENTIFIER_BINDING (id); + TREE_VEC_ELT (binding, 3) = IDENTIFIER_CLASS_VALUE (id); + IDENTIFIER_BINDING (id) = NULL_TREE; + IDENTIFIER_CLASS_VALUE (id) = NULL_TREE; + } + TREE_CHAIN (binding) = old_bindings; + old_bindings = binding; + skip_it: + ; + } + return old_bindings; +} + +void +maybe_push_to_top_level (pseudo) + int pseudo; +{ + extern int current_lang_stacksize; + struct saved_scope *s + = (struct saved_scope *) xmalloc (sizeof (struct saved_scope)); + struct binding_level *b = inner_binding_level; + tree old_bindings = NULL_TREE; + + if (current_function_decl) + push_cp_function_context (NULL_TREE); + + if (previous_class_type) + old_bindings = store_bindings (previous_class_values, old_bindings); + + /* Have to include global_binding_level, because class-level decls + aren't listed anywhere useful. */ + for (; b; b = b->level_chain) + { + tree t; + + /* Template IDs are inserted into the global level. If they were + inserted into namespace level, finish_file wouldn't find them + when doing pending instantiations. Therefore, don't stop at + namespace level, but continue until :: . */ + if (b == global_binding_level || (pseudo && b->pseudo_global)) + break; + + old_bindings = store_bindings (b->names, old_bindings); + /* We also need to check class_shadowed to save class-level type + bindings, since pushclass doesn't fill in b->names. */ + if (b->parm_flag == 2) + old_bindings = store_bindings (b->class_shadowed, old_bindings); + + /* 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)); + } + + s->old_binding_level = current_binding_level; + current_binding_level = b; + + s->old_namespace = current_namespace; + s->class_name = current_class_name; + s->class_type = current_class_type; + s->access_specifier = current_access_specifier; + s->function_decl = current_function_decl; + s->class_bindings = class_binding_level; + 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->minimal_parse_mode = minimal_parse_mode; + s->last_function_parms = last_function_parms; + s->template_parms = current_template_parms; + s->processing_template_decl = processing_template_decl; + s->previous_class_type = previous_class_type; + s->previous_class_values = previous_class_values; + s->processing_specialization = processing_specialization; + s->processing_explicit_instantiation = processing_explicit_instantiation; + + current_class_name = current_class_type = NULL_TREE; + current_function_decl = NULL_TREE; + class_binding_level = (struct binding_level *)0; + 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; + shadowed_labels = NULL_TREE; + minimal_parse_mode = 0; + previous_class_type = previous_class_values = NULL_TREE; + processing_specialization = 0; + processing_explicit_instantiation = 0; + current_template_parms = NULL_TREE; + processing_template_decl = 0; + current_namespace = global_namespace; + + s->prev = current_saved_scope; + s->old_bindings = old_bindings; + current_saved_scope = s; + + push_obstacks (&permanent_obstack, &permanent_obstack); +} + +void +push_to_top_level () +{ + maybe_push_to_top_level (0); +} + +void +pop_from_top_level () +{ + extern int current_lang_stacksize; + struct saved_scope *s = current_saved_scope; + tree t; + + /* Clear out class-level bindings cache. */ + if (previous_class_type) + { + popclass (-1); + previous_class_type = NULL_TREE; + } + + pop_obstacks (); + + current_binding_level = s->old_binding_level; + current_saved_scope = s->prev; + for (t = s->old_bindings; t; ) + { + tree save = t; + tree id = TREE_VEC_ELT (t, 0); + if (id) + { + SET_IDENTIFIER_TYPE_VALUE (id, TREE_VEC_ELT (t, 1)); + IDENTIFIER_BINDING (id) = TREE_VEC_ELT (t, 2); + IDENTIFIER_CLASS_VALUE (id) = TREE_VEC_ELT (t, 3); + } + t = TREE_CHAIN (t); + TREE_CHAIN (save) = free_binding_vecs; + free_binding_vecs = save; + } + current_namespace = s->old_namespace; + current_class_name = s->class_name; + current_class_type = s->class_type; + current_access_specifier = s->access_specifier; + current_function_decl = s->function_decl; + class_binding_level = s->class_bindings; + 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; + minimal_parse_mode = s->minimal_parse_mode; + last_function_parms = s->last_function_parms; + current_template_parms = s->template_parms; + processing_template_decl = s->processing_template_decl; + previous_class_type = s->previous_class_type; + previous_class_values = s->previous_class_values; + processing_specialization = s->processing_specialization; + processing_explicit_instantiation = s->processing_explicit_instantiation; + + free (s); + + if (current_function_decl) + pop_cp_function_context (NULL_TREE); +} + +/* 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->namespace_p) + { + /* Shadow the marker, not the real thing, so that the marker + gets restored later. */ + tree old_type_value = REAL_IDENTIFIER_TYPE_VALUE (id); + b->type_shadowed + = tree_cons (id, old_type_value, b->type_shadowed); + } + else + { + tree binding = binding_for_name (id, current_namespace); + BINDING_TYPE (binding) = type; + /* Store marker instead of real type. */ + type = global_type_node; + } + 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); +} + +/* Return the type associated with id. */ + +tree +identifier_type_value (id) + tree id; +{ + /* There is no type with that name, anywhere. */ + if (REAL_IDENTIFIER_TYPE_VALUE (id) == NULL_TREE) + return NULL_TREE; + /* This is not the type marker, but the real thing. */ + if (REAL_IDENTIFIER_TYPE_VALUE (id) != global_type_node) + return REAL_IDENTIFIER_TYPE_VALUE (id); + /* Have to search for it. It must be on the global level, now. + Ask lookup_name not to return non-types. */ + id = lookup_name_real (id, 2, 1, 0); + if (id) + return TREE_TYPE (id); + return NULL_TREE; +} + +/* Pop off extraneous binding levels left over due to syntax errors. + + We don't pop past namespaces, as they might be valid. */ + +void +pop_everything () +{ +#ifdef DEBUG_CP_BINDING_LEVELS + fprintf (stderr, "XXX entering pop_everything ()\n"); +#endif + while (! toplevel_bindings_p () && ! pseudo_global_level_p ()) + { + 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 +} + +/* The type TYPE is being declared. If it is a class template, or a + specialization of a class template, do any processing required and + perform error-checking. If IS_FRIEND is non-zero, this TYPE is + being declared a friend. B is the binding level at which this TYPE + should be bound. + + Returns the TYPE_DECL for TYPE, which may have been altered by this + processing. */ + +static tree +maybe_process_template_type_declaration (type, globalize, b) + tree type; + int globalize; + struct binding_level* b; +{ + tree decl = TYPE_NAME (type); + + if (processing_template_parmlist) + /* You can't declare a new template type in a template parameter + list. But, you can declare a non-template type: + + template <class A*> struct S; + + is a forward-declaration of `A'. */ + ; + else + { + maybe_check_template_type (type); + + my_friendly_assert (IS_AGGR_TYPE (type) + || TREE_CODE (type) == ENUMERAL_TYPE, 0); + + + if (/* If !GLOBALIZE then we are looking at a definition. + It may not be a primary template. (For example, in: + + template <class T> + struct S1 { class S2 {}; } + + we have to push_template_decl for S2.) */ + (processing_template_decl && !globalize) + /* If we are declaring a friend template class, we will + have GLOBALIZE set, since something like: + + template <class T> + struct S1 { + template <class U> + friend class S2; + }; + + declares S2 to be at global scope. */ + || PROCESSING_REAL_TEMPLATE_DECL_P ()) + { + /* This may change after the call to + push_template_decl_real, but we want the original value. */ + tree name = DECL_NAME (decl); + + decl = push_template_decl_real (decl, globalize); + /* If the current binding level is the binding level for the + template parameters (see the comment in + begin_template_parm_list) and the enclosing level is a class + scope, and we're not looking at a friend, push the + declaration of the member class into the class scope. In the + friend case, push_template_decl will already have put the + friend into global scope, if appropriate. */ + if (TREE_CODE (type) != ENUMERAL_TYPE + && !globalize && b->pseudo_global + && b->level_chain->parm_flag == 2) + { + pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type), + b->level_chain); + finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type)); + /* Put this tag on the list of tags for the class, since + that won't happen below because B is not the class + binding level, but is instead the pseudo-global level. */ + b->level_chain->tags = + saveable_tree_cons (name, type, b->level_chain->tags); + TREE_NONLOCAL_FLAG (type) = 1; + if (TYPE_SIZE (current_class_type) == NULL_TREE) + CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags; + } + } + } + + return decl; +} + +/* Push a tag name NAME for struct/class/union/enum type TYPE. + Normally put it into the inner-most non-tag-transparent 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 (toplevel_bindings_p ()) + 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) + { + tree cs = current_scope (); + + if (! globalize) + context = cs; + else if (cs != NULL_TREE + && TREE_CODE_CLASS (TREE_CODE (cs)) == 't') + /* When declaring a friend class of a local class, we want + to inject the newly named class into the scope + containing the local class, not the namespace scope. */ + context = hack_decl_function_context (get_type_decl (cs)); + } + if (context) + c_decl = TREE_CODE (context) == FUNCTION_DECL + ? context : TYPE_MAIN_DECL (context); + + if (!context) + context = current_namespace; + + /* Do C++ gratuitous typedefing. */ + if (IDENTIFIER_TYPE_VALUE (name) != type) + { + register tree d = NULL_TREE; + int newdecl = 0, in_class = 0; + + if ((b->pseudo_global && b->level_chain->parm_flag == 2) + || b->parm_flag == 2) + in_class = 1; + else + d = lookup_nested_type (type, c_decl); + + if (d == NULL_TREE) + { + newdecl = 1; + d = build_decl (TYPE_DECL, name, type); + if (current_lang_name == lang_name_java) + TYPE_FOR_JAVA (type) = 1; + SET_DECL_ARTIFICIAL (d); + if (! in_class) + set_identifier_type_value_with_scope (name, type, b); + } + else + d = TYPE_MAIN_DECL (d); + + TYPE_NAME (type) = d; + DECL_CONTEXT (d) = FROB_CONTEXT (context); + + d = maybe_process_template_type_declaration (type, + globalize, b); + + if (b->parm_flag == 2) + { + pushdecl_class_level (d); + if (newdecl && !PROCESSING_REAL_TEMPLATE_DECL_P ()) + /* Put this TYPE_DECL on the TYPE_FIELDS list for the + class. But if it's a member template class, we + want the TEMPLATE_DECL, not the TYPE_DECL, so this + is done later. */ + finish_member_declaration (d); + } + else + d = pushdecl_with_scope (d, b); + + if (newdecl) + { + if (ANON_AGGRNAME_P (name)) + DECL_IGNORED_P (d) = 1; + + TYPE_CONTEXT (type) = DECL_CONTEXT (d); + DECL_ASSEMBLER_NAME (d) = DECL_NAME (d); + if (!uses_template_parms (type)) + 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. */ + + tree d = build_decl (TYPE_DECL, NULL_TREE, type); + 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&'. */ + +int +decls_match (newdecl, olddecl) + tree newdecl, olddecl; +{ + int types_match; + + if (newdecl == olddecl) + return 1; + + if (TREE_CODE (newdecl) != TREE_CODE (olddecl)) + /* If the two DECLs are not even the same kind of thing, we're not + interested in their types. */ + return 0; + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + tree f1 = TREE_TYPE (newdecl); + tree f2 = TREE_TYPE (olddecl); + tree p1 = TYPE_ARG_TYPES (f1); + tree p2 = TYPE_ARG_TYPES (f2); + + if (DECL_REAL_CONTEXT (newdecl) != DECL_REAL_CONTEXT (olddecl) + && ! (DECL_LANGUAGE (newdecl) == lang_c + && DECL_LANGUAGE (olddecl) == lang_c)) + return 0; + + /* 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 (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2))) + { + 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); + } + else + types_match = 0; + } + else if (TREE_CODE (newdecl) == TEMPLATE_DECL) + { + if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl), + DECL_TEMPLATE_PARMS (olddecl))) + return 0; + + if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) + 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), + COMPARE_REDECLARATION); + } + + 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 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 (TREE_CODE (newdecl) == TYPE_DECL) + return; + + name = DECL_ASSEMBLER_NAME (newdecl); + if (TREE_PUBLIC (name) && DECL_THIS_STATIC (newdecl)) + { + /* It's okay to redeclare an ANSI built-in function as static, + or to declare a non-ANSI built-in function as anything. */ + if (! (TREE_CODE (newdecl) == FUNCTION_DECL + && olddecl != NULL_TREE + && TREE_CODE (olddecl) == FUNCTION_DECL + && (DECL_BUILT_IN (olddecl) + || DECL_BUILT_IN_NONANSI (olddecl)))) + { + cp_pedwarn (IDENTIFIER_IMPLICIT_DECL (name) + ? implicit_extern_static_warning + : explicit_extern_static_warning, newdecl); + if (olddecl != NULL_TREE) + cp_pedwarn_at ("previous declaration of `%D'", olddecl); + } + } +} + +/* 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) + tree newdecl, olddecl; +{ + extern struct obstack permanent_obstack; + unsigned olddecl_uid = DECL_UID (olddecl); + int olddecl_friend = 0, types_match = 0; + int new_defines_function = 0; + + if (newdecl == olddecl) + return 1; + + types_match = decls_match (newdecl, 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 just pretend the types match here. */ + if (TREE_TYPE (newdecl) == error_mark_node + || TREE_TYPE (olddecl) == error_mark_node) + types_match = 1; + + /* Check for redeclaration and other discrepancies. */ + if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_ARTIFICIAL (olddecl) + && (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 (olddecl) == TYPE_DECL && DECL_ARTIFICIAL (olddecl) + && TREE_CODE (newdecl) != TYPE_DECL + && ! (TREE_CODE (newdecl) == TEMPLATE_DECL + && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)) + || (TREE_CODE (newdecl) == TYPE_DECL && DECL_ARTIFICIAL (newdecl) + && TREE_CODE (olddecl) != TYPE_DECL + && ! (TREE_CODE (olddecl) == TEMPLATE_DECL + && (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) + == 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. */ + return 0; + } + + if ((TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_FUNCTION_TEMPLATE_P (olddecl)) + || (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_FUNCTION_TEMPLATE_P (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 (DECL_REAL_CONTEXT (newdecl) != DECL_REAL_CONTEXT (olddecl)) + /* These are certainly not duplicate declarations; they're + from different scopes. */ + return 0; + + 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 (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == TYPE_DECL + || TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) + { + cp_error ("declaration of template `%#D'", newdecl); + cp_error_at ("conflicts with previous declaration `%#D'", + olddecl); + } + else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL + && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL + && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))), + TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl)))) + && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl), + DECL_TEMPLATE_PARMS (olddecl))) + { + cp_error ("new declaration `%#D'", newdecl); + cp_error_at ("ambiguates old 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); + } + else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), + TYPE_ARG_TYPES (TREE_TYPE (olddecl)))) + { + 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) + { + cp_error ("conflicting types for `%#D'", newdecl); + cp_error_at ("previous declaration as `%#D'", olddecl); + } + } + else if (TREE_CODE (newdecl) == FUNCTION_DECL + && ((DECL_TEMPLATE_SPECIALIZATION (olddecl) + && (!DECL_TEMPLATE_INFO (newdecl) + || (DECL_TI_TEMPLATE (newdecl) + != DECL_TI_TEMPLATE (olddecl)))) + || (DECL_TEMPLATE_SPECIALIZATION (newdecl) + && (!DECL_TEMPLATE_INFO (olddecl) + || (DECL_TI_TEMPLATE (olddecl) + != DECL_TI_TEMPLATE (newdecl)))))) + /* It's OK to have a template specialization and a non-template + with the same type, or to have specializations of two + different templates with the same type. Note that if one is a + specialization, and the other is an instantiation of the same + template, that we do not exit at this point. That situation + can occur if we instantiate a template class, and then + specialize one of its methods. This situation is legal, but + the declarations must be merged in the usual way. */ + return 0; + else if (TREE_CODE (newdecl) == FUNCTION_DECL + && ((DECL_TEMPLATE_INSTANTIATION (olddecl) + && !DECL_USE_TEMPLATE (newdecl)) + || (DECL_TEMPLATE_INSTANTIATION (newdecl) + && !DECL_USE_TEMPLATE (olddecl)))) + /* One of the declarations is a template instantiation, and the + other is not a template at all. That's OK. */ + return 0; + else if (TREE_CODE (newdecl) == NAMESPACE_DECL + && DECL_NAMESPACE_ALIAS (newdecl) + && DECL_NAMESPACE_ALIAS (newdecl) == DECL_NAMESPACE_ALIAS (olddecl)) + /* Redeclaration of namespace alias, ignore it. */ + return 1; + 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) + && namespace_bindings_p ()) + ? "`%#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)); + } + } + + if (DECL_LANG_SPECIFIC (olddecl) && DECL_USE_TEMPLATE (olddecl)) + ; + else if (TREE_CODE (olddecl) == FUNCTION_DECL) + { + tree t1 = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); + tree t2 = TYPE_ARG_TYPES (TREE_TYPE (newdecl)); + int i = 1; + + if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE) + t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2); + + for (; t1 && t1 != void_list_node; + t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2), i++) + if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2)) + { + if (1 == simple_cst_equal (TREE_PURPOSE (t1), + TREE_PURPOSE (t2))) + { + if (pedantic) + { + cp_pedwarn ("default argument given for parameter %d of `%#D'", + i, newdecl); + cp_pedwarn_at ("after previous specification in `%#D'", + olddecl); + } + } + else + { + cp_error ("default argument given for parameter %d of `%#D'", + i, newdecl); + cp_error_at ("after previous specification in `%#D'", + olddecl); + } + } + + if (DECL_THIS_INLINE (newdecl) && ! DECL_THIS_INLINE (olddecl) + && TREE_ADDRESSABLE (olddecl) && warn_inline) + { + cp_warning ("`%#D' was used before it was declared inline", + newdecl); + cp_warning_at ("previous non-inline declaration here", + olddecl); + } + } + } + + /* 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_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0) + DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl); + DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl); + DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); + DECL_ABSTRACT_VIRTUAL_P (newdecl) |= DECL_ABSTRACT_VIRTUAL_P (olddecl); + DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl); + DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl); + new_defines_function = 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 definition. */ + && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl)) + /* Don't warn about friends, let add_friend take care of it. */ + && ! DECL_FRIEND_P (newdecl)) + { + cp_warning ("redundant redeclaration of `%D' in same scope", newdecl); + cp_warning_at ("previous declaration of `%D'", 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); + } + } + + /* Copy all the DECL_... slots specified in the new decl + except for any that we copy here from the old type. */ + DECL_MACHINE_ATTRIBUTES (newdecl) + = merge_machine_decl_attributes (olddecl, newdecl); + + if (TREE_CODE (newdecl) == TEMPLATE_DECL) + { + if (! duplicate_decls (DECL_TEMPLATE_RESULT (newdecl), + DECL_TEMPLATE_RESULT (olddecl))) + cp_error ("invalid redeclaration of %D", newdecl); + TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)); + DECL_TEMPLATE_SPECIALIZATIONS (olddecl) + = chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl), + DECL_TEMPLATE_SPECIALIZATIONS (newdecl)); + + return 1; + } + + if (types_match) + { + /* Automatically handles default parameters. */ + tree oldtype = TREE_TYPE (olddecl); + tree newtype; + + /* Make sure we put the new type in the same obstack as the old one. */ + if (oldtype) + push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype)); + else + { + push_obstacks_nochange (); + end_temporary_allocation (); + } + + /* Merge the data types specified in the two decls. */ + newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); + + if (TREE_CODE (newdecl) == VAR_DECL) + DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl); + /* Do this after calling `common_type' so that default + parameters don't confuse us. */ + else if (TREE_CODE (newdecl) == FUNCTION_DECL + && (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)) + != TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)))) + { + TREE_TYPE (newdecl) = build_exception_variant (newtype, + TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl))); + TREE_TYPE (olddecl) = build_exception_variant (newtype, + TYPE_RAISES_EXCEPTIONS (oldtype)); + + if ((pedantic || ! DECL_IN_SYSTEM_HEADER (olddecl)) + && DECL_SOURCE_LINE (olddecl) != 0 + && flag_exceptions + && ! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl))) + { + cp_pedwarn ("declaration of `%D' throws different exceptions", + newdecl); + cp_pedwarn_at ("previous declaration here", olddecl); + } + } + TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype; + + /* Lay the type out, unless already done. */ + if (newtype != canonical_type_variant (oldtype) + && TREE_TYPE (newdecl) != error_mark_node + && !(processing_template_decl && uses_template_parms (newdecl))) + layout_type (TREE_TYPE (newdecl)); + + if ((TREE_CODE (newdecl) == VAR_DECL + || TREE_CODE (newdecl) == PARM_DECL + || TREE_CODE (newdecl) == RESULT_DECL + || TREE_CODE (newdecl) == FIELD_DECL + || TREE_CODE (newdecl) == TYPE_DECL) + && !(processing_template_decl && uses_template_parms (newdecl))) + layout_decl (newdecl, 0); + + /* 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); + if (DECL_LANG_SPECIFIC (newdecl) + && DECL_LANG_SPECIFIC (olddecl)) + DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (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. */ + DECL_WEAK (newdecl) |= DECL_WEAK (olddecl); + DECL_ONE_ONLY (newdecl) |= DECL_ONE_ONLY (olddecl); + TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); + TREE_STATIC (olddecl) = TREE_STATIC (newdecl) |= TREE_STATIC (olddecl); + if (! DECL_EXTERNAL (olddecl)) + DECL_EXTERNAL (newdecl) = 0; + + if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl)) + { + DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl); + DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl); + DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl); + /* Don't really know how much of the language-specific + values we should copy from old to new. */ + DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl); + DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl); + DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl); + DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); + olddecl_friend = DECL_FRIEND_P (olddecl); + } + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + if (DECL_TEMPLATE_INSTANTIATION (olddecl) + && !DECL_TEMPLATE_INSTANTIATION (newdecl)) + { + /* If newdecl is not a specialization, then it is not a + template-related function at all. And that means that we + shoud have exited above, returning 0. */ + my_friendly_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl), + 0); + + if (TREE_USED (olddecl)) + /* From [temp.expl.spec]: + + If a template, a member template or the member of a class + template is explicitly specialized then that + specialization shall be declared before the first use of + that specialization that would cause an implicit + instantiation to take place, in every translation unit in + which such a use occurs. */ + cp_error ("explicit specialization of %D after first use", + olddecl); + + SET_DECL_TEMPLATE_SPECIALIZATION (olddecl); + } + DECL_THIS_INLINE (newdecl) |= DECL_THIS_INLINE (olddecl); + + /* 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 (! types_match) + { + DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl); + DECL_ASSEMBLER_NAME (olddecl) = DECL_ASSEMBLER_NAME (newdecl); + DECL_RTL (olddecl) = DECL_RTL (newdecl); + } + if (! types_match || new_defines_function) + { + /* These need to be copied so that the names are available. */ + DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl); + DECL_RESULT (olddecl) = DECL_RESULT (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 (DECL_LANG_SPECIFIC (olddecl)) + DECL_MAIN_VARIANT (newdecl) = DECL_MAIN_VARIANT (olddecl); + } + + if (TREE_CODE (newdecl) == NAMESPACE_DECL) + { + NAMESPACE_LEVEL (newdecl) = NAMESPACE_LEVEL (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); + DECL_ASSEMBLER_NAME (newdecl) = DECL_ASSEMBLER_NAME (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 (DECL_TEMPLATE_INSTANTIATION (newdecl)) + { + /* If newdecl is a template instantiation, it is possible that + the following sequence of events has occurred: + + o A friend function was declared in a class template. The + class template was instantiated. + + o The instantiation of the friend declaration was + recorded on the instantiation list, and is newdecl. + + o Later, however, instantiate_class_template called pushdecl + on the newdecl to perform name injection. But, pushdecl in + turn called duplicate_decls when it discovered that another + declaration of a global function with the same name already + existed. + + o Here, in duplicate_decls, we decided to clobber newdecl. + + If we're going to do that, we'd better make sure that + olddecl, and not newdecl, is on the list of + instantiations so that if we try to do the instantiation + again we won't get the clobbered declaration. */ + + tree tmpl = DECL_TI_TEMPLATE (newdecl); + tree decls = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); + + for (; decls; decls = TREE_CHAIN (decls)) + if (TREE_VALUE (decls) == newdecl) + TREE_VALUE (decls) = olddecl; + } + + if (((char *)newdecl + ROUND (function_size) == (char *)nl + && ((char *)newdecl + ROUND (function_size) + + ROUND (sizeof (struct lang_decl)) + == obstack_next_free (&permanent_obstack))) + || ((char *)newdecl + ROUND (function_size) + == obstack_next_free (&permanent_obstack))) + { + DECL_MAIN_VARIANT (newdecl) = olddecl; + DECL_LANG_SPECIFIC (olddecl) = ol; + bcopy ((char *)nl, (char *)ol, sizeof (struct lang_decl)); + + obstack_free (&permanent_obstack, newdecl); + } + else if (LANG_DECL_PERMANENT (ol) && ol != nl) + { + if (DECL_MAIN_VARIANT (olddecl) == olddecl) + { + /* Save these lang_decls that would otherwise be lost. */ + extern tree free_lang_decl_chain; + tree free_lang_decl = (tree) ol; + + if (DECL_LANG_SPECIFIC (olddecl) == ol) + abort (); + + 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; + + /* NEWDECL contains the merged attribute lists. + Update OLDDECL to be the same. */ + DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl); + + 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; + register tree name = DECL_ASSEMBLER_NAME (x); + int need_new_binding = 1; + + if (DECL_TEMPLATE_PARM_P (x)) + /* Template parameters have no context; they are not X::T even + when declared within a class or namespace. */ + ; + else + { + if (current_function_decl && x != current_function_decl + /* A local declaration for a function doesn't constitute + nesting. */ + && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x)) + /* Don't change DECL_CONTEXT of virtual methods. */ + && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x)) + && !DECL_CONTEXT (x)) + DECL_CONTEXT (x) = current_function_decl; + if (!DECL_CONTEXT (x)) + DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace); + } + + /* 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 || TREE_CODE (x) == VAR_DECL + || TREE_CODE (x) == NAMESPACE_DECL || TREE_CODE (x) == TEMPLATE_TYPE_PARM + || TREE_CODE (x) == TEMPLATE_TEMPLATE_PARM) + name = DECL_NAME (x); + + if (name) + { +#if 0 + /* Not needed...see below. */ + char *file; + int line; +#endif + if (TREE_CODE (name) == TEMPLATE_ID_EXPR) + name = TREE_OPERAND (name, 0); + + /* Namespace-scoped variables are not found in the current level. */ + if (TREE_CODE (x) == VAR_DECL && DECL_NAMESPACE_SCOPE_P (x)) + t = namespace_binding (name, DECL_CONTEXT (x)); + else + 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 0 + /* This is turned off until I have time to do it right (bpk). */ + /* With the code below that uses it... */ + file = DECL_SOURCE_FILE (t); + line = DECL_SOURCE_LINE (t); +#endif + if (TREE_CODE (t) == PARM_DECL) + { + if (DECL_CONTEXT (t) == NULL_TREE) + fatal ("parse errors have confused me too much"); + + /* Check for duplicate params. */ + if (duplicate_decls (x, t)) + return t; + } + else if (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c) + || DECL_FUNCTION_TEMPLATE_P (x)) + && is_overloaded_fn (t)) + /* Don't do anything just yet. */; + else if (t == wchar_decl_node) + { + if (pedantic && ! DECL_IN_SYSTEM_HEADER (x)) + cp_pedwarn ("redeclaration of wchar_t as `%T'", TREE_TYPE (x)); + + /* Throw away the redeclaration. */ + return t; + } + else if (TREE_CODE (t) != TREE_CODE (x)) + { + 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)); + else if (TREE_CODE (t) == FUNCTION_DECL) + check_default_args (t); + + return t; + } + else if (DECL_MAIN_P (x)) + { + /* A redeclaration of main, but not a duplicate of the + previous one. + + [basic.start.main] + + This function shall not be overloaded. */ + cp_error_at ("invalid redeclaration of `%D'", t); + cp_error ("as `%D'", x); + /* We don't try to push this declaration since that + causes a crash. */ + return x; + } + } + + check_template_shadow (x); + + /* If this is a function conjured up by the backend, massage it + so it looks friendly. */ + if (TREE_CODE (x) == FUNCTION_DECL + && ! DECL_LANG_SPECIFIC (x)) + { + retrofit_lang_decl (x); + DECL_LANGUAGE (x) = lang_c; + } + + if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x)) + { + t = push_overloaded_decl (x, PUSH_LOCAL); + if (t != x || DECL_LANGUAGE (x) == lang_c) + return t; + if (!namespace_bindings_p ()) + /* We do not need to create a binding for this name; + push_overloaded_decl will have already done so if + necessary. */ + need_new_binding = 0; + } + else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x)) + return push_overloaded_decl (x, PUSH_GLOBAL); + + /* If declaring a type as a typedef, copy the type (unless we're + at line 0), and install this TYPE_DECL as the new type's typedef + name. See the extensive comment in ../c-decl.c (pushdecl). */ + if (TREE_CODE (x) == TYPE_DECL) + { + tree type = TREE_TYPE (x); + if (DECL_SOURCE_LINE (x) == 0) + { + if (TYPE_NAME (type) == 0) + TYPE_NAME (type) = x; + } + else if (type != error_mark_node && TYPE_NAME (type) != x + /* We don't want to copy the type when all we're + doing is making a TYPE_DECL for the purposes of + inlining. */ + && (!TYPE_NAME (type) + || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x))) + { + push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type)); + + DECL_ORIGINAL_TYPE (x) = type; + type = build_type_copy (type); + TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x)); + TYPE_NAME (type) = x; + TREE_TYPE (x) = type; + + pop_obstacks (); + } + + if (type != error_mark_node + && TYPE_NAME (type) + && TYPE_IDENTIFIER (type)) + set_identifier_type_value_with_scope (DECL_NAME (x), type, + current_binding_level); + + } + + /* 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_NAMESPACE_VALUE (name) != NULL_TREE + && (DECL_EXTERNAL (IDENTIFIER_NAMESPACE_VALUE (name)) + || TREE_PUBLIC (IDENTIFIER_NAMESPACE_VALUE (name)))) + decl = IDENTIFIER_NAMESPACE_VALUE (name); + else + decl = NULL_TREE; + + if (decl + /* If different sort of thing, we already gave an error. */ + && TREE_CODE (decl) == TREE_CODE (x) + && !same_type_p (TREE_TYPE (x), TREE_TYPE (decl))) + { + cp_pedwarn ("type mismatch with previous external decl", x); + cp_pedwarn_at ("previous external decl of `%#D'", decl); + } + } + + /* This name is new in its binding level. + Install the new declaration and return it. */ + if (namespace_bindings_p ()) + { + /* Install a global value. */ + + /* 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; + + if (!(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x) + && t != NULL_TREE)) + { + if (TREE_CODE (x) == FUNCTION_DECL) + my_friendly_assert + ((IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE) + || (IDENTIFIER_GLOBAL_VALUE (name) == x), 378); + SET_IDENTIFIER_NAMESPACE_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_VALUE (name); + tree oldglobal = IDENTIFIER_NAMESPACE_VALUE (name); + + if (need_new_binding) + { + push_local_binding (name, x, 0); + /* Because push_local_binding will hook X on to the + current_binding_level's name list, we don't want to + do that again below. */ + need_new_binding = 0; + } + + /* 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), + current_binding_level); + + /* Clear out any TYPE_DECL shadowed by a namespace so that + we won't think this is a type. The C struct hack doesn't + go through namespaces. */ + if (TREE_CODE (x) == NAMESPACE_DECL) + set_identifier_type_value_with_scope (name, NULL_TREE, + current_binding_level); + + /* 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) + && oldglobal != NULL_TREE + && TREE_CODE (x) == FUNCTION_DECL + && TREE_CODE (oldglobal) == FUNCTION_DECL) + { + /* We have one. Their types must agree. */ + if (decls_match (x, oldglobal)) + /* OK */; + else + { + cp_warning ("extern declaration of `%#D' doesn't match", x); + cp_warning_at ("global declaration `%#D'", 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); + } + else if (warn_shadow && oldlocal != NULL_TREE + && current_binding_level->is_for_scope + && !DECL_DEAD_FOR_LOCAL (oldlocal)) + { + warning ("variable `%s' shadows local", + IDENTIFIER_POINTER (name)); + cp_warning_at (" this is the shadowed declaration", oldlocal); + } + /* Maybe warn if shadowing something else. */ + else if (warn_shadow && !DECL_EXTERNAL (x) + /* No shadow warnings for internally generated vars. */ + && ! 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 + && current_class_ptr + && !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) + /* XXX shadow warnings in outer-more namespaces */ + warnstring = "declaration of `%s' shadows global declaration"; + + if (warnstring) + warning (warnstring, IDENTIFIER_POINTER (name)); + } + } + + if (TREE_CODE (x) == FUNCTION_DECL) + check_default_args (x); + + /* Keep count of variables in this level with incomplete type. */ + if (TREE_CODE (x) == VAR_DECL + && TREE_TYPE (x) != error_mark_node + && ((TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE + && PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE)) + /* RTTI TD entries are created while defining the type_info. */ + || (TYPE_LANG_SPECIFIC (TREE_TYPE (x)) + && TYPE_BEING_DEFINED (TREE_TYPE (x))))) + current_binding_level->incomplete + = tree_cons (NULL_TREE, x, current_binding_level->incomplete); + } + + if (need_new_binding) + { + /* Put decls on list in reverse order. + We will reverse them later if necessary. */ + TREE_CHAIN (x) = current_binding_level->names; + current_binding_level->names = x; + if (! (current_binding_level != global_binding_level + || TREE_PERMANENT (x))) + my_friendly_abort (124); + } + + return x; +} + +/* Same as pushdecl, but define X in binding-level LEVEL. We rely on the + caller to set DECL_CONTEXT properly. */ + +static tree +pushdecl_with_scope (x, level) + tree x; + struct binding_level *level; +{ + register struct binding_level *b; + tree function_decl = current_function_decl; + + current_function_decl = NULL_TREE; + if (level->parm_flag == 2) + { + b = class_binding_level; + class_binding_level = level; + pushdecl_class_level (x); + class_binding_level = b; + } + else + { + b = current_binding_level; + current_binding_level = level; + x = pushdecl (x); + current_binding_level = b; + } + current_function_decl = function_decl; + return x; +} + +/* Like pushdecl, only it places X in the current namespace, + if appropriate. */ + +tree +pushdecl_namespace_level (x) + tree x; +{ + register struct binding_level *b = inner_binding_level; + register tree t; + + t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace)); + + /* 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 + { + *ptr = newval; + } + } + return t; +} + +/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, + if appropriate. */ + +tree +pushdecl_top_level (x) + tree x; +{ + tree cur_namespace = current_namespace; + current_namespace = global_namespace; + x = pushdecl_namespace_level (x); + current_namespace = cur_namespace; + return x; +} + +/* Make the declaration of X appear in CLASS scope. */ + +void +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)) + { + /* A name N used in a class S shall refer to the same declaration + in its context and when re-evaluated in the completed scope of S. + Types, enums, and static vars are checked here; other + members are checked in finish_struct. */ + tree icv = IDENTIFIER_CLASS_VALUE (name); + + /* This should match check_member_decl_is_same_in_complete_scope. */ + if (icv && icv != x + && flag_optional_diags + /* Don't complain about inherited names. */ + && id_in_current_class (name) + /* Or shadowed tags. */ + && !(DECL_DECLARES_TYPE_P (icv) + && DECL_CONTEXT (icv) == current_class_type)) + { + cp_pedwarn ("declaration of identifier `%D' as `%#D'", name, x); + cp_pedwarn_at ("conflicts with previous use in class as `%#D'", + icv); + } + + check_template_shadow (x); + } + + push_class_level_binding (name, x); + if (TREE_CODE (x) == TYPE_DECL) + set_identifier_type_value (name, TREE_TYPE (x)); + } +} + +#if 0 +/* 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. */ + +void +pushdecl_nonclass_level (x) + tree x; +{ + struct binding_level *b = current_binding_level; + + my_friendly_assert (b->parm_flag != 2, 180); + +#if 0 + /* Get out of template binding levels */ + while (b->pseudo_global) + b = b->level_chain; +#endif + + pushdecl_with_scope (x, b); +} +#endif + +/* 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; +{ + /* The class_binding_level will be NULL if x is a template + parameter name in a member template. */ + if (!class_binding_level) + return; + + /* If this declaration shadows a declaration from an enclosing + class, then we will need to restore IDENTIFIER_CLASS_VALUE when + we leave this class. Record the shadowed declaration here. */ + maybe_push_cache_obstack (); + class_binding_level->class_shadowed + = tree_cons (name, IDENTIFIER_CLASS_VALUE (name), + class_binding_level->class_shadowed); + TREE_TYPE (class_binding_level->class_shadowed) + = x; + pop_obstacks (); + + /* Put the binding on the stack of bindings for the identifier, and + update IDENTIFIER_CLASS_VALUE. */ + push_class_binding (name, x); + + obstack_ptr_grow (&decl_obstack, x); +} + +/* Insert another USING_DECL into the current binding level, + returning this declaration. If this is a redeclaration, + do nothing and return NULL_TREE. */ + +tree +push_using_decl (scope, name) + tree scope; + tree name; +{ + tree decl; + + my_friendly_assert (TREE_CODE (scope) == NAMESPACE_DECL, 383); + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 384); + for (decl = current_binding_level->usings; decl; decl = TREE_CHAIN (decl)) + if (DECL_INITIAL (decl) == scope && DECL_NAME (decl) == name) + break; + if (decl) + return NULL_TREE; + decl = build_lang_decl (USING_DECL, name, void_type_node); + DECL_INITIAL (decl) = scope; + TREE_CHAIN (decl) = current_binding_level->usings; + current_binding_level->usings = decl; + return decl; +} + +/* Add namespace to using_directives. Return NULL_TREE if nothing was + changed (i.e. there was already a directive), or the fresh + TREE_LIST otherwise. */ + +tree +push_using_directive (used) + tree used; +{ + tree ud = current_binding_level->using_directives; + tree iter, ancestor; + + /* Check if we already have this. */ + if (purpose_member (used, ud) != NULL_TREE) + return NULL_TREE; + + /* Recursively add all namespaces used. */ + for (iter = DECL_NAMESPACE_USING (used); iter; iter = TREE_CHAIN (iter)) + push_using_directive (TREE_PURPOSE (iter)); + + ancestor = namespace_ancestor (current_decl_namespace (), used); + ud = current_binding_level->using_directives; + ud = perm_tree_cons (used, ancestor, ud); + current_binding_level->using_directives = ud; + return ud; +} + +/* DECL is a FUNCTION_DECL for a non-member function, 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. + + FLAGS is a bitwise-or of the following values: + PUSH_LOCAL: Bind DECL in the current scope, rather than at + namespace scope. + PUSH_USING: DECL is being pushed as the result of a using + declaration. + + 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, flags) + tree decl; + int flags; +{ + tree name = DECL_NAME (decl); + tree old; + tree new_binding; + int doing_global = (namespace_bindings_p () || !(flags & PUSH_LOCAL)); + + if (doing_global) + { + old = namespace_binding (name, DECL_CONTEXT (decl)); + 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 = lookup_name_current_level (name); + + if (old) + { + if (TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old)) + { + tree t = TREE_TYPE (old); + if (IS_AGGR_TYPE (t) && warn_shadow + && (! DECL_IN_SYSTEM_HEADER (decl) + || ! DECL_IN_SYSTEM_HEADER (old))) + cp_warning ("`%#D' hides constructor for `%#T'", decl, t); + old = NULL_TREE; + } + else if (is_overloaded_fn (old)) + { + tree tmp; + + for (tmp = old; tmp; tmp = OVL_NEXT (tmp)) + { + tree fn = OVL_CURRENT (tmp); + + if (TREE_CODE (tmp) == OVERLOAD && OVL_USED (tmp) + && !(flags & PUSH_USING) + && compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), + TYPE_ARG_TYPES (TREE_TYPE (decl)))) + cp_error ("`%#D' conflicts with previous using declaration `%#D'", + decl, fn); + + if (duplicate_decls (decl, fn)) + return fn; + } + } + else + { + cp_error_at ("previous non-function declaration `%#D'", old); + cp_error ("conflicts with function declaration `%#D'", decl); + return decl; + } + } + + if (old || TREE_CODE (decl) == TEMPLATE_DECL) + { + if (old && TREE_CODE (old) != OVERLOAD) + new_binding = ovl_cons (decl, ovl_cons (old, NULL_TREE)); + else + new_binding = ovl_cons (decl, old); + if (flags & PUSH_USING) + OVL_USED (new_binding) = 1; + } + else + /* NAME is not ambiguous. */ + new_binding = decl; + + if (doing_global) + set_namespace_binding (name, current_namespace, new_binding); + else + { + /* We only create an OVERLOAD if there was a previous binding at + this level. In that case, we need to remove the old binding + and replace it with the new binding. We must also run + through the NAMES on the binding level where the name was + bound to update the chain. */ + if (TREE_CODE (new_binding) == OVERLOAD) + { + tree *d; + + for (d = &BINDING_LEVEL (IDENTIFIER_BINDING (name))->names; + *d; + d = &TREE_CHAIN (*d)) + if (*d == old + || (TREE_CODE (*d) == TREE_LIST + && TREE_VALUE (*d) == old)) + { + if (TREE_CODE (*d) == TREE_LIST) + /* Just replace the old binding with the new. */ + TREE_VALUE (*d) = new_binding; + else + /* Build a TREE_LIST to wrap the OVERLOAD. */ + *d = build_tree_list (NULL_TREE, new_binding); + + /* And update the CPLUS_BINDING node. */ + BINDING_VALUE (IDENTIFIER_BINDING (name)) + = new_binding; + return decl; + } + + /* We should always find a previous binding in this case. */ + my_friendly_abort (0); + } + + /* Install the new binding. */ + push_local_binding (name, new_binding, flags); + } + + 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 && (! warn_implicit || toplevel_bindings_p ())) + end_temporary_allocation (); + + /* We used to reuse an old implicit decl here, + but this loses with inline functions because it can clobber + 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. */ + 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 (same_type_p (TREE_TYPE (newdecl), TREE_TYPE (olddecl))) + 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; + + /* If both functions come from different namespaces, this is not + a redeclaration - this is a conflict with a used function. */ + if (DECL_NAMESPACE_SCOPE_P (olddecl) + && DECL_CONTEXT (olddecl) != DECL_CONTEXT (newdecl)) + return "`%D' conflicts with used function"; + + /* We'll complain about linkage mismatches in + warn_extern_redeclared_static. */ + + /* Defining the same name twice is no good. */ + if (DECL_INITIAL (olddecl) != NULL_TREE + && DECL_INITIAL (newdecl) != NULL_TREE) + { + if (DECL_NAME (olddecl) == NULL_TREE) + return "`%#D' not declared in class"; + else + return "redefinition of `%#D'"; + } + return 0; + } + else if (TREE_CODE (newdecl) == TEMPLATE_DECL) + { + if ((TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL + && DECL_INITIAL (DECL_TEMPLATE_RESULT (newdecl)) + && DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl))) + || (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL + && TYPE_SIZE (TREE_TYPE (newdecl)) + && TYPE_SIZE (TREE_TYPE (olddecl)))) + return "redefinition of `%#D'"; + return 0; + } + else if (toplevel_bindings_p ()) + { + /* Objects declared at top level: */ + /* If at least one is a reference, it's ok. */ + if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl)) + return 0; + /* Reject two definitions. */ + 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 + || named_label_uses->names_in_scope != current_binding_level->names + || named_label_uses->label_decl != decl)) + { + struct named_label_list *new_ent; + new_ent + = (struct named_label_list*)oballoc (sizeof (struct named_label_list)); + new_ent->label_decl = decl; + new_ent->names_in_scope = current_binding_level->names; + new_ent->binding_level = current_binding_level; + new_ent->lineno_o_goto = lineno; + new_ent->filename_o_goto = input_filename; + new_ent->next = named_label_uses; + named_label_uses = new_ent; + } + + /* 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); + + /* Make sure every label has an rtx. */ + label_rtx (decl); + + /* 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); + named_label_uses->label_decl = 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); + } + + 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; + + if (minimal_parse_mode) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + decl = build_decl (LABEL_DECL, name, void_type_node); + pop_obstacks (); + DECL_SOURCE_LINE (decl) = line; + DECL_SOURCE_FILE (decl) = filename; + add_tree (decl); + return decl; + } + + 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 (name == get_identifier ("wchar_t")) + cp_pedwarn ("label named wchar_t"); + + if (DECL_INITIAL (decl) != NULL_TREE) + { + cp_error ("duplicate label `%D'", decl); + return 0; + } + else + { + struct named_label_list *uses, *prev; + int identified = 0; + + /* 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; + + prev = NULL; + uses = named_label_uses; + while (uses != NULL) + if (uses->label_decl == decl) + { + struct binding_level *b = current_binding_level; + while (b) + { + tree new_decls = b->names; + tree old_decls = (b == uses->binding_level) + ? uses->names_in_scope : 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 + && pod_type_p (TREE_TYPE (new_decls)))) + { + if (! identified) + { + cp_error ("jump to label `%D'", decl); + error_with_file_and_line (uses->filename_o_goto, + uses->lineno_o_goto, + " from here"); + identified = 1; + } + if (DECL_INITIAL (new_decls) + || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))) + cp_error_at (" crosses initialization of `%#D'", + new_decls); + else + cp_error_at (" enters scope of non-POD `%#D'", + new_decls); + } + new_decls = TREE_CHAIN (new_decls); + } + if (b == uses->binding_level) + break; + b = b->level_chain; + } + + if (prev != NULL) + prev->next = uses->next; + else + named_label_uses = uses->next; + + uses = uses->next; + } + else + { + prev = uses; + uses = uses->next; + } + current_function_return_value = NULL_TREE; + return decl; + } +} + +struct cp_switch +{ + struct binding_level *level; + struct cp_switch *next; +}; + +static struct cp_switch *switch_stack; + +void +push_switch () +{ + struct cp_switch *p + = (struct cp_switch *) oballoc (sizeof (struct cp_switch)); + p->level = current_binding_level; + p->next = switch_stack; + switch_stack = p; +} + +void +pop_switch () +{ + switch_stack = switch_stack->next; +} + +/* Same, but for CASE labels. If DECL is NULL_TREE, it's the default. */ +/* XXX Note decl is never actually used. (bpk) */ + +void +define_case_label () +{ + tree cleanup = last_cleanup_this_contour (); + struct binding_level *b = current_binding_level; + int identified = 0; + + if (cleanup) + { + static int explained = 0; + cp_warning_at ("destructor needed for `%#D'", TREE_PURPOSE (cleanup)); + warning ("where case label appears here"); + if (!explained) + { + warning ("(enclose actions of previous case statements requiring"); + warning ("destructors in their own binding contours.)"); + explained = 1; + } + } + + for (; b && b != switch_stack->level; b = b->level_chain) + { + tree new_decls = b->names; + for (; new_decls; new_decls = TREE_CHAIN (new_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 (! identified) + error ("jump to case label"); + identified = 1; + cp_error_at (" crosses initialization of `%#D'", + new_decls); + } + } + } + + /* 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; + tree name; + struct binding_level *binding_level; + int thislevel_only; +{ + register struct binding_level *level; + /* Non-zero if, we should look past a pseudo-global level, even if + THISLEVEL_ONLY. */ + int allow_pseudo_global = 1; + + 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 if (level->namespace_p) + /* Do namespace lookup. */ + for (tail = current_namespace; 1; tail = CP_DECL_CONTEXT (tail)) + { + tree old = binding_for_name (name, tail); + + /* If we just skipped past a pseudo global level, even + though THISLEVEL_ONLY, and we find a template class + declaration, then we use the _TYPE node for the + template. See the example below. */ + if (thislevel_only && !allow_pseudo_global + && old && BINDING_VALUE (old) + && DECL_CLASS_TEMPLATE_P (BINDING_VALUE (old))) + old = TREE_TYPE (BINDING_VALUE (old)); + else + old = BINDING_TYPE (old); + + /* If it has an original type, it is a typedef, and we + should not return it. */ + if (old && DECL_ORIGINAL_TYPE (TYPE_NAME (old))) + old = NULL_TREE; + if (old && TREE_CODE (old) != form + && !(form != ENUMERAL_TYPE && TREE_CODE (old) == TEMPLATE_DECL)) + { + cp_error ("`%#D' redeclared as %C", old, form); + return NULL_TREE; + } + if (old) + return old; + if (thislevel_only || tail == global_namespace) + return NULL_TREE; + } + 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)) + { + /* Definition isn't the kind we were looking for. */ + cp_error ("`%#D' redeclared as %C", TREE_VALUE (tail), + form); + return NULL_TREE; + } + return TREE_VALUE (tail); + } + } + if (thislevel_only && ! level->tag_transparent) + { + if (level->pseudo_global && allow_pseudo_global) + { + /* We must deal with cases like this: + + template <class T> struct S; + template <class T> struct S {}; + + When looking up `S', for the second declaration, we + would like to find the first declaration. But, we + are in the pseudo-global level created for the + template parameters, rather than the (surrounding) + namespace level. Thus, we keep going one more level, + even though THISLEVEL_ONLY is non-zero. */ + allow_pseudo_global = 0; + continue; + } + else + return NULL_TREE; + } + if (current_class_type && level->level_chain->namespace_p) + { + /* 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 NULL_TREE; + } + 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_MAIN_DECL (context)); + break; + case 'd': + context = DECL_CONTEXT (context); + break; + default: + my_friendly_abort (10); + } + continue; + no_context: + break; + } + } + } + return NULL_TREE; +} + +#if 0 +void +set_current_level_tags_transparency (tags_transparent) + int tags_transparent; +{ + current_binding_level->tag_transparent = tags_transparent; +} +#endif + +/* 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; +} + +/* 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: + if (TYPE_NAME (type) && TYPE_IDENTIFIER (type)) + return lookup_name (TYPE_IDENTIFIER (type), 1); + return NULL_TREE; + default: + my_friendly_abort (12); + } + } + return NULL_TREE; +} + +/* Look up NAME in the NAMESPACE. */ + +tree +lookup_namespace_name (namespace, name) + tree namespace, name; +{ + struct tree_binding _b; + tree val; + + my_friendly_assert (TREE_CODE (namespace) == NAMESPACE_DECL, 370); + + if (TREE_CODE (name) == NAMESPACE_DECL) + /* This happens for A::B<int> when B is a namespace. */ + return name; + else if (TREE_CODE (name) == TEMPLATE_DECL) + { + /* This happens for A::B where B is a template, and there are no + template arguments. */ + cp_error ("invalid use of `%D'", name); + return error_mark_node; + } + + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 373); + + val = binding_init (&_b); + if (!qualified_lookup_using_namespace (name, namespace, val, 0)) + return error_mark_node; + + if (BINDING_VALUE (val)) + { + val = BINDING_VALUE (val); + + /* If we have a single function from a using decl, pull it out. */ + if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val)) + val = OVL_FUNCTION (val); + return val; + } + + cp_error ("`%D' undeclared in namespace `%D'", name, namespace); + return error_mark_node; +} + +/* Hash a TYPENAME_TYPE. K is really of type `tree'. */ + +static unsigned long +typename_hash (k) + hash_table_key k; +{ + unsigned long hash; + tree t; + + t = (tree) k; + hash = (((unsigned long) TYPE_CONTEXT (t)) + ^ ((unsigned long) DECL_NAME (TYPE_NAME (t)))); + + return hash; +} + +/* Compare two TYPENAME_TYPEs. K1 and K2 are really of type `tree'. */ + +static boolean +typename_compare (k1, k2) + hash_table_key k1; + hash_table_key k2; +{ + tree t1; + tree t2; + tree d1; + tree d2; + + t1 = (tree) k1; + t2 = (tree) k2; + d1 = TYPE_NAME (t1); + d2 = TYPE_NAME (t2); + + return (DECL_NAME (d1) == DECL_NAME (d2) + && same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)) + && ((TREE_TYPE (t1) != NULL_TREE) + == (TREE_TYPE (t2) != NULL_TREE)) + && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)) + && TYPENAME_TYPE_FULLNAME (t1) == TYPENAME_TYPE_FULLNAME (t2)); +} + +/* Build a TYPENAME_TYPE. If the type is `typename T::t', CONTEXT is + the type of `T', NAME is the IDENTIFIER_NODE for `t'. If BASE_TYPE + is non-NULL, this type is being created by the implicit typename + extension, and BASE_TYPE is a type named `t' in some base class of + `T' which depends on template parameters. + + Returns the new TYPENAME_TYPE. */ + +tree +build_typename_type (context, name, fullname, base_type) + tree context; + tree name; + tree fullname; + tree base_type; +{ + tree t; + tree d; + struct hash_entry* e; + + static struct hash_table ht; + + push_obstacks (&permanent_obstack, &permanent_obstack); + + if (!ht.table + && !hash_table_init (&ht, &hash_newfunc, &typename_hash, + &typename_compare)) + fatal ("virtual memory exhausted"); + + /* Build the TYPENAME_TYPE. */ + t = make_lang_type (TYPENAME_TYPE); + TYPE_CONTEXT (t) = FROB_CONTEXT (context); + TYPENAME_TYPE_FULLNAME (t) = fullname; + TREE_TYPE (t) = base_type; + + /* Build the corresponding TYPE_DECL. */ + d = build_decl (TYPE_DECL, name, t); + TYPE_NAME (TREE_TYPE (d)) = d; + TYPE_STUB_DECL (TREE_TYPE (d)) = d; + DECL_CONTEXT (d) = FROB_CONTEXT (context); + DECL_ARTIFICIAL (d) = 1; + + /* See if we already have this type. */ + e = hash_lookup (&ht, t, /*create=*/false, /*copy=*/0); + if (e) + { + /* This will free not only TREE_TYPE, but the lang-specific data + and the TYPE_DECL as well. */ + obstack_free (&permanent_obstack, t); + t = (tree) e->key; + } + else + /* Insert the type into the table. */ + hash_lookup (&ht, t, /*create=*/true, /*copy=*/0); + + pop_obstacks (); + + return t; +} + +tree +make_typename_type (context, name) + tree context, name; +{ + tree t; + tree fullname; + + if (TREE_CODE_CLASS (TREE_CODE (name)) == 't') + name = TYPE_IDENTIFIER (name); + else if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + + fullname = name; + + if (TREE_CODE (name) == TEMPLATE_ID_EXPR) + { + name = TREE_OPERAND (name, 0); + if (TREE_CODE (name) == TEMPLATE_DECL) + name = TREE_OPERAND (fullname, 0) = DECL_NAME (name); + } + if (TREE_CODE (name) != IDENTIFIER_NODE) + my_friendly_abort (2000); + + if (TREE_CODE (context) == NAMESPACE_DECL) + { + /* We can get here from typename_sub0 in the explicit_template_type + expansion. Just fail. */ + cp_error ("no class template named `%#T' in `%#T'", + name, context); + return error_mark_node; + } + + if (! uses_template_parms (context) + || currently_open_class (context)) + { + if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR) + { + if (IS_AGGR_TYPE (context)) + t = lookup_field (context, name, 0, 0); + else + t = NULL_TREE; + + if (t == NULL_TREE || TREE_CODE (t) != TEMPLATE_DECL + || TREE_CODE (DECL_RESULT (t)) != TYPE_DECL) + { + cp_error ("no class template named `%#T' in `%#T'", + name, context); + return error_mark_node; + } + + return lookup_template_class (t, TREE_OPERAND (fullname, 1), + NULL_TREE, context, + /*entering_scope=*/0); + } + else + { + if (IS_AGGR_TYPE (context)) + t = lookup_field (context, name, 0, 1); + else + t = NULL_TREE; + + if (t == NULL_TREE) + { + cp_error ("no type named `%#T' in `%#T'", name, context); + return error_mark_node; + } + + return TREE_TYPE (t); + } + } + + return build_typename_type (context, name, fullname, NULL_TREE); +} + +/* Select the right _DECL from multiple choices. */ + +static tree +select_decl (binding, flags) + tree binding; + int flags; +{ + tree val; + val = BINDING_VALUE (binding); + if (LOOKUP_NAMESPACES_ONLY (flags)) + { + /* We are not interested in types. */ + if (val && TREE_CODE (val) == NAMESPACE_DECL) + return val; + return NULL_TREE; + } + + /* If we could have a type and + we have nothing or we need a type and have none. */ + if (BINDING_TYPE (binding) + && (!val || ((flags & LOOKUP_PREFER_TYPES) + && TREE_CODE (val) != TYPE_DECL))) + val = TYPE_STUB_DECL (BINDING_TYPE (binding)); + /* Don't return non-types if we really prefer types. */ + else if (val && LOOKUP_TYPES_ONLY (flags) && TREE_CODE (val) != TYPE_DECL + && (!looking_for_template || TREE_CODE (val) != TEMPLATE_DECL)) + val = NULL_TREE; + + return val; +} + +/* Unscoped lookup of a global, iterate over namespaces, considering + using namespace statements. */ + +static tree +unqualified_namespace_lookup (name, flags) + tree name; + int flags; +{ + struct tree_binding _binding; + tree b = binding_init (&_binding); + tree initial = current_decl_namespace(); + tree scope = initial; + tree siter; + struct binding_level *level; + tree val = NULL_TREE; + + while (!val) + { + val = binding_for_name (name, scope); + + /* Initialize binding for this context. */ + BINDING_VALUE (b) = BINDING_VALUE (val); + BINDING_TYPE (b) = BINDING_TYPE (val); + + /* Add all _DECLs seen through local using-directives. */ + for (level = current_binding_level; + !level->namespace_p; + level = level->level_chain) + if (!lookup_using_namespace (name, b, level->using_directives, + scope, flags)) + /* Give up because of error. */ + return NULL_TREE; + + /* Add all _DECLs seen through global using-directives. */ + /* XXX local and global using lists should work equally. */ + siter = initial; + while (1) + { + if (!lookup_using_namespace (name, b, DECL_NAMESPACE_USING (siter), + scope, flags)) + /* Give up because of error. */ + return NULL_TREE; + if (siter == scope) break; + siter = CP_DECL_CONTEXT (siter); + } + + val = select_decl (b, flags); + if (scope == global_namespace) + break; + scope = CP_DECL_CONTEXT (scope); + } + return val; +} + +/* Combine prefer_type and namespaces_only into flags. */ + +static int +lookup_flags (prefer_type, namespaces_only) + int prefer_type, namespaces_only; +{ + if (namespaces_only) + return LOOKUP_PREFER_NAMESPACES; + if (prefer_type > 1) + return LOOKUP_PREFER_TYPES; + if (prefer_type > 0) + return LOOKUP_PREFER_BOTH; + return 0; +} + +/* Given a lookup that returned VAL, use FLAGS to decide if we want to + ignore it or not. Subroutine of lookup_name_real. */ + +static tree +qualify_lookup (val, flags) + tree val; + int flags; +{ + if (val == NULL_TREE) + return val; + if ((flags & LOOKUP_PREFER_NAMESPACES) && TREE_CODE (val) == NAMESPACE_DECL) + return val; + if ((flags & LOOKUP_PREFER_TYPES) + && (TREE_CODE (val) == TYPE_DECL + || ((flags & LOOKUP_TEMPLATES_EXPECTED) + && DECL_CLASS_TEMPLATE_P (val)))) + return val; + if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES)) + return NULL_TREE; + return val; +} + +/* 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 or namespaces. + If PREFER_TYPE is > 1, we reject non-type decls (e.g. namespaces). + If PREFER_TYPE is -2, we're being called from yylex(). (UGLY) + Otherwise we prefer non-TYPE_DECLs. + + If NONCLASS is non-zero, we don't look for the NAME in class scope, + using IDENTIFIER_CLASS_VALUE. */ + +static tree +lookup_name_real (name, prefer_type, nonclass, namespaces_only) + tree name; + int prefer_type, nonclass, namespaces_only; +{ + register tree val; + int yylex = 0; + tree from_obj = NULL_TREE; + int flags; + + /* Hack: copy flag set by parser, if set. */ + if (only_namespace_names) + namespaces_only = 1; + + if (prefer_type == -2) + { + extern int looking_for_typename; + tree type = NULL_TREE; + + yylex = 1; + prefer_type = looking_for_typename; + + flags = lookup_flags (prefer_type, namespaces_only); + /* During parsing, we need to complain. */ + flags |= LOOKUP_COMPLAIN; + /* If the next thing is '<', class templates are types. */ + if (looking_for_template) + flags |= LOOKUP_TEMPLATES_EXPECTED; + + /* std:: becomes :: for now. */ + if (got_scope == std_node) + got_scope = void_type_node; + + if (got_scope) + type = got_scope; + else if (got_object != error_mark_node) + type = got_object; + + if (type) + { + if (type == error_mark_node) + return error_mark_node; + if (TREE_CODE (type) == TYPENAME_TYPE && TREE_TYPE (type)) + type = TREE_TYPE (type); + + if (TYPE_P (type)) + type = complete_type (type); + + if (TREE_CODE (type) == VOID_TYPE) + type = global_namespace; + if (TREE_CODE (type) == NAMESPACE_DECL) + { + struct tree_binding b; + val = binding_init (&b); + if (!qualified_lookup_using_namespace (name, type, val, flags)) + return NULL_TREE; + val = select_decl (val, flags); + } + else if (! IS_AGGR_TYPE (type) + || TREE_CODE (type) == TEMPLATE_TYPE_PARM + || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM + || TREE_CODE (type) == TYPENAME_TYPE) + /* Someone else will give an error about this if needed. */ + val = NULL_TREE; + else if (TYPE_BEING_DEFINED (type)) + { + val = IDENTIFIER_CLASS_VALUE (name); + if (val && DECL_CONTEXT (val) != type) + { + 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)) == type) + { + val = TREE_VALUE (t); + break; + } + } + } + if (val == NULL_TREE) + val = lookup_field (type, name, 0, 1); + } + else if (type == current_class_type) + val = IDENTIFIER_CLASS_VALUE (name); + else + val = lookup_member (type, name, 0, prefer_type); + } + else + val = NULL_TREE; + + if (got_scope) + goto done; + else if (got_object && val) + from_obj = val; + } + else + flags = lookup_flags (prefer_type, namespaces_only); + + /* First, look in non-namespace scopes. */ + for (val = IDENTIFIER_BINDING (name); val; val = TREE_CHAIN (val)) + { + if (!LOCAL_BINDING_P (val) && nonclass) + /* We're not looking for class-scoped bindings, so keep going. */ + continue; + + /* If this is the kind of thing we're looking for, we're done. */ + if (qualify_lookup (BINDING_VALUE (val), flags)) + { + val = BINDING_VALUE (val); + break; + } + else if ((flags & LOOKUP_PREFER_TYPES) + && qualify_lookup (BINDING_TYPE (val), flags)) + { + val = BINDING_TYPE (val); + break; + } + } + + /* If VAL is a type from a dependent base, we're not really supposed + to be able to see it; the fact that we can is the "implicit + typename" extension. We call lookup_field here to turn VAL into + a TYPE_DECL for a TYPENAME_TYPE. */ + if (processing_template_decl && val + && val == IDENTIFIER_CLASS_VALUE (name) + && TREE_CODE (val) == TYPE_DECL + && !currently_open_class (DECL_CONTEXT (val)) + && uses_template_parms (current_class_type)) + val = lookup_field (current_class_type, name, 0, 1); + + /* We don't put names from baseclasses onto the IDENTIFIER_BINDING + list when we're defining a type. It would probably be simpler to + do this, but we don't. So, we must lookup names from base + classes explicitly. */ + if (!val && !nonclass + && current_class_type && TYPE_BEING_DEFINED (current_class_type)) + { + val = qualify_lookup (lookup_field (current_class_type, name, 0, 0), + flags); + if (!val) + val = qualify_lookup (lookup_nested_field (name, !yylex), + flags); + } + + /* If we found a type from a dependent base class (using the + implicit typename extension) make sure that there's not some + global name which should be chosen instead. */ + if (val && TREE_CODE (val) == TYPE_DECL + && IMPLICIT_TYPENAME_P (TREE_TYPE (val))) + { + tree global_val; + + /* Any other name takes precedence over an implicit typename. Warn the + user about this potentially confusing lookup. */ + global_val = unqualified_namespace_lookup (name, flags); + + if (global_val) + { + tree subtype; + + /* Only warn when not lexing; we don't want to warn if they + use this name as a declarator. */ + subtype = TREE_TYPE (TREE_TYPE (val)); + if (! yylex + && ! (TREE_CODE (global_val) == TEMPLATE_DECL + && CLASSTYPE_TEMPLATE_INFO (subtype) + && CLASSTYPE_TI_TEMPLATE (subtype) == global_val) + && ! (TREE_CODE (global_val) == TYPE_DECL + && same_type_p (TREE_TYPE (global_val), subtype))) + { + cp_warning ("lookup of `%D' finds `%#D'", name, global_val); + cp_warning (" instead of `%D' from dependent base class", + val); + cp_warning (" (use `typename %T::%D' if that's what you meant)", + constructor_name (current_class_type), name); + } + + /* Use the global value instead of the implicit typename. */ + val = global_val; + } + } + else if (!val) + /* No local, or class-scoped binding. Look for a namespace-scope + declaration. */ + val = unqualified_namespace_lookup (name, flags); + + done: + if (val) + { + /* This should only warn about types used in qualified-ids. */ + if (from_obj && from_obj != val) + { + if (looking_for_typename && TREE_CODE (from_obj) == TYPE_DECL + && TREE_CODE (val) == TYPE_DECL + && TREE_TYPE (from_obj) != TREE_TYPE (val)) + { + cp_pedwarn ("lookup of `%D' in the scope of `%#T' (`%#T')", + name, got_object, TREE_TYPE (from_obj)); + cp_pedwarn (" does not match lookup in the current scope (`%#T')", + TREE_TYPE (val)); + } + + /* We don't change val to from_obj if got_object depends on + template parms because that breaks implicit typename for + destructor calls. */ + if (! uses_template_parms (got_object)) + val = from_obj; + } + + /* If we have a single function from a using decl, pull it out. */ + if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val)) + val = OVL_FUNCTION (val); + } + else if (from_obj) + val = from_obj; + + return val; +} + +tree +lookup_name_nonclass (name) + tree name; +{ + return lookup_name_real (name, 0, 1, 0); +} + +tree +lookup_function_nonclass (name, args) + tree name; + tree args; +{ + return lookup_arg_dependent (name, lookup_name_nonclass (name), args); +} + +tree +lookup_name_namespace_only (name) + tree name; +{ + /* type-or-namespace, nonclass, namespace_only */ + return lookup_name_real (name, 1, 1, 1); +} + +tree +lookup_name (name, prefer_type) + tree name; + int prefer_type; +{ + return lookup_name_real (name, prefer_type, 0, 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->namespace_p) + { + t = IDENTIFIER_NAMESPACE_VALUE (name); + + /* extern "C" function() */ + if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST) + t = TREE_VALUE (t); + } + else if (IDENTIFIER_BINDING (name) + && LOCAL_BINDING_P (IDENTIFIER_BINDING (name))) + { + struct binding_level *b = current_binding_level; + + while (1) + { + if (BINDING_LEVEL (IDENTIFIER_BINDING (name)) == b) + return IDENTIFIER_VALUE (name); + + if (b->keep == 2) + b = b->level_chain; + else + break; + } + } + + return t; +} + +/* Like lookup_name_current_level, but for types. */ + +tree +lookup_type_current_level (name) + tree name; +{ + register tree t = NULL_TREE; + + my_friendly_assert (! current_binding_level->namespace_p, 980716); + + if (REAL_IDENTIFIER_TYPE_VALUE (name) != NULL_TREE + && REAL_IDENTIFIER_TYPE_VALUE (name) != global_type_node) + { + struct binding_level *b = current_binding_level; + while (1) + { + if (purpose_member (name, b->type_shadowed)) + return REAL_IDENTIFIER_TYPE_VALUE (name); + if (b->keep == 2) + b = b->level_chain; + else + break; + } + } + + return t; +} + +void +begin_only_namespace_names () +{ + only_namespace_names = 1; +} + +void +end_only_namespace_names () +{ + only_namespace_names = 0; +} + +/* 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 ATTRIBUTE_UNUSED; +{ + 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); +} + +#if 0 +/* Unused -- brendan 970107 */ +/* 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; +#endif + +/* 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 = NULL_TREE; + + 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) + { + tdecl = pushdecl (build_decl (TYPE_DECL, tname, type)); + set_identifier_type_value (tname, NULL_TREE); + if ((int) rid_index < (int) RID_MAX) + /* Built-in types live in the global namespace. */ + SET_IDENTIFIER_GLOBAL_VALUE (tname, tdecl); + } + if (rname != NULL_TREE) + { + if (tname != NULL_TREE) + { + set_identifier_type_value (rname, NULL_TREE); + SET_IDENTIFIER_GLOBAL_VALUE (rname, tdecl); + } + else + { + tdecl = pushdecl (build_decl (TYPE_DECL, rname, type)); + set_identifier_type_value (rname, NULL_TREE); + } + } +} + +/* Record one of the standard Java types. + * Declare it as having the given NAME. + * If SIZE > 0, it is the size of one of the integral types; + * otherwise it is the negative of the size of one of the other types. */ + +static tree +record_builtin_java_type (name, size) + char *name; + int size; +{ + tree type, decl; + if (size > 0) + type = make_signed_type (size); + else if (size > -32) + { /* "__java_char" or ""__java_boolean". */ + type = make_unsigned_type (-size); + /*if (size == -1) TREE_SET_CODE (type, BOOLEAN_TYPE);*/ + } + else + { /* "__java_float" or ""__java_double". */ + type = make_node (REAL_TYPE); + TYPE_PRECISION (type) = - size; + layout_type (type); + } + record_builtin_type (RID_MAX, name, type); + decl = TYPE_NAME (type); + DECL_IGNORED_P (decl) = 1; + TYPE_FOR_JAVA (type) = 1; + return type; +} + +/* Push a type into the namespace so that the back-ends ignore it. */ + +static void +record_unknown_type (type, name) + tree type; + char *name; +{ + tree decl = pushdecl (build_decl (TYPE_DECL, get_identifier (name), type)); + /* Make sure the "unknown type" typedecl gets ignored for debug info. */ + DECL_IGNORED_P (decl) = 1; + TYPE_DECL_SUPPRESS_DEBUG (decl) = 1; + TYPE_SIZE (type) = TYPE_SIZE (void_type_node); + TYPE_ALIGN (type) = 1; + TYPE_MODE (type) = TYPE_MODE (void_type_node); +} + +/* 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, PUSH_GLOBAL); +} + +#ifdef __GNUC__ +__inline +#endif +tree +auto_function (name, type, code) + tree name, type; + enum built_in_function code; +{ + return define_function + (IDENTIFIER_POINTER (name), type, code, push_overloaded_decl_1, + IDENTIFIER_POINTER (build_decl_overload (name, TYPE_ARG_TYPES (type), + 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 () +{ + register tree endlink, int_endlink, double_endlink, unsigned_endlink; + tree fields[20]; + /* Data type of memcpy. */ + tree memcpy_ftype, strlen_ftype; + int wchar_type_size; + tree temp; + tree array_domain_type; + tree vb_off_identifier = NULL_TREE; + /* Function type `char *(char *, char *)' and similar ones */ + tree string_ftype_ptr_ptr, int_ftype_string_string; + tree sizetype_endlink; + tree ptr_ftype, ptr_ftype_unsigned, ptr_ftype_sizetype; + tree void_ftype, void_ftype_int, void_ftype_ptr; + + /* Have to make these distinct before we try using them. */ + lang_name_cplusplus = get_identifier ("C++"); + lang_name_c = get_identifier ("C"); + lang_name_java = get_identifier ("Java"); + + /* Enter the global namespace. */ + my_friendly_assert (global_namespace == NULL_TREE, 375); + my_friendly_assert (current_lang_name == NULL_TREE, 375); + current_lang_name = lang_name_cplusplus; + push_namespace (get_identifier ("::")); + global_namespace = current_namespace; + current_lang_name = NULL_TREE; + + if (flag_strict_prototype == 2) + flag_strict_prototype = pedantic; + if (! flag_permissive && ! pedantic) + flag_pedantic_errors = 1; + + strict_prototypes_lang_c = flag_strict_prototype; + + /* Initially, C. */ + current_lang_name = lang_name_c; + + current_function_decl = NULL_TREE; + named_labels = NULL_TREE; + named_label_uses = NULL; + current_binding_level = NULL_BINDING_LEVEL; + free_binding_level = NULL_BINDING_LEVEL; + + /* 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); + + /* 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; + /* The global level is the namespace level of ::. */ + NAMESPACE_LEVEL (global_namespace) = global_binding_level; + declare_namespace_level (); + + this_identifier = get_identifier (THIS_NAME); + in_charge_identifier = get_identifier (IN_CHARGE_NAME); + ctor_identifier = get_identifier (CTOR_NAME); + dtor_identifier = get_identifier (DTOR_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"); + if (flag_handle_signatures) + { + tag_identifier = get_identifier (SIGTABLE_TAG_NAME); + vb_off_identifier = get_identifier (SIGTABLE_VB_OFF_NAME); + vt_off_identifier = get_identifier (SIGTABLE_VT_OFF_NAME); + } + + /* Define `int' and `char' first so that dbx will output them first. */ + + 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); + + short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE); + record_builtin_type (RID_SHORT, "short int", short_integer_type_node); + short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE); + record_builtin_type (RID_MAX, "short unsigned int", short_unsigned_type_node); + record_builtin_type (RID_MAX, "unsigned short", short_unsigned_type_node); + + /* `unsigned long' is the standard type for sizeof. + Note that stddef.h uses `unsigned long', + and this must agree, even if long and int are the same size. */ + set_sizetype + (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)))); + + ptrdiff_type_node + = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE))); + + /* Define both `signed char' and `unsigned char'. */ + signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE); + record_builtin_type (RID_MAX, "signed char", signed_char_type_node); + unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE); + record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node); + + /* These are types that type_for_size and type_for_mode use. */ + intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node)); + intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node)); + intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node)); + intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node)); +#if HOST_BITS_PER_WIDE_INT >= 64 + intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode)); + pushdecl (build_decl (TYPE_DECL, get_identifier ("__int128_t"), intTI_type_node)); +#endif + unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node)); + unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node)); + unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node)); + unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node)); +#if HOST_BITS_PER_WIDE_INT >= 64 + unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode)); + pushdecl (build_decl (TYPE_DECL, get_identifier ("__uint128_t"), unsigned_intTI_type_node)); +#endif + + float_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE; + record_builtin_type (RID_FLOAT, NULL_PTR, float_type_node); + layout_type (float_type_node); + + double_type_node = make_node (REAL_TYPE); + if (flag_short_double) + TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE; + else + TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE; + record_builtin_type (RID_DOUBLE, NULL_PTR, double_type_node); + layout_type (double_type_node); + + long_double_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE; + record_builtin_type (RID_MAX, "long double", long_double_type_node); + layout_type (long_double_type_node); + + complex_integer_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"), + complex_integer_type_node)); + TREE_TYPE (complex_integer_type_node) = integer_type_node; + layout_type (complex_integer_type_node); + + complex_float_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"), + complex_float_type_node)); + TREE_TYPE (complex_float_type_node) = float_type_node; + layout_type (complex_float_type_node); + + complex_double_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"), + complex_double_type_node)); + TREE_TYPE (complex_double_type_node) = double_type_node; + layout_type (complex_double_type_node); + + complex_long_double_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"), + complex_long_double_type_node)); + TREE_TYPE (complex_long_double_type_node) = long_double_type_node; + layout_type (complex_long_double_type_node); + + java_byte_type_node = record_builtin_java_type ("__java_byte", 8); + java_short_type_node = record_builtin_java_type ("__java_short", 16); + java_int_type_node = record_builtin_java_type ("__java_int", 32); + java_long_type_node = record_builtin_java_type ("__java_long", 64); + java_float_type_node = record_builtin_java_type ("__java_float", -32); + java_double_type_node = record_builtin_java_type ("__java_double", -64); + java_char_type_node = record_builtin_java_type ("__java_char", -16); + java_boolean_type_node = record_builtin_java_type ("__java_boolean", -1); + + integer_zero_node = build_int_2 (0, 0); + TREE_TYPE (integer_zero_node) = integer_type_node; + integer_one_node = build_int_2 (1, 0); + TREE_TYPE (integer_one_node) = integer_type_node; + integer_two_node = build_int_2 (2, 0); + TREE_TYPE (integer_two_node) = integer_type_node; + integer_three_node = build_int_2 (3, 0); + TREE_TYPE (integer_three_node) = integer_type_node; + + boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE); + TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE); + TYPE_MAX_VALUE (boolean_type_node) = build_int_2 (1, 0); + TREE_TYPE (TYPE_MAX_VALUE (boolean_type_node)) = boolean_type_node; + TYPE_PRECISION (boolean_type_node) = 1; + record_builtin_type (RID_BOOL, "bool", boolean_type_node); + boolean_false_node = build_int_2 (0, 0); + TREE_TYPE (boolean_false_node) = boolean_type_node; + boolean_true_node = build_int_2 (1, 0); + TREE_TYPE (boolean_true_node) = boolean_type_node; + + /* These are needed by stor-layout.c. */ + size_zero_node = size_int (0); + size_one_node = size_int (1); + + signed_size_zero_node = build_int_2 (0, 0); + TREE_TYPE (signed_size_zero_node) = make_signed_type (TYPE_PRECISION (sizetype)); + + void_type_node = make_node (VOID_TYPE); + record_builtin_type (RID_VOID, NULL_PTR, void_type_node); + layout_type (void_type_node); /* Uses integer_zero_node. */ + void_list_node = build_tree_list (NULL_TREE, void_type_node); + TREE_PARMLIST (void_list_node) = 1; + + null_pointer_node = build_int_2 (0, 0); + TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node); + layout_type (TREE_TYPE (null_pointer_node)); + + /* Used for expressions that do nothing, but are not errors. */ + void_zero_node = build_int_2 (0, 0); + TREE_TYPE (void_zero_node) = void_type_node; + + string_type_node = build_pointer_type (char_type_node); + const_string_type_node + = build_pointer_type (build_qualified_type (char_type_node, + TYPE_QUAL_CONST)); +#if 0 + record_builtin_type (RID_MAX, NULL_PTR, string_type_node); +#endif + + /* 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); + + ptr_type_node = build_pointer_type (void_type_node); + const_ptr_type_node + = build_pointer_type (build_qualified_type (void_type_node, + TYPE_QUAL_CONST)); +#if 0 + record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node); +#endif + endlink = void_list_node; + int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink); + double_endlink = tree_cons (NULL_TREE, double_type_node, endlink); + unsigned_endlink = tree_cons (NULL_TREE, unsigned_type_node, endlink); + + ptr_ftype = build_function_type (ptr_type_node, NULL_TREE); + ptr_ftype_unsigned = build_function_type (ptr_type_node, unsigned_endlink); + sizetype_endlink = tree_cons (NULL_TREE, sizetype, endlink); + /* We realloc here because sizetype could be int or unsigned. S'ok. */ + ptr_ftype_sizetype = build_function_type (ptr_type_node, sizetype_endlink); + + void_ftype = build_function_type (void_type_node, endlink); + void_ftype_int = build_function_type (void_type_node, int_endlink); + void_ftype_ptr + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, endlink)); + void_ftype_ptr + = build_exception_variant (void_ftype_ptr, + tree_cons (NULL_TREE, NULL_TREE, NULL_TREE)); + + float_ftype_float + = build_function_type (float_type_node, + tree_cons (NULL_TREE, float_type_node, endlink)); + + double_ftype_double + = build_function_type (double_type_node, double_endlink); + + ldouble_ftype_ldouble + = build_function_type (long_double_type_node, + tree_cons (NULL_TREE, long_double_type_node, + 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)); + + 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)))); + + string_ftype_ptr_ptr /* strcpy prototype */ + = build_function_type (string_type_node, + tree_cons (NULL_TREE, string_type_node, + tree_cons (NULL_TREE, + const_string_type_node, + endlink))); + + int_ftype_string_string /* strcmp prototype */ + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, const_string_type_node, + tree_cons (NULL_TREE, + const_string_type_node, + endlink))); + + strlen_ftype /* strlen prototype */ + = build_function_type (sizetype, + tree_cons (NULL_TREE, const_string_type_node, + endlink)); + + memcpy_ftype /* memcpy prototype */ + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + 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", default_function_type, + BUILT_IN_CONSTANT_P, NULL_PTR); + + builtin_return_address_fndecl + = builtin_function ("__builtin_return_address", ptr_ftype_unsigned, + BUILT_IN_RETURN_ADDRESS, NULL_PTR); + + builtin_function ("__builtin_frame_address", ptr_ftype_unsigned, + BUILT_IN_FRAME_ADDRESS, NULL_PTR); + + builtin_function ("__builtin_alloca", ptr_ftype_sizetype, + BUILT_IN_ALLOCA, "alloca"); + builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR); + /* Define alloca, ffs as builtins. + Declare _exit just to mark it as volatile. */ + if (! flag_no_builtin && !flag_no_nonansi_builtin) + { + temp = builtin_function ("alloca", ptr_ftype_sizetype, + BUILT_IN_ALLOCA, NULL_PTR); + /* Suppress error if redefined as a non-function. */ + DECL_BUILT_IN_NONANSI (temp) = 1; + temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR); + /* Suppress error if redefined as a non-function. */ + DECL_BUILT_IN_NONANSI (temp) = 1; + temp = builtin_function ("_exit", void_ftype_int, + NOT_BUILT_IN, NULL_PTR); + TREE_THIS_VOLATILE (temp) = 1; + TREE_SIDE_EFFECTS (temp) = 1; + /* Suppress error if redefined as a non-function. */ + DECL_BUILT_IN_NONANSI (temp) = 1; + } + + builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR); + builtin_function ("__builtin_fabsf", float_ftype_float, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("__builtin_fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("__builtin_labs", long_ftype_long, + BUILT_IN_LABS, NULL_PTR); + builtin_function ("__builtin_saveregs", ptr_ftype, + BUILT_IN_SAVEREGS, NULL_PTR); + builtin_function ("__builtin_classify_type", default_function_type, + BUILT_IN_CLASSIFY_TYPE, NULL_PTR); + builtin_function ("__builtin_next_arg", ptr_ftype, + BUILT_IN_NEXT_ARG, NULL_PTR); + builtin_function ("__builtin_args_info", int_ftype_int, + BUILT_IN_ARGS_INFO, NULL_PTR); + builtin_function ("__builtin_setjmp", + build_function_type (integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)), + BUILT_IN_SETJMP, NULL_PTR); + builtin_function ("__builtin_longjmp", + build_function_type (integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink))), + BUILT_IN_LONGJMP, NULL_PTR); + + /* Untyped call and return. */ + builtin_function ("__builtin_apply_args", ptr_ftype, + 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_ftype_sizetype, NULL_TREE)); + builtin_function ("__builtin_apply", + build_function_type (ptr_type_node, temp), + BUILT_IN_APPLY, NULL_PTR); + builtin_function ("__builtin_return", void_ftype_ptr, + BUILT_IN_RETURN, NULL_PTR); + + /* CYGNUS LOCAL -- branch prediction */ + builtin_function ("__builtin_expect", + build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + int_endlink)), + BUILT_IN_EXPECT, NULL_PTR); + + /* END CYGNUS LOCAL -- branch prediction */ + + /* Currently under experimentation. */ + builtin_function ("__builtin_memcpy", memcpy_ftype, + BUILT_IN_MEMCPY, "memcpy"); + builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet, + BUILT_IN_MEMCMP, "memcmp"); + builtin_function ("__builtin_strcmp", int_ftype_string_string, + BUILT_IN_STRCMP, "strcmp"); + builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr, + BUILT_IN_STRCPY, "strcpy"); + builtin_function ("__builtin_strlen", strlen_ftype, + BUILT_IN_STRLEN, "strlen"); + builtin_function ("__builtin_sqrtf", float_ftype_float, + BUILT_IN_FSQRT, "sqrtf"); + builtin_function ("__builtin_fsqrt", double_ftype_double, + BUILT_IN_FSQRT, NULL_PTR); + builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble, + BUILT_IN_FSQRT, "sqrtl"); + builtin_function ("__builtin_sinf", float_ftype_float, + BUILT_IN_SIN, "sinf"); + builtin_function ("__builtin_sin", double_ftype_double, + BUILT_IN_SIN, "sin"); + builtin_function ("__builtin_sinl", ldouble_ftype_ldouble, + BUILT_IN_SIN, "sinl"); + builtin_function ("__builtin_cosf", float_ftype_float, + BUILT_IN_COS, "cosf"); + builtin_function ("__builtin_cos", double_ftype_double, + BUILT_IN_COS, "cos"); + builtin_function ("__builtin_cosl", ldouble_ftype_ldouble, + BUILT_IN_COS, "cosl"); + + if (!flag_no_builtin) + { + 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); + builtin_function ("fabsf", float_ftype_float, BUILT_IN_FABS, NULL_PTR); + builtin_function ("fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR); + builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP, + NULL_PTR); + builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP, + NULL_PTR); + builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY, + NULL_PTR); + builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN, NULL_PTR); + builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT, NULL_PTR); + builtin_function ("sqrt", double_ftype_double, BUILT_IN_FSQRT, NULL_PTR); + builtin_function ("sqrtl", ldouble_ftype_ldouble, BUILT_IN_FSQRT, + NULL_PTR); + builtin_function ("sinf", float_ftype_float, BUILT_IN_SIN, NULL_PTR); + builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR); + builtin_function ("sinl", ldouble_ftype_ldouble, BUILT_IN_SIN, NULL_PTR); + builtin_function ("cosf", float_ftype_float, BUILT_IN_COS, NULL_PTR); + builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR); + builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS, NULL_PTR); + + /* Declare these functions volatile + to avoid spurious "control drops through" warnings. */ + temp = builtin_function ("abort", void_ftype, + NOT_BUILT_IN, NULL_PTR); + TREE_THIS_VOLATILE (temp) = 1; + TREE_SIDE_EFFECTS (temp) = 1; + /* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on + them... */ + DECL_BUILT_IN_NONANSI (temp) = 1; + temp = builtin_function ("exit", void_ftype_int, + NOT_BUILT_IN, NULL_PTR); + TREE_THIS_VOLATILE (temp) = 1; + TREE_SIDE_EFFECTS (temp) = 1; + DECL_BUILT_IN_NONANSI (temp) = 1; + } + +#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, NULL_PTR); + builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR); + builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR, + NULL_PTR); + builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, + NULL_PTR); + builtin_function ("__builtin_fmod", double_ftype_double_double, + BUILT_IN_FMOD, NULL_PTR); + builtin_function ("__builtin_frem", double_ftype_double_double, + BUILT_IN_FREM, NULL_PTR); + builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int, + BUILT_IN_MEMSET, NULL_PTR); + builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP, + NULL_PTR); + builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN, + NULL_PTR); +#endif + + /* C++ extensions */ + + unknown_type_node = make_node (UNKNOWN_TYPE); + record_unknown_type (unknown_type_node, "unknown type"); + + /* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node. */ + TREE_TYPE (unknown_type_node) = unknown_type_node; + + TREE_TYPE (null_node) = type_for_size (POINTER_SIZE, 0); + + /* 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); + + /* Artificial declaration of wchar_t -- can be bashed */ + wchar_decl_node = build_decl (TYPE_DECL, get_identifier ("wchar_t"), + wchar_type_node); + pushdecl (wchar_decl_node); + + /* This is for wide string constants. */ + wchar_array_type_node + = build_array_type (wchar_type_node, array_domain_type); + + 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_qualified_type (vtable_entry_type, + TYPE_QUAL_CONST); + } + record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type); + + vtbl_type_node + = build_cplus_array_type (vtable_entry_type, NULL_TREE); + layout_type (vtbl_type_node); + vtbl_type_node = build_qualified_type (vtbl_type_node, TYPE_QUAL_CONST); + record_builtin_type (RID_MAX, NULL_PTR, vtbl_type_node); + vtbl_ptr_type_node = build_pointer_type (vtable_entry_type); + layout_type (vtbl_ptr_type_node); + record_builtin_type (RID_MAX, NULL_PTR, vtbl_ptr_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, tag_identifier, + delta_type_node); + fields[1] = build_lang_field_decl (FIELD_DECL, vb_off_identifier, + delta_type_node); + fields[2] = build_lang_field_decl (FIELD_DECL, delta_identifier, + delta_type_node); + fields[3] = build_lang_field_decl (FIELD_DECL, index_identifier, + delta_type_node); + fields[4] = build_lang_field_decl (FIELD_DECL, pfn_identifier, + ptr_type_node); + + /* Set the alignment to the max of the alignment of ptr_type_node and + delta_type_node. Double alignment wastes a word on the Sparc. */ + finish_builtin_type (sigtable_entry_type, SIGTABLE_PTR_TYPE, fields, 4, + (TYPE_ALIGN (ptr_type_node) > TYPE_ALIGN (delta_type_node)) + ? ptr_type_node + : delta_type_node); + + /* Make this part of an invisible union. */ + fields[5] = copy_node (fields[4]); + TREE_TYPE (fields[5]) = delta_type_node; + DECL_NAME (fields[5]) = vt_off_identifier; + DECL_MODE (fields[5]) = TYPE_MODE (delta_type_node); + DECL_SIZE (fields[5]) = TYPE_SIZE (delta_type_node); + TREE_UNSIGNED (fields[5]) = 0; + TREE_CHAIN (fields[4]) = fields[5]; + + sigtable_entry_type = build_qualified_type (sigtable_entry_type, + TYPE_QUAL_CONST); + record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_entry_type); + } + + std_node = build_decl (NAMESPACE_DECL, + get_identifier (flag_honor_std ? "fake std":"std"), + void_type_node); + pushdecl (std_node); + + global_type_node = make_node (LANG_TYPE); + record_unknown_type (global_type_node, "global type"); + + /* Now, C++. */ + current_lang_name = lang_name_cplusplus; + + { + tree bad_alloc_type_node, newtype, deltype; + if (flag_honor_std) + push_namespace (get_identifier ("std")); + bad_alloc_type_node = xref_tag + (class_type_node, get_identifier ("bad_alloc"), 1); + if (flag_honor_std) + pop_namespace (); + newtype = build_exception_variant + (ptr_ftype_sizetype, build_tree_list (NULL_TREE, bad_alloc_type_node)); + deltype = build_exception_variant + (void_ftype_ptr, build_tree_list (NULL_TREE, NULL_TREE)); + auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN); + auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN); + global_delete_fndecl + = auto_function (ansi_opname[(int) DELETE_EXPR], deltype, NOT_BUILT_IN); + auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype, NOT_BUILT_IN); + } + + abort_fndecl + = define_function ("__pure_virtual", void_ftype, + NOT_BUILT_IN, 0, 0); + + /* Perform other language dependent initializations. */ + init_class_processing (); + init_init_processing (); + init_search_processing (); + if (flag_rtti) + init_rtti_processing (); + + if (flag_exceptions) + init_exception_processing (); + if (flag_no_inline) + { + flag_inline_functions = 0; + } + + if (! supports_one_only ()) + flag_weak = 0; + + /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */ + declare_function_name (); + + /* Prepare to check format strings against argument lists. */ + init_function_format_info (); + + /* Show we use EH for cleanups. */ + using_eh_for_cleanups (); + + print_error_function = lang_print_error_function; + lang_get_alias_set = &c_get_alias_set; + + /* Maintain consistency. Perhaps we should just complain if they + say -fwritable-strings? */ + if (flag_writable_strings) + flag_const_strings = 0; +} + +/* Function to print any language-specific context for an error message. */ + +static void +lang_print_error_function (file) + char *file; +{ + default_print_error_function (file); + maybe_print_template_context (); +} + +/* 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) PROTO((tree)); + char *library_name; +{ + tree decl = build_lang_decl (FUNCTION_DECL, get_identifier (name), type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + + my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 392); + DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); + + /* 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; +} + +/* When we call finish_struct for an anonymous union, we create + default copy constructors and such. But, an anonymous union + shouldn't have such things; this function undoes the damage to the + anonymous union type T. + + (The reason that we create the synthesized methods is that we don't + distinguish `union { int i; }' from `typedef union { int i; } U'. + The first is an anonymous union; the second is just an ordinary + union type.) */ + +void +fixup_anonymous_union (t) + tree t; +{ + tree *q; + + /* Wipe out memory of synthesized methods */ + TYPE_HAS_CONSTRUCTOR (t) = 0; + TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0; + TYPE_HAS_INIT_REF (t) = 0; + TYPE_HAS_CONST_INIT_REF (t) = 0; + TYPE_HAS_ASSIGN_REF (t) = 0; + TYPE_HAS_ASSIGNMENT (t) = 0; + TYPE_HAS_CONST_ASSIGN_REF (t) = 0; + + /* Splice the implicitly generated functions out of the TYPE_METHODS + list. */ + q = &TYPE_METHODS (t); + while (*q) + { + if (DECL_ARTIFICIAL (*q)) + *q = TREE_CHAIN (*q); + else + q = &TREE_CHAIN (*q); + } + + /* ANSI C++ June 5 1992 WP 9.5.3. Anonymous unions may not have + function members. */ + if (TYPE_METHODS (t)) + error ("an anonymous union cannot have function members"); +} + +/* Make sure that a declaration with no declarator is well-formed, i.e. + just defines a tagged type or anonymous union. + + Returns the type defined, if any. */ + +tree +check_tag_decl (declspecs) + tree declspecs; +{ + int found_type = 0; + tree ob_modifier = NULL_TREE; + register tree link; + register tree t = NULL_TREE; + + for (link = declspecs; link; link = TREE_CHAIN (link)) + { + register tree value = TREE_VALUE (link); + + if (TYPE_P (value)) + { + ++found_type; + + if (IS_AGGR_TYPE (value) || TREE_CODE (value) == ENUMERAL_TYPE) + { + my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261); + t = value; + } + } + else if (value == ridpointers[(int) RID_FRIEND]) + { + if (current_class_type == NULL_TREE + || current_scope () != current_class_type) + ob_modifier = value; + } + else if (value == ridpointers[(int) RID_STATIC] + || value == ridpointers[(int) RID_EXTERN] + || value == ridpointers[(int) RID_AUTO] + || value == ridpointers[(int) RID_REGISTER] + || value == ridpointers[(int) RID_INLINE] + || value == ridpointers[(int) RID_VIRTUAL] + || value == ridpointers[(int) RID_CONST] + || value == ridpointers[(int) RID_VOLATILE] + || value == ridpointers[(int) RID_EXPLICIT]) + ob_modifier = value; + } + + if (found_type > 1) + error ("multiple types in one declaration"); + + /* Inside a class, we might be in a friend or access declaration. + Until we have a good way of detecting the latter, don't warn. */ + if (t == NULL_TREE && ! current_class_type) + pedwarn ("declaration does not declare anything"); + else if (t && ANON_UNION_TYPE_P (t)) + /* Anonymous unions are objects, so they can have specifiers. */; + else if (ob_modifier) + { + if (ob_modifier == ridpointers[(int) RID_INLINE] + || ob_modifier == ridpointers[(int) RID_VIRTUAL]) + cp_error ("`%D' can only be specified for functions", ob_modifier); + else if (ob_modifier == ridpointers[(int) RID_FRIEND]) + cp_error ("`%D' can only be specified inside a class", ob_modifier); + else if (ob_modifier == ridpointers[(int) RID_EXPLICIT]) + cp_error ("`%D' can only be specified for constructors", + ob_modifier); + else + cp_error ("`%D' can only be specified for objects and functions", + ob_modifier); + } + + return t; +} + +/* 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; +{ + tree t = check_tag_decl (declspecs); + + if (t) + maybe_process_partial_specialization (t); + + /* 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 (t && ANON_UNION_TYPE_P (t)) + { + fixup_anonymous_union (t); + + if (TYPE_FIELDS (t)) + { + tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0, + NULL_TREE); + finish_anon_union (decl); + } + } +} + +/* 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 `cp_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, attributes, prefix_attributes) + tree declarator, declspecs; + int initialized; + tree attributes, prefix_attributes; +{ + register tree decl; + register tree type, tem; + tree context; + extern int have_extern_spec; + extern int used_extern_spec; + tree attrlist; + +#if 0 + /* See code below that used this. */ + int init_written = initialized; +#endif + + /* 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 (attributes || prefix_attributes) + attrlist = build_scratch_list (attributes, prefix_attributes); + else + attrlist = NULL_TREE; + + decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, + attrlist); + + if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE) + return NULL_TREE; + + type = TREE_TYPE (decl); + + /* Don't lose if destructors must be executed at file-level. */ + if (! processing_template_decl && TREE_STATIC (decl) + && TYPE_NEEDS_DESTRUCTOR (complete_type (type)) + && !TREE_PERMANENT (decl)) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + decl = copy_node (decl); + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree itype = TYPE_DOMAIN (type); + if (itype && ! TREE_PERMANENT (itype)) + { + itype = build_index_type (copy_to_permanent (TYPE_MAX_VALUE (itype))); + type = build_cplus_array_type (TREE_TYPE (type), itype); + TREE_TYPE (decl) = type; + } + } + pop_obstacks (); + } + + context + = (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl)) + ? DECL_CLASS_CONTEXT (decl) + : DECL_CONTEXT (decl); + + if (initialized && context && TREE_CODE (context) == NAMESPACE_DECL + && context != current_namespace && TREE_CODE (decl) == VAR_DECL) + { + /* When parsing the initializer, lookup should use the object's + namespace. */ + push_decl_namespace (context); + } + + /* We are only interested in class contexts, later. */ + if (context && TREE_CODE (context) == NAMESPACE_DECL) + context = NULL_TREE; + + if (initialized) + /* Is it valid for this decl to have an initializer at all? + If not, set INITIALIZED to zero, which will indirectly + tell `cp_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 `cp_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: + if (! processing_template_decl) + { + if (type != error_mark_node) + { + if (TYPE_SIZE (type) != NULL_TREE + && ! TREE_CONSTANT (TYPE_SIZE (type))) + { + cp_error + ("variable-sized object `%D' may not be initialized", + decl); + initialized = 0; + } + + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE) + { + cp_error + ("elements of array `%#D' have incomplete type", decl); + initialized = 0; + } + } + } + } + + if (initialized) + { + if (! toplevel_bindings_p () + && DECL_EXTERNAL (decl)) + cp_warning ("declaration of `%#D' has `extern' and is initialized", + decl); + DECL_EXTERNAL (decl) = 0; + if (toplevel_bindings_p ()) + TREE_STATIC (decl) = 1; + + /* Tell `pushdecl' this is an initialized decl + even though we don't yet have the initializer expression. + Also tell `cp_finish_decl' it may store the real initializer. */ + DECL_INITIAL (decl) = error_mark_node; + } + + if (context && TYPE_SIZE (complete_type (context)) != NULL_TREE) + { + pushclass (context, 2); + + 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 (DECL_CONTEXT (field) != context) + { + cp_pedwarn ("ANSI C++ does not permit `%T::%D' to be defined as `%T::%D'", + DECL_CONTEXT (field), DECL_NAME (decl), + context, DECL_NAME (decl)); + DECL_CONTEXT (decl) = DECL_CONTEXT (field); + } + /* Static data member are tricky; an in-class initialization + still doesn't provide a definition, so the in-class + declaration will have DECL_EXTERNAL set, but will have an + initialization. Thus, duplicate_decls won't warn + about this situation, and so we check here. */ + if (DECL_INITIAL (decl) && DECL_INITIAL (field)) + cp_error ("duplicate initialization of %D", decl); + if (duplicate_decls (decl, field)) + decl = field; + } + } + else + { + tree field = check_classfn (context, decl); + if (field && duplicate_decls (decl, field)) + decl = field; + } + + /* cp_finish_decl sets DECL_EXTERNAL if DECL_IN_AGGR_P is set. */ + DECL_IN_AGGR_P (decl) = 0; + if ((DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl)) + || CLASSTYPE_USE_TEMPLATE (context)) + { + SET_DECL_TEMPLATE_SPECIALIZATION (decl); + /* [temp.expl.spec] An explicit specialization of a static data + member of a template is a definition if the declaration + includes an initializer; otherwise, it is a declaration. + + We check for processing_specialization so this only applies + to the new specialization syntax. */ + if (DECL_INITIAL (decl) == NULL_TREE && processing_specialization) + DECL_EXTERNAL (decl) = 1; + } + + if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)) + cp_pedwarn ("declaration of `%#D' outside of class is not definition", + decl); + } + +#ifdef SET_DEFAULT_DECL_ATTRIBUTES + SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes); +#endif + + /* Set attributes here so if duplicate decl, will have proper attributes. */ + cplus_decl_attributes (decl, attributes, prefix_attributes); + + /* 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 + /* Definitions of namespace members outside their namespace are + possible. */ + && TREE_CODE (DECL_CONTEXT (decl)) != NAMESPACE_DECL) + || (TREE_CODE (decl) == TEMPLATE_DECL && !namespace_bindings_p ()) + || TREE_CODE (type) == LANG_TYPE + /* The declaration of template specializations does not affect + the functions available for overload resolution, so we do not + call pushdecl. */ + || (TREE_CODE (decl) == FUNCTION_DECL + && DECL_TEMPLATE_SPECIALIZATION (decl))) + tem = decl; + else + tem = pushdecl (decl); + + if (processing_template_decl) + { + if (! current_function_decl) + tem = push_template_decl (tem); + else if (minimal_parse_mode) + DECL_VINDEX (tem) + = build_min_nt (DECL_STMT, copy_to_permanent (declarator), + copy_to_permanent (declspecs), + NULL_TREE); + } + + +#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS) + /* Tell the back-end to use or not use .common as appropriate. If we say + -fconserve-space, we want this to save .data 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. */ + DECL_COMMON (tem) = flag_conserve_space || ! TREE_PUBLIC (tem); +#endif + + if (! processing_template_decl) + start_decl_1 (tem); + + /* Corresponding pop_obstacks is done in `cp_finish_decl'. */ + push_obstacks_nochange (); + +#if 0 + /* We have no way of knowing whether the initializer will need to be + evaluated at run-time or not until we've parsed it, so let's just put + it in the permanent obstack. (jason) */ + 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 (toplevel_bindings_p () && debug_temp_inits) + { + if (processing_template_decl + || 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 (); + } + } +#endif + + return tem; +} + +void +start_decl_1 (decl) + tree decl; +{ + tree type = TREE_TYPE (decl); + int initialized = (DECL_INITIAL (decl) != NULL_TREE); + + /* 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 `cp_finish_decl' to ignore the initializer once it is parsed. */ + { + /* 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 (complete_type (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; + type = TREE_TYPE (decl) = error_mark_node; + } + else if (TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE) + { + if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)) + cp_error ("elements of array `%#D' have incomplete type", decl); + /* else we already gave an error in start_decl. */ + initialized = 0; + } + } + + if (!initialized + && TREE_CODE (decl) != TYPE_DECL + && TREE_CODE (decl) != TEMPLATE_DECL + && IS_AGGR_TYPE (type) && ! DECL_EXTERNAL (decl)) + { + if ((! processing_template_decl || ! uses_template_parms (type)) + && TYPE_SIZE (complete_type (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)). */ + type = TREE_TYPE (decl) = 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 0 + /* We don't do this yet for GNU C++. */ + /* For a local variable, define the RTL now. */ + if (! toplevel_bindings_p () + /* 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 (! initialized) + DECL_INITIAL (decl) = NULL_TREE; +} + +/* Handle initialization of references. + These three arguments are from `cp_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) + tree decl, type, init; +{ + tree tmp; + + if (init == NULL_TREE) + { + if ((DECL_LANG_SPECIFIC (decl) == 0 + || DECL_IN_AGGR_P (decl) == 0) + && ! DECL_THIS_EXTERN (decl)) + { + cp_error ("`%D' declared as reference but not initialized", decl); + if (TREE_CODE (decl) == VAR_DECL) + SET_DECL_REFERENCE_SLOT (decl, error_mark_node); + } + 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 (init)) == REFERENCE_TYPE) + init = convert_from_reference (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|DIRECT_BIND, decl); + + if (tmp == error_mark_node) + goto fail; + else if (tmp != NULL_TREE) + { + init = tmp; + 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; +} + +/* Fill in DECL_INITIAL with some magical value to prevent expand_decl from + mucking with forces it does not comprehend (i.e. initialization with a + constructor). If we are at global scope and won't go into COMMON, fill + it in with a dummy CONSTRUCTOR to force the variable into .data; + otherwise we can use error_mark_node. */ + +static tree +obscure_complex_init (decl, init) + tree decl, init; +{ + if (! flag_no_inline && TREE_STATIC (decl)) + { + if (extract_init (decl, init)) + return NULL_TREE; + } + +#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS) + if (toplevel_bindings_p () && ! DECL_COMMON (decl)) + DECL_INITIAL (decl) = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE, + NULL_TREE); + else +#endif + DECL_INITIAL (decl) = error_mark_node; + + return init; +} + +/* Issue an error message if DECL is an uninitialized const variable. */ + +static void +check_for_uninitialized_const_var (decl) + tree decl; +{ + tree type = TREE_TYPE (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 */ + if (TREE_CODE (decl) == VAR_DECL + && TREE_CODE (type) != REFERENCE_TYPE + && CP_TYPE_CONST_P (type) + && !TYPE_NEEDS_CONSTRUCTING (type) + && !DECL_INITIAL (decl)) + cp_error ("uninitialized const `%D'", decl); +} + +/* 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++, `cp_finish_decl' must be fairly evasive: it must keep initializers + for aggregates that have constructors alive on the permanent obstack, + so that the global initializing functions can be written at the end. + + INIT0 holds the value of an initializer that should be allowed to escape + the normal rules. + + FLAGS is LOOKUP_ONLYCONVERTING is the = init syntax was used, else 0 + if the (init) syntax was used. + + For functions that take default parameters, DECL points to its + "maximal" instantiation. `cp_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 +cp_finish_decl (decl, init, asmspec_tree, need_pop, flags) + tree decl, init; + tree asmspec_tree; + int need_pop; + int flags; +{ + register tree type; + tree cleanup = NULL_TREE, ttype = NULL_TREE; + int was_incomplete; + int temporary = allocation_temporary_p (); + char *asmspec = NULL; + int was_readonly = 0; + int already_used = 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 (init && TREE_CODE (init) == NAMESPACE_DECL) + { + cp_error ("Cannot initialize `%D' to namespace `%D'", + decl, init); + init = NULL_TREE; + } + + if (current_class_type + && DECL_REAL_CONTEXT (decl) == current_class_type + && TYPE_BEING_DEFINED (current_class_type) + && (DECL_INITIAL (decl) || init)) + DECL_DEFINED_IN_CLASS_P (decl) = 1; + + if (TREE_CODE (decl) == VAR_DECL + && DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL + && DECL_CONTEXT (decl) != current_namespace + && init) + { + /* Leave the namespace of the object. */ + pop_decl_namespace (); + } + + /* 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); + + if (type == error_mark_node) + { + if (toplevel_bindings_p () && temporary) + end_temporary_allocation (); + + return; + } + + if (TYPE_HAS_MUTABLE_P (type)) + TREE_READONLY (decl) = 0; + + if (processing_template_decl) + { + if (init && DECL_INITIAL (decl)) + DECL_INITIAL (decl) = init; + if (minimal_parse_mode && ! DECL_ARTIFICIAL (decl)) + { + tree stmt = DECL_VINDEX (decl); + /* If the decl is declaring a member of a local class (in a + template function), the DECL_VINDEX will either be NULL, + or it will be an actual virtual function index, not a + DECL_STMT. */ + if (stmt != NULL_TREE && TREE_CODE (stmt) == DECL_STMT) + { + DECL_VINDEX (decl) = NULL_TREE; + TREE_OPERAND (stmt, 2) = copy_to_permanent (init); + add_tree (stmt); + } + } + + goto finish_end0; + } + /* 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); + + /* If we have installed this as the canonical typedef for this + type, and that type has not been defined yet, delay emitting + the debug information for it, as we will emit it later. */ + if (TYPE_MAIN_DECL (TREE_TYPE (decl)) == decl + && TYPE_SIZE (TREE_TYPE (decl)) == NULL_TREE) + TYPE_DECL_SUPPRESS_DEBUG (decl) = 1; + + rest_of_decl_compilation (decl, NULL_PTR, + DECL_CONTEXT (decl) == NULL_TREE, at_eof); + goto finish_end; + } + if (TREE_CODE (decl) != FUNCTION_DECL) + { + ttype = target_type (type); + } + + 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. */ + 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))) + { + if (TREE_STATIC (decl)) + make_decl_rtl (decl, NULL_PTR, + toplevel_bindings_p () + || pseudo_global_level_p ()); + grok_reference_init (decl, type, init); + 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 + && TREE_HAS_CONSTRUCTOR (init)) + { + if (TYPE_NON_AGGREGATE_CLASS (type)) + { + cp_error ("`%D' must be initialized by constructor, not by `{...}'", + decl); + init = error_mark_node; + } + else + goto dont_use_constructor; + } + } + else + { + dont_use_constructor: + if (TREE_CODE (init) != TREE_VEC) + init = store_init_value (decl, init); + } + + if (init) + /* We must hide the initializer so that expand_decl + won't try to do something it does not understand. */ + init = obscure_complex_init (decl, init); + } + 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); + } + + check_for_uninitialized_const_var (decl); + + if (TYPE_SIZE (type) != NULL_TREE + && TYPE_NEEDS_CONSTRUCTING (type)) + init = obscure_complex_init (decl, NULL_TREE); + + } + else + check_for_uninitialized_const_var (decl); + + /* For top-level declaration, the initial value was read in + the temporary obstack. MAXINDEX, rtl, etc. to be made below + must go in the permanent obstack; but don't discard the + temporary data yet. */ + + if (toplevel_bindings_p () && temporary) + end_temporary_allocation (); + + /* Deduce size of array from initialization, if not already known. */ + + 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 (complete_type (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 (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl)) + note_debug_info_needed (DECL_CONTEXT (decl)); + + 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) + /* Cleanups for static variables are handled by `finish_file'. */ + && ! TREE_STATIC (decl)) + { + int yes = suspend_momentary (); + 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. */ + + was_incomplete = (DECL_SIZE (decl) == NULL_TREE); + + if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == RESULT_DECL) + { + /* ??? FIXME: What about nested classes? */ + int toplev = toplevel_bindings_p () || pseudo_global_level_p (); + int was_temp + = (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type) + && allocation_temporary_p ()); + + if (was_temp) + end_temporary_allocation (); + + /* Static data in a function with comdat linkage also has comdat + linkage. */ + if (TREE_CODE (decl) == VAR_DECL + && TREE_STATIC (decl) + /* Don't mess with __FUNCTION__. */ + && ! TREE_ASM_WRITTEN (decl) + && current_function_decl + && DECL_CONTEXT (decl) == current_function_decl + && (DECL_THIS_INLINE (current_function_decl) + || DECL_TEMPLATE_INSTANTIATION (current_function_decl)) + && TREE_PUBLIC (current_function_decl)) + { + /* Rather than try to get this right with inlining, we suppress + inlining of such functions. */ + current_function_cannot_inline + = "function with static variable cannot be inline"; + + /* If flag_weak, we don't need to mess with this, as we can just + make the function weak, and let it refer to its unique local + copy. This works because we don't allow the function to be + inlined. */ + if (! flag_weak) + { + if (DECL_INTERFACE_KNOWN (current_function_decl)) + { + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = DECL_EXTERNAL (current_function_decl); + } + else if (DECL_INITIAL (decl) == NULL_TREE + || DECL_INITIAL (decl) == error_mark_node) + { + TREE_PUBLIC (decl) = 1; + DECL_COMMON (decl) = 1; + } + /* else we lose. We can only do this if we can use common, + which we can't if it has been initialized. */ + + if (TREE_PUBLIC (decl)) + DECL_ASSEMBLER_NAME (decl) + = build_static_name (current_function_decl, DECL_NAME (decl)); + else if (! DECL_ARTIFICIAL (decl)) + { + cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl); + cp_warning_at (" you can work around this by removing the initializer"), decl; + } + } + } + + else if (TREE_CODE (decl) == VAR_DECL + && DECL_LANG_SPECIFIC (decl) + && DECL_COMDAT (decl)) + { + /* Dynamically initialized vars go into common. */ + if (DECL_INITIAL (decl) == NULL_TREE + || DECL_INITIAL (decl) == error_mark_node) + DECL_COMMON (decl) = 1; + else if (EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))) + { + DECL_COMMON (decl) = 1; + DECL_INITIAL (decl) = error_mark_node; + } + else + { + /* Statically initialized vars are weak or comdat, if + supported. */ + if (flag_weak) + make_decl_one_only (decl); + else + { + /* We can't do anything useful; leave vars for explicit + instantiation. */ + DECL_EXTERNAL (decl) = 1; + DECL_NOT_REALLY_EXTERN (decl) = 0; + } + } + } + + 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, at_eof); + } + 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, at_eof); + } + else + /* Just a constant field. Should not need any rtl. */ + goto finish_end0; + } + else + rest_of_decl_compilation (decl, asmspec, toplev, at_eof); + + 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) + ; + else if (DECL_EXTERNAL (decl) + && ! (DECL_LANG_SPECIFIC (decl) + && DECL_NOT_REALLY_EXTERN (decl))) + { + if (init) + DECL_INITIAL (decl) = init; + } + 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 + || TYPE_NEEDS_DESTRUCTOR (type)) + expand_static_init (decl, init); + } + else if (! toplev) + { + /* 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 (current_binding_level->is_for_scope) + { + struct binding_level *outer + = current_binding_level->level_chain; + + /* Check to see if the same name is already bound at + the outer level, either because it was directly declared, + or because a dead for-decl got preserved. In either case, + the code would not have been valid under the ARM + scope rules, so clear is_for_scope for the + current_binding_level. + + Otherwise, we need to preserve the temp slot for decl + to last into the outer binding level. */ + + tree outer_binding + = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (decl))); + + if (outer_binding && BINDING_LEVEL (outer_binding) == outer + && (TREE_CODE (BINDING_VALUE (outer_binding)) + == VAR_DECL) + && DECL_DEAD_FOR_LOCAL (BINDING_VALUE (outer_binding))) + { + BINDING_VALUE (outer_binding) + = DECL_SHADOWED_FOR_VAR (BINDING_VALUE (outer_binding)); + current_binding_level->is_for_scope = 0; + } + else if (DECL_IN_MEMORY_P (decl)) + preserve_temp_slots (DECL_RTL (decl)); + } + + expand_start_target_temps (); + + if (DECL_SIZE (decl) && type != error_mark_node) + { + /* Compute and store the initial value. */ + expand_decl_init (decl); + already_used = TREE_USED (decl) || TREE_USED (type); + + if (init || TYPE_NEEDS_CONSTRUCTING (type)) + { + emit_line_note (DECL_SOURCE_FILE (decl), + DECL_SOURCE_LINE (decl)); + expand_aggr_init (decl, init, flags); + } + + /* Set this to 0 so we can tell whether an aggregate which + was initialized was ever used. Don't do this if it has a + destructor, so we don't complain about the 'resource + allocation is initialization' idiom. */ + /* Now set attribute((unused)) on types so decls of + that type will be marked used. (see TREE_USED, above.) + This avoids the warning problems this particular code + tried to work around. */ + + if (TYPE_NEEDS_CONSTRUCTING (type) + && ! already_used + && cleanup == NULL_TREE + && DECL_NAME (decl)) + TREE_USED (decl) = 0; + + if (already_used) + TREE_USED (decl) = 1; + } + + /* Cleanup any temporaries needed for the initial value. */ + expand_end_target_temps (); + + if (DECL_SIZE (decl) && type != error_mark_node) + { + /* 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); + } + } + } + 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_REAL_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 + && context == current_class_type) + popclass (1); + } + } + + finish_end: + + /* If requested, warn about definitions of large data objects. */ + + if (warn_larger_than + && ! processing_template_decl + && (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; +} + +/* This is here for a midend callback from c-common.c */ + +void +finish_decl (decl, init, asmspec_tree) + tree decl, init; + tree asmspec_tree; +{ + cp_finish_decl (decl, init, asmspec_tree, 1, 0); +} + +void +expand_static_init (decl, init) + tree decl; + tree init; +{ + tree oldstatic = value_member (decl, static_aggregates); + + if (oldstatic) + { + if (TREE_PURPOSE (oldstatic) && init != NULL_TREE) + cp_error ("multiple initializations given for `%D'", decl); + } + else if (! toplevel_bindings_p () && ! pseudo_global_level_p ()) + { + /* 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. This code + looks like: + + static int temp = 0; + if (!temp) { + // Do initialization. + temp = 1; + // Register variable for destruction at end of program. + } + + Note that the `temp' variable is only set to 1 *after* the + initialization is complete. This ensures that an exception, + thrown during the construction, will cause the variable to + reinitialized when we pass through this code again, as per: + + [stmt.dcl] + + If the initialization exits by throwing an exception, the + initialization is not complete, so it will be tried again + the next time control enters the declaration. + + In theory, this process should be thread-safe, too; multiple + threads should not be able to initialize the variable more + than once. We don't yet attempt to ensure thread-safety. */ + temp = get_temp_name (integer_type_node, 1); + rest_of_decl_compilation (temp, NULL_PTR, 0, 0); + + /* Begin the conditional initialization. */ + expand_start_cond (build_binary_op (EQ_EXPR, temp, + integer_zero_node, 1), 0); + expand_start_target_temps (); + + /* Do the initialization itself. */ + if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)) + || (init && TREE_CODE (init) == TREE_LIST)) + { + expand_aggr_init (decl, init, 0); + do_pending_stack_adjust (); + } + else if (init) + expand_assignment (decl, init, 0, 0); + + /* Set TEMP to 1. */ + expand_assignment (temp, integer_one_node, 0, 0); + + /* Cleanup any temporaries needed for the initial value. If + destroying one of the temporaries causes an exception to be + thrown, then the object itself has still been fully + constructed. */ + expand_end_target_temps (); + + /* Use atexit to register a function for destroying this static + variable. */ + if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) + { + tree cleanup, fcall; + static tree Atexit = 0; + if (Atexit == 0) + { + tree atexit_fndecl, PFV, pfvlist; + /* Remember this information until end of file. */ + push_obstacks (&permanent_obstack, &permanent_obstack); + PFV = build_pointer_type (build_function_type + (void_type_node, void_list_node)); + + pfvlist = tree_cons (NULL_TREE, PFV, void_list_node); + + push_lang_context (lang_name_c); + atexit_fndecl + = builtin_function ("atexit", + build_function_type (void_type_node, + pfvlist), + NOT_BUILT_IN, NULL_PTR); + mark_used (atexit_fndecl); + Atexit = default_conversion (atexit_fndecl); + pop_lang_context (); + pop_obstacks (); + } + + /* Call build_cleanup before we enter the anonymous function + so that any access checks will be done relative to the + current scope, rather than the scope of the anonymous + function. */ + fcall = build_cleanup (decl); + cleanup = start_anon_func (); + expand_expr_stmt (fcall); + end_anon_func (); + mark_addressable (cleanup); + cleanup = build_unary_op (ADDR_EXPR, cleanup, 0); + fcall = build_function_call (Atexit, expr_tree_cons (NULL_TREE, cleanup, NULL_TREE)); + expand_expr_stmt (fcall); + } + + 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) + { + int eltsize + = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value))); + maxindex = build_int_2 ((TREE_STRING_LENGTH (initial_value) + / eltsize) - 1, 0); + } + else if (TREE_CODE (initial_value) == CONSTRUCTOR) + { + tree elts = CONSTRUCTOR_ELTS (initial_value); + maxindex = size_binop (MINUS_EXPR, integer_zero_node, size_one_node); + for (; elts; elts = TREE_CHAIN (elts)) + { + if (TREE_PURPOSE (elts)) + maxindex = TREE_PURPOSE (elts); + else + maxindex = size_binop (PLUS_EXPR, maxindex, size_one_node); + } + maxindex = copy_node (maxindex); + } + 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); + /* The type of the main variant should never be used for arrays + of different sizes. It should only ever be completed with the + size of the array. */ + if (! TYPE_DOMAIN (TYPE_MAIN_VARIANT (type))) + TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)) = TYPE_DOMAIN (type); + } + + /* Lay out the type now that we can get the real answer. */ + + 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 exception specifications", 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. + + Returns `error_mark_node' if something goes wrong, after issuing + applicable error messages. */ + +static tree +grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals, + raises, attrlist, check, friendp, publicp, inlinep, funcdef_flag, + template_count, in_namespace) + tree ctype, type; + tree declarator; + tree orig_declarator; + int virtualp; + enum overload_flags flags; + tree quals, raises, attrlist; + int check, friendp, publicp, inlinep, funcdef_flag, template_count; + tree in_namespace; +{ + tree cname, decl; + int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; + tree t; + + 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 (type, raises); + } + + decl = build_lang_decl (FUNCTION_DECL, declarator, type); + /* Propagate volatile out from type to decl. */ + if (TYPE_VOLATILE (type)) + TREE_THIS_VOLATILE (decl) = 1; + + /* If this decl has namespace scope, set that up. */ + if (in_namespace) + set_decl_namespace (decl, in_namespace); + else if (publicp && ! ctype) + DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); + + /* `main' and builtins have implicit 'C' linkage. */ + if ((MAIN_NAME_P (declarator) + || (IDENTIFIER_LENGTH (declarator) > 10 + && IDENTIFIER_POINTER (declarator)[0] == '_' + && IDENTIFIER_POINTER (declarator)[1] == '_' + && strncmp (IDENTIFIER_POINTER (declarator)+2, "builtin_", 8) == 0)) + && current_lang_name == lang_name_cplusplus + && ctype == NULL_TREE + /* NULL_TREE means global namespace. */ + && DECL_CONTEXT (decl) == NULL_TREE) + DECL_LANGUAGE (decl) = lang_c; + + /* Should probably propagate const out from type to decl I bet (mrs). */ + if (staticp) + { + DECL_STATIC_FUNCTION_P (decl) = 1; + DECL_CONTEXT (decl) = ctype; + } + + if (ctype) + DECL_CLASS_CONTEXT (decl) = ctype; + + if (ctype == NULL_TREE && DECL_MAIN_P (decl)) + { + if (processing_template_decl) + error ("cannot declare `main' to be a template"); + if (inlinep) + error ("cannot declare `main' to be inline"); + else if (! publicp) + error ("cannot declare `main' to be static"); + inlinep = 0; + publicp = 1; + } + + /* Members of anonymous types and local classes have no linkage; make + them internal. */ + if (ctype && (ANON_AGGRNAME_P (TYPE_IDENTIFIER (ctype)) + || hack_decl_function_context (TYPE_MAIN_DECL (ctype)))) + publicp = 0; + + if (publicp) + { + /* [basic.link]: A name with no linkage (notably, the name of a class + or enumeration declared in a local scope) shall not be used to + declare an entity with linkage. + + Only check this for public decls for now. */ + t = no_linkage_check (TREE_TYPE (decl)); + if (t) + { + if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))) + { + if (DECL_LANGUAGE (decl) == lang_c) + /* Allow this; it's pretty common in C. */; + else + cp_pedwarn ("non-local function `%#D' uses anonymous type", + decl); + } + else + cp_pedwarn ("non-local function `%#D' uses local type `%T'", + decl, t); + } + } + + TREE_PUBLIC (decl) = publicp; + if (! publicp) + { + DECL_INTERFACE_KNOWN (decl) = 1; + DECL_NOT_REALLY_EXTERN (decl) = 1; + } + + if (inlinep) + DECL_THIS_INLINE (decl) = DECL_INLINE (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); + + if (ctype && hack_decl_function_context (decl)) + DECL_NO_STATIC_CHAIN (decl) = 1; + + for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t)) + if (TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG) + { + add_defarg_fn (decl); + break; + } + + if (friendp + && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR) + { + if (funcdef_flag) + cp_error + ("defining explicit specialization `%D' in friend declaration", + orig_declarator); + else + { + if (PROCESSING_REAL_TEMPLATE_DECL_P ()) + { + /* Something like `template <class T> friend void f<T>()'. */ + cp_error ("template-id `%D' in declaration of primary template", + orig_declarator); + return error_mark_node; + } + + /* A friend declaration of the form friend void f<>(). Record + the information in the TEMPLATE_ID_EXPR. */ + SET_DECL_IMPLICIT_INSTANTIATION (decl); + DECL_TEMPLATE_INFO (decl) + = perm_tree_cons (TREE_OPERAND (orig_declarator, 0), + TREE_OPERAND (orig_declarator, 1), + NULL_TREE); + } + } + + /* Plain overloading: will not be grok'd by grokclassfn. */ + if (! ctype && ! processing_template_decl + && DECL_LANGUAGE (decl) != lang_c + && (! DECL_USE_TEMPLATE (decl) || name_mangling_version < 1)) + set_mangled_name_for_decl (decl); + + if (funcdef_flag) + /* Make the init_value nonzero so pushdecl knows this is not + tentative. error_mark_node is replaced later with the BLOCK. */ + DECL_INITIAL (decl) = error_mark_node; + + /* Caller will do the rest of this. */ + if (check < 0) + return decl; + + if (check && funcdef_flag) + DECL_INITIAL (decl) = error_mark_node; + + if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator) + { + tree tmp; + /* 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, decl, flags, quals); + + decl = check_explicit_specialization (orig_declarator, decl, + template_count, + 2 * (funcdef_flag != 0) + + 4 * (friendp != 0)); + if (decl == error_mark_node) + return error_mark_node; + + if ((! TYPE_FOR_JAVA (ctype) || check_java_method (decl)) + && check) + { + tmp = check_classfn (ctype, decl); + + if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL) + tmp = DECL_TEMPLATE_RESULT(tmp); + + if (tmp && DECL_ARTIFICIAL (tmp)) + cp_error ("definition of implicitly-declared `%D'", tmp); + if (tmp && duplicate_decls (decl, tmp)) + return tmp; + } + if (! grok_ctor_properties (ctype, decl)) + return error_mark_node; + } + 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, decl, flags, quals); + + decl = check_explicit_specialization (orig_declarator, decl, + template_count, + 2 * (funcdef_flag != 0) + + 4 * (friendp != 0)); + if (decl == error_mark_node) + return error_mark_node; + + if (ctype != NULL_TREE + && (! TYPE_FOR_JAVA (ctype) || check_java_method (decl)) + && check) + { + tmp = check_classfn (ctype, decl); + + if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL) + tmp = DECL_TEMPLATE_RESULT (tmp); + + if (tmp && DECL_STATIC_FUNCTION_P (tmp) + && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) + { + /* Remove the `this' parm added by grokclassfn. + XXX Isn't this done in start_function, too? */ + revert_static_member_fn (&decl, NULL, NULL); + last_function_parms = TREE_CHAIN (last_function_parms); + } + if (tmp && DECL_ARTIFICIAL (tmp)) + cp_error ("definition of implicitly-declared `%D'", tmp); + if (tmp) + { + if (!duplicate_decls (decl, tmp)) + my_friendly_abort (892); + return tmp; + } + } + + if (ctype == NULL_TREE || check) + return decl; + + if (attrlist) + cplus_decl_attributes (decl, TREE_PURPOSE (attrlist), + TREE_VALUE (attrlist)); + make_decl_rtl (decl, NULL_PTR, 1); + + if (virtualp) + { + DECL_VIRTUAL_P (decl) = 1; + if (DECL_VINDEX (decl) == NULL_TREE) + DECL_VINDEX (decl) = error_mark_node; + IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1; + } + } + return decl; +} + +static tree +grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace) + tree type; + tree declarator; + RID_BIT_TYPE *specbits_in; + int initialized; + int constp; + tree in_namespace; +{ + tree decl; + RID_BIT_TYPE specbits; + + specbits = *specbits_in; + + 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; + DECL_ASSEMBLER_NAME (decl) = build_static_name (basetype, declarator); + } + else + { + tree context; + + if (in_namespace) + context = in_namespace; + else if (namespace_bindings_p () || RIDBIT_SETP (RID_EXTERN, specbits)) + context = current_namespace; + else + context = NULL_TREE; + + decl = build_decl (VAR_DECL, declarator, complete_type (type)); + + if (context) + set_decl_namespace (decl, context); + + context = DECL_CONTEXT (decl); + if (declarator && context && current_lang_name != lang_name_c) + DECL_ASSEMBLER_NAME (decl) = build_static_name (context, declarator); + } + + if (in_namespace) + set_decl_namespace (decl, in_namespace); + + 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_CLASS_SCOPE_P (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 (toplevel_bindings_p ()) + { + TREE_PUBLIC (decl) = (RIDBIT_NOTSETP (RID_STATIC, specbits) + && (DECL_THIS_EXTERN (decl) || ! constp)); + 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); + } + + if (TREE_PUBLIC (decl)) + { + /* [basic.link]: A name with no linkage (notably, the name of a class + or enumeration declared in a local scope) shall not be used to + declare an entity with linkage. + + Only check this for public decls for now. */ + tree t = no_linkage_check (TREE_TYPE (decl)); + if (t) + { + if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))) + /* Ignore for now; `enum { foo } e' is pretty common. */; + else + cp_pedwarn ("non-local variable `%#D' uses local type `%T'", + decl, t); + } + } + + return decl; +} + +/* Create and return a canonical pointer to member function type, for + TYPE, which is a POINTER_TYPE to a METHOD_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); + SET_IS_AGGR_TYPE (u, 0); + fields[0] = build_lang_field_decl (FIELD_DECL, pfn_identifier, type); + fields[1] = build_lang_field_decl (FIELD_DECL, delta2_identifier, + delta_type_node); + 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; + /* ... and not really an aggregate. */ + SET_IS_AGGR_TYPE (t, 0); + + 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. + CATCHPARM for a parameter declaration before a catch clause. + 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. + + ATTRLIST is a TREE_LIST node with prefix attributes in TREE_VALUE and + normal attributes in TREE_PURPOSE, or NULL_TREE. + + 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 }; + +/* DECL is a VAR_DECL defined in-class, whose TYPE is also given. + Check to see that the definition is valid. Issue appropriate error + messages. Return 1 if the definition is particularly bad, or 0 + otherwise. */ + +int +check_static_variable_definition (decl, type) + tree decl; + tree type; +{ + /* 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 (CLASS_TYPE_P (type) || TREE_CODE (type) == REFERENCE_TYPE) + { + cp_error ("in-class initialization of static data member of non-integral type `%T'", + type); + /* If we just return the declaration, crashes will sometimes + occur. We therefore return void_type_node, as if this was a + friend declaration, to cause callers to completely ignore + this declaration. */ + return 1; + } + else if (!CP_TYPE_CONST_P (type)) + cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'", + decl); + else if (pedantic && !INTEGRAL_TYPE_P (type)) + cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", decl, type); + + return 0; +} + +tree +grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) + tree declspecs; + tree declarator; + enum decl_context decl_context; + int initialized; + tree attrlist; +{ + RID_BIT_TYPE specbits; + int nclasses = 0; + tree spec; + tree type = NULL_TREE; + int longlong = 0; + int constp; + int restrictp; + int volatilep; + int type_quals; + int virtualp, explicitp, friendp, inlinep, staticp; + int explicit_int = 0; + int explicit_char = 0; + int defaulted_int = 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; +#if 0 + /* See the code below that used this. */ + tree decl_machine_attr = NULL_TREE; +#endif + /* 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; + tree raises = NULL_TREE; + int template_count = 0; + tree in_namespace = NULL_TREE; + tree inner_attrs; + int ignore_attrs; + + 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; + + /* Look inside a declarator for the name being declared + and get it as a string, for an error message. */ + { + tree *next = &declarator; + register tree decl; + name = NULL; + + while (next && *next) + { + decl = *next; + switch (TREE_CODE (decl)) + { + case TREE_LIST: + /* For attributes. */ + next = &TREE_VALUE (decl); + break; + + case COND_EXPR: + ctype = NULL_TREE; + next = &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; + if (TREE_CODE (name) == TYPE_DECL) + TREE_OPERAND (decl, 0) = name = constructor_name (name); + 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) + { + cp_error ("destructor `%T' must match class name `%T'", + name, rename); + TREE_OPERAND (decl, 0) = rename; + } + next = &name; + } + break; + + case ADDR_EXPR: /* C++ reference declaration */ + /* Fall through. */ + case ARRAY_REF: + case INDIRECT_REF: + ctype = NULL_TREE; + innermost_code = TREE_CODE (decl); + next = &TREE_OPERAND (decl, 0); + break; + + 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 + cp_finish_decl so we can get the variable + initialized... */ + + tree attributes, prefix_attributes; + + *next = TREE_OPERAND (decl, 0); + init = TREE_OPERAND (decl, 1); + + if (attrlist) + { + attributes = TREE_PURPOSE (attrlist); + prefix_attributes = TREE_VALUE (attrlist); + } + else + { + attributes = NULL_TREE; + prefix_attributes = NULL_TREE; + } + + decl = start_decl (declarator, declspecs, 1, + attributes, prefix_attributes); + if (decl) + { + /* Look for __unused__ attribute */ + if (TREE_USED (TREE_TYPE (decl))) + TREE_USED (decl) = 1; + finish_decl (decl, init, NULL_TREE); + } + else + cp_error ("invalid declarator"); + return 0; + } + innermost_code = TREE_CODE (decl); + if (decl_context == FIELD && ctype == NULL_TREE) + ctype = current_class_type; + if (ctype + && TREE_OPERAND (decl, 0) + && (TREE_CODE (TREE_OPERAND (decl, 0)) == TYPE_DECL + && ((DECL_NAME (TREE_OPERAND (decl, 0)) + == constructor_name_full (ctype)) + || (DECL_NAME (TREE_OPERAND (decl, 0)) + == constructor_name (ctype))))) + TREE_OPERAND (decl, 0) = constructor_name (ctype); + next = &TREE_OPERAND (decl, 0); + decl = *next; + if (ctype != NULL_TREE + && decl != NULL_TREE && flags != DTOR_FLAG + && decl == constructor_name (ctype)) + { + return_type = return_ctor; + ctor_return_type = ctype; + } + ctype = NULL_TREE; + break; + + case TEMPLATE_ID_EXPR: + { + tree fns = TREE_OPERAND (decl, 0); + + if (TREE_CODE (fns) == LOOKUP_EXPR) + fns = TREE_OPERAND (fns, 0); + + if (TREE_CODE (fns) == IDENTIFIER_NODE) + dname = fns; + else if (is_overloaded_fn (fns)) + dname = DECL_NAME (get_first_fn (fns)); + else + my_friendly_abort (0); + } + /* Fall through. */ + + case IDENTIFIER_NODE: + if (TREE_CODE (decl) == IDENTIFIER_NODE) + dname = decl; + + next = 0; + + if (is_rid (dname)) + { + cp_error ("declarator-id missing; using reserved word `%D'", + dname); + name = IDENTIFIER_POINTER (dname); + } + if (! IDENTIFIER_OPNAME_P (dname) + /* GNU/Linux headers use '__op'. Arrgh. */ + || (IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname))) + name = IDENTIFIER_POINTER (dname); + else + { + 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); + } + break; + + /* C++ extension */ + case SCOPE_REF: + { + /* Perform error checking, and decide on a ctype. */ + tree cname = TREE_OPERAND (decl, 0); + if (cname == NULL_TREE) + ctype = NULL_TREE; + else if (TREE_CODE (cname) == NAMESPACE_DECL) + { + ctype = NULL_TREE; + in_namespace = TREE_OPERAND (decl, 0); + TREE_OPERAND (decl, 0) = NULL_TREE; + } + else if (! is_aggr_type (cname, 1)) + TREE_OPERAND (decl, 0) = NULL_TREE; + /* Must test TREE_OPERAND (decl, 1), in case user gives + us `typedef (class::memfunc)(int); memfunc *memfuncptr;' */ + else if (TREE_OPERAND (decl, 1) + && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF) + ctype = cname; + else if (TREE_CODE (cname) == TEMPLATE_TYPE_PARM + || TREE_CODE (cname) == TEMPLATE_TEMPLATE_PARM) + { + cp_error ("`%T::%D' is not a valid declarator", cname, + TREE_OPERAND (decl, 1)); + cp_error (" perhaps you want `typename %T::%D' to make it a type", + cname, TREE_OPERAND (decl, 1)); + return void_type_node; + } + else if (ctype == NULL_TREE) + ctype = cname; + else if (TREE_COMPLEXITY (decl) == current_class_depth) + TREE_OPERAND (decl, 0) = ctype; + else + { + if (! UNIQUELY_DERIVED_FROM_P (cname, ctype)) + { + cp_error ("type `%T' is not derived from type `%T'", + cname, ctype); + TREE_OPERAND (decl, 0) = NULL_TREE; + } + else + ctype = cname; + } + + if (ctype && TREE_CODE (TREE_OPERAND (decl, 1)) == TYPE_DECL + && ((DECL_NAME (TREE_OPERAND (decl, 1)) + == constructor_name_full (ctype)) + || (DECL_NAME (TREE_OPERAND (decl, 1)) + == constructor_name (ctype)))) + TREE_OPERAND (decl, 1) = constructor_name (ctype); + next = &TREE_OPERAND (decl, 1); + decl = *next; + if (ctype) + { + if (TREE_CODE (decl) == IDENTIFIER_NODE + && constructor_name (ctype) == decl) + { + return_type = return_ctor; + ctor_return_type = ctype; + } + else if (TREE_CODE (decl) == BIT_NOT_EXPR + && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE + && (constructor_name (ctype) == TREE_OPERAND (decl, 0) + || constructor_name_full (ctype) == TREE_OPERAND (decl, 0))) + { + return_type = return_dtor; + ctor_return_type = ctype; + flags = DTOR_FLAG; + TREE_OPERAND (decl, 0) = constructor_name (ctype); + next = &TREE_OPERAND (decl, 0); + } + } + } + break; + + case ERROR_MARK: + next = 0; + break; + + case TYPE_DECL: + /* Parse error puts this typespec where + a declarator should go. */ + cp_error ("`%T' specified as declarator-id", DECL_NAME (decl)); + if (TREE_TYPE (decl) == current_class_type) + cp_error (" perhaps you want `%T' for a constructor", + current_class_name); + dname = DECL_NAME (decl); + name = IDENTIFIER_POINTER (dname); + + /* Avoid giving two errors for this. */ + IDENTIFIER_CLASS_VALUE (dname) = NULL_TREE; + + declspecs = temp_tree_cons (NULL_TREE, integer_type_node, + declspecs); + *next = dname; + next = 0; + break; + + default: + cp_compiler_error ("`%D' as declarator", decl); + 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; + + if (((dname && IDENTIFIER_OPNAME_P (dname)) || flags == TYPENAME_FLAG) + && innermost_code != CALL_EXPR + && ! (ctype && declspecs == NULL_TREE)) + { + cp_error ("declaration of `%D' as non-function", dname); + return void_type_node; + } + + /* 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). + + We also want to avoid calling this a PARM if it is in a namespace. */ + + if (decl_context == NORMAL && ! namespace_bindings_p () + && ! pseudo_global_level_p ()) + { + struct binding_level *b = current_binding_level; + current_binding_level = b->level_chain; + if (current_binding_level != 0 && toplevel_bindings_p ()) + decl_context = PARM; + current_binding_level = b; + } + + /* 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) + { + if (id == ridpointers[(int) RID_BOOL]) + error ("`bool' is now a keyword"); + else + cp_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_LAST_MODIFIER; i++) + { + if (ridpointers[i] == id) + { + if (i == (int) RID_LONG && RIDBIT_SETP (i, specbits)) + { + if (pedantic && ! in_system_header && warn_long_long) + pedwarn ("ANSI C++ does not support `long long'"); + 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; + } + } + } + /* C++ aggregate types. */ + else if (TREE_CODE (id) == TYPE_DECL || TREE_CODE (id) == TEMPLATE_DECL) + { + if (type) + cp_error ("multiple declarations `%T' and `%T'", type, + TREE_TYPE (id)); + else + { + type = TREE_TYPE (id); + TREE_VALUE (spec) = type; + } + 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); +#if 0 + /* See the code below that used this. */ + decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id); +#endif + typedef_decl = t; + } + } + else if (id != error_mark_node) + /* Can't change CLASS nodes into RECORD nodes here! */ + type = id; + + found: ; + } + + typedef_type = type; + + /* No type at all: default to `int', and set DEFAULTED_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; + defaulted_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 = build_pointer_type (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) + && (decl_context == FIELD || decl_context == NORMAL)) + { + explicit_int = 0; + opaque_typedef = 1; + type = copy_node (opaque_type_node); + } + else + { + /* We handle `main' specially here, because 'main () { }' is so + common. With no options, it is allowed. With -Wreturn-type, + it is a warning. It is only an error with -pedantic-errors. */ + int is_main = (funcdef_flag + && MAIN_NAME_P (dname) + && ctype == NULL_TREE + && in_namespace == NULL_TREE + && current_namespace == global_namespace); + + if (in_system_header) + /* Allow it, sigh. */; + else if (pedantic || ! is_main) + cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type", + dname); + else if (warn_return_type) + cp_warning ("ANSI C++ forbids declaration `%D' with no type", + 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 = build_pointer_type (ctor_return_type); + } + else if (return_type == return_conversion) + { + if (!same_type_p (type, ctor_return_type)) + 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; + } + + 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_qualified_type (long_double_type_node, + CP_TYPE_QUALS (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) + 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 && !defaulted_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; + } + } + + if (RIDBIT_SETP (RID_COMPLEX, specbits) + && TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE) + { + error ("complex invalid for `%s'", name); + RIDBIT_RESET (RID_COMPLEX, specbits); + } + + /* Decide whether an integer type is signed or not. + Optionally treat bitfields as signed by default. */ + if (RIDBIT_SETP (RID_UNSIGNED, specbits) + || (bitfield && ! flag_signed_bitfields + && (explicit_int || defaulted_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; + + if (RIDBIT_SETP (RID_COMPLEX, specbits)) + { + /* If we just have "complex", it is equivalent to + "complex double", but if any modifiers at all are specified it is + the complex form of TYPE. E.g, "complex short" is + "complex short int". */ + + if (defaulted_int && ! longlong + && ! (RIDBIT_SETP (RID_LONG, specbits) + || RIDBIT_SETP (RID_SHORT, specbits) + || RIDBIT_SETP (RID_SIGNED, specbits) + || RIDBIT_SETP (RID_UNSIGNED, specbits))) + type = complex_double_type_node; + else if (type == integer_type_node) + type = complex_integer_type_node; + else if (type == float_type_node) + type = complex_float_type_node; + else if (type == double_type_node) + type = complex_double_type_node; + else if (type == long_double_type_node) + type = complex_long_double_type_node; + else + type = build_complex_type (type); + } + + if (return_type == return_conversion + && (RIDBIT_SETP (RID_CONST, specbits) + || RIDBIT_SETP (RID_VOLATILE, specbits) + || RIDBIT_SETP (RID_RESTRICT, specbits))) + cp_error ("qualifiers are not allowed on declaration of `operator %T'", + ctor_return_type); + + /* Set CONSTP if this declaration is `const', whether by + explicit specification or via a typedef. + Likewise for VOLATILEP. */ + + constp = !! RIDBIT_SETP (RID_CONST, specbits) + CP_TYPE_CONST_P (type); + restrictp = + !! RIDBIT_SETP (RID_RESTRICT, specbits) + CP_TYPE_RESTRICT_P (type); + volatilep = + !! RIDBIT_SETP (RID_VOLATILE, specbits) + CP_TYPE_VOLATILE_P (type); + type_quals = ((constp ? TYPE_QUAL_CONST : 0) + | (restrictp ? TYPE_QUAL_RESTRICT : 0) + | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + type = cp_build_qualified_type (type, type_quals); + staticp = 0; + inlinep = !! RIDBIT_SETP (RID_INLINE, specbits); + virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits); + RIDBIT_RESET (RID_VIRTUAL, specbits); + explicitp = RIDBIT_SETP (RID_EXPLICIT, specbits) != 0; + RIDBIT_RESET (RID_EXPLICIT, 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_FRIEND, specbits); + + /* $7.1.2, Function specifiers */ + if (friendp && explicitp) + error ("only declarations of constructors can be `explicit'"); + + if (RIDBIT_SETP (RID_MUTABLE, specbits)) + { +/* CYGNUS LOCAL Embedded C++ */ + if (flag_embedded_cxx) + pedwarn ("Embedded C++ prohibits use of mutable"); +/* END CYGNUS LOCAL Embedded C++ */ + if (decl_context == PARM) + { + error ("non-member `%s' cannot be declared `mutable'", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } + else if (friendp || decl_context == TYPENAME) + { + error ("non-object member `%s' cannot be declared `mutable'", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } + } + + /* Warn if two storage classes are given. Default to `auto'. */ + + if (RIDBIT_ANY_SET (specbits)) + { + 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 || decl_context != FIELD)) + { + 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 + && ANON_UNION_TYPE_P (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)) + { + if (type_quals != TYPE_UNQUALIFIED) + { + error ("type qualifiers specified for signature member function `%s'", name); + type_quals = TYPE_UNQUALIFIED; + } + 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 || decl_context == CATCHPARM) + && (RIDBIT_SETP (RID_REGISTER, specbits) + || RIDBIT_SETP (RID_AUTO, specbits))) + ; + else if (RIDBIT_SETP (RID_TYPEDEF, specbits)) + ; + else if (decl_context == FIELD + && ! IS_SIGNATURE (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 = NULL_TREE; + register int op = 0; + + if (declarator) + { + /* Avoid trying to get an operand off an identifier node. */ + if (TREE_CODE (declarator) == IDENTIFIER_NODE) + tmp = declarator; + else + tmp = TREE_OPERAND (declarator, 0); + 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" : "field"), + op ? operator_name_string (tmp) : name); + } + else + error (((decl_context == PARM || decl_context == CATCHPARM) + ? "storage class specified for parameter `%s'" + : "storage class specified for typename"), name); + 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 (toplevel_bindings_p ()) + { + /* It's common practice (and completely valid) to have a const + be initialized and declared extern. */ + if (!(type_quals & TYPE_QUAL_CONST)) + 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 + && ! toplevel_bindings_p ()) + error ("nested function `%s' declared `extern'", name); + else if (toplevel_bindings_p ()) + { + if (RIDBIT_SETP (RID_AUTO, specbits)) + error ("top-level declaration of `%s' specifies `auto'", name); + } + + if (nclasses > 0 && friendp) + error ("storage class specifiers invalid in friend function declarations"); + + /* 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). */ + + inner_attrs = NULL_TREE; + ignore_attrs = 0; + + while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE + && TREE_CODE (declarator) != TEMPLATE_ID_EXPR) + { + /* 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 (type == error_mark_node) + { + 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) + { + tree dummy = build_decl (TYPE_DECL, NULL_TREE, type); + ctype = grok_method_quals (ctype, dummy, quals); + type = TREE_TYPE (dummy); + quals = NULL_TREE; + } + } + + /* See the comment for the TREE_LIST case, below. */ + if (ignore_attrs) + ignore_attrs = 0; + else if (inner_attrs) + { + decl_attributes (type, inner_attrs, NULL_TREE); + inner_attrs = NULL_TREE; + } + + switch (TREE_CODE (declarator)) + { + case TREE_LIST: + { + /* We encode a declarator with embedded attributes using + a TREE_LIST. The attributes apply to the declarator + directly inside them, so we have to skip an iteration + before applying them to the type. If the declarator just + inside is the declarator-id, we apply the attrs to the + decl itself. */ + inner_attrs = TREE_PURPOSE (declarator); + ignore_attrs = 1; + declarator = TREE_VALUE (declarator); + } + break; + + case ARRAY_REF: + { + register tree itype = NULL_TREE; + register tree size = TREE_OPERAND (declarator, 1); + /* The index is a signed object `sizetype' bits wide. */ + tree index_type = signed_type (sizetype); + + declarator = TREE_OPERAND (declarator, 0); + + /* Check for some types that there cannot be arrays of. */ + + if (TREE_CODE (type) == VOID_TYPE) + { + cp_error ("declaration of `%D' as array of voids", dname); + type = error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + cp_error ("declaration of `%D' as array of functions", dname); + type = error_mark_node; + } + + /* ARM $8.4.3: Since you can't have a pointer to a reference, + you can't have arrays of references. If we allowed them, + then we'd be saying x[i] is valid for an array x, but + then you'd have to ask: what does `*(x + i)' mean? */ + if (TREE_CODE (type) == REFERENCE_TYPE) + { + if (decl_context == TYPENAME) + cp_error ("cannot make arrays of references"); + else + cp_error ("declaration of `%D' as array of references", + dname); + type = error_mark_node; + } + + if (TREE_CODE (type) == OFFSET_TYPE) + { + cp_error ("declaration of `%D' as array of data members", + dname); + type = error_mark_node; + } + + if (TREE_CODE (type) == METHOD_TYPE) + { + cp_error ("declaration of `%D' as array of function members", + dname); + type = error_mark_node; + } + + if (size == error_mark_node) + type = error_mark_node; + else if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)) + { + /* [dcl.array] + + the constant expressions that specify the bounds of + the arrays can be omitted only for the first member + of the sequence. */ + cp_error ("declaration of `%D' as multidimensional array", + dname); + cp_error ("must have bounds for all dimensions except the first"); + type = error_mark_node; + } + + 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 involves a template parameter, it will be a + constant at instantiation time, but we don't know + what the value is yet. Even if no template + parameters are involved, we may an expression that + is not a constant; we don't even simplify `1 + 2' + when processing a template. */ + if (processing_template_decl) + { + /* Resolve a qualified reference to an enumerator or + static const data member of ours. */ + if (TREE_CODE (size) == SCOPE_REF + && TREE_OPERAND (size, 0) == current_class_type) + { + tree t = lookup_field (current_class_type, + TREE_OPERAND (size, 1), 0, 0); + if (t) + size = t; + } + + itype = make_node (INTEGER_TYPE); + TYPE_MIN_VALUE (itype) = size_zero_node; + TYPE_MAX_VALUE (itype) = build_min + (MINUS_EXPR, sizetype, size, integer_one_node); + goto dont_grok_size; + } + + if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE + && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (size)) != BOOLEAN_TYPE) + { + cp_error ("size of array `%D' has non-integer type", + dname); + size = integer_one_node; + } + if (TREE_READONLY_DECL_P (size)) + size = decl_constant_value (size); + if (pedantic && integer_zerop (size)) + cp_pedwarn ("ANSI C++ forbids zero-size array `%D'", dname); + if (TREE_CONSTANT (size)) + { + int old_flag_pedantic_errors = flag_pedantic_errors; + int old_pedantic = pedantic; + pedantic = flag_pedantic_errors = 1; + /* Always give overflow errors on array subscripts. */ + constant_expression_warning (size); + pedantic = old_pedantic; + flag_pedantic_errors = old_flag_pedantic_errors; + if (INT_CST_LT (size, integer_zero_node)) + { + cp_error ("size of array `%D' is negative", dname); + size = integer_one_node; + } + } + else + { + if (pedantic) + { + if (dname) + cp_pedwarn ("ANSI C++ forbids variable-size array `%D'", + dname); + else + cp_pedwarn ("ANSI C++ forbids variable-size array"); + } + } + + itype + = fold (build_binary_op (MINUS_EXPR, + cp_convert (index_type, size), + cp_convert (index_type, + integer_one_node), 1)); + if (! TREE_CONSTANT (itype)) + itype = variable_size (itype); + else if (TREE_OVERFLOW (itype)) + { + error ("overflow in array dimension"); + TREE_OVERFLOW (itype) = 0; + } + + /* If we're a parm, we need to have a permanent type so + mangling checks for re-use will work right. If both the + element and index types are permanent, the array type + will be, too. */ + if (decl_context == PARM + && allocation_temporary_p () && TREE_PERMANENT (type)) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + itype = build_index_type (itype); + pop_obstacks (); + } + else + itype = build_index_type (itype); + + dont_grok_size: + resume_momentary (yes); + } + + type = build_cplus_array_type (type, itype); + ctype = NULL_TREE; + } + break; + + case CALL_EXPR: + { + tree arg_types; + int funcdecl_p; + tree inner_parms = TREE_OPERAND (declarator, 1); + tree inner_decl = TREE_OPERAND (declarator, 0); + + /* Declaring a function type. + Make sure we have a valid type for the function to return. */ + + /* We now know that the TYPE_QUALS don't apply to the + decl, but to its return type. */ + type_quals = TYPE_UNQUALIFIED; + + /* 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 (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF) + inner_decl = TREE_OPERAND (inner_decl, 1); + + if (inner_decl && TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR) + inner_decl = dname; + + /* Pick up type qualifiers which should be applied to `this'. */ + quals = TREE_OPERAND (declarator, 2); + + /* Pick up the exception specifications. */ + raises = TREE_TYPE (declarator); + + /* Say it's a definition only for the CALL_EXPR + closest to the identifier. */ + funcdecl_p + = inner_decl + && (TREE_CODE (inner_decl) == IDENTIFIER_NODE + || TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR + || TREE_CODE (inner_decl) == BIT_NOT_EXPR); + + if (ctype == NULL_TREE + && decl_context == FIELD + && funcdecl_p + && (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 (quals) + { + cp_error ("destructors may not be `%s'", + IDENTIFIER_POINTER (TREE_VALUE (quals))); + quals = NULL_TREE; + } + 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. */ + { + if (explicitp == 1) + explicitp = 2; + /* 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 (quals) + { + cp_error ("constructors may not be `%s'", + IDENTIFIER_POINTER (TREE_VALUE (quals))); + quals = NULL_TREE; + } + { + 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 = build_pointer_type (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) + { + if (initialized) + error ("can't initialize friend function `%s'", name); + if (virtualp) + { + /* Cannot be both friend and virtual. */ + error ("virtual functions cannot be friends"); + RIDBIT_RESET (RID_FRIEND, specbits); + friendp = 0; + } + if (decl_context == NORMAL) + error ("friend declaration not in class definition"); + if (current_function_decl && funcdef_flag) + cp_error ("can't define friend function `%s' in a local class definition", + name); + } + + /* Construct the function type and go to the next + inner layer of declarator. */ + + declarator = TREE_OPERAND (declarator, 0); + + /* FIXME: This is where default args should be fully + processed. */ + + arg_types = grokparms (inner_parms, funcdecl_p ? funcdef_flag : 0); + + if (declarator && flags == DTOR_FLAG) + { + /* A destructor declared in the body of a class will + be represented as a BIT_NOT_EXPR. But, we just + want the underlying IDENTIFIER. */ + 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) + { + cp_error ("destructors may not have parameters"); + arg_types = void_list_node; + last_function_parms = NULL_TREE; + } + } + + /* ANSI says that `const int foo ();' + does not make the function foo const. */ + type = build_function_type (type, arg_types); + + { + tree t; + for (t = arg_types; t; t = TREE_CHAIN (t)) + if (TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG) + { + add_defarg_fn (type); + break; + } + } + } + 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; + } + + if (TREE_CODE (type) == OFFSET_TYPE + && (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE + || TREE_CODE (TREE_TYPE (type)) == REFERENCE_TYPE)) + { + cp_error ("cannot declare pointer to `%#T' member", + TREE_TYPE (type)); + type = TREE_TYPE (type); + } + + /* Merge any constancy or volatility into the target type + for the pointer. */ + + /* We now know that the TYPE_QUALS don't apply to the decl, + but to the target of the pointer. */ + type_quals = TYPE_UNQUALIFIED; + + 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); +#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); + } + } + else if (TREE_CODE (declarator) == ADDR_EXPR) + { + if (TREE_CODE (type) == VOID_TYPE) + 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; + + constp = 0; + volatilep = 0; + restrictp = 0; + for (typemodlist = TREE_TYPE (declarator); typemodlist; + typemodlist = TREE_CHAIN (typemodlist)) + { + tree qualifier = TREE_VALUE (typemodlist); + + if (qualifier == ridpointers[(int) RID_CONST]) + constp++; + else if (qualifier == ridpointers[(int) RID_VOLATILE]) + volatilep++; + else if (qualifier == ridpointers[(int) RID_RESTRICT]) + restrictp++; + else if (!erred) + { + erred = 1; + error ("invalid type modifier within pointer declarator"); + } + } + if (constp > 1) + pedwarn ("duplicate `const'"); + if (volatilep > 1) + pedwarn ("duplicate `volatile'"); + if (restrictp > 1) + pedwarn ("duplicate `restrict'"); + + type_quals = ((constp ? TYPE_QUAL_CONST : 0) + | (restrictp ? TYPE_QUAL_RESTRICT : 0) + | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + if (TREE_CODE (declarator) == ADDR_EXPR + && (constp || volatilep)) + { + if (constp) + pedwarn ("discarding `const' applied to a reference"); + if (volatilep) + pedwarn ("discarding `volatile' applied to a reference"); + type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); + } + type = cp_build_qualified_type (type, type_quals); + } + 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); + tree t; + + /* 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 (TREE_COMPLEXITY (declarator) == -1) + /* Namespace member. */ + pop_decl_namespace (); + else if (friendp && (TREE_COMPLEXITY (declarator) < 2)) + /* Don't fall out into global scope. Hides real bug? --eichin */ ; + else if (! IS_AGGR_TYPE_CODE + (TREE_CODE (TREE_OPERAND (declarator, 0)))) + ; + else if (TREE_COMPLEXITY (declarator) == current_class_depth) + { + /* Resolve any TYPENAME_TYPEs from the decl-specifier-seq + that refer to ctype. They couldn't be resolved earlier + because we hadn't pushed into the class yet. + Example: resolve 'B<T>::type' in + 'B<typename B<T>::type> B<T>::f () { }'. */ + if (current_template_parms + && uses_template_parms (type) + && uses_template_parms (current_class_type)) + { + tree args = current_template_args (); + type = tsubst (type, args, NULL_TREE); + } + + /* 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); + + t = ctype; + while (t != NULL_TREE && CLASS_TYPE_P (t)) + { + if (CLASSTYPE_TEMPLATE_INFO (t) && + !CLASSTYPE_TEMPLATE_SPECIALIZATION (t)) + template_count += 1; + t = TYPE_MAIN_DECL (t); + if (DECL_LANG_SPECIFIC (t)) + t = DECL_CLASS_CONTEXT (t); + else + t = NULL_TREE; + } + + 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 (ctype == current_class_type) + { + /* class A { + void A::f (); + }; + + Is this ill-formed? */ + + if (pedantic) + cp_pedwarn ("extra qualification `%T::' on member `%s' ignored", + ctype, name); + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (current_class_type == NULL_TREE + || friendp) + type = build_cplus_method_type (ctype, 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 (RIDBIT_SETP (RID_TYPEDEF, specbits) + || TYPE_SIZE (complete_type (ctype)) != NULL_TREE) + { + /* Have to move this code elsewhere in this function. + this code is used for i.e., typedef int A::M; M *pm; + + It is? How? jason 10/2/94 */ + + if (current_class_type) + { + cp_error ("cannot declare member `%T::%s' within `%T'", + ctype, name, current_class_type); + return void_type_node; + } + type = build_offset_type (ctype, type); + } + else if (uses_template_parms (ctype)) + { + if (TREE_CODE (type) == FUNCTION_TYPE) + type + = build_cplus_method_type (ctype, TREE_TYPE (type), + TYPE_ARG_TYPES (type)); + } + 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 (ctype, 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); + } + } + + /* See the comment for the TREE_LIST case, above. */ + if (inner_attrs) + { + if (! ignore_attrs) + decl_attributes (type, inner_attrs, NULL_TREE); + else if (attrlist) + TREE_VALUE (attrlist) = chainon (inner_attrs, TREE_VALUE (attrlist)); + else + attrlist = build_decl_list (NULL_TREE, inner_attrs); + } + + if (explicitp == 1) + { + error ("only constructors can be declared `explicit'"); + explicitp = 0; + } + + /* Now TYPE has the actual type. */ + + /* If this is declaring a typedef name, return a TYPE_DECL. */ + + if (RIDBIT_SETP (RID_MUTABLE, specbits)) + { + if (type_quals & TYPE_QUAL_CONST) + { + error ("const `%s' cannot be declared `mutable'", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } + else if (staticp) + { + error ("static `%s' cannot be declared `mutable'", name); + RIDBIT_RESET (RID_MUTABLE, specbits); + } + } + + if (RIDBIT_SETP (RID_TYPEDEF, specbits) && decl_context != TYPENAME) + { + tree decl; + + /* Note that the grammar rejects storage classes + in typenames, fields or parameters. */ + if (current_lang_name == lang_name_java) + TYPE_FOR_JAVA (type) = 1; + + if (decl_context == FIELD) + { + if (declarator == constructor_name (current_class_type)) + cp_pedwarn ("ANSI C++ forbids nested type `%D' with same name as enclosing class", + declarator); + decl = build_lang_decl (TYPE_DECL, declarator, type); + if (IS_SIGNATURE (current_class_type) && opaque_typedef) + SIGNATURE_HAS_OPAQUE_TYPEDECLS (current_class_type) = 1; + } + else + { + /* Make sure this typedef lives as long as its type, + since it might be used as a template parameter. */ + if (type != error_mark_node) + push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type)); + decl = build_decl (TYPE_DECL, declarator, type); + if (type != error_mark_node) + pop_obstacks (); + } + + /* 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))) + { + /* FIXME: This is bogus; we should not be doing this for + cv-qualified types. */ + + /* For anonymous structs that are cv-qualified, need to use + TYPE_MAIN_VARIANT so that name will mangle correctly. As + type not referenced after this block, don't bother + resetting type to original type, ie. TREE_TYPE (decl). */ + type = TYPE_MAIN_VARIANT (type); + + /* Replace the anonymous name with the real name everywhere. */ + lookup_tag_reverse (type, declarator); + TYPE_NAME (type) = decl; + + if (TYPE_LANG_SPECIFIC (type)) + TYPE_WAS_ANONYMOUS (type) = 1; + + /* If this is a typedef within a template class, the nested + type is a (non-primary) template. The name for the + template needs updating as well. */ + if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_TEMPLATE_INFO (type)) + DECL_NAME (CLASSTYPE_TI_TEMPLATE (type)) + = TYPE_IDENTIFIER (type); + + /* XXX Temporarily set the scope. + When returning, start_decl expects it as NULL_TREE, + and will then then set it using pushdecl. */ + my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 980404); + if (current_class_type) + DECL_CONTEXT (decl) = current_class_type; + else + DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); + + DECL_ASSEMBLER_NAME (decl) = DECL_NAME (decl); + DECL_ASSEMBLER_NAME (decl) + = get_identifier (build_overload_name (type, 1, 1)); + DECL_CONTEXT (decl) = NULL_TREE; + + /* FIXME remangle member functions; member functions of a + type with external linkage have external linkage. */ + } + + 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); + + bad_specifiers (decl, "type", virtualp, quals != NULL_TREE, + inlinep, friendp, raises != NULL_TREE); + + if (initialized) + error ("typedef declaration includes an initializer"); + + 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 (type_quals != TYPE_UNQUALIFIED) + { + if (IS_SIGNATURE (type)) + error ("type qualifiers specified for signature type"); + type_quals = TYPE_UNQUALIFIED; + } + + /* Special case: "friend class foo" looks like a TYPENAME context. */ + if (friendp) + { + if (type_quals != TYPE_UNQUALIFIED) + { + cp_error ("type qualifiers specified for friend class declaration"); + type_quals = TYPE_UNQUALIFIED; + } + if (inlinep) + { + cp_error ("`inline' specified for friend class declaration"); + inlinep = 0; + } + + /* Only try to do this stuff if we didn't already give up. */ + if (type != integer_type_node) + { + /* 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) + { + tree dummy = build_decl (TYPE_DECL, declarator, type); + 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 + && decl_context != CATCHPARM + && 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 (TREE_CODE (type) == VOID_TYPE && decl_context != PARM) + { + if (! declarator) + error ("unnamed variable or field declared void"); + else if (TREE_CODE (declarator) == IDENTIFIER_NODE) + { + if (IDENTIFIER_OPNAME_P (declarator)) + my_friendly_abort (356); + 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. */ + + if (decl_context == PARM || decl_context == CATCHPARM) + { + if (ctype || in_namespace) + 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 (TREE_TYPE (type)); + type_quals = TYPE_UNQUALIFIED; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + type = build_pointer_type (type); + else if (TREE_CODE (type) == OFFSET_TYPE) + type = build_pointer_type (type); + else if (TREE_CODE (type) == VOID_TYPE && declarator) + { + error ("declaration of `%s' as void", name); + return NULL_TREE; + } + } + + { + register tree decl; + + if (decl_context == PARM) + { + 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 (in_namespace && !friendp) + { + /* Something like struct S { int N::j; }; */ + cp_error ("invalid use of `::'"); + decl = NULL_TREE; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + int publicp = 0; + tree function_context; + + /* We catch the others as conflicts with the builtin + typedefs. */ + if (friendp && declarator == ridpointers[(int) RID_SIGNED]) + { + cp_error ("function `%D' cannot be declared friend", + declarator); + friendp = 0; + } + + if (friendp == 0) + { + if (ctype == NULL_TREE) + 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 (ctype, TREE_TYPE (type), + TYPE_ARG_TYPES (type)); + } + + /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */ + function_context = (ctype != NULL_TREE) ? + hack_decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE; + publicp = (! friendp || ! staticp) + && function_context == NULL_TREE; + decl = grokfndecl (ctype, type, + TREE_CODE (declarator) != TEMPLATE_ID_EXPR + ? declarator : dname, + declarator, + virtualp, flags, quals, raises, attrlist, + friendp ? -1 : 0, friendp, publicp, inlinep, + funcdef_flag, template_count, in_namespace); + if (decl == NULL_TREE || decl == error_mark_node) + return decl; +#if 0 + /* This clobbers the attrs stored in `decl' from `attrlist'. */ + /* The decl and setting of decl_machine_attr is also turned off. */ + decl = build_decl_attribute_variant (decl, decl_machine_attr); +#endif + + /* [class.conv.ctor] + + A constructor declared without the function-specifier + explicit that can be called with a single parameter + specifies a conversion from the type of its first + parameter to the type of its class. Such a constructor + is called a converting constructor. */ + if (explicitp == 2) + DECL_NONCONVERTING_P (decl) = 1; + else if (DECL_CONSTRUCTOR_P (decl)) + { + /* The constructor can be called with exactly one + parameter if there is at least one parameter, and + any subsequent parameters have default arguments. + We don't look at the first parameter, which is + really just the `this' parameter for the new + object. */ + tree arg_types = + TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl))); + + /* Skip the `in_chrg' argument too, if present. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (decl))) + arg_types = TREE_CHAIN (arg_types); + + if (arg_types == void_list_node + || (arg_types + && TREE_CHAIN (arg_types) + && TREE_CHAIN (arg_types) != void_list_node + && !TREE_PURPOSE (TREE_CHAIN (arg_types)))) + DECL_NONCONVERTING_P (decl) = 1; + } + } + else if (TREE_CODE (type) == METHOD_TYPE) + { + /* We only get here for friend declarations of + members of other classes. */ + /* All method decls are public, so tell grokfndecl to set + TREE_PUBLIC, also. */ + decl = grokfndecl (ctype, type, declarator, declarator, + virtualp, flags, quals, raises, attrlist, + friendp ? -1 : 0, friendp, 1, 0, funcdef_flag, + template_count, in_namespace); + if (decl == NULL_TREE) + return NULL_TREE; + } + else if (!staticp && ! processing_template_decl + && TYPE_SIZE (complete_type (type)) == NULL_TREE + && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0)) + { + if (declarator) + cp_error ("field `%D' has incomplete type", declarator); + else + cp_error ("name `%T' has incomplete type", type); + + /* 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 (TYPE_IDENTIFIER (current_class_type)) + && declspecs && TREE_VALUE (declspecs) + && TREE_TYPE (TREE_VALUE (declspecs)) == type) + cp_error (" in instantiation of template `%T'", + 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)) + { + if (template_class_depth (current_class_type) == 0) + { + decl + = check_explicit_specialization + (declarator, decl, + template_count, 2 * (funcdef_flag != 0) + 4); + if (decl == error_mark_node) + return error_mark_node; + } + + t = do_friend (ctype, declarator, decl, + last_function_parms, flags, quals, + funcdef_flag); + } + 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) + { + if (!staticp) + { + /* An attempt is being made to initialize a non-static + member. But, from [class.mem]: + + 4 A member-declarator can contain a + constant-initializer only if it declares a static + member (_class.static_) of integral or enumeration + type, see _class.static.data_. + + This used to be relatively common practice, but + the rest of the compiler does not correctly + handle the initialization unless the member is + static so we make it static below. */ + cp_pedwarn ("ANSI C++ forbids initialization of member `%D'", + declarator); + cp_pedwarn ("making `%D' static", declarator); + staticp = 1; + } + + if (uses_template_parms (type)) + /* We'll check at instantiation time. */ + ; + else if (check_static_variable_definition (declarator, + type)) + /* If we just return the declaration, crashes + will sometimes occur. We therefore return + void_type_node, as if this was a friend + declaration, to cause callers to completely + ignore this declaration. */ + return void_type_node; + } + + /* 9.2p13 [class.mem] */ + if (declarator == constructor_name (current_class_type) + /* Divergence from the standard: In extern "C", we + allow non-static data members here, because C does + and /usr/include/netinet/in.h uses that. */ + && (staticp || ! in_system_header)) + cp_pedwarn ("ANSI C++ forbids data member `%D' with same name as enclosing class", + declarator); + + if (staticp) + { + /* C++ allows static class members. + All other work for this is done by grokfield. + This VAR_DCL 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) = 1; + } + 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; + int publicp = 0; + + if (! declarator) + return NULL_TREE; + + if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) + original_name = dname; + else + original_name = declarator; + + 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 (! toplevel_bindings_p () + && (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; + } + } + else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2) + type = build_cplus_method_type (ctype, TREE_TYPE (type), + TYPE_ARG_TYPES (type)); + + /* Record presence of `static'. */ + publicp = (ctype != NULL_TREE + || RIDBIT_SETP (RID_EXTERN, specbits) + || !RIDBIT_SETP (RID_STATIC, specbits)); + + decl = grokfndecl (ctype, type, original_name, declarator, + virtualp, flags, quals, raises, attrlist, + 1, friendp, + publicp, inlinep, funcdef_flag, + template_count, in_namespace); + if (decl == NULL_TREE) + return NULL_TREE; + + /* Among other times, could occur from check_explicit_specialization + returning an error_mark_node. */ + if (decl == error_mark_node) + return error_mark_node; + + 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_pedwarn ("cannot declare member function `%D' to have static linkage", decl); + 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); + } + } + } + else + { + /* It's a variable. */ + + /* An uninitialized decl with `extern' is a reference. */ + decl = grokvardecl (type, declarator, &specbits, + initialized, + (type_quals & TYPE_QUAL_CONST) != 0, + in_namespace); + bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE, + inlinep, friendp, raises != NULL_TREE); + + if (ctype) + { + DECL_CONTEXT (decl) = ctype; + if (staticp == 1) + { + cp_pedwarn ("static member `%D' re-declared as static", decl); + staticp = 0; + RIDBIT_RESET (RID_STATIC, specbits); + } + if (RIDBIT_SETP (RID_REGISTER, specbits) && TREE_STATIC (decl)) + { + cp_error ("static member `%D' declared `register'", decl); + RIDBIT_RESET (RID_REGISTER, specbits); + } + if (RIDBIT_SETP (RID_EXTERN, specbits) && pedantic) + { + cp_pedwarn ("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; + + if (RIDBIT_SETP (RID_STATIC, specbits)) + DECL_THIS_STATIC (decl) = 1; + + /* Record constancy and volatility. */ + /* FIXME: Disallow `restrict' pointer-to-member declarations. */ + c_apply_type_quals_to_decl (type_quals, decl); + + 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 (toplevel_bindings_p ()) + { + /* 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 start_function. Ensure that each of the parameter + types (as listed in PARMS) is complete, as is required for a + function definition. */ + +static void +require_complete_types_for_parms (parms) + tree parms; +{ + while (parms) + { + tree type = TREE_TYPE (parms); + if (TYPE_SIZE (complete_type (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; + } + else + layout_decl (parms, 0); + + parms = TREE_CHAIN (parms); + } +} + +/* Returns DECL if DECL is a local variable (or parameter). Returns + NULL_TREE otherwise. */ + +static tree +local_variable_p (t) + tree t; +{ + if ((TREE_CODE (t) == VAR_DECL + /* A VAR_DECL with a context that is a _TYPE is a static data + member. */ + && !TYPE_P (CP_DECL_CONTEXT (t)) + /* Any other non-local variable must be at namespace scope. */ + && TREE_CODE (CP_DECL_CONTEXT (t)) != NAMESPACE_DECL) + || (TREE_CODE (t) == PARM_DECL)) + return t; + + return NULL_TREE; +} + +/* Check that ARG, which is a default-argument expression for a + parameter DECL, is legal. Returns ARG, or ERROR_MARK_NODE, if + something goes wrong. DECL may also be a _TYPE node, rather than a + DECL, if there is no DECL available. */ + +tree +check_default_argument (decl, arg) + tree decl; + tree arg; +{ + tree var; + tree decl_type; + + if (TREE_CODE (arg) == DEFAULT_ARG) + /* We get a DEFAULT_ARG when looking at an in-class declaration + with a default argument. Ignore the argument for now; we'll + deal with it after the class is complete. */ + return arg; + + if (processing_template_decl || uses_template_parms (arg)) + /* We don't do anything checking until instantiation-time. Note + that there may be uninstantiated arguments even for an + instantiated function, since default arguments are not + instantiated until they are needed. */ + return arg; + + if (TYPE_P (decl)) + { + decl_type = decl; + decl = NULL_TREE; + } + else + decl_type = TREE_TYPE (decl); + + if (arg == error_mark_node + || decl == error_mark_node + || TREE_TYPE (arg) == error_mark_node + || decl_type == error_mark_node) + /* Something already went wrong. There's no need to check + further. */ + return error_mark_node; + + /* [dcl.fct.default] + + A default argument expression is implicitly converted to the + parameter type. */ + if (!TREE_TYPE (arg) + || !can_convert_arg (decl_type, TREE_TYPE (arg), arg)) + { + if (decl) + cp_error ("default argument for `%#D' has type `%T'", + decl, TREE_TYPE (arg)); + else + cp_error ("default argument for paramter of type `%T' has type `%T'", + decl_type, TREE_TYPE (arg)); + + return error_mark_node; + } + + /* [dcl.fct.default] + + Local variables shall not be used in default argument + expressions. + + The keyword `this' shall not be used in a default argument of a + member function. */ + var = search_tree (arg, local_variable_p); + if (var) + { + cp_error ("default argument `%E' uses local variable `%D'", + arg, var); + return error_mark_node; + } + + /* All is well. */ + return arg; +} + +/* 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_CODE (TREE_VALUE (first_parm)) != VOID_TYPE) + 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; + + 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 = NULL_TREE, list_node = parm; + register tree decl = TREE_VALUE (parm); + tree init = TREE_PURPOSE (parm); + + chain = TREE_CHAIN (parm); + /* @@ weak defense against parse errors. */ + if (TREE_CODE (decl) != VOID_TYPE + && TREE_CODE (decl) != TREE_LIST) + { + /* Give various messages as the need arises. */ + if (TREE_CODE (decl) == STRING_CST) + cp_error ("invalid string constant `%E'", decl); + else if (TREE_CODE (decl) == INTEGER_CST) + error ("invalid integer constant in parameter list, did you forget to give parameter name?"); + continue; + } + + if (TREE_CODE (decl) != VOID_TYPE) + { + decl = grokdeclarator (TREE_VALUE (decl), + TREE_PURPOSE (decl), + PARM, init != NULL_TREE, + NULL_TREE); + if (! decl || TREE_TYPE (decl) == error_mark_node) + continue; + + /* Top-level qualifiers on the parameters are + ignored for function types. */ + type = TYPE_MAIN_VARIANT (TREE_TYPE (decl)); + + if (TREE_CODE (type) == VOID_TYPE) + decl = void_type_node; + else if (TREE_CODE (type) == METHOD_TYPE) + { + if (DECL_NAME (decl)) + /* Cannot use the decl here because + we don't have DECL_CONTEXT set up yet. */ + cp_error ("parameter `%D' invalidly declared method type", + 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)) + cp_error ("parameter `%D' invalidly declared offset type", + 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. */ + } + else if (POINTER_TYPE_P (type)) + { + tree t = type; + while (POINTER_TYPE_P (t) + || (TREE_CODE (t) == ARRAY_TYPE + && TYPE_DOMAIN (t) != NULL_TREE)) + t = TREE_TYPE (t); + if (TREE_CODE (t) == ARRAY_TYPE) + cp_error ("parameter type `%T' includes %s to array of unknown bound", + type, + TYPE_PTR_P (type) ? "pointer" : "reference"); + } + } + + if (TREE_CODE (decl) == VOID_TYPE) + { + if (result == NULL_TREE) + { + result = void_list_node; + last_result = result; + } + else + { + TREE_CHAIN (last_result) = void_list_node; + last_result = void_list_node; + } + 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 && init) + { + any_init++; + init = check_default_argument (decl, init); + } + else + init = NULL_TREE; + + if (decls == NULL_TREE) + { + decls = decl; + last_decl = decls; + } + else + { + TREE_CHAIN (last_decl) = decl; + last_decl = decl; + } + if (! current_function_decl && TREE_PERMANENT (list_node)) + { + TREE_PURPOSE (list_node) = init; + TREE_VALUE (list_node) = type; + TREE_CHAIN (list_node) = NULL_TREE; + } + else + list_node = saveable_tree_cons (init, type, NULL_TREE); + 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; + + return result; +} + +/* Called from the parser to update an element of TYPE_ARG_TYPES for some + FUNCTION_TYPE with the newly parsed version of its default argument, which + was previously digested as text. See snarf_defarg et al in lex.c. */ + +void +replace_defarg (arg, init) + tree arg, init; +{ + if (! processing_template_decl + && ! can_convert_arg (TREE_VALUE (arg), TREE_TYPE (init), init)) + cp_pedwarn ("invalid type `%T' for default argument to `%T'", + TREE_TYPE (init), TREE_VALUE (arg)); + TREE_PURPOSE (arg) = init; +} + +int +copy_args_p (d) + tree d; +{ + tree t = FUNCTION_ARG_CHAIN (d); + if (DECL_CONSTRUCTOR_P (d) + && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (d))) + t = TREE_CHAIN (t); + if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE + && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t))) + == DECL_CLASS_CONTEXT (d)) + && (TREE_CHAIN (t) == NULL_TREE + || TREE_CHAIN (t) == void_list_node + || TREE_PURPOSE (TREE_CHAIN (t)))) + return 1; + return 0; +} + +/* 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 (TYPE_USES_VIRTUAL_BASECLASSES (ctype)) + { + my_friendly_assert (parmtypes + && TREE_VALUE (parmtypes) == integer_type_node, + 980529); + parmtypes = TREE_CHAIN (parmtypes); + parmtype = TREE_VALUE (parmtypes); + } + + /* [class.copy] + + A non-template constructor for class X is a copy constructor if + its first parameter is of type X&, const X&, volatile X& or const + volatile X&, and either there are no other parameters or else all + other parameters have default arguments. */ + if (TREE_CODE (parmtype) == REFERENCE_TYPE + && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype + && (TREE_CHAIN (parmtypes) == NULL_TREE + || TREE_CHAIN (parmtypes) == void_list_node + || TREE_PURPOSE (TREE_CHAIN (parmtypes))) + && !(DECL_TEMPLATE_INSTANTIATION (decl) + && is_member_template (DECL_TI_TEMPLATE (decl)))) + { + TYPE_HAS_INIT_REF (ctype) = 1; + if (CP_TYPE_CONST_P (TREE_TYPE (parmtype))) + TYPE_HAS_CONST_INIT_REF (ctype) = 1; + } + /* [class.copy] + + A declaration of a constructor for a class X is ill-formed if its + first parameter is of type (optionally cv-qualified) X and either + there are no other parameters or else all other parameters have + default arguments. + + We *don't* complain about member template instantiations that + have this form, though; they can occur as we try to decide what + constructor to use during overload resolution. Since overload + resolution will never prefer such a constructor to the + non-template copy constructor (which is either explicitly or + implicitly defined), there's no need to worry about their + existence. Theoretically, they should never even be + instantiated, but that's hard to forestall. */ + else if (TYPE_MAIN_VARIANT (parmtype) == ctype + && (TREE_CHAIN (parmtypes) == NULL_TREE + || TREE_CHAIN (parmtypes) == void_list_node + || TREE_PURPOSE (TREE_CHAIN (parmtypes))) + && !(DECL_TEMPLATE_INSTANTIATION (decl) + && is_member_template (DECL_TI_TEMPLATE (decl)))) + { + cp_error ("invalid constructor; you probably meant `%T (const %T&)'", + ctype, ctype); + SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype); + return 0; + } + 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] + || IDENTIFIER_TYPENAME_P (name)); +} + +/* Do a little sanity-checking on how they declared their operator. */ + +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) + { + /* [class.copy] + + A user-declared copy assignment operator X::operator= is a + non-static non-template member function of class X with + exactly one parameter of type X, X&, const X&, volatile X& or + const volatile X&. */ + if (name == ansi_opname[(int) MODIFY_EXPR] + && !(DECL_TEMPLATE_INSTANTIATION (decl) + && is_member_template (DECL_TI_TEMPLATE (decl)))) + 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 (IDENTIFIER_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_CODE (TREE_VALUE (p)) != VOID_TYPE ; 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 + || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM) + goto foundaggr; + } + cp_error + ("`%D' must have an argument of class or enumerated type", + decl); + foundaggr: + ; + } + } + + if (name == ansi_opname[(int) CALL_EXPR]) + return; /* No restrictions on args. */ + + if (IDENTIFIER_TYPENAME_P (name) && ! DECL_TEMPLATE_INFO (decl)) + { + 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"; + /* Don't force t to be complete here. */ + else if (IS_AGGR_TYPE (t) + && TYPE_SIZE (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 + || CP_TYPE_CONST_P (TREE_TYPE (parmtype))) + TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1; + } + } + 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]) + && ! processing_template_decl + && ! same_type_p (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); + } + + /* More Effective C++ rule 6. */ + if (warn_ecpp + && (name == ansi_opname[(int) POSTINCREMENT_EXPR] + || name == ansi_opname[(int) POSTDECREMENT_EXPR])) + { + tree arg = TREE_VALUE (argtypes); + tree ret = TREE_TYPE (TREE_TYPE (decl)); + if (methodp || TREE_CODE (arg) == REFERENCE_TYPE) + arg = TREE_TYPE (arg); + arg = TYPE_MAIN_VARIANT (arg); + if (list_length (argtypes) == 2) + { + if (TREE_CODE (ret) != REFERENCE_TYPE + || !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (ret)), + arg)) + cp_warning ("prefix `%D' should return `%T'", decl, + build_reference_type (arg)); + } + else + { + if (!same_type_p (TYPE_MAIN_VARIANT (ret), arg)) + cp_warning ("postfix `%D' should return `%T'", decl, arg); + } + } + } + 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); + } + + /* More Effective C++ rule 7. */ + if (warn_ecpp + && (name == ansi_opname [TRUTH_ANDIF_EXPR] + || name == ansi_opname [TRUTH_ORIF_EXPR] + || name == ansi_opname [COMPOUND_EXPR])) + cp_warning ("user-defined `%D' always evaluates both arguments", + decl); + } + + /* Effective C++ rule 23. */ + if (warn_ecpp + && list_length (argtypes) == 3 + && (name == ansi_opname [PLUS_EXPR] + || name == ansi_opname [MINUS_EXPR] + || name == ansi_opname [TRUNC_DIV_EXPR] + || name == ansi_opname [MULT_EXPR]) + && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE) + cp_warning ("`%D' should return by value", 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); + } + } +} + +static char * +tag_name (code) + enum tag_types code; +{ + switch (code) + { + case record_type: + return "struct"; + case class_type: + return "class"; + case union_type: + return "union "; + case enum_type: + return "enum"; + case signature_type: + return "signature"; + default: + my_friendly_abort (981122); + } +} + +/* 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.) */ + +tree +xref_tag (code_type_node, name, globalize) + tree code_type_node; + tree name; + int globalize; +{ + enum tag_types tag_code; + enum tree_code code; + int temp = 0; + register tree ref, t; + struct binding_level *b = inner_binding_level; + int got_type = 0; + tree attributes = NULL_TREE; + + /* If we are called from the parser, code_type_node will sometimes be a + TREE_LIST. This indicates that the user wrote + "class __attribute__ ((foo)) bar". Extract the attributes so we can + use them later. */ + if (TREE_CODE (code_type_node) == TREE_LIST) + { + attributes = TREE_PURPOSE (code_type_node); + code_type_node = TREE_VALUE (code_type_node); + } + + tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node); + switch (tag_code) + { + case record_type: + case class_type: + case signature_type: + code = RECORD_TYPE; + break; + case union_type: + code = UNION_TYPE; + break; + case enum_type: + code = ENUMERAL_TYPE; + break; + default: + my_friendly_abort (18); + } + + /* If a cross reference is requested, look up the type + already defined for this tag and return it. */ + if (TREE_CODE_CLASS (TREE_CODE (name)) == 't') + { + t = name; + name = TYPE_IDENTIFIER (t); + got_type = 1; + } + else + t = IDENTIFIER_TYPE_VALUE (name); + + if (t && TREE_CODE (t) != code && TREE_CODE (t) != TEMPLATE_TYPE_PARM + && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM) + t = NULL_TREE; + + if (! globalize) + { + /* 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. */ + ref = lookup_tag (code, name, b, 1); + } + else + { + if (current_class_type + && template_class_depth (current_class_type) + && PROCESSING_REAL_TEMPLATE_DECL_P ()) + /* Since GLOBALIZE is non-zero, we are not looking at a + definition of this tag. Since, in addition, we are currently + processing a (member) template declaration of a template + class, we don't want to do any lookup at all; consider: + + template <class X> + struct S1 + + template <class U> + struct S2 + { template <class V> + friend struct S1; }; + + Here, the S2::S1 declaration should not be confused with the + outer declaration. In particular, the inner version should + have a template parameter of level 2, not level 1. This + would be particularly important if the member declaration + were instead: + + template <class V = U> friend struct S1; + + say, when we should tsubst into `U' when instantiating S2. */ + ref = NULL_TREE; + else + { + if (t) + { + if (t != TYPE_MAIN_VARIANT (t)) + cp_pedwarn ("using typedef-name `%D' after `%s'", + TYPE_NAME (t), tag_name (tag_code)); + 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 != NULL_TREE + && processing_template_decl + && DECL_CLASS_TEMPLATE_P (ref) + && template_class_depth (current_class_type) == 0) + /* Since GLOBALIZE is true, we're declaring a global + template, so we want this type. */ + ref = DECL_RESULT (ref); + + 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) + { + cp_error ("use of enum `%#D' without previous declaration", name); + + 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); + } + else + { + struct binding_level *old_b = class_binding_level; + + ref = make_lang_type (code); + + if (tag_code == signature_type) + { + SET_SIGNATURE (ref); + /* Since a signature type will be turned into the type + of signature tables, it's not only an interface. */ + CLASSTYPE_INTERFACE_ONLY (ref) = 0; + SET_CLASSTYPE_INTERFACE_KNOWN (ref); + /* A signature doesn't have a vtable. */ + CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = 0; + } + +#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; + } + } + else + { + /* If it no longer looks like a nested type, make sure it's + in global scope. + If it is not an IDENTIFIER, this is not a declaration */ + if (b->namespace_p && !class_binding_level + && TREE_CODE (name) == IDENTIFIER_NODE) + { + if (IDENTIFIER_NAMESPACE_VALUE (name) == NULL_TREE) + SET_IDENTIFIER_NAMESPACE_VALUE (name, TYPE_NAME (ref)); + } + + if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref)) + redeclare_class_template (ref, current_template_parms); + } + + /* 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 (); + + TREE_TYPE (ref) = attributes; + + if (ref && TYPE_P (ref)) + { + /* [dcl.type.elab] + + If the identifier resolves to a typedef-name or a template + type-parameter, the elaborated-type-specifier is + ill-formed. */ + if (TYPE_LANG_SPECIFIC (ref) && TYPE_WAS_ANONYMOUS (ref)) + cp_error ("`%T' is a typedef name", ref); + else if (TREE_CODE (ref) == TEMPLATE_TYPE_PARM) + cp_error ("`%T' is a template type paramter", ref); + } + + return ref; +} + +tree +xref_tag_from_type (old, id, globalize) + tree old, id; + int globalize; +{ + tree code_type_node; + + if (TREE_CODE (old) == RECORD_TYPE) + code_type_node = (CLASSTYPE_DECLARED_CLASS (old) + ? class_type_node : record_type_node); + else + code_type_node = union_type_node; + + if (id == NULL_TREE) + id = TYPE_IDENTIFIER (old); + + return xref_tag (code_type_node, id, globalize); +} + +void +xref_basetypes (code_type_node, name, ref, binfo) + tree code_type_node; + tree name, ref; + tree 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; + int i, len; + enum tag_types tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node); + + if (tag_code == union_type) + { + cp_error ("derived union `%T' invalid", ref); + return; + } + + len = list_length (binfo); + push_obstacks (TYPE_OBSTACK (ref), TYPE_OBSTACK (ref)); + + 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) == access_public_node + || TREE_PURPOSE (binfo) == access_public_virtual_node + || (tag_code != class_type + && (TREE_PURPOSE (binfo) == access_default_node + || TREE_PURPOSE (binfo) == access_default_virtual_node))); + int via_protected + = (TREE_PURPOSE (binfo) == access_protected_node + || TREE_PURPOSE (binfo) == access_protected_virtual_node); + int via_virtual + = (TREE_PURPOSE (binfo) == access_private_virtual_node + || TREE_PURPOSE (binfo) == access_protected_virtual_node + || TREE_PURPOSE (binfo) == access_public_virtual_node + || TREE_PURPOSE (binfo) == access_default_virtual_node); + tree basetype = TREE_VALUE (binfo); + tree base_binfo; + + if (basetype && TREE_CODE (basetype) == TYPE_DECL) + basetype = TREE_TYPE (basetype); + if (!basetype + || (TREE_CODE (basetype) != RECORD_TYPE + && TREE_CODE (basetype) != TYPENAME_TYPE + && TREE_CODE (basetype) != TEMPLATE_TYPE_PARM + && TREE_CODE (basetype) != TEMPLATE_TEMPLATE_PARM)) + { + cp_error ("base type `%T' fails to be a struct or class type", + TREE_VALUE (binfo)); + continue; + } + + GNU_xref_hier (name, basetype, via_public, via_virtual, 0); + +#if 1 + /* This code replaces similar code in layout_basetypes. + We put the complete_type first for implicit `typename'. */ + if (TYPE_SIZE (complete_type (basetype)) == NULL_TREE + && ! (current_template_parms && uses_template_parms (basetype))) + { + 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; + } + + if (TYPE_FOR_JAVA (basetype) + && current_lang_stack == current_lang_base) + TYPE_FOR_JAVA (ref) = 1; + + /* 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, + CLASS_TYPE_P (basetype) + ? TYPE_BINFO_VTABLE (basetype) : NULL_TREE, + CLASS_TYPE_P (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; + BINFO_INHERITANCE_CHAIN (base_binfo) = TYPE_BINFO (ref); + + /* We need to unshare the binfos now so that lookups during class + definition work. */ + unshare_base_binfos (base_binfo); + + SET_CLASSTYPE_MARKED (basetype); + + /* 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; + } + + if (CLASS_TYPE_P (basetype)) + { + TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype); + TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (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) + { + tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, 0)); + + if (CLASS_TYPE_P (basetype)) + TYPE_USES_MULTIPLE_INHERITANCE (ref) + = TYPE_USES_MULTIPLE_INHERITANCE (basetype); + } + + 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); + + pop_obstacks (); +} + + +/* 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; + + /* We are wasting space here and putting these on the permanent_obstack so + that typeid(local enum) will work correctly. */ + push_obstacks (&permanent_obstack, &permanent_obstack); + + /* If this is the real definition for a previous forward reference, + fill in the contents in the same object that used to be the + forward reference. */ + + 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 `%#T'", enumtype); + else + { + enumtype = make_node (ENUMERAL_TYPE); + pushtag (name, enumtype, 0); + } + + if (current_class_type) + TREE_ADDRESSABLE (b->tags) = 1; + + /* We don't copy this value because build_enumerator needs to do it. */ + enum_next_value = integer_zero_node; + enum_overflow = 0; + + GNU_xref_decl (current_function_decl, enumtype); + return enumtype; +} + +/* 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) + tree enumtype; +{ + register tree minnode = NULL_TREE, maxnode = NULL_TREE; + /* Calculate the maximum value of any enumerator in this type. */ + + tree values = TYPE_VALUES (enumtype); + if (values) + { + tree pair; + + for (pair = values; pair; pair = TREE_CHAIN (pair)) + { + tree decl; + tree value; + + /* The TREE_VALUE is a CONST_DECL for this enumeration + constant. */ + decl = TREE_VALUE (pair); + + /* The DECL_INITIAL will be NULL if we are processing a + template declaration and this enumeration constant had no + explicit initializer. */ + value = DECL_INITIAL (decl); + if (value && !processing_template_decl) + { + /* Set the TREE_TYPE for the VALUE as well. That's so + that when we call decl_constant_value we get an + entity of the right type (but with the constant + value). Since we shouldn't ever call + decl_constant_value on a template type, there's no + reason to do that when processing_template_decl. + And, if the expression is something like a + TEMPLATE_PARM_INDEX or a CAST_EXPR doing so will + wreak havoc on the intended type of the expression. + + Of course, there's also no point in trying to compute + minimum or maximum values if we're in a template. */ + TREE_TYPE (value) = enumtype; + + if (!minnode) + minnode = maxnode = value; + else if (tree_int_cst_lt (maxnode, value)) + maxnode = value; + else if (tree_int_cst_lt (value, minnode)) + minnode = value; + } + + if (processing_template_decl) + /* If this is just a template, leave the CONST_DECL + alone. That way tsubst_copy will find CONST_DECLs for + CONST_DECLs, and not INTEGER_CSTs. */ + ; + else + /* In the list we're building up, we want the enumeration + values, not the CONST_DECLs. */ + TREE_VALUE (pair) = value; + } + } + else + maxnode = minnode = integer_zero_node; + + TYPE_VALUES (enumtype) = nreverse (values); + + if (processing_template_decl) + { + tree scope = current_scope (); + if (scope && TREE_CODE (scope) == FUNCTION_DECL) + add_tree (build_min (TAG_DEFN, enumtype)); + } + else + { + int unsignedp = tree_int_cst_sgn (minnode) >= 0; + int lowprec = min_precision (minnode, unsignedp); + int highprec = min_precision (maxnode, unsignedp); + int precision = MAX (lowprec, highprec); + tree tem; + + TYPE_SIZE (enumtype) = NULL_TREE; + + /* Set TYPE_MIN_VALUE and TYPE_MAX_VALUE according to `precision'. */ + + TYPE_PRECISION (enumtype) = precision; + if (unsignedp) + fixup_unsigned_type (enumtype); + else + fixup_signed_type (enumtype); + + if (flag_short_enums || (precision > TYPE_PRECISION (integer_type_node))) + /* Use the width of the narrowest normal C type which is wide + enough. */ + TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size + (precision, 1)); + else + TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node); + + TYPE_SIZE (enumtype) = 0; + layout_type (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_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (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. */ + rest_of_type_compilation (enumtype, namespace_bindings_p ()); + } + + /* In start_enum we pushed obstacks. Here, we must pop them. */ + pop_obstacks (); + + return enumtype; +} + +/* Build and install a CONST_DECL for an enumeration constant of the + enumeration type TYPE whose NAME and VALUE (if any) are provided. + Assignment of sequential values by default is handled here. */ + +tree +build_enumerator (name, value, type) + tree name; + tree value; + tree type; +{ + tree decl, result; + tree context; + + /* Remove no-op casts from the value. */ + if (value) + STRIP_TYPE_NOPS (value); + + if (! processing_template_decl) + { + /* Validate and default VALUE. */ + if (value != NULL_TREE) + { + if (TREE_READONLY_DECL_P (value)) + value = decl_constant_value (value); + + if (TREE_CODE (value) == INTEGER_CST) + { + value = default_conversion (value); + constant_expression_warning (value); + } + else + { + cp_error ("enumerator value for `%D' not integer constant", name); + value = NULL_TREE; + } + } + + /* Default based on previous value. */ + if (value == NULL_TREE && ! processing_template_decl) + { + value = enum_next_value; + if (enum_overflow) + cp_error ("overflow in enumeration values at `%D'", name); + } + + /* Remove no-op casts from the value. */ + if (value) + STRIP_TYPE_NOPS (value); +#if 0 + /* To fix MAX_VAL enum consts. (bkoz) */ + TREE_TYPE (value) = integer_type_node; +#endif + } + + /* We always have to copy here; not all INTEGER_CSTs are unshared. + Even in other cases, we will later (in finish_enum) be setting the + type of VALUE. */ + if (value != NULL_TREE) + value = copy_node (value); + + /* C++ associates enums with global, function, or class declarations. */ + + context = current_scope (); + if (context && context == current_class_type) + /* This enum declaration is local to the class. */ + decl = build_lang_field_decl (CONST_DECL, name, type); + else + /* It's a global enum, or it's local to a function. (Note local to + a function could mean local to a class method. */ + decl = build_decl (CONST_DECL, name, type); + + DECL_CONTEXT (decl) = FROB_CONTEXT (context); + DECL_INITIAL (decl) = value; + TREE_READONLY (decl) = 1; + + if (context && context == current_class_type) + { + pushdecl_class_level (decl); + /* In something like `struct S { enum E { i = 7 }; };' we put `i' + on the TYPE_FIELDS list for `S'. (That's so that you can say + things like `S::i' later.) */ + finish_member_declaration (decl); + } + else + { + pushdecl (decl); + GNU_xref_decl (current_function_decl, decl); + } + + if (! processing_template_decl) + { + /* Set basis for default for next value. */ + enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value, + integer_one_node, PLUS_EXPR); + enum_overflow = tree_int_cst_lt (enum_next_value, value); + } + + result = saveable_tree_cons (name, decl, NULL_TREE); + return result; +} + + +static int function_depth; + +/* Create the FUNCTION_DECL for a function definition. + DECLSPECS and DECLARATOR are the parts of the declaration; + they describe the function's name and the type it returns, + but twisted together in a fashion that parallels the syntax of C. + + If PRE_PARSED_P is non-zero then DECLARATOR is really the DECL for + the function we are about to process; DECLSPECS are ignored. For + example, we set PRE_PARSED_P when processing the definition of + inline function that was defined in-class; the definition is + actually processed when the class is complete. In this case, + PRE_PARSED_P is 2. We also set PRE_PARSED_P when instanting the + body of a template function, and when constructing thunk functions + and such; in these cases PRE_PARSED_P is 1. + + 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, attrs, pre_parsed_p) + tree declspecs, declarator, attrs; + int pre_parsed_p; +{ + tree decl1; + 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_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE, 160); + my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161); + + /* Assume, until we see it does. */ + current_function_returns_value = 0; + current_function_returns_null = 0; + named_labels = 0; + shadowed_labels = 0; + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + current_function_parms_stored = 0; + original_result_rtx = NULL_RTX; + base_init_expr = NULL_TREE; + current_base_init_list = NULL_TREE; + current_member_init_list = NULL_TREE; + ctor_label = dtor_label = NULL_TREE; + static_labelno = 0; + + 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 0 + /* What was this testing for, exactly? */ + if (! DECL_ARGUMENTS (decl1) + && !DECL_STATIC_FUNCTION_P (decl1) + && !DECL_ARTIFICIAL (decl1) + && DECL_CLASS_SCOPE_P (decl1) + && TYPE_IDENTIFIER (DECL_CONTEXT (decl1)) + && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (DECL_CONTEXT (decl1)))) + { + tree binding = binding_for_name (DECL_NAME (decl1), + current_namespace); + 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 (BINDING_VALUE (binding)) + cp_error_at ("previous declaration here", BINDING_VALUE (binding)); + } +#endif + + 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; + } + + last_function_parms = DECL_ARGUMENTS (decl1); + last_function_parm_tags = NULL_TREE; + } + else + { + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL_TREE); + /* If the declarator is not suitable for a function definition, + cause a syntax error. */ + if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) return 0; + + fntype = TREE_TYPE (decl1); + + restype = TREE_TYPE (fntype); + if (CLASS_TYPE_P (restype) && !CLASSTYPE_GOT_SEMICOLON (restype)) + { + cp_error ("semicolon missing after declaration of `%#T'", restype); + shadow_tag (build_expr_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 (DECL_MAIN_P (decl1)) + { + /* If this doesn't return integer_type, complain. */ + if (TREE_TYPE (TREE_TYPE (decl1)) != integer_type_node) + { + if (pedantic || warn_return_type) + pedwarn ("return type for `main' changed to `int'"); + TREE_TYPE (decl1) = fntype = default_function_type; + } + } + } + + /* 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))); + + announce_function (decl1); + + /* Set up current_class_type, and enter the scope of the class, if + appropriate. */ + if (ctype) + push_nested_class (ctype, 1); + else if (DECL_STATIC_FUNCTION_P (decl1)) + push_nested_class (DECL_CONTEXT (decl1), 2); + + /* Now that we have entered the scope of the class, we must restore + the bindings for any template parameters surrounding DECL1, if it + is an inline member template. (Order is important; consider the + case where a template parameter has the same name as a field of + the class.) It is not until after this point that + PROCESSING_TEMPLATE_DECL is guaranteed to be set up correctly. */ + if (pre_parsed_p == 2) + maybe_begin_member_template_processing (decl1); + + /* We are now in the scope of the function being defined. */ + current_function_decl = decl1; + + /* 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; + + if (! processing_template_decl) + { + /* In a function definition, arg types must be complete. */ + require_complete_types_for_parms (current_function_parms); + + if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE) + { + cp_error ("return-type `%#T' is an incomplete type", + TREE_TYPE (fntype)); + + /* Make it return void instead, but don't change the + type of the DECL_RESULT, in case we have a named return value. */ + if (ctype) + TREE_TYPE (decl1) + = build_cplus_method_type (build_type_variant (ctype, + TREE_READONLY (decl1), + TREE_SIDE_EFFECTS (decl1)), + void_type_node, + FUNCTION_ARG_CHAIN (decl1)); + else + TREE_TYPE (decl1) + = build_function_type (void_type_node, + TYPE_ARG_TYPES (TREE_TYPE (decl1))); + DECL_RESULT (decl1) + = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (fntype))); + TREE_READONLY (DECL_RESULT (decl1)) + = CP_TYPE_CONST_P (TREE_TYPE (fntype)); + TREE_THIS_VOLATILE (DECL_RESULT (decl1)) + = CP_TYPE_VOLATILE_P (TREE_TYPE (fntype)); + } + + if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype)) + && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (fntype))) + abstract_virtuals_error (decl1, TREE_TYPE (fntype)); + } + + /* Effective C++ rule 15. See also c_expand_return. */ + if (warn_ecpp + && DECL_NAME (decl1) == ansi_opname[(int) MODIFY_EXPR] + && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE) + cp_warning ("`operator=' should return a reference to `*this'"); + + /* 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; + +#ifdef SET_DEFAULT_DECL_ATTRIBUTES + SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs); +#endif + + /* This function exists in static storage. + (This does not mean `static' in the C sense!) */ + TREE_STATIC (decl1) = 1; + + /* We must call push_template_decl after current_class_type is set + up. (If we are processing inline definitions after exiting a + class scope, current_class_type will be NULL_TREE until set above + by push_nested_class.) */ + if (processing_template_decl) + decl1 = push_template_decl (decl1); + + /* Record the decl so that the function name is defined. + If we already have a decl for this name, and it is a FUNCTION_DECL, + use the old decl. */ + if (!processing_template_decl && pre_parsed_p == 0) + { + /* A specialization is not used to guide overload resolution. */ + if ((flag_guiding_decls + || !DECL_TEMPLATE_SPECIALIZATION (decl1)) + && ! DECL_FUNCTION_MEMBER_P (decl1)) + decl1 = pushdecl (decl1); + else + { + /* We need to set the DECL_CONTEXT. */ + if (!DECL_CONTEXT (decl1) && DECL_TEMPLATE_INFO (decl1)) + DECL_CONTEXT (decl1) = DECL_CONTEXT (DECL_TI_TEMPLATE (decl1)); + /* And make sure we have enough default args. */ + check_default_args (decl1); + } + DECL_MAIN_VARIANT (decl1) = decl1; + fntype = TREE_TYPE (decl1); + } + + current_function_decl = decl1; + + if (DECL_INTERFACE_KNOWN (decl1)) + { + tree ctx = hack_decl_function_context (decl1); + + if (DECL_NOT_REALLY_EXTERN (decl1)) + DECL_EXTERNAL (decl1) = 0; + + if (ctx != NULL_TREE && DECL_THIS_INLINE (ctx) + && TREE_PUBLIC (ctx)) + /* This is a function in a local class in an extern inline + function. */ + comdat_linkage (decl1); + } + /* If this function belongs to an interface, it is public. + If it belongs to someone else's interface, it is also external. + This only affects inlines and template instantiations. */ + else if (interface_unknown == 0 + && (! DECL_TEMPLATE_INSTANTIATION (decl1) + || flag_alt_external_templates)) + { + if (DECL_THIS_INLINE (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1) + || processing_template_decl) + { + DECL_EXTERNAL (decl1) + = (interface_only + || (DECL_THIS_INLINE (decl1) && ! flag_implement_inlines)); + + /* For WIN32 we also want to put these in linkonce sections. */ + maybe_make_one_only (decl1); + } + else + DECL_EXTERNAL (decl1) = 0; + DECL_NOT_REALLY_EXTERN (decl1) = 0; + DECL_INTERFACE_KNOWN (decl1) = 1; + } + else + { + /* This is a definition, not a reference. + So clear DECL_EXTERNAL. */ + DECL_EXTERNAL (decl1) = 0; + + if ((DECL_THIS_INLINE (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1)) + && ! DECL_INTERFACE_KNOWN (decl1) + /* Don't try to defer nested functions for now. */ + && ! hack_decl_function_context (decl1)) + DECL_DEFER_OUTPUT (decl1) = 1; + else + DECL_INTERFACE_KNOWN (decl1) = 1; + } + + if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)) + { + if (TREE_CODE (fntype) == METHOD_TYPE) + TREE_TYPE (decl1) = fntype + = build_function_type (TREE_TYPE (fntype), + TREE_CHAIN (TYPE_ARG_TYPES (fntype))); + current_function_parms = TREE_CHAIN (current_function_parms); + DECL_ARGUMENTS (decl1) = current_function_parms; + ctype = NULL_TREE; + } + restype = TREE_TYPE (fntype); + + if (ctype) + { + /* If we're compiling a friend function, neither of the variables + current_class_ptr nor current_class_type will have values. */ + if (! doing_friend) + { + /* We know that this was set up by `grokclassfn'. + We do not wait until `store_parm_decls', since evil + parse errors may never get us to that point. Here + we keep the consistency between `current_class_type' + and `current_class_ptr'. */ + tree t = current_function_parms; + + my_friendly_assert (t != NULL_TREE + && TREE_CODE (t) == PARM_DECL, 162); + + if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE) + { + int i; + + if (! hack_decl_function_context (decl1)) + temporary_allocation (); + i = suspend_momentary (); + + /* Normally, build_indirect_ref returns + current_class_ref whenever current_class_ptr is + dereferenced. This time, however, we want it to + *create* current_class_ref, so we temporarily clear + current_class_ptr to fool it. */ + current_class_ptr = NULL_TREE; + current_class_ref = build_indirect_ref (t, NULL_PTR); + current_class_ptr = t; + + resume_momentary (i); + if (! hack_decl_function_context (decl1)) + end_temporary_allocation (); + } + else + /* We're having a signature pointer here. */ + current_class_ref = current_class_ptr = t; + + } + } + else + current_class_ptr = current_class_ref = NULL_TREE; + + pushlevel (0); + current_binding_level->parm_flag = 1; + + GNU_xref_function (decl1, current_function_parms); + + if (attrs) + cplus_decl_attributes (decl1, NULL_TREE, attrs); + + make_function_rtl (decl1); + + /* Promote the value to int before returning it. */ + if (C_PROMOTING_INTEGER_TYPE_P (restype)) + restype = type_promotes_to (restype); + + /* 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; + + if (DECL_RESULT (decl1) == NULL_TREE) + { + DECL_RESULT (decl1) + = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype)); + TREE_READONLY (DECL_RESULT (decl1)) = CP_TYPE_CONST_P (restype); + TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = CP_TYPE_VOLATILE_P (restype); + } + + /* Allocate further tree nodes temporarily during compilation + of this function only. Tiemann moved up here from bottom of fn. */ + /* If this is a nested function, then we must continue to allocate RTL + on the permanent obstack in case we need to inline it later. */ + if (! hack_decl_function_context (decl1)) + temporary_allocation (); + + if (processing_template_decl) + { + ++minimal_parse_mode; + last_tree = DECL_SAVED_TREE (decl1) + = build_nt (EXPR_STMT, void_zero_node); + } + + ++function_depth; + + if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1)) + && DECL_LANGUAGE (decl1) == lang_cplusplus) + { + dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + ctor_label = NULL_TREE; + } + else + { + dtor_label = NULL_TREE; + if (DECL_CONSTRUCTOR_P (decl1)) + ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + } + + return 1; +} + +/* Called after store_parm_decls for a function-try-block. We need to update + last_parm_cleanup_insn so that the base initializers for a constructor + are run within this block, not before it. */ + +void +expand_start_early_try_stmts () +{ + expand_start_try_stmts (); + last_parm_cleanup_insn = get_last_insn (); +} + +/* Store the parameter declarations into the current function declaration. + This is called after parsing the parameter declarations, before + digesting the body of the function. + + Also install to binding contour return value identifier, if any. */ + +void +store_parm_decls () +{ + register tree fndecl = current_function_decl; + register tree parm; + int parms_have_cleanups = 0; + tree cleanups = NULL_TREE; + + /* This is either a chain of PARM_DECLs (when a prototype is used). */ + tree specparms = current_function_parms; + + /* This is a list of types declared among parms in a prototype. */ + tree parmtags = current_function_parm_tags; + + /* 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 (toplevel_bindings_p ()) + fatal ("parse errors have confused me too much"); + + /* Initialize RTL machinery. */ + init_function_start (fndecl, input_filename, lineno); + + /* 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; + if (DECL_NAME (parm) == NULL_TREE) + { + pushdecl (parm); + } + else if (TREE_CODE (TREE_TYPE (parm)) == VOID_TYPE) + cp_error ("parameter `%D' declared void", parm); + else + { + /* Now fill in DECL_REFERENCE_SLOT for any of the parm decls. + A parameter is assumed not to have any side effects. + If this should change for any reason, then this + will have to wrap the bashed reference type in a save_expr. + + Also, if the parameter type is declared to be an X + and there is an X(X&) constructor, we cannot lay it + into the stack (any more), so we make this parameter + look like it is really of reference type. Functions + which pass parameters to this function will know to + create a temporary in their frame, and pass a reference + to that. */ + + if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE + && TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm)))) + SET_DECL_REFERENCE_SLOT (parm, convert_from_reference (parm)); + + pushdecl (parm); + } + if (! processing_template_decl + && (cleanup = maybe_build_cleanup (parm), cleanup)) + { + expand_decl (parm); + parms_have_cleanups = 1; + + /* Keep track of the cleanups. */ + cleanups = tree_cons (parm, cleanup, cleanups); + } + } + 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))); + + /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */ + declare_function_name (); + + /* Initialize the RTL code for the function. */ + DECL_SAVED_INSNS (fndecl) = NULL_RTX; + if (! processing_template_decl) + expand_function_start (fndecl, parms_have_cleanups); + + current_function_parms_stored = 1; + + /* If this function is `main', emit a call to `__main' + to run global initializers, etc. */ + if (DECL_MAIN_P (fndecl)) + expand_main_function (); + + /* Now that we have initialized the parms, we can start their + cleanups. We cannot do this before, since expand_decl_cleanup + should not be called before the parm can be used. */ + if (cleanups + && ! processing_template_decl) + { + for (cleanups = nreverse (cleanups); cleanups; cleanups = TREE_CHAIN (cleanups)) + { + if (! expand_decl_cleanup (TREE_PURPOSE (cleanups), TREE_VALUE (cleanups))) + cp_error ("parser lost in parsing declaration of `%D'", + TREE_PURPOSE (cleanups)); + } + } + + /* 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); + } + + if (! processing_template_decl && flag_exceptions) + { + /* Do the starting of the exception specifications, if we have any. */ + if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) + expand_start_eh_spec (); + } + + last_parm_cleanup_insn = get_last_insn (); + last_dtor_insn = get_last_insn (); +} + +/* Bind a name and initialization to the return value of + the current function. */ + +void +store_return_init (return_id, init) + tree return_id, init; +{ + tree decl = DECL_RESULT (current_function_decl); + + if (pedantic) + /* Give this error as many times as there are occurrences, + so that users can use Emacs compilation buffers to find + and fix all such places. */ + 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 + cp_error ("return identifier `%D' already in place", 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 `cp_finish_decl' know that this initializer is ok. */ + DECL_INITIAL (decl) = init; + pushdecl (decl); + + if (minimal_parse_mode) + add_tree (build_min_nt (RETURN_INIT, return_id, + copy_to_permanent (init))); + else + cp_finish_decl (decl, init, NULL_TREE, 0, 0); + } +} + + +/* 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. + + FLAGS is a bitwise or of the following values: + 1 - CALL_POPLEVEL + 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. + 2 - INCLASS_INLINE + We just finished processing the body of an in-class inline + function definition. (This processing will have taken place + after the class definition is complete.) + + NESTED is nonzero if we were in the middle of compiling another function + when we started on this one. */ + +void +finish_function (lineno, flags, nested) + int lineno; + int flags; + int nested; +{ + register tree fndecl = current_function_decl; + tree fntype, ctype = NULL_TREE; + rtx last_parm_insn, insns; + /* Label to use if this function is supposed to return a value. */ + tree no_return_label = NULL_TREE; + tree decls = NULL_TREE; + int call_poplevel = (flags & 1) != 0; + int inclass_inline = (flags & 2) != 0; + int in_template; + + /* When we get some parse errors, we can end up without a + current_function_decl, so cope. */ + if (fndecl == NULL_TREE) + return; + + if (! nested && function_depth > 1) + nested = 1; + + fntype = TREE_TYPE (fndecl); + +/* TREE_READONLY (fndecl) = 1; + This caused &foo to be of type ptr-to-const-function + which then got a warning when stored in a ptr-to-function variable. */ + + /* This happens on strange parse errors. */ + if (! current_function_parms_stored) + { + call_poplevel = 0; + store_parm_decls (); + } + + if (processing_template_decl) + { + if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel) + { + decls = getdecls (); + expand_end_bindings (decls, decls != NULL_TREE, 0); + poplevel (decls != NULL_TREE, 0, 0); + } + } + else + { + 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; + tree in_charge_node = lookup_name (in_charge_identifier, 0); + tree virtual_size; + int ok_to_optimize_dtor = 0; + int empty_dtor = get_last_insn () == last_dtor_insn; + + if (current_function_assigns_this) + cond = build (NE_EXPR, boolean_type_node, + current_class_ptr, integer_zero_node); + else + { + int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type); + + /* If this destructor is empty, then we don't need to check + whether `this' is NULL in some cases. */ + if ((flag_this_is_variable & 1) == 0) + ok_to_optimize_dtor = 1; + else if (empty_dtor) + ok_to_optimize_dtor + = (n_baseclasses == 0 + || (n_baseclasses == 1 + && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0)))); + } + + /* These initializations might go inline. Protect + the binding level of the parms. */ + pushlevel (0); + expand_start_bindings (0); + + if (current_function_assigns_this) + { + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + } + + /* Generate the code to call destructor on base class. + If this destructor belongs to a class with virtual + functions, then set the virtual function table + pointer to represent the type of our base class. */ + + /* This side-effect makes call to `build_delete' generate the + code we have to have at the end of this destructor. + `build_delete' will set the flag again. */ + TYPE_HAS_DESTRUCTOR (current_class_type) = 0; + + /* These are two cases where we cannot delegate deletion. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type) + || TYPE_GETS_REG_DELETE (current_class_type)) + exprstmt = build_delete (current_class_type, current_class_ref, integer_zero_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0); + else + exprstmt = build_delete (current_class_type, current_class_ref, in_charge_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0); + + /* If we did not assign to this, then `this' is non-zero at + the end of a destructor. As a special optimization, don't + emit test if this is an empty destructor. If it does nothing, + it does nothing. If it calls a base destructor, the base + destructor will perform the test. */ + + if (exprstmt != error_mark_node + && (TREE_CODE (exprstmt) != NOP_EXPR + || TREE_OPERAND (exprstmt, 0) != integer_zero_node + || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))) + { + expand_label (dtor_label); + if (cond != integer_one_node) + expand_start_cond (cond, 0); + if (exprstmt != void_zero_node) + /* Don't call `expand_expr_stmt' if we're not going to do + anything, since -Wall will give a diagnostic. */ + expand_expr_stmt (exprstmt); + + /* Run destructor on all virtual baseclasses. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + { + tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type))); + expand_start_cond (build (BIT_AND_EXPR, integer_type_node, + in_charge_node, integer_two_node), 0); + while (vbases) + { + if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases))) + { + tree vb = get_vbase + (BINFO_TYPE (vbases), + TYPE_BINFO (current_class_type)); + expand_expr_stmt + (build_scoped_method_call + (current_class_ref, vb, dtor_identifier, + build_expr_list (NULL_TREE, integer_zero_node))); + } + vbases = TREE_CHAIN (vbases); + } + expand_end_cond (); + } + + do_pending_stack_adjust (); + if (cond != integer_one_node) + expand_end_cond (); + } + + virtual_size = c_sizeof (current_class_type); + + /* At the end, call delete if that's what's requested. */ + + /* FDIS sez: At the point of definition of a virtual destructor + (including an implicit definition), non-placement operator + delete shall be looked up in the scope of the destructor's + class and if found shall be accessible and unambiguous. + + This is somewhat unclear, but I take it to mean that if the + class only defines placement deletes we don't do anything here. + So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain + for us if they ever try to delete one of these. */ + + if (TYPE_GETS_REG_DELETE (current_class_type) + || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + exprstmt = build_op_delete_call + (DELETE_EXPR, current_class_ptr, virtual_size, + LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE); + else + exprstmt = NULL_TREE; + + if (exprstmt) + { + cond = build (BIT_AND_EXPR, integer_type_node, + in_charge_node, integer_one_node); + expand_start_cond (cond, 0); + expand_expr_stmt (exprstmt); + expand_end_cond (); + } + + /* End of destructor. */ + expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0); + poplevel (getdecls () != NULL_TREE, 0, 0); + + /* Back to the top of destructor. */ + /* Don't execute destructor code if `this' is NULL. */ + + start_sequence (); + + /* If the dtor is empty, and we know there is not possible way we + could use any vtable entries, before they are possibly set by + a base class dtor, we don't have to setup the vtables, as we + know that any base class dtoring will set up any vtables it + needs. We avoid MI, because one base class dtor can do a + virtual dispatch to an overridden function that would need to + have a non-related vtable set up, we cannot avoid setting up + vtables in that case. We could change this to see if there is + just one vtable. */ + if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type)) + { + /* Make all virtual function table pointers in non-virtual base + classes point to CURRENT_CLASS_TYPE's virtual function + tables. */ + expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr); + + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr); + } + + if (! ok_to_optimize_dtor) + { + cond = build_binary_op (NE_EXPR, + current_class_ptr, integer_zero_node, 1); + expand_start_cond (cond, 0); + } + + insns = get_insns (); + end_sequence (); + + last_parm_insn = get_first_nonparm_insn (); + if (last_parm_insn == NULL_RTX) + last_parm_insn = get_last_insn (); + else + last_parm_insn = previous_insn (last_parm_insn); + + emit_insns_after (insns, last_parm_insn); + + if (! ok_to_optimize_dtor) + expand_end_cond (); + } + else if (current_function_assigns_this) + { + /* Does not need to call emit_base_init, because + that is done (if needed) just after assignment to this + is seen. */ + + if (DECL_CONSTRUCTOR_P (current_function_decl)) + { + end_protect_partials (); + expand_label (ctor_label); + ctor_label = NULL_TREE; + + if (call_poplevel) + { + decls = getdecls (); + expand_end_bindings (decls, decls != NULL_TREE, 0); + poplevel (decls != NULL_TREE, 0, 0); + } + /* c_expand_return knows to return 'this' from a constructor. */ + c_expand_return (NULL_TREE); + } + else if (TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl))) != VOID_TYPE + && return_label != NULL_RTX) + no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + base_init_expr = NULL_TREE; + } + else if (DECL_CONSTRUCTOR_P (fndecl)) + { + tree cond = NULL_TREE, thenclause = NULL_TREE; + /* Allow constructor for a type to get a new instance of the object + using `build_new'. */ + tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type); + CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE; + + DECL_RETURNS_FIRST_ARG (fndecl) = 1; + + if (flag_this_is_variable > 0) + { + cond = build_binary_op (EQ_EXPR, + current_class_ptr, integer_zero_node, 1); + thenclause = build_modify_expr (current_class_ptr, NOP_EXPR, + build_new (NULL_TREE, current_class_type, void_type_node, 0)); + } + + CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals; + + start_sequence (); + + if (flag_this_is_variable > 0) + { + expand_start_cond (cond, 0); + expand_expr_stmt (thenclause); + expand_end_cond (); + } + + /* Emit insns from `emit_base_init' which sets up virtual + function table pointer(s). */ + if (base_init_expr) + { + expand_expr_stmt (base_init_expr); + base_init_expr = NULL_TREE; + } + + insns = get_insns (); + end_sequence (); + + /* This is where the body of the constructor begins. */ + + emit_insns_after (insns, last_parm_cleanup_insn); + + end_protect_partials (); + + /* This is where the body of the constructor ends. */ + expand_label (ctor_label); + ctor_label = NULL_TREE; + + if (call_poplevel) + { + decls = getdecls (); + expand_end_bindings (decls, decls != NULL_TREE, 0); + poplevel (decls != NULL_TREE, 1, 0); + } + + /* c_expand_return knows to return 'this' from a constructor. */ + c_expand_return (NULL_TREE); + + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + } + else if (DECL_MAIN_P (fndecl)) + { + /* Make it so that `main' always returns 0 by default. */ +#ifdef VMS + c_expand_return (integer_one_node); +#else + c_expand_return (integer_zero_node); +#endif + } + 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_exceptions) + expand_exception_blocks (); + + /* 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); + + /* 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); + } + + /* Generate rtl for function exit. */ + expand_function_end (input_filename, lineno, 1); + } + + /* If we're processing a template, squirrel away the definition + until we do an instantiation. */ + if (processing_template_decl) + { + --minimal_parse_mode; + DECL_SAVED_TREE (fndecl) = TREE_CHAIN (DECL_SAVED_TREE (fndecl)); + /* We have to save this value here in case + maybe_end_member_template_processing decides to pop all the + template parameters. */ + in_template = 1; + } + else + in_template = 0; + + /* This must come after expand_function_end because cleanups might + have declarations (from inline functions) that need to go into + this function's blocks. */ + if (current_binding_level->parm_flag != 1) + my_friendly_abort (122); + poplevel (1, 0, 1); + + /* If this is a in-class inline definition, we may have to pop the + bindings for the template parameters that we added in + maybe_begin_member_template_processing when start_function was + called. */ + if (inclass_inline) + maybe_end_member_template_processing (); + + /* Reset scope for C++: if we were in the scope of a class, + then when we finish this function, we are not longer so. + This cannot be done until we know for sure that no more + class members will ever be referenced in this function + (i.e., calls to destructors). */ + if (current_class_name) + { + ctype = current_class_type; + pop_nested_class (1); + } + + /* Must mark the RESULT_DECL as being in this function. */ + DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; + + /* Set the BLOCK_SUPERCONTEXT of the outermost function scope to point + to the FUNCTION_DECL node itself. */ + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + if (!in_template) + { + int saved_flag_keep_inline_functions = + flag_keep_inline_functions; + + /* So we can tell if jump_optimize sets it to 1. */ + can_reach_end = 0; + + if (DECL_CONTEXT (fndecl) != NULL_TREE + && hack_decl_function_context (fndecl)) + /* Trick rest_of_compilation into not deferring output of this + function, even if it is inline, since the rtl_obstack for + this function is the function_obstack of the enclosing + function and will be deallocated when the enclosing + function is gone. See save_tree_status. */ + flag_keep_inline_functions = 1; + + /* Run the optimizers and output the assembler code for this + function. */ + + if (DECL_ARTIFICIAL (fndecl)) + { + /* Do we really *want* to inline this synthesized method? */ + + int save_fif = flag_inline_functions; + flag_inline_functions = 1; + + /* Turn off DECL_INLINE for the moment so function_cannot_inline_p + will check our size. */ + DECL_INLINE (fndecl) = 0; + + rest_of_compilation (fndecl); + flag_inline_functions = save_fif; + } + else + rest_of_compilation (fndecl); + + flag_keep_inline_functions = saved_flag_keep_inline_functions; + + if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (fndecl)) + { + /* Set DECL_EXTERNAL so that assemble_external will be called as + necessary. We'll clear it again in finish_file. */ + if (! DECL_EXTERNAL (fndecl)) + DECL_NOT_REALLY_EXTERN (fndecl) = 1; + DECL_EXTERNAL (fndecl) = 1; + 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 + && TREE_CODE (TREE_TYPE (fntype)) != VOID_TYPE) + { + /* If this function returns non-void and control can drop through, + complain. */ + cp_warning ("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"); + } + + --function_depth; + + /* Free all the tree nodes making up this function. */ + /* Switch back to allocating nodes permanently + until we start another function. */ + if (! nested) + permanent_allocation (1); + + if (DECL_SAVED_INSNS (fndecl) == NULL_RTX) + { + tree t; + + /* 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; + for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t)) + DECL_RTL (t) = DECL_INCOMING_RTL (t) = NULL_RTX; + } + + if (DECL_STATIC_CONSTRUCTOR (fndecl)) + static_ctors = perm_tree_cons (NULL_TREE, fndecl, static_ctors); + if (DECL_STATIC_DESTRUCTOR (fndecl)) + static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors); + + if (! nested) + { + /* Let the error reporting routines know that we're outside a + function. For a nested function, this value is used in + pop_cp_function_context and then reset via pop_function_context. */ + current_function_decl = NULL_TREE; + } + + named_label_uses = NULL; + current_class_ptr = NULL_TREE; + current_class_ref = NULL_TREE; +} + +/* Create the FUNCTION_DECL for a function definition. + 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, attrlist) + tree declarator, declspecs, attrlist; +{ + tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, + attrlist); + + /* Something too ugly to handle. */ + if (fndecl == NULL_TREE) + return NULL_TREE; + + /* Pass friends other than inline friend functions back. */ + if (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; + + if (DECL_IN_AGGR_P (fndecl)) + { + if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type) + { + if (DECL_CONTEXT (fndecl) + && TREE_CODE( DECL_CONTEXT (fndecl)) != NAMESPACE_DECL) + cp_error ("`%D' is already defined in class %s", fndecl, + TYPE_NAME_STRING (DECL_CONTEXT (fndecl))); + } + return void_type_node; + } + + check_template_shadow (fndecl); + + DECL_THIS_INLINE (fndecl) = 1; + + if (flag_default_inline) + DECL_INLINE (fndecl) = 1; + + /* We process method specializations in finish_struct_1. */ + if (processing_template_decl && !DECL_TEMPLATE_SPECIALIZATION (fndecl)) + fndecl = push_template_decl (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 (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); + } + + cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0, 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 (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) + pop_binding (DECL_NAME (link), link); + my_friendly_assert (TREE_CODE (link) != FUNCTION_DECL, 163); + DECL_CONTEXT (link) = NULL_TREE; + } + + 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); + + 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 *list; + + if (current_binding_level->incomplete == NULL_TREE) + return; + + if (!type) /* Don't do this for class templates. */ + return; + + for (list = ¤t_binding_level->incomplete; *list; ) + { + tree decl = TREE_VALUE (*list); + if ((decl && TREE_TYPE (decl) == type) + || (TREE_TYPE (decl) + && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE + && TREE_TYPE (TREE_TYPE (decl)) == type)) + { + int toplevel = toplevel_bindings_p (); + if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE + && TREE_TYPE (TREE_TYPE (decl)) == type) + layout_type (TREE_TYPE (decl)); + layout_decl (decl, 0); + rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0); + if (! toplevel) + { + tree cleanup; + expand_decl (decl); + cleanup = maybe_build_cleanup (decl); + expand_decl_init (decl); + if (! expand_decl_cleanup (decl, cleanup)) + cp_error ("parser lost in parsing declaration of `%D'", + decl); + } + *list = TREE_CHAIN (*list); + } + else + list = &TREE_CHAIN (*list); + } +} + +/* If DECL is of a type which needs a cleanup, build that cleanup here. + See build_delete for information about AUTO_DELETE. + + Don't build these on the momentary obstack; they must live + the life of the binding contour. */ + +static tree +maybe_build_cleanup_1 (decl, auto_delete) + tree decl, auto_delete; +{ + tree type = TREE_TYPE (decl); + if (TYPE_NEEDS_DESTRUCTOR (type)) + { + int temp = 0, flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; + tree rval; + + if (TREE_CODE (decl) != PARM_DECL) + temp = suspend_momentary (); + + if (TREE_CODE (type) == ARRAY_TYPE) + rval = decl; + else + { + 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; + + rval = build_delete (TREE_TYPE (rval), rval, auto_delete, flags, 0); + + if (TYPE_USES_VIRTUAL_BASECLASSES (type) + && ! TYPE_HAS_DESTRUCTOR (type)) + rval = build_compound_expr (expr_tree_cons (NULL_TREE, rval, + build_expr_list (NULL_TREE, build_vbase_delete (type, decl)))); + + if (TREE_CODE (decl) != PARM_DECL) + resume_momentary (temp); + + return rval; + } + return 0; +} + +/* If DECL is of a type which needs a cleanup, build that cleanup + here. The cleanup does free the storage with a call to delete. */ + +tree +maybe_build_cleanup_and_delete (decl) + tree decl; +{ + return maybe_build_cleanup_1 (decl, integer_three_node); +} + +/* If DECL is of a type which needs a cleanup, build that cleanup + here. The cleanup does not free the storage with a call a delete. */ + +tree +maybe_build_cleanup (decl) + tree decl; +{ + return maybe_build_cleanup_1 (decl, integer_two_node); +} + +/* 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 (processing_template_decl) + { + add_tree (build_min_nt (EXPR_STMT, exp)); + return; + } + + /* Arrange for all temps to disappear. */ + expand_start_target_temps (); + + if (TREE_TYPE (exp) == unknown_type_node) + { + if (TREE_CODE (exp) == COMPONENT_REF) + error ("invalid reference to a member function name, did you forget the ()?"); + else + error ("address of overloaded function with no contextual type information"); + } + else + { + if (TREE_CODE (exp) == FUNCTION_DECL) + { + cp_warning ("reference, not call, to function `%D'", exp); + warning ("at this point in file"); + } + +#if 0 + /* We should do this eventually, but right now this causes regex.o from + libg++ to miscompile, and tString to core dump. */ + exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); +#endif + + /* Strip unused implicit INDIRECT_REFs of references. */ + if (TREE_CODE (exp) == INDIRECT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE) + exp = TREE_OPERAND (exp, 0); + + /* If we don't do this, we end up down inside expand_expr + trying to do TYPE_MODE on the ERROR_MARK, and really + go outside the bounds of the type. */ + if (exp != error_mark_node) + expand_expr_stmt (break_out_cleanups (exp)); + } + + /* Clean up any pending cleanups. This happens when a function call + returns a cleanup-needing value that nobody uses. */ + expand_end_target_temps (); +} + +/* 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; + expand_expr_stmt (base_init_expr); + check_base_init (current_class_type); + } + current_function_assigns_this = 1; +} + +/* 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); + + if (CP_TYPE_QUALS (TREE_TYPE (TREE_VALUE (args))) + != TYPE_UNQUALIFIED) + cp_error ("static member function `%#D' declared with type qualifiers", + *decl); + + args = TREE_CHAIN (args); + tmp = build_function_type (TREE_TYPE (function), args); + tmp = build_qualified_type (tmp, CP_TYPE_QUALS (function)); + tmp = build_exception_variant (tmp, + TYPE_RAISES_EXCEPTIONS (function)); + TREE_TYPE (*decl) = tmp; + if (DECL_ARGUMENTS (*decl)) + DECL_ARGUMENTS (*decl) = TREE_CHAIN (DECL_ARGUMENTS (*decl)); + DECL_STATIC_FUNCTION_P (*decl) = 1; + if (fn) + *fn = tmp; + if (argtypes) + *argtypes = args; +} + +int +id_in_current_class (id) + tree id; +{ + return !!purpose_member (id, class_binding_level->class_shadowed); +} + +struct cp_function +{ + int returns_value; + int returns_null; + int assigns_this; + int just_assigned_this; + int parms_stored; + int temp_name_counter; + tree named_labels; + struct named_label_list *named_label_uses; + tree shadowed_labels; + tree ctor_label; + tree dtor_label; + rtx last_dtor_insn; + rtx last_parm_cleanup_insn; + tree base_init_list; + tree member_init_list; + tree base_init_expr; + tree current_class_ptr; + tree current_class_ref; + rtx result_rtx; + struct cp_function *next; + struct binding_level *binding_level; + int static_labelno; +}; + +static struct cp_function *cp_function_chain; + +extern int temp_name_counter; + +/* Save and reinitialize the variables + used during compilation of a C++ function. */ + +void +push_cp_function_context (context) + tree context; +{ + struct cp_function *p + = (struct cp_function *) xmalloc (sizeof (struct cp_function)); + + push_function_context_to (context); + + p->next = cp_function_chain; + cp_function_chain = p; + + p->named_labels = named_labels; + p->named_label_uses = named_label_uses; + p->shadowed_labels = shadowed_labels; + p->returns_value = current_function_returns_value; + p->returns_null = current_function_returns_null; + p->binding_level = current_binding_level; + p->ctor_label = ctor_label; + p->dtor_label = dtor_label; + p->last_dtor_insn = last_dtor_insn; + p->last_parm_cleanup_insn = last_parm_cleanup_insn; + p->assigns_this = current_function_assigns_this; + p->just_assigned_this = current_function_just_assigned_this; + p->parms_stored = current_function_parms_stored; + p->result_rtx = original_result_rtx; + p->base_init_expr = base_init_expr; + p->temp_name_counter = temp_name_counter; + p->base_init_list = current_base_init_list; + p->member_init_list = current_member_init_list; + p->current_class_ptr = current_class_ptr; + p->current_class_ref = current_class_ref; + p->static_labelno = static_labelno; +} + +/* Restore the variables used during compilation of a C++ function. */ + +void +pop_cp_function_context (context) + tree context; +{ + struct cp_function *p = cp_function_chain; + tree link; + + /* Bring back all the labels that were shadowed. */ + for (link = shadowed_labels; link; link = TREE_CHAIN (link)) + if (DECL_NAME (TREE_VALUE (link)) != 0) + SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)), + TREE_VALUE (link)); + + pop_function_context_from (context); + + cp_function_chain = p->next; + + named_labels = p->named_labels; + named_label_uses = p->named_label_uses; + shadowed_labels = p->shadowed_labels; + current_function_returns_value = p->returns_value; + current_function_returns_null = p->returns_null; + current_binding_level = p->binding_level; + ctor_label = p->ctor_label; + dtor_label = p->dtor_label; + last_dtor_insn = p->last_dtor_insn; + last_parm_cleanup_insn = p->last_parm_cleanup_insn; + current_function_assigns_this = p->assigns_this; + current_function_just_assigned_this = p->just_assigned_this; + current_function_parms_stored = p->parms_stored; + original_result_rtx = p->result_rtx; + base_init_expr = p->base_init_expr; + temp_name_counter = p->temp_name_counter; + current_base_init_list = p->base_init_list; + current_member_init_list = p->member_init_list; + current_class_ptr = p->current_class_ptr; + current_class_ref = p->current_class_ref; + static_labelno = p->static_labelno; + + free (p); +} + +int +in_function_p () +{ + return function_depth != 0; +} |