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