| /* Process declarations and variables for C compiler. |
| Copyright (C) 1988, 92-97, 1998 Free Software Foundation, Inc. |
| Contributed by Michael Tiemann (tiemann@cygnus.com) |
| |
| This file is part of GNU CC. |
| |
| GNU CC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU CC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU CC; see the file COPYING. If not, write to |
| the Free Software Foundation, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. */ |
| |
| |
| /* Process declarations and symbol lookup for C front end. |
| Also constructs types; the standard scalar types at initialization, |
| and structure, union, array and enum types when they are declared. */ |
| |
| /* ??? not all decl nodes are given the most useful possible |
| line numbers. For example, the CONST_DECLs for enum values. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "tree.h" |
| #include "rtl.h" |
| #include "flags.h" |
| #include "cp-tree.h" |
| #include "decl.h" |
| #include "lex.h" |
| #include <signal.h> |
| #include "obstack.h" |
| #include "defaults.h" |
| #include "output.h" |
| #include "except.h" |
| #include "toplev.h" |
| |
| #define obstack_chunk_alloc xmalloc |
| #define obstack_chunk_free free |
| |
| extern tree builtin_return_address_fndecl; |
| |
| extern struct obstack permanent_obstack; |
| extern struct obstack* saveable_obstack; |
| |
| extern int current_class_depth; |
| |
| extern tree static_ctors, static_dtors; |
| |
| extern int static_labelno; |
| |
| extern tree current_namespace; |
| extern tree global_namespace; |
| |
| extern void (*print_error_function) PROTO((char *)); |
| |
| /* Stack of places to restore the search obstack back to. */ |
| |
| /* Obstack used for remembering local class declarations (like |
| enums and static (const) members. */ |
| #include "stack.h" |
| struct obstack decl_obstack; |
| static struct stack_level *decl_stack; |
| |
| #ifndef CHAR_TYPE_SIZE |
| #define CHAR_TYPE_SIZE BITS_PER_UNIT |
| #endif |
| |
| #ifndef SHORT_TYPE_SIZE |
| #define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2)) |
| #endif |
| |
| #ifndef INT_TYPE_SIZE |
| #define INT_TYPE_SIZE BITS_PER_WORD |
| #endif |
| |
| #ifndef LONG_TYPE_SIZE |
| #define LONG_TYPE_SIZE BITS_PER_WORD |
| #endif |
| |
| #ifndef LONG_LONG_TYPE_SIZE |
| #define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2) |
| #endif |
| |
| #ifndef WCHAR_UNSIGNED |
| #define WCHAR_UNSIGNED 0 |
| #endif |
| |
| #ifndef FLOAT_TYPE_SIZE |
| #define FLOAT_TYPE_SIZE BITS_PER_WORD |
| #endif |
| |
| #ifndef DOUBLE_TYPE_SIZE |
| #define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) |
| #endif |
| |
| #ifndef LONG_DOUBLE_TYPE_SIZE |
| #define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) |
| #endif |
| |
| #ifndef BOOL_TYPE_SIZE |
| #ifdef SLOW_BYTE_ACCESS |
| #define BOOL_TYPE_SIZE ((SLOW_BYTE_ACCESS) ? (POINTER_SIZE) : (CHAR_TYPE_SIZE)) |
| #else |
| #define BOOL_TYPE_SIZE CHAR_TYPE_SIZE |
| #endif |
| #endif |
| |
| /* We let tm.h override the types used here, to handle trivial differences |
| such as the choice of unsigned int or long unsigned int for size_t. |
| When machines start needing nontrivial differences in the size type, |
| it would be best to do something here to figure out automatically |
| from other information what type to use. */ |
| |
| #ifndef SIZE_TYPE |
| #define SIZE_TYPE "long unsigned int" |
| #endif |
| |
| #ifndef PTRDIFF_TYPE |
| #define PTRDIFF_TYPE "long int" |
| #endif |
| |
| #ifndef WCHAR_TYPE |
| #define WCHAR_TYPE "int" |
| #endif |
| |
| static tree grokparms PROTO((tree, int)); |
| static tree lookup_nested_type PROTO((tree, tree)); |
| static char *redeclaration_error_message PROTO((tree, tree)); |
| static tree push_overloaded_decl PROTO((tree, int)); |
| |
| static struct stack_level *push_decl_level PROTO((struct stack_level *, |
| struct obstack *)); |
| static void push_binding_level PROTO((struct binding_level *, int, |
| int)); |
| static void pop_binding_level PROTO((void)); |
| static void suspend_binding_level PROTO((void)); |
| static void resume_binding_level PROTO((struct binding_level *)); |
| static struct binding_level *make_binding_level PROTO((void)); |
| static int namespace_bindings_p PROTO((void)); |
| static void declare_namespace_level PROTO((void)); |
| static void signal_catch PROTO((int)); |
| static void storedecls PROTO((tree)); |
| static void storetags PROTO((tree)); |
| static void require_complete_types_for_parms PROTO((tree)); |
| static void push_overloaded_decl_1 PROTO((tree)); |
| static int ambi_op_p PROTO((tree)); |
| static int unary_op_p PROTO((tree)); |
| static tree store_bindings PROTO((tree, tree)); |
| static tree lookup_tag_reverse PROTO((tree, tree)); |
| static tree obscure_complex_init PROTO((tree, tree)); |
| static tree maybe_build_cleanup_1 PROTO((tree, tree)); |
| static tree lookup_name_real PROTO((tree, int, int, int)); |
| static void warn_extern_redeclared_static PROTO((tree, tree)); |
| static void grok_reference_init PROTO((tree, tree, tree)); |
| static tree grokfndecl PROTO((tree, tree, tree, tree, int, |
| enum overload_flags, tree, |
| tree, tree, int, int, int, int, int, int, tree)); |
| static tree grokvardecl PROTO((tree, tree, RID_BIT_TYPE *, int, int, tree)); |
| static tree lookup_tag PROTO((enum tree_code, tree, |
| struct binding_level *, int)); |
| static void set_identifier_type_value_with_scope |
| PROTO((tree, tree, struct binding_level *)); |
| static void set_identifier_local_value_with_scope |
| PROTO((tree, tree, struct binding_level *)); |
| static void record_builtin_type PROTO((enum rid, char *, tree)); |
| static void record_unknown_type PROTO((tree, char *)); |
| static int member_function_or_else PROTO((tree, tree, char *)); |
| static void bad_specifiers PROTO((tree, char *, int, int, int, int, |
| int)); |
| static void lang_print_error_function PROTO((char *)); |
| |
| #if defined (DEBUG_CP_BINDING_LEVELS) |
| static void indent PROTO((void)); |
| #endif |
| |
| /* A node which has tree code ERROR_MARK, and whose type is itself. |
| All erroneous expressions are replaced with this node. All functions |
| that accept nodes as arguments should avoid generating error messages |
| if this node is one of the arguments, since it is undesirable to get |
| multiple error messages from one error in the input. */ |
| |
| tree error_mark_node; |
| |
| /* Erroneous argument lists can use this *IFF* they do not modify it. */ |
| tree error_mark_list; |
| |
| /* INTEGER_TYPE and REAL_TYPE nodes for the standard data types */ |
| |
| tree short_integer_type_node; |
| tree integer_type_node; |
| tree long_integer_type_node; |
| tree long_long_integer_type_node; |
| |
| tree short_unsigned_type_node; |
| tree unsigned_type_node; |
| tree long_unsigned_type_node; |
| tree long_long_unsigned_type_node; |
| |
| tree ptrdiff_type_node; |
| |
| tree unsigned_char_type_node; |
| tree signed_char_type_node; |
| tree char_type_node; |
| tree wchar_type_node; |
| tree signed_wchar_type_node; |
| tree unsigned_wchar_type_node; |
| |
| tree wchar_decl_node; |
| |
| tree float_type_node; |
| tree double_type_node; |
| tree long_double_type_node; |
| |
| tree complex_integer_type_node; |
| tree complex_float_type_node; |
| tree complex_double_type_node; |
| tree complex_long_double_type_node; |
| |
| tree intQI_type_node; |
| tree intHI_type_node; |
| tree intSI_type_node; |
| tree intDI_type_node; |
| tree intTI_type_node; |
| |
| tree unsigned_intQI_type_node; |
| tree unsigned_intHI_type_node; |
| tree unsigned_intSI_type_node; |
| tree unsigned_intDI_type_node; |
| tree unsigned_intTI_type_node; |
| |
| tree java_byte_type_node; |
| tree java_short_type_node; |
| tree java_int_type_node; |
| tree java_long_type_node; |
| tree java_float_type_node; |
| tree java_double_type_node; |
| tree java_char_type_node; |
| tree java_boolean_type_node; |
| |
| /* A VOID_TYPE node, and the same, packaged in a TREE_LIST. */ |
| |
| tree void_type_node, void_list_node; |
| tree void_zero_node; |
| |
| /* Nodes for types `void *' and `const void *'. */ |
| |
| tree ptr_type_node; |
| tree const_ptr_type_node; |
| |
| /* Nodes for types `char *' and `const char *'. */ |
| |
| tree string_type_node, const_string_type_node; |
| |
| /* Type `char[256]' or something like it. |
| Used when an array of char is needed and the size is irrelevant. */ |
| |
| tree char_array_type_node; |
| |
| /* Type `int[256]' or something like it. |
| Used when an array of int needed and the size is irrelevant. */ |
| |
| tree int_array_type_node; |
| |
| /* Type `wchar_t[256]' or something like it. |
| Used when a wide string literal is created. */ |
| |
| tree wchar_array_type_node; |
| |
| /* The bool data type, and constants */ |
| tree boolean_type_node, boolean_true_node, boolean_false_node; |
| |
| /* Type `int ()' -- used for implicit declaration of functions. */ |
| |
| tree default_function_type; |
| |
| /* Function types `double (double)' and `double (double, double)', etc. */ |
| |
| static tree double_ftype_double, double_ftype_double_double; |
| static tree int_ftype_int, long_ftype_long; |
| static tree float_ftype_float; |
| static tree ldouble_ftype_ldouble; |
| |
| /* Function type `int (const void *, const void *, size_t)' */ |
| static tree int_ftype_cptr_cptr_sizet; |
| |
| /* C++ extensions */ |
| tree vtable_entry_type; |
| tree delta_type_node; |
| #if 0 |
| /* Old rtti stuff. */ |
| tree __baselist_desc_type_node; |
| tree __i_desc_type_node, __m_desc_type_node; |
| tree __t_desc_array_type, __i_desc_array_type, __m_desc_array_type; |
| #endif |
| tree __t_desc_type_node; |
| #if 0 |
| tree __tp_desc_type_node; |
| #endif |
| tree __access_mode_type_node; |
| tree __bltn_desc_type_node, __user_desc_type_node, __class_desc_type_node; |
| tree __ptr_desc_type_node, __attr_desc_type_node, __func_desc_type_node; |
| tree __ptmf_desc_type_node, __ptmd_desc_type_node; |
| #if 0 |
| /* Not needed yet? May be needed one day? */ |
| tree __bltn_desc_array_type, __user_desc_array_type, __class_desc_array_type; |
| tree __ptr_desc_array_type, __attr_dec_array_type, __func_desc_array_type; |
| tree __ptmf_desc_array_type, __ptmd_desc_array_type; |
| #endif |
| |
| /* Indicates that there is a type value in some namespace, although |
| that is not necessarily in scope at the moment. */ |
| |
| static tree global_type_node; |
| |
| tree class_star_type_node; |
| tree class_type_node, record_type_node, union_type_node, enum_type_node; |
| tree unknown_type_node; |
| tree opaque_type_node, signature_type_node; |
| tree sigtable_entry_type; |
| |
| /* Array type `vtable_entry_type[]' */ |
| tree vtbl_type_node; |
| |
| /* namespace std */ |
| tree std_node; |
| int in_std = 0; |
| |
| /* Expect only namespace names now. */ |
| static int only_namespace_names; |
| |
| /* In a destructor, the point at which all derived class destroying |
| has been done, just before any base class destroying will be done. */ |
| |
| tree dtor_label; |
| |
| /* In a destructor, the last insn emitted after the start of the |
| function and the parms. */ |
| |
| static rtx last_dtor_insn; |
| |
| /* In a constructor, the last insn emitted after the start of the |
| function and the parms, the exception specification and any |
| function-try-block. The constructor initializers are emitted after |
| this insn. */ |
| |
| static rtx last_parm_cleanup_insn; |
| |
| /* In a constructor, the point at which we are ready to return |
| the pointer to the initialized object. */ |
| |
| tree ctor_label; |
| |
| /* A FUNCTION_DECL which can call `abort'. Not necessarily the |
| one that the user will declare, but sufficient to be called |
| by routines that want to abort the program. */ |
| |
| tree abort_fndecl; |
| |
| extern rtx cleanup_label, return_label; |
| |
| /* If original DECL_RESULT of current function was a register, |
| but due to being an addressable named return value, would up |
| on the stack, this variable holds the named return value's |
| original location. */ |
| static rtx original_result_rtx; |
| |
| /* Sequence of insns which represents base initialization. */ |
| tree base_init_expr; |
| |
| /* C++: Keep these around to reduce calls to `get_identifier'. |
| Identifiers for `this' in member functions and the auto-delete |
| parameter for destructors. */ |
| tree this_identifier, in_charge_identifier; |
| tree ctor_identifier, dtor_identifier; |
| /* Used in pointer to member functions, in vtables, and in sigtables. */ |
| tree pfn_identifier, index_identifier, delta_identifier, delta2_identifier; |
| tree pfn_or_delta2_identifier, tag_identifier; |
| tree vt_off_identifier; |
| |
| struct named_label_list |
| { |
| struct binding_level *binding_level; |
| tree names_in_scope; |
| tree label_decl; |
| char *filename_o_goto; |
| int lineno_o_goto; |
| struct named_label_list *next; |
| }; |
| |
| /* A list (chain of TREE_LIST nodes) of named label uses. |
| The TREE_PURPOSE field is the list of variables defined |
| in the label's scope defined at the point of use. |
| The TREE_VALUE field is the LABEL_DECL used. |
| The TREE_TYPE field holds `current_binding_level' at the |
| point of the label's use. |
| |
| BWAHAHAAHAHahhahahahaah. No, no, no, said the little chicken. |
| |
| Look at the pretty struct named_label_list. See the pretty struct |
| with the pretty named fields that describe what they do. See the |
| pretty lack of gratuitous casts. Notice the code got a lot cleaner. |
| |
| Used only for jumps to as-yet undefined labels, since |
| jumps to defined labels can have their validity checked |
| by stmt.c. */ |
| |
| static struct named_label_list *named_label_uses = NULL; |
| |
| /* A list of objects which have constructors or destructors |
| which reside in the global scope. The decl is stored in |
| the TREE_VALUE slot and the initializer is stored |
| in the TREE_PURPOSE slot. */ |
| tree static_aggregates; |
| |
| /* -- end of C++ */ |
| |
| /* Two expressions that are constants with value zero. |
| The first is of type `int', the second of type `void *'. */ |
| |
| tree integer_zero_node; |
| tree null_pointer_node; |
| |
| /* The value for __null (NULL), either of type `void *' or, with -ansi, |
| an integer type of the same size. */ |
| |
| tree null_node; |
| |
| /* A node for the integer constants 1, 2, and 3. */ |
| |
| tree integer_one_node, integer_two_node, integer_three_node; |
| |
| /* While defining an enum type, this is 1 plus the last enumerator |
| constant value. */ |
| |
| static tree enum_next_value; |
| |
| /* Nonzero means that there was overflow computing enum_next_value. */ |
| |
| static int enum_overflow; |
| |
| /* Parsing a function declarator leaves a list of parameter names |
| or a chain or parameter decls here. */ |
| |
| tree last_function_parms; |
| |
| /* Parsing a function declarator leaves here a chain of structure |
| and enum types declared in the parmlist. */ |
| |
| static tree last_function_parm_tags; |
| |
| /* After parsing the declarator that starts a function definition, |
| `start_function' puts here the list of parameter names or chain of decls. |
| `store_parm_decls' finds it here. */ |
| |
| static tree current_function_parms; |
| |
| /* Similar, for last_function_parm_tags. */ |
| static tree current_function_parm_tags; |
| |
| /* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function |
| that have names. Here so we can clear out their names' definitions |
| at the end of the function. */ |
| |
| static tree named_labels; |
| |
| /* A list of LABEL_DECLs from outer contexts that are currently shadowed. */ |
| |
| static tree shadowed_labels; |
| |
| /* The FUNCTION_DECL for the function currently being compiled, |
| or 0 if between functions. */ |
| tree current_function_decl; |
| |
| /* Set to 0 at beginning of a function definition, set to 1 if |
| a return statement that specifies a return value is seen. */ |
| |
| int current_function_returns_value; |
| |
| /* Set to 0 at beginning of a function definition, set to 1 if |
| a return statement with no argument is seen. */ |
| |
| int current_function_returns_null; |
| |
| /* Set to 0 at beginning of a function definition, and whenever |
| a label (case or named) is defined. Set to value of expression |
| returned from function when that value can be transformed into |
| a named return value. */ |
| |
| tree current_function_return_value; |
| |
| /* 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 means give `double' the same size as `float'. */ |
| |
| extern int flag_short_double; |
| |
| /* Nonzero means don't recognize any builtin functions. */ |
| |
| extern int flag_no_builtin; |
| |
| /* Nonzero means don't recognize the non-ANSI builtin functions. |
| -ansi sets this. */ |
| |
| extern int flag_no_nonansi_builtin; |
| |
| /* Nonzero means enable obscure ANSI features and disable GNU extensions |
| that might cause ANSI-compliant code to be miscompiled. */ |
| |
| extern int flag_ansi; |
| |
| /* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes) |
| objects. */ |
| extern int flag_huge_objects; |
| |
| /* Nonzero if we want to conserve space in the .o files. We do this |
| by putting uninitialized data and runtime initialized data into |
| .common instead of .data at the expense of not flagging multiple |
| definitions. */ |
| extern int flag_conserve_space; |
| |
| /* Pointers to the base and current top of the language name stack. */ |
| |
| extern tree *current_lang_base, *current_lang_stack; |
| |
| /* C and C++ flags are in decl2.c. */ |
| |
| /* Set to 0 at beginning of a constructor, set to 1 |
| if that function does an allocation before referencing its |
| instance variable. */ |
| static int current_function_assigns_this; |
| int current_function_just_assigned_this; |
| |
| /* Set to 0 at beginning of a function. Set non-zero when |
| store_parm_decls is called. Don't call store_parm_decls |
| if this flag is non-zero! */ |
| int current_function_parms_stored; |
| |
| /* Flag used when debugging spew.c */ |
| |
| extern int spew_debug; |
| |
| /* This is a copy of the class_shadowed list of the previous class binding |
| contour when at global scope. It's used to reset IDENTIFIER_CLASS_VALUEs |
| when entering another class scope (i.e. a cache miss). */ |
| extern tree previous_class_values; |
| |
| /* A expression of value 0 with the same precision as a sizetype |
| node, but signed. */ |
| tree signed_size_zero_node; |
| |
| |
| /* Allocate a level of searching. */ |
| |
| static |
| struct stack_level * |
| push_decl_level (stack, obstack) |
| struct stack_level *stack; |
| struct obstack *obstack; |
| { |
| struct stack_level tem; |
| tem.prev = stack; |
| |
| return push_stack_level (obstack, (char *)&tem, sizeof (tem)); |
| } |
| |
| /* For each binding contour we allocate a binding_level structure |
| which records the names defined in that contour. |
| Contours include: |
| 0) the global one |
| 1) one for each function definition, |
| where internal declarations of the parameters appear. |
| 2) one for each compound statement, |
| to record its declarations. |
| |
| The current meaning of a name can be found by searching the levels |
| from the current one out to the global one. |
| |
| Off to the side, may be the class_binding_level. This exists only |
| to catch class-local declarations. It is otherwise nonexistent. |
| |
| Also there may be binding levels that catch cleanups that must be |
| run when exceptions occur. */ |
| |
| /* 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; |
| |
| /* A list of USING_DECL nodes. */ |
| tree usings; |
| |
| /* A list of used namespaces. PURPOSE is the namespace, |
| VALUE the common ancestor with this binding_level's namespace. */ |
| tree using_directives; |
| |
| /* 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; |
| |
| /* List of decls in `names' that have incomplete |
| structure or union types. */ |
| tree incomplete; |
| |
| /* List of VAR_DECLS saved from a previous for statement. |
| These would be dead in ANSI-conforming code, but might |
| be referenced in ARM-era code. */ |
| tree dead_vars_from_for; |
| |
| /* 1 for the level that holds the parameters of a function. |
| 2 for the level that holds a class declaration. |
| 3 for levels that hold parameter declarations. */ |
| unsigned parm_flag : 4; |
| |
| /* 1 means make a BLOCK for this level regardless of all else. |
| 2 for temporary binding contours created by the compiler. */ |
| unsigned keep : 3; |
| |
| /* Nonzero if this level "doesn't exist" for tags. */ |
| unsigned tag_transparent : 1; |
| |
| /* Nonzero if this level can safely have additional |
| cleanup-needing variables added to it. */ |
| unsigned more_cleanups_ok : 1; |
| unsigned have_cleanups : 1; |
| |
| /* Nonzero if this level is for storing the decls for template |
| parameters and generic decls; these decls will be discarded and |
| replaced with a TEMPLATE_DECL. */ |
| unsigned pseudo_global : 1; |
| |
| /* This is set for a namespace binding level. */ |
| unsigned namespace_p : 1; |
| |
| /* True if this level is that of a for-statement where we need to |
| worry about ambiguous (ARM or ANSI) scope rules. */ |
| unsigned is_for_scope : 1; |
| |
| /* Two bits left for this word. */ |
| |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| /* Binding depth at which this level began. */ |
| unsigned binding_depth; |
| #endif /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| }; |
| |
| #define NULL_BINDING_LEVEL ((struct binding_level *) NULL) |
| |
| /* The (non-class) binding level currently in effect. */ |
| |
| static struct binding_level *current_binding_level; |
| |
| /* The binding level of the current class, if any. */ |
| |
| static struct binding_level *class_binding_level; |
| |
| /* The current (class or non-class) binding level currently in effect. */ |
| |
| #define inner_binding_level \ |
| (class_binding_level ? class_binding_level : current_binding_level) |
| |
| /* A chain of binding_level structures awaiting reuse. */ |
| |
| static struct binding_level *free_binding_level; |
| |
| /* The outermost binding level, for names of file scope. |
| This is created when the compiler is started and exists |
| through the entire run. */ |
| |
| static struct binding_level *global_binding_level; |
| |
| /* Binding level structures are initialized by copying this one. */ |
| |
| static struct binding_level clear_binding_level; |
| |
| /* Nonzero means unconditionally make a BLOCK for the next level pushed. */ |
| |
| static int keep_next_level_flag; |
| |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| static int binding_depth = 0; |
| static int is_class_level = 0; |
| |
| static void |
| indent () |
| { |
| register unsigned i; |
| |
| for (i = 0; i < binding_depth*2; i++) |
| putc (' ', stderr); |
| } |
| #endif /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| |
| static tree pushdecl_with_scope PROTO((tree, struct binding_level *)); |
| |
| static void |
| push_binding_level (newlevel, tag_transparent, keep) |
| struct binding_level *newlevel; |
| int tag_transparent, keep; |
| { |
| /* Add this level to the front of the chain (stack) of levels that |
| are active. */ |
| *newlevel = clear_binding_level; |
| if (class_binding_level) |
| { |
| newlevel->level_chain = class_binding_level; |
| class_binding_level = (struct binding_level *)0; |
| } |
| else |
| { |
| newlevel->level_chain = current_binding_level; |
| } |
| current_binding_level = newlevel; |
| newlevel->tag_transparent = tag_transparent; |
| newlevel->more_cleanups_ok = 1; |
| newlevel->keep = keep; |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| newlevel->binding_depth = binding_depth; |
| indent (); |
| fprintf (stderr, "push %s level 0x%08x line %d\n", |
| (is_class_level) ? "class" : "block", newlevel, lineno); |
| is_class_level = 0; |
| binding_depth++; |
| #endif /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| } |
| |
| static void |
| pop_binding_level () |
| { |
| if (class_binding_level) |
| current_binding_level = class_binding_level; |
| |
| if (global_binding_level) |
| { |
| /* Cannot pop a level, if there are none left to pop. */ |
| if (current_binding_level == global_binding_level) |
| my_friendly_abort (123); |
| } |
| /* Pop the current level, and free the structure for reuse. */ |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| binding_depth--; |
| indent (); |
| fprintf (stderr, "pop %s level 0x%08x line %d\n", |
| (is_class_level) ? "class" : "block", |
| current_binding_level, lineno); |
| if (is_class_level != (current_binding_level == class_binding_level)) |
| { |
| indent (); |
| fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n"); |
| } |
| is_class_level = 0; |
| #endif /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| { |
| register struct binding_level *level = current_binding_level; |
| current_binding_level = current_binding_level->level_chain; |
| level->level_chain = free_binding_level; |
| #if 0 /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| if (level->binding_depth != binding_depth) |
| abort (); |
| #endif /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| free_binding_level = level; |
| |
| class_binding_level = current_binding_level; |
| if (class_binding_level->parm_flag != 2) |
| class_binding_level = 0; |
| while (current_binding_level->parm_flag == 2) |
| current_binding_level = current_binding_level->level_chain; |
| } |
| } |
| |
| static void |
| suspend_binding_level () |
| { |
| if (class_binding_level) |
| current_binding_level = class_binding_level; |
| |
| if (global_binding_level) |
| { |
| /* Cannot suspend a level, if there are none left to suspend. */ |
| if (current_binding_level == global_binding_level) |
| my_friendly_abort (123); |
| } |
| /* Suspend the current level. */ |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| binding_depth--; |
| indent (); |
| fprintf (stderr, "suspend %s level 0x%08x line %d\n", |
| (is_class_level) ? "class" : "block", |
| current_binding_level, lineno); |
| if (is_class_level != (current_binding_level == class_binding_level)) |
| { |
| indent (); |
| fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n"); |
| } |
| is_class_level = 0; |
| #endif /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| { |
| current_binding_level = current_binding_level->level_chain; |
| class_binding_level = current_binding_level; |
| if (class_binding_level->parm_flag != 2) |
| class_binding_level = 0; |
| while (current_binding_level->parm_flag == 2) |
| current_binding_level = current_binding_level->level_chain; |
| } |
| } |
| |
| static void |
| resume_binding_level (b) |
| struct binding_level *b; |
| { |
| /* Resuming binding levels is meant only for namespaces, |
| and those cannot nest into classes. */ |
| my_friendly_assert(!class_binding_level, 386); |
| /* Also, resuming a non-directly nested namespace is a no-no. */ |
| my_friendly_assert(b->level_chain == current_binding_level, 386); |
| current_binding_level = b; |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| b->binding_depth = binding_depth; |
| indent (); |
| fprintf (stderr, "resume %s level 0x%08x line %d\n", |
| (is_class_level) ? "class" : "block", b, lineno); |
| is_class_level = 0; |
| binding_depth++; |
| #endif /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| } |
| |
| /* Create a new `struct binding_level'. */ |
| |
| static |
| struct binding_level * |
| make_binding_level () |
| { |
| /* NOSTRICT */ |
| return (struct binding_level *) xmalloc (sizeof (struct binding_level)); |
| } |
| |
| /* Nonzero if we are currently in the global binding level. */ |
| |
| int |
| global_bindings_p () |
| { |
| return current_binding_level == global_binding_level; |
| } |
| |
| /* Nonzero if we are currently in a toplevel binding level. This |
| means either the global binding level or a namespace in a toplevel |
| binding level. |
| Since there are no non-toplevel namespace levels, this really |
| means any namespace or pseudo-global level. */ |
| |
| int |
| toplevel_bindings_p () |
| { |
| return current_binding_level->namespace_p |
| || current_binding_level->pseudo_global; |
| } |
| |
| /* Nonzero if this is a namespace scope. */ |
| |
| static int |
| namespace_bindings_p () |
| { |
| return current_binding_level->namespace_p; |
| } |
| |
| void |
| keep_next_level () |
| { |
| keep_next_level_flag = 1; |
| } |
| |
| /* Nonzero if the current level needs to have a BLOCK made. */ |
| |
| int |
| kept_level_p () |
| { |
| return (current_binding_level->blocks != NULL_TREE |
| || current_binding_level->keep |
| || current_binding_level->names != NULL_TREE |
| || (current_binding_level->tags != NULL_TREE |
| && !current_binding_level->tag_transparent)); |
| } |
| |
| /* Identify this binding level as a level of parameters. */ |
| |
| void |
| declare_parm_level () |
| { |
| current_binding_level->parm_flag = 1; |
| } |
| |
| void |
| declare_pseudo_global_level () |
| { |
| current_binding_level->pseudo_global = 1; |
| } |
| |
| static void |
| declare_namespace_level () |
| { |
| current_binding_level->namespace_p = 1; |
| } |
| |
| int |
| pseudo_global_level_p () |
| { |
| return current_binding_level->pseudo_global; |
| } |
| |
| void |
| set_class_shadows (shadows) |
| tree shadows; |
| { |
| class_binding_level->class_shadowed = shadows; |
| } |
| |
| /* Enter a new binding level. |
| If TAG_TRANSPARENT is nonzero, do so only for the name space of variables, |
| not for that of tags. */ |
| |
| void |
| pushlevel (tag_transparent) |
| int tag_transparent; |
| { |
| register struct binding_level *newlevel = NULL_BINDING_LEVEL; |
| |
| /* If this is the top level of a function, |
| just make sure that NAMED_LABELS is 0. |
| They should have been set to 0 at the end of the previous function. */ |
| |
| if (current_binding_level == global_binding_level) |
| my_friendly_assert (named_labels == NULL_TREE, 134); |
| |
| /* Reuse or create a struct for this binding level. */ |
| |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| if (0) |
| #else /* !defined(DEBUG_CP_BINDING_LEVELS) */ |
| if (free_binding_level) |
| #endif /* !defined(DEBUG_CP_BINDING_LEVELS) */ |
| { |
| newlevel = free_binding_level; |
| free_binding_level = free_binding_level->level_chain; |
| } |
| else |
| { |
| newlevel = make_binding_level (); |
| } |
| |
| push_binding_level (newlevel, tag_transparent, keep_next_level_flag); |
| GNU_xref_start_scope ((HOST_WIDE_INT) newlevel); |
| keep_next_level_flag = 0; |
| } |
| |
| void |
| note_level_for_for () |
| { |
| current_binding_level->is_for_scope = 1; |
| } |
| |
| void |
| pushlevel_temporary (tag_transparent) |
| int tag_transparent; |
| { |
| pushlevel (tag_transparent); |
| current_binding_level->keep = 2; |
| clear_last_expr (); |
| |
| /* Note we don't call push_momentary() here. Otherwise, it would cause |
| cleanups to be allocated on the momentary obstack, and they will be |
| overwritten by the next statement. */ |
| |
| expand_start_bindings (0); |
| } |
| |
| /* 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 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); |
| |
| if (current_binding_level->keep == 1) |
| keep = 1; |
| |
| /* Get the decls in the order they were written. |
| Usually current_binding_level->names is in reverse order. |
| But parameter decls were previously put in forward order. */ |
| |
| if (reverse) |
| current_binding_level->names |
| = decls = nreverse (current_binding_level->names); |
| else |
| decls = current_binding_level->names; |
| |
| /* Output any nested inline functions within this block |
| if they weren't already output. */ |
| |
| for (decl = decls; decl; decl = TREE_CHAIN (decl)) |
| if (TREE_CODE (decl) == FUNCTION_DECL |
| && ! TREE_ASM_WRITTEN (decl) |
| && DECL_INITIAL (decl) != NULL_TREE |
| && TREE_ADDRESSABLE (decl) |
| && decl_function_context (decl) == current_function_decl) |
| { |
| /* If this decl was copied from a file-scope decl |
| on account of a block-scope extern decl, |
| propagate TREE_ADDRESSABLE to the file-scope decl. */ |
| if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE) |
| TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; |
| else |
| { |
| push_function_context (); |
| output_inline_function (decl); |
| pop_function_context (); |
| } |
| } |
| |
| /* If there were any declarations or structure tags in that level, |
| or if this level is a function body, |
| create a BLOCK to record them for the life of this function. */ |
| |
| block = NULL_TREE; |
| block_previously_created = (current_binding_level->this_block != NULL_TREE); |
| if (block_previously_created) |
| block = current_binding_level->this_block; |
| else if (keep == 1 || functionbody) |
| block = make_node (BLOCK); |
| if (block != NULL_TREE) |
| { |
| if (block_previously_created) |
| { |
| if (decls || tags || subblocks) |
| { |
| if (BLOCK_VARS (block) || BLOCK_TYPE_TAGS (block)) |
| { |
| warning ("internal compiler error: debugging info corrupted"); |
| } |
| BLOCK_VARS (block) = decls; |
| BLOCK_TYPE_TAGS (block) = tags; |
| |
| /* We can have previous subblocks and new subblocks when |
| doing fixup_gotos with complex cleanups. We chain the new |
| subblocks onto the end of any pre-existing subblocks. */ |
| BLOCK_SUBBLOCKS (block) = chainon (BLOCK_SUBBLOCKS (block), |
| subblocks); |
| } |
| /* If we created the block earlier on, and we are just |
| diddling it now, then it already should have a proper |
| BLOCK_END_NOTE value associated with it. */ |
| } |
| else |
| { |
| BLOCK_VARS (block) = decls; |
| BLOCK_TYPE_TAGS (block) = tags; |
| BLOCK_SUBBLOCKS (block) = subblocks; |
| /* Otherwise, for a new block, install a new BLOCK_END_NOTE value. */ |
| remember_end_note (block); |
| } |
| } |
| |
| /* In each subblock, record that this is its superior. */ |
| |
| if (keep >= 0) |
| for (link = subblocks; link; link = TREE_CHAIN (link)) |
| BLOCK_SUPERCONTEXT (link) = block; |
| |
| /* Clear out the meanings of the local variables of this level. */ |
| |
| if (current_binding_level->is_for_scope && flag_new_for_scope == 1) |
| { |
| struct binding_level *outer = current_binding_level->level_chain; |
| for (link = decls; link; link = TREE_CHAIN (link)) |
| { |
| if (TREE_CODE (link) == VAR_DECL) |
| DECL_DEAD_FOR_LOCAL (link) = 1; |
| else |
| IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE; |
| } |
| |
| /* Save declarations made in a 'for' statement so we can support pre-ANSI |
| 'for' scoping semantics. */ |
| |
| for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) |
| { |
| tree id = TREE_PURPOSE (link); |
| tree decl = IDENTIFIER_LOCAL_VALUE (id); |
| |
| if (decl && DECL_DEAD_FOR_LOCAL (decl)) |
| { |
| /* In this case keep the dead for-decl visible, |
| but remember what (if anything) it shadowed. */ |
| DECL_SHADOWED_FOR_VAR (decl) = TREE_VALUE (link); |
| TREE_CHAIN (decl) = outer->dead_vars_from_for; |
| outer->dead_vars_from_for = decl; |
| } |
| else |
| IDENTIFIER_LOCAL_VALUE (id) = TREE_VALUE (link); |
| } |
| } |
| else /* Not special for scope. */ |
| { |
| 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); |
| |
| /* We first restore the regular decls and *then* the dead_vars_from_for |
| to handle this case: |
| |
| int i; // i#1 |
| { |
| for (int i; ; ) { ...} // i#2 |
| int i; // i#3 |
| } // we are here |
| |
| In this case, we want remove the binding for i#3, restoring |
| that of i#2. Then we want to remove the binding for i#2, |
| and restore that of i#1. */ |
| |
| link = current_binding_level->dead_vars_from_for; |
| for (; link != NULL_TREE; link = TREE_CHAIN (link)) |
| { |
| tree id = DECL_NAME (link); |
| if (IDENTIFIER_LOCAL_VALUE (id) == link) |
| IDENTIFIER_LOCAL_VALUE (id) = DECL_SHADOWED_FOR_VAR (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)) |
| SET_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) |
| { |
| struct named_label_list *labels; |
| for (labels = named_label_uses; labels; labels = labels->next) |
| if (labels->binding_level == current_binding_level) |
| { |
| labels->binding_level = level_chain; |
| labels->names_in_scope = level_chain->names; |
| } |
| } |
| } |
| |
| tmp = current_binding_level->keep; |
| |
| pop_binding_level (); |
| if (functionbody) |
| DECL_INITIAL (current_function_decl) = block; |
| else if (block) |
| { |
| if (!block_previously_created) |
| current_binding_level->blocks |
| = chainon (current_binding_level->blocks, block); |
| } |
| /* If we did not make a block for the level just exited, |
| any blocks made for inner levels |
| (since they cannot be recorded as subblocks in that level) |
| must be carried forward so they will later become subblocks |
| of something else. */ |
| else if (subblocks) |
| { |
| 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) |
| { |
| expand_end_bindings (getdecls (), keep, 1); |
| /* Each and every BLOCK node created here in `poplevel' is important |
| (e.g. for proper debugging information) so if we created one |
| earlier, mark it as "used". */ |
| if (block) |
| TREE_USED (block) = 1; |
| block = poplevel (keep, reverse, real_functionbody); |
| } |
| |
| /* Each and every BLOCK node created here in `poplevel' is important |
| (e.g. for proper debugging information) so if we created one |
| earlier, mark it as "used". */ |
| if (block) |
| TREE_USED (block) = 1; |
| return block; |
| } |
| |
| /* Delete the node BLOCK from the current binding level. |
| This is used for the block inside a stmt expr ({...}) |
| so that the block can be reinserted where appropriate. */ |
| |
| void |
| delete_block (block) |
| tree block; |
| { |
| tree t; |
| if (current_binding_level->blocks == block) |
| current_binding_level->blocks = TREE_CHAIN (block); |
| for (t = current_binding_level->blocks; t;) |
| { |
| if (TREE_CHAIN (t) == block) |
| TREE_CHAIN (t) = TREE_CHAIN (block); |
| else |
| t = TREE_CHAIN (t); |
| } |
| TREE_CHAIN (block) = NULL_TREE; |
| /* Clear TREE_USED which is always set by poplevel. |
| The flag is set again if insert_block is called. */ |
| TREE_USED (block) = 0; |
| } |
| |
| /* Insert BLOCK at the end of the list of subblocks of the |
| current binding level. This is used when a BIND_EXPR is expanded, |
| to handle the BLOCK node inside the BIND_EXPR. */ |
| |
| void |
| insert_block (block) |
| tree block; |
| { |
| TREE_USED (block) = 1; |
| current_binding_level->blocks |
| = chainon (current_binding_level->blocks, block); |
| } |
| |
| /* Set the BLOCK node for the innermost scope |
| (the one we are currently in). */ |
| |
| void |
| set_block (block) |
| register tree block; |
| { |
| current_binding_level->this_block = block; |
| } |
| |
| /* Do a pushlevel for class declarations. */ |
| |
| void |
| pushlevel_class () |
| { |
| register struct binding_level *newlevel; |
| |
| /* Reuse or create a struct for this binding level. */ |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| if (0) |
| #else /* !defined(DEBUG_CP_BINDING_LEVELS) */ |
| if (free_binding_level) |
| #endif /* !defined(DEBUG_CP_BINDING_LEVELS) */ |
| { |
| newlevel = free_binding_level; |
| free_binding_level = free_binding_level->level_chain; |
| } |
| else |
| { |
| newlevel = make_binding_level (); |
| } |
| |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| is_class_level = 1; |
| #endif /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| |
| push_binding_level (newlevel, 0, 0); |
| |
| decl_stack = push_decl_level (decl_stack, &decl_obstack); |
| class_binding_level = current_binding_level; |
| class_binding_level->parm_flag = 2; |
| /* We have just pushed into a new binding level. Now, fake out the rest |
| of the compiler. Set the `current_binding_level' back to point to |
| the most closely containing non-class binding level. */ |
| do |
| { |
| current_binding_level = current_binding_level->level_chain; |
| } |
| while (current_binding_level->parm_flag == 2); |
| } |
| |
| /* ...and a poplevel for class declarations. FORCE is used to force |
| clearing out of CLASS_VALUEs after a class definition. */ |
| |
| tree |
| poplevel_class (force) |
| int force; |
| { |
| register struct binding_level *level = class_binding_level; |
| tree block = NULL_TREE; |
| tree shadowed; |
| |
| my_friendly_assert (level != 0, 354); |
| |
| decl_stack = pop_stack_level (decl_stack); |
| 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 IDENTIFIER_CLASS_VALUE to NULL_TREE, since first of all this slot |
| shouldn't even be used when current_class_type isn't set, and second, |
| if we don't touch it here, we're able to use the cache effect if the |
| next time we're entering a class scope, it is the same class. */ |
| if (current_class_depth != 1 || force) |
| for (shadowed = level->class_shadowed; |
| shadowed; |
| shadowed = TREE_CHAIN (shadowed)) |
| IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed); |
| else |
| /* Remember to save what IDENTIFIER's were bound in this scope so we |
| can recover from cache misses. */ |
| { |
| previous_class_type = current_class_type; |
| previous_class_values = class_binding_level->class_shadowed; |
| } |
| for (shadowed = level->type_shadowed; |
| shadowed; |
| shadowed = TREE_CHAIN (shadowed)) |
| SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed), TREE_VALUE (shadowed)); |
| |
| GNU_xref_end_scope ((HOST_WIDE_INT) class_binding_level, |
| (HOST_WIDE_INT) class_binding_level->level_chain, |
| class_binding_level->parm_flag, |
| class_binding_level->keep); |
| |
| if (class_binding_level->parm_flag != 2) |
| class_binding_level = (struct binding_level *)0; |
| |
| /* Now, pop out of the binding level which we created up in the |
| `pushlevel_class' routine. */ |
| #if defined(DEBUG_CP_BINDING_LEVELS) |
| is_class_level = 1; |
| #endif /* defined(DEBUG_CP_BINDING_LEVELS) */ |
| |
| pop_binding_level (); |
| |
| return block; |
| } |
| |
| /* For debugging. */ |
| static int no_print_functions = 0; |
| static int no_print_builtins = 0; |
| |
| void |
| print_binding_level (lvl) |
| struct binding_level *lvl; |
| { |
| tree t; |
| int i = 0, len; |
| fprintf (stderr, " blocks="); |
| fprintf (stderr, HOST_PTR_PRINTF, lvl->blocks); |
| fprintf (stderr, " n_incomplete=%d parm_flag=%d keep=%d", |
| list_length (lvl->incomplete), lvl->parm_flag, lvl->keep); |
| if (lvl->tag_transparent) |
| fprintf (stderr, " tag-transparent"); |
| if (lvl->more_cleanups_ok) |
| fprintf (stderr, " more-cleanups-ok"); |
| if (lvl->have_cleanups) |
| fprintf (stderr, " have-cleanups"); |
| fprintf (stderr, "\n"); |
| if (lvl->names) |
| { |
| fprintf (stderr, " names:\t"); |
| /* We can probably fit 3 names to a line? */ |
| for (t = lvl->names; t; t = TREE_CHAIN (t)) |
| { |
| if (no_print_functions && (TREE_CODE (t) == FUNCTION_DECL)) |
| continue; |
| if (no_print_builtins |
| && (TREE_CODE (t) == TYPE_DECL) |
| && (!strcmp (DECL_SOURCE_FILE (t),"<built-in>"))) |
| continue; |
| |
| /* Function decls tend to have longer names. */ |
| if (TREE_CODE (t) == FUNCTION_DECL) |
| len = 3; |
| else |
| len = 2; |
| i += len; |
| if (i > 6) |
| { |
| fprintf (stderr, "\n\t"); |
| i = len; |
| } |
| print_node_brief (stderr, "", t, 0); |
| if (t == error_mark_node) |
| break; |
| } |
| if (i) |
| fprintf (stderr, "\n"); |
| } |
| if (lvl->tags) |
| { |
| fprintf (stderr, " tags:\t"); |
| i = 0; |
| for (t = lvl->tags; t; t = TREE_CHAIN (t)) |
| { |
| if (TREE_PURPOSE (t) == NULL_TREE) |
| len = 3; |
| else if (TREE_PURPOSE (t) == TYPE_IDENTIFIER (TREE_VALUE (t))) |
| len = 2; |
| else |
| len = 4; |
| i += len; |
| if (i > 5) |
| { |
| fprintf (stderr, "\n\t"); |
| i = len; |
| } |
| if (TREE_PURPOSE (t) == NULL_TREE) |
| { |
| print_node_brief (stderr, "<unnamed-typedef", TREE_VALUE (t), 0); |
| fprintf (stderr, ">"); |
| } |
| else if (TREE_PURPOSE (t) == TYPE_IDENTIFIER (TREE_VALUE (t))) |
| print_node_brief (stderr, "", TREE_VALUE (t), 0); |
| else |
| { |
| print_node_brief (stderr, "<typedef", TREE_PURPOSE (t), 0); |
| print_node_brief (stderr, "", TREE_VALUE (t), 0); |
| fprintf (stderr, ">"); |
| } |
| } |
| if (i) |
| fprintf (stderr, "\n"); |
| } |
| if (lvl->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)) |
| { |
| fprintf (stderr, " %s ", IDENTIFIER_POINTER (TREE_PURPOSE (t))); |
| } |
| fprintf (stderr, "\n"); |
| } |
| } |
| |
| void |
| print_other_binding_stack (stack) |
| struct binding_level *stack; |
| { |
| struct binding_level *level; |
| for (level = stack; level != global_binding_level; level = level->level_chain) |
| { |
| fprintf (stderr, "binding level "); |
| fprintf (stderr, HOST_PTR_PRINTF, level); |
| fprintf (stderr, "\n"); |
| print_binding_level (level); |
| } |
| } |
| |
| void |
| print_binding_stack () |
| { |
| struct binding_level *b; |
| fprintf (stderr, "current_binding_level="); |
| fprintf (stderr, HOST_PTR_PRINTF, current_binding_level); |
| fprintf (stderr, "\nclass_binding_level="); |
| fprintf (stderr, HOST_PTR_PRINTF, class_binding_level); |
| fprintf (stderr, "\nglobal_binding_level="); |
| fprintf (stderr, HOST_PTR_PRINTF, global_binding_level); |
| fprintf (stderr, "\n"); |
| if (class_binding_level) |
| { |
| for (b = class_binding_level; b; b = b->level_chain) |
| if (b == current_binding_level) |
| break; |
| if (b) |
| b = class_binding_level; |
| else |
| b = current_binding_level; |
| } |
| else |
| b = current_binding_level; |
| print_other_binding_stack (b); |
| fprintf (stderr, "global:\n"); |
| print_binding_level (global_binding_level); |
| } |
| |
| /* Namespace binding access routines: The namespace_bindings field of |
| the identifier is polymorphic, with three possible values: |
| NULL_TREE, a list of CPLUS_BINDINGS, or any other tree_node |
| indicating the BINDING_VALUE of global_namespace. */ |
| |
| /* Check whether the a binding for the name to scope is known. |
| Assumes that the bindings of the name are already a list |
| of bindings. Returns the binding found, or NULL_TREE. */ |
| |
| static tree |
| find_binding (name, scope) |
| tree name; |
| tree scope; |
| { |
| tree iter, prev = NULL_TREE; |
| |
| scope = ORIGINAL_NAMESPACE (scope); |
| |
| for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name); iter; |
| iter = TREE_CHAIN (iter)) |
| { |
| my_friendly_assert (TREE_CODE (iter) == CPLUS_BINDING, 374); |
| if (BINDING_SCOPE (iter) == scope) |
| { |
| /* Move binding found to the fron of the list, so |
| subsequent lookups will find it faster. */ |
| if (prev) |
| { |
| TREE_CHAIN (prev) = TREE_CHAIN (iter); |
| TREE_CHAIN (iter) = IDENTIFIER_NAMESPACE_BINDINGS (name); |
| IDENTIFIER_NAMESPACE_BINDINGS (name) = iter; |
| } |
| return iter; |
| } |
| prev = iter; |
| } |
| return NULL_TREE; |
| } |
| |
| /* Always returns a binding for name in scope. If the |
| namespace_bindings is not a list, convert it to one first. |
| If no binding is found, make a new one. */ |
| |
| tree |
| binding_for_name (name, scope) |
| tree name; |
| tree scope; |
| { |
| tree b = IDENTIFIER_NAMESPACE_BINDINGS (name); |
| tree result; |
| |
| scope = ORIGINAL_NAMESPACE (scope); |
| |
| if (b && TREE_CODE (b) != CPLUS_BINDING) |
| { |
| /* Get rid of optimization for global scope. */ |
| IDENTIFIER_NAMESPACE_BINDINGS (name) = NULL_TREE; |
| BINDING_VALUE (binding_for_name (name, global_namespace)) = b; |
| b = IDENTIFIER_NAMESPACE_BINDINGS (name); |
| } |
| if (b && (result = find_binding (name, scope))) |
| return result; |
| /* Not found, make a new permanent one. */ |
| push_obstacks (&permanent_obstack, &permanent_obstack); |
| result = make_node (CPLUS_BINDING); |
| TREE_CHAIN (result) = b; |
| IDENTIFIER_NAMESPACE_BINDINGS (name) = result; |
| BINDING_SCOPE (result) = scope; |
| BINDING_TYPE (result) = NULL_TREE; |
| BINDING_VALUE (result) = NULL_TREE; |
| pop_obstacks (); |
| return result; |
| } |
| |
| /* Return the binding value for name in scope, considering that |
| namespace_binding may or may not be a list of CPLUS_BINDINGS. */ |
| |
| tree |
| namespace_binding (name, scope) |
| tree name; |
| tree scope; |
| { |
| tree b = IDENTIFIER_NAMESPACE_BINDINGS (name); |
| if (b == NULL_TREE) |
| return NULL_TREE; |
| if (scope == NULL_TREE) |
| scope = global_namespace; |
| if (TREE_CODE (b) != CPLUS_BINDING) |
| return (scope == global_namespace) ? b : NULL_TREE; |
| name = find_binding (name,scope); |
| if (name == NULL_TREE) |
| return name; |
| return BINDING_VALUE (name); |
| } |
| |
| /* Set the binding value for name in scope. If modifying the binding |
| of global_namespace is attempted, try to optimize it. */ |
| |
| void |
| set_namespace_binding (name, scope, val) |
| tree name; |
| tree scope; |
| tree val; |
| { |
| tree b; |
| |
| if (scope == NULL_TREE) |
| scope = global_namespace; |
| |
| if (scope == global_namespace) |
| { |
| b = IDENTIFIER_NAMESPACE_BINDINGS (name); |
| if (b == NULL_TREE || TREE_CODE (b) != CPLUS_BINDING) |
| { |
| IDENTIFIER_NAMESPACE_BINDINGS (name) = val; |
| return; |
| } |
| } |
| b = binding_for_name (name, scope); |
| BINDING_VALUE (b) = val; |
| } |
| |
| /* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we |
| select a name that is unique to this compilation unit. */ |
| |
| void |
| push_namespace (name) |
| tree name; |
| { |
| tree d; |
| int need_new = 1; |
| int implicit_use = 0; |
| int global = 0; |
| if (!global_namespace) |
| { |
| /* This must be ::. */ |
| my_friendly_assert (name == get_identifier ("::"), 377); |
| global = 1; |
| } |
| else if (!name) |
| { |
| /* The name of anonymous namespace is unique for the translation |
| unit. */ |
| static tree anon_name = NULL_TREE; |
| if (!anon_name) |
| anon_name = get_file_function_name ('N'); |
| name = anon_name; |
| d = IDENTIFIER_NAMESPACE_VALUE (name); |
| if (d) |
| /* Reopening anonymous namespace. */ |
| need_new = 0; |
| implicit_use = 1; |
| } |
| else if (current_namespace == global_namespace |
| && name == DECL_NAME (std_node)) |
| { |
| in_std++; |
| return; |
| } |
| else |
| { |
| /* Check whether this is an extended namespace definition. */ |
| d = IDENTIFIER_NAMESPACE_VALUE (name); |
| if (d != NULL_TREE && TREE_CODE (d) == NAMESPACE_DECL) |
| { |
| need_new = 0; |
| if (DECL_NAMESPACE_ALIAS (d)) |
| { |
| cp_error ("namespace alias `%D' not allowed here, assuming `%D'", |
| d, DECL_NAMESPACE_ALIAS (d)); |
| d = DECL_NAMESPACE_ALIAS (d); |
| } |
| } |
| } |
| |
| if (need_new) |
| { |
| /* Make a new namespace, binding the name to it. */ |
| d = build_lang_decl (NAMESPACE_DECL, name, void_type_node); |
| /* The global namespace is not pushed, and the global binding |
| level is set elsewhere. */ |
| if (!global) |
| { |
| d = pushdecl (d); |
| pushlevel (0); |
| declare_namespace_level (); |
| NAMESPACE_LEVEL (d) = current_binding_level; |
| } |
| } |
| else |
| resume_binding_level (NAMESPACE_LEVEL (d)); |
| |
| if (implicit_use) |
| do_using_directive (d); |
| /* Enter the name space. */ |
| current_namespace = d; |
| } |
| |
| /* Pop from the scope of the current namespace. */ |
| |
| void |
| pop_namespace () |
| { |
| if (current_namespace == global_namespace) |
| { |
| my_friendly_assert (in_std>0, 980421); |
| in_std--; |
| return; |
| } |
| current_namespace = CP_DECL_CONTEXT (current_namespace); |
| /* The binding level is not popped, as it might be re-opened later. */ |
| suspend_binding_level (); |
| } |
| |
| /* Concatenate the binding levels of all namespaces. */ |
| |
| void |
| cat_namespace_levels() |
| { |
| tree current; |
| tree last; |
| struct binding_level *b; |
| |
| last = NAMESPACE_LEVEL (global_namespace) -> names; |
| /* The nested namespaces appear in the names list of their ancestors. */ |
| for (current = last; current; current = TREE_CHAIN (current)) |
| { |
| if (TREE_CODE (current) != NAMESPACE_DECL |
| || DECL_NAMESPACE_ALIAS (current)) |
| continue; |
| if (!DECL_LANG_SPECIFIC (current)) |
| { |
| /* Hmm. std. */ |
| my_friendly_assert (current == std_node, 393); |
| continue; |
| } |
| b = NAMESPACE_LEVEL (current); |
| while (TREE_CHAIN (last)) |
| last = TREE_CHAIN (last); |
| TREE_CHAIN (last) = NAMESPACE_LEVEL (current) -> names; |
| } |
| } |
| |
| /* Subroutines for reverting temporarily to top-level for instantiation |
| of templates and such. We actually need to clear out the class- and |
| local-value slots of all identifiers, so that only the global values |
| are at all visible. Simply setting current_binding_level to the global |
| scope isn't enough, because more binding levels may be pushed. */ |
| struct saved_scope { |
| struct binding_level *old_binding_level; |
| tree old_bindings; |
| tree old_namespace; |
| struct saved_scope *prev; |
| tree class_name, class_type, function_decl; |
| struct binding_level *class_bindings; |
| tree *lang_base, *lang_stack, lang_name; |
| int lang_stacksize; |
| int minimal_parse_mode; |
| tree last_function_parms; |
| tree template_parms; |
| HOST_WIDE_INT processing_template_decl; |
| tree previous_class_type, previous_class_values; |
| int processing_specialization; |
| int processing_explicit_instantiation; |
| }; |
| static struct saved_scope *current_saved_scope; |
| |
| /* A chain of the binding vecs created by store_bindings. We create a |
| whole bunch of these during compilation, on permanent_obstack, so we |
| can't just throw them away. */ |
| static tree free_binding_vecs; |
| |
| static tree |
| store_bindings (names, old_bindings) |
| tree names, old_bindings; |
| { |
| tree t; |
| for (t = names; t; t = TREE_CHAIN (t)) |
| { |
| tree binding, t1, id; |
| |
| if (TREE_CODE (t) == TREE_LIST) |
| id = TREE_PURPOSE (t); |
| else |
| id = DECL_NAME (t); |
| |
| if (!id |
| || (!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; |
| |
| if (free_binding_vecs) |
| { |
| binding = free_binding_vecs; |
| free_binding_vecs = TREE_CHAIN (free_binding_vecs); |
| } |
| else |
| binding = make_tree_vec (4); |
| |
| if (id) |
| { |
| my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 135); |
| TREE_VEC_ELT (binding, 0) = id; |
| TREE_VEC_ELT (binding, 1) = REAL_IDENTIFIER_TYPE_VALUE (id); |
| TREE_VEC_ELT (binding, 2) = IDENTIFIER_LOCAL_VALUE (id); |
| TREE_VEC_ELT (binding, 3) = IDENTIFIER_CLASS_VALUE (id); |
| IDENTIFIER_LOCAL_VALUE (id) = NULL_TREE; |
| IDENTIFIER_CLASS_VALUE (id) = NULL_TREE; |
| } |
| TREE_CHAIN (binding) = old_bindings; |
| old_bindings = binding; |
| skip_it: |
| ; |
| } |
| return old_bindings; |
| } |
| |
| void |
| maybe_push_to_top_level (pseudo) |
| int pseudo; |
| { |
| extern int current_lang_stacksize; |
| struct saved_scope *s |
| = (struct saved_scope *) xmalloc (sizeof (struct saved_scope)); |
| struct binding_level *b = inner_binding_level; |
| tree old_bindings = NULL_TREE; |
| |
| if (current_function_decl) |
| push_cp_function_context (NULL_TREE); |
| |
| if (previous_class_type) |
| old_bindings = store_bindings (previous_class_values, old_bindings); |
| |
| /* Have to include global_binding_level, because class-level decls |
| aren't listed anywhere useful. */ |
| for (; b; b = b->level_chain) |
| { |
| tree t; |
| |
| /* Template IDs are inserted into the global level. If they were |
| inserted into namespace level, finish_file wouldn't find them |
| when doing pending instantiations. Therefore, don't stop at |
| namespace level, but continue until :: . */ |
| if (b == global_binding_level || (pseudo && b->pseudo_global)) |
| break; |
| |
| old_bindings = store_bindings (b->names, old_bindings); |
| /* We also need to check class_shadowed to save class-level type |
| bindings, since pushclass doesn't fill in b->names. */ |
| if (b->parm_flag == 2) |
| old_bindings = store_bindings (b->class_shadowed, old_bindings); |
| |
| /* Unwind type-value slots back to top level. */ |
| for (t = b->type_shadowed; t; t = TREE_CHAIN (t)) |
| SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (t), TREE_VALUE (t)); |
| } |
| |
| s->old_binding_level = current_binding_level; |
| current_binding_level = b; |
| |
| s->old_namespace = current_namespace; |
| s->class_name = current_class_name; |
| s->class_type = current_class_type; |
| s->function_decl = current_function_decl; |
| s->class_bindings = class_binding_level; |
| s->lang_stack = current_lang_stack; |
| s->lang_base = current_lang_base; |
| s->lang_stacksize = current_lang_stacksize; |
| s->lang_name = current_lang_name; |
| s->minimal_parse_mode = minimal_parse_mode; |
| s->last_function_parms = last_function_parms; |
| s->template_parms = current_template_parms; |
| s->processing_template_decl = processing_template_decl; |
| s->previous_class_type = previous_class_type; |
| s->previous_class_values = previous_class_values; |
| s->processing_specialization = processing_specialization; |
| s->processing_explicit_instantiation = processing_explicit_instantiation; |
| |
| current_class_name = current_class_type = NULL_TREE; |
| current_function_decl = NULL_TREE; |
| class_binding_level = (struct binding_level *)0; |
| current_lang_stacksize = 10; |
| current_lang_stack = current_lang_base |
| = (tree *) xmalloc (current_lang_stacksize * sizeof (tree)); |
| current_lang_name = lang_name_cplusplus; |
| strict_prototype = strict_prototypes_lang_cplusplus; |
| named_labels = NULL_TREE; |
| shadowed_labels = NULL_TREE; |
| minimal_parse_mode = 0; |
| previous_class_type = previous_class_values = NULL_TREE; |
| processing_specialization = 0; |
| processing_explicit_instantiation = 0; |
| current_template_parms = NULL_TREE; |
| processing_template_decl = 0; |
| current_namespace = global_namespace; |
| |
| s->prev = current_saved_scope; |
| s->old_bindings = old_bindings; |
| current_saved_scope = s; |
| |
| push_obstacks (&permanent_obstack, &permanent_obstack); |
| } |
| |
| void |
| push_to_top_level () |
| { |
| maybe_push_to_top_level (0); |
| } |
| |
| void |
| pop_from_top_level () |
| { |
| extern int current_lang_stacksize; |
| struct saved_scope *s = current_saved_scope; |
| tree t; |
| |
| /* Clear out class-level bindings cache. */ |
| if (previous_class_type) |
| { |
| popclass (-1); |
| previous_class_type = NULL_TREE; |
| } |
| |
| pop_obstacks (); |
| |
| current_binding_level = s->old_binding_level; |
| current_saved_scope = s->prev; |
| for (t = s->old_bindings; t; ) |
| { |
| tree save = t; |
| tree id = TREE_VEC_ELT (t, 0); |
| if (id) |
| { |
| SET_IDENTIFIER_TYPE_VALUE (id, TREE_VEC_ELT (t, 1)); |
| IDENTIFIER_LOCAL_VALUE (id) = TREE_VEC_ELT (t, 2); |
| IDENTIFIER_CLASS_VALUE (id) = TREE_VEC_ELT (t, 3); |
| } |
| t = TREE_CHAIN (t); |
| TREE_CHAIN (save) = free_binding_vecs; |
| free_binding_vecs = save; |
| } |
| current_namespace = s->old_namespace; |
| current_class_name = s->class_name; |
| current_class_type = s->class_type; |
| current_function_decl = s->function_decl; |
| class_binding_level = s->class_bindings; |
| free (current_lang_base); |
| current_lang_base = s->lang_base; |
| current_lang_stack = s->lang_stack; |
| current_lang_name = s->lang_name; |
| current_lang_stacksize = s->lang_stacksize; |
| if (current_lang_name == lang_name_cplusplus) |
| strict_prototype = strict_prototypes_lang_cplusplus; |
| else if (current_lang_name == lang_name_c) |
| strict_prototype = strict_prototypes_lang_c; |
| minimal_parse_mode = s->minimal_parse_mode; |
| last_function_parms = s->last_function_parms; |
| current_template_parms = s->template_parms; |
| processing_template_decl = s->processing_template_decl; |
| previous_class_type = s->previous_class_type; |
| previous_class_values = s->previous_class_values; |
| processing_specialization = s->processing_specialization; |
| processing_explicit_instantiation = s->processing_explicit_instantiation; |
| |
| free (s); |
| |
| if (current_function_decl) |
| pop_cp_function_context (NULL_TREE); |
| } |
| |
| /* Push a definition of struct, union or enum tag "name". |
| into binding_level "b". "type" should be the type node, |
| We assume that the tag "name" is not already defined. |
| |
| Note that the definition may really be just a forward reference. |
| In that case, the TYPE_SIZE will be a NULL_TREE. |
| |
| C++ gratuitously puts all these tags in the name space. */ |
| |
| /* When setting the IDENTIFIER_TYPE_VALUE field of an identifier ID, |
| record the shadowed value for this binding contour. TYPE is |
| the type that ID maps to. */ |
| |
| static void |
| set_identifier_type_value_with_scope (id, type, b) |
| tree id; |
| tree type; |
| struct binding_level *b; |
| { |
| if (!b->namespace_p) |
| { |
| /* Shadow the marker, not the real thing, so that the marker |
| gets restored later. */ |
| tree old_type_value = REAL_IDENTIFIER_TYPE_VALUE (id); |
| b->type_shadowed |
| = tree_cons (id, old_type_value, b->type_shadowed); |
| } |
| else |
| { |
| tree binding = binding_for_name (id, current_namespace); |
| BINDING_TYPE (binding) = type; |
| /* Store marker instead of real type. */ |
| type = global_type_node; |
| } |
| SET_IDENTIFIER_TYPE_VALUE (id, type); |
| } |
| |
| /* As set_identifier_type_value_with_scope, but using inner_binding_level. */ |
| |
| void |
| set_identifier_type_value (id, type) |
| tree id; |
| tree type; |
| { |
| set_identifier_type_value_with_scope (id, type, inner_binding_level); |
| } |
| |
| static void |
| set_identifier_local_value_with_scope (id, val, b) |
| tree id, val; |
| struct binding_level *b; |
| { |
| tree oldlocal; |
| my_friendly_assert (! b->namespace_p, 980716); |
| |
| oldlocal = IDENTIFIER_LOCAL_VALUE (id); |
| b->shadowed = tree_cons (id, oldlocal, b->shadowed); |
| IDENTIFIER_LOCAL_VALUE (id) = val; |
| } |
| |
| void |
| set_identifier_local_value (id, val) |
| tree id, val; |
| { |
| set_identifier_local_value_with_scope (id, val, current_binding_level); |
| } |
| |
| /* Return the type associated with id. */ |
| |
| tree |
| identifier_type_value (id) |
| tree id; |
| { |
| /* There is no type with that name, anywhere. */ |
| if (REAL_IDENTIFIER_TYPE_VALUE (id) == NULL_TREE) |
| return NULL_TREE; |
| /* This is not the type marker, but the real thing. */ |
| if (REAL_IDENTIFIER_TYPE_VALUE (id) != global_type_node) |
| return REAL_IDENTIFIER_TYPE_VALUE (id); |
| /* Have to search for it. It must be on the global level, now. |
| Ask lookup_name not to return non-types. */ |
| id = lookup_name_real (id, 2, 1, 0); |
| if (id) |
| return TREE_TYPE (id); |
| return NULL_TREE; |
| } |
| |
| /* Pop off extraneous binding levels left over due to syntax errors. |
| |
| We don't pop past namespaces, as they might be valid. */ |
| |
| void |
| pop_everything () |
| { |
| #ifdef DEBUG_CP_BINDING_LEVELS |
| fprintf (stderr, "XXX entering pop_everything ()\n"); |
| #endif |
| while (! toplevel_bindings_p () && ! pseudo_global_level_p ()) |
| { |
| if (class_binding_level) |
| pop_nested_class (1); |
| else |
| poplevel (0, 0, 0); |
| } |
| #ifdef DEBUG_CP_BINDING_LEVELS |
| fprintf (stderr, "XXX leaving pop_everything ()\n"); |
| #endif |
| } |
| |
| /* Push a tag name NAME for struct/class/union/enum type TYPE. |
| Normally put it into the inner-most non-tag-transparent scope, |
| but if GLOBALIZE is true, put it in the inner-most non-class scope. |
| The latter is needed for implicit declarations. */ |
| |
| void |
| pushtag (name, type, globalize) |
| tree name, type; |
| int globalize; |
| { |
| register struct binding_level *b; |
| tree context = 0; |
| tree c_decl = 0; |
| |
| b = inner_binding_level; |
| while (b->tag_transparent |
| || (globalize && b->parm_flag == 2)) |
| b = b->level_chain; |
| |
| if (toplevel_bindings_p ()) |
| b->tags = perm_tree_cons (name, type, b->tags); |
| else |
| b->tags = saveable_tree_cons (name, type, b->tags); |
| |
| if (name) |
| { |
| context = type ? TYPE_CONTEXT (type) : NULL_TREE; |
| if (! context) |
| { |
| tree cs = current_scope (); |
| |
| if (! globalize) |
| context = cs; |
| else if (cs != NULL_TREE |
| && TREE_CODE_CLASS (TREE_CODE (cs)) == 't') |
| /* When declaring a friend class of a local class, we want |
| to inject the newly named class into the scope |
| containing the local class, not the namespace scope. */ |
| context = hack_decl_function_context (get_type_decl (cs)); |
| } |
| if (context) |
| c_decl = TREE_CODE (context) == FUNCTION_DECL |
| ? context : TYPE_MAIN_DECL (context); |
| |
| if (!context) |
| context = current_namespace; |
| |
| /* Do C++ gratuitous typedefing. */ |
| if (IDENTIFIER_TYPE_VALUE (name) != type) |
| { |
| register tree d = NULL_TREE; |
| int newdecl = 0, in_class = 0; |
| |
| if ((b->pseudo_global && b->level_chain->parm_flag == 2) |
| || b->parm_flag == 2) |
| in_class = 1; |
| else |
| d = lookup_nested_type (type, c_decl); |
| |
| if (d == NULL_TREE) |
| { |
| newdecl = 1; |
| d = build_decl (TYPE_DECL, name, type); |
| if (current_lang_name == lang_name_java) |
| TYPE_FOR_JAVA (type) = 1; |
| SET_DECL_ARTIFICIAL (d); |
| if (! in_class) |
| set_identifier_type_value_with_scope (name, type, b); |
| } |
| else |
| d = TYPE_MAIN_DECL (d); |
| |
| TYPE_NAME (type) = d; |
| DECL_CONTEXT (d) = FROB_CONTEXT (context); |
| |
| if (processing_template_parmlist) |
| /* You can't declare a new template type in a template |
| parameter list. But, you can declare a non-template |
| type: |
| |
| template <class A*> struct S; |
| |
| is a forward-declaration of `A'. */ |
| ; |
| else if (IS_AGGR_TYPE (type) |
| && (/* If !GLOBALIZE then we are looking at a |
| definition. It may not be a primary template. |
| (For example, in: |
| |
| template <class T> |
| struct S1 { class S2 {}; } |
| |
| we have to push_template_decl for S2.) */ |
| (processing_template_decl && !globalize) |
| /* If we are declaring a friend template class, we |
| will have GLOBALIZE set, since something like: |
| |
| template <class T> |
| struct S1 { |
| template <class U> |
| friend class S2; |
| }; |
| |
| declares S2 to be at global scope. */ |
| || (processing_template_decl > |
| template_class_depth (current_class_type)))) |
| { |
| d = push_template_decl_real (d, globalize); |
| /* If the current binding level is the binding level for |
| the template parameters (see the comment in |
| begin_template_parm_list) and the enclosing level is |
| a class scope, and we're not looking at a friend, |
| push the declaration of the member class into the |
| class scope. In the friend case, push_template_decl |
| will already have put the friend into global scope, |
| if appropriate. */ |
| if (!globalize && b->pseudo_global && |
| b->level_chain->parm_flag == 2) |
| { |
| pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type), |
| b->level_chain); |
| /* Put this tag on the list of tags for the class, |
| since that won't happen below because B is not |
| the class binding level, but is instead the |
| pseudo-global level. */ |
| b->level_chain->tags = |
| saveable_tree_cons (name, type, b->level_chain->tags); |
| TREE_NONLOCAL_FLAG (type) = 1; |
| if (TYPE_SIZE (current_class_type) == NULL_TREE) |
| CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags; |
| } |
| } |
| |
| if (b->parm_flag == 2) |
| d = pushdecl_class_level (d); |
| else |
| d = pushdecl_with_scope (d, b); |
| |
| if (newdecl) |
| { |
| if (ANON_AGGRNAME_P (name)) |
| DECL_IGNORED_P (d) = 1; |
| |
| TYPE_CONTEXT (type) = DECL_CONTEXT (d); |
| DECL_ASSEMBLER_NAME (d) = DECL_NAME (d); |
| DECL_ASSEMBLER_NAME (d) |
| = get_identifier (build_overload_name (type, 1, 1)); |
| } |
| } |
| if (b->parm_flag == 2) |
| { |
| TREE_NONLOCAL_FLAG (type) = 1; |
| if (TYPE_SIZE (current_class_type) == NULL_TREE) |
| CLASSTYPE_TAGS (current_class_type) = b->tags; |
| } |
| } |
| |
| if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) |
| /* Use the canonical TYPE_DECL for this node. */ |
| TYPE_STUB_DECL (type) = TYPE_NAME (type); |
| else |
| { |
| /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE |
| will be the tagged type we just added to the current |
| binding level. This fake NULL-named TYPE_DECL node helps |
| dwarfout.c to know when it needs to output a |
| representation of a tagged type, and it also gives us a |
| convenient place to record the "scope start" address for |
| the tagged type. */ |
| |
| tree d = build_decl (TYPE_DECL, NULL_TREE, type); |
| TYPE_STUB_DECL (type) = pushdecl_with_scope (d, b); |
| } |
| } |
| |
| /* Counter used to create anonymous type names. */ |
| |
| static int anon_cnt = 0; |
| |
| /* Return an IDENTIFIER which can be used as a name for |
| anonymous structs and unions. */ |
| |
| tree |
| make_anon_name () |
| { |
| char buf[32]; |
| |
| sprintf (buf, ANON_AGGRNAME_FORMAT, anon_cnt++); |
| return get_identifier (buf); |
| } |
| |
| /* Clear the TREE_PURPOSE slot of tags which have anonymous typenames. |
| This keeps dbxout from getting confused. */ |
| |
| void |
| clear_anon_tags () |
| { |
| register struct binding_level *b; |
| register tree tags; |
| static int last_cnt = 0; |
| |
| /* Fast out if no new anon names were declared. */ |
| if (last_cnt == anon_cnt) |
| return; |
| |
| b = current_binding_level; |
| while (b->tag_transparent) |
| b = b->level_chain; |
| tags = b->tags; |
| while (tags) |
| { |
| /* A NULL purpose means we have already processed all tags |
| from here to the end of the list. */ |
| if (TREE_PURPOSE (tags) == NULL_TREE) |
| break; |
| if (ANON_AGGRNAME_P (TREE_PURPOSE (tags))) |
| TREE_PURPOSE (tags) = NULL_TREE; |
| tags = TREE_CHAIN (tags); |
| } |
| last_cnt = anon_cnt; |
| } |
| |
| /* Subroutine of duplicate_decls: return truthvalue of whether |
| or not types of these decls match. |
| |
| For C++, we must compare the parameter list so that `int' can match |
| `int&' in a parameter position, but `int&' is not confused with |
| `const int&'. */ |
| |
| int |
| decls_match (newdecl, olddecl) |
| tree newdecl, olddecl; |
| { |
| int types_match; |
| |
| if (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); |
| |
| if (DECL_REAL_CONTEXT (newdecl) != DECL_REAL_CONTEXT (olddecl) |
| && ! (DECL_LANGUAGE (newdecl) == lang_c |
| && DECL_LANGUAGE (olddecl) == lang_c)) |
| return 0; |
| |
| /* When we parse a static member function definition, |
| we put together a FUNCTION_DECL which thinks its type |
| is METHOD_TYPE. Change that to FUNCTION_TYPE, and |
| proceed. */ |
| if (TREE_CODE (f1) == METHOD_TYPE && DECL_STATIC_FUNCTION_P (olddecl)) |
| revert_static_member_fn (&newdecl, &f1, &p1); |
| else if (TREE_CODE (f2) == METHOD_TYPE |
| && DECL_STATIC_FUNCTION_P (newdecl)) |
| revert_static_member_fn (&olddecl, &f2, &p2); |
| |
| /* Here we must take care of the case where new default |
| parameters are specified. Also, warn if an old |
| declaration becomes ambiguous because default |
| parameters may cause the two to be ambiguous. */ |
| if (TREE_CODE (f1) != TREE_CODE (f2)) |
| { |
| if (TREE_CODE (f1) == OFFSET_TYPE) |
| cp_compiler_error ("`%D' redeclared as member function", newdecl); |
| else |
| cp_compiler_error ("`%D' redeclared as non-member function", newdecl); |
| return 0; |
| } |
| |
| if (comptypes (TREE_TYPE (f1), TREE_TYPE (f2), 1)) |
| { |
| if (! strict_prototypes_lang_c && DECL_LANGUAGE (olddecl) == lang_c |
| && p2 == NULL_TREE) |
| { |
| types_match = self_promoting_args_p (p1); |
| if (p1 == void_list_node) |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl); |
| } |
| else if (!strict_prototypes_lang_c && DECL_LANGUAGE (olddecl)==lang_c |
| && DECL_LANGUAGE (newdecl) == lang_c && p1 == NULL_TREE) |
| { |
| types_match = self_promoting_args_p (p2); |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl); |
| } |
| else |
| types_match = compparms (p1, p2, 3); |
| } |
| else |
| types_match = 0; |
| } |
| else if (TREE_CODE (newdecl) == TEMPLATE_DECL |
| && TREE_CODE (olddecl) == TEMPLATE_DECL) |
| { |
| if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl), |
| DECL_TEMPLATE_PARMS (olddecl))) |
| return 0; |
| |
| if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) |
| types_match = 1; |
| else |
| types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl), |
| DECL_TEMPLATE_RESULT (newdecl)); |
| } |
| else |
| { |
| if (TREE_TYPE (newdecl) == error_mark_node) |
| types_match = TREE_TYPE (olddecl) == error_mark_node; |
| else if (TREE_TYPE (olddecl) == NULL_TREE) |
| types_match = TREE_TYPE (newdecl) == NULL_TREE; |
| else if (TREE_TYPE (newdecl) == NULL_TREE) |
| types_match = 0; |
| /* Qualifiers must match, and they may be present on either, the type |
| or the decl. */ |
| else if ((TREE_READONLY (newdecl) |
| || TYPE_READONLY (TREE_TYPE (newdecl))) |
| == (TREE_READONLY (olddecl) |
| || TYPE_READONLY (TREE_TYPE (olddecl))) |
| && (TREE_THIS_VOLATILE (newdecl) |
| || TYPE_VOLATILE (TREE_TYPE (newdecl))) |
| == (TREE_THIS_VOLATILE (olddecl) |
| || TYPE_VOLATILE (TREE_TYPE (olddecl)))) |
| types_match = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (newdecl)), |
| TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)), 1); |
| else |
| types_match = 0; |
| } |
| |
| return types_match; |
| } |
| |
| /* If NEWDECL is `static' and an `extern' was seen previously, |
| warn about it. (OLDDECL may be NULL_TREE; NAME contains |
| information about previous usage as an `extern'.) |
| |
| Note that this does not apply to the C++ case of declaring |
| a variable `extern const' and then later `const'. |
| |
| Don't complain about built-in functions, since they are beyond |
| the user's control. */ |
| |
| static void |
| warn_extern_redeclared_static (newdecl, olddecl) |
| tree newdecl, olddecl; |
| { |
| tree name; |
| |
| static char *explicit_extern_static_warning |
| = "`%D' was declared `extern' and later `static'"; |
| static char *implicit_extern_static_warning |
| = "`%D' was declared implicitly `extern' and later `static'"; |
| |
| if (TREE_CODE (newdecl) == TYPE_DECL) |
| return; |
| |
| name = DECL_ASSEMBLER_NAME (newdecl); |
| if (TREE_PUBLIC (name) && DECL_THIS_STATIC (newdecl)) |
| { |
| /* It's okay to redeclare an ANSI built-in function as static, |
| or to declare a non-ANSI built-in function as anything. */ |
| if (! (TREE_CODE (newdecl) == FUNCTION_DECL |
| && olddecl != NULL_TREE |
| && TREE_CODE (olddecl) == FUNCTION_DECL |
| && (DECL_BUILT_IN (olddecl) |
| || DECL_BUILT_IN_NONANSI (olddecl)))) |
| { |
| cp_pedwarn (IDENTIFIER_IMPLICIT_DECL (name) |
| ? implicit_extern_static_warning |
| : explicit_extern_static_warning, newdecl); |
| if (olddecl != NULL_TREE) |
| cp_pedwarn_at ("previous declaration of `%D'", olddecl); |
| } |
| } |
| } |
| |
| /* Handle when a new declaration NEWDECL has the same name as an old |
| one OLDDECL in the same binding contour. Prints an error message |
| if appropriate. |
| |
| If safely possible, alter OLDDECL to look like NEWDECL, and return 1. |
| Otherwise, return 0. */ |
| |
| int |
| duplicate_decls (newdecl, olddecl) |
| tree newdecl, olddecl; |
| { |
| extern struct obstack permanent_obstack; |
| unsigned olddecl_uid = DECL_UID (olddecl); |
| int olddecl_friend = 0, types_match = 0; |
| int new_defines_function = 0; |
| |
| if (newdecl == olddecl) |
| return 1; |
| |
| types_match = decls_match (newdecl, olddecl); |
| |
| /* If either the type of the new decl or the type of the old decl is an |
| error_mark_node, then that implies that we have already issued an |
| error (earlier) for some bogus type specification, and in that case, |
| it is rather pointless to harass the user with yet more error message |
| about the same declaration, so just pretend the types match here. */ |
| if (TREE_TYPE (newdecl) == error_mark_node |
| || TREE_TYPE (olddecl) == error_mark_node) |
| types_match = 1; |
| |
| /* Check for redeclaration and other discrepancies. */ |
| if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_ARTIFICIAL (olddecl) |
| && (DECL_BUILT_IN (olddecl) || DECL_BUILT_IN_NONANSI (olddecl))) |
| { |
| /* If you declare a built-in or predefined function name as static, |
| the old definition is overridden, but optionally warn this was a |
| bad choice of name. Ditto for overloads. */ |
| if (! TREE_PUBLIC (newdecl) |
| || (TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl))) |
| { |
| if (warn_shadow) |
| cp_warning ("shadowing %s function `%#D'", |
| DECL_BUILT_IN (olddecl) ? "built-in" : "library", |
| olddecl); |
| /* Discard the old built-in function. */ |
| return 0; |
| } |
| else if (! types_match) |
| { |
| if (TREE_CODE (newdecl) != FUNCTION_DECL) |
| { |
| /* If the built-in is not ansi, then programs can override |
| it even globally without an error. */ |
| if (! DECL_BUILT_IN (olddecl)) |
| cp_warning ("library function `%#D' redeclared as non-function `%#D'", |
| olddecl, newdecl); |
| else |
| { |
| cp_error ("declaration of `%#D'", newdecl); |
| cp_error ("conflicts with built-in declaration `%#D'", |
| olddecl); |
| } |
| return 0; |
| } |
| |
| cp_warning ("declaration of `%#D'", newdecl); |
| cp_warning ("conflicts with built-in declaration `%#D'", |
| olddecl); |
| } |
| } |
| else if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) |
| { |
| if ((TREE_CODE (olddecl) == TYPE_DECL && DECL_ARTIFICIAL (olddecl) |
| && TREE_CODE (newdecl) != TYPE_DECL |
| && ! (TREE_CODE (newdecl) == TEMPLATE_DECL |
| && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)) |
| || (TREE_CODE (newdecl) == TYPE_DECL && DECL_ARTIFICIAL (newdecl) |
| && TREE_CODE (olddecl) != TYPE_DECL |
| && ! (TREE_CODE (olddecl) == TEMPLATE_DECL |
| && (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) |
| == TYPE_DECL)))) |
| { |
| /* We do nothing special here, because C++ does such nasty |
| things with TYPE_DECLs. Instead, just let the TYPE_DECL |
| get shadowed, and know that if we need to find a TYPE_DECL |
| for a given name, we can look in the IDENTIFIER_TYPE_VALUE |
| slot of the identifier. */ |
| return 0; |
| } |
| |
| if ((TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_FUNCTION_TEMPLATE_P (olddecl)) |
| || (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_FUNCTION_TEMPLATE_P (newdecl))) |
| return 0; |
| |
| cp_error ("`%#D' redeclared as different kind of symbol", newdecl); |
| if (TREE_CODE (olddecl) == TREE_LIST) |
| olddecl = TREE_VALUE (olddecl); |
| cp_error_at ("previous declaration of `%#D'", olddecl); |
| |
| /* New decl is completely inconsistent with the old one => |
| tell caller to replace the old one. */ |
| |
| return 0; |
| } |
| else if (!types_match) |
| { |
| if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| /* The name of a class template may not be declared to refer to |
| any other template, class, function, object, namespace, value, |
| or type in the same scope. */ |
| if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == TYPE_DECL |
| || TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) |
| { |
| cp_error ("declaration of template `%#D'", newdecl); |
| cp_error_at ("conflicts with previous declaration `%#D'", |
| olddecl); |
| } |
| else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL |
| && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL |
| && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))), |
| TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))), 3) |
| && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl), |
| DECL_TEMPLATE_PARMS (olddecl))) |
| { |
| cp_error ("new declaration `%#D'", newdecl); |
| cp_error_at ("ambiguates old declaration `%#D'", olddecl); |
| } |
| return 0; |
| } |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (DECL_LANGUAGE (newdecl) == lang_c |
| && DECL_LANGUAGE (olddecl) == lang_c) |
| { |
| cp_error ("declaration of C function `%#D' conflicts with", |
| newdecl); |
| cp_error_at ("previous declaration `%#D' here", olddecl); |
| } |
| else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), |
| TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 3)) |
| { |
| cp_error ("new declaration `%#D'", newdecl); |
| cp_error_at ("ambiguates old declaration `%#D'", olddecl); |
| } |
| else |
| return 0; |
| } |
| |
| /* Already complained about this, so don't do so again. */ |
| else if (current_class_type == NULL_TREE |
| || IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (newdecl)) != current_class_type) |
| { |
| cp_error ("conflicting types for `%#D'", newdecl); |
| cp_error_at ("previous declaration as `%#D'", olddecl); |
| } |
| } |
| else if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && ((DECL_TEMPLATE_SPECIALIZATION (olddecl) |
| && (!DECL_TEMPLATE_INFO (newdecl) |
| || (DECL_TI_TEMPLATE (newdecl) |
| != DECL_TI_TEMPLATE (olddecl)))) |
| || (DECL_TEMPLATE_SPECIALIZATION (newdecl) |
| && (!DECL_TEMPLATE_INFO (olddecl) |
| || (DECL_TI_TEMPLATE (olddecl) |
| != DECL_TI_TEMPLATE (newdecl)))))) |
| /* It's OK to have a template specialization and a non-template |
| with the same type, or to have specializations of two |
| different templates with the same type. Note that if one is a |
| specialization, and the other is an instantiation of the same |
| template, that we do not exit at this point. That situation |
| can occur if we instantiate a template class, and then |
| specialize one of its methods. This situation is legal, but |
| the declarations must be merged in the usual way. */ |
| return 0; |
| else if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && ((DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && !DECL_USE_TEMPLATE (newdecl)) |
| || (DECL_TEMPLATE_INSTANTIATION (newdecl) |
| && !DECL_USE_TEMPLATE (olddecl)))) |
| /* One of the declarations is a template instantiation, and the |
| other is not a template at all. That's OK. */ |
| return 0; |
| else if (TREE_CODE (newdecl) == NAMESPACE_DECL |
| && DECL_NAMESPACE_ALIAS (newdecl) |
| && DECL_NAMESPACE_ALIAS (newdecl) == DECL_NAMESPACE_ALIAS (olddecl)) |
| /* Redeclaration of namespace alias, ignore it. */ |
| return 1; |
| else |
| { |
| char *errmsg = redeclaration_error_message (newdecl, olddecl); |
| if (errmsg) |
| { |
| cp_error (errmsg, newdecl); |
| if (DECL_NAME (olddecl) != NULL_TREE) |
| cp_error_at ((DECL_INITIAL (olddecl) |
| && namespace_bindings_p ()) |
| ? "`%#D' previously defined here" |
| : "`%#D' previously declared here", olddecl); |
| } |
| else if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_INITIAL (olddecl) != NULL_TREE |
| && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) == NULL_TREE |
| && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != NULL_TREE) |
| { |
| /* Prototype decl follows defn w/o prototype. */ |
| cp_warning_at ("prototype for `%#D'", newdecl); |
| cp_warning_at ("follows non-prototype definition here", olddecl); |
| } |
| else if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl)) |
| { |
| /* extern "C" int foo (); |
| int foo () { bar (); } |
| is OK. */ |
| if (current_lang_stack == current_lang_base) |
| DECL_LANGUAGE (newdecl) = DECL_LANGUAGE (olddecl); |
| else |
| { |
| cp_error_at ("previous declaration of `%#D' with %L linkage", |
| olddecl, DECL_LANGUAGE (olddecl)); |
| cp_error ("conflicts with new declaration with %L linkage", |
| DECL_LANGUAGE (newdecl)); |
| } |
| } |
| |
| if (DECL_LANG_SPECIFIC (olddecl) && DECL_USE_TEMPLATE (olddecl)) |
| ; |
| else if (TREE_CODE (olddecl) == FUNCTION_DECL) |
| { |
| tree t1 = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); |
| tree t2 = TYPE_ARG_TYPES (TREE_TYPE (newdecl)); |
| int i = 1; |
| |
| if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE) |
| t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2); |
| |
| for (; t1 && t1 != void_list_node; |
| t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2), i++) |
| if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2)) |
| { |
| if (1 == simple_cst_equal (TREE_PURPOSE (t1), |
| TREE_PURPOSE (t2))) |
| { |
| if (pedantic) |
| { |
| cp_pedwarn ("default argument given for parameter %d of `%#D'", |
| i, newdecl); |
| cp_pedwarn_at ("after previous specification in `%#D'", |
| olddecl); |
| } |
| } |
| else |
| { |
| cp_error ("default argument given for parameter %d of `%#D'", |
| i, newdecl); |
| cp_error_at ("after previous specification in `%#D'", |
| olddecl); |
| } |
| } |
| |
| if (DECL_THIS_INLINE (newdecl) && ! DECL_THIS_INLINE (olddecl) |
| && TREE_ADDRESSABLE (olddecl) && warn_inline) |
| { |
| cp_warning ("`%#D' was used before it was declared inline", |
| newdecl); |
| cp_warning_at ("previous non-inline declaration here", |
| olddecl); |
| } |
| } |
| /* These bits are logically part of the type for non-functions. */ |
| else if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl) |
| || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl)) |
| { |
| cp_pedwarn ("type qualifiers for `%#D'", newdecl); |
| cp_pedwarn_at ("conflict with previous decl `%#D'", olddecl); |
| } |
| } |
| |
| /* If new decl is `static' and an `extern' was seen previously, |
| warn about it. */ |
| warn_extern_redeclared_static (newdecl, olddecl); |
| |
| /* We have committed to returning 1 at this point. */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| /* Now that functions must hold information normally held |
| by field decls, there is extra work to do so that |
| declaration information does not get destroyed during |
| definition. */ |
| if (DECL_VINDEX (olddecl)) |
| DECL_VINDEX (newdecl) = DECL_VINDEX (olddecl); |
| if (DECL_CONTEXT (olddecl)) |
| DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl); |
| if (DECL_CLASS_CONTEXT (olddecl)) |
| DECL_CLASS_CONTEXT (newdecl) = DECL_CLASS_CONTEXT (olddecl); |
| if (DECL_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0) |
| DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl); |
| DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl); |
| DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); |
| DECL_ABSTRACT_VIRTUAL_P (newdecl) |= DECL_ABSTRACT_VIRTUAL_P (olddecl); |
| DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl); |
| DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl); |
| new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE; |
| |
| /* Optionally warn about more than one declaration for the same |
| name, but don't warn about a function declaration followed by a |
| definition. */ |
| if (warn_redundant_decls && ! DECL_ARTIFICIAL (olddecl) |
| && !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE) |
| /* Don't warn about extern decl followed by definition. */ |
| && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl)) |
| /* Don't warn about friends, let add_friend take care of it. */ |
| && ! DECL_FRIEND_P (newdecl)) |
| { |
| cp_warning ("redundant redeclaration of `%D' in same scope", newdecl); |
| cp_warning_at ("previous declaration of `%D'", olddecl); |
| } |
| } |
| |
| /* Deal with C++: must preserve virtual function table size. */ |
| if (TREE_CODE (olddecl) == TYPE_DECL) |
| { |
| register tree newtype = TREE_TYPE (newdecl); |
| register tree oldtype = TREE_TYPE (olddecl); |
| |
| if (newtype != error_mark_node && oldtype != error_mark_node |
| && TYPE_LANG_SPECIFIC (newtype) && TYPE_LANG_SPECIFIC (oldtype)) |
| { |
| CLASSTYPE_VSIZE (newtype) = CLASSTYPE_VSIZE (oldtype); |
| CLASSTYPE_FRIEND_CLASSES (newtype) |
| = CLASSTYPE_FRIEND_CLASSES (oldtype); |
| } |
| } |
| |
| /* Copy all the DECL_... slots specified in the new decl |
| except for any that we copy here from the old type. */ |
| DECL_MACHINE_ATTRIBUTES (newdecl) |
| = merge_machine_decl_attributes (olddecl, newdecl); |
| |
| if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| if (DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl)) == NULL_TREE) |
| { |
| if (! duplicate_decls (DECL_TEMPLATE_RESULT (newdecl), |
| DECL_TEMPLATE_RESULT (olddecl))) |
| cp_error ("invalid redeclaration of %D", newdecl); |
| TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)); |
| DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl); |
| DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl); |
| } |
| DECL_TEMPLATE_SPECIALIZATIONS (newdecl) |
| = DECL_TEMPLATE_SPECIALIZATIONS (olddecl); |
| |
| return 1; |
| } |
| |
| if (types_match) |
| { |
| /* Automatically handles default parameters. */ |
| tree oldtype = TREE_TYPE (olddecl); |
| tree newtype; |
| |
| /* Make sure we put the new type in the same obstack as the old one. */ |
| if (oldtype) |
| push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype)); |
| else |
| { |
| push_obstacks_nochange (); |
| end_temporary_allocation (); |
| } |
| |
| /* Merge the data types specified in the two decls. */ |
| newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); |
| |
| if (TREE_CODE (newdecl) == VAR_DECL) |
| DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl); |
| /* Do this after calling `common_type' so that default |
| parameters don't confuse us. */ |
| else if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)) |
| != TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)))) |
| { |
| TREE_TYPE (newdecl) = build_exception_variant (newtype, |
| TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl))); |
| TREE_TYPE (olddecl) = build_exception_variant (newtype, |
| TYPE_RAISES_EXCEPTIONS (oldtype)); |
| |
| if ((pedantic || ! DECL_IN_SYSTEM_HEADER (olddecl)) |
| && DECL_SOURCE_LINE (olddecl) != 0 |
| && flag_exceptions |
| && ! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl))) |
| { |
| cp_pedwarn ("declaration of `%D' throws different exceptions", |
| newdecl); |
| cp_pedwarn_at ("previous declaration here", olddecl); |
| } |
| } |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype; |
| |
| /* Lay the type out, unless already done. */ |
| if (newtype != canonical_type_variant (oldtype) |
| && TREE_TYPE (newdecl) != error_mark_node |
| && !(processing_template_decl && uses_template_parms (newdecl))) |
| layout_type (TREE_TYPE (newdecl)); |
| |
| if ((TREE_CODE (newdecl) == VAR_DECL |
| || TREE_CODE (newdecl) == PARM_DECL |
| || TREE_CODE (newdecl) == RESULT_DECL |
| || TREE_CODE (newdecl) == FIELD_DECL |
| || TREE_CODE (newdecl) == TYPE_DECL) |
| && !(processing_template_decl && uses_template_parms (newdecl))) |
| layout_decl (newdecl, 0); |
| |
| /* Merge the type qualifiers. */ |
| if (TREE_READONLY (newdecl)) |
| TREE_READONLY (olddecl) = 1; |
| if (TREE_THIS_VOLATILE (newdecl)) |
| TREE_THIS_VOLATILE (olddecl) = 1; |
| |
| /* Merge the initialization information. */ |
| if (DECL_INITIAL (newdecl) == NULL_TREE |
| && DECL_INITIAL (olddecl) != NULL_TREE) |
| { |
| DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); |
| DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl); |
| DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl); |
| } |
| |
| /* Merge the section attribute. |
| We want to issue an error if the sections conflict but that must be |
| done later in decl_attributes since we are called before attributes |
| are assigned. */ |
| if (DECL_SECTION_NAME (newdecl) == NULL_TREE) |
| DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); |
| |
| /* Keep the old rtl since we can safely use it, unless it's the |
| call to abort() used for abstract virtuals. */ |
| if ((DECL_LANG_SPECIFIC (olddecl) |
| && !DECL_ABSTRACT_VIRTUAL_P (olddecl)) |
| || DECL_RTL (olddecl) != DECL_RTL (abort_fndecl)) |
| DECL_RTL (newdecl) = DECL_RTL (olddecl); |
| |
| pop_obstacks (); |
| } |
| /* If cannot merge, then use the new type and qualifiers, |
| and don't preserve the old rtl. */ |
| else |
| { |
| /* Clean out any memory we had of the old declaration. */ |
| tree oldstatic = value_member (olddecl, static_aggregates); |
| if (oldstatic) |
| TREE_VALUE (oldstatic) = error_mark_node; |
| |
| TREE_TYPE (olddecl) = TREE_TYPE (newdecl); |
| TREE_READONLY (olddecl) = TREE_READONLY (newdecl); |
| TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); |
| TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl); |
| } |
| |
| /* Merge the storage class information. */ |
| DECL_WEAK (newdecl) |= DECL_WEAK (olddecl); |
| DECL_ONE_ONLY (newdecl) |= DECL_ONE_ONLY (olddecl); |
| TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); |
| TREE_STATIC (olddecl) = TREE_STATIC (newdecl) |= TREE_STATIC (olddecl); |
| if (! DECL_EXTERNAL (olddecl)) |
| DECL_EXTERNAL (newdecl) = 0; |
| |
| if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl)) |
| { |
| DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl); |
| DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl); |
| DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl); |
| /* Don't really know how much of the language-specific |
| values we should copy from old to new. */ |
| DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl); |
| DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl); |
| DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl); |
| if (DECL_TEMPLATE_INFO (newdecl) == NULL_TREE) |
| { |
| DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); |
| DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl); |
| } |
| olddecl_friend = DECL_FRIEND_P (olddecl); |
| } |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && !DECL_TEMPLATE_INSTANTIATION (newdecl)) |
| { |
| /* If newdecl is not a specialization, then it is not a |
| template-related function at all. And that means that we |
| shoud have exited above, returning 0. */ |
| my_friendly_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl), |
| 0); |
| |
| if (TREE_USED (olddecl)) |
| /* From [temp.expl.spec]: |
| |
| If a template, a member template or the member of a class |
| template is explicitly specialized then that |
| specialization shall be declared before the first use of |
| that specialization that would cause an implicit |
| instantiation to take place, in every translation unit in |
| which such a use occurs. */ |
| cp_error ("explicit specialization of %D after first use", |
| olddecl); |
| |
| SET_DECL_TEMPLATE_SPECIALIZATION (olddecl); |
| } |
| DECL_THIS_INLINE (newdecl) |= DECL_THIS_INLINE (olddecl); |
| |
| /* If either decl says `inline', this fn is inline, unless its |
| definition was passed already. */ |
| if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == NULL_TREE) |
| DECL_INLINE (olddecl) = 1; |
| DECL_INLINE (newdecl) = DECL_INLINE (olddecl); |
| |
| if (! types_match) |
| { |
| DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl); |
| DECL_ASSEMBLER_NAME (olddecl) = DECL_ASSEMBLER_NAME (newdecl); |
| DECL_RTL (olddecl) = DECL_RTL (newdecl); |
| } |
| if (! types_match || new_defines_function) |
| { |
| /* These need to be copied so that the names are available. */ |
| DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl); |
| DECL_RESULT (olddecl) = DECL_RESULT (newdecl); |
| } |
| if (new_defines_function) |
| /* If defining a function declared with other language |
| linkage, use the previously declared language linkage. */ |
| DECL_LANGUAGE (newdecl) = DECL_LANGUAGE (olddecl); |
| else |
| { |
| /* If redeclaring a builtin function, and not a definition, |
| it stays built in. */ |
| if (DECL_BUILT_IN (olddecl)) |
| { |
| DECL_BUILT_IN (newdecl) = 1; |
| DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); |
| /* If we're keeping the built-in definition, keep the rtl, |
| regardless of declaration matches. */ |
| DECL_RTL (newdecl) = DECL_RTL (olddecl); |
| } |
| else |
| DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl); |
| |
| DECL_RESULT (newdecl) = DECL_RESULT (olddecl); |
| if ((DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl))) |
| /* Previously saved insns go together with |
| the function's previous definition. */ |
| DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); |
| /* Don't clear out the arguments if we're redefining a function. */ |
| if (DECL_ARGUMENTS (olddecl)) |
| DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); |
| } |
| if (DECL_LANG_SPECIFIC (olddecl)) |
| DECL_MAIN_VARIANT (newdecl) = DECL_MAIN_VARIANT (olddecl); |
| } |
| |
| if (TREE_CODE (newdecl) == NAMESPACE_DECL) |
| { |
| NAMESPACE_LEVEL (newdecl) = NAMESPACE_LEVEL (olddecl); |
| } |
| |
| /* Now preserve various other info from the definition. */ |
| TREE_ADDRESSABLE (newdecl) = TREE_ADDRESSABLE (olddecl); |
| TREE_ASM_WRITTEN (newdecl) = TREE_ASM_WRITTEN (olddecl); |
| DECL_COMMON (newdecl) = DECL_COMMON (olddecl); |
| DECL_ASSEMBLER_NAME (newdecl) = DECL_ASSEMBLER_NAME (olddecl); |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| int function_size; |
| struct lang_decl *ol = DECL_LANG_SPECIFIC (olddecl); |
| struct lang_decl *nl = DECL_LANG_SPECIFIC (newdecl); |
| |
| function_size = sizeof (struct tree_decl); |
| |
| bcopy ((char *) newdecl + sizeof (struct tree_common), |
| (char *) olddecl + sizeof (struct tree_common), |
| function_size - sizeof (struct tree_common)); |
| |
| /* Can we safely free the storage used by newdecl? */ |
| |
| #define ROUND(x) ((x + obstack_alignment_mask (&permanent_obstack)) \ |
| & ~ obstack_alignment_mask (&permanent_obstack)) |
| |
| if (DECL_TEMPLATE_INSTANTIATION (newdecl)) |
| { |
| /* If newdecl is a template instantiation, it is possible that |
| the following sequence of events has occurred: |
| |
| o A friend function was declared in a class template. The |
| class template was instantiated. |
| |
| o The instantiation of the friend declaration was |
| recorded on the instantiation list, and is newdecl. |
| |
| o Later, however, instantiate_class_template called pushdecl |
| on the newdecl to perform name injection. But, pushdecl in |
| turn called duplicate_decls when it discovered that another |
| declaration of a global function with the same name already |
| existed. |
| |
| o Here, in duplicate_decls, we decided to clobber newdecl. |
| |
| If we're going to do that, we'd better make sure that |
| olddecl, and not newdecl, is on the list of |
| instantiations so that if we try to do the instantiation |
| again we won't get the clobbered declaration. */ |
| |
| tree tmpl = DECL_TI_TEMPLATE (newdecl); |
| tree decls = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); |
| |
| for (; decls; decls = TREE_CHAIN (decls)) |
| if (TREE_VALUE (decls) == newdecl) |
| TREE_VALUE (decls) = olddecl; |
| } |
| |
| if (((char *)newdecl + ROUND (function_size) == (char *)nl |
| && ((char *)newdecl + ROUND (function_size) |
| + ROUND (sizeof (struct lang_decl)) |
| == obstack_next_free (&permanent_obstack))) |
| || ((char *)newdecl + ROUND (function_size) |
| == obstack_next_free (&permanent_obstack))) |
| { |
| DECL_MAIN_VARIANT (newdecl) = olddecl; |
| DECL_LANG_SPECIFIC (olddecl) = ol; |
| bcopy ((char *)nl, (char *)ol, sizeof (struct lang_decl)); |
| |
| obstack_free (&permanent_obstack, newdecl); |
| } |
| else if (LANG_DECL_PERMANENT (ol) && ol != nl) |
| { |
| if (DECL_MAIN_VARIANT (olddecl) == olddecl) |
| { |
| /* Save these lang_decls that would otherwise be lost. */ |
| extern tree free_lang_decl_chain; |
| tree free_lang_decl = (tree) ol; |
| |
| if (DECL_LANG_SPECIFIC (olddecl) == ol) |
| abort (); |
| |
| TREE_CHAIN (free_lang_decl) = free_lang_decl_chain; |
| free_lang_decl_chain = free_lang_decl; |
| } |
| else |
| { |
| /* Storage leak. */; |
| } |
| } |
| } |
| else |
| { |
| bcopy ((char *) newdecl + sizeof (struct tree_common), |
| (char *) olddecl + sizeof (struct tree_common), |
| sizeof (struct tree_decl) - sizeof (struct tree_common) |
| + tree_code_length [(int)TREE_CODE (newdecl)] * sizeof (char *)); |
| } |
| |
| DECL_UID (olddecl) = olddecl_uid; |
| if (olddecl_friend) |
| DECL_FRIEND_P (olddecl) = 1; |
| |
| /* NEWDECL contains the merged attribute lists. |
| Update OLDDECL to be the same. */ |
| DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl); |
| |
| return 1; |
| } |
| |
| /* Record a decl-node X as belonging to the current lexical scope. |
| Check for errors (such as an incompatible declaration for the same |
| name already seen in the same scope). |
| |
| Returns either X or an old decl for the same name. |
| I
|