| /* 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. |
| If an old decl is returned, it may have been smashed |
| to agree with what X says. */ |
| |
| tree |
| pushdecl (x) |
| tree x; |
| { |
| register tree t; |
| register tree name = DECL_ASSEMBLER_NAME (x); |
| register struct binding_level *b = current_binding_level; |
| |
| if (current_function_decl && x != current_function_decl |
| /* A local declaration for a function doesn't constitute nesting. */ |
| && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x)) |
| /* Don't change DECL_CONTEXT of virtual methods. */ |
| && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x)) |
| && ! DECL_CONTEXT (x)) |
| DECL_CONTEXT (x) = current_function_decl; |
| if (!DECL_CONTEXT (x)) |
| DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace); |
| |
| /* Type are looked up using the DECL_NAME, as that is what the rest of the |
| compiler wants to use. */ |
| if (TREE_CODE (x) == TYPE_DECL || TREE_CODE (x) == VAR_DECL |
| || TREE_CODE (x) == NAMESPACE_DECL || TREE_CODE (x) == TEMPLATE_TYPE_PARM |
| || TREE_CODE (x) == TEMPLATE_TEMPLATE_PARM) |
| name = DECL_NAME (x); |
| |
| if (name) |
| { |
| #if 0 |
| /* Not needed...see below. */ |
| char *file; |
| int line; |
| #endif |
| if (TREE_CODE (name) == TEMPLATE_ID_EXPR) |
| name = TREE_OPERAND (name, 0); |
| |
| /* Namespace-scoped variables are not found in the current level. */ |
| if (TREE_CODE (x) == VAR_DECL && DECL_NAMESPACE_SCOPE_P (x)) |
| t = namespace_binding (name, DECL_CONTEXT (x)); |
| else |
| t = lookup_name_current_level (name); |
| if (t == error_mark_node) |
| { |
| /* error_mark_node is 0 for a while during initialization! */ |
| t = NULL_TREE; |
| cp_error_at ("`%#D' used prior to declaration", x); |
| } |
| |
| else if (t != NULL_TREE) |
| { |
| #if 0 |
| /* This is turned off until I have time to do it right (bpk). */ |
| /* With the code below that uses it... */ |
| file = DECL_SOURCE_FILE (t); |
| line = DECL_SOURCE_LINE (t); |
| #endif |
| if (TREE_CODE (t) == PARM_DECL) |
| { |
| if (DECL_CONTEXT (t) == NULL_TREE) |
| fatal ("parse errors have confused me too much"); |
| |
| /* Check for duplicate params. */ |
| if (duplicate_decls (x, t)) |
| return t; |
| } |
| else if (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c) |
| || DECL_FUNCTION_TEMPLATE_P (x)) |
| && is_overloaded_fn (t)) |
| /* Don't do anything just yet. */; |
| else if (t == wchar_decl_node) |
| { |
| if (pedantic && ! DECL_IN_SYSTEM_HEADER (x)) |
| cp_pedwarn ("redeclaration of wchar_t as `%T'", TREE_TYPE (x)); |
| |
| /* Throw away the redeclaration. */ |
| return t; |
| } |
| else if (TREE_CODE (t) != TREE_CODE (x)) |
| { |
| if (duplicate_decls (x, t)) |
| return t; |
| } |
| else if (duplicate_decls (x, t)) |
| { |
| #if 0 |
| /* This is turned off until I have time to do it right (bpk). */ |
| |
| /* Also warn if they did a prototype with `static' on it, but |
| then later left the `static' off. */ |
| if (! TREE_PUBLIC (name) && TREE_PUBLIC (x)) |
| { |
| if (DECL_LANG_SPECIFIC (t) && DECL_FRIEND_P (t)) |
| return t; |
| |
| if (extra_warnings) |
| { |
| cp_warning ("`static' missing from declaration of `%D'", |
| t); |
| warning_with_file_and_line (file, line, |
| "previous declaration of `%s'", |
| decl_as_string (t, 0)); |
| } |
| |
| /* Now fix things so it'll do what they expect. */ |
| if (current_function_decl) |
| TREE_PUBLIC (current_function_decl) = 0; |
| } |
| /* Due to interference in memory reclamation (X may be |
| obstack-deallocated at this point), we must guard against |
| one really special case. [jason: This should be handled |
| by start_function] */ |
| if (current_function_decl == x) |
| current_function_decl = t; |
| #endif |
| if (TREE_CODE (t) == TYPE_DECL) |
| SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (t)); |
| else if (TREE_CODE (t) == FUNCTION_DECL) |
| check_default_args (t); |
| |
| return t; |
| } |
| else if (DECL_MAIN_P (x)) |
| { |
| /* A redeclaration of main, but not a duplicate of the |
| previous one. |
| |
| [basic.start.main] |
| |
| This function shall not be overloaded. */ |
| cp_error_at ("invalid redeclaration of `%D'", t); |
| cp_error ("as `%D'", x); |
| /* We don't try to push this declaration since that |
| causes a crash. */ |
| return x; |
| } |
| } |
| |
| if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x)) |
| { |
| t = push_overloaded_decl (x, 1); |
| if (t != x || DECL_LANGUAGE (x) == lang_c) |
| return t; |
| } |
| else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x)) |
| return push_overloaded_decl (x, 0); |
| |
| /* If declaring a type as a typedef, copy the type (unless we're |
| at line 0), and install this TYPE_DECL as the new type's typedef |
| name. See the extensive comment in ../c-decl.c (pushdecl). */ |
| if (TREE_CODE (x) == TYPE_DECL) |
| { |
| tree type = TREE_TYPE (x); |
| if (DECL_SOURCE_LINE (x) == 0) |
| { |
| if (TYPE_NAME (type) == 0) |
| TYPE_NAME (type) = x; |
| } |
| else if (type != error_mark_node && TYPE_NAME (type) != x) |
| { |
| push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type)); |
| |
| DECL_ORIGINAL_TYPE (x) = type; |
| type = build_type_copy (type); |
| TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x)); |
| TYPE_NAME (type) = x; |
| TREE_TYPE (x) = type; |
| |
| pop_obstacks (); |
| } |
| |
| if (type != error_mark_node |
| && TYPE_NAME (type) |
| && TYPE_IDENTIFIER (type)) |
| set_identifier_type_value_with_scope (DECL_NAME (x), type, b); |
| } |
| |
| /* Multiple external decls of the same identifier ought to match. |
| |
| We get warnings about inline functions where they are defined. |
| We get warnings about other functions from push_overloaded_decl. |
| |
| Avoid duplicate warnings where they are used. */ |
| if (TREE_PUBLIC (x) && TREE_CODE (x) != FUNCTION_DECL) |
| { |
| tree decl; |
| tree bindings = binding_for_name (name, current_namespace); |
| |
| if (BINDING_VALUE (bindings) != NULL_TREE |
| && (DECL_EXTERNAL (BINDING_VALUE (bindings)) |
| || TREE_PUBLIC (BINDING_VALUE (bindings)))) |
| decl = BINDING_VALUE (bindings); |
| else |
| decl = NULL_TREE; |
| |
| if (decl |
| /* If different sort of thing, we already gave an error. */ |
| && TREE_CODE (decl) == TREE_CODE (x) |
| && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl), 1)) |
| { |
| cp_pedwarn ("type mismatch with previous external decl", x); |
| cp_pedwarn_at ("previous external decl of `%#D'", decl); |
| } |
| } |
| |
| /* This name is new in its binding level. |
| Install the new declaration and return it. */ |
| if (namespace_bindings_p ()) |
| { |
| /* Install a global value. */ |
| tree bindings = binding_for_name (name, current_namespace); |
| |
| /* If the first global decl has external linkage, |
| warn if we later see static one. */ |
| if (BINDING_VALUE (bindings) == NULL_TREE && TREE_PUBLIC (x)) |
| TREE_PUBLIC (name) = 1; |
| |
| /* Don't install an artificial TYPE_DECL if we already have |
| another _DECL with that name. */ |
| if (TREE_CODE (x) != TYPE_DECL |
| || t == NULL_TREE |
| || ! DECL_ARTIFICIAL (x)) |
| { |
| if (TREE_CODE (x) == FUNCTION_DECL) |
| my_friendly_assert ((BINDING_VALUE (bindings) == NULL_TREE) |
| || BINDING_VALUE (bindings) == x, 378); |
| BINDING_VALUE (bindings) = x; |
| } |
| |
| /* Don't forget if the function was used via an implicit decl. */ |
| if (IDENTIFIER_IMPLICIT_DECL (name) |
| && TREE_USED (IDENTIFIER_IMPLICIT_DECL (name))) |
| TREE_USED (x) = 1; |
| |
| /* Don't forget if its address was taken in that way. */ |
| if (IDENTIFIER_IMPLICIT_DECL (name) |
| && TREE_ADDRESSABLE (IDENTIFIER_IMPLICIT_DECL (name))) |
| TREE_ADDRESSABLE (x) = 1; |
| |
| /* Warn about mismatches against previous implicit decl. */ |
| if (IDENTIFIER_IMPLICIT_DECL (name) != NULL_TREE |
| /* If this real decl matches the implicit, don't complain. */ |
| && ! (TREE_CODE (x) == FUNCTION_DECL |
| && TREE_TYPE (TREE_TYPE (x)) == integer_type_node)) |
| cp_warning |
| ("`%D' was previously implicitly declared to return `int'", x); |
| |
| /* If new decl is `static' and an `extern' was seen previously, |
| warn about it. */ |
| if (x != NULL_TREE && t != NULL_TREE && decls_match (x, t)) |
| warn_extern_redeclared_static (x, t); |
| } |
| else |
| { |
| /* Here to install a non-global value. */ |
| tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); |
| tree oldglobal = binding_for_name (name, current_namespace); |
| |
| /* Don't install an artificial TYPE_DECL if we already have |
| another _DECL with that name. */ |
| if (TREE_CODE (x) != TYPE_DECL |
| || t == NULL_TREE |
| || ! DECL_ARTIFICIAL (x)) |
| set_identifier_local_value_with_scope (name, x, b); |
| |
| /* If this is a TYPE_DECL, push it into the type value slot. */ |
| if (TREE_CODE (x) == TYPE_DECL) |
| set_identifier_type_value_with_scope (name, TREE_TYPE (x), b); |
| |
| /* Clear out any TYPE_DECL shadowed by a namespace so that |
| we won't think this is a type. The C struct hack doesn't |
| go through namespaces. */ |
| if (TREE_CODE (x) == NAMESPACE_DECL) |
| set_identifier_type_value_with_scope (name, NULL_TREE, b); |
| |
| /* If this is an extern function declaration, see if we |
| have a global definition or declaration for the function. */ |
| if (oldlocal == NULL_TREE |
| && DECL_EXTERNAL (x) |
| && BINDING_VALUE (oldglobal) != NULL_TREE |
| && TREE_CODE (x) == FUNCTION_DECL |
| && TREE_CODE (BINDING_VALUE (oldglobal)) == FUNCTION_DECL) |
| { |
| /* We have one. Their types must agree. */ |
| if (decls_match (x, BINDING_VALUE (oldglobal))) |
| /* OK */; |
| else |
| { |
| cp_warning ("extern declaration of `%#D' doesn't match", x); |
| cp_warning_at ("global declaration `%#D'", BINDING_VALUE (oldglobal)); |
| } |
| } |
| /* If we have a local external declaration, |
| and no file-scope declaration has yet been seen, |
| then if we later have a file-scope decl it must not be static. */ |
| if (oldlocal == NULL_TREE |
| && BINDING_VALUE (oldglobal) == NULL_TREE |
| && DECL_EXTERNAL (x) |
| && TREE_PUBLIC (x)) |
| { |
| TREE_PUBLIC (name) = 1; |
| } |
| |
| if (DECL_FROM_INLINE (x)) |
| /* Inline decls shadow nothing. */; |
| |
| /* Warn if shadowing an argument at the top level of the body. */ |
| else if (oldlocal != NULL_TREE && !DECL_EXTERNAL (x) |
| && TREE_CODE (oldlocal) == PARM_DECL |
| && TREE_CODE (x) != PARM_DECL) |
| { |
| /* Go to where the parms should be and see if we |
| find them there. */ |
| struct binding_level *b = current_binding_level->level_chain; |
| |
| if (cleanup_label) |
| b = b->level_chain; |
| |
| /* ARM $8.3 */ |
| if (b->parm_flag == 1) |
| cp_error ("declaration of `%#D' shadows a parameter", name); |
| } |
| else if (warn_shadow && oldlocal != NULL_TREE && b->is_for_scope |
| && !DECL_DEAD_FOR_LOCAL (oldlocal)) |
| { |
| warning ("variable `%s' shadows local", |
| IDENTIFIER_POINTER (name)); |
| cp_warning_at (" this is the shadowed declaration", oldlocal); |
| } |
| /* Maybe warn if shadowing something else. */ |
| else if (warn_shadow && !DECL_EXTERNAL (x) |
| /* No shadow warnings for internally generated vars. */ |
| && ! DECL_ARTIFICIAL (x) |
| /* No shadow warnings for vars made for inlining. */ |
| && ! DECL_FROM_INLINE (x)) |
| { |
| char *warnstring = NULL; |
| |
| if (oldlocal != NULL_TREE && TREE_CODE (oldlocal) == PARM_DECL) |
| warnstring = "declaration of `%s' shadows a parameter"; |
| else if (IDENTIFIER_CLASS_VALUE (name) != NULL_TREE |
| && current_class_ptr |
| && !TREE_STATIC (name)) |
| warnstring = "declaration of `%s' shadows a member of `this'"; |
| else if (oldlocal != NULL_TREE) |
| warnstring = "declaration of `%s' shadows previous local"; |
| else if (BINDING_VALUE (oldglobal) != NULL_TREE) |
| /* XXX shadow warnings in outer-more namespaces */ |
| warnstring = "declaration of `%s' shadows global declaration"; |
| |
| if (warnstring) |
| warning (warnstring, IDENTIFIER_POINTER (name)); |
| } |
| } |
| |
| if (TREE_CODE (x) == FUNCTION_DECL) |
| check_default_args (x); |
| |
| /* Keep count of variables in this level with incomplete type. */ |
| if (TREE_CODE (x) == VAR_DECL |
| && TREE_TYPE (x) != error_mark_node |
| && ((TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE |
| && PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE)) |
| /* RTTI TD entries are created while defining the type_info. */ |
| || (TYPE_LANG_SPECIFIC (TREE_TYPE (x)) |
| && TYPE_BEING_DEFINED (TREE_TYPE (x))))) |
| b->incomplete = tree_cons (NULL_TREE, x, b->incomplete); |
| } |
| |
| /* Put decls on list in reverse order. |
| We will reverse them later if necessary. */ |
| TREE_CHAIN (x) = b->names; |
| b->names = x; |
| if (! (b != global_binding_level || TREE_PERMANENT (x))) |
| my_friendly_abort (124); |
| |
| return x; |
| } |
| |
| /* Same as pushdecl, but define X in binding-level LEVEL. We rely on the |
| caller to set DECL_CONTEXT properly. */ |
| |
| static tree |
| pushdecl_with_scope (x, level) |
| tree x; |
| struct binding_level *level; |
| { |
| register struct binding_level *b; |
| tree function_decl = current_function_decl; |
| |
| current_function_decl = NULL_TREE; |
| if (level->parm_flag == 2) |
| { |
| b = class_binding_level; |
| class_binding_level = level; |
| pushdecl_class_level (x); |
| class_binding_level = b; |
| } |
| else |
| { |
| b = current_binding_level; |
| current_binding_level = level; |
| x = pushdecl (x); |
| current_binding_level = b; |
| } |
| current_function_decl = function_decl; |
| return x; |
| } |
| |
| /* Like pushdecl, only it places X in the current namespace, |
| if appropriate. */ |
| |
| tree |
| pushdecl_namespace_level (x) |
| tree x; |
| { |
| register struct binding_level *b = inner_binding_level; |
| register tree t; |
| |
| t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace)); |
| |
| /* Now, the type_shadowed stack may screw us. Munge it so it does |
| what we want. */ |
| if (TREE_CODE (x) == TYPE_DECL) |
| { |
| tree name = DECL_NAME (x); |
| tree newval; |
| tree *ptr = (tree *)0; |
| for (; b != global_binding_level; b = b->level_chain) |
| { |
| tree shadowed = b->type_shadowed; |
| for (; shadowed; shadowed = TREE_CHAIN (shadowed)) |
| if (TREE_PURPOSE (shadowed) == name) |
| { |
| ptr = &TREE_VALUE (shadowed); |
| /* Can't break out of the loop here because sometimes |
| a binding level will have duplicate bindings for |
| PT names. It's gross, but I haven't time to fix it. */ |
| } |
| } |
| newval = TREE_TYPE (x); |
| if (ptr == (tree *)0) |
| { |
| /* @@ This shouldn't be needed. My test case "zstring.cc" trips |
| up here if this is changed to an assertion. --KR */ |
| SET_IDENTIFIER_TYPE_VALUE (name, newval); |
| } |
| else |
| { |
| *ptr = newval; |
| } |
| } |
| return t; |
| } |
| |
| /* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, |
| if appropriate. */ |
| |
| tree |
| pushdecl_top_level (x) |
| tree x; |
| { |
| tree cur_namespace = current_namespace; |
| current_namespace = global_namespace; |
| x = pushdecl_namespace_level (x); |
| current_namespace = cur_namespace; |
| return x; |
| } |
| |
| /* Make the declaration of X appear in CLASS scope. */ |
| |
| tree |
| pushdecl_class_level (x) |
| tree x; |
| { |
| /* Don't use DECL_ASSEMBLER_NAME here! Everything that looks in class |
| scope looks for the pre-mangled name. */ |
| register tree name = DECL_NAME (x); |
| |
| if (name) |
| { |
| if (TYPE_BEING_DEFINED (current_class_type)) |
| { |
| /* A name N used in a class S shall refer to the same declaration |
| in its context and when re-evaluated in the completed scope of S. |
| |
| Types, enums, and static vars are checked here; other |
| members are checked in finish_struct. */ |
| tree icv = IDENTIFIER_CLASS_VALUE (name); |
| |
| if (icv && icv != x |
| && flag_optional_diags |
| /* Don't complain about inherited names. */ |
| && id_in_current_class (name) |
| /* Or shadowed tags. */ |
| && !(DECL_DECLARES_TYPE_P (icv) |
| && DECL_CONTEXT (icv) == current_class_type)) |
| { |
| cp_pedwarn ("declaration of identifier `%D' as `%#D'", name, x); |
| cp_pedwarn_at ("conflicts with previous use in class as `%#D'", |
| icv); |
| } |
| } |
| |
| push_class_level_binding (name, x); |
| if (TREE_CODE (x) == TYPE_DECL) |
| { |
| set_identifier_type_value (name, TREE_TYPE (x)); |
| } |
| } |
| return x; |
| } |
| |
| #if 0 |
| /* This function is used to push the mangled decls for nested types into |
| the appropriate scope. Previously pushdecl_top_level was used, but that |
| is incorrect for members of local classes. */ |
| |
| void |
| pushdecl_nonclass_level (x) |
| tree x; |
| { |
| struct binding_level *b = current_binding_level; |
| |
| my_friendly_assert (b->parm_flag != 2, 180); |
| |
| #if 0 |
| /* Get out of template binding levels */ |
| while (b->pseudo_global) |
| b = b->level_chain; |
| #endif |
| |
| pushdecl_with_scope (x, b); |
| } |
| #endif |
| |
| /* Make the declaration(s) of X appear in CLASS scope |
| under the name NAME. */ |
| |
| void |
| push_class_level_binding (name, x) |
| tree name; |
| tree x; |
| { |
| /* The class_binding_level will be NULL if x is a template |
| parameter name in a member template. */ |
| if (!class_binding_level) |
| return; |
| |
| if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x) |
| && purpose_member (name, class_binding_level->class_shadowed)) |
| return; |
| |
| maybe_push_cache_obstack (); |
| class_binding_level->class_shadowed |
| = tree_cons (name, IDENTIFIER_CLASS_VALUE (name), |
| class_binding_level->class_shadowed); |
| pop_obstacks (); |
| IDENTIFIER_CLASS_VALUE (name) = x; |
| obstack_ptr_grow (&decl_obstack, x); |
| } |
| |
| /* Insert another USING_DECL into the current binding level, |
| returning this declaration. If this is a redeclaration, |
| do nothing and return NULL_TREE. */ |
| |
| tree |
| push_using_decl (scope, name) |
| tree scope; |
| tree name; |
| { |
| tree decl; |
| |
| my_friendly_assert (TREE_CODE (scope) == NAMESPACE_DECL, 383); |
| my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 384); |
| for (decl = current_binding_level->usings; decl; decl = TREE_CHAIN (decl)) |
| if (DECL_INITIAL (decl) == scope && DECL_NAME (decl) == name) |
| break; |
| if (decl) |
| return NULL_TREE; |
| decl = build_lang_decl (USING_DECL, name, void_type_node); |
| DECL_INITIAL (decl) = scope; |
| TREE_CHAIN (decl) = current_binding_level->usings; |
| current_binding_level->usings = decl; |
| return decl; |
| } |
| |
| /* Add namespace to using_directives. Return NULL_TREE if nothing was |
| changed (i.e. there was already a directive), or the fresh |
| TREE_LIST otherwise. */ |
| |
| tree |
| push_using_directive (used) |
| tree used; |
| { |
| tree ud = current_binding_level->using_directives; |
| tree iter, ancestor; |
| |
| /* Check if we already have this. */ |
| if (purpose_member (used, ud) != NULL_TREE) |
| return NULL_TREE; |
| |
| /* Recursively add all namespaces used. */ |
| for (iter = DECL_NAMESPACE_USING (used); iter; iter = TREE_CHAIN (iter)) |
| push_using_directive (TREE_PURPOSE (iter)); |
| |
| ancestor = namespace_ancestor (current_decl_namespace (), used); |
| ud = current_binding_level->using_directives; |
| ud = perm_tree_cons (used, ancestor, ud); |
| current_binding_level->using_directives = ud; |
| return ud; |
| } |
| |
| /* DECL is a FUNCTION_DECL which may have other definitions already in |
| place. We get around this by making the value of the identifier point |
| to a list of all the things that want to be referenced by that name. It |
| is then up to the users of that name to decide what to do with that |
| list. |
| |
| DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its DECL_RESULT |
| slot. It is dealt with the same way. |
| |
| The value returned may be a previous declaration if we guessed wrong |
| about what language DECL should belong to (C or C++). Otherwise, |
| it's always DECL (and never something that's not a _DECL). */ |
| |
| static tree |
| push_overloaded_decl (decl, forgettable) |
| tree decl; |
| int forgettable; |
| { |
| tree orig_name = DECL_NAME (decl); |
| tree old; |
| int doing_global = (namespace_bindings_p () || ! forgettable); |
| |
| if (doing_global) |
| { |
| old = namespace_binding (orig_name, DECL_CONTEXT (decl)); |
| if (old && TREE_CODE (old) == FUNCTION_DECL |
| && DECL_ARTIFICIAL (old) |
| && (DECL_BUILT_IN (old) || DECL_BUILT_IN_NONANSI (old))) |
| { |
| if (duplicate_decls (decl, old)) |
| return old; |
| old = NULL_TREE; |
| } |
| } |
| else |
| { |
| old = IDENTIFIER_LOCAL_VALUE (orig_name); |
| |
| if (! purpose_member (orig_name, current_binding_level->shadowed)) |
| { |
| current_binding_level->shadowed |
| = tree_cons (orig_name, old, current_binding_level->shadowed); |
| old = NULL_TREE; |
| } |
| } |
| |
| if (old) |
| { |
| if (TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old)) |
| { |
| tree t = TREE_TYPE (old); |
| if (IS_AGGR_TYPE (t) && warn_shadow |
| && (! DECL_IN_SYSTEM_HEADER (decl) |
| || ! DECL_IN_SYSTEM_HEADER (old))) |
| cp_warning ("`%#D' hides constructor for `%#T'", decl, t); |
| old = NULL_TREE; |
| } |
| else if (is_overloaded_fn (old)) |
| { |
| tree tmp; |
| |
| for (tmp = old; tmp; tmp = OVL_NEXT (tmp)) |
| if (decl == OVL_CURRENT (tmp) |
| || duplicate_decls (decl, OVL_CURRENT (tmp))) |
| return OVL_CURRENT (tmp); |
| } |
| else |
| { |
| cp_error_at ("previous non-function declaration `%#D'", old); |
| cp_error ("conflicts with function declaration `%#D'", decl); |
| return decl; |
| } |
| } |
| |
| if (old || TREE_CODE (decl) == TEMPLATE_DECL) |
| { |
| if (old && TREE_CODE (old) != OVERLOAD) |
| old = ovl_cons (old, NULL_TREE); |
| old = ovl_cons (decl, old); |
| } |
| else |
| /* orig_name is not ambiguous. */ |
| old = decl; |
| |
| if (doing_global) |
| set_namespace_binding (orig_name, current_namespace, old); |
| else |
| IDENTIFIER_LOCAL_VALUE (orig_name) = old; |
| |
| return decl; |
| } |
| |
| /* Generate an implicit declaration for identifier FUNCTIONID |
| as a function of type int (). Print a warning if appropriate. */ |
| |
| tree |
| implicitly_declare (functionid) |
| tree functionid; |
| { |
| register tree decl; |
| int temp = allocation_temporary_p (); |
| |
| push_obstacks_nochange (); |
| |
| /* Save the decl permanently so we can warn if definition follows. |
| In ANSI C, warn_implicit is usually false, so the saves little space. |
| But in C++, it's usually true, hence the extra code. */ |
| if (temp && (! warn_implicit || toplevel_bindings_p ())) |
| end_temporary_allocation (); |
| |
| /* We used to reuse an old implicit decl here, |
| but this loses with inline functions because it can clobber |
| the saved decl chains. */ |
| decl = build_lang_decl (FUNCTION_DECL, functionid, default_function_type); |
| |
| DECL_EXTERNAL (decl) = 1; |
| TREE_PUBLIC (decl) = 1; |
| |
| /* ANSI standard says implicit declarations are in the innermost block. |
| So we record the decl in the standard fashion. */ |
| pushdecl (decl); |
| rest_of_decl_compilation (decl, NULL_PTR, 0, 0); |
| |
| if (warn_implicit |
| /* Only one warning per identifier. */ |
| && IDENTIFIER_IMPLICIT_DECL (functionid) == NULL_TREE) |
| { |
| cp_pedwarn ("implicit declaration of function `%#D'", decl); |
| } |
| |
| SET_IDENTIFIER_IMPLICIT_DECL (functionid, decl); |
| |
| pop_obstacks (); |
| |
| return decl; |
| } |
| |
| /* Return zero if the declaration NEWDECL is valid |
| when the declaration OLDDECL (assumed to be for the same name) |
| has already been seen. |
| Otherwise return an error message format string with a %s |
| where the identifier should go. */ |
| |
| static char * |
| redeclaration_error_message (newdecl, olddecl) |
| tree newdecl, olddecl; |
| { |
| if (TREE_CODE (newdecl) == TYPE_DECL) |
| { |
| /* Because C++ can put things into name space for free, |
| constructs like "typedef struct foo { ... } foo" |
| would look like an erroneous redeclaration. */ |
| if (comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0)) |
| return 0; |
| else |
| return "redefinition of `%#D'"; |
| } |
| else if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| /* If this is a pure function, its olddecl will actually be |
| the original initialization to `0' (which we force to call |
| abort()). Don't complain about redefinition in this case. */ |
| if (DECL_LANG_SPECIFIC (olddecl) && DECL_ABSTRACT_VIRTUAL_P (olddecl)) |
| return 0; |
| |
| /* If both functions come from different namespaces, this is not |
| a redeclaration - this is a conflict with a used function. */ |
| if (DECL_NAMESPACE_SCOPE_P (olddecl) |
| && DECL_CONTEXT (olddecl) != DECL_CONTEXT (newdecl)) |
| return "`%D' conflicts with used function"; |
| |
| /* We'll complain about linkage mismatches in |
| warn_extern_redeclared_static. */ |
| |
| /* Defining the same name twice is no good. */ |
| if (DECL_INITIAL (olddecl) != NULL_TREE |
| && DECL_INITIAL (newdecl) != NULL_TREE) |
| { |
| if (DECL_NAME (olddecl) == NULL_TREE) |
| return "`%#D' not declared in class"; |
| else |
| return "redefinition of `%#D'"; |
| } |
| return 0; |
| } |
| else if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| if ((TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL |
| && DECL_INITIAL (DECL_TEMPLATE_RESULT (newdecl)) |
| && DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl))) |
| || (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL |
| && TYPE_SIZE (TREE_TYPE (newdecl)) |
| && TYPE_SIZE (TREE_TYPE (olddecl)))) |
| return "redefinition of `%#D'"; |
| return 0; |
| } |
| else if (toplevel_bindings_p ()) |
| { |
| /* Objects declared at top level: */ |
| /* If at least one is a reference, it's ok. */ |
| if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl)) |
| return 0; |
| /* Reject two definitions. */ |
| return "redefinition of `%#D'"; |
| } |
| else |
| { |
| /* Objects declared with block scope: */ |
| /* Reject two definitions, and reject a definition |
| together with an external reference. */ |
| if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl))) |
| return "redeclaration of `%#D'"; |
| return 0; |
| } |
| } |
| |
| /* Get the LABEL_DECL corresponding to identifier ID as a label. |
| Create one if none exists so far for the current function. |
| This function is called for both label definitions and label references. */ |
| |
| tree |
| lookup_label (id) |
| tree id; |
| { |
| register tree decl = IDENTIFIER_LABEL_VALUE (id); |
| |
| if (current_function_decl == NULL_TREE) |
| { |
| error ("label `%s' referenced outside of any function", |
| IDENTIFIER_POINTER (id)); |
| return NULL_TREE; |
| } |
| |
| if ((decl == NULL_TREE |
| || DECL_SOURCE_LINE (decl) == 0) |
| && (named_label_uses == NULL |
| || named_label_uses->names_in_scope != current_binding_level->names |
| || named_label_uses->label_decl != decl)) |
| { |
| struct named_label_list *new_ent; |
| new_ent |
| = (struct named_label_list*)oballoc (sizeof (struct named_label_list)); |
| new_ent->label_decl = decl; |
| new_ent->names_in_scope = current_binding_level->names; |
| new_ent->binding_level = current_binding_level; |
| new_ent->lineno_o_goto = lineno; |
| new_ent->filename_o_goto = input_filename; |
| new_ent->next = named_label_uses; |
| named_label_uses = new_ent; |
| } |
| |
| /* Use a label already defined or ref'd with this name. */ |
| if (decl != NULL_TREE) |
| { |
| /* But not if it is inherited and wasn't declared to be inheritable. */ |
| if (DECL_CONTEXT (decl) != current_function_decl |
| && ! C_DECLARED_LABEL_FLAG (decl)) |
| return shadow_label (id); |
| return decl; |
| } |
| |
| decl = build_decl (LABEL_DECL, id, void_type_node); |
| |
| /* Make sure every label has an rtx. */ |
| label_rtx (decl); |
| |
| /* A label not explicitly declared must be local to where it's ref'd. */ |
| DECL_CONTEXT (decl) = current_function_decl; |
| |
| DECL_MODE (decl) = VOIDmode; |
| |
| /* Say where one reference is to the label, |
| for the sake of the error if it is not defined. */ |
| DECL_SOURCE_LINE (decl) = lineno; |
| DECL_SOURCE_FILE (decl) = input_filename; |
| |
| SET_IDENTIFIER_LABEL_VALUE (id, decl); |
| |
| named_labels = tree_cons (NULL_TREE, decl, named_labels); |
| named_label_uses->label_decl = decl; |
| |
| return decl; |
| } |
| |
| /* Make a label named NAME in the current function, |
| shadowing silently any that may be inherited from containing functions |
| or containing scopes. |
| |
| Note that valid use, if the label being shadowed |
| comes from another scope in the same function, |
| requires calling declare_nonlocal_label right away. */ |
| |
| tree |
| shadow_label (name) |
| tree name; |
| { |
| register tree decl = IDENTIFIER_LABEL_VALUE (name); |
| |
| if (decl != NULL_TREE) |
| { |
| shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels); |
| SET_IDENTIFIER_LABEL_VALUE (name, NULL_TREE); |
| } |
| |
| return lookup_label (name); |
| } |
| |
| /* Define a label, specifying the location in the source file. |
| Return the LABEL_DECL node for the label, if the definition is valid. |
| Otherwise return 0. */ |
| |
| tree |
| define_label (filename, line, name) |
| char *filename; |
| int line; |
| tree name; |
| { |
| tree decl; |
| |
| if (minimal_parse_mode) |
| { |
| push_obstacks (&permanent_obstack, &permanent_obstack); |
| decl = build_decl (LABEL_DECL, name, void_type_node); |
| pop_obstacks (); |
| DECL_SOURCE_LINE (decl) = line; |
| DECL_SOURCE_FILE (decl) = filename; |
| add_tree (decl); |
| return decl; |
| } |
| |
| decl = lookup_label (name); |
| |
| /* After labels, make any new cleanups go into their |
| own new (temporary) binding contour. */ |
| current_binding_level->more_cleanups_ok = 0; |
| |
| /* If label with this name is known from an outer context, shadow it. */ |
| if (decl != NULL_TREE && DECL_CONTEXT (decl) != current_function_decl) |
| { |
| shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels); |
| SET_IDENTIFIER_LABEL_VALUE (name, NULL_TREE); |
| decl = lookup_label (name); |
| } |
| |
| if (name == get_identifier ("wchar_t")) |
| cp_pedwarn ("label named wchar_t"); |
| |
| if (DECL_INITIAL (decl) != NULL_TREE) |
| { |
| cp_error ("duplicate label `%D'", decl); |
| return 0; |
| } |
| else |
| { |
| struct named_label_list *uses, *prev; |
| int identified = 0; |
| |
| /* Mark label as having been defined. */ |
| DECL_INITIAL (decl) = error_mark_node; |
| /* Say where in the source. */ |
| DECL_SOURCE_FILE (decl) = filename; |
| DECL_SOURCE_LINE (decl) = line; |
| |
| prev = NULL; |
| uses = named_label_uses; |
| while (uses != NULL) |
| if (uses->label_decl == decl) |
| { |
| struct binding_level *b = current_binding_level; |
| while (b) |
| { |
| tree new_decls = b->names; |
| tree old_decls = (b == uses->binding_level) |
| ? uses->names_in_scope : NULL_TREE; |
| while (new_decls != old_decls) |
| { |
| if (TREE_CODE (new_decls) == VAR_DECL |
| /* Don't complain about crossing initialization |
| of internal entities. They can't be accessed, |
| and they should be cleaned up |
| by the time we get to the label. */ |
| && ! DECL_ARTIFICIAL (new_decls) |
| && ((DECL_INITIAL (new_decls) != NULL_TREE |
| && DECL_INITIAL (new_decls) != error_mark_node) |
| || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls)))) |
| { |
| if (! identified) |
| { |
| cp_error ("jump to label `%D'", decl); |
| error_with_file_and_line (uses->filename_o_goto, |
| uses->lineno_o_goto, |
| " from here"); |
| identified = 1; |
| } |
| cp_error_at (" crosses initialization of `%#D'", |
| new_decls); |
| } |
| new_decls = TREE_CHAIN (new_decls); |
| } |
| if (b == uses->binding_level) |
| break; |
| b = b->level_chain; |
| } |
| |
| if (prev != NULL) |
| prev->next = uses->next; |
| else |
| named_label_uses = uses->next; |
| |
| uses = uses->next; |
| } |
| else |
| { |
| prev = uses; |
| uses = uses->next; |
| } |
| current_function_return_value = NULL_TREE; |
| return decl; |
| } |
| } |
| |
| struct cp_switch |
| { |
| struct binding_level *level; |
| struct cp_switch *next; |
| }; |
| |
| static struct cp_switch *switch_stack; |
| |
| void |
| push_switch () |
| { |
| struct cp_switch *p |
| = (struct cp_switch *) oballoc (sizeof (struct cp_switch)); |
| p->level = current_binding_level; |
| p->next = switch_stack; |
| switch_stack = p; |
| } |
| |
| void |
| pop_switch () |
| { |
| switch_stack = switch_stack->next; |
| } |
| |
| /* Same, but for CASE labels. If DECL is NULL_TREE, it's the default. */ |
| /* XXX Note decl is never actually used. (bpk) */ |
| |
| void |
| define_case_label (decl) |
| tree decl; |
| { |
| tree cleanup = last_cleanup_this_contour (); |
| struct binding_level *b = current_binding_level; |
| int identified = 0; |
| |
| if (cleanup) |
| { |
| static int explained = 0; |
| cp_warning_at ("destructor needed for `%#D'", TREE_PURPOSE (cleanup)); |
| warning ("where case label appears here"); |
| if (!explained) |
| { |
| warning ("(enclose actions of previous case statements requiring"); |
| warning ("destructors in their own binding contours.)"); |
| explained = 1; |
| } |
| } |
| |
| for (; b && b != switch_stack->level; b = b->level_chain) |
| { |
| tree new_decls = b->names; |
| for (; new_decls; new_decls = TREE_CHAIN (new_decls)) |
| { |
| if (TREE_CODE (new_decls) == VAR_DECL |
| /* Don't complain about crossing initialization |
| of internal entities. They can't be accessed, |
| and they should be cleaned up |
| by the time we get to the label. */ |
| && ! DECL_ARTIFICIAL (new_decls) |
| && ((DECL_INITIAL (new_decls) != NULL_TREE |
| && DECL_INITIAL (new_decls) != error_mark_node) |
| || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls)))) |
| { |
| if (! identified) |
| error ("jump to case label"); |
| identified = 1; |
| cp_error_at (" crosses initialization of `%#D'", |
| new_decls); |
| } |
| } |
| } |
| |
| /* After labels, make any new cleanups go into their |
| own new (temporary) binding contour. */ |
| |
| current_binding_level->more_cleanups_ok = 0; |
| current_function_return_value = NULL_TREE; |
| } |
| |
| /* Return the list of declarations of the current level. |
| Note that this list is in reverse order unless/until |
| you nreverse it; and when you do nreverse it, you must |
| store the result back using `storedecls' or you will lose. */ |
| |
| tree |
| getdecls () |
| { |
| return current_binding_level->names; |
| } |
| |
| /* Return the list of type-tags (for structs, etc) of the current level. */ |
| |
| tree |
| gettags () |
| { |
| return current_binding_level->tags; |
| } |
| |
| /* Store the list of declarations of the current level. |
| This is done for the parameter declarations of a function being defined, |
| after they are modified in the light of any missing parameters. */ |
| |
| static void |
| storedecls (decls) |
| tree decls; |
| { |
| current_binding_level->names = decls; |
| } |
| |
| /* Similarly, store the list of tags of the current level. */ |
| |
| static void |
| storetags (tags) |
| tree tags; |
| { |
| current_binding_level->tags = tags; |
| } |
| |
| /* Given NAME, an IDENTIFIER_NODE, |
| return the structure (or union or enum) definition for that name. |
| Searches binding levels from BINDING_LEVEL up to the global level. |
| If THISLEVEL_ONLY is nonzero, searches only the specified context |
| (but skips any tag-transparent contexts to find one that is |
| meaningful for tags). |
| FORM says which kind of type the caller wants; |
| it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. |
| If the wrong kind of type is found, and it's not a template, an error is |
| reported. */ |
| |
| static tree |
| lookup_tag (form, name, binding_level, thislevel_only) |
| enum tree_code form; |
| tree name; |
| struct binding_level *binding_level; |
| int thislevel_only; |
| { |
| register struct binding_level *level; |
| |
| for (level = binding_level; level; level = level->level_chain) |
| { |
| register tree tail; |
| if (ANON_AGGRNAME_P (name)) |
| for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) |
| { |
| /* There's no need for error checking here, because |
| anon names are unique throughout the compilation. */ |
| if (TYPE_IDENTIFIER (TREE_VALUE (tail)) == name) |
| return TREE_VALUE (tail); |
| } |
| else if (level->namespace_p) |
| /* Do namespace lookup. */ |
| /* XXX: is this a real lookup, considering using-directives etc. ??? */ |
| for (tail = current_namespace; 1; tail = CP_DECL_CONTEXT (tail)) |
| { |
| tree old = BINDING_TYPE (binding_for_name (name, tail)); |
| /* If it has an original type, it is a typedef, and we |
| should not return it. */ |
| if (old && DECL_ORIGINAL_TYPE (TYPE_NAME (old))) |
| old = NULL_TREE; |
| if (old && TREE_CODE (old) != form |
| && !(form != ENUMERAL_TYPE && TREE_CODE (old) == TEMPLATE_DECL)) |
| { |
| cp_error ("`%#D' redeclared as %C", old, form); |
| return NULL_TREE; |
| } |
| if (old) |
| return old; |
| if (thislevel_only || tail == global_namespace) |
| return NULL_TREE; |
| } |
| else |
| for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) |
| { |
| if (TREE_PURPOSE (tail) == name) |
| { |
| enum tree_code code = TREE_CODE (TREE_VALUE (tail)); |
| /* Should tighten this up; it'll probably permit |
| UNION_TYPE and a struct template, for example. */ |
| if (code != form |
| && !(form != ENUMERAL_TYPE && code == TEMPLATE_DECL)) |
| { |
| /* Definition isn't the kind we were looking for. */ |
| cp_error ("`%#D' redeclared as %C", TREE_VALUE (tail), |
| form); |
| return NULL_TREE; |
| } |
| return TREE_VALUE (tail); |
| } |
| } |
| if (thislevel_only && ! level->tag_transparent) |
| { |
| if (level->pseudo_global) |
| { |
| tree t = IDENTIFIER_CLASS_VALUE (name); |
| if (t && DECL_CLASS_TEMPLATE_P (t)) |
| return TREE_TYPE (t); |
| t = IDENTIFIER_NAMESPACE_VALUE (name); |
| if (t && DECL_CLASS_TEMPLATE_P (t)) |
| return TREE_TYPE (t); |
| } |
| return NULL_TREE; |
| } |
| if (current_class_type && level->level_chain->namespace_p) |
| { |
| /* Try looking in this class's tags before heading into |
| global binding level. */ |
| tree context = current_class_type; |
| while (context) |
| { |
| switch (TREE_CODE_CLASS (TREE_CODE (context))) |
| { |
| tree these_tags; |
| case 't': |
| these_tags = CLASSTYPE_TAGS (context); |
| if (ANON_AGGRNAME_P (name)) |
| while (these_tags) |
| { |
| if (TYPE_IDENTIFIER (TREE_VALUE (these_tags)) |
| == name) |
| return TREE_VALUE (tail); |
| these_tags = TREE_CHAIN (these_tags); |
| } |
| else |
| while (these_tags) |
| { |
| if (TREE_PURPOSE (these_tags) == name) |
| { |
| if (TREE_CODE (TREE_VALUE (these_tags)) != form) |
| { |
| cp_error ("`%#D' redeclared as %C in class scope", |
| TREE_VALUE (tail), form); |
| return NULL_TREE; |
| } |
| return TREE_VALUE (tail); |
| } |
| these_tags = TREE_CHAIN (these_tags); |
| } |
| /* If this type is not yet complete, then don't |
| look at its context. */ |
| if (TYPE_SIZE (context) == NULL_TREE) |
| goto no_context; |
| /* Go to next enclosing type, if any. */ |
| context = DECL_CONTEXT (TYPE_MAIN_DECL (context)); |
| break; |
| case 'd': |
| context = DECL_CONTEXT (context); |
| break; |
| default: |
| my_friendly_abort (10); |
| } |
| continue; |
| no_context: |
| break; |
| } |
| } |
| } |
| return NULL_TREE; |
| } |
| |
| #if 0 |
| void |
| set_current_level_tags_transparency (tags_transparent) |
| int tags_transparent; |
| { |
| current_binding_level->tag_transparent = tags_transparent; |
| } |
| #endif |
| |
| /* Given a type, find the tag that was defined for it and return the tag name. |
| Otherwise return 0. However, the value can never be 0 |
| in the cases in which this is used. |
| |
| C++: If NAME is non-zero, this is the new name to install. This is |
| done when replacing anonymous tags with real tag names. */ |
| |
| static tree |
| lookup_tag_reverse (type, name) |
| tree type; |
| tree name; |
| { |
| register struct binding_level *level; |
| |
| for (level = current_binding_level; level; level = level->level_chain) |
| { |
| register tree tail; |
| for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) |
| { |
| if (TREE_VALUE (tail) == type) |
| { |
| if (name) |
| TREE_PURPOSE (tail) = name; |
| return TREE_PURPOSE (tail); |
| } |
| } |
| } |
| return NULL_TREE; |
| } |
| |
| /* Lookup TYPE in CONTEXT (a chain of nested types or a FUNCTION_DECL). |
| Return the type value, or NULL_TREE if not found. */ |
| |
| static tree |
| lookup_nested_type (type, context) |
| tree type; |
| tree context; |
| { |
| if (context == NULL_TREE) |
| return NULL_TREE; |
| while (context) |
| { |
| switch (TREE_CODE (context)) |
| { |
| case TYPE_DECL: |
| { |
| tree ctype = TREE_TYPE (context); |
| tree match = value_member (type, CLASSTYPE_TAGS (ctype)); |
| if (match) |
| return TREE_VALUE (match); |
| context = DECL_CONTEXT (context); |
| |
| /* When we have a nested class whose member functions have |
| local types (e.g., a set of enums), we'll arrive here |
| with the DECL_CONTEXT as the actual RECORD_TYPE node for |
| the enclosing class. Instead, we want to make sure we |
| come back in here with the TYPE_DECL, not the RECORD_TYPE. */ |
| if (context && TREE_CODE (context) == RECORD_TYPE) |
| context = TREE_CHAIN (context); |
| } |
| break; |
| case FUNCTION_DECL: |
| if (TYPE_NAME (type) && TYPE_IDENTIFIER (type)) |
| return lookup_name (TYPE_IDENTIFIER (type), 1); |
| return NULL_TREE; |
| default: |
| my_friendly_abort (12); |
| } |
| } |
| return NULL_TREE; |
| } |
| |
| /* Look up NAME in the NAMESPACE. */ |
| |
| tree |
| lookup_namespace_name (namespace, name) |
| tree namespace, name; |
| { |
| struct tree_binding _b; |
| tree val; |
| |
| my_friendly_assert (TREE_CODE (namespace) == NAMESPACE_DECL, 370); |
| my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 373); |
| |
| val = binding_init (&_b); |
| if (!qualified_lookup_using_namespace (name, namespace, val, 0)) |
| return error_mark_node; |
| |
| if (BINDING_VALUE (val)) |
| { |
| val = BINDING_VALUE (val); |
| |
| /* If we have a single function from a using decl, pull it out. */ |
| if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val)) |
| val = OVL_FUNCTION (val); |
| return val; |
| } |
| |
| cp_error ("`%D' undeclared in namespace `%D'", name, namespace); |
| return error_mark_node; |
| } |
| |
| tree |
| make_typename_type (context, name) |
| tree context, name; |
| { |
| tree t, d; |
| tree fullname; |
| |
| if (TREE_CODE_CLASS (TREE_CODE (name)) == 't') |
| name = TYPE_IDENTIFIER (name); |
| else if (TREE_CODE (name) == TYPE_DECL) |
| name = DECL_NAME (name); |
| |
| fullname = name; |
| |
| if (TREE_CODE (name) == TEMPLATE_ID_EXPR) |
| { |
| name = TREE_OPERAND (name, 0); |
| if (TREE_CODE (name) == TEMPLATE_DECL) |
| name = TREE_OPERAND (fullname, 0) = DECL_NAME (name); |
| } |
| if (TREE_CODE (name) != IDENTIFIER_NODE) |
| my_friendly_abort (2000); |
| |
| if (! uses_template_parms (context) |
| || currently_open_class (context)) |
| { |
| if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR) |
| { |
| if (IS_AGGR_TYPE (context)) |
| t = lookup_field (context, name, 0, 0); |
| else |
| t = NULL_TREE; |
| |
| if (t == NULL_TREE || TREE_CODE (t) != TEMPLATE_DECL |
| || TREE_CODE (DECL_RESULT (t)) != TYPE_DECL) |
| { |
| cp_error ("no class template named `%#T' in `%#T'", |
| name, context); |
| return error_mark_node; |
| } |
| |
| return lookup_template_class (t, TREE_OPERAND (fullname, 1), |
| NULL_TREE, context); |
| } |
| else |
| { |
| if (IS_AGGR_TYPE (context)) |
| t = lookup_field (context, name, 0, 1); |
| else |
| t = NULL_TREE; |
| |
| if (t == NULL_TREE) |
| { |
| cp_error ("no type named `%#T' in `%#T'", name, context); |
| return error_mark_node; |
| } |
| |
| return TREE_TYPE (t); |
| } |
| } |
| |
| if (processing_template_decl) |
| push_obstacks (&permanent_obstack, &permanent_obstack); |
| t = make_lang_type (TYPENAME_TYPE); |
| TYPENAME_TYPE_FULLNAME (t) = fullname; |
| d = build_decl (TYPE_DECL, name, t); |
| if (processing_template_decl) |
| pop_obstacks (); |
| |
| TYPE_CONTEXT (t) = FROB_CONTEXT (context); |
| TYPE_NAME (TREE_TYPE (d)) = d; |
| TYPE_STUB_DECL (TREE_TYPE (d)) = d; |
| DECL_CONTEXT (d) = FROB_CONTEXT (context); |
| CLASSTYPE_GOT_SEMICOLON (t) = 1; |
| |
| return t; |
| } |
| |
| /* Select the right _DECL from multiple choices. */ |
| |
| static tree |
| select_decl (binding, flags) |
| tree binding; |
| int flags; |
| { |
| tree val; |
| val = BINDING_VALUE (binding); |
| if (LOOKUP_NAMESPACES_ONLY (flags)) |
| { |
| /* We are not interested in types. */ |
| if (val && TREE_CODE (val) == NAMESPACE_DECL) |
| return val; |
| return NULL_TREE; |
| } |
| |
| /* If we could have a type and |
| we have nothing or we need a type and have none. */ |
| if (BINDING_TYPE (binding) |
| && (!val || ((flags & LOOKUP_PREFER_TYPES) |
| && TREE_CODE (val) != TYPE_DECL))) |
| val = TYPE_STUB_DECL (BINDING_TYPE (binding)); |
| /* Don't return non-types if we really prefer types. */ |
| else if (val && LOOKUP_TYPES_ONLY (flags) && TREE_CODE (val) != TYPE_DECL |
| && (!looking_for_template || TREE_CODE (val) != TEMPLATE_DECL)) |
| val = NULL_TREE; |
| |
| return val; |
| } |
| |
| /* Unscoped lookup of a global, iterate over namespaces, considering |
| using namespace statements. */ |
| |
| static tree |
| unqualified_namespace_lookup (name, flags) |
| tree name; |
| int flags; |
| { |
| struct tree_binding _binding; |
| tree b = binding_init (&_binding); |
| tree initial = current_decl_namespace(); |
| tree scope = initial; |
| tree siter; |
| struct binding_level *level; |
| tree val = NULL_TREE; |
| |
| while (!val) |
| { |
| val = binding_for_name (name, scope); |
| |
| /* Initialize binding for this context. */ |
| BINDING_VALUE (b) = BINDING_VALUE (val); |
| BINDING_TYPE (b) = BINDING_TYPE (val); |
| |
| /* Add all _DECLs seen through local using-directives. */ |
| for (level = current_binding_level; |
| !level->namespace_p; |
| level = level->level_chain) |
| if (!lookup_using_namespace (name, b, level->using_directives, |
| scope, flags)) |
| /* Give up because of error. */ |
| return NULL_TREE; |
| |
| /* Add all _DECLs seen through global using-directives. */ |
| /* XXX local and global using lists should work equally. */ |
| siter = initial; |
| while (1) |
| { |
| if (!lookup_using_namespace (name, b, DECL_NAMESPACE_USING (siter), |
| scope, flags)) |
| /* Give up because of error. */ |
| return NULL_TREE; |
| if (siter == scope) break; |
| siter = CP_DECL_CONTEXT (siter); |
| } |
| |
| val = select_decl (b, flags); |
| if (scope == global_namespace) |
| break; |
| scope = CP_DECL_CONTEXT (scope); |
| } |
| return val; |
| } |
| |
| /* Combine prefer_type and namespaces_only into flags. */ |
| |
| static int |
| lookup_flags (prefer_type, namespaces_only) |
| int prefer_type, namespaces_only; |
| { |
| if (namespaces_only) |
| return LOOKUP_PREFER_NAMESPACES; |
| if (prefer_type > 1) |
| return LOOKUP_PREFER_TYPES; |
| if (prefer_type > 0) |
| return LOOKUP_PREFER_BOTH; |
| return 0; |
| } |
| |
| /* Given a lookup that returned VAL, use FLAGS to decide if we want to |
| ignore it or not. Subroutine of lookup_name_real. */ |
| |
| static tree |
| qualify_lookup (val, flags) |
| tree val; |
| int flags; |
| { |
| if (val == NULL_TREE) |
| return val; |
| if ((flags & LOOKUP_PREFER_NAMESPACES) && TREE_CODE (val) == NAMESPACE_DECL) |
| return val; |
| if ((flags & LOOKUP_PREFER_TYPES) |
| && (TREE_CODE (val) == TYPE_DECL |
| || ((flags & LOOKUP_TEMPLATES_EXPECTED) |
| && DECL_CLASS_TEMPLATE_P (val)))) |
| return val; |
| if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES)) |
| return NULL_TREE; |
| return val; |
| } |
| |
| /* Look up NAME in the current binding level and its superiors in the |
| namespace of variables, functions and typedefs. Return a ..._DECL |
| node of some kind representing its definition if there is only one |
| such declaration, or return a TREE_LIST with all the overloaded |
| definitions if there are many, or return 0 if it is undefined. |
| |
| If PREFER_TYPE is > 0, we prefer TYPE_DECLs or namespaces. |
| If PREFER_TYPE is > 1, we reject non-type decls (e.g. namespaces). |
| If PREFER_TYPE is -2, we're being called from yylex(). (UGLY) |
| Otherwise we prefer non-TYPE_DECLs. |
| |
| If NONCLASS is non-zero, we don't look for the NAME in class scope, |
| using IDENTIFIER_CLASS_VALUE. */ |
| |
| static tree |
| lookup_name_real (name, prefer_type, nonclass, namespaces_only) |
| tree name; |
| int prefer_type, nonclass, namespaces_only; |
| { |
| register tree val; |
| int yylex = 0; |
| tree from_obj = NULL_TREE; |
| tree locval, classval; |
| int flags; |
| |
| /* Hack: copy flag set by parser, if set. */ |
| if (only_namespace_names) |
| namespaces_only = 1; |
| |
| if (prefer_type == -2) |
| { |
| extern int looking_for_typename; |
| tree type = NULL_TREE; |
| |
| yylex = 1; |
| prefer_type = looking_for_typename; |
| |
| flags = lookup_flags (prefer_type, namespaces_only); |
| /* During parsing, we need to complain. */ |
| flags |= LOOKUP_COMPLAIN; |
| /* If the next thing is '<', class templates are types. */ |
| if (looking_for_template) |
| flags |= LOOKUP_TEMPLATES_EXPECTED; |
| |
| /* std:: becomes :: for now. */ |
| if (got_scope == std_node) |
| got_scope = void_type_node; |
| |
| if (got_scope) |
| type = got_scope; |
| else if (got_object != error_mark_node) |
| type = got_object; |
| |
| if (type) |
| { |
| if (type == error_mark_node) |
| return error_mark_node; |
| if (TREE_CODE (type) == TYPENAME_TYPE && TREE_TYPE (type)) |
| type = TREE_TYPE (type); |
| |
| if (TYPE_P (type)) |
| type = complete_type (type); |
| |
| if (TREE_CODE (type) == VOID_TYPE) |
| type = global_namespace; |
| if (TREE_CODE (type) == NAMESPACE_DECL) |
| { |
| struct tree_binding b; |
| val = binding_init (&b); |
| if (!qualified_lookup_using_namespace (name, type, val, flags)) |
| return NULL_TREE; |
| val = select_decl (val, flags); |
| } |
| else if (! IS_AGGR_TYPE (type) |
| || TREE_CODE (type) == TEMPLATE_TYPE_PARM |
| || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM |
| || TREE_CODE (type) == TYPENAME_TYPE) |
| /* Someone else will give an error about this if needed. */ |
| val = NULL_TREE; |
| else if (TYPE_BEING_DEFINED (type)) |
| { |
| val = IDENTIFIER_CLASS_VALUE (name); |
| if (val && DECL_CONTEXT (val) != type) |
| { |
| struct binding_level *b = class_binding_level; |
| for (val = NULL_TREE; b; b = b->level_chain) |
| { |
| tree t = purpose_member (name, b->class_shadowed); |
| if (t && TREE_VALUE (t) |
| && DECL_CONTEXT (TREE_VALUE (t)) == type) |
| { |
| val = TREE_VALUE (t); |
| break; |
| } |
| } |
| } |
| if (val == NULL_TREE) |
| val = lookup_field (type, name, 0, 1); |
| } |
| else if (type == current_class_type) |
| val = IDENTIFIER_CLASS_VALUE (name); |
| else |
| val = lookup_member (type, name, 0, prefer_type); |
| } |
| else |
| val = NULL_TREE; |
| |
| if (got_scope) |
| goto done; |
| else if (got_object && val) |
| from_obj = val; |
| } |
| else |
| flags = lookup_flags (prefer_type, namespaces_only); |
| |
| locval = classval = NULL_TREE; |
| |
| if (! namespace_bindings_p ()) |
| locval = qualify_lookup (IDENTIFIER_LOCAL_VALUE (name), flags); |
| |
| /* In C++ class fields are between local and global scope, |
| just before the global scope. */ |
| if (current_class_type && ! nonclass) |
| { |
| classval = IDENTIFIER_CLASS_VALUE (name); |
| if (classval == NULL_TREE && TYPE_BEING_DEFINED (current_class_type)) |
| /* Try to find values from base classes if we are presently |
| defining a type. We are presently only interested in |
| TYPE_DECLs. */ |
| classval = lookup_field (current_class_type, name, 0, 1); |
| |
| /* Add implicit 'typename' to types from template bases. lookup_field |
| will do this for us. If classval is actually from an enclosing |
| scope, lookup_nested_field will get it for us. */ |
| if (processing_template_decl |
| && classval && TREE_CODE (classval) == TYPE_DECL |
| && ! currently_open_class (DECL_CONTEXT (classval)) |
| && uses_template_parms (current_class_type) |
| && ! DECL_ARTIFICIAL (classval)) |
| classval = lookup_field (current_class_type, name, 0, 1); |
| |
| /* yylex() calls this with -2, since we should never start digging for |
| the nested name at the point where we haven't even, for example, |
| created the COMPONENT_REF or anything like that. */ |
| if (classval == NULL_TREE) |
| classval = lookup_nested_field (name, ! yylex); |
| |
| classval = qualify_lookup (classval, flags); |
| } |
| |
| if (locval && classval) |
| { |
| if (current_scope () == current_function_decl |
| && ! hack_decl_function_context (current_function_decl)) |
| /* Not in a nested function. */ |
| val = locval; |
| else |
| { |
| /* This is incredibly horrible. The whole concept of |
| IDENTIFIER_LOCAL_VALUE / IDENTIFIER_CLASS_VALUE / |
| IDENTIFIER_GLOBAL_VALUE needs to be scrapped for local |
| classes. */ |
| tree lctx = hack_decl_function_context (locval); |
| tree cctx = hack_decl_function_context (classval); |
| |
| if (lctx == current_scope ()) |
| val = locval; |
| else if (lctx == cctx) |
| val = classval; |
| else |
| /* I don't know which is right; let's just guess for now. */ |
| val = locval; |
| } |
| } |
| else if (locval) |
| val = locval; |
| else if (classval) |
| val = classval; |
| else |
| val = unqualified_namespace_lookup (name, flags); |
| |
| done: |
| if (val) |
| { |
| /* This should only warn about types used in qualified-ids. */ |
| if (from_obj && from_obj != val) |
| { |
| if (looking_for_typename && TREE_CODE (from_obj) == TYPE_DECL |
| && TREE_CODE (val) == TYPE_DECL |
| && TREE_TYPE (from_obj) != TREE_TYPE (val)) |
| { |
| cp_pedwarn ("lookup of `%D' in the scope of `%#T' (`%#T')", |
| name, got_object, TREE_TYPE (from_obj)); |
| cp_pedwarn (" does not match lookup in the current scope (`%#T')", |
| TREE_TYPE (val)); |
| } |
| |
| /* We don't change val to from_obj if got_object depends on |
| template parms because that breaks implicit typename for |
| destructor calls. */ |
| if (! uses_template_parms (got_object)) |
| val = from_obj; |
| } |
| |
| if ((TREE_CODE (val) == TEMPLATE_DECL && looking_for_template) |
| || TREE_CODE (val) == TYPE_DECL || prefer_type <= 0) |
| ; |
| /* Caller wants a class-or-namespace-name. */ |
| else if (prefer_type == 1 && TREE_CODE (val) == NAMESPACE_DECL) |
| ; |
| else if (IDENTIFIER_HAS_TYPE_VALUE (name)) |
| val = TYPE_MAIN_DECL (IDENTIFIER_TYPE_VALUE (name)); |
| else if (TREE_TYPE (val) == error_mark_node) |
| val = error_mark_node; |
| |
| /* If we have a single function from a using decl, pull it out. */ |
| if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val)) |
| val = OVL_FUNCTION (val); |
| } |
| else if (from_obj) |
| val = from_obj; |
| |
| return val; |
| } |
| |
| tree |
| lookup_name_nonclass (name) |
| tree name; |
| { |
| return lookup_name_real (name, 0, 1, 0); |
| } |
| |
| tree |
| lookup_function_nonclass (name, args) |
| tree name; |
| tree args; |
| { |
| return lookup_arg_dependent (name, lookup_name_nonclass (name), args); |
| } |
| |
| tree |
| lookup_name_namespace_only (name) |
| tree name; |
| { |
| /* type-or-namespace, nonclass, namespace_only */ |
| return lookup_name_real (name, 1, 1, 1); |
| } |
| |
| tree |
| lookup_name (name, prefer_type) |
| tree name; |
| int prefer_type; |
| { |
| return lookup_name_real (name, prefer_type, 0, 0); |
| } |
| |
| /* Similar to `lookup_name' but look only at current binding level. */ |
| |
| tree |
| lookup_name_current_level (name) |
| tree name; |
| { |
| register tree t = NULL_TREE; |
| |
| if (current_binding_level->namespace_p) |
| { |
| t = IDENTIFIER_NAMESPACE_VALUE (name); |
| |
| /* extern "C" function() */ |
| if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST) |
| t = TREE_VALUE (t); |
| } |
| else if (IDENTIFIER_LOCAL_VALUE (name) != NULL_TREE) |
| { |
| struct binding_level *b = current_binding_level; |
| while (1) |
| { |
| if (purpose_member (name, b->shadowed)) |
| return IDENTIFIER_LOCAL_VALUE (name); |
| if (b->keep == 2) |
| b = b->level_chain; |
| else |
| break; |
| } |
| } |
| |
| return t; |
| } |
| |
| /* Like lookup_name_current_level, but for types. */ |
| |
| tree |
| lookup_type_current_level (name) |
| tree name; |
| { |
| register tree t = NULL_TREE; |
| |
| my_friendly_assert (! current_binding_level->namespace_p, 980716); |
| |
| if (REAL_IDENTIFIER_TYPE_VALUE (name) != NULL_TREE |
| && REAL_IDENTIFIER_TYPE_VALUE (name) != global_type_node) |
| { |
| struct binding_level *b = current_binding_level; |
| while (1) |
| { |
| if (purpose_member (name, b->type_shadowed)) |
| return REAL_IDENTIFIER_TYPE_VALUE (name); |
| if (b->keep == 2) |
| b = b->level_chain; |
| else |
| break; |
| } |
| } |
| |
| return t; |
| } |
| |
| void |
| begin_only_namespace_names () |
| { |
| only_namespace_names = 1; |
| } |
| |
| void |
| end_only_namespace_names () |
| { |
| only_namespace_names = 0; |
| } |
| |
| /* Arrange for the user to get a source line number, even when the |
| compiler is going down in flames, so that she at least has a |
| chance of working around problems in the compiler. We used to |
| call error(), but that let the segmentation fault continue |
| through; now, it's much more passive by asking them to send the |
| maintainers mail about the problem. */ |
| |
| static void |
| signal_catch (sig) |
| int sig ATTRIBUTE_UNUSED; |
| { |
| signal (SIGSEGV, SIG_DFL); |
| #ifdef SIGIOT |
| signal (SIGIOT, SIG_DFL); |
| #endif |
| #ifdef SIGILL |
| signal (SIGILL, SIG_DFL); |
| #endif |
| #ifdef SIGABRT |
| signal (SIGABRT, SIG_DFL); |
| #endif |
| #ifdef SIGBUS |
| signal (SIGBUS, SIG_DFL); |
| #endif |
| my_friendly_abort (0); |
| } |
| |
| #if 0 |
| /* Unused -- brendan 970107 */ |
| /* Array for holding types considered "built-in". These types |
| are output in the module in which `main' is defined. */ |
| static tree *builtin_type_tdescs_arr; |
| static int builtin_type_tdescs_len, builtin_type_tdescs_max; |
| #endif |
| |
| /* Push the declarations of builtin types into the namespace. |
| RID_INDEX, if < RID_MAX is the index of the builtin type |
| in the array RID_POINTERS. NAME is the name used when looking |
| up the builtin type. TYPE is the _TYPE node for the builtin type. */ |
| |
| static void |
| record_builtin_type (rid_index, name, type) |
| enum rid rid_index; |
| char *name; |
| tree type; |
| { |
| tree rname = NULL_TREE, tname = NULL_TREE; |
| tree tdecl = NULL_TREE; |
| |
| if ((int) rid_index < (int) RID_MAX) |
| rname = ridpointers[(int) rid_index]; |
| if (name) |
| tname = get_identifier (name); |
| |
| TYPE_BUILT_IN (type) = 1; |
| |
| if (tname) |
| { |
| tdecl = pushdecl (build_decl (TYPE_DECL, tname, type)); |
| set_identifier_type_value (tname, NULL_TREE); |
| if ((int) rid_index < (int) RID_MAX) |
| /* Built-in types live in the global namespace. */ |
| SET_IDENTIFIER_GLOBAL_VALUE (tname, tdecl); |
| } |
| if (rname != NULL_TREE) |
| { |
| if (tname != NULL_TREE) |
| { |
| set_identifier_type_value (rname, NULL_TREE); |
| SET_IDENTIFIER_GLOBAL_VALUE (rname, tdecl); |
| } |
| else |
| { |
| tdecl = pushdecl (build_decl (TYPE_DECL, rname, type)); |
| set_identifier_type_value (rname, NULL_TREE); |
| } |
| } |
| } |
| |
| /* Record one of the standard Java types. |
| * Declare it as having the given NAME. |
| * If SIZE > 0, it is the size of one of the integral types; |
| * otherwise it is the negative of the size of one of the other types. */ |
| |
| static tree |
| record_builtin_java_type (name, size) |
| char *name; |
| int size; |
| { |
| tree type, decl; |
| if (size > 0) |
| type = make_signed_type (size); |
| else if (size > -32) |
| { /* "__java_char" or ""__java_boolean". */ |
| type = make_unsigned_type (-size); |
| /*if (size == -1) TREE_SET_CODE (type, BOOLEAN_TYPE);*/ |
| } |
| else |
| { /* "__java_float" or ""__java_double". */ |
| type = make_node (REAL_TYPE); |
| TYPE_PRECISION (type) = - size; |
| layout_type (type); |
| } |
| record_builtin_type (RID_MAX, name, type); |
| decl = TYPE_NAME (type); |
| DECL_IGNORED_P (decl) = 1; |
| TYPE_FOR_JAVA (type) = 1; |
| return type; |
| } |
| |
| /* Push a type into the namespace so that the back-ends ignore it. */ |
| |
| static void |
| record_unknown_type (type, name) |
| tree type; |
| char *name; |
| { |
| tree decl = pushdecl (build_decl (TYPE_DECL, get_identifier (name), type)); |
| /* Make sure the "unknown type" typedecl gets ignored for debug info. */ |
| DECL_IGNORED_P (decl) = 1; |
| TYPE_DECL_SUPPRESS_DEBUG (decl) = 1; |
| TYPE_SIZE (type) = TYPE_SIZE (void_type_node); |
| TYPE_ALIGN (type) = 1; |
| TYPE_MODE (type) = TYPE_MODE (void_type_node); |
| } |
| |
| /* Push overloaded decl, in global scope, with one argument so it |
| can be used as a callback from define_function. */ |
| |
| static void |
| push_overloaded_decl_1 (x) |
| tree x; |
| { |
| push_overloaded_decl (x, 0); |
| } |
| |
| #ifdef __GNUC__ |
| __inline |
| #endif |
| tree |
| auto_function (name, type, code) |
| tree name, type; |
| enum built_in_function code; |
| { |
| return define_function |
| (IDENTIFIER_POINTER (name), type, code, push_overloaded_decl_1, |
| IDENTIFIER_POINTER (build_decl_overload (name, TYPE_ARG_TYPES (type), |
| 0))); |
| } |
| |
| /* Create the predefined scalar types of C, |
| and some nodes representing standard constants (0, 1, (void *)0). |
| Initialize the global binding level. |
| Make definitions for built-in primitive functions. */ |
| |
| void |
| init_decl_processing () |
| { |
| register tree endlink, int_endlink, double_endlink, unsigned_endlink; |
| tree fields[20]; |
| /* Data type of memcpy. */ |
| tree memcpy_ftype, strlen_ftype; |
| int wchar_type_size; |
| tree temp; |
| tree array_domain_type; |
| extern int flag_strict_prototype; |
| tree vb_off_identifier = NULL_TREE; |
| /* Function type `char *(char *, char *)' and similar ones */ |
| tree string_ftype_ptr_ptr, int_ftype_string_string; |
| tree sizetype_endlink; |
| tree ptr_ftype, ptr_ftype_unsigned, ptr_ftype_sizetype; |
| tree void_ftype, void_ftype_int, void_ftype_ptr, ptr_ftype_void; |
| |
| /* Have to make these distinct before we try using them. */ |
| lang_name_cplusplus = get_identifier ("C++"); |
| lang_name_c = get_identifier ("C"); |
| lang_name_java = get_identifier ("Java"); |
| |
| /* Enter the global namespace. */ |
| my_friendly_assert (global_namespace == NULL_TREE, 375); |
| my_friendly_assert (current_lang_name == NULL_TREE, 375); |
| current_lang_name = lang_name_cplusplus; |
| push_namespace (get_identifier ("::")); |
| global_namespace = current_namespace; |
| current_lang_name = NULL_TREE; |
| |
| if (flag_strict_prototype == 2) |
| { |
| if (pedantic) |
| strict_prototypes_lang_c = strict_prototypes_lang_cplusplus; |
| } |
| else |
| strict_prototypes_lang_c = flag_strict_prototype; |
| |
| /* Initially, C. */ |
| current_lang_name = lang_name_c; |
| |
| current_function_decl = NULL_TREE; |
| named_labels = NULL_TREE; |
| named_label_uses = NULL; |
| current_binding_level = NULL_BINDING_LEVEL; |
| free_binding_level = NULL_BINDING_LEVEL; |
| |
| #ifndef __CYGWIN32__ |
| /* Because most segmentation signals can be traced back into user |
| code, catch them and at least give the user a chance of working |
| around compiler bugs. */ |
| signal (SIGSEGV, signal_catch); |
| |
| /* We will also catch aborts in the back-end through signal_catch and |
| give the user a chance to see where the error might be, and to defeat |
| aborts in the back-end when there have been errors previously in their |
| code. */ |
| #ifdef SIGIOT |
| signal (SIGIOT, signal_catch); |
| #endif |
| #ifdef SIGILL |
| signal (SIGILL, signal_catch); |
| #endif |
| #ifdef SIGABRT |
| signal (SIGABRT, signal_catch); |
| #endif |
| #ifdef SIGBUS |
| signal (SIGBUS, signal_catch); |
| #endif |
| #else /* ndef __CYGWIN32__ */ |
| /* Cygwin32 cannot handle catching signals other than |
| SIGABRT yet. We hope this will cease to be the case soon. */ |
| #ifdef SIGABRT |
| signal (SIGABRT, signal_catch); |
| #endif |
| #endif /* ndef __CYGWIN32__ */ |
| |
| gcc_obstack_init (&decl_obstack); |
| |
| /* Must lay these out before anything else gets laid out. */ |
| error_mark_node = make_node (ERROR_MARK); |
| TREE_PERMANENT (error_mark_node) = 1; |
| TREE_TYPE (error_mark_node) = error_mark_node; |
| error_mark_list = build_tree_list (error_mark_node, error_mark_node); |
| TREE_TYPE (error_mark_list) = error_mark_node; |
| |
| /* Make the binding_level structure for global names. */ |
| pushlevel (0); |
| global_binding_level = current_binding_level; |
| /* The global level is the namespace level of ::. */ |
| NAMESPACE_LEVEL (global_namespace) = global_binding_level; |
| declare_namespace_level (); |
| |
| this_identifier = get_identifier (THIS_NAME); |
| in_charge_identifier = get_identifier (IN_CHARGE_NAME); |
| ctor_identifier = get_identifier (CTOR_NAME); |
| dtor_identifier = get_identifier (DTOR_NAME); |
| pfn_identifier = get_identifier (VTABLE_PFN_NAME); |
| index_identifier = get_identifier (VTABLE_INDEX_NAME); |
| delta_identifier = get_identifier (VTABLE_DELTA_NAME); |
| delta2_identifier = get_identifier (VTABLE_DELTA2_NAME); |
| pfn_or_delta2_identifier = get_identifier ("__pfn_or_delta2"); |
| if (flag_handle_signatures) |
| { |
| tag_identifier = get_identifier (SIGTABLE_TAG_NAME); |
| vb_off_identifier = get_identifier (SIGTABLE_VB_OFF_NAME); |
| vt_off_identifier = get_identifier (SIGTABLE_VT_OFF_NAME); |
| } |
| |
| /* Define `int' and `char' first so that dbx will output them first. */ |
| |
| integer_type_node = make_signed_type (INT_TYPE_SIZE); |
| record_builtin_type (RID_INT, NULL_PTR, integer_type_node); |
| |
| /* Define `char', which is like either `signed char' or `unsigned char' |
| but not the same as either. */ |
| |
| char_type_node |
| = (flag_signed_char |
| ? make_signed_type (CHAR_TYPE_SIZE) |
| : make_unsigned_type (CHAR_TYPE_SIZE)); |
| record_builtin_type (RID_CHAR, "char", char_type_node); |
| |
| long_integer_type_node = make_signed_type (LONG_TYPE_SIZE); |
| record_builtin_type (RID_LONG, "long int", long_integer_type_node); |
| |
| unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE); |
| record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node); |
| |
| long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE); |
| record_builtin_type (RID_MAX, "long unsigned int", long_unsigned_type_node); |
| record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node); |
| |
| long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE); |
| record_builtin_type (RID_MAX, "long long int", long_long_integer_type_node); |
| |
| long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE); |
| record_builtin_type (RID_MAX, "long long unsigned int", |
| long_long_unsigned_type_node); |
| record_builtin_type (RID_MAX, "long long unsigned", |
| long_long_unsigned_type_node); |
| |
| short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE); |
| record_builtin_type (RID_SHORT, "short int", short_integer_type_node); |
| short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE); |
| record_builtin_type (RID_MAX, "short unsigned int", short_unsigned_type_node); |
| record_builtin_type (RID_MAX, "unsigned short", short_unsigned_type_node); |
| |
| /* `unsigned long' is the standard type for sizeof. |
| Note that stddef.h uses `unsigned long', |
| and this must agree, even if long and int are the same size. */ |
| set_sizetype |
| (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)))); |
| |
| ptrdiff_type_node |
| = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE))); |
| |
| /* Define both `signed char' and `unsigned char'. */ |
| signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE); |
| record_builtin_type (RID_MAX, "signed char", signed_char_type_node); |
| unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE); |
| record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node); |
| |
| /* These are types that type_for_size and type_for_mode use. */ |
| intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node)); |
| intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node)); |
| intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node)); |
| intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node)); |
| intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, intTI_type_node)); |
| unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node)); |
| unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node)); |
| unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node)); |
| unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node)); |
| unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode)); |
| pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intTI_type_node)); |
| |
| float_type_node = make_node (REAL_TYPE); |
| TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE; |
| record_builtin_type (RID_FLOAT, NULL_PTR, float_type_node); |
| layout_type (float_type_node); |
| |
| double_type_node = make_node (REAL_TYPE); |
| if (flag_short_double) |
| TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE; |
| else |
| TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE; |
| record_builtin_type (RID_DOUBLE, NULL_PTR, double_type_node); |
| layout_type (double_type_node); |
| |
| long_double_type_node = make_node (REAL_TYPE); |
| TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE; |
| record_builtin_type (RID_MAX, "long double", long_double_type_node); |
| layout_type (long_double_type_node); |
| |
| complex_integer_type_node = make_node (COMPLEX_TYPE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"), |
| complex_integer_type_node)); |
| TREE_TYPE (complex_integer_type_node) = integer_type_node; |
| layout_type (complex_integer_type_node); |
| |
| complex_float_type_node = make_node (COMPLEX_TYPE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"), |
| complex_float_type_node)); |
| TREE_TYPE (complex_float_type_node) = float_type_node; |
| layout_type (complex_float_type_node); |
| |
| complex_double_type_node = make_node (COMPLEX_TYPE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"), |
| complex_double_type_node)); |
| TREE_TYPE (complex_double_type_node) = double_type_node; |
| layout_type (complex_double_type_node); |
| |
| complex_long_double_type_node = make_node (COMPLEX_TYPE); |
| pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"), |
| complex_long_double_type_node)); |
| TREE_TYPE (complex_long_double_type_node) = long_double_type_node; |
| layout_type (complex_long_double_type_node); |
| |
| java_byte_type_node = record_builtin_java_type ("__java_byte", 8); |
| java_short_type_node = record_builtin_java_type ("__java_short", 16); |
| java_int_type_node = record_builtin_java_type ("__java_int", 32); |
| java_long_type_node = record_builtin_java_type ("__java_long", 64); |
| java_float_type_node = record_builtin_java_type ("__java_float", -32); |
| java_double_type_node = record_builtin_java_type ("__java_double", -64); |
| java_char_type_node = record_builtin_java_type ("__java_char", -16); |
| java_boolean_type_node = record_builtin_java_type ("__java_boolean", -1); |
| |
| integer_zero_node = build_int_2 (0, 0); |
| TREE_TYPE (integer_zero_node) = integer_type_node; |
| integer_one_node = build_int_2 (1, 0); |
| TREE_TYPE (integer_one_node) = integer_type_node; |
| integer_two_node = build_int_2 (2, 0); |
| TREE_TYPE (integer_two_node) = integer_type_node; |
| integer_three_node = build_int_2 (3, 0); |
| TREE_TYPE (integer_three_node) = integer_type_node; |
| |
| boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE); |
| TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE); |
| TYPE_MAX_VALUE (boolean_type_node) = build_int_2 (1, 0); |
| TREE_TYPE (TYPE_MAX_VALUE (boolean_type_node)) = boolean_type_node; |
| TYPE_PRECISION (boolean_type_node) = 1; |
| record_builtin_type (RID_BOOL, "bool", boolean_type_node); |
| boolean_false_node = build_int_2 (0, 0); |
| TREE_TYPE (boolean_false_node) = boolean_type_node; |
| boolean_true_node = build_int_2 (1, 0); |
| TREE_TYPE (boolean_true_node) = boolean_type_node; |
| |
| /* These are needed by stor-layout.c. */ |
| size_zero_node = size_int (0); |
| size_one_node = size_int (1); |
| |
| signed_size_zero_node = build_int_2 (0, 0); |
| TREE_TYPE (signed_size_zero_node) = make_signed_type (TYPE_PRECISION (sizetype)); |
| |
| void_type_node = make_node (VOID_TYPE); |
| record_builtin_type (RID_VOID, NULL_PTR, void_type_node); |
| layout_type (void_type_node); /* Uses integer_zero_node. */ |
| void_list_node = build_tree_list (NULL_TREE, void_type_node); |
| TREE_PARMLIST (void_list_node) = 1; |
| |
| null_pointer_node = build_int_2 (0, 0); |
| TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node); |
| layout_type (TREE_TYPE (null_pointer_node)); |
| |
| /* Used for expressions that do nothing, but are not errors. */ |
| void_zero_node = build_int_2 (0, 0); |
| TREE_TYPE (void_zero_node) = void_type_node; |
| |
| string_type_node = build_pointer_type (char_type_node); |
| const_string_type_node |
| = build_pointer_type (build_type_variant (char_type_node, 1, 0)); |
| #if 0 |
| record_builtin_type (RID_MAX, NULL_PTR, string_type_node); |
| #endif |
| |
| /* Make a type to be the domain of a few array types |
| whose domains don't really matter. |
| 200 is small enough that it always fits in size_t |
| and large enough that it can hold most function names for the |
| initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */ |
| array_domain_type = build_index_type (build_int_2 (200, 0)); |
| |
| /* Make a type for arrays of characters. |
| With luck nothing will ever really depend on the length of this |
| array type. */ |
| char_array_type_node |
| = build_array_type (char_type_node, array_domain_type); |
| /* Likewise for arrays of ints. */ |
| int_array_type_node |
| = build_array_type (integer_type_node, array_domain_type); |
| |
| /* This is just some anonymous class type. Nobody should ever |
| need to look inside this envelope. */ |
| class_star_type_node = build_pointer_type (make_lang_type (RECORD_TYPE)); |
| |
| default_function_type |
| = build_function_type (integer_type_node, NULL_TREE); |
| |
| ptr_type_node = build_pointer_type (void_type_node); |
| const_ptr_type_node |
| = build_pointer_type (build_type_variant (void_type_node, 1, 0)); |
| #if 0 |
| record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node); |
| #endif |
| endlink = void_list_node; |
| int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink); |
| double_endlink = tree_cons (NULL_TREE, double_type_node, endlink); |
| unsigned_endlink = tree_cons (NULL_TREE, unsigned_type_node, endlink); |
| |
| ptr_ftype = build_function_type (ptr_type_node, NULL_TREE); |
| ptr_ftype_unsigned = build_function_type (ptr_type_node, unsigned_endlink); |
| sizetype_endlink = tree_cons (NULL_TREE, sizetype, endlink); |
| /* We realloc here because sizetype could be int or unsigned. S'ok. */ |
| ptr_ftype_sizetype = build_function_type (ptr_type_node, sizetype_endlink); |
| |
| void_ftype = build_function_type (void_type_node, endlink); |
| void_ftype_int = build_function_type (void_type_node, int_endlink); |
| void_ftype_ptr |
| = build_function_type (void_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, endlink)); |
| void_ftype_ptr |
| = build_exception_variant (void_ftype_ptr, |
| tree_cons (NULL_TREE, NULL_TREE, NULL_TREE)); |
| |
| float_ftype_float |
| = build_function_type (float_type_node, |
| tree_cons (NULL_TREE, float_type_node, endlink)); |
| |
| double_ftype_double |
| = build_function_type (double_type_node, double_endlink); |
| |
| ldouble_ftype_ldouble |
| = build_function_type (long_double_type_node, |
| tree_cons (NULL_TREE, long_double_type_node, |
| endlink)); |
| |
| double_ftype_double_double |
| = build_function_type (double_type_node, |
| tree_cons (NULL_TREE, double_type_node, |
| double_endlink)); |
| |
| int_ftype_int |
| = build_function_type (integer_type_node, int_endlink); |
| |
| long_ftype_long |
| = build_function_type (long_integer_type_node, |
| tree_cons (NULL_TREE, long_integer_type_node, |
| endlink)); |
| |
| int_ftype_cptr_cptr_sizet |
| = build_function_type (integer_type_node, |
| tree_cons (NULL_TREE, const_ptr_type_node, |
| tree_cons (NULL_TREE, const_ptr_type_node, |
| tree_cons (NULL_TREE, |
| sizetype, |
| endlink)))); |
| |
| string_ftype_ptr_ptr /* strcpy prototype */ |
| = build_function_type (string_type_node, |
| tree_cons (NULL_TREE, string_type_node, |
| tree_cons (NULL_TREE, |
| const_string_type_node, |
| endlink))); |
| |
| int_ftype_string_string /* strcmp prototype */ |
| = build_function_type (integer_type_node, |
| tree_cons (NULL_TREE, const_string_type_node, |
| tree_cons (NULL_TREE, |
| const_string_type_node, |
| endlink))); |
| |
| strlen_ftype /* strlen prototype */ |
| = build_function_type (sizetype, |
| tree_cons (NULL_TREE, const_string_type_node, |
| endlink)); |
| |
| memcpy_ftype /* memcpy prototype */ |
| = build_function_type (ptr_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| tree_cons (NULL_TREE, const_ptr_type_node, |
| sizetype_endlink))); |
| |
| if (flag_huge_objects) |
| delta_type_node = long_integer_type_node; |
| else |
| delta_type_node = short_integer_type_node; |
| |
| builtin_function ("__builtin_constant_p", default_function_type, |
| BUILT_IN_CONSTANT_P, NULL_PTR); |
| |
| builtin_return_address_fndecl |
| = builtin_function ("__builtin_return_address", ptr_ftype_unsigned, |
| BUILT_IN_RETURN_ADDRESS, NULL_PTR); |
| |
| builtin_function ("__builtin_frame_address", ptr_ftype_unsigned, |
| BUILT_IN_FRAME_ADDRESS, NULL_PTR); |
| |
| ptr_ftype_void = build_function_type (ptr_type_node, endlink); |
| builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR); |
| builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR); |
| |
| builtin_function ("__builtin_alloca", ptr_ftype_sizetype, |
| BUILT_IN_ALLOCA, "alloca"); |
| builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR); |
| /* Define alloca, ffs as builtins. |
| Declare _exit just to mark it as volatile. */ |
| if (! flag_no_builtin && !flag_no_nonansi_builtin) |
| { |
| temp = builtin_function ("alloca", ptr_ftype_sizetype, |
| BUILT_IN_ALLOCA, NULL_PTR); |
| /* Suppress error if redefined as a non-function. */ |
| DECL_BUILT_IN_NONANSI (temp) = 1; |
| temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR); |
| /* Suppress error if redefined as a non-function. */ |
| DECL_BUILT_IN_NONANSI (temp) = 1; |
| temp = builtin_function ("_exit", void_ftype_int, |
| NOT_BUILT_IN, NULL_PTR); |
| TREE_THIS_VOLATILE (temp) = 1; |
| TREE_SIDE_EFFECTS (temp) = 1; |
| /* Suppress error if redefined as a non-function. */ |
| DECL_BUILT_IN_NONANSI (temp) = 1; |
| } |
| |
| builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR); |
| builtin_function ("__builtin_fabsf", float_ftype_float, BUILT_IN_FABS, |
| NULL_PTR); |
| builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS, |
| NULL_PTR); |
| builtin_function ("__builtin_fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS, |
| NULL_PTR); |
| builtin_function ("__builtin_labs", long_ftype_long, |
| BUILT_IN_LABS, NULL_PTR); |
| builtin_function ("__builtin_saveregs", ptr_ftype, |
| BUILT_IN_SAVEREGS, NULL_PTR); |
| builtin_function ("__builtin_classify_type", default_function_type, |
| BUILT_IN_CLASSIFY_TYPE, NULL_PTR); |
| builtin_function ("__builtin_next_arg", ptr_ftype, |
| BUILT_IN_NEXT_ARG, NULL_PTR); |
| builtin_function ("__builtin_args_info", int_ftype_int, |
| BUILT_IN_ARGS_INFO, NULL_PTR); |
| builtin_function ("__builtin_setjmp", |
| build_function_type (integer_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| endlink)), |
| BUILT_IN_SETJMP, NULL_PTR); |
| builtin_function ("__builtin_longjmp", |
| build_function_type (integer_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| tree_cons (NULL_TREE, |
| integer_type_node, |
| endlink))), |
| BUILT_IN_LONGJMP, NULL_PTR); |
| |
| /* Untyped call and return. */ |
| builtin_function ("__builtin_apply_args", ptr_ftype, |
| BUILT_IN_APPLY_ARGS, NULL_PTR); |
| |
| temp = tree_cons (NULL_TREE, |
| build_pointer_type (build_function_type (void_type_node, |
| NULL_TREE)), |
| tree_cons (NULL_TREE, ptr_ftype_sizetype, NULL_TREE)); |
| builtin_function ("__builtin_apply", |
| build_function_type (ptr_type_node, temp), |
| BUILT_IN_APPLY, NULL_PTR); |
| builtin_function ("__builtin_return", void_ftype_ptr, |
| BUILT_IN_RETURN, NULL_PTR); |
| |
| /* Currently under experimentation. */ |
| builtin_function ("__builtin_memcpy", memcpy_ftype, |
| BUILT_IN_MEMCPY, "memcpy"); |
| builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet, |
| BUILT_IN_MEMCMP, "memcmp"); |
| builtin_function ("__builtin_strcmp", int_ftype_string_string, |
| BUILT_IN_STRCMP, "strcmp"); |
| builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr, |
| BUILT_IN_STRCPY, "strcpy"); |
| builtin_function ("__builtin_strlen", strlen_ftype, |
| BUILT_IN_STRLEN, "strlen"); |
| builtin_function ("__builtin_sqrtf", float_ftype_float, |
| BUILT_IN_FSQRT, "sqrtf"); |
| builtin_function ("__builtin_fsqrt", double_ftype_double, |
| BUILT_IN_FSQRT, NULL_PTR); |
| builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble, |
| BUILT_IN_FSQRT, "sqrtl"); |
| builtin_function ("__builtin_sinf", float_ftype_float, |
| BUILT_IN_SIN, "sinf"); |
| builtin_function ("__builtin_sin", double_ftype_double, |
| BUILT_IN_SIN, "sin"); |
| builtin_function ("__builtin_sinl", ldouble_ftype_ldouble, |
| BUILT_IN_SIN, "sinl"); |
| builtin_function ("__builtin_cosf", float_ftype_float, |
| BUILT_IN_COS, "cosf"); |
| builtin_function ("__builtin_cos", double_ftype_double, |
| BUILT_IN_COS, "cos"); |
| builtin_function ("__builtin_cosl", ldouble_ftype_ldouble, |
| BUILT_IN_COS, "cosl"); |
| |
| if (!flag_no_builtin) |
| { |
| builtin_function ("abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR); |
| builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS, NULL_PTR); |
| builtin_function ("labs", long_ftype_long, BUILT_IN_LABS, NULL_PTR); |
| builtin_function ("fabsf", float_ftype_float, BUILT_IN_FABS, NULL_PTR); |
| builtin_function ("fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS, |
| NULL_PTR); |
| builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR); |
| builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP, |
| NULL_PTR); |
| builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP, |
| NULL_PTR); |
| builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY, |
| NULL_PTR); |
| builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN, NULL_PTR); |
| builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT, NULL_PTR); |
| builtin_function ("sqrt", double_ftype_double, BUILT_IN_FSQRT, NULL_PTR); |
| builtin_function ("sqrtl", ldouble_ftype_ldouble, BUILT_IN_FSQRT, |
| NULL_PTR); |
| builtin_function ("sinf", float_ftype_float, BUILT_IN_SIN, NULL_PTR); |
| builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR); |
| builtin_function ("sinl", ldouble_ftype_ldouble, BUILT_IN_SIN, NULL_PTR); |
| builtin_function ("cosf", float_ftype_float, BUILT_IN_COS, NULL_PTR); |
| builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR); |
| builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS, NULL_PTR); |
| |
| /* Declare these functions volatile |
| to avoid spurious "control drops through" warnings. */ |
| temp = builtin_function ("abort", void_ftype, |
| NOT_BUILT_IN, NULL_PTR); |
| TREE_THIS_VOLATILE (temp) = 1; |
| TREE_SIDE_EFFECTS (temp) = 1; |
| /* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on |
| them... */ |
| DECL_BUILT_IN_NONANSI (temp) = 1; |
| temp = builtin_function ("exit", void_ftype_int, |
| NOT_BUILT_IN, NULL_PTR); |
| TREE_THIS_VOLATILE (temp) = 1; |
| TREE_SIDE_EFFECTS (temp) = 1; |
| DECL_BUILT_IN_NONANSI (temp) = 1; |
| } |
| |
| #if 0 |
| /* Support for these has not been written in either expand_builtin |
| or build_function_call. */ |
| builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, NULL_PTR); |
| builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR); |
| builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR, |
| NULL_PTR); |
| builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, |
| NULL_PTR); |
| builtin_function ("__builtin_fmod", double_ftype_double_double, |
| BUILT_IN_FMOD, NULL_PTR); |
| builtin_function ("__builtin_frem", double_ftype_double_double, |
| BUILT_IN_FREM, NULL_PTR); |
| builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int, |
| BUILT_IN_MEMSET, NULL_PTR); |
| builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP, |
| NULL_PTR); |
| builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN, |
| NULL_PTR); |
| #endif |
| |
| /* C++ extensions */ |
| |
| unknown_type_node = make_node (UNKNOWN_TYPE); |
| record_unknown_type (unknown_type_node, "unknown type"); |
| |
| /* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node. */ |
| TREE_TYPE (unknown_type_node) = unknown_type_node; |
| |
| if (flag_ansi) |
| TREE_TYPE (null_node) = type_for_size (POINTER_SIZE, 0); |
| else |
| TREE_TYPE (null_node) = build_pointer_type (unknown_type_node); |
| |
| /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same |
| result. */ |
| TYPE_POINTER_TO (unknown_type_node) = unknown_type_node; |
| TYPE_REFERENCE_TO (unknown_type_node) = unknown_type_node; |
| |
| /* This is for handling opaque types in signatures. */ |
| opaque_type_node = copy_node (ptr_type_node); |
| TYPE_MAIN_VARIANT (opaque_type_node) = opaque_type_node; |
| record_builtin_type (RID_MAX, 0, opaque_type_node); |
| |
| /* This is special for C++ so functions can be overloaded. */ |
| wchar_type_node |
| = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE))); |
| wchar_type_size = TYPE_PRECISION (wchar_type_node); |
| signed_wchar_type_node = make_signed_type (wchar_type_size); |
| unsigned_wchar_type_node = make_unsigned_type (wchar_type_size); |
| wchar_type_node |
| = TREE_UNSIGNED (wchar_type_node) |
| ? unsigned_wchar_type_node |
| : signed_wchar_type_node; |
| record_builtin_type (RID_WCHAR, "__wchar_t", wchar_type_node); |
| |
| /* Artificial declaration of wchar_t -- can be bashed */ |
| wchar_decl_node = build_decl (TYPE_DECL, get_identifier ("wchar_t"), |
| wchar_type_node); |
| pushdecl (wchar_decl_node); |
| |
| /* This is for wide string constants. */ |
| wchar_array_type_node |
| = build_array_type (wchar_type_node, array_domain_type); |
| |
| if (flag_vtable_thunks) |
| { |
| /* Make sure we get a unique function type, so we can give |
| its pointer type a name. (This wins for gdb.) */ |
| tree vfunc_type = make_node (FUNCTION_TYPE); |
| TREE_TYPE (vfunc_type) = integer_type_node; |
| TYPE_ARG_TYPES (vfunc_type) = NULL_TREE; |
| layout_type (vfunc_type); |
| |
| vtable_entry_type = build_pointer_type (vfunc_type); |
| } |
| else |
| { |
| vtable_entry_type = make_lang_type (RECORD_TYPE); |
| fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier, |
| delta_type_node); |
| fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier, |
| delta_type_node); |
| fields[2] = build_lang_field_decl (FIELD_DECL, pfn_identifier, |
| ptr_type_node); |
| finish_builtin_type (vtable_entry_type, VTBL_PTR_TYPE, fields, 2, |
| double_type_node); |
| |
| /* Make this part of an invisible union. */ |
| fields[3] = copy_node (fields[2]); |
| TREE_TYPE (fields[3]) = delta_type_node; |
| DECL_NAME (fields[3]) = delta2_identifier; |
| DECL_MODE (fields[3]) = TYPE_MODE (delta_type_node); |
| DECL_SIZE (fields[3]) = TYPE_SIZE (delta_type_node); |
| TREE_UNSIGNED (fields[3]) = 0; |
| TREE_CHAIN (fields[2]) = fields[3]; |
| vtable_entry_type = build_type_variant (vtable_entry_type, 1, 0); |
| } |
| record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type); |
| |
| vtbl_type_node |
| = build_array_type (vtable_entry_type, NULL_TREE); |
| layout_type (vtbl_type_node); |
| vtbl_type_node = cp_build_type_variant (vtbl_type_node, 1, 0); |
| record_builtin_type (RID_MAX, NULL_PTR, vtbl_type_node); |
| |
| /* Simplify life by making a "sigtable_entry_type". Give its |
| fields names so that the debugger can use them. */ |
| |
| if (flag_handle_signatures) |
| { |
| sigtable_entry_type = make_lang_type (RECORD_TYPE); |
| fields[0] = build_lang_field_decl (FIELD_DECL, tag_identifier, |
| delta_type_node); |
| fields[1] = build_lang_field_decl (FIELD_DECL, vb_off_identifier, |
| delta_type_node); |
| fields[2] = build_lang_field_decl (FIELD_DECL, delta_identifier, |
| delta_type_node); |
| fields[3] = build_lang_field_decl (FIELD_DECL, index_identifier, |
| delta_type_node); |
| fields[4] = build_lang_field_decl (FIELD_DECL, pfn_identifier, |
| ptr_type_node); |
| |
| /* Set the alignment to the max of the alignment of ptr_type_node and |
| delta_type_node. Double alignment wastes a word on the Sparc. */ |
| finish_builtin_type (sigtable_entry_type, SIGTABLE_PTR_TYPE, fields, 4, |
| (TYPE_ALIGN (ptr_type_node) > TYPE_ALIGN (delta_type_node)) |
| ? ptr_type_node |
| : delta_type_node); |
| |
| /* Make this part of an invisible union. */ |
| fields[5] = copy_node (fields[4]); |
| TREE_TYPE (fields[5]) = delta_type_node; |
| DECL_NAME (fields[5]) = vt_off_identifier; |
| DECL_MODE (fields[5]) = TYPE_MODE (delta_type_node); |
| DECL_SIZE (fields[5]) = TYPE_SIZE (delta_type_node); |
| TREE_UNSIGNED (fields[5]) = 0; |
| TREE_CHAIN (fields[4]) = fields[5]; |
| |
| sigtable_entry_type = build_type_variant (sigtable_entry_type, 1, 0); |
| record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_entry_type); |
| } |
| |
| std_node = build_decl (NAMESPACE_DECL, |
| get_identifier (flag_honor_std ? "fake std":"std"), |
| void_type_node); |
| pushdecl (std_node); |
| |
| global_type_node = make_node (LANG_TYPE); |
| record_unknown_type (global_type_node, "global type"); |
| |
| /* Now, C++. */ |
| current_lang_name = lang_name_cplusplus; |
| |
| { |
| tree bad_alloc_type_node, newtype, deltype; |
| if (flag_honor_std) |
| push_namespace (get_identifier ("std")); |
| bad_alloc_type_node = xref_tag |
| (class_type_node, get_identifier ("bad_alloc"), NULL_TREE, 1); |
| if (flag_honor_std) |
| pop_namespace (); |
| newtype = build_exception_variant |
| (ptr_ftype_sizetype, build_tree_list (NULL_TREE, bad_alloc_type_node)); |
| deltype = build_exception_variant |
| (void_ftype_ptr, build_tree_list (NULL_TREE, NULL_TREE)); |
| auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN); |
| auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN); |
| auto_function (ansi_opname[(int) DELETE_EXPR], deltype, NOT_BUILT_IN); |
| auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype, NOT_BUILT_IN); |
| } |
| |
| abort_fndecl |
| = define_function ("__pure_virtual", void_ftype, |
| NOT_BUILT_IN, 0, 0); |
| |
| /* Perform other language dependent initializations. */ |
| init_class_processing (); |
| init_init_processing (); |
| init_search_processing (); |
| if (flag_rtti) |
| init_rtti_processing (); |
| |
| if (flag_exceptions) |
| init_exception_processing (); |
| if (flag_no_inline) |
| { |
| flag_inline_functions = 0; |
| } |
| |
| if (! supports_one_only ()) |
| flag_weak = 0; |
| |
| /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */ |
| declare_function_name (); |
| |
| /* Prepare to check format strings against argument lists. */ |
| init_function_format_info (); |
| |
| /* Show we use EH for cleanups. */ |
| using_eh_for_cleanups (); |
| |
| print_error_function = lang_print_error_function; |
| lang_get_alias_set = &c_get_alias_set; |
| } |
| |
| /* Function to print any language-specific context for an error message. */ |
| |
| static void |
| lang_print_error_function (file) |
| char *file; |
| { |
| default_print_error_function (file); |
| maybe_print_template_context (); |
| } |
| |
| /* Make a definition for a builtin function named NAME and whose data type |
| is TYPE. TYPE should be a function type with argument types. |
| FUNCTION_CODE tells later passes how to compile calls to this function. |
| See tree.h for its possible values. |
| |
| If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME, |
| the name to be called if we can't opencode the function. */ |
| |
| tree |
| define_function (name, type, function_code, pfn, library_name) |
| char *name; |
| tree type; |
| enum built_in_function function_code; |
| void (*pfn) PROTO((tree)); |
| char *library_name; |
| { |
| tree decl = build_lang_decl (FUNCTION_DECL, get_identifier (name), type); |
| DECL_EXTERNAL (decl) = 1; |
| TREE_PUBLIC (decl) = 1; |
| DECL_ARTIFICIAL (decl) = 1; |
| |
| my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 392); |
| DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); |
| |
| /* Since `pushdecl' relies on DECL_ASSEMBLER_NAME instead of DECL_NAME, |
| we cannot change DECL_ASSEMBLER_NAME until we have installed this |
| function in the namespace. */ |
| if (pfn) (*pfn) (decl); |
| if (library_name) |
| DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name); |
| make_function_rtl (decl); |
| if (function_code != NOT_BUILT_IN) |
| { |
| DECL_BUILT_IN (decl) = 1; |
| DECL_FUNCTION_CODE (decl) = function_code; |
| } |
| return decl; |
| } |
| |
| /* Called when a declaration is seen that contains no names to declare. |
| If its type is a reference to a structure, union or enum inherited |
| from a containing scope, shadow that tag name for the current scope |
| with a forward reference. |
| If its type defines a new named structure or union |
| or defines an enum, it is valid but we need not do anything here. |
| Otherwise, it is an error. |
| |
| C++: may have to grok the declspecs to learn about static, |
| complain for anonymous unions. */ |
| |
| void |
| shadow_tag (declspecs) |
| tree declspecs; |
| { |
| int found_tag = 0; |
| tree ob_modifier = NULL_TREE; |
| register tree link; |
| register enum tree_code code, ok_code = ERROR_MARK; |
| register tree t = NULL_TREE; |
| |
| for (link = declspecs; link; link = TREE_CHAIN (link)) |
| { |
| register tree value = TREE_VALUE (link); |
| |
| code = TREE_CODE (value); |
| if (IS_AGGR_TYPE_CODE (code) || code == ENUMERAL_TYPE) |
| { |
| my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261); |
| |
| if (IS_AGGR_TYPE (value) && CLASSTYPE_USE_TEMPLATE (value)) |
| { |
| if (CLASSTYPE_IMPLICIT_INSTANTIATION (value) |
| && TYPE_SIZE (value) == NULL_TREE) |
| { |
| SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (value); |
| if (processing_template_decl) |
| push_template_decl (TYPE_MAIN_DECL (value)); |
| } |
| else if (CLASSTYPE_TEMPLATE_INSTANTIATION (value)) |
| cp_error ("specialization after instantiation of `%T'", value); |
| } |
| |
| t = value; |
| ok_code = code; |
| found_tag++; |
| } |
| else if (value == ridpointers[(int) RID_STATIC] |
| || value == ridpointers[(int) RID_EXTERN] |
| || value == ridpointers[(int) RID_AUTO] |
| || value == ridpointers[(int) RID_REGISTER] |
| || value == ridpointers[(int) RID_INLINE] |
| || value == ridpointers[(int) RID_VIRTUAL] |
| || value == ridpointers[(int) RID_EXPLICIT]) |
| ob_modifier = value; |
| } |
| |
| /* This is where the variables in an anonymous union are |
| declared. An anonymous union declaration looks like: |
| union { ... } ; |
| because there is no declarator after the union, the parser |
| sends that declaration here. */ |
| if (ok_code == UNION_TYPE |
| && t != NULL_TREE |
| && ((TREE_CODE (TYPE_NAME (t)) == IDENTIFIER_NODE |
| && ANON_AGGRNAME_P (TYPE_NAME (t))) |
| || (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL |
| && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))))) |
| { |
| /* See also grok_x_components. */ |
| tree *q; |
| |
| /* Wipe out memory of synthesized methods */ |
| TYPE_HAS_CONSTRUCTOR (t) = 0; |
| TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0; |
| TYPE_HAS_INIT_REF (t) = 0; |
| TYPE_HAS_CONST_INIT_REF (t) = 0; |
| TYPE_HAS_ASSIGN_REF (t) = 0; |
| TYPE_HAS_ASSIGNMENT (t) = 0; |
| TYPE_HAS_CONST_ASSIGN_REF (t) = 0; |
| |
| q = &TYPE_METHODS (t); |
| while (*q) |
| { |
| if (DECL_ARTIFICIAL (*q)) |
| *q = TREE_CHAIN (*q); |
| else |
| q = &TREE_CHAIN (*q); |
| } |
| |
| /* ANSI C++ June 5 1992 WP 9.5.3. Anonymous unions may not have |
| function members. */ |
| if (TYPE_METHODS (t)) |
| error ("an anonymous union cannot have function members"); |
| |
| if (TYPE_FIELDS (t)) |
| { |
| tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0, |
| NULL_TREE); |
| finish_anon_union (decl); |
| } |
| } |
| else |
| { |
| /* Anonymous unions are objects, that's why we only check for |
| inappropriate specifiers in this branch. */ |
| |
| if (ob_modifier) |
| { |
| if (ob_modifier == ridpointers[(int) RID_INLINE] |
| || ob_modifier == ridpointers[(int) RID_VIRTUAL]) |
| cp_error ("`%D' can only be specified for functions", ob_modifier); |
| else if (ob_modifier == ridpointers[(int) RID_EXPLICIT]) |
| cp_error ("`%D' can only be specified for constructors", |
| ob_modifier); |
| else |
| cp_error ("`%D' can only be specified for objects and functions", |
| ob_modifier); |
| } |
| |
| if (found_tag == 0) |
| cp_error ("abstract declarator used as declaration"); |
| else if (found_tag > 1) |
| pedwarn ("multiple types in one declaration"); |
| } |
| } |
| |
| /* Decode a "typename", such as "int **", returning a ..._TYPE node. */ |
| |
| tree |
| groktypename (typename) |
| tree typename; |
| { |
| if (TREE_CODE (typename) != TREE_LIST) |
| return typename; |
| return grokdeclarator (TREE_VALUE (typename), |
| TREE_PURPOSE (typename), |
| TYPENAME, 0, NULL_TREE); |
| } |
| |
| /* Decode a declarator in an ordinary declaration or data definition. |
| This is called as soon as the type information and variable name |
| have been parsed, before parsing the initializer if any. |
| Here we create the ..._DECL node, fill in its type, |
| and put it on the list of decls for the current context. |
| The ..._DECL node is returned as the value. |
| |
| Exception: for arrays where the length is not specified, |
| the type is left null, to be filled in by `cp_finish_decl'. |
| |
| Function definitions do not come here; they go to start_function |
| instead. However, external and forward declarations of functions |
| do go through here. Structure field declarations are done by |
| grokfield and not through here. */ |
| |
| /* Set this to zero to debug not using the temporary obstack |
| to parse initializers. */ |
| int debug_temp_inits = 1; |
| |
| tree |
| start_decl (declarator, declspecs, initialized, attributes, prefix_attributes) |
| tree declarator, declspecs; |
| int initialized; |
| tree attributes, prefix_attributes; |
| { |
| register tree decl; |
| register tree type, tem; |
| tree context; |
| extern int have_extern_spec; |
| extern int used_extern_spec; |
| |
| #if 0 |
| /* See code below that used this. */ |
| int init_written = initialized; |
| #endif |
| |
| /* This should only be done once on the top most decl. */ |
| if (have_extern_spec && !used_extern_spec) |
| { |
| declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), |
| declspecs); |
| used_extern_spec = 1; |
| } |
| |
| decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, |
| NULL_TREE); |
| if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE) |
| return NULL_TREE; |
| |
| type = TREE_TYPE (decl); |
| |
| /* Don't lose if destructors must be executed at file-level. */ |
| if (! processing_template_decl && TREE_STATIC (decl) |
| && TYPE_NEEDS_DESTRUCTOR (complete_type (type)) |
| && !TREE_PERMANENT (decl)) |
| { |
| push_obstacks (&permanent_obstack, &permanent_obstack); |
| decl = copy_node (decl); |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| tree itype = TYPE_DOMAIN (type); |
| if (itype && ! TREE_PERMANENT (itype)) |
| { |
| itype = build_index_type (copy_to_permanent (TYPE_MAX_VALUE (itype))); |
| type = build_cplus_array_type (TREE_TYPE (type), itype); |
| TREE_TYPE (decl) = type; |
| } |
| } |
| pop_obstacks (); |
| } |
| |
| context |
| = (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl)) |
| ? DECL_CLASS_CONTEXT (decl) |
| : DECL_CONTEXT (decl); |
| |
| if (initialized && context && TREE_CODE (context) == NAMESPACE_DECL |
| && context != current_namespace && TREE_CODE (decl) == VAR_DECL) |
| { |
| /* When parsing the initializer, lookup should use the object's |
| namespace. */ |
| push_decl_namespace (context); |
| } |
| |
| /* We are only interested in class contexts, later. */ |
| if (context && TREE_CODE (context) == NAMESPACE_DECL) |
| context = NULL_TREE; |
| |
| if (initialized) |
| /* Is it valid for this decl to have an initializer at all? |
| If not, set INITIALIZED to zero, which will indirectly |
| tell `cp_finish_decl' to ignore the initializer once it is parsed. */ |
| switch (TREE_CODE (decl)) |
| { |
| case TYPE_DECL: |
| /* typedef foo = bar means give foo the same type as bar. |
| We haven't parsed bar yet, so `cp_finish_decl' will fix that up. |
| Any other case of an initialization in a TYPE_DECL is an error. */ |
| if (pedantic || list_length (declspecs) > 1) |
| { |
| cp_error ("typedef `%D' is initialized", decl); |
| initialized = 0; |
| } |
| break; |
| |
| case FUNCTION_DECL: |
| cp_error ("function `%#D' is initialized like a variable", decl); |
| initialized = 0; |
| break; |
| |
| default: |
| if (! processing_template_decl) |
| { |
| if (type != error_mark_node) |
| { |
| if (TYPE_SIZE (type) != NULL_TREE |
| && ! TREE_CONSTANT (TYPE_SIZE (type))) |
| { |
| cp_error |
| ("variable-sized object `%D' may not be initialized", |
| decl); |
| initialized = 0; |
| } |
| |
| if (TREE_CODE (type) == ARRAY_TYPE |
| && TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE) |
| { |
| cp_error |
| ("elements of array `%#D' have incomplete type", decl); |
| initialized = 0; |
| } |
| } |
| } |
| } |
| |
| if (initialized) |
| { |
| if (! toplevel_bindings_p () |
| && DECL_EXTERNAL (decl)) |
| cp_warning ("declaration of `%#D' has `extern' and is initialized", |
| decl); |
| DECL_EXTERNAL (decl) = 0; |
| if (toplevel_bindings_p ()) |
| TREE_STATIC (decl) = 1; |
| |
| /* Tell `pushdecl' this is an initialized decl |
| even though we don't yet have the initializer expression. |
| Also tell `cp_finish_decl' it may store the real initializer. */ |
| DECL_INITIAL (decl) = error_mark_node; |
| } |
| |
| if (context && TYPE_SIZE (complete_type (context)) != NULL_TREE) |
| { |
| if (TREE_CODE (decl) == VAR_DECL) |
| { |
| tree field = lookup_field (context, DECL_NAME (decl), 0, 0); |
| if (field == NULL_TREE || TREE_CODE (field) != VAR_DECL) |
| cp_error ("`%#D' is not a static member of `%#T'", decl, context); |
| else |
| { |
| if (DECL_CONTEXT (field) != context) |
| { |
| cp_pedwarn ("ANSI C++ does not permit `%T::%D' to be defined as `%T::%D'", |
| DECL_CONTEXT (field), DECL_NAME (decl), |
| context, DECL_NAME (decl)); |
| DECL_CONTEXT (decl) = DECL_CONTEXT (field); |
| } |
| /* Static data member are tricky; an in-class initialization |
| still doesn't provide a definition, so the in-class |
| declaration will have DECL_EXTERNAL set, but will have an |
| initialization. Thus, duplicate_decls won't warn |
| about this situation, and so we check here. */ |
| if (DECL_INITIAL (decl) && DECL_INITIAL (field)) |
| cp_error ("duplicate initialization of %D", decl); |
| if (duplicate_decls (decl, field)) |
| decl = field; |
| } |
| } |
| else |
| { |
| tree field = check_classfn (context, decl); |
| if (field && duplicate_decls (decl, field)) |
| decl = field; |
| } |
| |
| /* cp_finish_decl sets DECL_EXTERNAL if DECL_IN_AGGR_P is set. */ |
| DECL_IN_AGGR_P (decl) = 0; |
| if ((DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl)) |
| || CLASSTYPE_USE_TEMPLATE (context)) |
| SET_DECL_TEMPLATE_SPECIALIZATION (decl); |
| |
| if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)) |
| cp_pedwarn ("declaration of `%#D' outside of class is not definition", |
| decl); |
| |
| pushclass (context, 2); |
| } |
| |
| /* Set attributes here so if duplicate decl, will have proper attributes. */ |
| cplus_decl_attributes (decl, attributes, prefix_attributes); |
| |
| /* Add this decl to the current binding level, but not if it |
| comes from another scope, e.g. a static member variable. |
| TEM may equal DECL or it may be a previous decl of the same name. */ |
| |
| if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE |
| /* Definitions of namespace members outside their namespace are |
| possible. */ |
| && TREE_CODE (DECL_CONTEXT (decl)) != NAMESPACE_DECL) |
| || (TREE_CODE (decl) == TEMPLATE_DECL && !namespace_bindings_p ()) |
| || TREE_CODE (type) == LANG_TYPE |
| /* The declaration of template specializations does not affect |
| the functions available for overload resolution, so we do not |
| call pushdecl. */ |
| || (TREE_CODE (decl) == FUNCTION_DECL |
| && DECL_TEMPLATE_SPECIALIZATION (decl))) |
| tem = decl; |
| else |
| tem = pushdecl (decl); |
| |
| if (processing_template_decl) |
| { |
| if (! current_function_decl) |
| tem = push_template_decl (tem); |
| else if (minimal_parse_mode) |
| DECL_VINDEX (tem) |
| = build_min_nt (DECL_STMT, copy_to_permanent (declarator), |
| copy_to_permanent (declspecs), |
| NULL_TREE); |
| } |
| |
| |
| #if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS) |
| /* Tell the back-end to use or not use .common as appropriate. If we say |
| -fconserve-space, we want this to save .data space, at the expense of |
| wrong semantics. If we say -fno-conserve-space, we want this to |
| produce errors about redefs; to do this we force variables into the |
| data segment. */ |
| DECL_COMMON (tem) = flag_conserve_space || ! TREE_PUBLIC (tem); |
| #endif |
| |
| if (! processing_template_decl) |
| start_decl_1 (tem); |
| |
| /* Corresponding pop_obstacks is done in `cp_finish_decl'. */ |
| push_obstacks_nochange (); |
| |
| #if 0 |
| /* We have no way of knowing whether the initializer will need to be |
| evaluated at run-time or not until we've parsed it, so let's just put |
| it in the permanent obstack. (jason) */ |
| if (init_written |
| && ! (TREE_CODE (tem) == PARM_DECL |
| || (TREE_READONLY (tem) |
| && (TREE_CODE (tem) == VAR_DECL |
| || TREE_CODE (tem) == FIELD_DECL)))) |
| { |
| /* When parsing and digesting the initializer, |
| use temporary storage. Do this even if we will ignore the value. */ |
| if (toplevel_bindings_p () && debug_temp_inits) |
| { |
| if (processing_template_decl |
| || TYPE_NEEDS_CONSTRUCTING (type) |
| || TREE_CODE (type) == REFERENCE_TYPE) |
| /* In this case, the initializer must lay down in permanent |
| storage, since it will be saved until `finish_file' is run. */ |
| ; |
| else |
| temporary_allocation (); |
| } |
| } |
| #endif |
| |
| return tem; |
| } |
| |
| void |
| start_decl_1 (decl) |
| tree decl; |
| { |
| tree type = TREE_TYPE (decl); |
| int initialized = (DECL_INITIAL (decl) != NULL_TREE); |
| |
| /* If this type of object needs a cleanup, and control may |
| jump past it, make a new binding level so that it is cleaned |
| up only when it is initialized first. */ |
| if (TYPE_NEEDS_DESTRUCTOR (type) |
| && current_binding_level->more_cleanups_ok == 0) |
| pushlevel_temporary (1); |
| |
| if (initialized) |
| /* Is it valid for this decl to have an initializer at all? |
| If not, set INITIALIZED to zero, which will indirectly |
| tell `cp_finish_decl' to ignore the initializer once it is parsed. */ |
| { |
| /* Don't allow initializations for incomplete types except for |
| arrays which might be completed by the initialization. */ |
| if (type == error_mark_node) |
| ; /* Don't complain again. */ |
| else if (TYPE_SIZE (complete_type (type)) != NULL_TREE) |
| ; /* A complete type is ok. */ |
| else if (TREE_CODE (type) != ARRAY_TYPE) |
| { |
| cp_error ("variable `%#D' has initializer but incomplete type", |
| decl); |
| initialized = 0; |
| type = TREE_TYPE (decl) = error_mark_node; |
| } |
| else if (TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE) |
| { |
| if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)) |
| cp_error ("elements of array `%#D' have incomplete type", decl); |
| /* else we already gave an error in start_decl. */ |
| initialized = 0; |
| } |
| } |
| |
| if (!initialized |
| && TREE_CODE (decl) != TYPE_DECL |
| && TREE_CODE (decl) != TEMPLATE_DECL |
| && IS_AGGR_TYPE (type) && ! DECL_EXTERNAL (decl)) |
| { |
| if ((! processing_template_decl || ! uses_template_parms (type)) |
| && TYPE_SIZE (complete_type (type)) == NULL_TREE) |
| { |
| cp_error ("aggregate `%#D' has incomplete type and cannot be initialized", |
| decl); |
| /* Change the type so that assemble_variable will give |
| DECL an rtl we can live with: (mem (const_int 0)). */ |
| type = TREE_TYPE (decl) = error_mark_node; |
| } |
| else |
| { |
| /* If any base type in the hierarchy of TYPE needs a constructor, |
| then we set initialized to 1. This way any nodes which are |
| created for the purposes of initializing this aggregate |
| will live as long as it does. This is necessary for global |
| aggregates which do not have their initializers processed until |
| the end of the file. */ |
| initialized = TYPE_NEEDS_CONSTRUCTING (type); |
| } |
| } |
| |
| #if 0 |
| /* We don't do this yet for GNU C++. */ |
| /* For a local variable, define the RTL now. */ |
| if (! toplevel_bindings_p () |
| /* But not if this is a duplicate decl |
| and we preserved the rtl from the previous one |
| (which may or may not happen). */ |
| && DECL_RTL (tem) == NULL_RTX) |
| { |
| if (TYPE_SIZE (TREE_TYPE (tem)) != NULL_TREE) |
| expand_decl (tem); |
| else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE |
| && DECL_INITIAL (tem) != NULL_TREE) |
| expand_decl (tem); |
| } |
| #endif |
| |
| if (! initialized) |
| DECL_INITIAL (decl) = NULL_TREE; |
| } |
| |
| /* Handle initialization of references. |
| These three arguments are from `cp_finish_decl', and have the |
| same meaning here that they do there. |
| |
| Quotes on semantics can be found in ARM 8.4.3. */ |
| |
| static void |
| grok_reference_init (decl, type, init) |
| tree decl, type, init; |
| { |
| tree tmp; |
| |
| if (init == NULL_TREE) |
| { |
| if ((DECL_LANG_SPECIFIC (decl) == 0 |
| || DECL_IN_AGGR_P (decl) == 0) |
| && ! DECL_THIS_EXTERN (decl)) |
| { |
| cp_error ("`%D' declared as reference but not initialized", decl); |
| if (TREE_CODE (decl) == VAR_DECL) |
| SET_DECL_REFERENCE_SLOT (decl, error_mark_node); |
| } |
| return; |
| } |
| |
| if (init == error_mark_node) |
| return; |
| |
| if (TREE_CODE (type) == REFERENCE_TYPE |
| && TREE_CODE (init) == CONSTRUCTOR) |
| { |
| cp_error ("ANSI C++ forbids use of initializer list to initialize reference `%D'", decl); |
| return; |
| } |
| |
| if (TREE_TYPE (init) && TREE_CODE (TREE_TYPE (init)) == UNKNOWN_TYPE) |
| /* decay_conversion is probably wrong for references to functions. */ |
| init = decay_conversion (instantiate_type (TREE_TYPE (type), init, 1)); |
| |
| if (TREE_CODE (init) == TREE_LIST) |
| init = build_compound_expr (init); |
| |
| if (TREE_CODE (TREE_TYPE (init)) == REFERENCE_TYPE) |
| init = convert_from_reference (init); |
| |
| if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE |
| && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE) |
| { |
| /* Note: default conversion is only called in very special cases. */ |
| init = default_conversion (init); |
| } |
| |
| tmp = convert_to_reference |
| (type, init, CONV_IMPLICIT, |
| LOOKUP_SPECULATIVELY|LOOKUP_NORMAL|DIRECT_BIND, decl); |
| |
| if (tmp == error_mark_node) |
| goto fail; |
| else if (tmp != NULL_TREE) |
| { |
| init = tmp; |
| DECL_INITIAL (decl) = save_expr (init); |
| } |
| else |
| { |
| cp_error ("cannot initialize `%T' from `%T'", type, TREE_TYPE (init)); |
| goto fail; |
| } |
| |
| /* ?? Can this be optimized in some cases to |
| hand back the DECL_INITIAL slot?? */ |
| if (TYPE_SIZE (TREE_TYPE (type))) |
| { |
| init = convert_from_reference (decl); |
| if (TREE_PERMANENT (decl)) |
| init = copy_to_permanent (init); |
| SET_DECL_REFERENCE_SLOT (decl, init); |
| } |
| |
| if (TREE_STATIC (decl) && ! TREE_CONSTANT (DECL_INITIAL (decl))) |
| { |
| expand_static_init (decl, DECL_INITIAL (decl)); |
| DECL_INITIAL (decl) = NULL_TREE; |
| } |
| return; |
| |
| fail: |
| if (TREE_CODE (decl) == VAR_DECL) |
| SET_DECL_REFERENCE_SLOT (decl, error_mark_node); |
| return; |
| } |
| |
| /* Fill in DECL_INITIAL with some magical value to prevent expand_decl from |
| mucking with forces it does not comprehend (i.e. initialization with a |
| constructor). If we are at global scope and won't go into COMMON, fill |
| it in with a dummy CONSTRUCTOR to force the variable into .data; |
| otherwise we can use error_mark_node. */ |
| |
| static tree |
| obscure_complex_init (decl, init) |
| tree decl, init; |
| { |
| if (! flag_no_inline && TREE_STATIC (decl)) |
| { |
| if (extract_init (decl, init)) |
| return NULL_TREE; |
| } |
| |
| #if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS) |
| if (toplevel_bindings_p () && ! DECL_COMMON (decl)) |
| DECL_INITIAL (decl) = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE, |
| NULL_TREE); |
| else |
| #endif |
| DECL_INITIAL (decl) = error_mark_node; |
| |
| return init; |
| } |
| |
| /* Finish processing of a declaration; |
| install its line number and initial value. |
| If the length of an array type is not known before, |
| it must be determined now, from the initial value, or it is an error. |
| |
| Call `pop_obstacks' iff NEED_POP is nonzero. |
| |
| For C++, `cp_finish_decl' must be fairly evasive: it must keep initializers |
| for aggregates that have constructors alive on the permanent obstack, |
| so that the global initializing functions can be written at the end. |
| |
| INIT0 holds the value of an initializer that should be allowed to escape |
| the normal rules. |
| |
| FLAGS is LOOKUP_ONLYCONVERTING is the = init syntax was used, else 0 |
| if the (init) syntax was used. |
| |
| For functions that take default parameters, DECL points to its |
| "maximal" instantiation. `cp_finish_decl' must then also declared its |
| subsequently lower and lower forms of instantiation, checking for |
| ambiguity as it goes. This can be sped up later. */ |
| |
| void |
| cp_finish_decl (decl, init, asmspec_tree, need_pop, flags) |
| tree decl, init; |
| tree asmspec_tree; |
| int need_pop; |
| int flags; |
| { |
| register tree type; |
| tree cleanup = NULL_TREE, ttype = NULL_TREE; |
| int was_incomplete; |
| int temporary = allocation_temporary_p (); |
| char *asmspec = NULL; |
| int was_readonly = 0; |
| int already_used = 0; |
| |
| /* If this is 0, then we did not change obstacks. */ |
| if (! decl) |
| { |
| if (init) |
| error ("assignment (not initialization) in declaration"); |
| return; |
| } |
| |
| /* If a name was specified, get the string. */ |
| if (asmspec_tree) |
| asmspec = TREE_STRING_POINTER (asmspec_tree); |
| |
| if (init && TREE_CODE (init) == NAMESPACE_DECL) |
| { |
| cp_error ("Cannot initialize `%D' to namespace `%D'", |
| decl, init); |
| init = NULL_TREE; |
| } |
| |
| if (TREE_CODE (decl) == VAR_DECL |
| && DECL_CONTEXT (decl) |
| && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL |
| && DECL_CONTEXT (decl) != current_namespace |
| && init) |
| { |
| /* Leave the namespace of the object. */ |
| pop_decl_namespace (); |
| } |
| |
| /* If the type of the thing we are declaring either has |
| a constructor, or has a virtual function table pointer, |
| AND its initialization was accepted by `start_decl', |
| then we stayed on the permanent obstack through the |
| declaration, otherwise, changed obstacks as GCC would. */ |
| |
| type = TREE_TYPE (decl); |
| |
| if (type == error_mark_node) |
| { |
| if (toplevel_bindings_p () && temporary) |
| end_temporary_allocation (); |
| |
| return; |
| } |
| |
| if (processing_template_decl) |
| { |
| if (init && DECL_INITIAL (decl)) |
| DECL_INITIAL (decl) = init; |
| if (minimal_parse_mode && ! DECL_ARTIFICIAL (decl)) |
| { |
| tree stmt = DECL_VINDEX (decl); |
| /* If the decl is declaring a member of a local class (in a |
| template function), the DECL_VINDEX will either be NULL, |
| or it will be an actual virtual function index, not a |
| DECL_STMT. */ |
| if (stmt != NULL_TREE && TREE_CODE (stmt) == DECL_STMT) |
| { |
| DECL_VINDEX (decl) = NULL_TREE; |
| TREE_OPERAND (stmt, 2) = copy_to_permanent (init); |
| add_tree (stmt); |
| } |
| } |
| |
| goto finish_end0; |
| } |
| /* Take care of TYPE_DECLs up front. */ |
| if (TREE_CODE (decl) == TYPE_DECL) |
| { |
| if (init && DECL_INITIAL (decl)) |
| { |
| /* typedef foo = bar; store the type of bar as the type of foo. */ |
| TREE_TYPE (decl) = type = TREE_TYPE (init); |
| DECL_INITIAL (decl) = init = NULL_TREE; |
| } |
| if (type != error_mark_node |
| && IS_AGGR_TYPE (type) && DECL_NAME (decl)) |
| { |
| if (TREE_TYPE (DECL_NAME (decl)) && TREE_TYPE (decl) != type) |
| cp_warning ("shadowing previous type declaration of `%#D'", decl); |
| set_identifier_type_value (DECL_NAME (decl), type); |
| CLASSTYPE_GOT_SEMICOLON (type) = 1; |
| } |
| GNU_xref_decl (current_function_decl, decl); |
| |
| /* If we have installed this as the canonical typedef for this |
| type, and that type has not been defined yet, delay emitting |
| the debug information for it, as we will emit it later. */ |
| if (TYPE_MAIN_DECL (TREE_TYPE (decl)) == decl |
| && TYPE_SIZE (TREE_TYPE (decl)) == NULL_TREE) |
| TYPE_DECL_SUPPRESS_DEBUG (decl) = 1; |
| |
| rest_of_decl_compilation (decl, NULL_PTR, |
| DECL_CONTEXT (decl) == NULL_TREE, at_eof); |
| goto finish_end; |
| } |
| if (TREE_CODE (decl) != FUNCTION_DECL) |
| { |
| ttype = target_type (type); |
| } |
| |
| if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl) |
| && TYPE_NEEDS_CONSTRUCTING (type)) |
| { |
| |
| /* Currently, GNU C++ puts constants in text space, making them |
| impossible to initialize. In the future, one would hope for |
| an operating system which understood the difference between |
| initialization and the running of a program. */ |
| was_readonly = 1; |
| TREE_READONLY (decl) = 0; |
| } |
| |
| if (TREE_CODE (decl) == FIELD_DECL) |
| { |
| if (init && init != error_mark_node) |
| my_friendly_assert (TREE_PERMANENT (init), 147); |
| |
| if (asmspec) |
| { |
| /* This must override the asm specifier which was placed |
| by grokclassfn. Lay this out fresh. */ |
| DECL_RTL (TREE_TYPE (decl)) = NULL_RTX; |
| DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec); |
| make_decl_rtl (decl, asmspec, 0); |
| } |
| } |
| /* If `start_decl' didn't like having an initialization, ignore it now. */ |
| else if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE) |
| init = NULL_TREE; |
| else if (DECL_EXTERNAL (decl)) |
| ; |
| else if (TREE_CODE (type) == REFERENCE_TYPE |
| || (TYPE_LANG_SPECIFIC (type) && IS_SIGNATURE_REFERENCE (type))) |
| { |
| if (TREE_STATIC (decl)) |
| make_decl_rtl (decl, NULL_PTR, |
| toplevel_bindings_p () |
| || pseudo_global_level_p ()); |
| grok_reference_init (decl, type, init); |
| init = NULL_TREE; |
| } |
| |
| GNU_xref_decl (current_function_decl, decl); |
| |
| if (TREE_CODE (decl) == FIELD_DECL) |
| ; |
| else if (TREE_CODE (decl) == CONST_DECL) |
| { |
| my_friendly_assert (TREE_CODE (decl) != REFERENCE_TYPE, 148); |
| |
| DECL_INITIAL (decl) = init; |
| |
| /* This will keep us from needing to worry about our obstacks. */ |
| my_friendly_assert (init != NULL_TREE, 149); |
| init = NULL_TREE; |
| } |
| else if (init) |
| { |
| if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type)) |
| { |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| init = digest_init (type, init, (tree *) 0); |
| else if (TREE_CODE (init) == CONSTRUCTOR) |
| { |
| if (TYPE_NON_AGGREGATE_CLASS (type)) |
| { |
| cp_error ("`%D' must be initialized by constructor, not by `{...}'", |
| decl); |
| init = error_mark_node; |
| } |
| else |
| goto dont_use_constructor; |
| } |
| } |
| else |
| { |
| dont_use_constructor: |
| if (TREE_CODE (init) != TREE_VEC) |
| init = store_init_value (decl, init); |
| } |
| |
| if (init) |
| /* We must hide the initializer so that expand_decl |
| won't try to do something it does not understand. */ |
| init = obscure_complex_init (decl, init); |
| } |
| else if (DECL_EXTERNAL (decl)) |
| ; |
| else if (TREE_CODE_CLASS (TREE_CODE (type)) == 't' |
| && (IS_AGGR_TYPE (type) || TYPE_NEEDS_CONSTRUCTING (type))) |
| { |
| tree ctype = type; |
| while (TREE_CODE (ctype) == ARRAY_TYPE) |
| ctype = TREE_TYPE (ctype); |
| if (! TYPE_NEEDS_CONSTRUCTING (ctype)) |
| { |
| if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (ctype)) |
| cp_error ("structure `%D' with uninitialized const members", decl); |
| if (CLASSTYPE_REF_FIELDS_NEED_INIT (ctype)) |
| cp_error ("structure `%D' with uninitialized reference members", |
| decl); |
| } |
| |
| if (TREE_CODE (decl) == VAR_DECL |
| && !DECL_INITIAL (decl) |
| && !TYPE_NEEDS_CONSTRUCTING (type) |
| && (TYPE_READONLY (type) || TREE_READONLY (decl))) |
| cp_error ("uninitialized const `%D'", decl); |
| |
| if (TYPE_SIZE (type) != NULL_TREE |
| && TYPE_NEEDS_CONSTRUCTING (type)) |
| init = obscure_complex_init (decl, NULL_TREE); |
| } |
| else if (TREE_CODE (decl) == VAR_DECL |
| && TREE_CODE (type) != REFERENCE_TYPE |
| && (TYPE_READONLY (type) || TREE_READONLY (decl))) |
| { |
| /* ``Unless explicitly declared extern, a const object does not have |
| external linkage and must be initialized. ($8.4; $12.1)'' ARM 7.1.6 |
| However, if it's `const int foo = 1; const int foo;', don't complain |
| about the second decl, since it does have an initializer before. |
| We deliberately don't complain about arrays, because they're |
| supposed to be initialized by a constructor. */ |
| if (! DECL_INITIAL (decl) |
| && TREE_CODE (type) != ARRAY_TYPE |
| && (!pedantic || !current_class_type)) |
| cp_error ("uninitialized const `%#D'", decl); |
| } |
| |
| /* For top-level declaration, the initial value was read in |
| the temporary obstack. MAXINDEX, rtl, etc. to be made below |
| must go in the permanent obstack; but don't discard the |
| temporary data yet. */ |
| |
| if (toplevel_bindings_p () && temporary) |
| end_temporary_allocation (); |
| |
| /* Deduce size of array from initialization, if not already known. */ |
| |
| if (TREE_CODE (type) == ARRAY_TYPE |
| && TYPE_DOMAIN (type) == NULL_TREE |
| && TREE_CODE (decl) != TYPE_DECL) |
| { |
| int do_default |
| = (TREE_STATIC (decl) |
| /* Even if pedantic, an external linkage array |
| may have incomplete type at first. */ |
| ? pedantic && ! DECL_EXTERNAL (decl) |
| : !DECL_EXTERNAL (decl)); |
| tree initializer = init ? init : DECL_INITIAL (decl); |
| int failure = complete_array_type (type, initializer, do_default); |
| |
| if (failure == 1) |
| cp_error ("initializer fails to determine size of `%D'", decl); |
| |
| if (failure == 2) |
| { |
| if (do_default) |
| cp_error ("array size missing in `%D'", decl); |
| /* If a `static' var's size isn't known, make it extern as |
| well as static, so it does not get allocated. If it's not |
| `static', then don't mark it extern; finish_incomplete_decl |
| will give it a default size and it will get allocated. */ |
| else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl)) |
| DECL_EXTERNAL (decl) = 1; |
| } |
| |
| if (pedantic && TYPE_DOMAIN (type) != NULL_TREE |
| && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), |
| integer_zero_node)) |
| cp_error ("zero-size array `%D'", decl); |
| |
| layout_decl (decl, 0); |
| } |
| |
| if (TREE_CODE (decl) == VAR_DECL) |
| { |
| if (DECL_SIZE (decl) == NULL_TREE |
| && TYPE_SIZE (complete_type (TREE_TYPE (decl))) != NULL_TREE) |
| layout_decl (decl, 0); |
| |
| if (TREE_STATIC (decl) && DECL_SIZE (decl) == NULL_TREE) |
| { |
| /* A static variable with an incomplete type: |
| that is an error if it is initialized. |
| Otherwise, let it through, but if it is not `extern' |
| then it may cause an error message later. */ |
| if (DECL_INITIAL (decl) != NULL_TREE) |
| cp_error ("storage size of `%D' isn't known", decl); |
| init = NULL_TREE; |
| } |
| else if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE) |
| { |
| /* An automatic variable with an incomplete type: that is an error. |
| Don't talk about array types here, since we took care of that |
| message in grokdeclarator. */ |
| cp_error ("storage size of `%D' isn't known", decl); |
| TREE_TYPE (decl) = error_mark_node; |
| } |
| else if (!DECL_EXTERNAL (decl) && IS_AGGR_TYPE (ttype)) |
| /* Let debugger know it should output info for this type. */ |
| note_debug_info_needed (ttype); |
| |
| if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl)) |
| note_debug_info_needed (DECL_CONTEXT (decl)); |
| |
| if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl)) |
| && DECL_SIZE (decl) != NULL_TREE |
| && ! TREE_CONSTANT (DECL_SIZE (decl))) |
| { |
| if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) |
| constant_expression_warning (DECL_SIZE (decl)); |
| else |
| cp_error ("storage size of `%D' isn't constant", decl); |
| } |
| |
| if (! DECL_EXTERNAL (decl) && TYPE_NEEDS_DESTRUCTOR (type) |
| /* Cleanups for static variables are handled by `finish_file'. */ |
| && ! TREE_STATIC (decl)) |
| { |
| int yes = suspend_momentary (); |
| cleanup = maybe_build_cleanup (decl); |
| resume_momentary (yes); |
| } |
| } |
| /* PARM_DECLs get cleanups, too. */ |
| else if (TREE_CODE (decl) == PARM_DECL && TYPE_NEEDS_DESTRUCTOR (type)) |
| { |
| if (temporary) |
| end_temporary_allocation (); |
| cleanup = maybe_build_cleanup (decl); |
| if (temporary) |
| resume_temporary_allocation (); |
| } |
| |
| /* Output the assembler code and/or RTL code for variables and functions, |
| unless the type is an undefined structure or union. |
| If not, it will get done when the type is completed. */ |
| |
| was_incomplete = (DECL_SIZE (decl) == NULL_TREE); |
| |
| if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL |
| || TREE_CODE (decl) == RESULT_DECL) |
| { |
| /* ??? FIXME: What about nested classes? */ |
| int toplev = toplevel_bindings_p () || pseudo_global_level_p (); |
| int was_temp |
| = (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type) |
| && allocation_temporary_p ()); |
| |
| if (was_temp) |
| end_temporary_allocation (); |
| |
| /* Static data in a function with comdat linkage also has comdat |
| linkage. */ |
| if (TREE_CODE (decl) == VAR_DECL |
| && TREE_STATIC (decl) |
| /* Don't mess with __FUNCTION__. */ |
| && ! TREE_ASM_WRITTEN (decl) |
| && current_function_decl |
| && DECL_CONTEXT (decl) == current_function_decl |
| && (DECL_THIS_INLINE (current_function_decl) |
| || DECL_TEMPLATE_INSTANTIATION (current_function_decl)) |
| && TREE_PUBLIC (current_function_decl)) |
| { |
| /* Rather than try to get this right with inlining, we suppress |
| inlining of such functions. */ |
| current_function_cannot_inline |
| = "function with static variable cannot be inline"; |
| |
| /* If flag_weak, we don't need to mess with this, as we can just |
| make the function weak, and let it refer to its unique local |
| copy. This works because we don't allow the function to be |
| inlined. */ |
| if (! flag_weak) |
| { |
| if (DECL_INTERFACE_KNOWN (current_function_decl)) |
| { |
| TREE_PUBLIC (decl) = 1; |
| DECL_EXTERNAL (decl) = DECL_EXTERNAL (current_function_decl); |
| } |
| else if (DECL_INITIAL (decl) == NULL_TREE |
| || DECL_INITIAL (decl) == error_mark_node) |
| { |
| TREE_PUBLIC (decl) = 1; |
| DECL_COMMON (decl) = 1; |
| } |
| /* else we lose. We can only do this if we can use common, |
| which we can't if it has been initialized. */ |
| |
| if (TREE_PUBLIC (decl)) |
| DECL_ASSEMBLER_NAME (decl) |
| = build_static_name (current_function_decl, DECL_NAME (decl)); |
| else if (! DECL_ARTIFICIAL (decl)) |
| { |
| cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl); |
| cp_warning_at (" you can work around this by removing the initializer"), decl; |
| } |
| } |
| } |
| |
| else if (TREE_CODE (decl) == VAR_DECL |
| && DECL_LANG_SPECIFIC (decl) |
| && DECL_COMDAT (decl)) |
| { |
| /* Dynamically initialized vars go into common. */ |
| if (DECL_INITIAL (decl) == NULL_TREE |
| || DECL_INITIAL (decl) == error_mark_node) |
| DECL_COMMON (decl) = 1; |
| else if (EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))) |
| { |
| DECL_COMMON (decl) = 1; |
| DECL_INITIAL (decl) = error_mark_node; |
| } |
| else |
| { |
| /* Statically initialized vars are weak or comdat, if |
| supported. */ |
| if (flag_weak) |
| make_decl_one_only (decl); |
| else |
| { |
| /* We can't do anything useful; leave vars for explicit |
| instantiation. */ |
| DECL_EXTERNAL (decl) = 1; |
| DECL_NOT_REALLY_EXTERN (decl) = 0; |
| } |
| } |
| } |
| |
| if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl)) |
| make_decl_rtl (decl, NULL_PTR, toplev); |
| else if (TREE_CODE (decl) == VAR_DECL |
| && TREE_READONLY (decl) |
| && DECL_INITIAL (decl) != NULL_TREE |
| && DECL_INITIAL (decl) != error_mark_node |
| && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))) |
| { |
| DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl)); |
| |
| if (asmspec) |
| DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec); |
| |
| if (! toplev |
| && TREE_STATIC (decl) |
| && ! TREE_SIDE_EFFECTS (decl) |
| && ! TREE_PUBLIC (decl) |
| && ! DECL_EXTERNAL (decl) |
| && ! TYPE_NEEDS_DESTRUCTOR (type) |
| && DECL_MODE (decl) != BLKmode) |
| { |
| /* If this variable is really a constant, then fill its DECL_RTL |
| slot with something which won't take up storage. |
| If something later should take its address, we can always give |
| it legitimate RTL at that time. */ |
| DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl)); |
| store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0); |
| TREE_ASM_WRITTEN (decl) = 1; |
| } |
| else if (toplev && ! TREE_PUBLIC (decl)) |
| { |
| /* If this is a static const, change its apparent linkage |
| if it belongs to a #pragma interface. */ |
| if (!interface_unknown) |
| { |
| TREE_PUBLIC (decl) = 1; |
| DECL_EXTERNAL (decl) = interface_only; |
| } |
| make_decl_rtl (decl, asmspec, toplev); |
| } |
| else |
| rest_of_decl_compilation (decl, asmspec, toplev, at_eof); |
| } |
| else if (TREE_CODE (decl) == VAR_DECL |
| && DECL_LANG_SPECIFIC (decl) |
| && DECL_IN_AGGR_P (decl)) |
| { |
| if (TREE_STATIC (decl)) |
| { |
| if (init == NULL_TREE |
| #ifdef DEFAULT_STATIC_DEFS |
| /* If this code is dead, then users must |
| explicitly declare static member variables |
| outside the class def'n as well. */ |
| && TYPE_NEEDS_CONSTRUCTING (type) |
| #endif |
| ) |
| { |
| DECL_EXTERNAL (decl) = 1; |
| make_decl_rtl (decl, asmspec, 1); |
| } |
| else |
| rest_of_decl_compilation (decl, asmspec, toplev, at_eof); |
| } |
| else |
| /* Just a constant field. Should not need any rtl. */ |
| goto finish_end0; |
| } |
| else |
| rest_of_decl_compilation (decl, asmspec, toplev, at_eof); |
| |
| if (was_temp) |
| resume_temporary_allocation (); |
| |
| if (type != error_mark_node |
| && TYPE_LANG_SPECIFIC (type) |
| && CLASSTYPE_ABSTRACT_VIRTUALS (type)) |
| abstract_virtuals_error (decl, type); |
| else if ((TREE_CODE (type) == FUNCTION_TYPE |
| || TREE_CODE (type) == METHOD_TYPE) |
| && TYPE_LANG_SPECIFIC (TREE_TYPE (type)) |
| && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (type))) |
| abstract_virtuals_error (decl, TREE_TYPE (type)); |
| |
| if (TYPE_LANG_SPECIFIC (type) && IS_SIGNATURE (type)) |
| signature_error (decl, type); |
| else if ((TREE_CODE (type) == FUNCTION_TYPE |
| || TREE_CODE (type) == METHOD_TYPE) |
| && TYPE_LANG_SPECIFIC (TREE_TYPE (type)) |
| && IS_SIGNATURE (TREE_TYPE (type))) |
| signature_error (decl, TREE_TYPE (type)); |
| |
| if (TREE_CODE (decl) == FUNCTION_DECL) |
| ; |
| else if (DECL_EXTERNAL (decl) |
| && ! (DECL_LANG_SPECIFIC (decl) |
| && DECL_NOT_REALLY_EXTERN (decl))) |
| { |
| if (init) |
| DECL_INITIAL (decl) = init; |
| } |
| else if (TREE_STATIC (decl) && type != error_mark_node) |
| { |
| /* Cleanups for static variables are handled by `finish_file'. */ |
| if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE |
| || TYPE_NEEDS_DESTRUCTOR (type)) |
| expand_static_init (decl, init); |
| } |
| else if (! toplev) |
| { |
| /* This is a declared decl which must live until the |
| end of the binding contour. It may need a cleanup. */ |
| |
| /* Recompute the RTL of a local array now |
| if it used to be an incomplete type. */ |
| if (was_incomplete && ! TREE_STATIC (decl)) |
| { |
| /* If we used it already as memory, it must stay in memory. */ |
| TREE_ADDRESSABLE (decl) = TREE_USED (decl); |
| /* If it's still incomplete now, no init will save it. */ |
| if (DECL_SIZE (decl) == NULL_TREE) |
| DECL_INITIAL (decl) = NULL_TREE; |
| expand_decl (decl); |
| } |
| else if (! TREE_ASM_WRITTEN (decl) |
| && (TYPE_SIZE (type) != NULL_TREE |
| || TREE_CODE (type) == ARRAY_TYPE)) |
| { |
| /* Do this here, because we did not expand this decl's |
| rtl in start_decl. */ |
| if (DECL_RTL (decl) == NULL_RTX) |
| expand_decl (decl); |
| else if (cleanup) |
| { |
| /* XXX: Why don't we use decl here? */ |
| /* Ans: Because it was already expanded? */ |
| if (! expand_decl_cleanup (NULL_TREE, cleanup)) |
| cp_error ("parser lost in parsing declaration of `%D'", |
| decl); |
| /* Cleanup used up here. */ |
| cleanup = NULL_TREE; |
| } |
| } |
| |
| if (current_binding_level->is_for_scope) |
| { |
| struct binding_level *outer = current_binding_level->level_chain; |
| |
| /* Check to see if the same name is already bound at |
| the outer level, either because it was directly declared, |
| or because a dead for-decl got preserved. In either case, |
| the code would not have been valid under the ARM |
| scope rules, so clear is_for_scope for the |
| current_binding_level. |
| |
| Otherwise, we need to preserve the temp slot for decl |
| to last into the outer binding level. */ |
| |
| int handling_dead_for_vars = 0; |
| tree link = outer->names; |
| for (; ; link = TREE_CHAIN (link)) |
| { |
| if (link == NULL && handling_dead_for_vars == 0) |
| { |
| link = outer->dead_vars_from_for; |
| handling_dead_for_vars = 1; |
| } |
| if (link == NULL) |
| { |
| if (DECL_IN_MEMORY_P (decl)) |
| preserve_temp_slots (DECL_RTL (decl)); |
| break; |
| } |
| if (DECL_NAME (link) == DECL_NAME (decl)) |
| { |
| if (handling_dead_for_vars) |
| { |
| tree shadowing |
| = purpose_member (DECL_NAME (decl), |
| current_binding_level->shadowed); |
| if (shadowing && TREE_VALUE (shadowing) == link) |
| TREE_VALUE (shadowing) |
| = DECL_SHADOWED_FOR_VAR (link); |
| } |
| current_binding_level->is_for_scope = 0; |
| break; |
| } |
| } |
| } |
| |
| expand_start_target_temps (); |
| |
| if (DECL_SIZE (decl) && type != error_mark_node) |
| { |
| /* Compute and store the initial value. */ |
| expand_decl_init (decl); |
| already_used = TREE_USED (decl) || TREE_USED (type); |
| |
| if (init || TYPE_NEEDS_CONSTRUCTING (type)) |
| { |
| emit_line_note (DECL_SOURCE_FILE (decl), |
| DECL_SOURCE_LINE (decl)); |
| expand_aggr_init (decl, init, 0, flags); |
| } |
| |
| /* Set this to 0 so we can tell whether an aggregate which |
| was initialized was ever used. Don't do this if it has a |
| destructor, so we don't complain about the 'resource |
| allocation is initialization' idiom. */ |
| /* Now set attribute((unused)) on types so decls of |
| that type will be marked used. (see TREE_USED, above.) |
| This avoids the warning problems this particular code |
| tried to work around. */ |
| |
| if (TYPE_NEEDS_CONSTRUCTING (type) |
| && ! already_used |
| && cleanup == NULL_TREE |
| && DECL_NAME (decl)) |
| TREE_USED (decl) = 0; |
| |
| if (already_used) |
| TREE_USED (decl) = 1; |
| } |
| |
| /* Cleanup any temporaries needed for the initial value. */ |
| expand_end_target_temps (); |
| |
| if (DECL_SIZE (decl) && type != error_mark_node) |
| { |
| /* Store the cleanup, if there was one. */ |
| if (cleanup) |
| { |
| if (! expand_decl_cleanup (decl, cleanup)) |
| cp_error ("parser lost in parsing declaration of `%D'", |
| decl); |
| } |
| } |
| } |
| finish_end0: |
| |
| /* Undo call to `pushclass' that was done in `start_decl' |
| due to initialization of qualified member variable. |
| I.e., Foo::x = 10; */ |
| { |
| tree context = DECL_REAL_CONTEXT (decl); |
| if (context |
| && TREE_CODE_CLASS (TREE_CODE (context)) == 't' |
| && (TREE_CODE (decl) == VAR_DECL |
| /* We also have a pushclass done that we need to undo here |
| if we're at top level and declare a method. */ |
| || TREE_CODE (decl) == FUNCTION_DECL) |
| /* If size hasn't been set, we're still defining it, |
| and therefore inside the class body; don't pop |
| the binding level.. */ |
| && TYPE_SIZE (context) != NULL_TREE |
| && context == current_class_type) |
| popclass (1); |
| } |
| } |
| |
| finish_end: |
| |
| /* If requested, warn about definitions of large data objects. */ |
| |
| if (warn_larger_than |
| && ! processing_template_decl |
| && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) |
| && !DECL_EXTERNAL (decl)) |
| { |
| register tree decl_size = DECL_SIZE (decl); |
| |
| if (decl_size && TREE_CODE (decl_size) == INTEGER_CST) |
| { |
| unsigned units = TREE_INT_CST_LOW (decl_size) / BITS_PER_UNIT; |
| |
| if (units > larger_than_size) |
| warning_with_decl (decl, "size of `%s' is %u bytes", units); |
| } |
| } |
| |
| if (need_pop) |
| { |
| /* Resume permanent allocation, if not within a function. */ |
| /* The corresponding push_obstacks_nochange is in start_decl, |
| start_method, groktypename, and in grokfield. */ |
| pop_obstacks (); |
| } |
| |
| if (was_readonly) |
| TREE_READONLY (decl) = 1; |
| } |
| |
| /* This is here for a midend callback from c-common.c */ |
| |
| void |
| finish_decl (decl, init, asmspec_tree) |
| tree decl, init; |
| tree asmspec_tree; |
| { |
| cp_finish_decl (decl, init, asmspec_tree, 1, 0); |
| } |
| |
| void |
| expand_static_init (decl, init) |
| tree decl; |
| tree init; |
| { |
| tree oldstatic = value_member (decl, static_aggregates); |
| |
| if (oldstatic) |
| { |
| if (TREE_PURPOSE (oldstatic) && init != NULL_TREE) |
| cp_error ("multiple initializations given for `%D'", decl); |
| } |
| else if (! toplevel_bindings_p () && ! pseudo_global_level_p ()) |
| { |
| /* Emit code to perform this initialization but once. */ |
| tree temp; |
| |
| /* Remember this information until end of file. */ |
| push_obstacks (&permanent_obstack, &permanent_obstack); |
| |
| /* Emit code to perform this initialization but once. */ |
| temp = get_temp_name (integer_type_node, 1); |
| rest_of_decl_compilation (temp, NULL_PTR, 0, 0); |
| expand_start_cond (build_binary_op (EQ_EXPR, temp, |
| integer_zero_node, 1), 0); |
| expand_start_target_temps (); |
| |
| expand_assignment (temp, integer_one_node, 0, 0); |
| if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)) |
| || (init && TREE_CODE (init) == TREE_LIST)) |
| { |
| expand_aggr_init (decl, init, 0, 0); |
| do_pending_stack_adjust (); |
| } |
| else if (init) |
| expand_assignment (decl, init, 0, 0); |
| |
| /* Cleanup any temporaries needed for the initial value. */ |
| expand_end_target_temps (); |
| |
| if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) |
| { |
| tree cleanup, fcall; |
| static tree Atexit = 0; |
| if (Atexit == 0) |
| { |
| tree atexit_fndecl, PFV, pfvlist; |
| /* Remember this information until end of file. */ |
| push_obstacks (&permanent_obstack, &permanent_obstack); |
| PFV = build_pointer_type (build_function_type |
| (void_type_node, void_list_node)); |
| |
| pfvlist = tree_cons (NULL_TREE, PFV, void_list_node); |
| |
| push_lang_context (lang_name_c); |
| atexit_fndecl |
| = builtin_function ("atexit", |
| build_function_type (void_type_node, |
| pfvlist), |
| NOT_BUILT_IN, NULL_PTR); |
| assemble_external (atexit_fndecl); |
| Atexit = default_conversion (atexit_fndecl); |
| pop_lang_context (); |
| pop_obstacks (); |
| } |
| |
| cleanup = start_anon_func (); |
| expand_expr_stmt (build_cleanup (decl)); |
| end_anon_func (); |
| mark_addressable (cleanup); |
| cleanup = build_unary_op (ADDR_EXPR, cleanup, 0); |
| fcall = build_function_call (Atexit, expr_tree_cons (NULL_TREE, cleanup, NULL_TREE)); |
| expand_expr_stmt (fcall); |
| } |
| |
| expand_end_cond (); |
| if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) |
| { |
| static_aggregates = perm_tree_cons (temp, decl, static_aggregates); |
| TREE_STATIC (static_aggregates) = 1; |
| } |
| |
| /* Resume old (possibly temporary) allocation. */ |
| pop_obstacks (); |
| } |
| else |
| { |
| /* This code takes into account memory allocation |
| policy of `start_decl'. Namely, if TYPE_NEEDS_CONSTRUCTING |
| does not hold for this object, then we must make permanent |
| the storage currently in the temporary obstack. */ |
| if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) |
| preserve_initializer (); |
| static_aggregates = perm_tree_cons (init, decl, static_aggregates); |
| } |
| } |
| |
| /* Make TYPE a complete type based on INITIAL_VALUE. |
| Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered, |
| 2 if there was no information (in which case assume 1 if DO_DEFAULT). */ |
| |
| int |
| complete_array_type (type, initial_value, do_default) |
| tree type, initial_value; |
| int do_default; |
| { |
| register tree maxindex = NULL_TREE; |
| int value = 0; |
| |
| if (initial_value) |
| { |
| /* Note MAXINDEX is really the maximum index, |
| one less than the size. */ |
| if (TREE_CODE (initial_value) == STRING_CST) |
| { |
| int eltsize |
| = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value))); |
| maxindex = build_int_2 ((TREE_STRING_LENGTH (initial_value) |
| / eltsize) - 1, 0); |
| } |
| else if (TREE_CODE (initial_value) == CONSTRUCTOR) |
| { |
| tree elts = CONSTRUCTOR_ELTS (initial_value); |
| maxindex = size_binop (MINUS_EXPR, integer_zero_node, size_one_node); |
| for (; elts; elts = TREE_CHAIN (elts)) |
| { |
| if (TREE_PURPOSE (elts)) |
| maxindex = TREE_PURPOSE (elts); |
| else |
| maxindex = size_binop (PLUS_EXPR, maxindex, size_one_node); |
| } |
| maxindex = copy_node (maxindex); |
| } |
| else |
| { |
| /* Make an error message unless that happened already. */ |
| if (initial_value != error_mark_node) |
| value = 1; |
| |
| /* Prevent further error messages. */ |
| maxindex = build_int_2 (0, 0); |
| } |
| } |
| |
| if (!maxindex) |
| { |
| if (do_default) |
| maxindex = build_int_2 (0, 0); |
| value = 2; |
| } |
| |
| if (maxindex) |
| { |
| tree itype; |
| |
| TYPE_DOMAIN (type) = build_index_type (maxindex); |
| if (! TREE_TYPE (maxindex)) |
| TREE_TYPE (maxindex) = TYPE_DOMAIN (type); |
| if (initial_value) |
| itype = TREE_TYPE (initial_value); |
| else |
| itype = NULL; |
| if (itype && !TYPE_DOMAIN (itype)) |
| TYPE_DOMAIN (itype) = TYPE_DOMAIN (type); |
| /* The type of the main variant should never be used for arrays |
| of different sizes. It should only ever be completed with the |
| size of the array. */ |
| if (! TYPE_DOMAIN (TYPE_MAIN_VARIANT (type))) |
| TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)) = TYPE_DOMAIN (type); |
| } |
| |
| /* Lay out the type now that we can get the real answer. */ |
| |
| layout_type (type); |
| |
| return value; |
| } |
| |
| /* Return zero if something is declared to be a member of type |
| CTYPE when in the context of CUR_TYPE. STRING is the error |
| message to print in that case. Otherwise, quietly return 1. */ |
| |
| static int |
| member_function_or_else (ctype, cur_type, string) |
| tree ctype, cur_type; |
| char *string; |
| { |
| if (ctype && ctype != cur_type) |
| { |
| error (string, TYPE_NAME_STRING (ctype)); |
| return 0; |
| } |
| return 1; |
| } |
| |
| /* Subroutine of `grokdeclarator'. */ |
| |
| /* Generate errors possibly applicable for a given set of specifiers. |
| This is for ARM $7.1.2. */ |
| |
| static void |
| bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises) |
| tree object; |
| char *type; |
| int virtualp, quals, friendp, raises, inlinep; |
| { |
| if (virtualp) |
| cp_error ("`%D' declared as a `virtual' %s", object, type); |
| if (inlinep) |
| cp_error ("`%D' declared as an `inline' %s", object, type); |
| if (quals) |
| cp_error ("`const' and `volatile' function specifiers on `%D' invalid in %s declaration", |
| object, type); |
| if (friendp) |
| cp_error_at ("invalid friend declaration", object); |
| if (raises) |
| cp_error_at ("invalid exception specifications", object); |
| } |
| |
| /* CTYPE is class type, or null if non-class. |
| TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE |
| or METHOD_TYPE. |
| DECLARATOR is the function's name. |
| VIRTUALP is truthvalue of whether the function is virtual or not. |
| FLAGS are to be passed through to `grokclassfn'. |
| QUALS are qualifiers indicating whether the function is `const' |
| or `volatile'. |
| RAISES is a list of exceptions that this function can raise. |
| CHECK is 1 if we must find this method in CTYPE, 0 if we should |
| not look, and -1 if we should not call `grokclassfn' at all. */ |
| |
| static tree |
| grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals, |
| raises, attrlist, check, friendp, publicp, inlinep, funcdef_flag, |
| template_count, in_namespace) |
| tree ctype, type; |
| tree declarator; |
| tree orig_declarator; |
| int virtualp; |
| enum overload_flags flags; |
| tree quals, raises, attrlist; |
| int check, friendp, publicp, inlinep, funcdef_flag, template_count; |
| tree in_namespace; |
| { |
| tree cname, decl; |
| int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; |
| tree t; |
| |
| if (ctype) |
| cname = TREE_CODE (TYPE_NAME (ctype)) == TYPE_DECL |
| ? TYPE_IDENTIFIER (ctype) : TYPE_NAME (ctype); |
| else |
| cname = NULL_TREE; |
| |
| if (raises) |
| { |
| type = build_exception_variant (type, raises); |
| } |
| |
| decl = build_lang_decl (FUNCTION_DECL, declarator, type); |
| /* Propagate volatile out from type to decl. */ |
| if (TYPE_VOLATILE (type)) |
| TREE_THIS_VOLATILE (decl) = 1; |
| |
| /* This decl is not from the current namespace. */ |
| if (in_namespace) |
| set_decl_namespace (decl, in_namespace); |
| |
| /* Should probably propagate const out from type to decl I bet (mrs). */ |
| if (staticp) |
| { |
| DECL_STATIC_FUNCTION_P (decl) = 1; |
| DECL_CONTEXT (decl) = ctype; |
| } |
| |
| if (ctype) |
| DECL_CLASS_CONTEXT (decl) = ctype; |
| |
| if (ctype == NULL_TREE && MAIN_NAME_P (declarator)) |
| { |
| if (inlinep) |
| error ("cannot declare `main' to be inline"); |
| else if (! publicp) |
| error ("cannot declare `main' to be static"); |
| inlinep = 0; |
| publicp = 1; |
| } |
| |
| TREE_PUBLIC (decl) = publicp; |
| if (! publicp) |
| { |
| DECL_INTERFACE_KNOWN (decl) = 1; |
| DECL_NOT_REALLY_EXTERN (decl) = 1; |
| } |
| |
| if (inlinep) |
| DECL_THIS_INLINE (decl) = DECL_INLINE (decl) = 1; |
| |
| DECL_EXTERNAL (decl) = 1; |
| if (quals != NULL_TREE && TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| cp_error ("%smember function `%D' cannot have `%T' method qualifier", |
| (ctype ? "static " : "non-"), decl, TREE_VALUE (quals)); |
| quals = NULL_TREE; |
| } |
| |
| if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))) |
| grok_op_properties (decl, virtualp, check < 0); |
| |
| if (ctype && hack_decl_function_context (decl)) |
| DECL_NO_STATIC_CHAIN (decl) = 1; |
| |
| for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t)) |
| if (TREE_PURPOSE (t) |
| && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG) |
| { |
| add_defarg_fn (decl); |
| break; |
| } |
| |
| if (friendp |
| && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR) |
| { |
| if (funcdef_flag) |
| cp_error |
| ("defining explicit specialization `%D' in friend declaration", |
| orig_declarator); |
| else |
| { |
| /* A friend declaration of the form friend void f<>(). Record |
| the information in the TEMPLATE_ID_EXPR. */ |
| SET_DECL_IMPLICIT_INSTANTIATION (decl); |
| DECL_TEMPLATE_INFO (decl) |
| = perm_tree_cons (TREE_OPERAND (orig_declarator, 0), |
| TREE_OPERAND (orig_declarator, 1), |
| NULL_TREE); |
| } |
| } |
| |
| /* Caller will do the rest of this. */ |
| if (check < 0) |
| return decl; |
| |
| if (check && funcdef_flag) |
| DECL_INITIAL (decl) = error_mark_node; |
| |
| if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator) |
| { |
| tree tmp; |
| /* Just handle constructors here. We could do this |
| inside the following if stmt, but I think |
| that the code is more legible by breaking this |
| case out. See comments below for what each of |
| the following calls is supposed to do. */ |
| DECL_CONSTRUCTOR_P (decl) = 1; |
| |
| grokclassfn (ctype, declarator, decl, flags, quals); |
| |
| decl = check_explicit_specialization (orig_declarator, decl, |
| template_count, |
| 2 * (funcdef_flag != 0) + |
| 4 * (friendp != 0)); |
| |
| if ((! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl)) |
| && check) |
| { |
| tmp = check_classfn (ctype, decl); |
| |
| if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL) |
| tmp = DECL_TEMPLATE_RESULT(tmp); |
| |
| if (tmp && DECL_ARTIFICIAL (tmp)) |
| cp_error ("definition of implicitly-declared `%D'", tmp); |
| if (tmp && duplicate_decls (decl, tmp)) |
| return tmp; |
| } |
| if (! grok_ctor_properties (ctype, decl)) |
| return NULL_TREE; |
| |
| if (check == 0 && ! current_function_decl) |
| { |
| /* Assembler names live in the global namespace. */ |
| tmp = IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)); |
| if (tmp == NULL_TREE) |
| SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl); |
| else if (TREE_CODE (tmp) != TREE_CODE (decl)) |
| cp_error ("inconsistent declarations for `%D'", decl); |
| else |
| { |
| duplicate_decls (decl, tmp); |
| decl = tmp; |
| } |
| make_decl_rtl (decl, NULL_PTR, 1); |
| } |
| } |
| else |
| { |
| tree tmp; |
| |
| /* Function gets the ugly name, field gets the nice one. |
| This call may change the type of the function (because |
| of default parameters)! */ |
| if (ctype != NULL_TREE) |
| grokclassfn (ctype, cname, decl, flags, quals); |
| |
| decl = check_explicit_specialization (orig_declarator, decl, |
| template_count, |
| 2 * (funcdef_flag != 0) + |
| 4 * (friendp != 0)); |
| if (ctype != NULL_TREE |
| && (! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl)) |
| && check) |
| { |
| tmp = check_classfn (ctype, decl); |
| |
| if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL) |
| tmp = DECL_TEMPLATE_RESULT (tmp); |
| |
| if (tmp && DECL_STATIC_FUNCTION_P (tmp) |
| && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) |
| { |
| /* Remove the `this' parm added by grokclassfn. |
| XXX Isn't this done in start_function, too? */ |
| revert_static_member_fn (&decl, NULL, NULL); |
| last_function_parms = TREE_CHAIN (last_function_parms); |
| } |
| if (tmp && DECL_ARTIFICIAL (tmp)) |
| cp_error ("definition of implicitly-declared `%D'", tmp); |
| if (tmp) |
| { |
| if (!duplicate_decls (decl, tmp)) |
| my_friendly_abort (892); |
| return tmp; |
| } |
| } |
| |
| if (ctype == NULL_TREE || check) |
| return decl; |
| |
| /* Now install the declaration of this function so that others may |
| find it (esp. its DECL_FRIENDLIST). Don't do this for local class |
| methods, though. */ |
| if (! current_function_decl) |
| { |
| if (!DECL_TEMPLATE_SPECIALIZATION (decl)) |
| { |
| /* We don't do this for specializations since the |
| equivalent checks will be done later. Also, at this |
| point the DECL_ASSEMBLER_NAME is not yet fully |
| accurate. */ |
| |
| /* FIXME: this should only need to look at |
| IDENTIFIER_GLOBAL_VALUE. */ |
| tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0); |
| if (tmp == NULL_TREE) |
| SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl); |
| else if (TREE_CODE (tmp) != TREE_CODE (decl)) |
| cp_error ("inconsistent declarations for `%D'", decl); |
| else |
| { |
| duplicate_decls (decl, tmp); |
| decl = tmp; |
| } |
| } |
| |
| if (attrlist) |
| cplus_decl_attributes (decl, TREE_PURPOSE (attrlist), |
| TREE_VALUE (attrlist)); |
| make_decl_rtl (decl, NULL_PTR, 1); |
| } |
| if (virtualp) |
| { |
| DECL_VIRTUAL_P (decl) = 1; |
| if (DECL_VINDEX (decl) == NULL_TREE) |
| DECL_VINDEX (decl) = error_mark_node; |
| IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1; |
| } |
| } |
| return decl; |
| } |
| |
| static tree |
| grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace) |
| tree type; |
| tree declarator; |
| RID_BIT_TYPE *specbits_in; |
| int initialized; |
| int constp; |
| tree in_namespace; |
| { |
| tree decl; |
| RID_BIT_TYPE specbits; |
| |
| specbits = *specbits_in; |
| |
| if (TREE_CODE (type) == OFFSET_TYPE) |
| { |
| /* If you declare a static member so that it |
| can be initialized, the code will reach here. */ |
| tree basetype = TYPE_OFFSET_BASETYPE (type); |
| type = TREE_TYPE (type); |
| decl = build_lang_field_decl (VAR_DECL, declarator, type); |
| DECL_CONTEXT (decl) = basetype; |
| DECL_CLASS_CONTEXT (decl) = basetype; |
| DECL_ASSEMBLER_NAME (decl) = build_static_name (basetype, declarator); |
| } |
| else |
| { |
| tree context = in_namespace ? in_namespace : current_namespace; |
| decl = build_decl (VAR_DECL, declarator, complete_type (type)); |
| if (context != global_namespace && namespace_bindings_p () |
| && current_lang_name != lang_name_c) |
| DECL_ASSEMBLER_NAME (decl) = build_static_name (context, |
| declarator); |
| } |
| |
| if (in_namespace) |
| set_decl_namespace (decl, in_namespace); |
| |
| if (RIDBIT_SETP (RID_EXTERN, specbits)) |
| { |
| DECL_THIS_EXTERN (decl) = 1; |
| DECL_EXTERNAL (decl) = !initialized; |
| } |
| |
| /* In class context, static means one per class, |
| public access, and static storage. */ |
| if (DECL_CLASS_SCOPE_P (decl)) |
| { |
| TREE_PUBLIC (decl) = 1; |
| TREE_STATIC (decl) = 1; |
| DECL_EXTERNAL (decl) = 0; |
| } |
| /* At top level, either `static' or no s.c. makes a definition |
| (perhaps tentative), and absence of `static' makes it public. */ |
| else if (toplevel_bindings_p ()) |
| { |
| TREE_PUBLIC (decl) = (RIDBIT_NOTSETP (RID_STATIC, specbits) |
| && (DECL_THIS_EXTERN (decl) || ! constp)); |
| TREE_STATIC (decl) = ! DECL_EXTERNAL (decl); |
| } |
| /* Not at top level, only `static' makes a static definition. */ |
| else |
| { |
| TREE_STATIC (decl) = !! RIDBIT_SETP (RID_STATIC, specbits); |
| TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); |
| } |
| return decl; |
| } |
| |
| /* Create a canonical pointer to member function type. */ |
| |
| tree |
| build_ptrmemfunc_type (type) |
| tree type; |
| { |
| tree fields[4]; |
| tree t; |
| tree u; |
| |
| /* If a canonical type already exists for this type, use it. We use |
| this method instead of type_hash_canon, because it only does a |
| simple equality check on the list of field members. */ |
| |
| if ((t = TYPE_GET_PTRMEMFUNC_TYPE (type))) |
| return t; |
| |
| push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type)); |
| |
| u = make_lang_type (UNION_TYPE); |
| IS_AGGR_TYPE (u) = 0; |
| fields[0] = build_lang_field_decl (FIELD_DECL, pfn_identifier, type); |
| fields[1] = build_lang_field_decl (FIELD_DECL, delta2_identifier, |
| delta_type_node); |
| finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node); |
| TYPE_NAME (u) = NULL_TREE; |
| |
| t = make_lang_type (RECORD_TYPE); |
| |
| /* Let the front-end know this is a pointer to member function... */ |
| TYPE_PTRMEMFUNC_FLAG (t) = 1; |
| /* ... and not really an aggregate. */ |
| IS_AGGR_TYPE (t) = 0; |
| |
| fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier, |
| delta_type_node); |
| fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier, |
| delta_type_node); |
| fields[2] = build_lang_field_decl (FIELD_DECL, pfn_or_delta2_identifier, u); |
| finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node); |
| |
| pop_obstacks (); |
| |
| /* Zap out the name so that the back-end will give us the debugging |
| information for this anonymous RECORD_TYPE. */ |
| TYPE_NAME (t) = NULL_TREE; |
| |
| TYPE_SET_PTRMEMFUNC_TYPE (type, t); |
| |
| /* Seems to be wanted. */ |
| CLASSTYPE_GOT_SEMICOLON (t) = 1; |
| return t; |
| } |
| |
| /* Given declspecs and a declarator, |
| determine the name and type of the object declared |
| and construct a ..._DECL node for it. |
| (In one case we can return a ..._TYPE node instead. |
| For invalid input we sometimes return 0.) |
| |
| DECLSPECS is a chain of tree_list nodes whose value fields |
| are the storage classes and type specifiers. |
| |
| DECL_CONTEXT says which syntactic context this declaration is in: |
| NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL. |
| FUNCDEF for a function definition. Like NORMAL but a few different |
| error messages in each case. Return value may be zero meaning |
| this definition is too screwy to try to parse. |
| MEMFUNCDEF for a function definition. Like FUNCDEF but prepares to |
| handle member functions (which have FIELD context). |
| Return value may be zero meaning this definition is too screwy to |
| try to parse. |
| PARM for a parameter declaration (either within a function prototype |
| or before a function body). Make a PARM_DECL, or return void_type_node. |
| CATCHPARM for a parameter declaration before a catch clause. |
| TYPENAME if for a typename (in a cast or sizeof). |
| Don't make a DECL node; just return the ..._TYPE node. |
| FIELD for a struct or union field; make a FIELD_DECL. |
| BITFIELD for a field with specified width. |
| INITIALIZED is 1 if the decl has an initializer. |
| |
| In the TYPENAME case, DECLARATOR is really an absolute declarator. |
| It may also be so in the PARM case, for a prototype where the |
| argument type is specified but not the name. |
| |
| This function is where the complicated C meanings of `static' |
| and `extern' are interpreted. |
| |
| For C++, if there is any monkey business to do, the function which |
| calls this one must do it, i.e., prepending instance variables, |
| renaming overloaded function names, etc. |
| |
| Note that for this C++, it is an error to define a method within a class |
| which does not belong to that class. |
| |
| Except in the case where SCOPE_REFs are implicitly known (such as |
| methods within a class being redundantly qualified), |
| declarations which involve SCOPE_REFs are returned as SCOPE_REFs |
| (class_name::decl_name). The caller must also deal with this. |
| |
| If a constructor or destructor is seen, and the context is FIELD, |
| then the type gains the attribute TREE_HAS_x. If such a declaration |
| is erroneous, NULL_TREE is returned. |
| |
| QUALS is used only for FUNCDEF and MEMFUNCDEF cases. For a member |
| function, these are the qualifiers to give to the `this' pointer. |
| |
| May return void_type_node if the declarator turned out to be a friend. |
| See grokfield for details. */ |
| |
| enum return_types { return_normal, return_ctor, return_dtor, return_conversion }; |
| |
| tree |
| grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) |
| tree declspecs; |
| tree declarator; |
| enum decl_context decl_context; |
| int initialized; |
| tree attrlist; |
| { |
| RID_BIT_TYPE specbits; |
| int nclasses = 0; |
| tree spec; |
| tree type = NULL_TREE; |
| int longlong = 0; |
| int constp; |
| int volatilep; |
| int virtualp, explicitp, friendp, inlinep, staticp; |
| int explicit_int = 0; |
| int explicit_char = 0; |
| int defaulted_int = 0; |
| int opaque_typedef = 0; |
| tree typedef_decl = NULL_TREE; |
| char *name; |
| tree typedef_type = NULL_TREE; |
| int funcdef_flag = 0; |
| enum tree_code innermost_code = ERROR_MARK; |
| int bitfield = 0; |
| #if 0 |
| /* See the code below that used this. */ |
| tree decl_machine_attr = NULL_TREE; |
| #endif |
| /* Set this to error_mark_node for FIELD_DECLs we could not handle properly. |
| All FIELD_DECLs we build here have `init' put into their DECL_INITIAL. */ |
| tree init = NULL_TREE; |
| |
| /* Keep track of what sort of function is being processed |
| so that we can warn about default return values, or explicit |
| return values which do not match prescribed defaults. */ |
| enum return_types return_type = return_normal; |
| |
| tree dname = NULL_TREE; |
| tree ctype = current_class_type; |
| tree ctor_return_type = NULL_TREE; |
| enum overload_flags flags = NO_SPECIAL; |
| tree quals = NULL_TREE; |
| tree raises = NULL_TREE; |
| int template_count = 0; |
| tree in_namespace = NULL_TREE; |
| |
| RIDBIT_RESET_ALL (specbits); |
| if (decl_context == FUNCDEF) |
| funcdef_flag = 1, decl_context = NORMAL; |
| else if (decl_context == MEMFUNCDEF) |
| funcdef_flag = -1, decl_context = FIELD; |
| else if (decl_context == BITFIELD) |
| bitfield = 1, decl_context = FIELD; |
| |
| /* Look inside a declarator for the name being declared |
| and get it as a string, for an error message. */ |
| { |
| tree *next = &declarator; |
| register tree decl; |
| name = NULL; |
| |
| while (next && *next) |
| { |
| decl = *next; |
| switch (TREE_CODE (decl)) |
| { |
| case COND_EXPR: |
| ctype = NULL_TREE; |
| next = &TREE_OPERAND (decl, 0); |
| break; |
| |
| case BIT_NOT_EXPR: /* For C++ destructors! */ |
| { |
| tree name = TREE_OPERAND (decl, 0); |
| tree rename = NULL_TREE; |
| |
| my_friendly_assert (flags == NO_SPECIAL, 152); |
| flags = DTOR_FLAG; |
| return_type = return_dtor; |
| if (TREE_CODE (name) == TYPE_DECL) |
| TREE_OPERAND (decl, 0) = name = constructor_name (name); |
| my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153); |
| if (ctype == NULL_TREE) |
| { |
| if (current_class_type == NULL_TREE) |
| { |
| error ("destructors must be member functions"); |
| flags = NO_SPECIAL; |
| } |
| else |
| { |
| tree t = constructor_name (current_class_name); |
| if (t != name) |
| rename = t; |
| } |
| } |
| else |
| { |
| tree t = constructor_name (ctype); |
| if (t != name) |
| rename = t; |
| } |
| |
| if (rename) |
| { |
| cp_error ("destructor `%T' must match class name `%T'", |
| name, rename); |
| TREE_OPERAND (decl, 0) = rename; |
| } |
| next = &name; |
| } |
| break; |
| |
| case ADDR_EXPR: /* C++ reference declaration */ |
| /* Fall through. */ |
| case ARRAY_REF: |
| case INDIRECT_REF: |
| ctype = NULL_TREE; |
| innermost_code = TREE_CODE (decl); |
| next = &TREE_OPERAND (decl, 0); |
| break; |
| |
| case CALL_EXPR: |
| if (parmlist_is_exprlist (TREE_OPERAND (decl, 1))) |
| { |
| /* This is actually a variable declaration using constructor |
| syntax. We need to call start_decl and cp_finish_decl so we |
| can get the variable initialized... */ |
| |
| *next = TREE_OPERAND (decl, 0); |
| init = TREE_OPERAND (decl, 1); |
| |
| decl = start_decl (declarator, declspecs, 1, NULL_TREE, NULL_TREE); |
| /* Look for __unused__ attribute */ |
| if (TREE_USED (TREE_TYPE (decl))) |
| TREE_USED (decl) = 1; |
| finish_decl (decl, init, NULL_TREE); |
| return 0; |
| } |
| innermost_code = TREE_CODE (decl); |
| if (decl_context == FIELD && ctype == NULL_TREE) |
| ctype = current_class_type; |
| if (ctype |
| && TREE_OPERAND (decl, 0) |
| && (TREE_CODE (TREE_OPERAND (decl, 0)) == TYPE_DECL |
| && ((DECL_NAME (TREE_OPERAND (decl, 0)) |
| == constructor_name_full (ctype)) |
| || (DECL_NAME (TREE_OPERAND (decl, 0)) |
| == constructor_name (ctype))))) |
| TREE_OPERAND (decl, 0) = constructor_name (ctype); |
| next = &TREE_OPERAND (decl, 0); |
| decl = *next; |
| if (ctype != NULL_TREE |
| && decl != NULL_TREE && flags != DTOR_FLAG |
| && decl == constructor_name (ctype)) |
| { |
| return_type = return_ctor; |
| ctor_return_type = ctype; |
| } |
| ctype = NULL_TREE; |
| break; |
| |
| case TEMPLATE_ID_EXPR: |
| { |
| tree fns = TREE_OPERAND (decl, 0); |
| |
| if (TREE_CODE (fns) == LOOKUP_EXPR) |
| fns = TREE_OPERAND (fns, 0); |
| |
| if (TREE_CODE (fns) == IDENTIFIER_NODE) |
| dname = fns; |
| else if (is_overloaded_fn (fns)) |
| dname = DECL_NAME (get_first_fn (fns)); |
| else |
| my_friendly_abort (0); |
| } |
| /* Fall through. */ |
| |
| case IDENTIFIER_NODE: |
| if (TREE_CODE (decl) == IDENTIFIER_NODE) |
| dname = decl; |
| |
| next = 0; |
| |
| if (is_rid (dname)) |
| { |
| cp_error ("declarator-id missing; using reserved word `%D'", |
| dname); |
| name = IDENTIFIER_POINTER (dname); |
| } |
| if (! IDENTIFIER_OPNAME_P (dname) |
| /* GNU/Linux headers use '__op'. Arrgh. */ |
| || (IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname))) |
| name = IDENTIFIER_POINTER (dname); |
| else |
| { |
| if (IDENTIFIER_TYPENAME_P (dname)) |
| { |
| my_friendly_assert (flags == NO_SPECIAL, 154); |
| flags = TYPENAME_FLAG; |
| ctor_return_type = TREE_TYPE (dname); |
| return_type = return_conversion; |
| } |
| name = operator_name_string (dname); |
| } |
| break; |
| |
| /* C++ extension */ |
| case SCOPE_REF: |
| { |
| /* Perform error checking, and decide on a ctype. */ |
| tree cname = TREE_OPERAND (decl, 0); |
| if (cname == NULL_TREE) |
| ctype = NULL_TREE; |
| else if (TREE_CODE (cname) == NAMESPACE_DECL) |
| { |
| ctype = NULL_TREE; |
| in_namespace = TREE_OPERAND (decl, 0); |
| TREE_OPERAND (decl, 0) = NULL_TREE; |
| } |
| else if (! is_aggr_type (cname, 1)) |
| TREE_OPERAND (decl, 0) = NULL_TREE; |
| /* Must test TREE_OPERAND (decl, 1), in case user gives |
| us `typedef (class::memfunc)(int); memfunc *memfuncptr;' */ |
| else if (TREE_OPERAND (decl, 1) |
| && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF) |
| ctype = cname; |
| else if (TREE_CODE (cname) == TEMPLATE_TYPE_PARM |
| || TREE_CODE (cname) == TEMPLATE_TEMPLATE_PARM) |
| { |
| cp_error ("`%T::%D' is not a valid declarator", cname, |
| TREE_OPERAND (decl, 1)); |
| cp_error (" perhaps you want `typename %T::%D' to make it a type", |
| cname, TREE_OPERAND (decl, 1)); |
| return void_type_node; |
| } |
| else if (ctype == NULL_TREE) |
| ctype = cname; |
| else if (TREE_COMPLEXITY (decl) == current_class_depth) |
| TREE_OPERAND (decl, 0) = ctype; |
| else |
| { |
| if (! UNIQUELY_DERIVED_FROM_P (cname, ctype)) |
| { |
| cp_error ("type `%T' is not derived from type `%T'", |
| cname, ctype); |
| TREE_OPERAND (decl, 0) = NULL_TREE; |
| } |
| else |
| ctype = cname; |
| } |
| |
| if (ctype && TREE_CODE (TREE_OPERAND (decl, 1)) == TYPE_DECL |
| && ((DECL_NAME (TREE_OPERAND (decl, 1)) |
| == constructor_name_full (ctype)) |
| || (DECL_NAME (TREE_OPERAND (decl, 1)) |
| == constructor_name (ctype)))) |
| TREE_OPERAND (decl, 1) = constructor_name (ctype); |
| next = &TREE_OPERAND (decl, 1); |
| decl = *next; |
| if (ctype) |
| { |
| if (TREE_CODE (decl) == IDENTIFIER_NODE |
| && constructor_name (ctype) == decl) |
| { |
| return_type = return_ctor; |
| ctor_return_type = ctype; |
| } |
| else if (TREE_CODE (decl) == BIT_NOT_EXPR |
| && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE |
| && (constructor_name (ctype) == TREE_OPERAND (decl, 0) |
| || constructor_name_full (ctype) == TREE_OPERAND (decl, 0))) |
| { |
| return_type = return_dtor; |
| ctor_return_type = ctype; |
| flags = DTOR_FLAG; |
| TREE_OPERAND (decl, 0) = constructor_name (ctype); |
| next = &TREE_OPERAND (decl, 0); |
| } |
| } |
| } |
| break; |
| |
| case ERROR_MARK: |
| next = 0; |
| break; |
| |
| case TYPE_DECL: |
| /* Parse error puts this typespec where |
| a declarator should go. */ |
| cp_error ("`%T' specified as declarator-id", DECL_NAME (decl)); |
| if (TREE_TYPE (decl) == current_class_type) |
| cp_error (" perhaps you want `%T' for a constructor", |
| current_class_name); |
| dname = DECL_NAME (decl); |
| name = IDENTIFIER_POINTER (dname); |
| |
| /* Avoid giving two errors for this. */ |
| IDENTIFIER_CLASS_VALUE (dname) = NULL_TREE; |
| |
| declspecs = temp_tree_cons (NULL_TREE, integer_type_node, |
| declspecs); |
| *next = dname; |
| next = 0; |
| break; |
| |
| default: |
| cp_compiler_error ("`%D' as declarator", decl); |
| return 0; /* We used to do a 155 abort here. */ |
| } |
| } |
| if (name == NULL) |
| name = "type name"; |
| } |
| |
| /* A function definition's declarator must have the form of |
| a function declarator. */ |
| |
| if (funcdef_flag && innermost_code != CALL_EXPR) |
| return 0; |
| |
| if (((dname && IDENTIFIER_OPNAME_P (dname)) || flags == TYPENAME_FLAG) |
| && innermost_code != CALL_EXPR |
| && ! (ctype && declspecs == NULL_TREE)) |
| { |
| cp_error ("declaration of `%D' as non-function", dname); |
| return void_type_node; |
| } |
| |
| /* Anything declared one level down from the top level |
| must be one of the parameters of a function |
| (because the body is at least two levels down). */ |
| |
| /* This heuristic cannot be applied to C++ nodes! Fixed, however, |
| by not allowing C++ class definitions to specify their parameters |
| with xdecls (must be spec.d in the parmlist). |
| |
| Since we now wait to push a class scope until we are sure that |
| we are in a legitimate method context, we must set oldcname |
| explicitly (since current_class_name is not yet alive). |
| |
| We also want to avoid calling this a PARM if it is in a namespace. */ |
| |
| if (decl_context == NORMAL && ! namespace_bindings_p () |
| && ! pseudo_global_level_p ()) |
| { |
| struct binding_level *b = current_binding_level; |
| current_binding_level = b->level_chain; |
| if (current_binding_level != 0 && toplevel_bindings_p ()) |
| decl_context = PARM; |
| current_binding_level = b; |
| } |
| |
| /* Look through the decl specs and record which ones appear. |
| Some typespecs are defined as built-in typenames. |
| Others, the ones that are modifiers of other types, |
| are represented by bits in SPECBITS: set the bits for |
| the modifiers that appear. Storage class keywords are also in SPECBITS. |
| |
| If there is a typedef name or a type, store the type in TYPE. |
| This includes builtin typedefs such as `int'. |
| |
| Set EXPLICIT_INT if the type is `int' or `char' and did not |
| come from a user typedef. |
| |
| Set LONGLONG if `long' is mentioned twice. |
| |
| For C++, constructors and destructors have their own fast treatment. */ |
| |
| for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) |
| { |
| register int i; |
| register tree id; |
| |
| /* Certain parse errors slip through. For example, |
| `int class;' is not caught by the parser. Try |
| weakly to recover here. */ |
| if (TREE_CODE (spec) != TREE_LIST) |
| return 0; |
| |
| id = TREE_VALUE (spec); |
| |
| if (TREE_CODE (id) == IDENTIFIER_NODE) |
| { |
| if (id == ridpointers[(int) RID_INT] |
| || id == ridpointers[(int) RID_CHAR] |
| || id == ridpointers[(int) RID_BOOL] |
| || id == ridpointers[(int) RID_WCHAR]) |
| { |
| if (type) |
| { |
| if (id == ridpointers[(int) RID_BOOL]) |
| error ("`bool' is now a keyword"); |
| else |
| cp_error ("extraneous `%T' ignored", id); |
| } |
| else |
| { |
| if (id == ridpointers[(int) RID_INT]) |
| explicit_int = 1; |
| else if (id == ridpointers[(int) RID_CHAR]) |
| explicit_char = 1; |
| type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id)); |
| } |
| goto found; |
| } |
| /* C++ aggregate types. */ |
| if (IDENTIFIER_HAS_TYPE_VALUE (id)) |
| { |
| if (type) |
| cp_error ("multiple declarations `%T' and `%T'", type, id); |
| else |
| type = IDENTIFIER_TYPE_VALUE (id); |
| goto found; |
| } |
| |
| for (i = (int) RID_FIRST_MODIFIER; i <= (int) RID_LAST_MODIFIER; i++) |
| { |
| if (ridpointers[i] == id) |
| { |
| if (i == (int) RID_LONG && RIDBIT_SETP (i, specbits)) |
| { |
| if (pedantic && ! in_system_header && warn_long_long) |
| pedwarn ("ANSI C++ does not support `long long'"); |
| if (longlong) |
| error ("`long long long' is too long for GCC"); |
| else |
| longlong = 1; |
| } |
| else if (RIDBIT_SETP (i, specbits)) |
| pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id)); |
| RIDBIT_SET (i, specbits); |
| goto found; |
| } |
| } |
| } |
| /* C++ aggregate types. */ |
| else if (TREE_CODE (id) == TYPE_DECL || TREE_CODE (id) == TEMPLATE_DECL) |
| { |
| if (type) |
| cp_error ("multiple declarations `%T' and `%T'", type, |
| TREE_TYPE (id)); |
| else |
| { |
| type = TREE_TYPE (id); |
| TREE_VALUE (spec) = type; |
| } |
| goto found; |
| } |
| if (type) |
| error ("two or more data types in declaration of `%s'", name); |
| else if (TREE_CODE (id) == IDENTIFIER_NODE) |
| { |
| register tree t = lookup_name (id, 1); |
| if (!t || TREE_CODE (t) != TYPE_DECL) |
| error ("`%s' fails to be a typedef or built in type", |
| IDENTIFIER_POINTER (id)); |
| else |
| { |
| type = TREE_TYPE (t); |
| #if 0 |
| /* See the code below that used this. */ |
| decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id); |
| #endif |
| typedef_decl = t; |
| } |
| } |
| else if (id != error_mark_node) |
| /* Can't change CLASS nodes into RECORD nodes here! */ |
| type = id; |
| |
| found: ; |
| } |
| |
| typedef_type = type; |
| |
| /* No type at all: default to `int', and set DEFAULTED_INT |
| because it was not a user-defined typedef. |
| Except when we have a `typedef' inside a signature, in |
| which case the type defaults to `unknown type' and is |
| instantiated when assigning to a signature pointer or ref. */ |
| |
| if (type == NULL_TREE |
| && (RIDBIT_SETP (RID_SIGNED, specbits) |
| || RIDBIT_SETP (RID_UNSIGNED, specbits) |
| || RIDBIT_SETP (RID_LONG, specbits) |
| || RIDBIT_SETP (RID_SHORT, specbits))) |
| { |
| /* These imply 'int'. */ |
| type = integer_type_node; |
| defaulted_int = 1; |
| } |
| |
| if (type == NULL_TREE) |
| { |
| explicit_int = -1; |
| if (return_type == return_dtor) |
| type = void_type_node; |
| else if (return_type == return_ctor) |
| type = build_pointer_type (ctor_return_type); |
| else if (return_type == return_conversion) |
| type = ctor_return_type; |
| else if (current_class_type |
| && IS_SIGNATURE (current_class_type) |
| && RIDBIT_SETP (RID_TYPEDEF, specbits) |
| && (decl_context == FIELD || decl_context == NORMAL)) |
| { |
| explicit_int = 0; |
| opaque_typedef = 1; |
| type = copy_node (opaque_type_node); |
| } |
| else |
| { |
| if (funcdef_flag) |
| { |
| if (warn_return_type |
| && return_type == return_normal) |
| /* Save warning until we know what is really going on. */ |
| warn_about_return_type = 1; |
| } |
| else if (RIDBIT_SETP (RID_TYPEDEF, specbits)) |
| pedwarn ("ANSI C++ forbids typedef which does not specify a type"); |
| else if (innermost_code != CALL_EXPR || pedantic |
| || (warn_return_type && return_type == return_normal)) |
| { |
| if (innermost_code == CALL_EXPR) |
| cp_pedwarn ("return-type of `%D' defaults to `int'", dname); |
| else |
| cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type", |
| dname); |
| } |
| type = integer_type_node; |
| } |
| } |
| else if (return_type == return_dtor) |
| { |
| error ("return type specification for destructor invalid"); |
| type = void_type_node; |
| } |
| else if (return_type == return_ctor) |
| { |
| error ("return type specification for constructor invalid"); |
| type = build_pointer_type (ctor_return_type); |
| } |
| else if (return_type == return_conversion) |
| { |
| if (comptypes (type, ctor_return_type, 1) == 0) |
| cp_error ("operator `%T' declared to return `%T'", |
| ctor_return_type, type); |
| else |
| cp_pedwarn ("return type specified for `operator %T'", |
| ctor_return_type); |
| |
| type = ctor_return_type; |
| } |
| |
| ctype = NULL_TREE; |
| |
| /* Now process the modifiers that were specified |
| and check for invalid combinations. */ |
| |
| /* Long double is a special combination. */ |
| |
| if (RIDBIT_SETP (RID_LONG, specbits) |
| && TYPE_MAIN_VARIANT (type) == double_type_node) |
| { |
| RIDBIT_RESET (RID_LONG, specbits); |
| type = build_type_variant (long_double_type_node, TYPE_READONLY (type), |
| TYPE_VOLATILE (type)); |
| } |
| |
| /* Check all other uses of type modifiers. */ |
| |
| if (RIDBIT_SETP (RID_UNSIGNED, specbits) |
| || RIDBIT_SETP (RID_SIGNED, specbits) |
| || RIDBIT_SETP (RID_LONG, specbits) |
| || RIDBIT_SETP (RID_SHORT, specbits)) |
| { |
| int ok = 0; |
| |
| if (TREE_CODE (type) == REAL_TYPE) |
| error ("short, signed or unsigned invalid for `%s'", name); |
| else if (TREE_CODE (type) != INTEGER_TYPE) |
| error ("long, short, signed or unsigned invalid for `%s'", name); |
| else if (RIDBIT_SETP (RID_LONG, specbits) |
| && RIDBIT_SETP (RID_SHORT, specbits)) |
| error ("long and short specified together for `%s'", name); |
| else if ((RIDBIT_SETP (RID_LONG, specbits) |
| || RIDBIT_SETP (RID_SHORT, specbits)) |
| && explicit_char) |
| error ("long or short specified with char for `%s'", name); |
| else if ((RIDBIT_SETP (RID_LONG, specbits) |
| || RIDBIT_SETP (RID_SHORT, specbits)) |
| && TREE_CODE (type) == REAL_TYPE) |
| error ("long or short specified with floating type for `%s'", name); |
| else if (RIDBIT_SETP (RID_SIGNED, specbits) |
| && RIDBIT_SETP (RID_UNSIGNED, specbits)) |
| error ("signed and unsigned given together for `%s'", name); |
| else |
| { |
| ok = 1; |
| if (!explicit_int && !defaulted_int && !explicit_char && pedantic) |
| { |
| pedwarn ("long, short, signed or unsigned used invalidly for `%s'", |
| name); |
| if (flag_pedantic_errors) |
| ok = 0; |
| } |
| } |
| |
| /* Discard the type modifiers if they are invalid. */ |
| if (! ok) |
| { |
| RIDBIT_RESET (RID_UNSIGNED, specbits); |
| RIDBIT_RESET (RID_SIGNED, specbits); |
| RIDBIT_RESET (RID_LONG, specbits); |
| RIDBIT_RESET (RID_SHORT, specbits); |
| longlong = 0; |
| } |
| } |
| |
| if (RIDBIT_SETP (RID_COMPLEX, specbits) |
| && TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE) |
| { |
| error ("complex invalid for `%s'", name); |
| RIDBIT_RESET (RID_COMPLEX, specbits); |
| } |
| |
| /* Decide whether an integer type is signed or not. |
| Optionally treat bitfields as signed by default. */ |
| if (RIDBIT_SETP (RID_UNSIGNED, specbits) |
| || (bitfield && ! flag_signed_bitfields |
| && (explicit_int || defaulted_int || explicit_char |
| /* A typedef for plain `int' without `signed' |
| can be controlled just like plain `int'. */ |
| || ! (typedef_decl != NULL_TREE |
| && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) |
| && TREE_CODE (type) != ENUMERAL_TYPE |
| && RIDBIT_NOTSETP (RID_SIGNED, specbits))) |
| { |
| if (longlong) |
| type = long_long_unsigned_type_node; |
| else if (RIDBIT_SETP (RID_LONG, specbits)) |
| type = long_unsigned_type_node; |
| else if (RIDBIT_SETP (RID_SHORT, specbits)) |
| type = short_unsigned_type_node; |
| else if (type == char_type_node) |
| type = unsigned_char_type_node; |
| else if (typedef_decl) |
| type = unsigned_type (type); |
| else |
| type = unsigned_type_node; |
| } |
| else if (RIDBIT_SETP (RID_SIGNED, specbits) |
| && type == char_type_node) |
| type = signed_char_type_node; |
| else if (longlong) |
| type = long_long_integer_type_node; |
| else if (RIDBIT_SETP (RID_LONG, specbits)) |
| type = long_integer_type_node; |
| else if (RIDBIT_SETP (RID_SHORT, specbits)) |
| type = short_integer_type_node; |
| |
| if (RIDBIT_SETP (RID_COMPLEX, specbits)) |
| { |
| /* If we just have "complex", it is equivalent to |
| "complex double", but if any modifiers at all are specified it is |
| the complex form of TYPE. E.g, "complex short" is |
| "complex short int". */ |
| |
| if (defaulted_int && ! longlong |
| && ! (RIDBIT_SETP (RID_LONG, specbits) |
| || RIDBIT_SETP (RID_SHORT, specbits) |
| || RIDBIT_SETP (RID_SIGNED, specbits) |
| || RIDBIT_SETP (RID_UNSIGNED, specbits))) |
| type = complex_double_type_node; |
| else if (type == integer_type_node) |
| type = complex_integer_type_node; |
| else if (type == float_type_node) |
| type = complex_float_type_node; |
| else if (type == double_type_node) |
| type = complex_double_type_node; |
| else if (type == long_double_type_node) |
| type = complex_long_double_type_node; |
| else |
| type = build_complex_type (type); |
| } |
| |
| if (return_type == return_conversion |
| && (RIDBIT_SETP (RID_CONST, specbits) |
| || RIDBIT_SETP (RID_VOLATILE, specbits))) |
| cp_error ("`operator %T' cannot be cv-qualified", |
| ctor_return_type); |
| |
| /* Set CONSTP if this declaration is `const', whether by |
| explicit specification or via a typedef. |
| Likewise for VOLATILEP. */ |
| |
| constp = !! RIDBIT_SETP (RID_CONST, specbits) + TYPE_READONLY (type); |
| volatilep = !! RIDBIT_SETP (RID_VOLATILE, specbits) + TYPE_VOLATILE (type); |
| type = build_type_variant (type, 0, 0); |
| staticp = 0; |
| inlinep = !! RIDBIT_SETP (RID_INLINE, specbits); |
| virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits); |
| RIDBIT_RESET (RID_VIRTUAL, specbits); |
| explicitp = RIDBIT_SETP (RID_EXPLICIT, specbits) != 0; |
| RIDBIT_RESET (RID_EXPLICIT, specbits); |
| |
| if (RIDBIT_SETP (RID_STATIC, specbits)) |
| staticp = 1 + (decl_context == FIELD); |
| |
| if (virtualp && staticp == 2) |
| { |
| cp_error ("member `%D' cannot be declared both virtual and static", |
| dname); |
| staticp = 0; |
| } |
| friendp = RIDBIT_SETP (RID_FRIEND, specbits); |
| RIDBIT_RESET (RID_FRIEND, specbits); |
| |
| if (RIDBIT_SETP (RID_MUTABLE, specbits)) |
| { |
| if (decl_context == PARM) |
| { |
| error ("non-member `%s' cannot be declared `mutable'", name); |
| RIDBIT_RESET (RID_MUTABLE, specbits); |
| } |
| else if (friendp || decl_context == TYPENAME) |
| { |
| error ("non-object member `%s' cannot be declared `mutable'", name); |
| RIDBIT_RESET (RID_MUTABLE, specbits); |
| } |
| } |
| |
| /* Warn if two storage classes are given. Default to `auto'. */ |
| |
| if (RIDBIT_ANY_SET (specbits)) |
| { |
| if (RIDBIT_SETP (RID_STATIC, specbits)) nclasses++; |
| if (RIDBIT_SETP (RID_EXTERN, specbits)) nclasses++; |
| if (decl_context == PARM && nclasses > 0) |
| error ("storage class specifiers invalid in parameter declarations"); |
| if (RIDBIT_SETP (RID_TYPEDEF, specbits)) |
| { |
| if (decl_context == PARM) |
| error ("typedef declaration invalid in parameter declaration"); |
| nclasses++; |
| } |
| if (RIDBIT_SETP (RID_AUTO, specbits)) nclasses++; |
| if (RIDBIT_SETP (RID_REGISTER, specbits)) nclasses++; |
| } |
| |
| /* Give error if `virtual' is used outside of class declaration. */ |
| if (virtualp |
| && (current_class_name == NULL_TREE || decl_context != FIELD)) |
| { |
| error ("virtual outside class declaration"); |
| virtualp = 0; |
| } |
| if (current_class_name == NULL_TREE && RIDBIT_SETP (RID_MUTABLE, specbits)) |
| { |
| error ("only members can be declared mutable"); |
| RIDBIT_RESET (RID_MUTABLE, specbits); |
| } |
| |
| /* Static anonymous unions are dealt with here. */ |
| if (staticp && decl_context == TYPENAME |
| && TREE_CODE (declspecs) == TREE_LIST |
| && ANON_UNION_TYPE_P (TREE_VALUE (declspecs))) |
| decl_context = FIELD; |
| |
| /* Give error if `const,' `volatile,' `inline,' `friend,' or `virtual' |
| is used in a signature member function declaration. */ |
| if (decl_context == FIELD |
| && IS_SIGNATURE (current_class_type) |
| && RIDBIT_NOTSETP (RID_TYPEDEF, specbits)) |
| { |
| if (constp) |
| { |
| error ("`const' specified for signature member function `%s'", name); |
| constp = 0; |
| } |
| if (volatilep) |
| { |
| error ("`volatile' specified for signature member function `%s'", |
| name); |
| volatilep = 0; |
| } |
| if (inlinep) |
| { |
| error ("`inline' specified for signature member function `%s'", name); |
| /* Later, we'll make signature member functions inline. */ |
| inlinep = 0; |
| } |
| if (friendp) |
| { |
| error ("`friend' declaration in signature definition"); |
| friendp = 0; |
| } |
| if (virtualp) |
| { |
| error ("`virtual' specified for signature member function `%s'", |
| name); |
| /* Later, we'll make signature member functions virtual. */ |
| virtualp = 0; |
| } |
| } |
| |
| /* Warn about storage classes that are invalid for certain |
| kinds of declarations (parameters, typenames, etc.). */ |
| |
| if (nclasses > 1) |
| error ("multiple storage classes in declaration of `%s'", name); |
| else if (decl_context != NORMAL && nclasses > 0) |
| { |
| if ((decl_context == PARM || decl_context == CATCHPARM) |
| && (RIDBIT_SETP (RID_REGISTER, specbits) |
| || RIDBIT_SETP (RID_AUTO, specbits))) |
| ; |
| else if (RIDBIT_SETP (RID_TYPEDEF, specbits)) |
| ; |
| else if (decl_context == FIELD |
| && ! IS_SIGNATURE (current_class_type) |
| /* C++ allows static class elements */ |
| && RIDBIT_SETP (RID_STATIC, specbits)) |
| /* C++ also allows inlines and signed and unsigned elements, |
| but in those cases we don't come in here. */ |
| ; |
| else |
| { |
| if (decl_context == FIELD) |
| { |
| tree tmp = NULL_TREE; |
| register int op = 0; |
| |
| if (declarator) |
| { |
| /* Avoid trying to get an operand off an identifier node. */ |
| if (TREE_CODE (declarator) == IDENTIFIER_NODE) |
| tmp = declarator; |
| else |
| tmp = TREE_OPERAND (declarator, 0); |
| op = IDENTIFIER_OPNAME_P (tmp); |
| } |
| error ("storage class specified for %s `%s'", |
| IS_SIGNATURE (current_class_type) |
| ? (op |
| ? "signature member operator" |
| : "signature member function") |
| : (op ? "member operator" : "field"), |
| op ? operator_name_string (tmp) : name); |
| } |
| else |
| error (((decl_context == PARM || decl_context == CATCHPARM) |
| ? "storage class specified for parameter `%s'" |
| : "storage class specified for typename"), name); |
| RIDBIT_RESET (RID_REGISTER, specbits); |
| RIDBIT_RESET (RID_AUTO, specbits); |
| RIDBIT_RESET (RID_EXTERN, specbits); |
| |
| if (decl_context == FIELD && IS_SIGNATURE (current_class_type)) |
| { |
| RIDBIT_RESET (RID_STATIC, specbits); |
| staticp = 0; |
| } |
| } |
| } |
| else if (RIDBIT_SETP (RID_EXTERN, specbits) && initialized && !funcdef_flag) |
| { |
| if (toplevel_bindings_p ()) |
| { |
| /* It's common practice (and completely valid) to have a const |
| be initialized and declared extern. */ |
| if (! constp) |
| warning ("`%s' initialized and declared `extern'", name); |
| } |
| else |
| error ("`%s' has both `extern' and initializer", name); |
| } |
| else if (RIDBIT_SETP (RID_EXTERN, specbits) && funcdef_flag |
| && ! toplevel_bindings_p ()) |
| error ("nested function `%s' declared `extern'", name); |
| else if (toplevel_bindings_p ()) |
| { |
| if (RIDBIT_SETP (RID_AUTO, specbits)) |
| error ("top-level declaration of `%s' specifies `auto'", name); |
| } |
| |
| if (nclasses > 0 && friendp) |
| error ("storage class specifiers invalid in friend function declarations"); |
| |
| /* Now figure out the structure of the declarator proper. |
| Descend through it, creating more complex types, until we reach |
| the declared identifier (or NULL_TREE, in an absolute declarator). */ |
| |
| while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE |
| && TREE_CODE (declarator) != TEMPLATE_ID_EXPR) |
| { |
| /* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]), |
| an INDIRECT_REF (for *...), |
| a CALL_EXPR (for ...(...)), |
| an identifier (for the name being declared) |
| or a null pointer (for the place in an absolute declarator |
| where the name was omitted). |
| For the last two cases, we have just exited the loop. |
| |
| For C++ it could also be |
| a SCOPE_REF (for class :: ...). In this case, we have converted |
| sensible names to types, and those are the values we use to |
| qualify the member name. |
| an ADDR_EXPR (for &...), |
| a BIT_NOT_EXPR (for destructors) |
| |
| At this point, TYPE is the type of elements of an array, |
| or for a function to return, or for a pointer to point to. |
| After this sequence of ifs, TYPE is the type of the |
| array or function or pointer, and DECLARATOR has had its |
| outermost layer removed. */ |
| |
| if (type == error_mark_node) |
| { |
| if (TREE_CODE (declarator) == SCOPE_REF) |
| declarator = TREE_OPERAND (declarator, 1); |
| else |
| declarator = TREE_OPERAND (declarator, 0); |
| continue; |
| } |
| if (quals != NULL_TREE |
| && (declarator == NULL_TREE |
| || TREE_CODE (declarator) != SCOPE_REF)) |
| { |
| if (ctype == NULL_TREE && TREE_CODE (type) == METHOD_TYPE) |
| ctype = TYPE_METHOD_BASETYPE (type); |
| if (ctype != NULL_TREE) |
| { |
| tree dummy = build_decl (TYPE_DECL, NULL_TREE, type); |
| ctype = grok_method_quals (ctype, dummy, quals); |
| type = TREE_TYPE (dummy); |
| quals = NULL_TREE; |
| } |
| } |
| switch (TREE_CODE (declarator)) |
| { |
| case ARRAY_REF: |
| { |
| register tree itype = NULL_TREE; |
| register tree size = TREE_OPERAND (declarator, 1); |
| /* The index is a signed object `sizetype' bits wide. */ |
| tree index_type = signed_type (sizetype); |
| |
| declarator = TREE_OPERAND (declarator, 0); |
| |
| /* Check for some types that there cannot be arrays of. */ |
| |
| if (TREE_CODE (type) == VOID_TYPE) |
| { |
| cp_error ("declaration of `%D' as array of voids", dname); |
| type = error_mark_node; |
| } |
| |
| if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| cp_error ("declaration of `%D' as array of functions", dname); |
| type = error_mark_node; |
| } |
| |
| /* ARM $8.4.3: Since you can't have a pointer to a reference, |
| you can't have arrays of references. If we allowed them, |
| then we'd be saying x[i] is valid for an array x, but |
| then you'd have to ask: what does `*(x + i)' mean? */ |
| if (TREE_CODE (type) == REFERENCE_TYPE) |
| { |
| if (decl_context == TYPENAME) |
| cp_error ("cannot make arrays of references"); |
| else |
| cp_error ("declaration of `%D' as array of references", |
| dname); |
| type = error_mark_node; |
| } |
| |
| if (TREE_CODE (type) == OFFSET_TYPE) |
| { |
| cp_error ("declaration of `%D' as array of data members", |
| dname); |
| type = error_mark_node; |
| } |
| |
| if (TREE_CODE (type) == METHOD_TYPE) |
| { |
| cp_error ("declaration of `%D' as array of function members", |
| dname); |
| type = error_mark_node; |
| } |
| |
| if (size == error_mark_node) |
| type = error_mark_node; |
| |
| if (type == error_mark_node) |
| continue; |
| |
| if (size) |
| { |
| /* Must suspend_momentary here because the index |
| type may need to live until the end of the function. |
| For example, it is used in the declaration of a |
| variable which requires destructing at the end of |
| the function; then build_vec_delete will need this |
| value. */ |
| int yes = suspend_momentary (); |
| /* Might be a cast. */ |
| if (TREE_CODE (size) == NOP_EXPR |
| && TREE_TYPE (size) == TREE_TYPE (TREE_OPERAND (size, 0))) |
| size = TREE_OPERAND (size, 0); |
| |
| /* If this involves a template parameter, it'll be |
| constant, but we don't know what the value is yet. */ |
| if (processing_template_decl) |
| { |
| itype = make_node (INTEGER_TYPE); |
| TYPE_MIN_VALUE (itype) = size_zero_node; |
| TYPE_MAX_VALUE (itype) = build_min |
| (MINUS_EXPR, sizetype, size, integer_one_node); |
| goto dont_grok_size; |
| } |
| |
| if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE |
| && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE) |
| { |
| cp_error ("size of array `%D' has non-integer type", |
| dname); |
| size = integer_one_node; |
| } |
| if (TREE_READONLY_DECL_P (size)) |
| size = decl_constant_value (size); |
| if (pedantic && integer_zerop (size)) |
| cp_pedwarn ("ANSI C++ forbids zero-size array `%D'", dname); |
| if (TREE_CONSTANT (size)) |
| { |
| int old_flag_pedantic_errors = flag_pedantic_errors; |
| int old_pedantic = pedantic; |
| pedantic = flag_pedantic_errors = 1; |
| /* Always give overflow errors on array subscripts. */ |
| constant_expression_warning (size); |
| pedantic = old_pedantic; |
| flag_pedantic_errors = old_flag_pedantic_errors; |
| if (INT_CST_LT (size, integer_zero_node)) |
| { |
| cp_error ("size of array `%D' is negative", dname); |
| size = integer_one_node; |
| } |
| } |
| else |
| { |
| if (pedantic) |
| { |
| if (dname) |
| cp_pedwarn ("ANSI C++ forbids variable-size array `%D'", |
| dname); |
| else |
| cp_pedwarn ("ANSI C++ forbids variable-size array"); |
| } |
| } |
| |
| itype |
| = fold (build_binary_op (MINUS_EXPR, |
| cp_convert (index_type, size), |
| cp_convert (index_type, |
| integer_one_node), 1)); |
| if (! TREE_CONSTANT (itype)) |
| itype = variable_size (itype); |
| else if (TREE_OVERFLOW (itype)) |
| { |
| error ("overflow in array dimension"); |
| TREE_OVERFLOW (itype) = 0; |
| } |
| |
| /* If we're a parm, we need to have a permanent type so |
| mangling checks for re-use will work right. If both the |
| element and index types are permanent, the array type |
| will be, too. */ |
| if (decl_context == PARM |
| && allocation_temporary_p () && TREE_PERMANENT (type)) |
| { |
| push_obstacks (&permanent_obstack, &permanent_obstack); |
| itype = build_index_type (itype); |
| pop_obstacks (); |
| } |
| else |
| itype = build_index_type (itype); |
| |
| dont_grok_size: |
| resume_momentary (yes); |
| } |
| |
| /* Build the array type itself, then merge any constancy or |
| volatility into the target type. We must do it in this order |
| to ensure that the TYPE_MAIN_VARIANT field of the array type |
| is set correctly. */ |
| |
| type = build_cplus_array_type (type, itype); |
| if (constp || volatilep) |
| type = cp_build_type_variant (type, constp, volatilep); |
| |
| ctype = NULL_TREE; |
| } |
| break; |
| |
| case CALL_EXPR: |
| { |
| tree arg_types; |
| int funcdecl_p; |
| tree inner_parms = TREE_OPERAND (declarator, 1); |
| tree inner_decl = TREE_OPERAND (declarator, 0); |
| |
| /* Declaring a function type. |
| Make sure we have a valid type for the function to return. */ |
| #if 0 |
| /* Is this an error? Should they be merged into TYPE here? */ |
| if (pedantic && (constp || volatilep)) |
| pedwarn ("function declared to return const or volatile result"); |
| #else |
| /* Merge any constancy or volatility into the function return |
| type. */ |
| |
| if (constp || volatilep) |
| { |
| type = cp_build_type_variant (type, constp, volatilep); |
| if (IS_AGGR_TYPE (type)) |
| build_pointer_type (type); |
| constp = 0; |
| volatilep = 0; |
| } |
| #endif |
| |
| /* Warn about some types functions can't return. */ |
| |
| if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| error ("`%s' declared as function returning a function", name); |
| type = integer_type_node; |
| } |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| error ("`%s' declared as function returning an array", name); |
| type = integer_type_node; |
| } |
| |
| if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF) |
| inner_decl = TREE_OPERAND (inner_decl, 1); |
| |
| if (inner_decl && TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR) |
| inner_decl = dname; |
| |
| /* Pick up type qualifiers which should be applied to `this'. */ |
| quals = TREE_OPERAND (declarator, 2); |
| |
| /* Pick up the exception specifications. */ |
| raises = TREE_TYPE (declarator); |
| |
| /* Say it's a definition only for the CALL_EXPR |
| closest to the identifier. */ |
| funcdecl_p |
| = inner_decl |
| && (TREE_CODE (inner_decl) == IDENTIFIER_NODE |
| || TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR |
| || TREE_CODE (inner_decl) == BIT_NOT_EXPR); |
| |
| if (ctype == NULL_TREE |
| && decl_context == FIELD |
| && funcdecl_p |
| && (friendp == 0 || dname == current_class_name)) |
| ctype = current_class_type; |
| |
| if (ctype && return_type == return_conversion) |
| TYPE_HAS_CONVERSION (ctype) = 1; |
| if (ctype && constructor_name (ctype) == dname) |
| { |
| /* We are within a class's scope. If our declarator name |
| is the same as the class name, and we are defining |
| a function, then it is a constructor/destructor, and |
| therefore returns a void type. */ |
| |
| if (flags == DTOR_FLAG) |
| { |
| /* ANSI C++ June 5 1992 WP 12.4.1. A destructor may |
| not be declared const or volatile. A destructor |
| may not be static. */ |
| if (staticp == 2) |
| error ("destructor cannot be static member function"); |
| if (quals) |
| { |
| cp_error ("destructors may not be `%s'", |
| IDENTIFIER_POINTER (TREE_VALUE (quals))); |
| quals = NULL_TREE; |
| } |
| if (decl_context == FIELD) |
| { |
| if (! member_function_or_else (ctype, current_class_type, |
| "destructor for alien class `%s' cannot be a member")) |
| return void_type_node; |
| } |
| } |
| else /* It's a constructor. */ |
| { |
| if (explicitp == 1) |
| explicitp = 2; |
| /* ANSI C++ June 5 1992 WP 12.1.2. A constructor may |
| not be declared const or volatile. A constructor may |
| not be virtual. A constructor may not be static. */ |
| if (staticp == 2) |
| error ("constructor cannot be static member function"); |
| if (virtualp) |
| { |
| pedwarn ("constructors cannot be declared virtual"); |
| virtualp = 0; |
| } |
| if (quals) |
| { |
| cp_error ("constructors may not be `%s'", |
| IDENTIFIER_POINTER (TREE_VALUE (quals))); |
| quals = NULL_TREE; |
| } |
| { |
| RID_BIT_TYPE tmp_bits; |
| bcopy ((void*)&specbits, (void*)&tmp_bits, sizeof (RID_BIT_TYPE)); |
| RIDBIT_RESET (RID_INLINE, tmp_bits); |
| RIDBIT_RESET (RID_STATIC, tmp_bits); |
| if (RIDBIT_ANY_SET (tmp_bits)) |
| error ("return value type specifier for constructor ignored"); |
| } |
| type = build_pointer_type (ctype); |
| if (decl_context == FIELD |
| && IS_SIGNATURE (current_class_type)) |
| { |
| error ("constructor not allowed in signature"); |
| return void_type_node; |
| } |
| else if (decl_context == FIELD) |
| { |
| if (! member_function_or_else (ctype, current_class_type, |
| "constructor for alien class `%s' cannot be member")) |
| return void_type_node; |
| TYPE_HAS_CONSTRUCTOR (ctype) = 1; |
| if (return_type != return_ctor) |
| return NULL_TREE; |
| } |
| } |
| if (decl_context == FIELD) |
| staticp = 0; |
| } |
| else if (friendp) |
| { |
| if (initialized) |
| error ("can't initialize friend function `%s'", name); |
| if (virtualp) |
| { |
| /* Cannot be both friend and virtual. */ |
| error ("virtual functions cannot be friends"); |
| RIDBIT_RESET (RID_FRIEND, specbits); |
| friendp = 0; |
| } |
| if (decl_context == NORMAL) |
| error ("friend declaration not in class definition"); |
| if (current_function_decl && funcdef_flag) |
| cp_error ("can't define friend function `%s' in a local class definition", |
| name); |
| } |
| |
| /* Construct the function type and go to the next |
| inner layer of declarator. */ |
| |
| declarator = TREE_OPERAND (declarator, 0); |
| |
| /* FIXME: This is where default args should be fully |
| processed. */ |
| |
| arg_types = grokparms (inner_parms, funcdecl_p ? funcdef_flag : 0); |
| |
| if (declarator && flags == DTOR_FLAG) |
| { |
| /* A destructor declared in the body of a class will |
| be represented as a BIT_NOT_EXPR. But, we just |
| want the underlying IDENTIFIER. */ |
| if (TREE_CODE (declarator) == BIT_NOT_EXPR) |
| declarator = TREE_OPERAND (declarator, 0); |
| |
| if (strict_prototype == 0 && arg_types == NULL_TREE) |
| arg_types = void_list_node; |
| else if (arg_types == NULL_TREE |
| || arg_types != void_list_node) |
| { |
| cp_error ("destructors may not have parameters"); |
| arg_types = void_list_node; |
| last_function_parms = NULL_TREE; |
| } |
| } |
| |
| /* ANSI says that `const int foo ();' |
| does not make the function foo const. */ |
| type = build_function_type (type, arg_types); |
| |
| { |
| tree t; |
| for (t = arg_types; t; t = TREE_CHAIN (t)) |
| if (TREE_PURPOSE (t) |
| && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG) |
| { |
| add_defarg_fn (type); |
| break; |
| } |
| } |
| } |
| break; |
| |
| case ADDR_EXPR: |
| case INDIRECT_REF: |
| /* Filter out pointers-to-references and references-to-references. |
| We can get these if a TYPE_DECL is used. */ |
| |
| if (TREE_CODE (type) == REFERENCE_TYPE) |
| { |
| error ("cannot declare %s to references", |
| TREE_CODE (declarator) == ADDR_EXPR |
| ? "references" : "pointers"); |
| declarator = TREE_OPERAND (declarator, 0); |
| continue; |
| } |
| |
| if (TREE_CODE (type) == OFFSET_TYPE |
| && (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE |
| || TREE_CODE (TREE_TYPE (type)) == REFERENCE_TYPE)) |
| { |
| cp_error ("cannot declare pointer to `%#T' member", |
| TREE_TYPE (type)); |
| type = TREE_TYPE (type); |
| } |
| |
| /* Merge any constancy or volatility into the target type |
| for the pointer. */ |
| |
| if (constp || volatilep) |
| { |
| /* A const or volatile signature pointer/reference is |
| pointing to a const or volatile object, i.e., the |
| `optr' is const or volatile, respectively, not the |
| signature pointer/reference itself. */ |
| if (! IS_SIGNATURE (type)) |
| { |
| type = cp_build_type_variant (type, constp, volatilep); |
| if (IS_AGGR_TYPE (type)) |
| build_pointer_type (type); |
| constp = 0; |
| volatilep = 0; |
| } |
| } |
| |
| if (IS_SIGNATURE (type)) |
| { |
| if (TREE_CODE (declarator) == ADDR_EXPR) |
| { |
| if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE |
| && TYPE_SIZE (type)) |
| cp_warning ("empty signature `%T' used in signature reference declaration", |
| type); |
| #if 0 |
| type = build_signature_reference_type (type, |
| constp, volatilep); |
| #else |
| sorry ("signature reference"); |
| return NULL_TREE; |
| #endif |
| } |
| else |
| { |
| if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE |
| && TYPE_SIZE (type)) |
| cp_warning ("empty signature `%T' used in signature pointer declaration", |
| type); |
| type = build_signature_pointer_type (type, |
| constp, volatilep); |
| } |
| constp = 0; |
| volatilep = 0; |
| } |
| else if (TREE_CODE (declarator) == ADDR_EXPR) |
| { |
| if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| error ("cannot declare references to functions; use pointer to function instead"); |
| type = build_pointer_type (type); |
| } |
| else |
| { |
| if (TREE_CODE (type) == VOID_TYPE) |
| error ("invalid type: `void &'"); |
| else |
| type = build_reference_type (type); |
| } |
| } |
| else if (TREE_CODE (type) == METHOD_TYPE) |
| { |
| type = build_ptrmemfunc_type (build_pointer_type (type)); |
| } |
| else |
| type = build_pointer_type (type); |
| |
| /* Process a list of type modifier keywords (such as |
| const or volatile) that were given inside the `*' or `&'. */ |
| |
| if (TREE_TYPE (declarator)) |
| { |
| register tree typemodlist; |
| int erred = 0; |
| for (typemodlist = TREE_TYPE (declarator); typemodlist; |
| typemodlist = TREE_CHAIN (typemodlist)) |
| { |
| if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_CONST]) |
| constp++; |
| else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_VOLATILE]) |
| volatilep++; |
| else if (!erred) |
| { |
| erred = 1; |
| error ("invalid type modifier within %s declarator", |
| TREE_CODE (declarator) == ADDR_EXPR |
| ? "reference" : "pointer"); |
| } |
| } |
| if (constp > 1) |
| pedwarn ("duplicate `const'"); |
| if (volatilep > 1) |
| pedwarn ("duplicate `volatile'"); |
| if (TREE_CODE (declarator) == ADDR_EXPR |
| && (constp || volatilep)) |
| { |
| if (constp) |
| pedwarn ("discarding `const' applied to a reference"); |
| if (volatilep) |
| pedwarn ("discarding `volatile' applied to a reference"); |
| constp = volatilep = 0; |
| } |
| } |
| declarator = TREE_OPERAND (declarator, 0); |
| ctype = NULL_TREE; |
| break; |
| |
| case SCOPE_REF: |
| { |
| /* We have converted type names to NULL_TREE if the |
| name was bogus, or to a _TYPE node, if not. |
| |
| The variable CTYPE holds the type we will ultimately |
| resolve to. The code here just needs to build |
| up appropriate member types. */ |
| tree sname = TREE_OPERAND (declarator, 1); |
| tree t; |
| |
| /* Destructors can have their visibilities changed as well. */ |
| if (TREE_CODE (sname) == BIT_NOT_EXPR) |
| sname = TREE_OPERAND (sname, 0); |
| |
| if (TREE_COMPLEXITY (declarator) == 0) |
| /* This needs to be here, in case we are called |
| multiple times. */ ; |
| else if (TREE_COMPLEXITY (declarator) == -1) |
| /* Namespace member. */ |
| pop_decl_namespace (); |
| else if (friendp && (TREE_COMPLEXITY (declarator) < 2)) |
| /* Don't fall out into global scope. Hides real bug? --eichin */ ; |
| else if (! IS_AGGR_TYPE_CODE |
| (TREE_CODE (TREE_OPERAND (declarator, 0)))) |
| ; |
| else if (TREE_COMPLEXITY (declarator) == current_class_depth) |
| { |
| /* Resolve any TYPENAME_TYPEs from the decl-specifier-seq |
| that refer to ctype. They couldn't be resolved earlier |
| because we hadn't pushed into the class yet. |
| Example: resolve 'B<T>::type' in |
| 'B<typename B<T>::type> B<T>::f () { }'. */ |
| if (current_template_parms |
| && uses_template_parms (type) |
| && uses_template_parms (current_class_type)) |
| { |
| tree args = current_template_args (); |
| type = tsubst (type, args, NULL_TREE); |
| } |
| |
| /* This pop_nested_class corresponds to the |
| push_nested_class used to push into class scope for |
| parsing the argument list of a function decl, in |
| qualified_id. */ |
| pop_nested_class (1); |
| TREE_COMPLEXITY (declarator) = current_class_depth; |
| } |
| else |
| my_friendly_abort (16); |
| |
| if (TREE_OPERAND (declarator, 0) == NULL_TREE) |
| { |
| /* We had a reference to a global decl, or |
| perhaps we were given a non-aggregate typedef, |
| in which case we cleared this out, and should just |
| keep going as though it wasn't there. */ |
| declarator = sname; |
| continue; |
| } |
| ctype = TREE_OPERAND (declarator, 0); |
| |
| t = ctype; |
| while (t != NULL_TREE) |
| { |
| if (CLASSTYPE_TEMPLATE_INFO (t) && |
| !CLASSTYPE_TEMPLATE_SPECIALIZATION (t)) |
| template_count += 1; |
| t = TYPE_MAIN_DECL (t); |
| if (DECL_LANG_SPECIFIC (t)) |
| t = DECL_CLASS_CONTEXT (t); |
| else |
| t = NULL_TREE; |
| } |
| |
| if (sname == NULL_TREE) |
| goto done_scoping; |
| |
| if (TREE_CODE (sname) == IDENTIFIER_NODE) |
| { |
| /* This is the `standard' use of the scoping operator: |
| basetype :: member . */ |
| |
| if (ctype == current_class_type) |
| { |
| /* class A { |
| void A::f (); |
| }; |
| |
| Is this ill-formed? */ |
| |
| if (pedantic) |
| cp_pedwarn ("extra qualification `%T::' on member `%s' ignored", |
| ctype, name); |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| if (current_class_type == NULL_TREE |
| || friendp) |
| type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), |
| TREE_TYPE (type), TYPE_ARG_TYPES (type)); |
| else |
| { |
| cp_error ("cannot declare member function `%T::%s' within `%T'", |
| ctype, name, current_class_type); |
| return void_type_node; |
| } |
| } |
| else if (RIDBIT_SETP (RID_TYPEDEF, specbits) |
| || TYPE_SIZE (complete_type (ctype)) != NULL_TREE) |
| { |
| /* Have to move this code elsewhere in this function. |
| this code is used for i.e., typedef int A::M; M *pm; |
| |
| It is? How? jason 10/2/94 */ |
| |
| if (current_class_type) |
| { |
| cp_error ("cannot declare member `%T::%s' within `%T'", |
| ctype, name, current_class_type); |
| return void_type_node; |
| } |
| type = build_offset_type (ctype, type); |
| } |
| else if (uses_template_parms (ctype)) |
| { |
| if (TREE_CODE (type) == FUNCTION_TYPE) |
| type |
| = build_cplus_method_type (build_type_variant (ctype, |
| constp, |
| volatilep), |
| TREE_TYPE (type), |
| TYPE_ARG_TYPES (type)); |
| } |
| else |
| { |
| cp_error ("structure `%T' not yet defined", ctype); |
| return error_mark_node; |
| } |
| |
| declarator = sname; |
| } |
| else if (TREE_CODE (sname) == SCOPE_REF) |
| my_friendly_abort (17); |
| else |
| { |
| done_scoping: |
| declarator = TREE_OPERAND (declarator, 1); |
| if (declarator && TREE_CODE (declarator) == CALL_EXPR) |
| /* In this case, we will deal with it later. */ |
| ; |
| else |
| { |
| if (TREE_CODE (type) == FUNCTION_TYPE) |
| type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), TREE_TYPE (type), TYPE_ARG_TYPES (type)); |
| else |
| type = build_offset_type (ctype, type); |
| } |
| } |
| } |
| break; |
| |
| case BIT_NOT_EXPR: |
| declarator = TREE_OPERAND (declarator, 0); |
| break; |
| |
| case RECORD_TYPE: |
| case UNION_TYPE: |
| case ENUMERAL_TYPE: |
| declarator = NULL_TREE; |
| break; |
| |
| case ERROR_MARK: |
| declarator = NULL_TREE; |
| break; |
| |
| default: |
| my_friendly_abort (158); |
| } |
| } |
| |
| if (explicitp == 1) |
| { |
| error ("only constructors can be declared `explicit'"); |
| explicitp = 0; |
| } |
| |
| /* Now TYPE has the actual type. */ |
| |
| /* If this is declaring a typedef name, return a TYPE_DECL. */ |
| |
| if (RIDBIT_SETP (RID_MUTABLE, specbits)) |
| { |
| if (constp) |
| { |
| error ("const `%s' cannot be declared `mutable'", name); |
| RIDBIT_RESET (RID_MUTABLE, specbits); |
| } |
| else if (staticp) |
| { |
| error ("static `%s' cannot be declared `mutable'", name); |
| RIDBIT_RESET (RID_MUTABLE, specbits); |
| } |
| } |
| |
| if (RIDBIT_SETP (RID_TYPEDEF, specbits) && decl_context != TYPENAME) |
| { |
| tree decl; |
| |
| /* Note that the grammar rejects storage classes |
| in typenames, fields or parameters. */ |
| if (constp || volatilep) |
| type = cp_build_type_variant (type, constp, volatilep); |
| if (current_lang_name == lang_name_java) |
| TYPE_FOR_JAVA (type) = 1; |
| |
| if (decl_context == FIELD) |
| { |
| if (declarator == current_class_name) |
| cp_pedwarn ("ANSI C++ forbids nested type `%D' with same name as enclosing class", |
| declarator); |
| decl = build_lang_decl (TYPE_DECL, declarator, type); |
| if (IS_SIGNATURE (current_class_type) && opaque_typedef) |
| SIGNATURE_HAS_OPAQUE_TYPEDECLS (current_class_type) = 1; |
| } |
| else |
| { |
| /* Make sure this typedef lives as long as its type, |
| since it might be used as a template parameter. */ |
| if (type != error_mark_node) |
| push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type)); |
| decl = build_decl (TYPE_DECL, declarator, type); |
| if (type != error_mark_node) |
| pop_obstacks (); |
| } |
| |
| /* If the user declares "struct {...} foo" then `foo' will have |
| an anonymous name. Fill that name in now. Nothing can |
| refer to it, so nothing needs know about the name change. |
| The TYPE_NAME field was filled in by build_struct_xref. */ |
| if (type != error_mark_node |
| && !TYPE_READONLY (type) && !TYPE_VOLATILE (type) |
| && TYPE_NAME (type) |
| && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL |
| && ANON_AGGRNAME_P (TYPE_IDENTIFIER (type))) |
| { |
| /* Replace the anonymous name with the real name everywhere. */ |
| lookup_tag_reverse (type, declarator); |
| TYPE_NAME (type) = decl; |
| |
| if (TYPE_LANG_SPECIFIC (type)) |
| TYPE_WAS_ANONYMOUS (type) = 1; |
| |
| /* XXX Temporarily set the scope. |
| When returning, start_decl expects it as NULL_TREE, |
| and will then then set it using pushdecl. */ |
| my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 980404); |
| if (current_class_type) |
| DECL_CONTEXT (decl) = current_class_type; |
| else |
| DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); |
| |
| DECL_ASSEMBLER_NAME (decl) = DECL_NAME (decl); |
| DECL_ASSEMBLER_NAME (decl) |
| = get_identifier (build_overload_name (type, 1, 1)); |
| DECL_CONTEXT (decl) = NULL_TREE; |
| } |
| |
| if (TREE_CODE (type) == OFFSET_TYPE || TREE_CODE (type) == METHOD_TYPE) |
| { |
| cp_error_at ("typedef name may not be class-qualified", decl); |
| return NULL_TREE; |
| } |
| else if (quals) |
| { |
| if (ctype == NULL_TREE) |
| { |
| if (TREE_CODE (type) != METHOD_TYPE) |
| cp_error_at ("invalid type qualifier for non-method type", decl); |
| else |
| ctype = TYPE_METHOD_BASETYPE (type); |
| } |
| if (ctype != NULL_TREE) |
| grok_method_quals (ctype, decl, quals); |
| } |
| |
| if (RIDBIT_SETP (RID_SIGNED, specbits) |
| || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) |
| C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; |
| |
| if (RIDBIT_SETP (RID_MUTABLE, specbits)) |
| { |
| error ("non-object member `%s' cannot be declared mutable", name); |
| } |
| |
| bad_specifiers (decl, "type", virtualp, quals != NULL_TREE, |
| inlinep, friendp, raises != NULL_TREE); |
| |
| if (initialized) |
| error ("typedef declaration includes an initializer"); |
| |
| return decl; |
| } |
| |
| /* Detect the case of an array type of unspecified size |
| which came, as such, direct from a typedef name. |
| We must copy the type, so that each identifier gets |
| a distinct type, so that each identifier's size can be |
| controlled separately by its own initializer. */ |
| |
| if (type == typedef_type && TREE_CODE (type) == ARRAY_TYPE |
| && TYPE_DOMAIN (type) == NULL_TREE) |
| { |
| type = build_cplus_array_type (TREE_TYPE (type), TYPE_DOMAIN (type)); |
| } |
| |
| /* If this is a type name (such as, in a cast or sizeof), |
| compute the type and return it now. */ |
| |
| if (decl_context == TYPENAME) |
| { |
| /* Note that the grammar rejects storage classes |
| in typenames, fields or parameters. */ |
| if (constp || volatilep) |
| { |
| if (IS_SIGNATURE (type)) |
| error ("`const' or `volatile' specified with signature type"); |
| else |
| type = cp_build_type_variant (type, constp, volatilep); |
| } |
| |
| /* Special case: "friend class foo" looks like a TYPENAME context. */ |
| if (friendp) |
| { |
| if (volatilep) |
| { |
| cp_error ("`volatile' specified for friend class declaration"); |
| volatilep = 0; |
| } |
| if (inlinep) |
| { |
| cp_error ("`inline' specified for friend class declaration"); |
| inlinep = 0; |
| } |
| |
| /* Only try to do this stuff if we didn't already give up. */ |
| if (type != integer_type_node) |
| { |
| /* A friendly class? */ |
| if (current_class_type) |
| make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type)); |
| else |
| error ("trying to make class `%s' a friend of global scope", |
| TYPE_NAME_STRING (type)); |
| type = void_type_node; |
| } |
| } |
| else if (quals) |
| { |
| tree dummy = build_decl (TYPE_DECL, declarator, type); |
| if (ctype == NULL_TREE) |
| { |
| my_friendly_assert (TREE_CODE (type) == METHOD_TYPE, 159); |
| ctype = TYPE_METHOD_BASETYPE (type); |
| } |
| grok_method_quals (ctype, dummy, quals); |
| type = TREE_TYPE (dummy); |
| } |
| |
| return type; |
| } |
| else if (declarator == NULL_TREE && decl_context != PARM |
| && decl_context != CATCHPARM |
| && TREE_CODE (type) != UNION_TYPE |
| && ! bitfield) |
| { |
| cp_error ("abstract declarator `%T' used as declaration", type); |
| declarator = make_anon_name (); |
| } |
| |
| /* `void' at top level (not within pointer) |
| is allowed only in typedefs or type names. |
| We don't complain about parms either, but that is because |
| a better error message can be made later. */ |
| |
| if (TREE_CODE (type) == VOID_TYPE && decl_context != PARM) |
| { |
| if (! declarator) |
| error ("unnamed variable or field declared void"); |
| else if (TREE_CODE (declarator) == IDENTIFIER_NODE) |
| { |
| if (IDENTIFIER_OPNAME_P (declarator)) |
| my_friendly_abort (356); |
| else |
| error ("variable or field `%s' declared void", name); |
| } |
| else |
| error ("variable or field declared void"); |
| type = integer_type_node; |
| } |
| |
| /* Now create the decl, which may be a VAR_DECL, a PARM_DECL |
| or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ |
| |
| { |
| register tree decl; |
| |
| if (decl_context == PARM) |
| { |
| if (ctype) |
| error ("cannot use `::' in parameter declaration"); |
| |
| /* A parameter declared as an array of T is really a pointer to T. |
| One declared as a function is really a pointer to a function. |
| One declared as a member is really a pointer to member. */ |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| /* Transfer const-ness of array into that of type pointed to. */ |
| type = build_pointer_type |
| (cp_build_type_variant (TREE_TYPE (type), constp, volatilep)); |
| volatilep = constp = 0; |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE) |
| type = build_pointer_type (type); |
| else if (TREE_CODE (type) == OFFSET_TYPE) |
| type = build_pointer_type (type); |
| else if (TREE_CODE (type) == VOID_TYPE && declarator) |
| { |
| error ("declaration of `%s' as void", name); |
| return NULL_TREE; |
| } |
| |
| decl = build_decl (PARM_DECL, declarator, complete_type (type)); |
| |
| bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE, |
| inlinep, friendp, raises != NULL_TREE); |
| if (current_class_type |
| && IS_SIGNATURE (current_class_type)) |
| { |
| if (inlinep) |
| error ("parameter of signature member function declared `inline'"); |
| if (RIDBIT_SETP (RID_AUTO, specbits)) |
| error ("parameter of signature member function declared `auto'"); |
| if (RIDBIT_SETP (RID_REGISTER, specbits)) |
| error ("parameter of signature member function declared `register'"); |
| } |
| |
| /* Compute the type actually passed in the parmlist, |
| for the case where there is no prototype. |
| (For example, shorts and chars are passed as ints.) |
| When there is a prototype, this is overridden later. */ |
| |
| DECL_ARG_TYPE (decl) = type_promotes_to (type); |
| } |
| else if (decl_context == FIELD) |
| { |
| if (type == error_mark_node) |
| { |
| /* Happens when declaring arrays of sizes which |
| are error_mark_node, for example. */ |
| decl = NULL_TREE; |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| int publicp = 0; |
| tree function_context; |
| |
| /* We catch the others as conflicts with the builtin |
| typedefs. */ |
| if (friendp && declarator == ridpointers[(int) RID_SIGNED]) |
| { |
| cp_error ("function `%D' cannot be declared friend", |
| declarator); |
| friendp = 0; |
| } |
| |
| if (friendp == 0) |
| { |
| if (ctype == NULL_TREE) |
| ctype = current_class_type; |
| |
| if (ctype == NULL_TREE) |
| { |
| cp_error ("can't make `%D' into a method -- not in a class", |
| declarator); |
| return void_type_node; |
| } |
| |
| /* ``A union may [ ... ] not [ have ] virtual functions.'' |
| ARM 9.5 */ |
| if (virtualp && TREE_CODE (ctype) == UNION_TYPE) |
| { |
| cp_error ("function `%D' declared virtual inside a union", |
| declarator); |
| return void_type_node; |
| } |
| |
| if (declarator == ansi_opname[(int) NEW_EXPR] |
| || declarator == ansi_opname[(int) VEC_NEW_EXPR] |
| || declarator == ansi_opname[(int) DELETE_EXPR] |
| || declarator == ansi_opname[(int) VEC_DELETE_EXPR]) |
| { |
| if (virtualp) |
| { |
| cp_error ("`%D' cannot be declared virtual, since it is always static", |
| declarator); |
| virtualp = 0; |
| } |
| } |
| else if (staticp < 2) |
| type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), |
| TREE_TYPE (type), TYPE_ARG_TYPES (type)); |
| } |
| |
| /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */ |
| function_context = (ctype != NULL_TREE) ? |
| hack_decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE; |
| publicp = (! friendp || ! staticp) |
| && function_context == NULL_TREE; |
| decl = grokfndecl (ctype, type, |
| TREE_CODE (declarator) != TEMPLATE_ID_EXPR |
| ? declarator : dname, |
| declarator, |
| virtualp, flags, quals, raises, attrlist, |
| friendp ? -1 : 0, friendp, publicp, inlinep, |
| funcdef_flag, template_count, in_namespace); |
| if (decl == NULL_TREE) |
| return NULL_TREE; |
| #if 0 |
| /* This clobbers the attrs stored in `decl' from `attrlist'. */ |
| /* The decl and setting of decl_machine_attr is also turned off. */ |
| decl = build_decl_attribute_variant (decl, decl_machine_attr); |
| #endif |
| |
| if (explicitp == 2) |
| DECL_NONCONVERTING_P (decl) = 1; |
| } |
| else if (TREE_CODE (type) == METHOD_TYPE) |
| { |
| /* We only get here for friend declarations of |
| members of other classes. */ |
| /* All method decls are public, so tell grokfndecl to set |
| TREE_PUBLIC, also. */ |
| decl = grokfndecl (ctype, type, declarator, declarator, |
| virtualp, flags, quals, raises, attrlist, |
| friendp ? -1 : 0, friendp, 1, 0, funcdef_flag, |
| template_count, in_namespace); |
| if (decl == NULL_TREE) |
| return NULL_TREE; |
| } |
| else if (!staticp && ! processing_template_decl |
| && TYPE_SIZE (complete_type (type)) == NULL_TREE |
| && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0)) |
| { |
| if (declarator) |
| cp_error ("field `%D' has incomplete type", declarator); |
| else |
| cp_error ("name `%T' has incomplete type", type); |
| |
| /* If we're instantiating a template, tell them which |
| instantiation made the field's type be incomplete. */ |
| if (current_class_type |
| && TYPE_NAME (current_class_type) |
| && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (current_class_type)) |
| && declspecs && TREE_VALUE (declspecs) |
| && TREE_TYPE (TREE_VALUE (declspecs)) == type) |
| cp_error (" in instantiation of template `%T'", |
| current_class_type); |
| |
| type = error_mark_node; |
| decl = NULL_TREE; |
| } |
| else |
| { |
| if (friendp) |
| { |
| error ("`%s' is neither function nor method; cannot be declared friend", |
| IDENTIFIER_POINTER (declarator)); |
| friendp = 0; |
| } |
| decl = NULL_TREE; |
| } |
| |
| if (friendp) |
| { |
| /* Friends are treated specially. */ |
| if (ctype == current_class_type) |
| warning ("member functions are implicitly friends of their class"); |
| else |
| { |
| tree t = NULL_TREE; |
| if (decl && DECL_NAME (decl)) |
| t = do_friend (ctype, declarator, decl, |
| last_function_parms, flags, quals, |
| funcdef_flag); |
| if (t && funcdef_flag) |
| return t; |
| |
| return void_type_node; |
| } |
| } |
| |
| /* Structure field. It may not be a function, except for C++ */ |
| |
| if (decl == NULL_TREE) |
| { |
| if (initialized) |
| { |
| if (!staticp) |
| { |
| /* An attempt is being made to initialize a non-static |
| member. But, from [class.mem]: |
| |
| 4 A member-declarator can contain a |
| constant-initializer only if it declares a static |
| member (_class.static_) of integral or enumeration |
| type, see _class.static.data_. |
| |
| This used to be relatively common practice, but |
| the rest of the compiler does not correctly |
| handle the initialization unless the member is |
| static so we make it static below. */ |
| cp_pedwarn ("ANSI C++ forbids initialization of %s `%D'", |
| constp ? "const member" : "member", |
| declarator); |
| cp_pedwarn ("making `%D' static", declarator); |
| staticp = 1; |
| } |
| |
| /* Motion 10 at San Diego: If a static const integral data |
| member is initialized with an integral constant |
| expression, the initializer may appear either in the |
| declaration (within the class), or in the definition, |
| but not both. If it appears in the class, the member is |
| a member constant. The file-scope definition is always |
| required. */ |
| if (! constp) |
| /* According to Mike Stump, we generate bad code for |
| this case, so we might as well always make it an |
| error. */ |
| cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'", |
| declarator); |
| |
| if (pedantic && ! INTEGRAL_TYPE_P (type) |
| && !uses_template_parms (type)) |
| cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", declarator, type); |
| } |
| |
| if (staticp) |
| { |
| /* ANSI C++ Apr '95 wp 9.2 */ |
| if (declarator == current_class_name) |
| cp_pedwarn ("ANSI C++ forbids static member `%D' with same name as enclosing class", |
| declarator); |
| |
| /* C++ allows static class members. |
| All other work for this is done by grokfield. |
| This VAR_DECL is built by build_lang_field_decl. |
| All other VAR_DECLs are built by build_decl. */ |
| decl = build_lang_field_decl (VAR_DECL, declarator, type); |
| TREE_STATIC (decl) = 1; |
| /* In class context, 'static' means public access. */ |
| TREE_PUBLIC (decl) = DECL_EXTERNAL (decl) = 1; |
| } |
| else |
| { |
| decl = build_lang_field_decl (FIELD_DECL, declarator, type); |
| if (RIDBIT_SETP (RID_MUTABLE, specbits)) |
| { |
| DECL_MUTABLE_P (decl) = 1; |
| RIDBIT_RESET (RID_MUTABLE, specbits); |
| } |
| } |
| |
| bad_specifiers (decl, "field", virtualp, quals != NULL_TREE, |
| inlinep, friendp, raises != NULL_TREE); |
| } |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) |
| { |
| tree original_name; |
| int publicp = 0; |
| |
| if (! declarator) |
| return NULL_TREE; |
| |
| if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) |
| original_name = dname; |
| else |
| original_name = declarator; |
| |
| if (RIDBIT_SETP (RID_AUTO, specbits)) |
| error ("storage class `auto' invalid for function `%s'", name); |
| else if (RIDBIT_SETP (RID_REGISTER, specbits)) |
| error ("storage class `register' invalid for function `%s'", name); |
| |
| /* Function declaration not at top level. |
| Storage classes other than `extern' are not allowed |
| and `extern' makes no difference. */ |
| if (! toplevel_bindings_p () |
| && (RIDBIT_SETP (RID_STATIC, specbits) |
| || RIDBIT_SETP (RID_INLINE, specbits)) |
| && pedantic) |
| { |
| if (RIDBIT_SETP (RID_STATIC, specbits)) |
| pedwarn ("storage class `static' invalid for function `%s' declared out of global scope", name); |
| else |
| pedwarn ("storage class `inline' invalid for function `%s' declared out of global scope", name); |
| } |
| |
| if (ctype == NULL_TREE) |
| { |
| if (virtualp) |
| { |
| error ("virtual non-class function `%s'", name); |
| virtualp = 0; |
| } |
| |
| if (current_lang_name == lang_name_cplusplus |
| && ! processing_template_decl |
| && ! MAIN_NAME_P (original_name) |
| && ! (IDENTIFIER_LENGTH (original_name) > 10 |
| && IDENTIFIER_POINTER (original_name)[0] == '_' |
| && IDENTIFIER_POINTER (original_name)[1] == '_' |
| && strncmp (IDENTIFIER_POINTER (original_name)+2, "builtin_", 8) == 0)) |
| /* Plain overloading: will not be grok'd by grokclassfn. */ |
| if (name_mangling_version < 1 |
| || TREE_CODE (declarator) != TEMPLATE_ID_EXPR) |
| declarator = build_decl_overload (dname, TYPE_ARG_TYPES (type), 0); |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2) |
| type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), |
| TREE_TYPE (type), TYPE_ARG_TYPES (type)); |
| |
| /* Record presence of `static'. */ |
| publicp = (ctype != NULL_TREE |
| || RIDBIT_SETP (RID_EXTERN, specbits) |
| || !RIDBIT_SETP (RID_STATIC, specbits)); |
| |
| decl = grokfndecl (ctype, type, original_name, declarator, |
| virtualp, flags, quals, raises, attrlist, |
| 1, friendp, |
| publicp, inlinep, funcdef_flag, |
| template_count, in_namespace); |
| if (decl == NULL_TREE) |
| return NULL_TREE; |
| |
| /* Among other times, could occur from check_explicit_specialization |
| returning an error_mark_node. */ |
| if (decl == error_mark_node) |
| return error_mark_node; |
| |
| if (ctype == NULL_TREE && DECL_LANGUAGE (decl) != lang_c |
| && (! DECL_USE_TEMPLATE (decl) || |
| name_mangling_version < 1)) |
| DECL_ASSEMBLER_NAME (decl) = declarator; |
| |
| if (staticp == 1) |
| { |
| int illegal_static = 0; |
| |
| /* Don't allow a static member function in a class, and forbid |
| declaring main to be static. */ |
| if (TREE_CODE (type) == METHOD_TYPE) |
| { |
| cp_pedwarn ("cannot declare member function `%D' to have static linkage", decl); |
| illegal_static = 1; |
| } |
| else if (current_function_decl) |
| { |
| /* FIXME need arm citation */ |
| error ("cannot declare static function inside another function"); |
| illegal_static = 1; |
| } |
| |
| if (illegal_static) |
| { |
| staticp = 0; |
| RIDBIT_RESET (RID_STATIC, specbits); |
| } |
| } |
| } |
| else |
| { |
| /* It's a variable. */ |
| |
| if (decl_context == CATCHPARM) |
| { |
| if (ctype) |
| { |
| ctype = NULL_TREE; |
| error ("cannot use `::' in parameter declaration"); |
| } |
| |
| /* A parameter declared as an array of T is really a pointer to T. |
| One declared as a function is really a pointer to a function. |
| One declared as a member is really a pointer to member. */ |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| /* Transfer const-ness of array into that of type |
| pointed to. */ |
| type = build_pointer_type |
| (cp_build_type_variant (TREE_TYPE (type), constp, volatilep)); |
| volatilep = constp = 0; |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE) |
| type = build_pointer_type (type); |
| else if (TREE_CODE (type) == OFFSET_TYPE) |
| type = build_pointer_type (type); |
| } |
| |
| /* An uninitialized decl with `extern' is a reference. */ |
| decl = grokvardecl (type, declarator, &specbits, |
| initialized, constp, in_namespace); |
| bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE, |
| inlinep, friendp, raises != NULL_TREE); |
| |
| if (ctype) |
| { |
| DECL_CONTEXT (decl) = ctype; |
| if (staticp == 1) |
| { |
| cp_pedwarn ("static member `%D' re-declared as static", decl); |
| staticp = 0; |
| RIDBIT_RESET (RID_STATIC, specbits); |
| } |
| if (RIDBIT_SETP (RID_REGISTER, specbits) && TREE_STATIC (decl)) |
| { |
| cp_error ("static member `%D' declared `register'", decl); |
| RIDBIT_RESET (RID_REGISTER, specbits); |
| } |
| if (RIDBIT_SETP (RID_EXTERN, specbits) && pedantic) |
| { |
| cp_pedwarn ("cannot explicitly declare member `%#D' to have extern linkage", |
| decl); |
| RIDBIT_RESET (RID_EXTERN, specbits); |
| } |
| } |
| } |
| |
| if (RIDBIT_SETP (RID_MUTABLE, specbits)) |
| { |
| error ("`%s' cannot be declared mutable", name); |
| } |
| |
| /* Record `register' declaration for warnings on & |
| and in case doing stupid register allocation. */ |
| |
| if (RIDBIT_SETP (RID_REGISTER, specbits)) |
| DECL_REGISTER (decl) = 1; |
| |
| if (RIDBIT_SETP (RID_EXTERN, specbits)) |
| DECL_THIS_EXTERN (decl) = 1; |
| |
| if (RIDBIT_SETP (RID_STATIC, specbits)) |
| DECL_THIS_STATIC (decl) = 1; |
| |
| /* Record constancy and volatility. */ |
| |
| if (constp) |
| TREE_READONLY (decl) = TREE_CODE (type) != REFERENCE_TYPE; |
| if (volatilep) |
| { |
| TREE_SIDE_EFFECTS (decl) = 1; |
| TREE_THIS_VOLATILE (decl) = 1; |
| } |
| |
| return decl; |
| } |
| } |
| |
| /* Tell if a parmlist/exprlist looks like an exprlist or a parmlist. |
| An empty exprlist is a parmlist. An exprlist which |
| contains only identifiers at the global level |
| is a parmlist. Otherwise, it is an exprlist. */ |
| |
| int |
| parmlist_is_exprlist (exprs) |
| tree exprs; |
| { |
| if (exprs == NULL_TREE || TREE_PARMLIST (exprs)) |
| return 0; |
| |
| if (toplevel_bindings_p ()) |
| { |
| /* At the global level, if these are all identifiers, |
| then it is a parmlist. */ |
| while (exprs) |
| { |
| if (TREE_CODE (TREE_VALUE (exprs)) != IDENTIFIER_NODE) |
| return 1; |
| exprs = TREE_CHAIN (exprs); |
| } |
| return 0; |
| } |
| return 1; |
| } |
| |
| /* Subroutine of `grokparms'. In a fcn definition, arg types must |
| be complete. |
| |
| C++: also subroutine of `start_function'. */ |
| |
| static void |
| require_complete_types_for_parms (parms) |
| tree parms; |
| { |
| if (processing_template_decl) |
| return; |
| |
| while (parms) |
| { |
| tree type = TREE_TYPE (parms); |
| if (TYPE_SIZE (complete_type (type)) == NULL_TREE) |
| { |
| if (DECL_NAME (parms)) |
| error ("parameter `%s' has incomplete type", |
| IDENTIFIER_POINTER (DECL_NAME (parms))); |
| else |
| error ("parameter has incomplete type"); |
| TREE_TYPE (parms) = error_mark_node; |
| } |
| #if 0 |
| /* If the arg types are incomplete in a declaration, |
| they must include undefined tags. |
| These tags can never be defined in the scope of the declaration, |
| so the types can never be completed, |
| and no call can be compiled successfully. */ |
| /* This is not the right behavior for C++, but not having |
| it is also probably wrong. */ |
| else |
| { |
| /* Now warn if is a pointer to an incomplete type. */ |
| while (TREE_CODE (type) == POINTER_TYPE |
| || TREE_CODE (type) == REFERENCE_TYPE) |
| type = TREE_TYPE (type); |
| type = TYPE_MAIN_VARIANT (type); |
| if (TYPE_SIZE (type) == NULL_TREE) |
| { |
| if (DECL_NAME (parm) != NULL_TREE) |
| warning ("parameter `%s' points to incomplete type", |
| IDENTIFIER_POINTER (DECL_NAME (parm))); |
| else |
| warning ("parameter points to incomplete type"); |
| } |
| } |
| #endif |
| parms = TREE_CHAIN (parms); |
| } |
| } |
| |
| /* Decode the list of parameter types for a function type. |
| Given the list of things declared inside the parens, |
| return a list of types. |
| |
| The list we receive can have three kinds of elements: |
| an IDENTIFIER_NODE for names given without types, |
| a TREE_LIST node for arguments given as typespecs or names with typespecs, |
| or void_type_node, to mark the end of an argument list |
| when additional arguments are not permitted (... was not used). |
| |
| FUNCDEF_FLAG is nonzero for a function definition, 0 for |
| a mere declaration. A nonempty identifier-list gets an error message |
| when FUNCDEF_FLAG is zero. |
| If FUNCDEF_FLAG is 1, then parameter types must be complete. |
| If FUNCDEF_FLAG is -1, then parameter types may be incomplete. |
| |
| If all elements of the input list contain types, |
| we return a list of the types. |
| If all elements contain no type (except perhaps a void_type_node |
| at the end), we return a null list. |
| If some have types and some do not, it is an error, and we |
| return a null list. |
| |
| Also set last_function_parms to either |
| a list of names (IDENTIFIER_NODEs) or a chain of PARM_DECLs. |
| A list of names is converted to a chain of PARM_DECLs |
| by store_parm_decls so that ultimately it is always a chain of decls. |
| |
| Note that in C++, parameters can take default values. These default |
| values are in the TREE_PURPOSE field of the TREE_LIST. It is |
| an error to specify default values which are followed by parameters |
| that have no default values, or an ELLIPSES. For simplicities sake, |
| only parameters which are specified with their types can take on |
| default values. */ |
| |
| static tree |
| grokparms (first_parm, funcdef_flag) |
| tree first_parm; |
| int funcdef_flag; |
| { |
| tree result = NULL_TREE; |
| tree decls = NULL_TREE; |
| |
| if (first_parm != NULL_TREE |
| && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE) |
| { |
| if (! funcdef_flag) |
| pedwarn ("parameter names (without types) in function declaration"); |
| last_function_parms = first_parm; |
| return NULL_TREE; |
| } |
| else if (first_parm != NULL_TREE |
| && TREE_CODE (TREE_VALUE (first_parm)) != TREE_LIST |
| && TREE_CODE (TREE_VALUE (first_parm)) != VOID_TYPE) |
| my_friendly_abort (145); |
| else |
| { |
| /* Types were specified. This is a list of declarators |
| each represented as a TREE_LIST node. */ |
| register tree parm, chain; |
| int any_init = 0, any_error = 0; |
| |
| if (first_parm != NULL_TREE) |
| { |
| tree last_result = NULL_TREE; |
| tree last_decl = NULL_TREE; |
| |
| for (parm = first_parm; parm != NULL_TREE; parm = chain) |
| { |
| tree type = NULL_TREE, list_node = parm; |
| register tree decl = TREE_VALUE (parm); |
| tree init = TREE_PURPOSE (parm); |
| |
| chain = TREE_CHAIN (parm); |
| /* @@ weak defense against parse errors. */ |
| if (TREE_CODE (decl) != VOID_TYPE |
| && TREE_CODE (decl) != TREE_LIST) |
| { |
| /* Give various messages as the need arises. */ |
| if (TREE_CODE (decl) == STRING_CST) |
| cp_error ("invalid string constant `%E'", decl); |
| else if (TREE_CODE (decl) == INTEGER_CST) |
| error ("invalid integer constant in parameter list, did you forget to give parameter name?"); |
| continue; |
| } |
| |
| if (TREE_CODE (decl) != VOID_TYPE) |
| { |
| decl = grokdeclarator (TREE_VALUE (decl), |
| TREE_PURPOSE (decl), |
| PARM, init != NULL_TREE, |
| NULL_TREE); |
| if (! decl) |
| continue; |
| type = TREE_TYPE (decl); |
| if (TREE_CODE (type) == VOID_TYPE) |
| decl = void_type_node; |
| else if (TREE_CODE (type) == METHOD_TYPE) |
| { |
| if (DECL_NAME (decl)) |
| /* Cannot use the decl here because |
| we don't have DECL_CONTEXT set up yet. */ |
| cp_error ("parameter `%D' invalidly declared method type", |
| DECL_NAME (decl)); |
| else |
| error ("parameter invalidly declared method type"); |
| type = build_pointer_type (type); |
| TREE_TYPE (decl) = type; |
| } |
| else if (TREE_CODE (type) == OFFSET_TYPE) |
| { |
| if (DECL_NAME (decl)) |
| cp_error ("parameter `%D' invalidly declared offset type", |
| DECL_NAME (decl)); |
| else |
| error ("parameter invalidly declared offset type"); |
| type = build_pointer_type (type); |
| TREE_TYPE (decl) = type; |
| } |
| else if (TREE_CODE (type) == RECORD_TYPE |
| && TYPE_LANG_SPECIFIC (type) |
| && CLASSTYPE_ABSTRACT_VIRTUALS (type)) |
| { |
| abstract_virtuals_error (decl, type); |
| any_error = 1; /* Seems like a good idea. */ |
| } |
| else if (TREE_CODE (type) == RECORD_TYPE |
| && TYPE_LANG_SPECIFIC (type) |
| && IS_SIGNATURE (type)) |
| { |
| signature_error (decl, type); |
| any_error = 1; /* Seems like a good idea. */ |
| } |
| } |
| |
| if (TREE_CODE (decl) == VOID_TYPE) |
| { |
| if (result == NULL_TREE) |
| { |
| result = void_list_node; |
| last_result = result; |
| } |
| else |
| { |
| TREE_CHAIN (last_result) = void_list_node; |
| last_result = void_list_node; |
| } |
| if (chain |
| && (chain != void_list_node || TREE_CHAIN (chain))) |
| error ("`void' in parameter list must be entire list"); |
| break; |
| } |
| |
| /* Since there is a prototype, args are passed in their own types. */ |
| DECL_ARG_TYPE (decl) = TREE_TYPE (decl); |
| #ifdef PROMOTE_PROTOTYPES |
| if ((TREE_CODE (type) == INTEGER_TYPE |
| || TREE_CODE (type) == ENUMERAL_TYPE) |
| && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) |
| DECL_ARG_TYPE (decl) = integer_type_node; |
| #endif |
| if (!any_error) |
| { |
| if (init) |
| { |
| any_init++; |
| if (TREE_CODE (init) == SAVE_EXPR) |
| PARM_DECL_EXPR (init) = 1; |
| else if (processing_template_decl) |
| ; |
| /* Unparsed default arg from in-class decl. */ |
| else if (TREE_CODE (init) == DEFAULT_ARG) |
| ; |
| else if (TREE_CODE (init) == VAR_DECL |
| || TREE_CODE (init) == PARM_DECL) |
| { |
| if (IDENTIFIER_LOCAL_VALUE (DECL_NAME (init))) |
| { |
| /* ``Local variables may not be used in default |
| argument expressions.'' dpANSI C++ 8.2.6 */ |
| /* If extern int i; within a function is not |
| considered a local variable, then this code is |
| wrong. */ |
| cp_error ("local variable `%D' may not be used as a default argument", init); |
| any_error = 1; |
| } |
| else if (TREE_READONLY_DECL_P (init)) |
| init = decl_constant_value (init); |
| } |
| else |
| init = require_instantiated_type (type, init, integer_zero_node); |
| if (! processing_template_decl |
| && init != error_mark_node |
| && TREE_CODE (init) != DEFAULT_ARG |
| && ! can_convert_arg (type, TREE_TYPE (init), init)) |
| cp_pedwarn ("invalid type `%T' for default argument to `%#D'", |
| TREE_TYPE (init), decl); |
| } |
| } |
| else |
| init = NULL_TREE; |
| |
| if (decls == NULL_TREE) |
| { |
| decls = decl; |
| last_decl = decls; |
| } |
| else |
| { |
| TREE_CHAIN (last_decl) = decl; |
| last_decl = decl; |
| } |
| if (! current_function_decl && TREE_PERMANENT (list_node)) |
| { |
| TREE_PURPOSE (list_node) = init; |
| TREE_VALUE (list_node) = type; |
| TREE_CHAIN (list_node) = NULL_TREE; |
| } |
| else |
| list_node = saveable_tree_cons (init, type, NULL_TREE); |
| if (result == NULL_TREE) |
| { |
| result = list_node; |
| last_result = result; |
| } |
| else |
| { |
| TREE_CHAIN (last_result) = list_node; |
| last_result = list_node; |
| } |
| } |
| if (last_result) |
| TREE_CHAIN (last_result) = NULL_TREE; |
| /* If there are no parameters, and the function does not end |
| with `...', then last_decl will be NULL_TREE. */ |
| if (last_decl != NULL_TREE) |
| TREE_CHAIN (last_decl) = NULL_TREE; |
| } |
| } |
| |
| last_function_parms = decls; |
| |
| /* In a fcn definition, arg types must be complete. */ |
| if (funcdef_flag > 0) |
| require_complete_types_for_parms (last_function_parms); |
| |
| return result; |
| } |
| |
| /* Called from the parser to update an element of TYPE_ARG_TYPES for some |
| FUNCTION_TYPE with the newly parsed version of its default argument, which |
| was previously digested as text. See snarf_defarg et al in lex.c. */ |
| |
| void |
| replace_defarg (arg, init) |
| tree arg, init; |
| { |
| if (! processing_template_decl |
| && ! can_convert_arg (TREE_VALUE (arg), TREE_TYPE (init), init)) |
| cp_pedwarn ("invalid type `%T' for default argument to `%T'", |
| TREE_TYPE (init), TREE_VALUE (arg)); |
| TREE_PURPOSE (arg) = init; |
| } |
| |
| int |
| copy_args_p (d) |
| tree d; |
| { |
| tree t = FUNCTION_ARG_CHAIN (d); |
| if (DECL_CONSTRUCTOR_P (d) |
| && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (d))) |
| t = TREE_CHAIN (t); |
| if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE |
| && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t))) |
| == DECL_CLASS_CONTEXT (d)) |
| && (TREE_CHAIN (t) == NULL_TREE |
| || TREE_CHAIN (t) == void_list_node |
| || TREE_PURPOSE (TREE_CHAIN (t)))) |
| return 1; |
| return 0; |
| } |
| |
| /* These memoizing functions keep track of special properties which |
| a class may have. `grok_ctor_properties' notices whether a class |
| has a constructor of the form X(X&), and also complains |
| if the class has a constructor of the form X(X). |
| `grok_op_properties' takes notice of the various forms of |
| operator= which are defined, as well as what sorts of type conversion |
| may apply. Both functions take a FUNCTION_DECL as an argument. */ |
| |
| int |
| grok_ctor_properties (ctype, decl) |
| tree ctype, decl; |
| { |
| tree parmtypes = FUNCTION_ARG_CHAIN (decl); |
| tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node; |
| |
| /* When a type has virtual baseclasses, a magical first int argument is |
| added to any ctor so we can tell if the class has been initialized |
| yet. This could screw things up in this function, so we deliberately |
| ignore the leading int if we're in that situation. */ |
| if (TYPE_USES_VIRTUAL_BASECLASSES (ctype)) |
| { |
| my_friendly_assert (parmtypes |
| && TREE_VALUE (parmtypes) == integer_type_node, |
| 980529); |
| parmtypes = TREE_CHAIN (parmtypes); |
| parmtype = TREE_VALUE (parmtypes); |
| } |
| |
| if (TREE_CODE (parmtype) == REFERENCE_TYPE |
| && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype |
| && (TREE_CHAIN (parmtypes) == NULL_TREE |
| || TREE_CHAIN (parmtypes) == void_list_node |
| || TREE_PURPOSE (TREE_CHAIN (parmtypes)))) |
| { |
| TYPE_HAS_INIT_REF (ctype) = 1; |
| if (TYPE_READONLY (TREE_TYPE (parmtype))) |
| TYPE_HAS_CONST_INIT_REF (ctype) = 1; |
| } |
| else if (TYPE_MAIN_VARIANT (parmtype) == ctype |
| && TREE_CHAIN (parmtypes) != NULL_TREE |
| && TREE_CHAIN (parmtypes) == void_list_node) |
| { |
| cp_error ("invalid constructor; you probably meant `%T (const %T&)'", |
| ctype, ctype); |
| SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype); |
| return 0; |
| } |
| else if (TREE_CODE (parmtype) == VOID_TYPE |
| || TREE_PURPOSE (parmtypes) != NULL_TREE) |
| TYPE_HAS_DEFAULT_CONSTRUCTOR (ctype) = 1; |
| |
| return 1; |
| } |
| |
| /* An operator with this name can be either unary or binary. */ |
| |
| static int |
| ambi_op_p (name) |
| tree name; |
| { |
| return (name == ansi_opname [(int) INDIRECT_REF] |
| || name == ansi_opname [(int) ADDR_EXPR] |
| || name == ansi_opname [(int) NEGATE_EXPR] |
| || name == ansi_opname[(int) POSTINCREMENT_EXPR] |
| || name == ansi_opname[(int) POSTDECREMENT_EXPR] |
| || name == ansi_opname [(int) CONVERT_EXPR]); |
| } |
| |
| /* An operator with this name can only be unary. */ |
| |
| static int |
| unary_op_p (name) |
| tree name; |
| { |
| return (name == ansi_opname [(int) TRUTH_NOT_EXPR] |
| || name == ansi_opname [(int) BIT_NOT_EXPR] |
| || name == ansi_opname [(int) COMPONENT_REF] |
| || OPERATOR_TYPENAME_P (name)); |
| } |
| |
| /* Do a little sanity-checking on how they declared their operator. */ |
| |
| void |
| grok_op_properties (decl, virtualp, friendp) |
| tree decl; |
| int virtualp, friendp; |
| { |
| tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); |
| int methodp = (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE); |
| tree name = DECL_NAME (decl); |
| |
| if (current_class_type == NULL_TREE) |
| friendp = 1; |
| |
| if (! friendp) |
| { |
| if (name == ansi_opname[(int) MODIFY_EXPR]) |
| TYPE_HAS_ASSIGNMENT (current_class_type) = 1; |
| else if (name == ansi_opname[(int) CALL_EXPR]) |
| TYPE_OVERLOADS_CALL_EXPR (current_class_type) = 1; |
| else if (name == ansi_opname[(int) ARRAY_REF]) |
| TYPE_OVERLOADS_ARRAY_REF (current_class_type) = 1; |
| else if (name == ansi_opname[(int) COMPONENT_REF] |
| || name == ansi_opname[(int) MEMBER_REF]) |
| TYPE_OVERLOADS_ARROW (current_class_type) = 1; |
| else if (name == ansi_opname[(int) NEW_EXPR]) |
| TYPE_GETS_NEW (current_class_type) |= 1; |
| else if (name == ansi_opname[(int) DELETE_EXPR]) |
| TYPE_GETS_DELETE (current_class_type) |= 1; |
| else if (name == ansi_opname[(int) VEC_NEW_EXPR]) |
| TYPE_GETS_NEW (current_class_type) |= 2; |
| else if (name == ansi_opname[(int) VEC_DELETE_EXPR]) |
| TYPE_GETS_DELETE (current_class_type) |= 2; |
| } |
| |
| if (name == ansi_opname[(int) NEW_EXPR] |
| || name == ansi_opname[(int) VEC_NEW_EXPR]) |
| { |
| /* When the compiler encounters the definition of A::operator new, it |
| doesn't look at the class declaration to find out if it's static. */ |
| if (methodp) |
| revert_static_member_fn (&decl, NULL, NULL); |
| |
| /* Take care of function decl if we had syntax errors. */ |
| if (argtypes == NULL_TREE) |
| TREE_TYPE (decl) |
| = build_function_type (ptr_type_node, |
| hash_tree_chain (integer_type_node, |
| void_list_node)); |
| else |
| TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl)); |
| } |
| else if (name == ansi_opname[(int) DELETE_EXPR] |
| || name == ansi_opname[(int) VEC_DELETE_EXPR]) |
| { |
| if (methodp) |
| revert_static_member_fn (&decl, NULL, NULL); |
| |
| if (argtypes == NULL_TREE) |
| TREE_TYPE (decl) |
| = build_function_type (void_type_node, |
| hash_tree_chain (ptr_type_node, |
| void_list_node)); |
| else |
| { |
| TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl)); |
| |
| if (! friendp && name == ansi_opname[(int) VEC_DELETE_EXPR] |
| && (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl))) |
| != void_list_node)) |
| TYPE_VEC_DELETE_TAKES_SIZE (current_class_type) = 1; |
| } |
| } |
| else |
| { |
| /* An operator function must either be a non-static member function |
| or have at least one parameter of a class, a reference to a class, |
| an enumeration, or a reference to an enumeration. 13.4.0.6 */ |
| if (! methodp || DECL_STATIC_FUNCTION_P (decl)) |
| { |
| if (OPERATOR_TYPENAME_P (name) |
| || name == ansi_opname[(int) CALL_EXPR] |
| || name == ansi_opname[(int) MODIFY_EXPR] |
| || name == ansi_opname[(int) COMPONENT_REF] |
| || name == ansi_opname[(int) ARRAY_REF]) |
| cp_error ("`%D' must be a nonstatic member function", decl); |
| else |
| { |
| tree p = argtypes; |
| |
| if (DECL_STATIC_FUNCTION_P (decl)) |
| cp_error ("`%D' must be either a non-static member function or a non-member function", decl); |
| |
| if (p) |
| for (; TREE_CODE (TREE_VALUE (p)) != VOID_TYPE ; p = TREE_CHAIN (p)) |
| { |
| tree arg = TREE_VALUE (p); |
| if (TREE_CODE (arg) == REFERENCE_TYPE) |
| arg = TREE_TYPE (arg); |
| |
| /* This lets bad template code slip through. */ |
| if (IS_AGGR_TYPE (arg) |
| || TREE_CODE (arg) == ENUMERAL_TYPE |
| || TREE_CODE (arg) == TEMPLATE_TYPE_PARM |
| || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM) |
| goto foundaggr; |
| } |
| cp_error |
| ("`%D' must have an argument of class or enumerated type", |
| decl); |
| foundaggr: |
| ; |
| } |
| } |
| |
| if (name == ansi_opname[(int) CALL_EXPR]) |
| return; /* No restrictions on args. */ |
| |
| if (IDENTIFIER_TYPENAME_P (name) && ! DECL_TEMPLATE_INFO (decl)) |
| { |
| tree t = TREE_TYPE (name); |
| if (TREE_CODE (t) == VOID_TYPE) |
| pedwarn ("void is not a valid type conversion operator"); |
| else if (! friendp) |
| { |
| int ref = (TREE_CODE (t) == REFERENCE_TYPE); |
| char *what = 0; |
| if (ref) |
| t = TYPE_MAIN_VARIANT (TREE_TYPE (t)); |
| |
| if (t == current_class_type) |
| what = "the same type"; |
| /* Don't force t to be complete here. */ |
| else if (IS_AGGR_TYPE (t) |
| && TYPE_SIZE (t) |
| && DERIVED_FROM_P (t, current_class_type)) |
| what = "a base class"; |
| |
| if (what) |
| warning ("conversion to %s%s will never use a type conversion operator", |
| ref ? "a reference to " : "", what); |
| } |
| } |
| |
| if (name == ansi_opname[(int) MODIFY_EXPR]) |
| { |
| tree parmtype; |
| |
| if (list_length (argtypes) != 3 && methodp) |
| { |
| cp_error ("`%D' must take exactly one argument", decl); |
| return; |
| } |
| parmtype = TREE_VALUE (TREE_CHAIN (argtypes)); |
| |
| if (copy_assignment_arg_p (parmtype, virtualp) |
| && ! friendp) |
| { |
| TYPE_HAS_ASSIGN_REF (current_class_type) = 1; |
| if (TREE_CODE (parmtype) != REFERENCE_TYPE |
| || TYPE_READONLY (TREE_TYPE (parmtype))) |
| TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1; |
| } |
| } |
| else if (name == ansi_opname[(int) COND_EXPR]) |
| { |
| /* 13.4.0.3 */ |
| pedwarn ("ANSI C++ prohibits overloading operator ?:"); |
| if (list_length (argtypes) != 4) |
| cp_error ("`%D' must take exactly three arguments", decl); |
| } |
| else if (ambi_op_p (name)) |
| { |
| if (list_length (argtypes) == 2) |
| /* prefix */; |
| else if (list_length (argtypes) == 3) |
| { |
| if ((name == ansi_opname[(int) POSTINCREMENT_EXPR] |
| || name == ansi_opname[(int) POSTDECREMENT_EXPR]) |
| && ! processing_template_decl |
| && TREE_VALUE (TREE_CHAIN (argtypes)) != integer_type_node) |
| { |
| if (methodp) |
| cp_error ("postfix `%D' must take `int' as its argument", |
| decl); |
| else |
| cp_error |
| ("postfix `%D' must take `int' as its second argument", |
| decl); |
| } |
| } |
| else |
| { |
| if (methodp) |
| cp_error ("`%D' must take either zero or one argument", decl); |
| else |
| cp_error ("`%D' must take either one or two arguments", decl); |
| } |
| |
| /* More Effective C++ rule 6. */ |
| if (warn_ecpp |
| && (name == ansi_opname[(int) POSTINCREMENT_EXPR] |
| || name == ansi_opname[(int) POSTDECREMENT_EXPR])) |
| { |
| tree arg = TREE_VALUE (argtypes); |
| tree ret = TREE_TYPE (TREE_TYPE (decl)); |
| if (methodp || TREE_CODE (arg) == REFERENCE_TYPE) |
| arg = TREE_TYPE (arg); |
| arg = TYPE_MAIN_VARIANT (arg); |
| if (list_length (argtypes) == 2) |
| { |
| if (TREE_CODE (ret) != REFERENCE_TYPE |
| || !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ret)), |
| arg, 1)) |
| cp_warning ("prefix `%D' should return `%T'", decl, |
| build_reference_type (arg)); |
| } |
| else |
| { |
| if (!comptypes (TYPE_MAIN_VARIANT (ret), arg, 1)) |
| cp_warning ("postfix `%D' should return `%T'", decl, arg); |
| } |
| } |
| } |
| else if (unary_op_p (name)) |
| { |
| if (list_length (argtypes) != 2) |
| { |
| if (methodp) |
| cp_error ("`%D' must take `void'", decl); |
| else |
| cp_error ("`%D' must take exactly one argument", decl); |
| } |
| } |
| else /* if (binary_op_p (name)) */ |
| { |
| if (list_length (argtypes) != 3) |
| { |
| if (methodp) |
| cp_error ("`%D' must take exactly one argument", decl); |
| else |
| cp_error ("`%D' must take exactly two arguments", decl); |
| } |
| |
| /* More Effective C++ rule 7. */ |
| if (warn_ecpp |
| && (name == ansi_opname [TRUTH_ANDIF_EXPR] |
| || name == ansi_opname [TRUTH_ORIF_EXPR] |
| || name == ansi_opname [COMPOUND_EXPR])) |
| cp_warning ("user-defined `%D' always evaluates both arguments", |
| decl); |
| } |
| |
| /* Effective C++ rule 23. */ |
| if (warn_ecpp |
| && list_length (argtypes) == 3 |
| && (name == ansi_opname [PLUS_EXPR] |
| || name == ansi_opname [MINUS_EXPR] |
| || name == ansi_opname [TRUNC_DIV_EXPR] |
| || name == ansi_opname [MULT_EXPR]) |
| && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE) |
| cp_warning ("`%D' should return by value", decl); |
| |
| /* 13.4.0.8 */ |
| if (argtypes) |
| for (; argtypes != void_list_node ; argtypes = TREE_CHAIN (argtypes)) |
| if (TREE_PURPOSE (argtypes)) |
| { |
| TREE_PURPOSE (argtypes) = NULL_TREE; |
| if (name == ansi_opname[(int) POSTINCREMENT_EXPR] |
| || name == ansi_opname[(int) POSTDECREMENT_EXPR]) |
| { |
| if (pedantic) |
| cp_pedwarn ("`%D' cannot have default arguments", decl); |
| } |
| else |
| cp_error ("`%D' cannot have default arguments", decl); |
| } |
| } |
| } |
| |
| /* Get the struct, enum or union (CODE says which) with tag NAME. |
| Define the tag as a forward-reference if it is not defined. |
| |
| C++: If a class derivation is given, process it here, and report |
| an error if multiple derivation declarations are not identical. |
| |
| If this is a definition, come in through xref_tag and only look in |
| the current frame for the name (since C++ allows new names in any |
| scope.) */ |
| |
| tree |
| xref_tag (code_type_node, name, binfo, globalize) |
| tree code_type_node; |
| tree name, binfo; |
| int globalize; |
| { |
| enum tag_types tag_code; |
| enum tree_code code; |
| int temp = 0; |
| register tree ref, t; |
| struct binding_level *b = inner_binding_level; |
| int got_type = 0; |
| tree attributes = NULL_TREE; |
| |
| /* If we are called from the parser, code_type_node will sometimes be a |
| TREE_LIST. This indicates that the user wrote |
| "class __attribute__ ((foo)) bar". Extract the attributes so we can |
| use them later. */ |
| if (TREE_CODE (code_type_node) == TREE_LIST) |
| { |
| attributes = TREE_PURPOSE (code_type_node); |
| code_type_node = TREE_VALUE (code_type_node); |
| } |
| |
| tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node); |
| switch (tag_code) |
| { |
| case record_type: |
| case class_type: |
| case signature_type: |
| code = RECORD_TYPE; |
| break; |
| case union_type: |
| code = UNION_TYPE; |
| break; |
| case enum_type: |
| code = ENUMERAL_TYPE; |
| break; |
| default: |
| my_friendly_abort (18); |
| } |
| |
| /* If a cross reference is requested, look up the type |
| already defined for this tag and return it. */ |
| if (TREE_CODE_CLASS (TREE_CODE (name)) == 't') |
| { |
| t = name; |
| name = TYPE_IDENTIFIER (t); |
| got_type = 1; |
| } |
| else |
| t = IDENTIFIER_TYPE_VALUE (name); |
| if (t && TREE_CODE (t) != code && TREE_CODE (t) != TEMPLATE_TYPE_PARM |
| && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM) |
| t = NULL_TREE; |
| |
| if (! globalize) |
| { |
| if (pedantic && t && (TREE_CODE (t) == TEMPLATE_TYPE_PARM |
| || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)) |
| { |
| cp_pedwarn ("redeclaration of template type-parameter `%T'", name); |
| cp_pedwarn_at (" previously declared here", t); |
| } |
| if (t && TYPE_CONTEXT (t) && got_type) |
| ref = t; |
| else |
| { |
| /* If we know we are defining this tag, only look it up in |
| this scope and don't try to find it as a type. */ |
| ref = lookup_tag (code, name, b, 1); |
| } |
| } |
| else |
| { |
| if (t) |
| ref = t; |
| else |
| ref = lookup_tag (code, name, b, 0); |
| |
| if (! ref) |
| { |
| /* Try finding it as a type declaration. If that wins, use it. */ |
| ref = lookup_name (name, 1); |
| |
| if (ref != NULL_TREE |
| && processing_template_decl |
| && DECL_CLASS_TEMPLATE_P (ref) |
| && template_class_depth (current_class_type) == 0) |
| /* Since GLOBALIZE is true, we're declaring a global |
| template, so we want this type. */ |
| ref = DECL_RESULT (ref); |
| |
| if (ref && TREE_CODE (ref) == TYPE_DECL |
| && TREE_CODE (TREE_TYPE (ref)) == code) |
| ref = TREE_TYPE (ref); |
| else |
| ref = NULL_TREE; |
| } |
| } |
| |
| push_obstacks_nochange (); |
| |
| if (! ref) |
| { |
| /* If no such tag is yet defined, create a forward-reference node |
| and record it as the "definition". |
| When a real declaration of this type is found, |
| the forward-reference will be altered into a real type. */ |
| |
| /* In C++, since these migrate into the global scope, we must |
| build them on the permanent obstack. */ |
| |
| temp = allocation_temporary_p (); |
| if (temp) |
| end_temporary_allocation (); |
| |
| if (code == ENUMERAL_TYPE) |
| { |
| cp_error ("use of enum `%#D' without previous declaration", name); |
| |
| ref = make_node (ENUMERAL_TYPE); |
| |
| /* Give the type a default layout like unsigned int |
| to avoid crashing if it does not get defined. */ |
| TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node); |
| TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node); |
| TREE_UNSIGNED (ref) = 1; |
| TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); |
| TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node); |
| TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); |
| |
| /* Enable us to recognize when a type is created in class context. |
| To do nested classes correctly, this should probably be cleared |
| out when we leave this classes scope. Currently this in only |
| done in `start_enum'. */ |
| |
| pushtag (name, ref, globalize); |
| } |
| else |
| { |
| struct binding_level *old_b = class_binding_level; |
| |
| ref = make_lang_type (code); |
| |
| if (tag_code == signature_type) |
| { |
| SET_SIGNATURE (ref); |
| /* Since a signature type will be turned into the type |
| of signature tables, it's not only an interface. */ |
| CLASSTYPE_INTERFACE_ONLY (ref) = 0; |
| SET_CLASSTYPE_INTERFACE_KNOWN (ref); |
| /* A signature doesn't have a vtable. */ |
| CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = 0; |
| } |
| |
| #ifdef NONNESTED_CLASSES |
| /* Class types don't nest the way enums do. */ |
| class_binding_level = (struct binding_level *)0; |
| #endif |
| pushtag (name, ref, globalize); |
| class_binding_level = old_b; |
| } |
| } |
| else |
| { |
| /* If it no longer looks like a nested type, make sure it's |
| in global scope. |
| If it is not an IDENTIFIER, this is not a declaration */ |
| if (b->namespace_p && !class_binding_level |
| && TREE_CODE (name) == IDENTIFIER_NODE) |
| { |
| if (IDENTIFIER_NAMESPACE_VALUE (name) == NULL_TREE) |
| SET_IDENTIFIER_NAMESPACE_VALUE (name, TYPE_NAME (ref)); |
| } |
| |
| if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref)) |
| redeclare_class_template (ref, current_template_parms); |
| } |
| |
| if (binfo) |
| xref_basetypes (code_type_node, name, ref, binfo); |
| |
| /* Until the type is defined, tentatively accept whatever |
| structure tag the user hands us. */ |
| if (TYPE_SIZE (ref) == NULL_TREE |
| && ref != current_class_type |
| /* Have to check this, in case we have contradictory tag info. */ |
| && IS_AGGR_TYPE_CODE (TREE_CODE (ref))) |
| { |
| if (tag_code == class_type) |
| CLASSTYPE_DECLARED_CLASS (ref) = 1; |
| else if (tag_code == record_type || tag_code == signature_type) |
| CLASSTYPE_DECLARED_CLASS (ref) = 0; |
| } |
| |
| pop_obstacks (); |
| |
| TREE_TYPE (ref) = attributes; |
| |
| return ref; |
| } |
| |
| tree |
| xref_tag_from_type (old, id, globalize) |
| tree old, id; |
| int globalize; |
| { |
| tree code_type_node; |
| |
| if (TREE_CODE (old) == RECORD_TYPE) |
| code_type_node = (CLASSTYPE_DECLARED_CLASS (old) |
| ? class_type_node : record_type_node); |
| else |
| code_type_node = union_type_node; |
| |
| if (id == NULL_TREE) |
| id = TYPE_IDENTIFIER (old); |
| |
| return xref_tag (code_type_node, id, NULL_TREE, globalize); |
| } |
| |
| void |
| xref_basetypes (code_type_node, name, ref, binfo) |
| tree code_type_node; |
| tree name, ref; |
| tree binfo; |
| { |
| /* In the declaration `A : X, Y, ... Z' we mark all the types |
| (A, X, Y, ..., Z) so we can check for duplicates. */ |
| tree binfos; |
| int i, len; |
| enum tag_types tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node); |
| |
| if (tag_code == union_type) |
| { |
| cp_error ("derived union `%T' invalid", ref); |
| return; |
| } |
| |
| len = list_length (binfo); |
| push_obstacks (TYPE_OBSTACK (ref), TYPE_OBSTACK (ref)); |
| |
| SET_CLASSTYPE_MARKED (ref); |
| BINFO_BASETYPES (TYPE_BINFO (ref)) = binfos = make_tree_vec (len); |
| |
| for (i = 0; binfo; binfo = TREE_CHAIN (binfo)) |
| { |
| /* The base of a derived struct is public by default. */ |
| int via_public |
| = (TREE_PURPOSE (binfo) == access_public_node |
| || TREE_PURPOSE (binfo) == access_public_virtual_node |
| || (tag_code != class_type |
| && (TREE_PURPOSE (binfo) == access_default_node |
| || TREE_PURPOSE (binfo) == access_default_virtual_node))); |
| int via_protected |
| = (TREE_PURPOSE (binfo) == access_protected_node |
| || TREE_PURPOSE (binfo) == access_protected_virtual_node); |
| int via_virtual |
| = (TREE_PURPOSE (binfo) == access_private_virtual_node |
| || TREE_PURPOSE (binfo) == access_protected_virtual_node |
| || TREE_PURPOSE (binfo) == access_public_virtual_node |
| || TREE_PURPOSE (binfo) == access_default_virtual_node); |
| tree basetype = TREE_VALUE (binfo); |
| tree base_binfo; |
| |
| if (basetype && TREE_CODE (basetype) == TYPE_DECL) |
| basetype = TREE_TYPE (basetype); |
| if (!basetype |
| || (TREE_CODE (basetype) != RECORD_TYPE |
| && TREE_CODE (basetype) != TYPENAME_TYPE |
| && TREE_CODE (basetype) != TEMPLATE_TYPE_PARM |
| && TREE_CODE (basetype) != TEMPLATE_TEMPLATE_PARM)) |
| { |
| cp_error ("base type `%T' fails to be a struct or class type", |
| TREE_VALUE (binfo)); |
| continue; |
| } |
| |
| GNU_xref_hier (name, basetype, via_public, via_virtual, 0); |
| |
| #if 1 |
| /* This code replaces similar code in layout_basetypes. |
| We put the complete_type first for implicit `typename'. */ |
| if (TYPE_SIZE (complete_type (basetype)) == NULL_TREE |
| && ! (current_template_parms && uses_template_parms (basetype))) |
| { |
| cp_error ("base class `%T' has incomplete type", basetype); |
| continue; |
| } |
| #endif |
| else |
| { |
| if (CLASSTYPE_MARKED (basetype)) |
| { |
| if (basetype == ref) |
| cp_error ("recursive type `%T' undefined", basetype); |
| else |
| cp_error ("duplicate base type `%T' invalid", basetype); |
| continue; |
| } |
| |
| if (TYPE_FOR_JAVA (basetype) |
| && current_lang_stack == current_lang_base) |
| TYPE_FOR_JAVA (ref) = 1; |
| |
| /* Note that the BINFO records which describe individual |
| inheritances are *not* shared in the lattice! They |
| cannot be shared because a given baseclass may be |
| inherited with different `accessibility' by different |
| derived classes. (Each BINFO record describing an |
| individual inheritance contains flags which say what |
| the `accessibility' of that particular inheritance is.) */ |
| |
| base_binfo = make_binfo (integer_zero_node, basetype, |
| TYPE_BINFO_VTABLE (basetype), |
| TYPE_BINFO_VIRTUALS (basetype), NULL_TREE); |
| |
| TREE_VEC_ELT (binfos, i) = base_binfo; |
| TREE_VIA_PUBLIC (base_binfo) = via_public; |
| TREE_VIA_PROTECTED (base_binfo) = via_protected; |
| TREE_VIA_VIRTUAL (base_binfo) = via_virtual; |
| BINFO_INHERITANCE_CHAIN (base_binfo) = TYPE_BINFO (ref); |
| |
| SET_CLASSTYPE_MARKED (basetype); |
| |
| /* We are free to modify these bits because they are meaningless |
| at top level, and BASETYPE is a top-level type. */ |
| if (via_virtual || TYPE_USES_VIRTUAL_BASECLASSES (basetype)) |
| { |
| TYPE_USES_VIRTUAL_BASECLASSES (ref) = 1; |
| TYPE_USES_COMPLEX_INHERITANCE (ref) = 1; |
| } |
| |
| TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype); |
| TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype); |
| CLASSTYPE_LOCAL_TYPEDECLS (ref) |= CLASSTYPE_LOCAL_TYPEDECLS (basetype); |
| i += 1; |
| } |
| } |
| if (i) |
| TREE_VEC_LENGTH (binfos) = i; |
| else |
| BINFO_BASETYPES (TYPE_BINFO (ref)) = NULL_TREE; |
| |
| if (i > 1) |
| TYPE_USES_MULTIPLE_INHERITANCE (ref) = 1; |
| else if (i == 1) |
| TYPE_USES_MULTIPLE_INHERITANCE (ref) |
| = TYPE_USES_MULTIPLE_INHERITANCE (BINFO_TYPE (TREE_VEC_ELT (binfos, 0))); |
| if (TYPE_USES_MULTIPLE_INHERITANCE (ref)) |
| TYPE_USES_COMPLEX_INHERITANCE (ref) = 1; |
| |
| /* Unmark all the types. */ |
| while (--i >= 0) |
| CLEAR_CLASSTYPE_MARKED (BINFO_TYPE (TREE_VEC_ELT (binfos, i))); |
| CLEAR_CLASSTYPE_MARKED (ref); |
| |
| pop_obstacks (); |
| } |
| |
| |
| tree current_local_enum = NULL_TREE; |
| |
| /* Begin compiling the definition of an enumeration type. |
| NAME is its name (or null if anonymous). |
| Returns the type object, as yet incomplete. |
| Also records info about it so that build_enumerator |
| may be used to declare the individual values as they are read. */ |
| |
| tree |
| start_enum (name) |
| tree name; |
| { |
| register tree enumtype = NULL_TREE; |
| struct binding_level *b = inner_binding_level; |
| |
| /* We are wasting space here and putting these on the permanent_obstack so |
| that typeid(local enum) will work correctly. */ |
| #if 0 |
| if (processing_template_decl && current_function_decl) |
| #endif |
| |
| end_temporary_allocation (); |
| |
| /* If this is the real definition for a previous forward reference, |
| fill in the contents in the same object that used to be the |
| forward reference. */ |
| |
| if (name != NULL_TREE) |
| enumtype = lookup_tag (ENUMERAL_TYPE, name, b, 1); |
| |
| if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE) |
| cp_error ("multiple definition of `%#T'", enumtype); |
| else |
| { |
| enumtype = make_node (ENUMERAL_TYPE); |
| pushtag (name, enumtype, 0); |
| } |
| |
| if (b->pseudo_global) |
| cp_error ("template declaration of `%#T'", enumtype); |
| |
| if (current_class_type) |
| TREE_ADDRESSABLE (b->tags) = 1; |
| |
| current_local_enum = NULL_TREE; |
| |
| /* We don't copy this value because build_enumerator needs to do it. */ |
| enum_next_value = integer_zero_node; |
| enum_overflow = 0; |
| |
| GNU_xref_decl (current_function_decl, enumtype); |
| return enumtype; |
| } |
| |
| /* After processing and defining all the values of an enumeration type, |
| install their decls in the enumeration type and finish it off. |
| ENUMTYPE is the type object and VALUES a list of name-value pairs. |
| Returns ENUMTYPE. */ |
| |
| tree |
| finish_enum (enumtype, values) |
| register tree enumtype, values; |
| { |
| register tree minnode = NULL_TREE, maxnode = NULL_TREE; |
| /* Calculate the maximum value of any enumerator in this type. */ |
| |
| if (values) |
| { |
| register tree pair; |
| register tree value = DECL_INITIAL (TREE_VALUE (values)); |
| |
| if (! processing_template_decl) |
| { |
| /* Speed up the main loop by performing some precalculations */ |
| TREE_TYPE (TREE_VALUE (values)) = enumtype; |
| TREE_TYPE (value) = enumtype; |
| minnode = maxnode = value; |
| } |
| TREE_VALUE (values) = value; |
| |
| for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair)) |
| { |
| value = DECL_INITIAL (TREE_VALUE (pair)); |
| if (! processing_template_decl) |
| { |
| TREE_TYPE (TREE_VALUE (pair)) = enumtype; |
| TREE_TYPE (value) = enumtype; |
| if (tree_int_cst_lt (maxnode, value)) |
| maxnode = value; |
| else if (tree_int_cst_lt (value, minnode)) |
| minnode = value; |
| } |
| TREE_VALUE (pair) = value; |
| } |
| } |
| else |
| maxnode = minnode = integer_zero_node; |
| |
| TYPE_VALUES (enumtype) = nreverse (values); |
| |
| if (processing_template_decl) |
| { |
| if (current_function_decl) |
| { |
| add_tree (build_min (TAG_DEFN, enumtype)); |
| resume_temporary_allocation (); |
| } |
| return enumtype; |
| } |
| |
| { |
| int unsignedp = tree_int_cst_sgn (minnode) >= 0; |
| int lowprec = min_precision (minnode, unsignedp); |
| int highprec = min_precision (maxnode, unsignedp); |
| int precision = MAX (lowprec, highprec); |
| |
| TYPE_SIZE (enumtype) = NULL_TREE; |
| |
| /* Set TYPE_MIN_VALUE and TYPE_MAX_VALUE according to `precision'. */ |
| |
| TYPE_PRECISION (enumtype) = precision; |
| if (unsignedp) |
| fixup_unsigned_type (enumtype); |
| else |
| fixup_signed_type (enumtype); |
| |
| if (flag_short_enums || (precision > TYPE_PRECISION (integer_type_node))) |
| /* Use the width of the narrowest normal C type which is wide enough. */ |
| TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size |
| (precision, 1)); |
| else |
| TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node); |
| |
| TYPE_SIZE (enumtype) = 0; |
| layout_type (enumtype); |
| } |
| |
| { |
| register tree tem; |
| |
| /* Fix up all variant types of this enum type. */ |
| for (tem = TYPE_MAIN_VARIANT (enumtype); tem; |
| tem = TYPE_NEXT_VARIANT (tem)) |
| { |
| TYPE_VALUES (tem) = TYPE_VALUES (enumtype); |
| TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype); |
| TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype); |
| TYPE_SIZE (tem) = TYPE_SIZE (enumtype); |
| TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype); |
| TYPE_MODE (tem) = TYPE_MODE (enumtype); |
| TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); |
| TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype); |
| TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype); |
| } |
| } |
| |
| /* Finish debugging output for this type. */ |
| rest_of_type_compilation (enumtype, namespace_bindings_p ()); |
| |
| return enumtype; |
| } |
| |
| /* Build and install a CONST_DECL for one value of the |
| current enumeration type (one that was begun with start_enum). |
| Return a tree-list containing the name and its value. |
| Assignment of sequential values by default is handled here. */ |
| |
| tree |
| build_enumerator (name, value) |
| tree name, value; |
| { |
| tree decl, result; |
| |
| /* Remove no-op casts from the value. */ |
| if (value) |
| STRIP_TYPE_NOPS (value); |
| |
| if (! processing_template_decl) |
| { |
| /* Validate and default VALUE. */ |
| if (value != NULL_TREE) |
| { |
| if (TREE_READONLY_DECL_P (value)) |
| value = decl_constant_value (value); |
| |
| if (TREE_CODE (value) == INTEGER_CST) |
| { |
| value = default_conversion (value); |
| constant_expression_warning (value); |
| } |
| else |
| { |
| cp_error ("enumerator value for `%D' not integer constant", name); |
| value = NULL_TREE; |
| } |
| } |
| |
| /* Default based on previous value. */ |
| if (value == NULL_TREE && ! processing_template_decl) |
| { |
| value = enum_next_value; |
| if (enum_overflow) |
| cp_error ("overflow in enumeration values at `%D'", name); |
| } |
| |
| /* Remove no-op casts from the value. */ |
| if (value) |
| STRIP_TYPE_NOPS (value); |
| |
| /* We have to always copy here; not all INTEGER_CSTs are unshared, |
| and there's no wedding ring. Look at size_int()...*/ |
| value = copy_node (value); |
| #if 0 |
| /* To fix MAX_VAL enum consts. (bkoz) */ |
| TREE_TYPE (value) = integer_type_node; |
| #endif |
| } |
| |
| /* C++ associates enums with global, function, or class declarations. */ |
| |
| decl = current_scope (); |
| if (decl && decl == current_class_type) |
| { |
| /* This enum declaration is local to the class, so we must put |
| it in that class's list of decls. */ |
| decl = build_lang_field_decl (CONST_DECL, name, integer_type_node); |
| DECL_INITIAL (decl) = value; |
| TREE_READONLY (decl) = 1; |
| pushdecl_class_level (decl); |
| TREE_CHAIN (decl) = current_local_enum; |
| current_local_enum = decl; |
| } |
| else |
| { |
| /* It's a global enum, or it's local to a function. (Note local to |
| a function could mean local to a class method. */ |
| decl = build_decl (CONST_DECL, name, integer_type_node); |
| DECL_INITIAL (decl) = value; |
| TREE_READONLY (decl) = 1; |
| |
| pushdecl (decl); |
| GNU_xref_decl (current_function_decl, decl); |
| } |
| |
| if (! processing_template_decl) |
| { |
| /* Set basis for default for next value. */ |
| enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value, |
| integer_one_node, PLUS_EXPR); |
| enum_overflow = tree_int_cst_lt (enum_next_value, value); |
| } |
| |
| result = saveable_tree_cons (name, decl, NULL_TREE); |
| return result; |
| } |
| |
| tree |
| grok_enum_decls (decl) |
| tree decl; |
| { |
| tree d = current_local_enum; |
| |
| if (d == NULL_TREE) |
| return decl; |
| |
| while (1) |
| { |
| if (TREE_CHAIN (d) == NULL_TREE) |
| { |
| TREE_CHAIN (d) = decl; |
| break; |
| } |
| d = TREE_CHAIN (d); |
| } |
| |
| decl = current_local_enum; |
| current_local_enum = NULL_TREE; |
| |
| return decl; |
| } |
| |
| static int function_depth; |
| |
| /* Create the FUNCTION_DECL for a function definition. |
| DECLSPECS and DECLARATOR are the parts of the declaration; |
| they describe the function's name and the type it returns, |
| but twisted together in a fashion that parallels the syntax of C. |
| |
| This function creates a binding context for the function body |
| as well as setting up the FUNCTION_DECL in current_function_decl. |
| |
| Returns 1 on success. If the DECLARATOR is not suitable for a function |
| (it defines a datum instead), we return 0, which tells |
| yyparse to report a parse error. |
| |
| For C++, we must first check whether that datum makes any sense. |
| For example, "class A local_a(1,2);" means that variable local_a |
| is an aggregate of type A, which should have a constructor |
| applied to it with the argument list [1, 2]. |
| |
| @@ There is currently no way to retrieve the storage |
| @@ allocated to FUNCTION (or all of its parms) if we return |
| @@ something we had previously. */ |
| |
| int |
| start_function (declspecs, declarator, attrs, pre_parsed_p) |
| tree declspecs, declarator, attrs; |
| int pre_parsed_p; |
| { |
| tree decl1; |
| tree ctype = NULL_TREE; |
| tree fntype; |
| tree restype; |
| extern int have_extern_spec; |
| extern int used_extern_spec; |
| int doing_friend = 0; |
| |
| /* Sanity check. */ |
| my_friendly_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE, 160); |
| my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161); |
| |
| /* Assume, until we see it does. */ |
| current_function_returns_value = 0; |
| current_function_returns_null = 0; |
| warn_about_return_type = 0; |
| named_labels = 0; |
| shadowed_labels = 0; |
| current_function_assigns_this = 0; |
| current_function_just_assigned_this = 0; |
| current_function_parms_stored = 0; |
| original_result_rtx = NULL_RTX; |
| base_init_expr = NULL_TREE; |
| current_base_init_list = NULL_TREE; |
| current_member_init_list = NULL_TREE; |
| ctor_label = dtor_label = NULL_TREE; |
| static_labelno = 0; |
| |
| clear_temp_name (); |
| |
| /* This should only be done once on the top most decl. */ |
| if (have_extern_spec && !used_extern_spec) |
| { |
| declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), declspecs); |
| used_extern_spec = 1; |
| } |
| |
| if (pre_parsed_p) |
| { |
| decl1 = declarator; |
| |
| #if 0 |
| /* What was this testing for, exactly? */ |
| if (! DECL_ARGUMENTS (decl1) |
| && !DECL_STATIC_FUNCTION_P (decl1) |
| && !DECL_ARTIFICIAL (decl1) |
| && DECL_CLASS_SCOPE_P (decl1) |
| && TYPE_IDENTIFIER (DECL_CONTEXT (decl1)) |
| && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (DECL_CONTEXT (decl1)))) |
| { |
| tree binding = binding_for_name (DECL_NAME (decl1), |
| current_namespace); |
| cp_error ("redeclaration of `%#D'", decl1); |
| if (IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1))) |
| cp_error_at ("previous declaration here", IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1))); |
| else if (BINDING_VALUE (binding)) |
| cp_error_at ("previous declaration here", BINDING_VALUE (binding)); |
| } |
| #endif |
| |
| fntype = TREE_TYPE (decl1); |
| if (TREE_CODE (fntype) == METHOD_TYPE) |
| ctype = TYPE_METHOD_BASETYPE (fntype); |
| |
| /* ANSI C++ June 5 1992 WP 11.4.5. A friend function defined in a |
| class is in the (lexical) scope of the class in which it is |
| defined. */ |
| if (!ctype && DECL_FRIEND_P (decl1)) |
| { |
| ctype = DECL_CLASS_CONTEXT (decl1); |
| |
| /* CTYPE could be null here if we're dealing with a template; |
| for example, `inline friend float foo()' inside a template |
| will have no CTYPE set. */ |
| if (ctype && TREE_CODE (ctype) != RECORD_TYPE) |
| ctype = NULL_TREE; |
| else |
| doing_friend = 1; |
| } |
| |
| /* In a fcn definition, arg types must be complete. */ |
| require_complete_types_for_parms (DECL_ARGUMENTS (decl1)); |
| |
| /* In case some arg types were completed since the declaration was |
| parsed, fix up the decls. */ |
| { |
| tree t = DECL_ARGUMENTS (decl1); |
| for (; t; t = TREE_CHAIN (t)) |
| layout_decl (t, 0); |
| } |
| |
| last_function_parms = DECL_ARGUMENTS (decl1); |
| last_function_parm_tags = NULL_TREE; |
| } |
| else |
| { |
| decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL_TREE); |
| /* If the declarator is not suitable for a function definition, |
| cause a syntax error. */ |
| if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) return 0; |
| |
| fntype = TREE_TYPE (decl1); |
| |
| restype = TREE_TYPE (fntype); |
| if (IS_AGGR_TYPE (restype) && ! TYPE_PTRMEMFUNC_P (restype) |
| && ! CLASSTYPE_GOT_SEMICOLON (restype)) |
| { |
| cp_error ("semicolon missing after declaration of `%#T'", restype); |
| shadow_tag (build_expr_list (NULL_TREE, restype)); |
| CLASSTYPE_GOT_SEMICOLON (restype) = 1; |
| if (TREE_CODE (fntype) == FUNCTION_TYPE) |
| fntype = build_function_type (integer_type_node, |
| TYPE_ARG_TYPES (fntype)); |
| else |
| fntype = build_cplus_method_type (build_type_variant (TYPE_METHOD_BASETYPE (fntype), TREE_READONLY (decl1), TREE_SIDE_EFFECTS (decl1)), |
| integer_type_node, |
| TYPE_ARG_TYPES (fntype)); |
| TREE_TYPE (decl1) = fntype; |
| } |
| |
| if (TREE_CODE (fntype) == METHOD_TYPE) |
| ctype = TYPE_METHOD_BASETYPE (fntype); |
| else if (DECL_MAIN_P (decl1)) |
| { |
| /* If this doesn't return integer_type, complain. */ |
| if (TREE_TYPE (TREE_TYPE (decl1)) != integer_type_node) |
| { |
| if (pedantic || warn_return_type) |
| pedwarn ("return type for `main' changed to `int'"); |
| TREE_TYPE (decl1) = fntype = default_function_type; |
| } |
| warn_about_return_type = 0; |
| } |
| } |
| |
| /* Warn if function was previously implicitly declared |
| (but not if we warned then). */ |
| if (! warn_implicit |
| && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)) != NULL_TREE) |
| cp_warning_at ("`%D' implicitly declared before its definition", IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1))); |
| |
| current_function_decl = decl1; |
| /* Save the parm names or decls from this function's declarator |
| where store_parm_decls will find them. */ |
| current_function_parms = last_function_parms; |
| current_function_parm_tags = last_function_parm_tags; |
| |
| announce_function (decl1); |
| |
| if (! processing_template_decl) |
| { |
| if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE) |
| { |
| cp_error ("return-type `%#T' is an incomplete type", |
| TREE_TYPE (fntype)); |
| |
| /* Make it return void instead, but don't change the |
| type of the DECL_RESULT, in case we have a named return value. */ |
| if (ctype) |
| TREE_TYPE (decl1) |
| = build_cplus_method_type (build_type_variant (ctype, |
| TREE_READONLY (decl1), |
| TREE_SIDE_EFFECTS (decl1)), |
| void_type_node, |
| FUNCTION_ARG_CHAIN (decl1)); |
| else |
| TREE_TYPE (decl1) |
| = build_function_type (void_type_node, |
| TYPE_ARG_TYPES (TREE_TYPE (decl1))); |
| DECL_RESULT (decl1) |
| = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (fntype))); |
| TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (TREE_TYPE (fntype)); |
| TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (TREE_TYPE (fntype)); |
| } |
| |
| if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype)) |
| && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (fntype))) |
| abstract_virtuals_error (decl1, TREE_TYPE (fntype)); |
| } |
| |
| if (warn_about_return_type) |
| pedwarn ("return-type defaults to `int'"); |
| |
| /* Effective C++ rule 15. See also c_expand_return. */ |
| if (warn_ecpp |
| && DECL_NAME (decl1) == ansi_opname[(int) MODIFY_EXPR] |
| && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE) |
| cp_warning ("`operator=' should return a reference to `*this'"); |
| |
| /* Make the init_value nonzero so pushdecl knows this is not tentative. |
| error_mark_node is replaced below (in poplevel) with the BLOCK. */ |
| DECL_INITIAL (decl1) = error_mark_node; |
| |
| /* This function exists in static storage. |
| (This does not mean `static' in the C sense!) */ |
| TREE_STATIC (decl1) = 1; |
| |
| /* Record the decl so that the function name is defined. |
| If we already have a decl for this name, and it is a FUNCTION_DECL, |
| use the old decl. */ |
| |
| if (processing_template_decl) |
| decl1 = push_template_decl (decl1); |
| else if (pre_parsed_p == 0) |
| { |
| /* A specialization is not used to guide overload resolution. */ |
| if ((flag_guiding_decls |
| || !DECL_TEMPLATE_SPECIALIZATION (decl1)) |
| && ! DECL_FUNCTION_MEMBER_P (decl1)) |
| decl1 = pushdecl (decl1); |
| else |
| { |
| /* We need to set the DECL_CONTEXT. */ |
| if (!DECL_CONTEXT (decl1) && DECL_TEMPLATE_INFO (decl1)) |
| DECL_CONTEXT (decl1) = DECL_CONTEXT (DECL_TI_TEMPLATE (decl1)); |
| /* And make sure we have enough default args. */ |
| check_default_args (decl1); |
| } |
| DECL_MAIN_VARIANT (decl1) = decl1; |
| fntype = TREE_TYPE (decl1); |
| } |
| |
| current_function_decl = decl1; |
| |
| if (DECL_INTERFACE_KNOWN (decl1)) |
| { |
| tree ctx = hack_decl_function_context (decl1); |
| |
| if (DECL_NOT_REALLY_EXTERN (decl1)) |
| DECL_EXTERNAL (decl1) = 0; |
| |
| if (ctx != NULL_TREE && DECL_THIS_INLINE (ctx) |
| && TREE_PUBLIC (ctx)) |
| /* This is a function in a local class in an extern inline |
| function. */ |
| comdat_linkage (decl1); |
| } |
| /* If this function belongs to an interface, it is public. |
| If it belongs to someone else's interface, it is also external. |
| It doesn't matter whether it's inline or not. */ |
| else if (interface_unknown == 0 |
| && (! DECL_TEMPLATE_INSTANTIATION (decl1) |
| || flag_alt_external_templates)) |
| { |
| if (DECL_THIS_INLINE (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1) |
| || processing_template_decl) |
| DECL_EXTERNAL (decl1) |
| = (interface_only |
| || (DECL_THIS_INLINE (decl1) && ! flag_implement_inlines)); |
| else |
| DECL_EXTERNAL (decl1) = 0; |
| DECL_NOT_REALLY_EXTERN (decl1) = 0; |
| DECL_INTERFACE_KNOWN (decl1) = 1; |
| } |
| else |
| { |
| /* This is a definition, not a reference. |
| So clear DECL_EXTERNAL. */ |
| DECL_EXTERNAL (decl1) = 0; |
| |
| if ((DECL_THIS_INLINE (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1)) |
| && ! DECL_INTERFACE_KNOWN (decl1) |
| /* Don't try to defer nested functions for now. */ |
| && ! hack_decl_function_context (decl1)) |
| DECL_DEFER_OUTPUT (decl1) = 1; |
| else |
| DECL_INTERFACE_KNOWN (decl1) = 1; |
| } |
| |
| if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)) |
| { |
| if (TREE_CODE (fntype) == METHOD_TYPE) |
| TREE_TYPE (decl1) = fntype |
| = build_function_type (TREE_TYPE (fntype), |
| TREE_CHAIN (TYPE_ARG_TYPES (fntype))); |
| current_function_parms = TREE_CHAIN (current_function_parms); |
| DECL_ARGUMENTS (decl1) = current_function_parms; |
| ctype = NULL_TREE; |
| } |
| restype = TREE_TYPE (fntype); |
| |
| if (ctype) |
| { |
| push_nested_class (ctype, 1); |
| |
| /* If we're compiling a friend function, neither of the variables |
| current_class_ptr nor current_class_type will have values. */ |
| if (! doing_friend) |
| { |
| /* We know that this was set up by `grokclassfn'. |
| We do not wait until `store_parm_decls', since evil |
| parse errors may never get us to that point. Here |
| we keep the consistency between `current_class_type' |
| and `current_class_ptr'. */ |
| tree t = current_function_parms; |
| |
| my_friendly_assert (t != NULL_TREE |
| && TREE_CODE (t) == PARM_DECL, 162); |
| |
| if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE) |
| { |
| int i = suspend_momentary (); |
| |
| /* Fool build_indirect_ref. */ |
| current_class_ptr = NULL_TREE; |
| current_class_ref = build_indirect_ref (t, NULL_PTR); |
| current_class_ptr = t; |
| resume_momentary (i); |
| } |
| else |
| /* We're having a signature pointer here. */ |
| current_class_ref = current_class_ptr = t; |
| |
| } |
| } |
| else |
| { |
| if (DECL_STATIC_FUNCTION_P (decl1)) |
| push_nested_class (DECL_CONTEXT (decl1), 2); |
| else |
| push_memoized_context (0, 1); |
| current_class_ptr = current_class_ref = NULL_TREE; |
| } |
| |
| pushlevel (0); |
| current_binding_level->parm_flag = 1; |
| |
| GNU_xref_function (decl1, current_function_parms); |
| |
| if (attrs) |
| cplus_decl_attributes (decl1, NULL_TREE, attrs); |
| make_function_rtl (decl1); |
| |
| /* Promote the value to int before returning it. */ |
| if (C_PROMOTING_INTEGER_TYPE_P (restype)) |
| restype = type_promotes_to (restype); |
| |
| /* If this fcn was already referenced via a block-scope `extern' decl |
| (or an implicit decl), propagate certain information about the usage. */ |
| if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (decl1))) |
| TREE_ADDRESSABLE (decl1) = 1; |
| |
| if (DECL_RESULT (decl1) == NULL_TREE) |
| { |
| DECL_RESULT (decl1) |
| = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype)); |
| TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (restype); |
| TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (restype); |
| } |
| |
| /* Allocate further tree nodes temporarily during compilation |
| of this function only. Tiemann moved up here from bottom of fn. */ |
| /* If this is a nested function, then we must continue to allocate RTL |
| on the permanent obstack in case we need to inline it later. */ |
| if (! hack_decl_function_context (decl1)) |
| temporary_allocation (); |
| |
| if (processing_template_decl) |
| { |
| ++minimal_parse_mode; |
| last_tree = DECL_SAVED_TREE (decl1) |
| = build_nt (EXPR_STMT, void_zero_node); |
| } |
| |
| ++function_depth; |
| |
| if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1)) |
| && DECL_LANGUAGE (decl1) == lang_cplusplus) |
| { |
| dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); |
| ctor_label = NULL_TREE; |
| } |
| else |
| { |
| dtor_label = NULL_TREE; |
| if (DECL_CONSTRUCTOR_P (decl1)) |
| ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); |
| } |
| |
| return 1; |
| } |
| |
| /* Called after store_parm_decls for a function-try-block. We need to update |
| last_parm_cleanup_insn so that the base initializers for a constructor |
| are run within this block, not before it. */ |
| |
| void |
| expand_start_early_try_stmts () |
| { |
| expand_start_try_stmts (); |
| last_parm_cleanup_insn = get_last_insn (); |
| } |
| |
| /* Store the parameter declarations into the current function declaration. |
| This is called after parsing the parameter declarations, before |
| digesting the body of the function. |
| |
| Also install to binding contour return value identifier, if any. */ |
| |
| void |
| store_parm_decls () |
| { |
| register tree fndecl = current_function_decl; |
| register tree parm; |
| int parms_have_cleanups = 0; |
| tree cleanups = NULL_TREE; |
| |
| /* This is either a chain of PARM_DECLs (when a prototype is used). */ |
| tree specparms = current_function_parms; |
| |
| /* This is a list of types declared among parms in a prototype. */ |
| tree parmtags = current_function_parm_tags; |
| |
| /* This is a chain of any other decls that came in among the parm |
| declarations. If a parm is declared with enum {foo, bar} x; |
| then CONST_DECLs for foo and bar are put here. */ |
| tree nonparms = NULL_TREE; |
| |
| if (toplevel_bindings_p ()) |
| fatal ("parse errors have confused me too much"); |
| |
| /* Initialize RTL machinery. */ |
| init_function_start (fndecl, input_filename, lineno); |
| |
| /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */ |
| declare_function_name (); |
| |
| /* Create a binding level for the parms. */ |
| expand_start_bindings (0); |
| |
| if (specparms != NULL_TREE) |
| { |
| /* This case is when the function was defined with an ANSI prototype. |
| The parms already have decls, so we need not do anything here |
| except record them as in effect |
| and complain if any redundant old-style parm decls were written. */ |
| |
| register tree next; |
| |
| /* Must clear this because it might contain TYPE_DECLs declared |
| at class level. */ |
| storedecls (NULL_TREE); |
| |
| for (parm = nreverse (specparms); parm; parm = next) |
| { |
| next = TREE_CHAIN (parm); |
| if (TREE_CODE (parm) == PARM_DECL) |
| { |
| tree cleanup; |
| if (DECL_NAME (parm) == NULL_TREE) |
| { |
| pushdecl (parm); |
| } |
| else if (TREE_CODE (TREE_TYPE (parm)) == VOID_TYPE) |
| cp_error ("parameter `%D' declared void", parm); |
| else |
| { |
| /* Now fill in DECL_REFERENCE_SLOT for any of the parm decls. |
| A parameter is assumed not to have any side effects. |
| If this should change for any reason, then this |
| will have to wrap the bashed reference type in a save_expr. |
| |
| Also, if the parameter type is declared to be an X |
| and there is an X(X&) constructor, we cannot lay it |
| into the stack (any more), so we make this parameter |
| look like it is really of reference type. Functions |
| which pass parameters to this function will know to |
| create a temporary in their frame, and pass a reference |
| to that. */ |
| |
| if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE |
| && TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm)))) |
| SET_DECL_REFERENCE_SLOT (parm, convert_from_reference (parm)); |
| |
| pushdecl (parm); |
| } |
| if (! processing_template_decl |
| && (cleanup = maybe_build_cleanup (parm), cleanup)) |
| { |
| expand_decl (parm); |
| parms_have_cleanups = 1; |
| |
| /* Keep track of the cleanups. */ |
| cleanups = tree_cons (parm, cleanup, cleanups); |
| } |
| } |
| else |
| { |
| /* If we find an enum constant or a type tag, |
| put it aside for the moment. */ |
| TREE_CHAIN (parm) = NULL_TREE; |
| nonparms = chainon (nonparms, parm); |
| } |
| } |
| |
| /* Get the decls in their original chain order |
| and record in the function. This is all and only the |
| PARM_DECLs that were pushed into scope by the loop above. */ |
| DECL_ARGUMENTS (fndecl) = getdecls (); |
| |
| storetags (chainon (parmtags, gettags ())); |
| } |
| else |
| DECL_ARGUMENTS (fndecl) = NULL_TREE; |
| |
| /* Now store the final chain of decls for the arguments |
| as the decl-chain of the current lexical scope. |
| Put the enumerators in as well, at the front so that |
| DECL_ARGUMENTS is not modified. */ |
| |
| storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl))); |
| |
| /* Initialize the RTL code for the function. */ |
| DECL_SAVED_INSNS (fndecl) = NULL_RTX; |
| if (! processing_template_decl) |
| expand_function_start (fndecl, parms_have_cleanups); |
| |
| current_function_parms_stored = 1; |
| |
| /* If this function is `main', emit a call to `__main' |
| to run global initializers, etc. */ |
| if (DECL_MAIN_P (fndecl)) |
| expand_main_function (); |
| |
| /* Now that we have initialized the parms, we can start their |
| cleanups. We cannot do this before, since expand_decl_cleanup |
| should not be called before the parm can be used. */ |
| if (cleanups |
| && ! processing_template_decl) |
| { |
| for (cleanups = nreverse (cleanups); cleanups; cleanups = TREE_CHAIN (cleanups)) |
| { |
| if (! expand_decl_cleanup (TREE_PURPOSE (cleanups), TREE_VALUE (cleanups))) |
| cp_error ("parser lost in parsing declaration of `%D'", |
| TREE_PURPOSE (cleanups)); |
| } |
| } |
| |
| /* Create a binding contour which can be used to catch |
| cleanup-generated temporaries. Also, if the return value needs or |
| has initialization, deal with that now. */ |
| if (parms_have_cleanups) |
| { |
| pushlevel (0); |
| expand_start_bindings (0); |
| } |
| |
| if (! processing_template_decl && flag_exceptions) |
| { |
| /* Do the starting of the exception specifications, if we have any. */ |
| if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) |
| expand_start_eh_spec (); |
| } |
| |
| last_parm_cleanup_insn = get_last_insn (); |
| last_dtor_insn = get_last_insn (); |
| } |
| |
| /* Bind a name and initialization to the return value of |
| the current function. */ |
| |
| void |
| store_return_init (return_id, init) |
| tree return_id, init; |
| { |
| tree decl = DECL_RESULT (current_function_decl); |
| |
| if (pedantic) |
| /* Give this error as many times as there are occurrences, |
| so that users can use Emacs compilation buffers to find |
| and fix all such places. */ |
| pedwarn ("ANSI C++ does not permit named return values"); |
| |
| if (return_id != NULL_TREE) |
| { |
| if (DECL_NAME (decl) == NULL_TREE) |
| { |
| DECL_NAME (decl) = return_id; |
| DECL_ASSEMBLER_NAME (decl) = return_id; |
| } |
| else |
| cp_error ("return identifier `%D' already in place", decl); |
| } |
| |
| /* Can't let this happen for constructors. */ |
| if (DECL_CONSTRUCTOR_P (current_function_decl)) |
| { |
| error ("can't redefine default return value for constructors"); |
| return; |
| } |
| |
| /* If we have a named return value, put that in our scope as well. */ |
| if (DECL_NAME (decl) != NULL_TREE) |
| { |
| /* If this named return value comes in a register, |
| put it in a pseudo-register. */ |
| if (DECL_REGISTER (decl)) |
| { |
| original_result_rtx = DECL_RTL (decl); |
| DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl)); |
| } |
| |
| /* Let `cp_finish_decl' know that this initializer is ok. */ |
| DECL_INITIAL (decl) = init; |
| pushdecl (decl); |
| |
| if (minimal_parse_mode) |
| add_tree (build_min_nt (RETURN_INIT, return_id, |
| copy_to_permanent (init))); |
| else |
| cp_finish_decl (decl, init, NULL_TREE, 0, 0); |
| } |
| } |
| |
| |
| /* Finish up a function declaration and compile that function |
| all the way to assembler language output. The free the storage |
| for the function definition. |
| |
| This is called after parsing the body of the function definition. |
| LINENO is the current line number. |
| |
| C++: CALL_POPLEVEL is non-zero if an extra call to poplevel |
| (and expand_end_bindings) must be made to take care of the binding |
| contour for the base initializers. This is only relevant for |
| constructors. |
| |
| NESTED is nonzero if we were in the middle of compiling another function |
| when we started on this one. */ |
| |
| void |
| finish_function (lineno, call_poplevel, nested) |
| int lineno; |
| int call_poplevel; |
| int nested; |
| { |
| register tree fndecl = current_function_decl; |
| tree fntype, ctype = NULL_TREE; |
| rtx last_parm_insn, insns; |
| /* Label to use if this function is supposed to return a value. */ |
| tree no_return_label = NULL_TREE; |
| tree decls = NULL_TREE; |
| |
| /* When we get some parse errors, we can end up without a |
| current_function_decl, so cope. */ |
| if (fndecl == NULL_TREE) |
| return; |
| |
| if (! nested && function_depth > 1) |
| nested = 1; |
| |
| fntype = TREE_TYPE (fndecl); |
| |
| /* TREE_READONLY (fndecl) = 1; |
| This caused &foo to be of type ptr-to-const-function |
| which then got a warning when stored in a ptr-to-function variable. */ |
| |
| /* This happens on strange parse errors. */ |
| if (! current_function_parms_stored) |
| { |
| call_poplevel = 0; |
| store_parm_decls (); |
| } |
| |
| if (processing_template_decl) |
| { |
| if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel) |
| { |
| decls = getdecls (); |
| expand_end_bindings (decls, decls != NULL_TREE, 0); |
| poplevel (decls != NULL_TREE, 0, 0); |
| } |
| } |
| else |
| { |
| if (write_symbols != NO_DEBUG /*&& TREE_CODE (fntype) != METHOD_TYPE*/) |
| { |
| tree ttype = target_type (fntype); |
| tree parmdecl; |
| |
| if (IS_AGGR_TYPE (ttype)) |
| /* Let debugger know it should output info for this type. */ |
| note_debug_info_needed (ttype); |
| |
| for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl)) |
| { |
| ttype = target_type (TREE_TYPE (parmdecl)); |
| if (IS_AGGR_TYPE (ttype)) |
| /* Let debugger know it should output info for this type. */ |
| note_debug_info_needed (ttype); |
| } |
| } |
| |
| /* Clean house because we will need to reorder insns here. */ |
| do_pending_stack_adjust (); |
| |
| if (dtor_label) |
| { |
| tree binfo = TYPE_BINFO (current_class_type); |
| tree cond = integer_one_node; |
| tree exprstmt; |
| tree in_charge_node = lookup_name (in_charge_identifier, 0); |
| tree virtual_size; |
| int ok_to_optimize_dtor = 0; |
| int empty_dtor = get_last_insn () == last_dtor_insn; |
| |
| if (current_function_assigns_this) |
| cond = build (NE_EXPR, boolean_type_node, |
| current_class_ptr, integer_zero_node); |
| else |
| { |
| int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type); |
| |
| /* If this destructor is empty, then we don't need to check |
| whether `this' is NULL in some cases. */ |
| if ((flag_this_is_variable & 1) == 0) |
| ok_to_optimize_dtor = 1; |
| else if (empty_dtor) |
| ok_to_optimize_dtor |
| = (n_baseclasses == 0 |
| || (n_baseclasses == 1 |
| && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0)))); |
| } |
| |
| /* These initializations might go inline. Protect |
| the binding level of the parms. */ |
| pushlevel (0); |
| expand_start_bindings (0); |
| |
| if (current_function_assigns_this) |
| { |
| current_function_assigns_this = 0; |
| current_function_just_assigned_this = 0; |
| } |
| |
| /* Generate the code to call destructor on base class. |
| If this destructor belongs to a class with virtual |
| functions, then set the virtual function table |
| pointer to represent the type of our base class. */ |
| |
| /* This side-effect makes call to `build_delete' generate the |
| code we have to have at the end of this destructor. */ |
| TYPE_HAS_DESTRUCTOR (current_class_type) = 0; |
| |
| /* These are two cases where we cannot delegate deletion. */ |
| if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type) |
| || TYPE_GETS_REG_DELETE (current_class_type)) |
| exprstmt = build_delete (current_class_type, current_class_ref, integer_zero_node, |
| LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0); |
| else |
| exprstmt = build_delete (current_class_type, current_class_ref, in_charge_node, |
| LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0); |
| |
| /* If we did not assign to this, then `this' is non-zero at |
| the end of a destructor. As a special optimization, don't |
| emit test if this is an empty destructor. If it does nothing, |
| it does nothing. If it calls a base destructor, the base |
| destructor will perform the test. */ |
| |
| if (exprstmt != error_mark_node |
| && (TREE_CODE (exprstmt) != NOP_EXPR |
| || TREE_OPERAND (exprstmt, 0) != integer_zero_node |
| || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))) |
| { |
| expand_label (dtor_label); |
| if (cond != integer_one_node) |
| expand_start_cond (cond, 0); |
| if (exprstmt != void_zero_node) |
| /* Don't call `expand_expr_stmt' if we're not going to do |
| anything, since -Wall will give a diagnostic. */ |
| expand_expr_stmt (exprstmt); |
| |
| /* Run destructor on all virtual baseclasses. */ |
| if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) |
| { |
| tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type))); |
| expand_start_cond (build (BIT_AND_EXPR, integer_type_node, |
| in_charge_node, integer_two_node), 0); |
| while (vbases) |
| { |
| if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases))) |
| { |
| tree vb = get_vbase |
| (BINFO_TYPE (vbases), |
| TYPE_BINFO (current_class_type)); |
| expand_expr_stmt |
| (build_scoped_method_call |
| (current_class_ref, vb, dtor_identifier, |
| build_expr_list (NULL_TREE, integer_zero_node))); |
| } |
| vbases = TREE_CHAIN (vbases); |
| } |
| expand_end_cond (); |
| } |
| |
| do_pending_stack_adjust (); |
| if (cond != integer_one_node) |
| expand_end_cond (); |
| } |
| |
| TYPE_HAS_DESTRUCTOR (current_class_type) = 1; |
| |
| virtual_size = c_sizeof (current_class_type); |
| |
| /* At the end, call delete if that's what's requested. */ |
| |
| /* FDIS sez: At the point of definition of a virtual destructor |
| (including an implicit definition), non-placement operator |
| delete shall be looked up in the scope of the destructor's |
| class and if found shall be accessible and unambiguous. |
| |
| This is somewhat unclear, but I take it to mean that if the |
| class only defines placement deletes we don't do anything here. |
| So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain |
| for us if they ever try to delete one of these. */ |
| |
| if (TYPE_GETS_REG_DELETE (current_class_type) |
| || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) |
| exprstmt = build_op_delete_call |
| (DELETE_EXPR, current_class_ptr, virtual_size, |
| LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE); |
| else |
| exprstmt = NULL_TREE; |
| |
| if (exprstmt) |
| { |
| cond = build (BIT_AND_EXPR, integer_type_node, |
| in_charge_node, integer_one_node); |
| expand_start_cond (cond, 0); |
| expand_expr_stmt (exprstmt); |
| expand_end_cond (); |
| } |
| |
| /* End of destructor. */ |
| expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0); |
| poplevel (2, 0, 0); /* XXX change to 1 */ |
| |
| /* Back to the top of destructor. */ |
| /* Don't execute destructor code if `this' is NULL. */ |
| |
| start_sequence (); |
| |
| /* If the dtor is empty, and we know there is not possible way we |
| could use any vtable entries, before they are possibly set by |
| a base class dtor, we don't have to setup the vtables, as we |
| know that any base class dtoring will set up any vtables it |
| needs. We avoid MI, because one base class dtor can do a |
| virtual dispatch to an overridden function that would need to |
| have a non-related vtable set up, we cannot avoid setting up |
| vtables in that case. We could change this to see if there is |
| just one vtable. */ |
| if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type)) |
| { |
| /* Make all virtual function table pointers in non-virtual base |
| classes point to CURRENT_CLASS_TYPE's virtual function |
| tables. */ |
| expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr); |
| |
| if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) |
| expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr); |
| } |
| |
| if (! ok_to_optimize_dtor) |
| { |
| cond = build_binary_op (NE_EXPR, |
| current_class_ptr, integer_zero_node, 1); |
| expand_start_cond (cond, 0); |
| } |
| |
| insns = get_insns (); |
| end_sequence (); |
| |
| last_parm_insn = get_first_nonparm_insn (); |
| if (last_parm_insn == NULL_RTX) |
| last_parm_insn = get_last_insn (); |
| else |
| last_parm_insn = previous_insn (last_parm_insn); |
| |
| emit_insns_after (insns, last_parm_insn); |
| |
| if (! ok_to_optimize_dtor) |
| expand_end_cond (); |
| } |
| else if (current_function_assigns_this) |
| { |
| /* Does not need to call emit_base_init, because |
| that is done (if needed) just after assignment to this |
| is seen. */ |
| |
| if (DECL_CONSTRUCTOR_P (current_function_decl)) |
| { |
| end_protect_partials (); |
| expand_label (ctor_label); |
| ctor_label = NULL_TREE; |
| |
| if (call_poplevel) |
| { |
| decls = getdecls (); |
| expand_end_bindings (decls, decls != NULL_TREE, 0); |
| poplevel (decls != NULL_TREE, 0, 0); |
| } |
| /* c_expand_return knows to return 'this' from a constructor. */ |
| c_expand_return (NULL_TREE); |
| } |
| else if (TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl))) != VOID_TYPE |
| && return_label != NULL_RTX) |
| no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); |
| |
| current_function_assigns_this = 0; |
| current_function_just_assigned_this = 0; |
| base_init_expr = NULL_TREE; |
| } |
| else if (DECL_CONSTRUCTOR_P (fndecl)) |
| { |
| tree cond = NULL_TREE, thenclause = NULL_TREE; |
| /* Allow constructor for a type to get a new instance of the object |
| using `build_new'. */ |
| tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type); |
| CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE; |
| |
| DECL_RETURNS_FIRST_ARG (fndecl) = 1; |
| |
| if (flag_this_is_variable > 0) |
| { |
| cond = build_binary_op (EQ_EXPR, |
| current_class_ptr, integer_zero_node, 1); |
| thenclause = build_modify_expr (current_class_ptr, NOP_EXPR, |
| build_new (NULL_TREE, current_class_type, void_type_node, 0)); |
| } |
| |
| CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals; |
| |
| start_sequence (); |
| |
| if (flag_this_is_variable > 0) |
| { |
| expand_start_cond (cond, 0); |
| expand_expr_stmt (thenclause); |
| expand_end_cond (); |
| } |
| |
| /* Emit insns from `emit_base_init' which sets up virtual |
| function table pointer(s). */ |
| if (base_init_expr) |
| { |
| expand_expr_stmt (base_init_expr); |
| base_init_expr = NULL_TREE; |
| } |
| |
| insns = get_insns (); |
| end_sequence (); |
| |
| /* This is where the body of the constructor begins. */ |
| |
| emit_insns_after (insns, last_parm_cleanup_insn); |
| |
| end_protect_partials (); |
| |
| /* This is where the body of the constructor ends. */ |
| expand_label (ctor_label); |
| ctor_label = NULL_TREE; |
| |
| if (call_poplevel) |
| { |
| decls = getdecls (); |
| expand_end_bindings (decls, decls != NULL_TREE, 0); |
| poplevel (decls != NULL_TREE, 1, 0); |
| } |
| |
| /* c_expand_return knows to return 'this' from a constructor. */ |
| c_expand_return (NULL_TREE); |
| |
| current_function_assigns_this = 0; |
| current_function_just_assigned_this = 0; |
| } |
| else if (DECL_MAIN_P (fndecl)) |
| { |
| /* Make it so that `main' always returns 0 by default. */ |
| #ifdef VMS |
| c_expand_return (integer_one_node); |
| #else |
| c_expand_return (integer_zero_node); |
| #endif |
| } |
| else if (return_label != NULL_RTX |
| && current_function_return_value == NULL_TREE |
| && ! DECL_NAME (DECL_RESULT (current_function_decl))) |
| no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); |
| |
| if (flag_exceptions) |
| expand_exception_blocks (); |
| |
| /* If this function is supposed to return a value, ensure that |
| we do not fall into the cleanups by mistake. The end of our |
| function will look like this: |
| |
| user code (may have return stmt somewhere) |
| goto no_return_label |
| cleanup_label: |
| cleanups |
| goto return_label |
| no_return_label: |
| NOTE_INSN_FUNCTION_END |
| return_label: |
| things for return |
| |
| If the user omits a return stmt in the USER CODE section, we |
| will have a control path which reaches NOTE_INSN_FUNCTION_END. |
| Otherwise, we won't. */ |
| if (no_return_label) |
| { |
| DECL_CONTEXT (no_return_label) = fndecl; |
| DECL_INITIAL (no_return_label) = error_mark_node; |
| DECL_SOURCE_FILE (no_return_label) = input_filename; |
| DECL_SOURCE_LINE (no_return_label) = lineno; |
| expand_goto (no_return_label); |
| } |
| |
| if (cleanup_label) |
| { |
| /* Remove the binding contour which is used |
| to catch cleanup-generated temporaries. */ |
| expand_end_bindings (0, 0, 0); |
| poplevel (0, 0, 0); |
| |
| /* Emit label at beginning of cleanup code for parameters. */ |
| emit_label (cleanup_label); |
| } |
| |
| /* Get return value into register if that's where it's supposed to be. */ |
| if (original_result_rtx) |
| fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx); |
| |
| /* Finish building code that will trigger warnings if users forget |
| to make their functions return values. */ |
| if (no_return_label || cleanup_label) |
| emit_jump (return_label); |
| if (no_return_label) |
| { |
| /* We don't need to call `expand_*_return' here because we |
| don't need any cleanups here--this path of code is only |
| for error checking purposes. */ |
| expand_label (no_return_label); |
| } |
| |
| /* Generate rtl for function exit. */ |
| expand_function_end (input_filename, lineno, 1); |
| } |
| |
| /* This must come after expand_function_end because cleanups might |
| have declarations (from inline functions) that need to go into |
| this function's blocks. */ |
| if (current_binding_level->parm_flag != 1) |
| my_friendly_abort (122); |
| poplevel (1, 0, 1); |
| |
| /* Reset scope for C++: if we were in the scope of a class, |
| then when we finish this function, we are not longer so. |
| This cannot be done until we know for sure that no more |
| class members will ever be referenced in this function |
| (i.e., calls to destructors). */ |
| if (current_class_name) |
| { |
| ctype = current_class_type; |
| pop_nested_class (1); |
| } |
| else |
| pop_memoized_context (1); |
| |
| /* Must mark the RESULT_DECL as being in this function. */ |
| DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; |
| |
| /* Set the BLOCK_SUPERCONTEXT of the outermost function scope to point |
| to the FUNCTION_DECL node itself. */ |
| BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; |
| |
| if (! processing_template_decl) |
| { |
| int saved_flag_keep_inline_functions = |
| flag_keep_inline_functions; |
| |
| /* So we can tell if jump_optimize sets it to 1. */ |
| can_reach_end = 0; |
| |
| if (DECL_CONTEXT (fndecl) != NULL_TREE |
| && hack_decl_function_context (fndecl)) |
| /* Trick rest_of_compilation into not deferring output of this |
| function, even if it is inline, since the rtl_obstack for |
| this function is the function_obstack of the enclosing |
| function and will be deallocated when the enclosing |
| function is gone. See save_tree_status. */ |
| flag_keep_inline_functions = 1; |
| |
| /* Run the optimizers and output the assembler code for this |
| function. */ |
| |
| if (DECL_ARTIFICIAL (fndecl)) |
| { |
| /* Do we really *want* to inline this synthesized method? */ |
| |
| int save_fif = flag_inline_functions; |
| flag_inline_functions = 1; |
| |
| /* Turn off DECL_INLINE for the moment so function_cannot_inline_p |
| will check our size. */ |
| DECL_INLINE (fndecl) = 0; |
| |
| rest_of_compilation (fndecl); |
| flag_inline_functions = save_fif; |
| } |
| else |
| rest_of_compilation (fndecl); |
| |
| flag_keep_inline_functions = saved_flag_keep_inline_functions; |
| |
| if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (fndecl)) |
| { |
| /* Set DECL_EXTERNAL so that assemble_external will be called as |
| necessary. We'll clear it again in finish_file. */ |
| if (! DECL_EXTERNAL (fndecl)) |
| DECL_NOT_REALLY_EXTERN (fndecl) = 1; |
| DECL_EXTERNAL (fndecl) = 1; |
| mark_inline_for_output (fndecl); |
| } |
| |
| if (ctype && TREE_ASM_WRITTEN (fndecl)) |
| note_debug_info_needed (ctype); |
| |
| current_function_returns_null |= can_reach_end; |
| |
| /* Since we don't normally go through c_expand_return for constructors, |
| this normally gets the wrong value. |
| Also, named return values have their return codes emitted after |
| NOTE_INSN_FUNCTION_END, confusing jump.c. */ |
| if (DECL_CONSTRUCTOR_P (fndecl) |
| || DECL_NAME (DECL_RESULT (fndecl)) != NULL_TREE) |
| current_function_returns_null = 0; |
| |
| if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null) |
| cp_warning ("`noreturn' function `%D' does return", fndecl); |
| else if ((warn_return_type || pedantic) |
| && current_function_returns_null |
| && TREE_CODE (TREE_TYPE (fntype)) != VOID_TYPE) |
| { |
| /* If this function returns non-void and control can drop through, |
| complain. */ |
| cp_warning ("control reaches end of non-void function `%D'", fndecl); |
| } |
| /* With just -W, complain only if function returns both with |
| and without a value. */ |
| else if (extra_warnings |
| && current_function_returns_value && current_function_returns_null) |
| warning ("this function may return with or without a value"); |
| } |
| |
| --function_depth; |
| |
| /* Free all the tree nodes making up this function. */ |
| /* Switch back to allocating nodes permanently |
| until we start another function. */ |
| if (processing_template_decl) |
| { |
| --minimal_parse_mode; |
| DECL_SAVED_TREE (fndecl) = TREE_CHAIN (DECL_SAVED_TREE (fndecl)); |
| } |
| |
| if (! nested) |
| permanent_allocation (1); |
| |
| if (DECL_SAVED_INSNS (fndecl) == NULL_RTX) |
| { |
| tree t; |
| |
| /* Stop pointing to the local nodes about to be freed. */ |
| /* But DECL_INITIAL must remain nonzero so we know this |
| was an actual function definition. */ |
| DECL_INITIAL (fndecl) = error_mark_node; |
| for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t)) |
| DECL_RTL (t) = DECL_INCOMING_RTL (t) = NULL_RTX; |
| } |
| |
| if (DECL_STATIC_CONSTRUCTOR (fndecl)) |
| static_ctors = perm_tree_cons (NULL_TREE, fndecl, static_ctors); |
| if (DECL_STATIC_DESTRUCTOR (fndecl)) |
| static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors); |
| |
| if (! nested) |
| { |
| /* Let the error reporting routines know that we're outside a |
| function. For a nested function, this value is used in |
| pop_cp_function_context and then reset via pop_function_context. */ |
| current_function_decl = NULL_TREE; |
| } |
| |
| named_label_uses = NULL; |
| current_class_ptr = NULL_TREE; |
| current_class_ref = NULL_TREE; |
| } |
| |
| /* Create the FUNCTION_DECL for a function definition. |
| LINE1 is the line number that the definition absolutely begins on. |
| LINE2 is the line number that the name of the function appears on. |
| DECLSPECS and DECLARATOR are the parts of the declaration; |
| they describe the return type and the name of the function, |
| but twisted together in a fashion that parallels the syntax of C. |
| |
| This function creates a binding context for the function body |
| as well as setting up the FUNCTION_DECL in current_function_decl. |
| |
| Returns a FUNCTION_DECL on success. |
| |
| If the DECLARATOR is not suitable for a function (it defines a datum |
| instead), we return 0, which tells yyparse to report a parse error. |
| |
| May return void_type_node indicating that this method is actually |
| a friend. See grokfield for more details. |
| |
| Came here with a `.pushlevel' . |
| |
| DO NOT MAKE ANY CHANGES TO THIS CODE WITHOUT MAKING CORRESPONDING |
| CHANGES TO CODE IN `grokfield'. */ |
| |
| tree |
| start_method (declspecs, declarator) |
| tree declarator, declspecs; |
| { |
| tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, |
| NULL_TREE); |
| |
| /* Something too ugly to handle. */ |
| if (fndecl == NULL_TREE) |
| return NULL_TREE; |
| |
| /* Pass friends other than inline friend functions back. */ |
| if (fndecl == void_type_node) |
| return fndecl; |
| |
| if (TREE_CODE (fndecl) != FUNCTION_DECL) |
| /* Not a function, tell parser to report parse error. */ |
| return NULL_TREE; |
| |
| if (IS_SIGNATURE (current_class_type)) |
| IS_DEFAULT_IMPLEMENTATION (fndecl) = 1; |
| |
| if (DECL_IN_AGGR_P (fndecl)) |
| { |
| if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type) |
| { |
| if (DECL_CONTEXT (fndecl) |
| && TREE_CODE( DECL_CONTEXT (fndecl)) != NAMESPACE_DECL) |
| cp_error ("`%D' is already defined in class %s", fndecl, |
| TYPE_NAME_STRING (DECL_CONTEXT (fndecl))); |
| } |
| return void_type_node; |
| } |
| |
| DECL_THIS_INLINE (fndecl) = 1; |
| |
| if (flag_default_inline) |
| DECL_INLINE (fndecl) = 1; |
| |
| if (processing_template_decl) |
| fndecl = push_template_decl (fndecl); |
| |
| /* We read in the parameters on the maybepermanent_obstack, |
| but we won't be getting back to them until after we |
| may have clobbered them. So the call to preserve_data |
| will keep them safe. */ |
| preserve_data (); |
| |
| if (! DECL_FRIEND_P (fndecl)) |
| { |
| if (TREE_CHAIN (fndecl)) |
| { |
| fndecl = copy_node (fndecl); |
| TREE_CHAIN (fndecl) = NULL_TREE; |
| } |
| |
| if (DECL_CONSTRUCTOR_P (fndecl)) |
| { |
| if (! grok_ctor_properties (current_class_type, fndecl)) |
| return void_type_node; |
| } |
| else if (IDENTIFIER_OPNAME_P (DECL_NAME (fndecl))) |
| grok_op_properties (fndecl, DECL_VIRTUAL_P (fndecl), 0); |
| } |
| |
| cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0, 0); |
| |
| /* Make a place for the parms */ |
| pushlevel (0); |
| current_binding_level->parm_flag = 1; |
| |
| DECL_IN_AGGR_P (fndecl) = 1; |
| return fndecl; |
| } |
| |
| /* Go through the motions of finishing a function definition. |
| We don't compile this method until after the whole class has |
| been processed. |
| |
| FINISH_METHOD must return something that looks as though it |
| came from GROKFIELD (since we are defining a method, after all). |
| |
| This is called after parsing the body of the function definition. |
| STMTS is the chain of statements that makes up the function body. |
| |
| DECL is the ..._DECL that `start_method' provided. */ |
| |
| tree |
| finish_method (decl) |
| tree decl; |
| { |
| register tree fndecl = decl; |
| tree old_initial; |
| |
| register tree link; |
| |
| if (decl == void_type_node) |
| return decl; |
| |
| old_initial = DECL_INITIAL (fndecl); |
| |
| /* Undo the level for the parms (from start_method). |
| This is like poplevel, but it causes nothing to be |
| saved. Saving information here confuses symbol-table |
| output routines. Besides, this information will |
| be correctly output when this method is actually |
| compiled. */ |
| |
| /* Clear out the meanings of the local variables of this level; |
| also record in each decl which block it belongs to. */ |
| |
| for (link = current_binding_level->names; link; link = TREE_CHAIN (link)) |
| { |
| if (DECL_NAME (link) != NULL_TREE) |
| IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0; |
| my_friendly_assert (TREE_CODE (link) != FUNCTION_DECL, 163); |
| DECL_CONTEXT (link) = NULL_TREE; |
| } |
| |
| /* Restore all name-meanings of the outer levels |
| that were shadowed by this level. */ |
| |
| for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) |
| IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); |
| for (link = current_binding_level->class_shadowed; |
| link; link = TREE_CHAIN (link)) |
| IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); |
| for (link = current_binding_level->type_shadowed; |
| link; link = TREE_CHAIN (link)) |
| SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link)); |
| |
| GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level, |
| (HOST_WIDE_INT) current_binding_level->level_chain, |
| current_binding_level->parm_flag, |
| current_binding_level->keep); |
| |
| poplevel (0, 0, 0); |
| |
| DECL_INITIAL (fndecl) = old_initial; |
| |
| /* We used to check if the context of FNDECL was different from |
| current_class_type as another way to get inside here. This didn't work |
| for String.cc in libg++. */ |
| if (DECL_FRIEND_P (fndecl)) |
| { |
| CLASSTYPE_INLINE_FRIENDS (current_class_type) |
| = tree_cons (NULL_TREE, fndecl, CLASSTYPE_INLINE_FRIENDS (current_class_type)); |
| decl = void_type_node; |
| } |
| |
| return decl; |
| } |
| |
| /* Called when a new struct TYPE is defined. |
| If this structure or union completes the type of any previous |
| variable declaration, lay it out and output its rtl. */ |
| |
| void |
| hack_incomplete_structures (type) |
| tree type; |
| { |
| tree *list; |
| |
| if (current_binding_level->incomplete == NULL_TREE) |
| return; |
| |
| if (!type) /* Don't do this for class templates. */ |
| return; |
| |
| for (list = ¤t_binding_level->incomplete; *list; ) |
| { |
| tree decl = TREE_VALUE (*list); |
| if ((decl && TREE_TYPE (decl) == type) |
| || (TREE_TYPE (decl) |
| && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE |
| && TREE_TYPE (TREE_TYPE (decl)) == type)) |
| { |
| int toplevel = toplevel_bindings_p (); |
| if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE |
| && TREE_TYPE (TREE_TYPE (decl)) == type) |
| layout_type (TREE_TYPE (decl)); |
| layout_decl (decl, 0); |
| rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0); |
| if (! toplevel) |
| { |
| tree cleanup; |
| expand_decl (decl); |
| cleanup = maybe_build_cleanup (decl); |
| expand_decl_init (decl); |
| if (! expand_decl_cleanup (decl, cleanup)) |
| cp_error ("parser lost in parsing declaration of `%D'", |
| decl); |
| } |
| *list = TREE_CHAIN (*list); |
| } |
| else |
| list = &TREE_CHAIN (*list); |
| } |
| } |
| |
| /* If DECL is of a type which needs a cleanup, build that cleanup here. |
| See build_delete for information about AUTO_DELETE. |
| |
| Don't build these on the momentary obstack; they must live |
| the life of the binding contour. */ |
| |
| static tree |
| maybe_build_cleanup_1 (decl, auto_delete) |
| tree decl, auto_delete; |
| { |
| tree type = TREE_TYPE (decl); |
| if (TYPE_NEEDS_DESTRUCTOR (type)) |
| { |
| int temp = 0, flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; |
| tree rval; |
| |
| if (TREE_CODE (decl) != PARM_DECL) |
| temp = suspend_momentary (); |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| rval = decl; |
| else |
| { |
| mark_addressable (decl); |
| rval = build_unary_op (ADDR_EXPR, decl, 0); |
| } |
| |
| /* Optimize for space over speed here. */ |
| if (! TYPE_USES_VIRTUAL_BASECLASSES (type) |
| || flag_expensive_optimizations) |
| flags |= LOOKUP_NONVIRTUAL; |
| |
| rval = build_delete (TREE_TYPE (rval), rval, auto_delete, flags, 0); |
| |
| if (TYPE_USES_VIRTUAL_BASECLASSES (type) |
| && ! TYPE_HAS_DESTRUCTOR (type)) |
| rval = build_compound_expr (expr_tree_cons (NULL_TREE, rval, |
| build_expr_list (NULL_TREE, build_vbase_delete (type, decl)))); |
| |
| if (TREE_CODE (decl) != PARM_DECL) |
| resume_momentary (temp); |
| |
| return rval; |
| } |
| return 0; |
| } |
| |
| /* If DECL is of a type which needs a cleanup, build that cleanup |
| here. The cleanup does free the storage with a call to delete. */ |
| |
| tree |
| maybe_build_cleanup_and_delete (decl) |
| tree decl; |
| { |
| return maybe_build_cleanup_1 (decl, integer_three_node); |
| } |
| |
| /* If DECL is of a type which needs a cleanup, build that cleanup |
| here. The cleanup does not free the storage with a call a delete. */ |
| |
| tree |
| maybe_build_cleanup (decl) |
| tree decl; |
| { |
| return maybe_build_cleanup_1 (decl, integer_two_node); |
| } |
| |
| /* Expand a C++ expression at the statement level. |
| This is needed to ferret out nodes which have UNKNOWN_TYPE. |
| The C++ type checker should get all of these out when |
| expressions are combined with other, type-providing, expressions, |
| leaving only orphan expressions, such as: |
| |
| &class::bar; / / takes its address, but does nothing with it. */ |
| |
| void |
| cplus_expand_expr_stmt (exp) |
| tree exp; |
| { |
| if (processing_template_decl) |
| { |
| add_tree (build_min_nt (EXPR_STMT, exp)); |
| return; |
| } |
| |
| /* Arrange for all temps to disappear. */ |
| expand_start_target_temps (); |
| |
| if (TREE_TYPE (exp) == unknown_type_node) |
| { |
| if (TREE_CODE (exp) == ADDR_EXPR || TREE_CODE (exp) == TREE_LIST) |
| error ("address of overloaded function with no contextual type information"); |
| else if (TREE_CODE (exp) == COMPONENT_REF) |
| warning ("useless reference to a member function name, did you forget the ()?"); |
| } |
| else |
| { |
| if (TREE_CODE (exp) == FUNCTION_DECL) |
| { |
| cp_warning ("reference, not call, to function `%D'", exp); |
| warning ("at this point in file"); |
| } |
| |
| #if 0 |
| /* We should do this eventually, but right now this causes regex.o from |
| libg++ to miscompile, and tString to core dump. */ |
| exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); |
| #endif |
| |
| /* Strip unused implicit INDIRECT_REFs of references. */ |
| if (TREE_CODE (exp) == INDIRECT_REF |
| && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE) |
| exp = TREE_OPERAND (exp, 0); |
| |
| /* If we don't do this, we end up down inside expand_expr |
| trying to do TYPE_MODE on the ERROR_MARK, and really |
| go outside the bounds of the type. */ |
| if (exp != error_mark_node) |
| expand_expr_stmt (break_out_cleanups (exp)); |
| } |
| |
| /* Clean up any pending cleanups. This happens when a function call |
| returns a cleanup-needing value that nobody uses. */ |
| expand_end_target_temps (); |
| } |
| |
| /* When a stmt has been parsed, this function is called. |
| |
| Currently, this function only does something within a |
| constructor's scope: if a stmt has just assigned to this, |
| and we are in a derived class, we call `emit_base_init'. */ |
| |
| void |
| finish_stmt () |
| { |
| extern struct nesting *cond_stack, *loop_stack, *case_stack; |
| |
| |
| if (current_function_assigns_this |
| || ! current_function_just_assigned_this) |
| return; |
| if (DECL_CONSTRUCTOR_P (current_function_decl)) |
| { |
| /* Constructors must wait until we are out of control |
| zones before calling base constructors. */ |
| if (cond_stack || loop_stack || case_stack) |
| return; |
| expand_expr_stmt (base_init_expr); |
| check_base_init (current_class_type); |
| } |
| current_function_assigns_this = 1; |
| } |
| |
| /* Change a static member function definition into a FUNCTION_TYPE, instead |
| of the METHOD_TYPE that we create when it's originally parsed. |
| |
| WARNING: DO NOT pass &TREE_TYPE (decl) to FN or &TYPE_ARG_TYPES |
| (TREE_TYPE (decl)) to ARGTYPES, as doing so will corrupt the types of |
| other decls. Either pass the addresses of local variables or NULL. */ |
| |
| void |
| revert_static_member_fn (decl, fn, argtypes) |
| tree *decl, *fn, *argtypes; |
| { |
| tree tmp; |
| tree function = fn ? *fn : TREE_TYPE (*decl); |
| tree args = argtypes ? *argtypes : TYPE_ARG_TYPES (function); |
| |
| if (TYPE_READONLY (TREE_TYPE (TREE_VALUE (args)))) |
| cp_error ("static member function `%#D' declared const", *decl); |
| if (TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (args)))) |
| cp_error ("static member function `%#D' declared volatile", *decl); |
| |
| args = TREE_CHAIN (args); |
| tmp = build_function_type (TREE_TYPE (function), args); |
| tmp = build_type_variant (tmp, TYPE_READONLY (function), |
| TYPE_VOLATILE (function)); |
| tmp = build_exception_variant (tmp, |
| TYPE_RAISES_EXCEPTIONS (function)); |
| TREE_TYPE (*decl) = tmp; |
| if (DECL_ARGUMENTS (*decl)) |
| DECL_ARGUMENTS (*decl) = TREE_CHAIN (DECL_ARGUMENTS (*decl)); |
| DECL_STATIC_FUNCTION_P (*decl) = 1; |
| if (fn) |
| *fn = tmp; |
| if (argtypes) |
| *argtypes = args; |
| } |
| |
| int |
| id_in_current_class (id) |
| tree id; |
| { |
| return !!purpose_member (id, class_binding_level->class_shadowed); |
| } |
| |
| struct cp_function |
| { |
| int returns_value; |
| int returns_null; |
| int warn_about_return_type; |
| int assigns_this; |
| int just_assigned_this; |
| int parms_stored; |
| int temp_name_counter; |
| tree named_labels; |
| tree shadowed_labels; |
| tree ctor_label; |
| tree dtor_label; |
| rtx last_dtor_insn; |
| rtx last_parm_cleanup_insn; |
| tree base_init_list; |
| tree member_init_list; |
| tree base_init_expr; |
| tree current_class_ptr; |
| tree current_class_ref; |
| rtx result_rtx; |
| struct cp_function *next; |
| struct binding_level *binding_level; |
| int static_labelno; |
| }; |
| |
| static struct cp_function *cp_function_chain; |
| |
| extern int temp_name_counter; |
| |
| /* Save and reinitialize the variables |
| used during compilation of a C++ function. */ |
| |
| void |
| push_cp_function_context (context) |
| tree context; |
| { |
| struct cp_function *p |
| = (struct cp_function *) xmalloc (sizeof (struct cp_function)); |
| |
| push_function_context_to (context); |
| |
| p->next = cp_function_chain; |
| cp_function_chain = p; |
| |
| p->named_labels = named_labels; |
| p->shadowed_labels = shadowed_labels; |
| p->returns_value = current_function_returns_value; |
| p->returns_null = current_function_returns_null; |
| p->warn_about_return_type = warn_about_return_type; |
| p->binding_level = current_binding_level; |
| p->ctor_label = ctor_label; |
| p->dtor_label = dtor_label; |
| p->last_dtor_insn = last_dtor_insn; |
| p->last_parm_cleanup_insn = last_parm_cleanup_insn; |
| p->assigns_this = current_function_assigns_this; |
| p->just_assigned_this = current_function_just_assigned_this; |
| p->parms_stored = current_function_parms_stored; |
| p->result_rtx = original_result_rtx; |
| p->base_init_expr = base_init_expr; |
| p->temp_name_counter = temp_name_counter; |
| p->base_init_list = current_base_init_list; |
| p->member_init_list = current_member_init_list; |
| p->current_class_ptr = current_class_ptr; |
| p->current_class_ref = current_class_ref; |
| p->static_labelno = static_labelno; |
| } |
| |
| /* Restore the variables used during compilation of a C++ function. */ |
| |
| void |
| pop_cp_function_context (context) |
| tree context; |
| { |
| struct cp_function *p = cp_function_chain; |
| tree link; |
| |
| /* Bring back all the labels that were shadowed. */ |
| for (link = shadowed_labels; link; link = TREE_CHAIN (link)) |
| if (DECL_NAME (TREE_VALUE (link)) != 0) |
| SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)), |
| TREE_VALUE (link)); |
| |
| pop_function_context_from (context); |
| |
| cp_function_chain = p->next; |
| |
| named_labels = p->named_labels; |
| shadowed_labels = p->shadowed_labels; |
| current_function_returns_value = p->returns_value; |
| current_function_returns_null = p->returns_null; |
| warn_about_return_type = p->warn_about_return_type; |
| current_binding_level = p->binding_level; |
| ctor_label = p->ctor_label; |
| dtor_label = p->dtor_label; |
| last_dtor_insn = p->last_dtor_insn; |
| last_parm_cleanup_insn = p->last_parm_cleanup_insn; |
| current_function_assigns_this = p->assigns_this; |
| current_function_just_assigned_this = p->just_assigned_this; |
| current_function_parms_stored = p->parms_stored; |
| original_result_rtx = p->result_rtx; |
| base_init_expr = p->base_init_expr; |
| temp_name_counter = p->temp_name_counter; |
| current_base_init_list = p->base_init_list; |
| current_member_init_list = p->member_init_list; |
| current_class_ptr = p->current_class_ptr; |
| current_class_ref = p->current_class_ref; |
| static_labelno = p->static_labelno; |
| |
| free (p); |
| } |
| |
| int |
| in_function_p () |
| { |
| return function_depth != 0; |
| } |