summaryrefslogtreecommitdiff
path: root/gcc/cp/decl.c
diff options
context:
space:
mode:
authorYamaArashi <shadow962@live.com>2016-01-06 01:47:28 -0800
committerYamaArashi <shadow962@live.com>2016-01-06 01:47:28 -0800
commitbe8b04496302184c6e8f04d6179f9c3afc50aeb6 (patch)
tree726e2468c0c07add773c0dbd86ab6386844259ae /gcc/cp/decl.c
initial commit
Diffstat (limited to 'gcc/cp/decl.c')
-rwxr-xr-xgcc/cp/decl.c14623
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 = &current_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;
+}