| /* Process declarations and variables for C++ compiler. |
| Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
| 2001, 2002, 2003, 2004 Free Software Foundation, Inc. |
| Contributed by Michael Tiemann (tiemann@cygnus.com) |
| |
| This file is part of GCC. |
| |
| GCC 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. |
| |
| GCC 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 GCC; 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 "coretypes.h" |
| #include "tm.h" |
| #include "tree.h" |
| #include "rtl.h" |
| #include "expr.h" |
| #include "flags.h" |
| #include "cp-tree.h" |
| #include "tree-inline.h" |
| #include "decl.h" |
| #include "lex.h" |
| #include "output.h" |
| #include "except.h" |
| #include "toplev.h" |
| #include "hashtab.h" |
| #include "tm_p.h" |
| #include "target.h" |
| #include "c-common.h" |
| #include "c-pragma.h" |
| #include "diagnostic.h" |
| #include "debug.h" |
| #include "timevar.h" |
| |
| static tree grokparms (tree, tree *); |
| static const char *redeclaration_error_message (tree, tree); |
| |
| static int decl_jump_unsafe (tree); |
| static void require_complete_types_for_parms (tree); |
| static int ambi_op_p (enum tree_code); |
| static int unary_op_p (enum tree_code); |
| static void push_local_name (tree); |
| static tree grok_reference_init (tree, tree, tree, tree *); |
| static tree grokfndecl (tree, tree, tree, tree, tree, int, |
| enum overload_flags, tree, |
| tree, int, int, int, int, int, int, tree); |
| static tree grokvardecl (tree, tree, RID_BIT_TYPE *, int, int, tree); |
| static void record_unknown_type (tree, const char *); |
| static tree builtin_function_1 (const char *, tree, tree, int, |
| enum built_in_class, const char *, |
| tree); |
| static tree build_library_fn_1 (tree, enum tree_code, tree); |
| static int member_function_or_else (tree, tree, enum overload_flags); |
| static void bad_specifiers (tree, const char *, int, int, int, int, |
| int); |
| static void check_for_uninitialized_const_var (tree); |
| static hashval_t typename_hash (const void *); |
| static int typename_compare (const void *, const void *); |
| static tree local_variable_p_walkfn (tree *, int *, void *); |
| static tree record_builtin_java_type (const char *, int); |
| static const char *tag_name (enum tag_types code); |
| static int walk_namespaces_r (tree, walk_namespaces_fn, void *); |
| static int walk_globals_r (tree, void*); |
| static int walk_vtables_r (tree, void*); |
| static tree make_label_decl (tree, int); |
| static void use_label (tree); |
| static void check_previous_goto_1 (tree, struct cp_binding_level *, tree, |
| const location_t *); |
| static void check_previous_goto (struct named_label_use_list *); |
| static void check_switch_goto (struct cp_binding_level *); |
| static void check_previous_gotos (tree); |
| static void pop_label (tree, tree); |
| static void pop_labels (tree); |
| static void maybe_deduce_size_from_array_init (tree, tree); |
| static void layout_var_decl (tree); |
| static void maybe_commonize_var (tree); |
| static tree check_initializer (tree, tree, int, tree *); |
| static void make_rtl_for_nonlocal_decl (tree, tree, const char *); |
| static void save_function_data (tree); |
| static void check_function_type (tree, tree); |
| static void begin_constructor_body (void); |
| static void finish_constructor_body (void); |
| static void begin_destructor_body (void); |
| static void finish_destructor_body (void); |
| static tree create_array_type_for_decl (tree, tree, tree); |
| static tree get_atexit_node (void); |
| static tree get_dso_handle_node (void); |
| static tree start_cleanup_fn (void); |
| static void end_cleanup_fn (void); |
| static tree cp_make_fname_decl (tree, int); |
| static void initialize_predefined_identifiers (void); |
| static tree check_special_function_return_type |
| (special_function_kind, tree, tree); |
| static tree push_cp_library_fn (enum tree_code, tree); |
| static tree build_cp_library_fn (tree, enum tree_code, tree); |
| static void store_parm_decls (tree); |
| static int cp_missing_noreturn_ok_p (tree); |
| static void initialize_local_var (tree, tree); |
| static void expand_static_init (tree, tree); |
| static tree next_initializable_field (tree); |
| static tree reshape_init (tree, tree *); |
| static tree build_typename_type (tree, tree, tree); |
| |
| /* Erroneous argument lists can use this *IFF* they do not modify it. */ |
| tree error_mark_list; |
| |
| /* The following symbols are subsumed in the cp_global_trees array, and |
| listed here individually for documentation purposes. |
| |
| C++ extensions |
| tree wchar_decl_node; |
| |
| tree vtable_entry_type; |
| tree delta_type_node; |
| tree __t_desc_type_node; |
| tree ti_desc_type_node; |
| tree bltn_desc_type_node, ptr_desc_type_node; |
| tree ary_desc_type_node, func_desc_type_node, enum_desc_type_node; |
| tree class_desc_type_node, si_class_desc_type_node, vmi_class_desc_type_node; |
| tree ptm_desc_type_node; |
| tree base_desc_type_node; |
| |
| tree class_type_node; |
| tree unknown_type_node; |
| |
| Array type `vtable_entry_type[]' |
| |
| tree vtbl_type_node; |
| tree vtbl_ptr_type_node; |
| |
| Namespaces, |
| |
| tree std_node; |
| tree abi_node; |
| |
| 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; |
| |
| The FUNCTION_DECL for the default `::operator delete'. |
| |
| tree global_delete_fndecl; |
| |
| Used by RTTI |
| tree type_info_type_node, tinfo_decl_id, tinfo_decl_type; |
| tree tinfo_var_id; |
| |
| */ |
| |
| tree cp_global_trees[CPTI_MAX]; |
| |
| /* Indicates that there is a type value in some namespace, although |
| that is not necessarily in scope at the moment. */ |
| |
| tree global_type_node; |
| |
| /* The node that holds the "name" of the global scope. */ |
| tree global_scope_name; |
| |
| /* Used only for jumps to as-yet undefined labels, since jumps to |
| defined labels can have their validity checked immediately. */ |
| |
| struct named_label_use_list GTY(()) |
| { |
| struct cp_binding_level *binding_level; |
| tree names_in_scope; |
| tree label_decl; |
| location_t o_goto_locus; |
| struct named_label_use_list *next; |
| }; |
| |
| #define named_label_uses cp_function_chain->x_named_label_uses |
| |
| #define local_names cp_function_chain->x_local_names |
| |
| /* 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++ */ |
| |
| /* A node for the integer constants 2, and 3. */ |
| |
| tree integer_two_node, integer_three_node; |
| |
| /* A list 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, and so we can check the validity of jumps to these labels. */ |
| |
| struct named_label_list GTY(()) |
| { |
| struct cp_binding_level *binding_level; |
| tree names_in_scope; |
| tree old_value; |
| tree label_decl; |
| tree bad_decls; |
| struct named_label_list *next; |
| unsigned int in_try_scope : 1; |
| unsigned int in_catch_scope : 1; |
| }; |
| |
| #define named_labels cp_function_chain->x_named_labels |
| |
| /* The number of function bodies which we are currently processing. |
| (Zero if we are at namespace scope, one inside the body of a |
| function, two inside the body of a function in a local class, etc.) */ |
| int function_depth; |
| |
| /* States indicating how grokdeclarator() should handle declspecs marked |
| with __attribute__((deprecated)). An object declared as |
| __attribute__((deprecated)) suppresses warnings of uses of other |
| deprecated items. */ |
| |
| enum deprecated_states { |
| DEPRECATED_NORMAL, |
| DEPRECATED_SUPPRESS |
| }; |
| |
| static enum deprecated_states deprecated_state = DEPRECATED_NORMAL; |
| |
| /* Set by add_implicitly_declared_members() to keep those members from |
| being flagged as deprecated or reported as using deprecated |
| types. */ |
| int adding_implicit_members = 0; |
| |
| /* True if a declaration with an `extern' linkage specifier is being |
| processed. */ |
| bool have_extern_spec; |
| |
| |
| /* A TREE_LIST of VAR_DECLs. The TREE_PURPOSE is a RECORD_TYPE or |
| UNION_TYPE; the TREE_VALUE is a VAR_DECL with that type. At the |
| time the VAR_DECL was declared, the type was incomplete. */ |
| |
| static GTY(()) tree incomplete_vars; |
| |
| /* Returns the kind of template specialization we are currently |
| processing, given that it's declaration contained N_CLASS_SCOPES |
| explicit scope qualifications. */ |
| |
| tmpl_spec_kind |
| current_tmpl_spec_kind (int n_class_scopes) |
| { |
| int n_template_parm_scopes = 0; |
| int seen_specialization_p = 0; |
| int innermost_specialization_p = 0; |
| struct cp_binding_level *b; |
| |
| /* Scan through the template parameter scopes. */ |
| for (b = current_binding_level; |
| b->kind == sk_template_parms; |
| b = b->level_chain) |
| { |
| /* If we see a specialization scope inside a parameter scope, |
| then something is wrong. That corresponds to a declaration |
| like: |
| |
| template <class T> template <> ... |
| |
| which is always invalid since [temp.expl.spec] forbids the |
| specialization of a class member template if the enclosing |
| class templates are not explicitly specialized as well. */ |
| if (b->explicit_spec_p) |
| { |
| if (n_template_parm_scopes == 0) |
| innermost_specialization_p = 1; |
| else |
| seen_specialization_p = 1; |
| } |
| else if (seen_specialization_p == 1) |
| return tsk_invalid_member_spec; |
| |
| ++n_template_parm_scopes; |
| } |
| |
| /* Handle explicit instantiations. */ |
| if (processing_explicit_instantiation) |
| { |
| if (n_template_parm_scopes != 0) |
| /* We've seen a template parameter list during an explicit |
| instantiation. For example: |
| |
| template <class T> template void f(int); |
| |
| This is erroneous. */ |
| return tsk_invalid_expl_inst; |
| else |
| return tsk_expl_inst; |
| } |
| |
| if (n_template_parm_scopes < n_class_scopes) |
| /* We've not seen enough template headers to match all the |
| specialized classes present. For example: |
| |
| template <class T> void R<T>::S<T>::f(int); |
| |
| This is invalid; there needs to be one set of template |
| parameters for each class. */ |
| return tsk_insufficient_parms; |
| else if (n_template_parm_scopes == n_class_scopes) |
| /* We're processing a non-template declaration (even though it may |
| be a member of a template class.) For example: |
| |
| template <class T> void S<T>::f(int); |
| |
| The `class T' maches the `S<T>', leaving no template headers |
| corresponding to the `f'. */ |
| return tsk_none; |
| else if (n_template_parm_scopes > n_class_scopes + 1) |
| /* We've got too many template headers. For example: |
| |
| template <> template <class T> void f (T); |
| |
| There need to be more enclosing classes. */ |
| return tsk_excessive_parms; |
| else |
| /* This must be a template. It's of the form: |
| |
| template <class T> template <class U> void S<T>::f(U); |
| |
| This is a specialization if the innermost level was a |
| specialization; otherwise it's just a definition of the |
| template. */ |
| return innermost_specialization_p ? tsk_expl_spec : tsk_template; |
| } |
| |
| /* Exit the current scope. */ |
| |
| void |
| finish_scope (void) |
| { |
| poplevel (0, 0, 0); |
| } |
| |
| /* When a label goes out of scope, check to see if that label was used |
| in a valid manner, and issue any appropriate warnings or errors. */ |
| |
| static void |
| pop_label (tree label, tree old_value) |
| { |
| if (!processing_template_decl) |
| { |
| if (DECL_INITIAL (label) == NULL_TREE) |
| { |
| location_t location; |
| |
| cp_error_at ("label `%D' used but not defined", label); |
| location.file = input_filename; |
| location.line = 0; |
| /* Avoid crashing later. */ |
| define_label (location, DECL_NAME (label)); |
| } |
| else if (warn_unused_label && !TREE_USED (label)) |
| cp_warning_at ("label `%D' defined but not used", label); |
| } |
| |
| SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), old_value); |
| } |
| |
| /* At the end of a function, all labels declared within the function |
| go out of scope. BLOCK is the top-level block for the |
| function. */ |
| |
| static void |
| pop_labels (tree block) |
| { |
| struct named_label_list *link; |
| |
| /* Clear out the definitions of all label names, since their scopes |
| end here. */ |
| for (link = named_labels; link; link = link->next) |
| { |
| pop_label (link->label_decl, link->old_value); |
| /* Put the labels into the "variables" of the top-level block, |
| so debugger can see them. */ |
| TREE_CHAIN (link->label_decl) = BLOCK_VARS (block); |
| BLOCK_VARS (block) = link->label_decl; |
| } |
| |
| named_labels = NULL; |
| } |
| |
| /* Exit a binding level. |
| Pop the level off, and restore the state of the identifier-decl mappings |
| that were in effect when this level was entered. |
| |
| If KEEP == 1, this level had explicit declarations, so |
| and create a "block" (a BLOCK node) for the level |
| to record its declarations and subblocks for symbol table output. |
| |
| If FUNCTIONBODY is nonzero, this level is the body of a function, |
| so create a block as if KEEP were set and also clear out all |
| label names. |
| |
| If REVERSE is nonzero, reverse the order of decls before putting |
| them into the BLOCK. */ |
| |
| tree |
| poplevel (int keep, int reverse, int functionbody) |
| { |
| 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; |
| tree subblocks; |
| tree block = NULL_TREE; |
| tree decl; |
| int leaving_for_scope; |
| scope_kind kind; |
| |
| timevar_push (TV_NAME_LOOKUP); |
| |
| my_friendly_assert (current_binding_level->kind != sk_class, 19990916); |
| |
| real_functionbody = (current_binding_level->kind == sk_cleanup |
| ? ((functionbody = 0), tmp) : functionbody); |
| subblocks = functionbody >= 0 ? current_binding_level->blocks : 0; |
| |
| my_friendly_assert (!current_binding_level->class_shadowed, |
| 19990414); |
| |
| /* We used to use KEEP == 2 to indicate that the new block should go |
| at the beginning of the list of blocks at this binding level, |
| rather than the end. This hack is no longer used. */ |
| my_friendly_assert (keep == 0 || keep == 1, 0); |
| |
| if (current_binding_level->keep) |
| keep = 1; |
| |
| /* Any uses of undefined labels, and any defined labels, now operate |
| under constraints of next binding contour. */ |
| if (cfun && !functionbody) |
| { |
| struct cp_binding_level *level_chain; |
| level_chain = current_binding_level->level_chain; |
| if (level_chain) |
| { |
| struct named_label_use_list *uses; |
| struct named_label_list *labels; |
| for (labels = named_labels; labels; labels = labels->next) |
| if (labels->binding_level == current_binding_level) |
| { |
| tree decl; |
| if (current_binding_level->kind == sk_try) |
| labels->in_try_scope = 1; |
| if (current_binding_level->kind == sk_catch) |
| labels->in_catch_scope = 1; |
| for (decl = labels->names_in_scope; decl; |
| decl = TREE_CHAIN (decl)) |
| if (decl_jump_unsafe (decl)) |
| labels->bad_decls = tree_cons (NULL_TREE, decl, |
| labels->bad_decls); |
| labels->binding_level = level_chain; |
| labels->names_in_scope = level_chain->names; |
| } |
| |
| for (uses = named_label_uses; uses; uses = uses->next) |
| if (uses->binding_level == current_binding_level) |
| { |
| uses->binding_level = level_chain; |
| uses->names_in_scope = level_chain->names; |
| } |
| } |
| } |
| |
| /* 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 (); |
| } |
| } |
| |
| /* When not in function-at-a-time mode, expand_end_bindings will |
| warn about unused variables. But, in function-at-a-time mode |
| expand_end_bindings is not passed the list of variables in the |
| current scope, and therefore no warning is emitted. So, we |
| explicitly warn here. */ |
| if (!processing_template_decl) |
| warn_about_unused_variables (getdecls ()); |
| |
| /* 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; |
| if (keep == 1 || functionbody) |
| block = make_node (BLOCK); |
| if (block != NULL_TREE) |
| { |
| BLOCK_VARS (block) = decls; |
| BLOCK_SUBBLOCKS (block) = subblocks; |
| } |
| |
| /* In each subblock, record that this is its superior. */ |
| if (keep >= 0) |
| for (link = subblocks; link; link = TREE_CHAIN (link)) |
| BLOCK_SUPERCONTEXT (link) = block; |
| |
| /* We still support the old for-scope rules, whereby the variables |
| in a for-init statement were in scope after the for-statement |
| ended. We only use the new rules if flag_new_for_scope is |
| nonzero. */ |
| leaving_for_scope |
| = current_binding_level->kind == sk_for && flag_new_for_scope == 1; |
| |
| /* Remove declarations for all the DECLs in this level. */ |
| for (link = decls; link; link = TREE_CHAIN (link)) |
| { |
| if (leaving_for_scope && TREE_CODE (link) == VAR_DECL |
| && DECL_NAME (link)) |
| { |
| cxx_binding *outer_binding |
| = IDENTIFIER_BINDING (DECL_NAME (link))->previous; |
| tree ns_binding; |
| |
| if (!outer_binding) |
| ns_binding = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (link)); |
| else |
| ns_binding = NULL_TREE; |
| |
| if (outer_binding |
| && outer_binding->scope == current_binding_level->level_chain) |
| /* We have something like: |
| |
| int i; |
| for (int i; ;); |
| |
| and we are leaving the `for' scope. There's no reason to |
| keep the binding of the inner `i' in this case. */ |
| pop_binding (DECL_NAME (link), link); |
| else if ((outer_binding |
| && (TREE_CODE (outer_binding->value) == TYPE_DECL)) |
| || (ns_binding && TREE_CODE (ns_binding) == TYPE_DECL)) |
| /* Here, we have something like: |
| |
| typedef int I; |
| |
| void f () { |
| for (int I; ;); |
| } |
| |
| We must pop the for-scope binding so we know what's a |
| type and what isn't. */ |
| pop_binding (DECL_NAME (link), link); |
| else |
| { |
| /* Mark this VAR_DECL as dead so that we can tell we left it |
| there only for backward compatibility. */ |
| DECL_DEAD_FOR_LOCAL (link) = 1; |
| |
| /* Keep track of what should have happened when we |
| popped the binding. */ |
| if (outer_binding && outer_binding->value) |
| DECL_SHADOWED_FOR_VAR (link) = outer_binding->value; |
| |
| /* Add it to the list of dead variables in the next |
| outermost binding to that we can remove these when we |
| leave that binding. */ |
| current_binding_level->level_chain->dead_vars_from_for |
| = tree_cons (NULL_TREE, link, |
| current_binding_level->level_chain-> |
| dead_vars_from_for); |
| |
| /* Although we don't pop the cxx_binding, we do clear |
| its SCOPE since the scope is going away now. */ |
| IDENTIFIER_BINDING (DECL_NAME (link))->scope = NULL; |
| } |
| } |
| else |
| { |
| /* Remove the binding. */ |
| decl = link; |
| if (TREE_CODE (decl) == TREE_LIST) |
| decl = TREE_VALUE (decl); |
| if (DECL_P (decl)) |
| pop_binding (DECL_NAME (decl), decl); |
| else if (TREE_CODE (decl) == OVERLOAD) |
| pop_binding (DECL_NAME (OVL_FUNCTION (decl)), decl); |
| else |
| abort (); |
| } |
| } |
| |
| /* Remove declarations for any `for' variables from inner scopes |
| that we kept around. */ |
| for (link = current_binding_level->dead_vars_from_for; |
| link; link = TREE_CHAIN (link)) |
| pop_binding (DECL_NAME (TREE_VALUE (link)), TREE_VALUE (link)); |
| |
| /* Restore the IDENTIFIER_TYPE_VALUEs. */ |
| for (link = current_binding_level->type_shadowed; |
| link; link = TREE_CHAIN (link)) |
| SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link)); |
| |
| /* Restore the IDENTIFIER_LABEL_VALUEs for local labels. */ |
| for (link = current_binding_level->shadowed_labels; |
| link; |
| link = TREE_CHAIN (link)) |
| pop_label (TREE_VALUE (link), TREE_PURPOSE (link)); |
| |
| /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs |
| list if a `using' declaration put them there. The debugging |
| back-ends won't understand OVERLOAD, so we remove them here. |
| Because the BLOCK_VARS are (temporarily) shared with |
| CURRENT_BINDING_LEVEL->NAMES we must do this fixup after we have |
| popped all the bindings. */ |
| if (block) |
| { |
| tree* d; |
| |
| for (d = &BLOCK_VARS (block); *d; ) |
| { |
| if (TREE_CODE (*d) == TREE_LIST) |
| *d = TREE_CHAIN (*d); |
| else |
| d = &TREE_CHAIN (*d); |
| } |
| } |
| |
| /* If the level being exited is the top level of a function, |
| check over all the labels. */ |
| if (functionbody) |
| { |
| /* Since 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; |
| pop_labels (block); |
| } |
| |
| kind = current_binding_level->kind; |
| |
| leave_scope (); |
| if (functionbody) |
| DECL_INITIAL (current_function_decl) = block; |
| else if (block) |
| current_binding_level->blocks |
| = chainon (current_binding_level->blocks, block); |
| |
| /* If we did not make a block for the level just exited, |
| any blocks made for inner levels |
| (since they cannot be recorded as subblocks in that level) |
| must be carried forward so they will later become subblocks |
| of something else. */ |
| else if (subblocks) |
| current_binding_level->blocks |
| = chainon (current_binding_level->blocks, subblocks); |
| |
| /* 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; |
| |
| /* Take care of compiler's internal binding structures. */ |
| if (kind == sk_cleanup) |
| { |
| tree scope_stmts; |
| |
| scope_stmts |
| = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/1); |
| if (block) |
| { |
| SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block; |
| SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block; |
| } |
| |
| block = poplevel (keep, reverse, functionbody); |
| } |
| |
| POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, 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 (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 (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 (tree block ATTRIBUTE_UNUSED ) |
| { |
| /* The RTL expansion machinery requires us to provide this callback, |
| but it is not applicable in function-at-a-time mode. */ |
| } |
| |
| /* Returns nonzero if T is a virtual function table. */ |
| |
| int |
| vtable_decl_p (tree t, void* data ATTRIBUTE_UNUSED ) |
| { |
| return (TREE_CODE (t) == VAR_DECL && DECL_VIRTUAL_P (t)); |
| } |
| |
| /* Returns nonzero if T is a TYPE_DECL for a type with virtual |
| functions. */ |
| |
| int |
| vtype_decl_p (tree t, void *data ATTRIBUTE_UNUSED ) |
| { |
| return (TREE_CODE (t) == TYPE_DECL |
| && TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE |
| && TYPE_POLYMORPHIC_P (TREE_TYPE (t))); |
| } |
| |
| struct walk_globals_data { |
| walk_globals_pred p; |
| walk_globals_fn f; |
| void *data; |
| }; |
| |
| /* Walk the vtable declarations in NAMESPACE. Whenever one is found |
| for which P returns nonzero, call F with its address. If any call |
| to F returns a nonzero value, return a nonzero value. */ |
| |
| static int |
| walk_vtables_r (tree namespace, void* data) |
| { |
| struct walk_globals_data* wgd = (struct walk_globals_data *) data; |
| walk_globals_fn f = wgd->f; |
| void *d = wgd->data; |
| tree decl = NAMESPACE_LEVEL (namespace)->vtables; |
| int result = 0; |
| |
| for (; decl ; decl = TREE_CHAIN (decl)) |
| result |= (*f) (&decl, d); |
| |
| return result; |
| } |
| |
| /* Walk the vtable declarations. Whenever one is found for which P |
| returns nonzero, call F with its address. If any call to F |
| returns a nonzero value, return a nonzero value. */ |
| bool |
| walk_vtables (walk_globals_pred p, walk_globals_fn f, void *data) |
| { |
| struct walk_globals_data wgd; |
| wgd.p = p; |
| wgd.f = f; |
| wgd.data = data; |
| |
| return walk_namespaces (walk_vtables_r, &wgd); |
| } |
| |
| /* Walk all the namespaces contained NAMESPACE, including NAMESPACE |
| itself, calling F for each. The DATA is passed to F as well. */ |
| |
| static int |
| walk_namespaces_r (tree namespace, walk_namespaces_fn f, void* data) |
| { |
| int result = 0; |
| tree current = NAMESPACE_LEVEL (namespace)->namespaces; |
| |
| result |= (*f) (namespace, data); |
| |
| for (; current; current = TREE_CHAIN (current)) |
| result |= walk_namespaces_r (current, f, data); |
| |
| return result; |
| } |
| |
| /* Walk all the namespaces, calling F for each. The DATA is passed to |
| F as well. */ |
| |
| int |
| walk_namespaces (walk_namespaces_fn f, void* data) |
| { |
| return walk_namespaces_r (global_namespace, f, data); |
| } |
| |
| /* Walk the global declarations in NAMESPACE. Whenever one is found |
| for which P returns nonzero, call F with its address. If any call |
| to F returns a nonzero value, return a nonzero value. */ |
| |
| static int |
| walk_globals_r (tree namespace, void* data) |
| { |
| struct walk_globals_data* wgd = (struct walk_globals_data *) data; |
| walk_globals_pred p = wgd->p; |
| walk_globals_fn f = wgd->f; |
| void *d = wgd->data; |
| tree *t; |
| int result = 0; |
| |
| t = &NAMESPACE_LEVEL (namespace)->names; |
| |
| while (*t) |
| { |
| tree glbl = *t; |
| |
| if ((*p) (glbl, d)) |
| result |= (*f) (t, d); |
| |
| /* If F changed *T, then *T still points at the next item to |
| examine. */ |
| if (*t == glbl) |
| t = &TREE_CHAIN (*t); |
| } |
| |
| return result; |
| } |
| |
| /* Walk the global declarations. Whenever one is found for which P |
| returns true, call F with its address. If any call to F |
| returns true, return true. */ |
| |
| bool |
| walk_globals (walk_globals_pred p, walk_globals_fn f, void *data) |
| { |
| struct walk_globals_data wgd; |
| wgd.p = p; |
| wgd.f = f; |
| wgd.data = data; |
| |
| return walk_namespaces (walk_globals_r, &wgd); |
| } |
| |
| /* Call wrapup_globals_declarations for the globals in NAMESPACE. If |
| DATA is non-NULL, this is the last time we will call |
| wrapup_global_declarations for this NAMESPACE. */ |
| |
| int |
| wrapup_globals_for_namespace (tree namespace, void* data) |
| { |
| struct cp_binding_level *level = NAMESPACE_LEVEL (namespace); |
| varray_type statics = level->static_decls; |
| tree *vec = &VARRAY_TREE (statics, 0); |
| int len = VARRAY_ACTIVE_SIZE (statics); |
| int last_time = (data != 0); |
| |
| if (last_time) |
| { |
| check_global_declarations (vec, len); |
| return 0; |
| } |
| |
| /* Write out any globals that need to be output. */ |
| return wrapup_global_declarations (vec, len); |
| } |
| |
| |
| /* In C++, you don't have to write `struct S' to refer to `S'; you |
| can just use `S'. We accomplish this by creating a TYPE_DECL as |
| if the user had written `typedef struct S S'. Create and return |
| the TYPE_DECL for TYPE. */ |
| |
| tree |
| create_implicit_typedef (tree name, tree type) |
| { |
| tree decl; |
| |
| decl = build_decl (TYPE_DECL, name, type); |
| DECL_ARTIFICIAL (decl) = 1; |
| /* There are other implicit type declarations, like the one *within* |
| a class that allows you to write `S::S'. We must distinguish |
| amongst these. */ |
| SET_DECL_IMPLICIT_TYPEDEF_P (decl); |
| TYPE_NAME (type) = decl; |
| |
| return decl; |
| } |
| |
| /* Remember a local name for name-mangling purposes. */ |
| |
| static void |
| push_local_name (tree decl) |
| { |
| size_t i, nelts; |
| tree t, name; |
| |
| timevar_push (TV_NAME_LOOKUP); |
| if (!local_names) |
| VARRAY_TREE_INIT (local_names, 8, "local_names"); |
| |
| name = DECL_NAME (decl); |
| |
| nelts = VARRAY_ACTIVE_SIZE (local_names); |
| for (i = 0; i < nelts; i++) |
| { |
| t = VARRAY_TREE (local_names, i); |
| if (DECL_NAME (t) == name) |
| { |
| if (!DECL_LANG_SPECIFIC (decl)) |
| retrofit_lang_decl (decl); |
| DECL_LANG_SPECIFIC (decl)->decl_flags.u2sel = 1; |
| if (DECL_LANG_SPECIFIC (t)) |
| DECL_DISCRIMINATOR (decl) = DECL_DISCRIMINATOR (t) + 1; |
| else |
| DECL_DISCRIMINATOR (decl) = 1; |
| |
| VARRAY_TREE (local_names, i) = decl; |
| timevar_pop (TV_NAME_LOOKUP); |
| return; |
| } |
| } |
| |
| VARRAY_PUSH_TREE (local_names, decl); |
| timevar_pop (TV_NAME_LOOKUP); |
| } |
| |
| /* 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 (tree newdecl, tree olddecl) |
| { |
| int types_match; |
| |
| if (newdecl == olddecl) |
| return 1; |
| |
| if (TREE_CODE (newdecl) != TREE_CODE (olddecl)) |
| /* If the two DECLs are not even the same kind of thing, we're not |
| interested in their types. */ |
| return 0; |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| tree f1 = TREE_TYPE (newdecl); |
| tree f2 = TREE_TYPE (olddecl); |
| tree p1 = TYPE_ARG_TYPES (f1); |
| tree p2 = TYPE_ARG_TYPES (f2); |
| |
| if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl) |
| && ! (DECL_EXTERN_C_P (newdecl) |
| && DECL_EXTERN_C_P (olddecl))) |
| return 0; |
| |
| if (TREE_CODE (f1) != TREE_CODE (f2)) |
| return 0; |
| |
| if (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2))) |
| { |
| if (p2 == NULL_TREE && DECL_EXTERN_C_P (olddecl) |
| && (DECL_BUILT_IN (olddecl) |
| #ifndef NO_IMPLICIT_EXTERN_C |
| || (DECL_IN_SYSTEM_HEADER (newdecl) && !DECL_CLASS_SCOPE_P (newdecl)) |
| || (DECL_IN_SYSTEM_HEADER (olddecl) && !DECL_CLASS_SCOPE_P (olddecl)) |
| #endif |
| )) |
| { |
| types_match = self_promoting_args_p (p1); |
| if (p1 == void_list_node) |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl); |
| } |
| #ifndef NO_IMPLICIT_EXTERN_C |
| else if (p1 == NULL_TREE |
| && (DECL_EXTERN_C_P (olddecl) |
| && DECL_IN_SYSTEM_HEADER (olddecl) |
| && !DECL_CLASS_SCOPE_P (olddecl)) |
| && (DECL_EXTERN_C_P (newdecl) |
| && DECL_IN_SYSTEM_HEADER (newdecl) |
| && !DECL_CLASS_SCOPE_P (newdecl))) |
| { |
| types_match = self_promoting_args_p (p2); |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl); |
| } |
| #endif |
| else |
| types_match = compparms (p1, p2); |
| } |
| else |
| types_match = 0; |
| } |
| else if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) |
| != TREE_CODE (DECL_TEMPLATE_RESULT (olddecl))) |
| return 0; |
| |
| 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 = same_type_p (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)), |
| TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))); |
| else |
| types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl), |
| DECL_TEMPLATE_RESULT (newdecl)); |
| } |
| else |
| { |
| if (TREE_TYPE (newdecl) == error_mark_node) |
| types_match = TREE_TYPE (olddecl) == error_mark_node; |
| else if (TREE_TYPE (olddecl) == NULL_TREE) |
| types_match = TREE_TYPE (newdecl) == NULL_TREE; |
| else if (TREE_TYPE (newdecl) == NULL_TREE) |
| types_match = 0; |
| else |
| types_match = comptypes (TREE_TYPE (newdecl), |
| TREE_TYPE (olddecl), |
| COMPARE_REDECLARATION); |
| } |
| |
| return types_match; |
| } |
| |
| /* If NEWDECL is `static' and an `extern' was seen previously, |
| warn about it. OLDDECL is the previous declaration. |
| |
| 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. */ |
| |
| void |
| warn_extern_redeclared_static (tree newdecl, tree olddecl) |
| { |
| static const char *const explicit_extern_static_warning |
| = "`%D' was declared `extern' and later `static'"; |
| static const char *const implicit_extern_static_warning |
| = "`%D' was declared implicitly `extern' and later `static'"; |
| |
| tree name; |
| |
| if (TREE_CODE (newdecl) == TYPE_DECL |
| || TREE_CODE (newdecl) == TEMPLATE_DECL |
| || TREE_CODE (newdecl) == CONST_DECL |
| || TREE_CODE (newdecl) == NAMESPACE_DECL) |
| return; |
| |
| /* Don't get confused by static member functions; that's a different |
| use of `static'. */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_STATIC_FUNCTION_P (newdecl)) |
| return; |
| |
| /* If the old declaration was `static', or the new one isn't, then |
| then everything is OK. */ |
| if (DECL_THIS_STATIC (olddecl) || !DECL_THIS_STATIC (newdecl)) |
| return; |
| |
| /* It's OK to declare a builtin function as `static'. */ |
| if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_ARTIFICIAL (olddecl)) |
| return; |
| |
| name = DECL_ASSEMBLER_NAME (newdecl); |
| pedwarn (IDENTIFIER_IMPLICIT_DECL (name) |
| ? implicit_extern_static_warning |
| : explicit_extern_static_warning, newdecl); |
| cp_pedwarn_at ("previous declaration of `%D'", olddecl); |
| } |
| |
| /* If NEWDECL is a redeclaration of OLDDECL, merge the declarations. |
| If the redeclaration is invalid, a diagnostic is issued, and the |
| error_mark_node is returned. Otherwise, OLDDECL is returned. |
| |
| If NEWDECL is not a redeclaration of OLDDECL, NULL_TREE is |
| returned. */ |
| |
| tree |
| duplicate_decls (tree newdecl, tree olddecl) |
| { |
| unsigned olddecl_uid = DECL_UID (olddecl); |
| int olddecl_friend = 0, types_match = 0; |
| int new_defines_function = 0; |
| |
| if (newdecl == olddecl) |
| return olddecl; |
| |
| types_match = decls_match (newdecl, olddecl); |
| |
| /* If either the type of the new decl or the type of the old decl is an |
| error_mark_node, then that implies that we have already issued an |
| error (earlier) for some bogus type specification, and in that case, |
| it is rather pointless to harass the user with yet more error message |
| about the same declaration, so just pretend the types match here. */ |
| if (TREE_TYPE (newdecl) == error_mark_node |
| || TREE_TYPE (olddecl) == error_mark_node) |
| types_match = 1; |
| |
| if (DECL_P (olddecl) |
| && TREE_CODE (newdecl) == FUNCTION_DECL |
| && TREE_CODE (olddecl) == FUNCTION_DECL |
| && (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl))) |
| { |
| if (DECL_DECLARED_INLINE_P (newdecl) |
| && DECL_UNINLINABLE (newdecl) |
| && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) |
| /* Already warned elsewhere. */; |
| else if (DECL_DECLARED_INLINE_P (olddecl) |
| && DECL_UNINLINABLE (olddecl) |
| && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) |
| /* Already warned. */; |
| else if (DECL_DECLARED_INLINE_P (newdecl) |
| && DECL_UNINLINABLE (olddecl) |
| && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) |
| { |
| warning ("%Jfunction '%D' redeclared as inline", newdecl, newdecl); |
| warning ("%Jprevious declaration of '%D' with attribute noinline", |
| olddecl, olddecl); |
| } |
| else if (DECL_DECLARED_INLINE_P (olddecl) |
| && DECL_UNINLINABLE (newdecl) |
| && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) |
| { |
| warning ("%Jfunction '%D' redeclared with attribute noinline", |
| newdecl, newdecl); |
| warning ("%Jprevious declaration of '%D' was inline", |
| olddecl, olddecl); |
| } |
| } |
| |
| /* Check for redeclaration and other discrepancies. */ |
| if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_ARTIFICIAL (olddecl)) |
| { |
| if (TREE_CODE (newdecl) != FUNCTION_DECL) |
| { |
| /* Avoid warnings redeclaring anticipated built-ins. */ |
| if (DECL_ANTICIPATED (olddecl)) |
| return NULL_TREE; |
| |
| /* 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. */ |
| if (! TREE_PUBLIC (newdecl)) |
| { |
| if (warn_shadow) |
| warning ("shadowing %s function `%#D'", |
| DECL_BUILT_IN (olddecl) ? "built-in" : "library", |
| olddecl); |
| /* Discard the old built-in function. */ |
| return NULL_TREE; |
| } |
| /* If the built-in is not ansi, then programs can override |
| it even globally without an error. */ |
| else if (! DECL_BUILT_IN (olddecl)) |
| warning ("library function `%#D' redeclared as non-function `%#D'", |
| olddecl, newdecl); |
| else |
| { |
| error ("declaration of `%#D'", newdecl); |
| error ("conflicts with built-in declaration `%#D'", |
| olddecl); |
| } |
| return NULL_TREE; |
| } |
| else if (!types_match) |
| { |
| /* Avoid warnings redeclaring anticipated built-ins. */ |
| if (DECL_ANTICIPATED (olddecl)) |
| ; /* Do nothing yet. */ |
| else if ((DECL_EXTERN_C_P (newdecl) |
| && DECL_EXTERN_C_P (olddecl)) |
| || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), |
| TYPE_ARG_TYPES (TREE_TYPE (olddecl)))) |
| { |
| /* A near match; override the builtin. */ |
| |
| if (TREE_PUBLIC (newdecl)) |
| { |
| warning ("new declaration `%#D'", newdecl); |
| warning ("ambiguates built-in declaration `%#D'", |
| olddecl); |
| } |
| else if (warn_shadow) |
| warning ("shadowing %s function `%#D'", |
| DECL_BUILT_IN (olddecl) ? "built-in" : "library", |
| olddecl); |
| } |
| else |
| /* Discard the old built-in function. */ |
| return NULL_TREE; |
| |
| /* Replace the old RTL to avoid problems with inlining. */ |
| SET_DECL_RTL (olddecl, DECL_RTL (newdecl)); |
| } |
| /* Even if the types match, prefer the new declarations type |
| for anticipated built-ins, for exception lists, etc... */ |
| else if (DECL_ANTICIPATED (olddecl)) |
| { |
| tree type = TREE_TYPE (newdecl); |
| tree attribs = (*targetm.merge_type_attributes) |
| (TREE_TYPE (olddecl), type); |
| |
| type = cp_build_type_attribute_variant (type, attribs); |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = type; |
| } |
| |
| /* Whether or not the builtin can throw exceptions has no |
| bearing on this declarator. */ |
| TREE_NOTHROW (olddecl) = 0; |
| |
| if (DECL_THIS_STATIC (newdecl) && !DECL_THIS_STATIC (olddecl)) |
| { |
| /* If a builtin function is redeclared as `static', merge |
| the declarations, but make the original one static. */ |
| DECL_THIS_STATIC (olddecl) = 1; |
| TREE_PUBLIC (olddecl) = 0; |
| |
| /* Make the old declaration consistent with the new one so |
| that all remnants of the builtin-ness of this function |
| will be banished. */ |
| SET_DECL_LANGUAGE (olddecl, DECL_LANGUAGE (newdecl)); |
| SET_DECL_RTL (olddecl, DECL_RTL (newdecl)); |
| } |
| } |
| 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 NULL_TREE; |
| } |
| |
| if ((TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_FUNCTION_TEMPLATE_P (olddecl)) |
| || (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_FUNCTION_TEMPLATE_P (newdecl))) |
| return NULL_TREE; |
| |
| 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 NULL_TREE; |
| } |
| else if (!types_match) |
| { |
| if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)) |
| /* These are certainly not duplicate declarations; they're |
| from different scopes. */ |
| return NULL_TREE; |
| |
| 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) |
| { |
| error ("declaration of template `%#D'", newdecl); |
| cp_error_at ("conflicts with previous declaration `%#D'", |
| olddecl); |
| } |
| else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL |
| && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL |
| && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))), |
| TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl)))) |
| && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl), |
| DECL_TEMPLATE_PARMS (olddecl)) |
| /* Template functions can be disambiguated by |
| return type. */ |
| && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)), |
| TREE_TYPE (TREE_TYPE (olddecl)))) |
| { |
| error ("new declaration `%#D'", newdecl); |
| cp_error_at ("ambiguates old declaration `%#D'", olddecl); |
| } |
| return NULL_TREE; |
| } |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl)) |
| { |
| 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)))) |
| { |
| error ("new declaration `%#D'", newdecl); |
| cp_error_at ("ambiguates old declaration `%#D'", olddecl); |
| } |
| else |
| return NULL_TREE; |
| } |
| |
| /* 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) |
| { |
| error ("conflicting declaration '%#D'", newdecl); |
| cp_error_at ("'%D' has a previous declaration as `%#D'", |
| olddecl, olddecl); |
| return NULL_TREE; |
| } |
| } |
| 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 valid, but |
| the declarations must be merged in the usual way. */ |
| return NULL_TREE; |
| 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 NULL_TREE; |
| else if (TREE_CODE (newdecl) == NAMESPACE_DECL) |
| { |
| /* In [namespace.alias] we have: |
| |
| In a declarative region, a namespace-alias-definition can be |
| used to redefine a namespace-alias declared in that declarative |
| region to refer only to the namespace to which it already |
| refers. |
| |
| Therefore, if we encounter a second alias directive for the same |
| alias, we can just ignore the second directive. */ |
| if (DECL_NAMESPACE_ALIAS (newdecl) |
| && (DECL_NAMESPACE_ALIAS (newdecl) |
| == DECL_NAMESPACE_ALIAS (olddecl))) |
| return olddecl; |
| /* [namespace.alias] |
| |
| A namespace-name or namespace-alias shall not be declared as |
| the name of any other entity in the same declarative region. |
| A namespace-name defined at global scope shall not be |
| declared as the name of any other entity in any glogal scope |
| of the program. */ |
| error ("declaration of `namespace %D' conflicts with", newdecl); |
| cp_error_at ("previous declaration of `namespace %D' here", olddecl); |
| return error_mark_node; |
| } |
| else |
| { |
| const char *errmsg = redeclaration_error_message (newdecl, olddecl); |
| if (errmsg) |
| { |
| 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); |
| return error_mark_node; |
| } |
| 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); |
| warning ("%Jfollows 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_depth () == 0) |
| SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); |
| else |
| { |
| cp_error_at ("previous declaration of `%#D' with %L linkage", |
| olddecl, DECL_LANGUAGE (olddecl)); |
| 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))) |
| { |
| pedwarn ("default argument given for parameter %d of `%#D'", |
| i, newdecl); |
| cp_pedwarn_at ("after previous specification in `%#D'", |
| olddecl); |
| } |
| else |
| { |
| error ("default argument given for parameter %d of `%#D'", |
| i, newdecl); |
| cp_error_at ("after previous specification in `%#D'", |
| olddecl); |
| } |
| } |
| |
| if (DECL_DECLARED_INLINE_P (newdecl) |
| && ! DECL_DECLARED_INLINE_P (olddecl) |
| && TREE_ADDRESSABLE (olddecl) && warn_inline) |
| { |
| warning ("`%#D' was used before it was declared inline", newdecl); |
| warning ("%Jprevious non-inline declaration here", olddecl); |
| } |
| } |
| } |
| |
| /* Do not merge an implicit typedef with an explicit one. In: |
| |
| class A; |
| ... |
| typedef class A A __attribute__ ((foo)); |
| |
| the attribute should apply only to the typedef. */ |
| if (TREE_CODE (olddecl) == TYPE_DECL |
| && (DECL_IMPLICIT_TYPEDEF_P (olddecl) |
| || DECL_IMPLICIT_TYPEDEF_P (newdecl))) |
| return NULL_TREE; |
| |
| /* 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); |
| DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl); |
| DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); |
| DECL_PURE_VIRTUAL_P (newdecl) |= DECL_PURE_VIRTUAL_P (olddecl); |
| DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl); |
| DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl); |
| DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl); |
| if (DECL_OVERLOADED_OPERATOR_P (olddecl) != ERROR_MARK) |
| SET_OVERLOADED_OPERATOR_CODE |
| (newdecl, DECL_OVERLOADED_OPERATOR_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) || DECL_FRIEND_P (olddecl))) |
| { |
| 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) |
| { |
| tree newtype = TREE_TYPE (newdecl); |
| tree oldtype = TREE_TYPE (olddecl); |
| |
| if (newtype != error_mark_node && oldtype != error_mark_node |
| && TYPE_LANG_SPECIFIC (newtype) && TYPE_LANG_SPECIFIC (oldtype)) |
| CLASSTYPE_FRIEND_CLASSES (newtype) |
| = CLASSTYPE_FRIEND_CLASSES (oldtype); |
| |
| DECL_ORIGINAL_TYPE (newdecl) = DECL_ORIGINAL_TYPE (olddecl); |
| } |
| |
| /* Copy all the DECL_... slots specified in the new decl |
| except for any that we copy here from the old type. */ |
| DECL_ATTRIBUTES (newdecl) |
| = (*targetm.merge_decl_attributes) (olddecl, newdecl); |
| |
| if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)); |
| DECL_TEMPLATE_SPECIALIZATIONS (olddecl) |
| = chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl), |
| DECL_TEMPLATE_SPECIALIZATIONS (newdecl)); |
| |
| /* If the new declaration is a definition, update the file and |
| line information on the declaration. */ |
| if (DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl)) == NULL_TREE |
| && DECL_INITIAL (DECL_TEMPLATE_RESULT (newdecl)) != NULL_TREE) |
| { |
| DECL_SOURCE_LOCATION (olddecl) |
| = DECL_SOURCE_LOCATION (DECL_TEMPLATE_RESULT (olddecl)) |
| = DECL_SOURCE_LOCATION (newdecl); |
| if (DECL_FUNCTION_TEMPLATE_P (newdecl)) |
| DECL_ARGUMENTS (DECL_TEMPLATE_RESULT (olddecl)) |
| = DECL_ARGUMENTS (DECL_TEMPLATE_RESULT (newdecl)); |
| } |
| |
| if (DECL_FUNCTION_TEMPLATE_P (newdecl)) |
| { |
| DECL_INLINE (DECL_TEMPLATE_RESULT (olddecl)) |
| |= DECL_INLINE (DECL_TEMPLATE_RESULT (newdecl)); |
| DECL_DECLARED_INLINE_P (DECL_TEMPLATE_RESULT (olddecl)) |
| |= DECL_DECLARED_INLINE_P (DECL_TEMPLATE_RESULT (newdecl)); |
| } |
| |
| return olddecl; |
| } |
| |
| if (types_match) |
| { |
| /* Automatically handles default parameters. */ |
| tree oldtype = TREE_TYPE (olddecl); |
| tree newtype; |
| |
| /* Merge the data types specified in the two decls. */ |
| newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); |
| |
| /* If merge_types produces a non-typedef type, just use the old type. */ |
| if (TREE_CODE (newdecl) == TYPE_DECL |
| && newtype == DECL_ORIGINAL_TYPE (newdecl)) |
| newtype = oldtype; |
| |
| if (TREE_CODE (newdecl) == VAR_DECL) |
| { |
| DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl); |
| DECL_INITIALIZED_P (newdecl) |= DECL_INITIALIZED_P (olddecl); |
| DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl) |
| |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl); |
| } |
| |
| /* Do this after calling `merge_types' 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 |
| && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)), |
| TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)), 1)) |
| { |
| error ("declaration of `%F' throws different exceptions", |
| newdecl); |
| cp_error_at ("than previous declaration `%F'", olddecl); |
| } |
| } |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype; |
| |
| /* Lay the type out, unless already done. */ |
| if (! same_type_p (newtype, 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_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); |
| if (CAN_HAVE_FULL_LANG_DECL_P (newdecl) |
| && DECL_LANG_SPECIFIC (newdecl) |
| && DECL_LANG_SPECIFIC (olddecl)) |
| { |
| DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl); |
| DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (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); |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) |
| |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); |
| DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl); |
| TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); |
| TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); |
| TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl); |
| DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); |
| DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl); |
| /* Keep the old RTL. */ |
| COPY_DECL_RTL (olddecl, newdecl); |
| } |
| else if (TREE_CODE (newdecl) == VAR_DECL |
| && (DECL_SIZE (olddecl) || !DECL_SIZE (newdecl))) |
| { |
| /* Keep the old RTL. We cannot keep the old RTL if the old |
| declaration was for an incomplete object and the new |
| declaration is not since many attributes of the RTL will |
| change. */ |
| COPY_DECL_RTL (olddecl, newdecl); |
| } |
| } |
| /* 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. */ |
| merge_weak (newdecl, olddecl); |
| |
| DECL_ONE_ONLY (newdecl) |= DECL_ONE_ONLY (olddecl); |
| DECL_DEFER_OUTPUT (newdecl) |= DECL_DEFER_OUTPUT (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); |
| DECL_TEMPLATE_INSTANTIATED (newdecl) |
| |= DECL_TEMPLATE_INSTANTIATED (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_LANG_SPECIFIC (newdecl)->decl_flags.u2 = |
| DECL_LANG_SPECIFIC (olddecl)->decl_flags.u2; |
| DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl); |
| DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); |
| DECL_INITIALIZED_IN_CLASS_P (newdecl) |
| |= DECL_INITIALIZED_IN_CLASS_P (olddecl); |
| olddecl_friend = DECL_FRIEND_P (olddecl); |
| |
| /* Only functions have DECL_BEFRIENDING_CLASSES. */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL |
| || DECL_FUNCTION_TEMPLATE_P (newdecl)) |
| { |
| DECL_BEFRIENDING_CLASSES (newdecl) |
| = chainon (DECL_BEFRIENDING_CLASSES (newdecl), |
| DECL_BEFRIENDING_CLASSES (olddecl)); |
| /* DECL_THUNKS is only valid for virtual functions, |
| otherwise it is a DECL_FRIEND_CONTEXT. */ |
| if (DECL_VIRTUAL_P (newdecl)) |
| DECL_THUNKS (newdecl) = DECL_THUNKS (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 |
| should 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. */ |
| error ("explicit specialization of %D after first use", |
| olddecl); |
| |
| SET_DECL_TEMPLATE_SPECIALIZATION (olddecl); |
| |
| /* [temp.expl.spec/14] We don't inline explicit specialization |
| just because the primary template says so. */ |
| } |
| else |
| { |
| if (DECL_PENDING_INLINE_INFO (newdecl) == 0) |
| DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl); |
| |
| DECL_DECLARED_INLINE_P (newdecl) |= DECL_DECLARED_INLINE_P (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); |
| |
| DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl) |
| = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)); |
| } |
| |
| /* Preserve abstractness on cloned [cd]tors. */ |
| DECL_ABSTRACT (newdecl) = DECL_ABSTRACT (olddecl); |
| |
| if (! types_match) |
| { |
| SET_DECL_LANGUAGE (olddecl, DECL_LANGUAGE (newdecl)); |
| COPY_DECL_ASSEMBLER_NAME (newdecl, olddecl); |
| SET_DECL_RTL (olddecl, DECL_RTL (newdecl)); |
| } |
| if (! types_match || new_defines_function) |
| { |
| /* These need to be copied so that the names are available. |
| Note that if the types do match, we'll preserve inline |
| info and other bits, but if not, we won't. */ |
| 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. */ |
| SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); |
| else if (types_match) |
| { |
| /* If redeclaring a builtin function, and not a definition, |
| it stays built in. */ |
| if (DECL_BUILT_IN (olddecl)) |
| { |
| DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); |
| DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); |
| /* If we're keeping the built-in definition, keep the rtl, |
| regardless of declaration matches. */ |
| SET_DECL_RTL (newdecl, DECL_RTL (olddecl)); |
| } |
| |
| DECL_RESULT (newdecl) = DECL_RESULT (olddecl); |
| /* Don't clear out the arguments if we're redefining a function. */ |
| if (DECL_ARGUMENTS (olddecl)) |
| DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); |
| } |
| } |
| else 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); |
| COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); |
| |
| /* If either declaration has a nondefault visibility, use it. */ |
| if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT) |
| { |
| if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT |
| && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) |
| { |
| warning ("%J'%D': visibility attribute ignored because it", |
| newdecl, newdecl); |
| warning ("%Jconflicts with previous declaration here", olddecl); |
| } |
| DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); |
| } |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| int function_size; |
| |
| function_size = sizeof (struct tree_decl); |
| |
| memcpy ((char *) olddecl + sizeof (struct tree_common), |
| (char *) newdecl + sizeof (struct tree_common), |
| function_size - sizeof (struct tree_common)); |
| |
| 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. */ |
| reregister_specialization (newdecl, |
| DECL_TI_TEMPLATE (newdecl), |
| olddecl); |
| } |
| else |
| { |
| memcpy ((char *) olddecl + sizeof (struct tree_common), |
| (char *) newdecl + sizeof (struct tree_common), |
| sizeof (struct tree_decl) - sizeof (struct tree_common) |
| + TREE_CODE_LENGTH (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_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl); |
| |
| /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl |
| so that encode_section_info has a chance to look at the new decl |
| flags and attributes. */ |
| if (DECL_RTL_SET_P (olddecl) |
| && (TREE_CODE (olddecl) == FUNCTION_DECL |
| || (TREE_CODE (olddecl) == VAR_DECL |
| && TREE_STATIC (olddecl)))) |
| make_decl_rtl (olddecl, NULL); |
| |
| return olddecl; |
| } |
| |
| /* Generate an implicit declaration for identifier FUNCTIONID |
| as a function of type int (). Print a warning if appropriate. */ |
| |
| tree |
| implicitly_declare (tree functionid) |
| { |
| tree decl; |
| |
| /* 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; |
| |
| /* ISO 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, 0, 0); |
| |
| if (warn_implicit |
| /* Only one warning per identifier. */ |
| && IDENTIFIER_IMPLICIT_DECL (functionid) == NULL_TREE) |
| { |
| pedwarn ("implicit declaration of function `%#D'", decl); |
| } |
| |
| SET_IDENTIFIER_IMPLICIT_DECL (functionid, decl); |
| |
| 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 const char * |
| redeclaration_error_message (tree newdecl, tree olddecl) |
| { |
| if (TREE_CODE (newdecl) == TYPE_DECL) |
| { |
| /* Because C++ can put things into name space for free, |
| constructs like "typedef struct foo { ... } foo" |
| would look like an erroneous redeclaration. */ |
| if (same_type_p (TREE_TYPE (newdecl), TREE_TYPE (olddecl))) |
| return 0; |
| else |
| return "redefinition of `%#D'"; |
| } |
| else if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| /* If this is a pure function, its olddecl will actually be |
| the original initialization to `0' (which we force to call |
| abort()). Don't complain about redefinition in this case. */ |
| if (DECL_LANG_SPECIFIC (olddecl) && DECL_PURE_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) |
| { |
| tree nt, ot; |
| |
| if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) |
| { |
| if (COMPLETE_TYPE_P (TREE_TYPE (newdecl)) |
| && COMPLETE_TYPE_P (TREE_TYPE (olddecl))) |
| return "redefinition of `%#D'"; |
| return NULL; |
| } |
| |
| if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) != FUNCTION_DECL |
| || (DECL_TEMPLATE_RESULT (newdecl) |
| == DECL_TEMPLATE_RESULT (olddecl))) |
| return NULL; |
| |
| nt = DECL_TEMPLATE_RESULT (newdecl); |
| if (DECL_TEMPLATE_INFO (nt)) |
| nt = DECL_TEMPLATE_RESULT (template_for_substitution (nt)); |
| ot = DECL_TEMPLATE_RESULT (olddecl); |
| if (DECL_TEMPLATE_INFO (ot)) |
| ot = DECL_TEMPLATE_RESULT (template_for_substitution (ot)); |
| if (DECL_INITIAL (nt) && DECL_INITIAL (ot)) |
| return "redefinition of `%#D'"; |
| |
| return NULL; |
| } |
| else if (toplevel_bindings_p () || DECL_NAMESPACE_SCOPE_P (newdecl)) |
| { |
| /* 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; |
| } |
| } |
| |
| /* Create a new label, named ID. */ |
| |
| static tree |
| make_label_decl (tree id, int local_p) |
| { |
| tree decl; |
| |
| decl = build_decl (LABEL_DECL, id, void_type_node); |
| |
| DECL_CONTEXT (decl) = current_function_decl; |
| DECL_MODE (decl) = VOIDmode; |
| C_DECLARED_LABEL_FLAG (decl) = local_p; |
| |
| /* Say where one reference is to the label, for the sake of the |
| error if it is not defined. */ |
| DECL_SOURCE_LOCATION (decl) = input_location; |
| |
| /* Record the fact that this identifier is bound to this label. */ |
| SET_IDENTIFIER_LABEL_VALUE (id, decl); |
| |
| return decl; |
| } |
| |
| /* Record this label on the list of used labels so that we can check |
| at the end of the function to see whether or not the label was |
| actually defined, and so we can check when the label is defined whether |
| this use is valid. */ |
| |
| static void |
| use_label (tree decl) |
| { |
| if (named_label_uses == NULL |
| || named_label_uses->names_in_scope != current_binding_level->names |
| || named_label_uses->label_decl != decl) |
| { |
| struct named_label_use_list *new_ent; |
| new_ent = ggc_alloc (sizeof (struct named_label_use_list)); |
| new_ent->label_decl = decl; |
| new_ent->names_in_scope = current_binding_level->names; |
| new_ent->binding_level = current_binding_level; |
| new_ent->o_goto_locus = input_location; |
| new_ent->next = named_label_uses; |
| named_label_uses = new_ent; |
| } |
| } |
| |
| /* Look for a label named ID in the current function. If one cannot |
| be found, create one. (We keep track of used, but undefined, |
| labels, and complain about them at the end of a function.) */ |
| |
| tree |
| lookup_label (tree id) |
| { |
| tree decl; |
| struct named_label_list *ent; |
| |
| timevar_push (TV_NAME_LOOKUP); |
| /* You can't use labels at global scope. */ |
| if (current_function_decl == NULL_TREE) |
| { |
| error ("label `%s' referenced outside of any function", |
| IDENTIFIER_POINTER (id)); |
| POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE); |
| } |
| |
| /* See if we've already got this label. */ |
| decl = IDENTIFIER_LABEL_VALUE (id); |
| if (decl != NULL_TREE && DECL_CONTEXT (decl) == current_function_decl) |
| POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl); |
| |
| /* Record this label on the list of labels used in this function. |
| We do this before calling make_label_decl so that we get the |
| IDENTIFIER_LABEL_VALUE before the new label is declared. */ |
| ent = ggc_alloc_cleared (sizeof (struct named_label_list)); |
| ent->old_value = IDENTIFIER_LABEL_VALUE (id); |
| ent->next = named_labels; |
| named_labels = ent; |
| |
| /* We need a new label. */ |
| decl = make_label_decl (id, /*local_p=*/0); |
| |
| /* Now fill in the information we didn't have before. */ |
| ent->label_decl = decl; |
| |
| POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl); |
| } |
| |
| /* Declare a local label named ID. */ |
| |
| tree |
| declare_local_label (tree id) |
| { |
| tree decl; |
| |
| /* Add a new entry to the SHADOWED_LABELS list so that when we leave |
| this scope we can restore the old value of |
| IDENTIFIER_TYPE_VALUE. */ |
| current_binding_level->shadowed_labels |
| = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE, |
| current_binding_level->shadowed_labels); |
| /* Look for the label. */ |
| decl = make_label_decl (id, /*local_p=*/1); |
| /* Now fill in the information we didn't have before. */ |
| TREE_VALUE (current_binding_level->shadowed_labels) = decl; |
| |
| return decl; |
| } |
| |
| /* Returns nonzero if it is ill-formed to jump past the declaration of |
| DECL. Returns 2 if it's also a real problem. */ |
| |
| static int |
| decl_jump_unsafe (tree decl) |
| { |
| if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl)) |
| return 0; |
| |
| if (DECL_INITIAL (decl) == NULL_TREE |
| && pod_type_p (TREE_TYPE (decl))) |
| return 0; |
| |
| /* This is really only important if we're crossing an initialization. |
| The POD stuff is just pedantry; why should it matter if the class |
| contains a field of pointer to member type? */ |
| if (DECL_INITIAL (decl) |
| || (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))) |
| return 2; |
| return 1; |
| } |
| |
| /* Check that a single previously seen jump to a newly defined label |
| is OK. DECL is the LABEL_DECL or 0; LEVEL is the binding_level for |
| the jump context; NAMES are the names in scope in LEVEL at the jump |
| context; FILE and LINE are the source position of the jump or 0. */ |
| |
| static void |
| check_previous_goto_1 (tree decl, |
| struct cp_binding_level* level, |
| tree names, const location_t *locus) |
| { |
| int identified = 0; |
| int saw_eh = 0; |
| struct cp_binding_level *b = current_binding_level; |
| for (; b; b = b->level_chain) |
| { |
| tree new_decls = b->names; |
| tree old_decls = (b == level ? names : NULL_TREE); |
| for (; new_decls != old_decls; |
| new_decls = TREE_CHAIN (new_decls)) |
| { |
| int problem = decl_jump_unsafe (new_decls); |
| if (! problem) |
| continue; |
| |
| if (! identified) |
| { |
| if (decl) |
| pedwarn ("jump to label `%D'", decl); |
| else |
| pedwarn ("jump to case label"); |
| |
| if (locus) |
| pedwarn ("%H from here", locus); |
| identified = 1; |
| } |
| |
| if (problem > 1) |
| cp_error_at (" crosses initialization of `%#D'", |
| new_decls); |
| else |
| cp_pedwarn_at (" enters scope of non-POD `%#D'", |
| new_decls); |
| } |
| |
| if (b == level) |
| break; |
| if ((b->kind == sk_try || b->kind == sk_catch) && ! saw_eh) |
| { |
| if (! identified) |
| { |
| if (decl) |
| pedwarn ("jump to label `%D'", decl); |
| else |
| pedwarn ("jump to case label"); |
| |
| if (locus) |
| pedwarn ("%H from here", locus); |
| identified = 1; |
| } |
| if (b->kind == sk_try) |
| error (" enters try block"); |
| else |
| error (" enters catch block"); |
| saw_eh = 1; |
| } |
| } |
| } |
| |
| static void |
| check_previous_goto (struct named_label_use_list* use) |
| { |
| check_previous_goto_1 (use->label_decl, use->binding_level, |
| use->names_in_scope, &use->o_goto_locus); |
| } |
| |
| static void |
| check_switch_goto (struct cp_binding_level* level) |
| { |
| check_previous_goto_1 (NULL_TREE, level, level->names, NULL); |
| } |
| |
| /* Check that any previously seen jumps to a newly defined label DECL |
| are OK. Called by define_label. */ |
| |
| static void |
| check_previous_gotos (tree decl) |
| { |
| struct named_label_use_list **usep; |
| |
| if (! TREE_USED (decl)) |
| return; |
| |
| for (usep = &named_label_uses; *usep; ) |
| { |
| struct named_label_use_list *use = *usep; |
| if (use->label_decl == decl) |
| { |
| check_previous_goto (use); |
| *usep = use->next; |
| } |
| else |
| usep = &(use->next); |
| } |
| } |
| |
| /* Check that a new jump to a label DECL is OK. Called by |
| finish_goto_stmt. */ |
| |
| void |
| check_goto (tree decl) |
| { |
| int identified = 0; |
| tree bad; |
| struct named_label_list *lab; |
| |
| /* We can't know where a computed goto is jumping. So we assume |
| that it's OK. */ |
| if (! DECL_P (decl)) |
| return; |
| |
| /* If the label hasn't been defined yet, defer checking. */ |
| if (! DECL_INITIAL (decl)) |
| { |
| use_label (decl); |
| return; |
| } |
| |
| for (lab = named_labels; lab; lab = lab->next) |
| if (decl == lab->label_decl) |
| break; |
| |
| /* If the label is not on named_labels it's a gcc local label, so |
| it must be in an outer scope, so jumping to it is always OK. */ |
| if (lab == 0) |
| return; |
| |
| if ((lab->in_try_scope || lab->in_catch_scope || lab->bad_decls) |
| && !identified) |
| { |
| cp_pedwarn_at ("jump to label `%D'", decl); |
| pedwarn (" from here"); |
| identified = 1; |
| } |
| |
| for (bad = lab->bad_decls; bad; bad = TREE_CHAIN (bad)) |
| { |
| tree b = TREE_VALUE (bad); |
| int u = decl_jump_unsafe (b); |
| |
| if (u > 1 && DECL_ARTIFICIAL (b)) |
| /* Can't skip init of __exception_info. */ |
| error ("%J enters catch block", b); |
| else if (u > 1) |
| cp_error_at (" skips initialization of `%#D'", b); |
| else |
| cp_pedwarn_at (" enters scope of non-POD `%#D'", b); |
| } |
| |
| if (lab->in_try_scope) |
| error (" enters try block"); |
| else if (lab->in_catch_scope) |
| error (" enters catch block"); |
| } |
| |
| /* Define a label, specifying the location in the source file. |
| Return the LABEL_DECL node for the label. */ |
| |
| tree |
| define_label (location_t location, tree name) |
| { |
| tree decl = lookup_label (name); |
| struct named_label_list *ent; |
| struct cp_binding_level *p; |
| |
| timevar_push (TV_NAME_LOOKUP); |
| for (ent = named_labels; ent; ent = ent->next) |
| if (ent->label_decl == decl) |
| break; |
| |
| /* After labels, make any new cleanups in the function go into their |
| own new (temporary) binding contour. */ |
| for (p = current_binding_level; |
| p->kind != sk_function_parms; |
| p = p->level_chain) |
| p->more_cleanups_ok = 0; |
| |
| if (name == get_identifier ("wchar_t")) |
| pedwarn ("label named wchar_t"); |
| |
| if (DECL_INITIAL (decl) != NULL_TREE) |
| error ("duplicate label `%D'", decl); |
| else |
| { |
| /* Mark label as having been defined. */ |
| DECL_INITIAL (decl) = error_mark_node; |
| /* Say where in the source. */ |
| DECL_SOURCE_LOCATION (decl) = location; |
| if (ent) |
| { |
| ent->names_in_scope = current_binding_level->names; |
| ent->binding_level = current_binding_level; |
| } |
| check_previous_gotos (decl); |
| } |
| |
| timevar_pop (TV_NAME_LOOKUP); |
| return decl; |
| } |
| |
| struct cp_switch |
| { |
| struct cp_binding_level *level; |
| struct cp_switch *next; |
| /* The SWITCH_STMT being built. */ |
| tree switch_stmt; |
| /* A splay-tree mapping the low element of a case range to the high |
| element, or NULL_TREE if there is no high element. Used to |
| determine whether or not a new case label duplicates an old case |
| label. We need a tree, rather than simply a hash table, because |
| of the GNU case range extension. */ |
| splay_tree cases; |
| }; |
| |
| /* A stack of the currently active switch statements. The innermost |
| switch statement is on the top of the stack. There is no need to |
| mark the stack for garbage collection because it is only active |
| during the processing of the body of a function, and we never |
| collect at that point. */ |
| |
| static struct cp_switch *switch_stack; |
| |
| /* Called right after a switch-statement condition is parsed. |
| SWITCH_STMT is the switch statement being parsed. */ |
| |
| void |
| push_switch (tree switch_stmt) |
| { |
| struct cp_switch *p = xmalloc (sizeof (struct cp_switch)); |
| p->level = current_binding_level; |
| p->next = switch_stack; |
| p->switch_stmt = switch_stmt; |
| p->cases = splay_tree_new (case_compare, NULL, NULL); |
| switch_stack = p; |
| } |
| |
| void |
| pop_switch (void) |
| { |
| struct cp_switch *cs; |
| |
| cs = switch_stack; |
| splay_tree_delete (cs->cases); |
| switch_stack = switch_stack->next; |
| free (cs); |
| } |
| |
| /* Note that we've seen a definition of a case label, and complain if this |
| is a bad place for one. */ |
| |
| tree |
| finish_case_label (tree low_value, tree high_value) |
| { |
| tree cond, r; |
| struct cp_binding_level *p; |
| |
| if (processing_template_decl) |
| { |
| tree label; |
| |
| /* For templates, just add the case label; we'll do semantic |
| analysis at instantiation-time. */ |
| label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); |
| return add_stmt (build_case_label (low_value, high_value, label)); |
| } |
| |
| /* Find the condition on which this switch statement depends. */ |
| cond = SWITCH_COND (switch_stack->switch_stmt); |
| if (cond && TREE_CODE (cond) == TREE_LIST) |
| cond = TREE_VALUE (cond); |
| |
| r = c_add_case_label (switch_stack->cases, cond, low_value, high_value); |
| |
| check_switch_goto (switch_stack->level); |
| |
| /* After labels, make any new cleanups in the function go into their |
| own new (temporary) binding contour. */ |
| for (p = current_binding_level; |
| p->kind != sk_function_parms; |
| p = p->level_chain) |
| p->more_cleanups_ok = 0; |
| |
| return r; |
| } |
| |
| /* Hash a TYPENAME_TYPE. K is really of type `tree'. */ |
| |
| static hashval_t |
| typename_hash (const void* k) |
| { |
| hashval_t hash; |
| tree t = (tree) k; |
| |
| hash = (htab_hash_pointer (TYPE_CONTEXT (t)) |
| ^ htab_hash_pointer (DECL_NAME (TYPE_NAME (t)))); |
| |
| return hash; |
| } |
| |
| /* Compare two TYPENAME_TYPEs. K1 and K2 are really of type `tree'. */ |
| |
| static int |
| typename_compare (const void * k1, const void * k2) |
| { |
| tree t1; |
| tree t2; |
| tree d1; |
| tree d2; |
| |
| t1 = (tree) k1; |
| t2 = (tree) k2; |
| d1 = TYPE_NAME (t1); |
| d2 = TYPE_NAME (t2); |
| |
| return (DECL_NAME (d1) == DECL_NAME (d2) |
| && TYPE_CONTEXT (t1) == TYPE_CONTEXT (t2) |
| && ((TREE_TYPE (t1) != NULL_TREE) |
| == (TREE_TYPE (t2) != NULL_TREE)) |
| && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)) |
| && TYPENAME_TYPE_FULLNAME (t1) == TYPENAME_TYPE_FULLNAME (t2)); |
| } |
| |
| /* Build a TYPENAME_TYPE. If the type is `typename T::t', CONTEXT is |
| the type of `T', NAME is the IDENTIFIER_NODE for `t'. If BASE_TYPE |
| is non-NULL, this type is being created by the implicit typename |
| extension, and BASE_TYPE is a type named `t' in some base class of |
| `T' which depends on template parameters. |
| |
| Returns the new TYPENAME_TYPE. */ |
| |
| static GTY ((param_is (union tree_node))) htab_t typename_htab; |
| |
| static tree |
| build_typename_type (tree context, tree name, tree fullname) |
| { |
| tree t; |
| tree d; |
| void **e; |
| |
| if (typename_htab == NULL) |
| { |
| typename_htab = htab_create_ggc (61, &typename_hash, |
| &typename_compare, NULL); |
| } |
| |
| /* Build the TYPENAME_TYPE. */ |
| t = make_aggr_type (TYPENAME_TYPE); |
| TYPE_CONTEXT (t) = FROB_CONTEXT (context); |
| TYPENAME_TYPE_FULLNAME (t) = fullname; |
| |
| /* Build the corresponding TYPE_DECL. */ |
| d = build_decl (TYPE_DECL, name, t); |
| TYPE_NAME (TREE_TYPE (d)) = d; |
| TYPE_STUB_DECL (TREE_TYPE (d)) = d; |
| DECL_CONTEXT (d) = FROB_CONTEXT (context); |
| DECL_ARTIFICIAL (d) = 1; |
| |
| /* See if we already have this type. */ |
| e = htab_find_slot (typename_htab, t, INSERT); |
| if (*e) |
| t = (tree) *e; |
| else |
| *e = t; |
| |
| return t; |
| } |
| |
| /* Resolve `typename CONTEXT::NAME'. Returns an appropriate type, |
| unless an error occurs, in which case error_mark_node is returned. |
| If we locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is |
| set, we return that, rather than the _TYPE it corresponds to, in |
| other cases we look through the type decl. If TF_ERROR is set, |
| complain about errors, otherwise be quiet. */ |
| |
| tree |
| make_typename_type (tree context, tree name, tsubst_flags_t complain) |
| { |
| tree fullname; |
| |
| if (name == error_mark_node |
| || context == NULL_TREE |
| || context == error_mark_node) |
| return error_mark_node; |
| |
| if (TYPE_P (name)) |
| { |
| if (!(TYPE_LANG_SPECIFIC (name) |
| && (CLASSTYPE_IS_TEMPLATE (name) |
| || CLASSTYPE_USE_TEMPLATE (name)))) |
| name = TYPE_IDENTIFIER (name); |
| else |
| /* Create a TEMPLATE_ID_EXPR for the type. */ |
| name = build_nt (TEMPLATE_ID_EXPR, |
| CLASSTYPE_TI_TEMPLATE (name), |
| CLASSTYPE_TI_ARGS (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) == TEMPLATE_DECL) |
| { |
| error ("`%D' used without template parameters", name); |
| return error_mark_node; |
| } |
| my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 20030802); |
| |
| if (TREE_CODE (context) == NAMESPACE_DECL) |
| { |
| /* We can get here from typename_sub0 in the explicit_template_type |
| expansion. Just fail. */ |
| if (complain & tf_error) |
| error ("no class template named `%#T' in `%#T'", |
| name, context); |
| return error_mark_node; |
| } |
| |
| if (!dependent_type_p (context) |
| || currently_open_class (context)) |
| { |
| if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR) |
| { |
| tree tmpl = NULL_TREE; |
| if (IS_AGGR_TYPE (context)) |
| tmpl = lookup_field (context, name, 0, false); |
| if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl)) |
| { |
| if (complain & tf_error) |
| error ("no class template named `%#T' in `%#T'", |
| name, context); |
| return error_mark_node; |
| } |
| |
| if (complain & tf_error) |
| perform_or_defer_access_check (TYPE_BINFO (context), tmpl); |
| |
| return lookup_template_class (tmpl, |
| TREE_OPERAND (fullname, 1), |
| NULL_TREE, context, |
| /*entering_scope=*/0, |
| tf_error | tf_warning | tf_user); |
| } |
| else |
| { |
| tree t; |
| |
| if (!IS_AGGR_TYPE (context)) |
| { |
| if (complain & tf_error) |
| error ("no type named `%#T' in `%#T'", name, context); |
| return error_mark_node; |
| } |
| |
| t = lookup_field (context, name, 0, true); |
| if (t) |
| { |
| if (TREE_CODE (t) != TYPE_DECL) |
| { |
| if (complain & tf_error) |
| error ("no type named `%#T' in `%#T'", name, context); |
| return error_mark_node; |
| } |
| |
| if (complain & tf_error) |
| perform_or_defer_access_check (TYPE_BINFO (context), t); |
| |
| if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl)) |
| t = TREE_TYPE (t); |
| |
| return t; |
| } |
| } |
| } |
| |
| /* If the CONTEXT is not a template type, then either the field is |
| there now or its never going to be. */ |
| if (!dependent_type_p (context)) |
| { |
| if (complain & tf_error) |
| error ("no type named `%#T' in `%#T'", name, context); |
| return error_mark_node; |
| } |
| |
| return build_typename_type (context, name, fullname); |
| } |
| |
| /* Resolve `CONTEXT::template NAME'. Returns an appropriate type, |
| unless an error occurs, in which case error_mark_node is returned. |
| If we locate a TYPE_DECL, we return that, rather than the _TYPE it |
| corresponds to. If COMPLAIN zero, don't complain about any errors |
| that occur. */ |
| |
| tree |
| make_unbound_class_template (tree context, tree name, tsubst_flags_t complain) |
| { |
| tree t; |
| tree d; |
| |
| if (TYPE_P (name)) |
| name = TYPE_IDENTIFIER (name); |
| else if (DECL_P (name)) |
| name = DECL_NAME (name); |
| if (TREE_CODE (name) != IDENTIFIER_NODE) |
| abort (); |
| |
| if (!dependent_type_p (context) |
| || currently_open_class (context)) |
| { |
| tree tmpl = NULL_TREE; |
| |
| if (IS_AGGR_TYPE (context)) |
| tmpl = lookup_field (context, name, 0, false); |
| |
| if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl)) |
| { |
| if (complain & tf_error) |
| error ("no class template named `%#T' in `%#T'", name, context); |
| return error_mark_node; |
| } |
| |
| if (complain & tf_error) |
| perform_or_defer_access_check (TYPE_BINFO (context), tmpl); |
| |
| return tmpl; |
| } |
| |
| /* Build the UNBOUND_CLASS_TEMPLATE. */ |
| t = make_aggr_type (UNBOUND_CLASS_TEMPLATE); |
| TYPE_CONTEXT (t) = FROB_CONTEXT (context); |
| TREE_TYPE (t) = NULL_TREE; |
| |
| /* Build the corresponding TEMPLATE_DECL. */ |
| d = build_decl (TEMPLATE_DECL, name, t); |
| TYPE_NAME (TREE_TYPE (d)) = d; |
| TYPE_STUB_DECL (TREE_TYPE (d)) = d; |
| DECL_CONTEXT (d) = FROB_CONTEXT (context); |
| DECL_ARTIFICIAL (d) = 1; |
| |
| return t; |
| } |
| |
| |
| |
| /* A chain of TYPE_DECLs for the builtin types. */ |
| |
| static GTY(()) tree builtin_type_decls; |
| |
| /* Return a chain of TYPE_DECLs for the builtin types. */ |
| |
| tree |
| cxx_builtin_type_decls (void) |
| { |
| return builtin_type_decls; |
| } |
| |
| /* Push the declarations of builtin types into the namespace. |
| RID_INDEX 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. */ |
| |
| void |
| record_builtin_type (enum rid rid_index, |
| const 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); |
| |
| /* The calls to SET_IDENTIFIER_GLOBAL_VALUE below should be |
| eliminated. Built-in types should not be looked up name; their |
| names are keywords that the parser can recognize. However, there |
| is code in c-common.c that uses identifier_global_value to look |
| up built-in types by name. */ |
| if (tname) |
| { |
| tdecl = build_decl (TYPE_DECL, tname, type); |
| DECL_ARTIFICIAL (tdecl) = 1; |
| SET_IDENTIFIER_GLOBAL_VALUE (tname, tdecl); |
| } |
| if (rname) |
| { |
| if (!tdecl) |
| { |
| tdecl = build_decl (TYPE_DECL, rname, type); |
| DECL_ARTIFICIAL (tdecl) = 1; |
| } |
| SET_IDENTIFIER_GLOBAL_VALUE (rname, tdecl); |
| } |
| |
| if (!TYPE_NAME (type)) |
| TYPE_NAME (type) = tdecl; |
| |
| if (tdecl) |
| { |
| TREE_CHAIN (tdecl) = builtin_type_decls; |
| builtin_type_decls = tdecl; |
| } |
| } |
| |
| /* 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 (const 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); |
| |
| /* Suppress generate debug symbol entries for these types, |
| since for normal C++ they are just clutter. |
| However, push_lang_context undoes this if extern "Java" is seen. */ |
| 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 (tree type, const 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_USER_ALIGN (type) = 0; |
| TYPE_MODE (type) = TYPE_MODE (void_type_node); |
| } |
| |
| /* An string for which we should create an IDENTIFIER_NODE at |
| startup. */ |
| |
| typedef struct predefined_identifier |
| { |
| /* The name of the identifier. */ |
| const char *const name; |
| /* The place where the IDENTIFIER_NODE should be stored. */ |
| tree *const node; |
| /* Nonzero if this is the name of a constructor or destructor. */ |
| const int ctor_or_dtor_p; |
| } predefined_identifier; |
| |
| /* Create all the predefined identifiers. */ |
| |
| static void |
| initialize_predefined_identifiers (void) |
| { |
| const predefined_identifier *pid; |
| |
| /* A table of identifiers to create at startup. */ |
| static const predefined_identifier predefined_identifiers[] = { |
| { "C++", &lang_name_cplusplus, 0 }, |
| { "C", &lang_name_c, 0 }, |
| { "Java", &lang_name_java, 0 }, |
| { CTOR_NAME, &ctor_identifier, 1 }, |
| { "__base_ctor", &base_ctor_identifier, 1 }, |
| { "__comp_ctor", &complete_ctor_identifier, 1 }, |
| { DTOR_NAME, &dtor_identifier, 1 }, |
| { "__comp_dtor", &complete_dtor_identifier, 1 }, |
| { "__base_dtor", &base_dtor_identifier, 1 }, |
| { "__deleting_dtor", &deleting_dtor_identifier, 1 }, |
| { IN_CHARGE_NAME, &in_charge_identifier, 0 }, |
| { "nelts", &nelts_identifier, 0 }, |
| { THIS_NAME, &this_identifier, 0 }, |
| { VTABLE_DELTA_NAME, &delta_identifier, 0 }, |
| { VTABLE_PFN_NAME, &pfn_identifier, 0 }, |
| { "_vptr", &vptr_identifier, 0 }, |
| { "__vtt_parm", &vtt_parm_identifier, 0 }, |
| { "::", &global_scope_name, 0 }, |
| { "std", &std_identifier, 0 }, |
| { NULL, NULL, 0 } |
| }; |
| |
| for (pid = predefined_identifiers; pid->name; ++pid) |
| { |
| *pid->node = get_identifier (pid->name); |
| if (pid->ctor_or_dtor_p) |
| IDENTIFIER_CTOR_OR_DTOR_P (*pid->node) = 1; |
| } |
| } |
| |
| /* 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 |
| cxx_init_decl_processing (void) |
| { |
| tree void_ftype; |
| tree void_ftype_ptr; |
| |
| /* Create all the identifiers we need. */ |
| initialize_predefined_identifiers (); |
| |
| /* Fill in back-end hooks. */ |
| lang_missing_noreturn_ok_p = &cp_missing_noreturn_ok_p; |
| |
| /* Create the global variables. */ |
| push_to_top_level (); |
| |
| current_function_decl = NULL_TREE; |
| current_binding_level = NULL; |
| /* Enter the global namespace. */ |
| my_friendly_assert (global_namespace == NULL_TREE, 375); |
| global_namespace = build_lang_decl (NAMESPACE_DECL, global_scope_name, |
| void_type_node); |
| begin_scope (sk_namespace, global_namespace); |
| |
| current_lang_name = NULL_TREE; |
| |
| /* Adjust various flags based on command-line settings. */ |
| if (!flag_permissive) |
| flag_pedantic_errors = 1; |
| if (!flag_no_inline) |
| { |
| flag_inline_trees = 1; |
| flag_no_inline = 1; |
| } |
| if (flag_inline_functions) |
| { |
| flag_inline_trees = 2; |
| flag_inline_functions = 0; |
| } |
| |
| /* Force minimum function alignment if using the least significant |
| bit of function pointers to store the virtual bit. */ |
| if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn |
| && force_align_functions_log < 1) |
| force_align_functions_log = 1; |
| |
| /* Initially, C. */ |
| current_lang_name = lang_name_c; |
| |
| build_common_tree_nodes (flag_signed_char); |
| |
| error_mark_list = build_tree_list (error_mark_node, error_mark_node); |
| TREE_TYPE (error_mark_list) = error_mark_node; |
| |
| /* Create the `std' namespace. */ |
| push_namespace (std_identifier); |
| std_node = current_namespace; |
| pop_namespace (); |
| |
| c_common_nodes_and_builtins (); |
| |
| 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_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; |
| |
| record_builtin_type (RID_BOOL, "bool", boolean_type_node); |
| truthvalue_type_node = boolean_type_node; |
| truthvalue_false_node = boolean_false_node; |
| truthvalue_true_node = boolean_true_node; |
| |
| empty_except_spec = build_tree_list (NULL_TREE, NULL_TREE); |
| |
| #if 0 |
| record_builtin_type (RID_MAX, NULL, string_type_node); |
| #endif |
| |
| delta_type_node = ptrdiff_type_node; |
| vtable_index_type = ptrdiff_type_node; |
| |
| vtt_parm_type = build_pointer_type (const_ptr_type_node); |
| void_ftype = build_function_type (void_type_node, void_list_node); |
| void_ftype_ptr = build_function_type (void_type_node, |
| tree_cons (NULL_TREE, |
| ptr_type_node, |
| void_list_node)); |
| void_ftype_ptr |
| = build_exception_variant (void_ftype_ptr, empty_except_spec); |
| |
| /* 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; |
| |
| /* 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; |
| |
| { |
| /* 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); |
| } |
| record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type); |
| |
| vtbl_type_node |
| = build_cplus_array_type (vtable_entry_type, NULL_TREE); |
| layout_type (vtbl_type_node); |
| vtbl_type_node = build_qualified_type (vtbl_type_node, TYPE_QUAL_CONST); |
| record_builtin_type (RID_MAX, NULL, vtbl_type_node); |
| vtbl_ptr_type_node = build_pointer_type (vtable_entry_type); |
| layout_type (vtbl_ptr_type_node); |
| record_builtin_type (RID_MAX, NULL, vtbl_ptr_type_node); |
| |
| push_namespace (get_identifier ("__cxxabiv1")); |
| abi_node = current_namespace; |
| pop_namespace (); |
| |
| 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_id; |
| tree bad_alloc_type_node; |
| tree bad_alloc_decl; |
| tree newtype, deltype; |
| tree ptr_ftype_sizetype; |
| |
| push_namespace (std_identifier); |
| bad_alloc_id = get_identifier ("bad_alloc"); |
| bad_alloc_type_node = make_aggr_type (RECORD_TYPE); |
| TYPE_CONTEXT (bad_alloc_type_node) = current_namespace; |
| bad_alloc_decl |
| = create_implicit_typedef (bad_alloc_id, bad_alloc_type_node); |
| DECL_CONTEXT (bad_alloc_decl) = current_namespace; |
| TYPE_STUB_DECL (bad_alloc_type_node) = bad_alloc_decl; |
| pop_namespace (); |
| |
| ptr_ftype_sizetype |
| = build_function_type (ptr_type_node, |
| tree_cons (NULL_TREE, |
| size_type_node, |
| void_list_node)); |
| newtype = build_exception_variant |
| (ptr_ftype_sizetype, add_exception_specifier |
| (NULL_TREE, bad_alloc_type_node, -1)); |
| deltype = build_exception_variant (void_ftype_ptr, empty_except_spec); |
| push_cp_library_fn (NEW_EXPR, newtype); |
| push_cp_library_fn (VEC_NEW_EXPR, newtype); |
| global_delete_fndecl = push_cp_library_fn (DELETE_EXPR, deltype); |
| push_cp_library_fn (VEC_DELETE_EXPR, deltype); |
| } |
| |
| abort_fndecl |
| = build_library_fn_ptr ("__cxa_pure_virtual", void_ftype); |
| |
| /* Perform other language dependent initializations. */ |
| init_class_processing (); |
| init_search_processing (); |
| init_rtti_processing (); |
| |
| if (flag_exceptions) |
| init_exception_processing (); |
| |
| if (! supports_one_only ()) |
| flag_weak = 0; |
| |
| make_fname_decl = cp_make_fname_decl; |
| start_fname_decls (); |
| |
| /* Show we use EH for cleanups. */ |
| using_eh_for_cleanups (); |
| |
| /* Maintain consistency. Perhaps we should just complain if they |
| say -fwritable-strings? */ |
| if (flag_writable_strings) |
| flag_const_strings = 0; |
| } |
| |
| /* Generate an initializer for a function naming variable from |
| NAME. NAME may be NULL, to indicate a dependent name. TYPE_P is |
| filled in with the type of the init. */ |
| |
| tree |
| cp_fname_init (const char* name, tree *type_p) |
| { |
| tree domain = NULL_TREE; |
| tree type; |
| tree init = NULL_TREE; |
| size_t length = 0; |
| |
| if (name) |
| { |
| length = strlen (name); |
| domain = build_index_type (size_int (length)); |
| init = build_string (length + 1, name); |
| } |
| |
| type = build_qualified_type (char_type_node, TYPE_QUAL_CONST); |
| type = build_cplus_array_type (type, domain); |
| |
| *type_p = type; |
| |
| if (init) |
| TREE_TYPE (init) = type; |
| else |
| init = error_mark_node; |
| |
| return init; |
| } |
| |
| /* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the |
| decl, NAME is the initialization string and TYPE_DEP indicates whether |
| NAME depended on the type of the function. We make use of that to detect |
| __PRETTY_FUNCTION__ inside a template fn. This is being done |
| lazily at the point of first use, so we musn't push the decl now. */ |
| |
| static tree |
| cp_make_fname_decl (tree id, int type_dep) |
| { |
| const char *const name = (type_dep && processing_template_decl |
| ? NULL : fname_as_string (type_dep)); |
| tree type; |
| tree init = cp_fname_init (name, &type); |
| tree decl = build_decl (VAR_DECL, id, type); |
| |
| /* As we're using pushdecl_with_scope, we must set the context. */ |
| DECL_CONTEXT (decl) = current_function_decl; |
| DECL_PRETTY_FUNCTION_P (decl) = type_dep; |
| |
| TREE_STATIC (decl) = 1; |
| TREE_READONLY (decl) = 1; |
| DECL_ARTIFICIAL (decl) = 1; |
| DECL_INITIAL (decl) = init; |
| |
| TREE_USED (decl) = 1; |
| |
| if (current_function_decl) |
| {<
|