| /* Process declarations and variables for -*- C++ -*- compiler. |
| Copyright (C) 1988-2022 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 3, 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 COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| |
| /* 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 "target.h" |
| #include "c-family/c-target.h" |
| #include "cp-tree.h" |
| #include "timevar.h" |
| #include "stringpool.h" |
| #include "cgraph.h" |
| #include "stor-layout.h" |
| #include "varasm.h" |
| #include "attribs.h" |
| #include "flags.h" |
| #include "tree-iterator.h" |
| #include "decl.h" |
| #include "intl.h" |
| #include "toplev.h" |
| #include "c-family/c-objc.h" |
| #include "c-family/c-pragma.h" |
| #include "c-family/c-ubsan.h" |
| #include "debug.h" |
| #include "plugin.h" |
| #include "builtins.h" |
| #include "gimplify.h" |
| #include "asan.h" |
| #include "gcc-rich-location.h" |
| #include "langhooks.h" |
| #include "context.h" /* For 'g'. */ |
| #include "omp-general.h" |
| #include "omp-offload.h" /* For offload_vars. */ |
| #include "opts.h" |
| #include "langhooks-def.h" /* For lhd_simulate_record_decl */ |
| |
| /* Possible cases of bad specifiers type used by bad_specifiers. */ |
| enum bad_spec_place { |
| BSP_VAR, /* variable */ |
| BSP_PARM, /* parameter */ |
| BSP_TYPE, /* type */ |
| BSP_FIELD /* field */ |
| }; |
| |
| static const char *redeclaration_error_message (tree, tree); |
| |
| static int decl_jump_unsafe (tree); |
| static void require_complete_types_for_parms (tree); |
| static tree grok_reference_init (tree, tree, tree, int); |
| static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *, |
| int, int, int, bool, int, tree, location_t); |
| static void check_static_variable_definition (tree, tree); |
| static void record_unknown_type (tree, const char *); |
| static int member_function_or_else (tree, tree, enum overload_flags); |
| static tree local_variable_p_walkfn (tree *, int *, void *); |
| static const char *tag_name (enum tag_types); |
| static tree lookup_and_check_tag (enum tag_types, tree, TAG_how, bool); |
| static void maybe_deduce_size_from_array_init (tree, tree); |
| static void layout_var_decl (tree); |
| static tree check_initializer (tree, tree, int, vec<tree, va_gc> **); |
| static void make_rtl_for_nonlocal_decl (tree, tree, const char *); |
| static void copy_type_enum (tree , tree); |
| static void check_function_type (tree, tree); |
| static void finish_constructor_body (void); |
| static void begin_destructor_body (void); |
| static void finish_destructor_body (void); |
| static void record_key_method_defined (tree); |
| static tree create_array_type_for_decl (tree, tree, tree, location_t); |
| 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 (location_t, tree, int); |
| static void initialize_predefined_identifiers (void); |
| static tree check_special_function_return_type |
| (special_function_kind, tree, tree, int, const location_t*); |
| static tree push_cp_library_fn (enum tree_code, tree, int); |
| static tree build_cp_library_fn (tree, enum tree_code, tree, int); |
| static void store_parm_decls (tree); |
| static void initialize_local_var (tree, tree); |
| static void expand_static_init (tree, tree); |
| static location_t smallest_type_location (const cp_decl_specifier_seq*); |
| |
| /* 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 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; |
| |
| Used by RTTI |
| tree type_info_type_node, tinfo_decl_id, tinfo_decl_type; |
| tree tinfo_var_id; */ |
| |
| tree cp_global_trees[CPTI_MAX]; |
| |
| /* A list of objects which have constructors or destructors |
| which reside in namespace scope. The decl is stored in |
| the TREE_VALUE slot and the initializer is stored |
| in the TREE_PURPOSE slot. */ |
| tree static_aggregates; |
| |
| /* Like static_aggregates, but for thread_local variables. */ |
| tree tls_aggregates; |
| |
| /* A hash-map mapping from variable decls to the dynamic initializer for |
| the decl. This is currently only used by OpenMP. */ |
| decl_tree_map *dynamic_initializers; |
| |
| /* -- end of C++ */ |
| |
| /* A node for the integer constant 2. */ |
| |
| tree integer_two_node; |
| |
| /* vector of static decls. */ |
| vec<tree, va_gc> *static_decls; |
| |
| /* vector of keyed classes. */ |
| vec<tree, va_gc> *keyed_classes; |
| |
| /* Used only for jumps to as-yet undefined labels, since jumps to |
| defined labels can have their validity checked immediately. */ |
| |
| struct GTY((chain_next ("%h.next"))) named_label_use_entry { |
| struct named_label_use_entry *next; |
| /* The binding level to which this entry is *currently* attached. |
| This is initially the binding level in which the goto appeared, |
| but is modified as scopes are closed. */ |
| cp_binding_level *binding_level; |
| /* The head of the names list that was current when the goto appeared, |
| or the inner scope popped. These are the decls that will *not* be |
| skipped when jumping to the label. */ |
| tree names_in_scope; |
| /* The location of the goto, for error reporting. */ |
| location_t o_goto_locus; |
| /* True if an OpenMP structured block scope has been closed since |
| the goto appeared. This means that the branch from the label will |
| illegally exit an OpenMP scope. */ |
| bool in_omp_scope; |
| }; |
| |
| /* 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 GTY((for_user)) named_label_entry { |
| |
| tree name; /* Name of decl. */ |
| |
| tree label_decl; /* LABEL_DECL, unless deleted local label. */ |
| |
| named_label_entry *outer; /* Outer shadowed chain. */ |
| |
| /* The binding level to which the label is *currently* attached. |
| This is initially set to the binding level in which the label |
| is defined, but is modified as scopes are closed. */ |
| cp_binding_level *binding_level; |
| |
| /* The head of the names list that was current when the label was |
| defined, or the inner scope popped. These are the decls that will |
| be skipped when jumping to the label. */ |
| tree names_in_scope; |
| |
| /* A vector of all decls from all binding levels that would be |
| crossed by a backward branch to the label. */ |
| vec<tree, va_gc> *bad_decls; |
| |
| /* A list of uses of the label, before the label is defined. */ |
| named_label_use_entry *uses; |
| |
| /* The following bits are set after the label is defined, and are |
| updated as scopes are popped. They indicate that a jump to the |
| label will illegally enter a scope of the given flavor. */ |
| bool in_try_scope; |
| bool in_catch_scope; |
| bool in_omp_scope; |
| bool in_transaction_scope; |
| bool in_constexpr_if; |
| bool in_consteval_if; |
| }; |
| |
| #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; |
| |
| /* Whether the exception-specifier is part of a function type (i.e. C++17). */ |
| bool flag_noexcept_type; |
| |
| /* 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_state = DEPRECATED_NORMAL; |
| |
| |
| /* A list of VAR_DECLs whose type was incomplete at the time the |
| variable was declared. */ |
| |
| struct GTY(()) incomplete_var { |
| tree decl; |
| tree incomplete_type; |
| }; |
| |
| |
| static GTY(()) vec<incomplete_var, va_gc> *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; |
| 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' matches 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 |
| check_label_used (tree label) |
| { |
| if (!processing_template_decl) |
| { |
| if (DECL_INITIAL (label) == NULL_TREE) |
| { |
| location_t location; |
| |
| error ("label %q+D used but not defined", label); |
| location = input_location; |
| /* FIXME want (LOCATION_FILE (input_location), (line)0) */ |
| /* Avoid crashing later. */ |
| define_label (location, DECL_NAME (label)); |
| } |
| else |
| warn_for_unused_label (label); |
| } |
| } |
| |
| /* Helper function to sort named label entries in a vector by DECL_UID. */ |
| |
| static int |
| sort_labels (const void *a, const void *b) |
| { |
| tree label1 = *(tree const *) a; |
| tree label2 = *(tree const *) b; |
| |
| /* DECL_UIDs can never be equal. */ |
| return DECL_UID (label1) > DECL_UID (label2) ? -1 : +1; |
| } |
| |
| /* 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) |
| { |
| if (!named_labels) |
| return; |
| |
| /* We need to add the labels to the block chain, so debug |
| information is emitted. But, we want the order to be stable so |
| need to sort them first. Otherwise the debug output could be |
| randomly ordered. I guess it's mostly stable, unless the hash |
| table implementation changes. */ |
| auto_vec<tree, 32> labels (named_labels->elements ()); |
| hash_table<named_label_hash>::iterator end (named_labels->end ()); |
| for (hash_table<named_label_hash>::iterator iter |
| (named_labels->begin ()); iter != end; ++iter) |
| { |
| named_label_entry *ent = *iter; |
| |
| gcc_checking_assert (!ent->outer); |
| if (ent->label_decl) |
| labels.quick_push (ent->label_decl); |
| ggc_free (ent); |
| } |
| named_labels = NULL; |
| labels.qsort (sort_labels); |
| |
| while (labels.length ()) |
| { |
| tree label = labels.pop (); |
| |
| DECL_CHAIN (label) = BLOCK_VARS (block); |
| BLOCK_VARS (block) = label; |
| |
| check_label_used (label); |
| } |
| } |
| |
| /* At the end of a block with local labels, restore the outer definition. */ |
| |
| static void |
| pop_local_label (tree id, tree label) |
| { |
| check_label_used (label); |
| named_label_entry **slot = named_labels->find_slot_with_hash |
| (id, IDENTIFIER_HASH_VALUE (id), NO_INSERT); |
| named_label_entry *ent = *slot; |
| |
| if (ent->outer) |
| ent = ent->outer; |
| else |
| { |
| ent = ggc_cleared_alloc<named_label_entry> (); |
| ent->name = id; |
| } |
| *slot = ent; |
| } |
| |
| /* The following two routines are used to interface to Objective-C++. |
| The binding level is purposely treated as an opaque type. */ |
| |
| void * |
| objc_get_current_scope (void) |
| { |
| return current_binding_level; |
| } |
| |
| /* The following routine is used by the NeXT-style SJLJ exceptions; |
| variables get marked 'volatile' so as to not be clobbered by |
| _setjmp()/_longjmp() calls. All variables in the current scope, |
| as well as parent scopes up to (but not including) ENCLOSING_BLK |
| shall be thusly marked. */ |
| |
| void |
| objc_mark_locals_volatile (void *enclosing_blk) |
| { |
| cp_binding_level *scope; |
| |
| for (scope = current_binding_level; |
| scope && scope != enclosing_blk; |
| scope = scope->level_chain) |
| { |
| tree decl; |
| |
| for (decl = scope->names; decl; decl = TREE_CHAIN (decl)) |
| objc_volatilize_decl (decl); |
| |
| /* Do not climb up past the current function. */ |
| if (scope->kind == sk_function_parms) |
| break; |
| } |
| } |
| |
| /* True if B is the level for the condition of a constexpr if. */ |
| |
| static bool |
| level_for_constexpr_if (cp_binding_level *b) |
| { |
| return (b->kind == sk_cond && b->this_entity |
| && TREE_CODE (b->this_entity) == IF_STMT |
| && IF_STMT_CONSTEXPR_P (b->this_entity)); |
| } |
| |
| /* True if B is the level for the condition of a consteval if. */ |
| |
| static bool |
| level_for_consteval_if (cp_binding_level *b) |
| { |
| return (b->kind == sk_cond && b->this_entity |
| && TREE_CODE (b->this_entity) == IF_STMT |
| && IF_STMT_CONSTEVAL_P (b->this_entity)); |
| } |
| |
| /* Update data for defined and undefined labels when leaving a scope. */ |
| |
| int |
| poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl) |
| { |
| named_label_entry *ent = *slot; |
| cp_binding_level *obl = bl->level_chain; |
| |
| if (ent->binding_level == bl) |
| { |
| tree decl; |
| |
| /* ENT->NAMES_IN_SCOPE may contain a mixture of DECLs and |
| TREE_LISTs representing OVERLOADs, so be careful. */ |
| for (decl = ent->names_in_scope; decl; decl = (DECL_P (decl) |
| ? DECL_CHAIN (decl) |
| : TREE_CHAIN (decl))) |
| if (decl_jump_unsafe (decl)) |
| vec_safe_push (ent->bad_decls, decl); |
| |
| ent->binding_level = obl; |
| ent->names_in_scope = obl->names; |
| switch (bl->kind) |
| { |
| case sk_try: |
| ent->in_try_scope = true; |
| break; |
| case sk_catch: |
| ent->in_catch_scope = true; |
| break; |
| case sk_omp: |
| ent->in_omp_scope = true; |
| break; |
| case sk_transaction: |
| ent->in_transaction_scope = true; |
| break; |
| case sk_block: |
| if (level_for_constexpr_if (bl->level_chain)) |
| ent->in_constexpr_if = true; |
| else if (level_for_consteval_if (bl->level_chain)) |
| ent->in_consteval_if = true; |
| break; |
| default: |
| break; |
| } |
| } |
| else if (ent->uses) |
| { |
| struct named_label_use_entry *use; |
| |
| for (use = ent->uses; use ; use = use->next) |
| if (use->binding_level == bl) |
| { |
| use->binding_level = obl; |
| use->names_in_scope = obl->names; |
| if (bl->kind == sk_omp) |
| use->in_omp_scope = true; |
| } |
| } |
| |
| return 1; |
| } |
| |
| /* Saved errorcount to avoid -Wunused-but-set-{parameter,variable} warnings |
| when errors were reported, except for -Werror-unused-but-set-*. */ |
| static int unused_but_set_errorcount; |
| |
| /* 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; |
| tree subblocks; |
| tree block; |
| tree decl; |
| scope_kind kind; |
| |
| auto_cond_timevar tv (TV_NAME_LOOKUP); |
| restart: |
| |
| block = NULL_TREE; |
| |
| gcc_assert (current_binding_level->kind != sk_class |
| && current_binding_level->kind != sk_namespace); |
| |
| if (current_binding_level->kind == sk_cleanup) |
| functionbody = 0; |
| subblocks = functionbody >= 0 ? current_binding_level->blocks : 0; |
| |
| gcc_assert (!vec_safe_length (current_binding_level->class_shadowed)); |
| |
| /* 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. */ |
| gcc_assert (keep == 0 || keep == 1); |
| |
| 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 && named_labels) |
| named_labels->traverse<cp_binding_level *, poplevel_named_label_1> |
| (current_binding_level); |
| |
| /* 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. */ |
| |
| decls = current_binding_level->names; |
| if (reverse) |
| { |
| decls = nreverse (decls); |
| current_binding_level->names = decls; |
| } |
| |
| /* 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; |
| /* Avoid function body block if possible. */ |
| if (functionbody && subblocks && BLOCK_CHAIN (subblocks) == NULL_TREE) |
| keep = 0; |
| else 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 = BLOCK_CHAIN (link)) |
| BLOCK_SUPERCONTEXT (link) = block; |
| |
| /* Before we remove the declarations first check for unused variables. */ |
| if ((warn_unused_variable || warn_unused_but_set_variable) |
| && current_binding_level->kind != sk_template_parms |
| && !processing_template_decl) |
| for (tree d = get_local_decls (); d; d = TREE_CHAIN (d)) |
| { |
| /* There are cases where D itself is a TREE_LIST. See in |
| push_local_binding where the list of decls returned by |
| getdecls is built. */ |
| decl = TREE_CODE (d) == TREE_LIST ? TREE_VALUE (d) : d; |
| |
| tree type = TREE_TYPE (decl); |
| if (VAR_P (decl) |
| && (! TREE_USED (decl) || !DECL_READ_P (decl)) |
| && ! DECL_IN_SYSTEM_HEADER (decl) |
| /* For structured bindings, consider only real variables, not |
| subobjects. */ |
| && (DECL_DECOMPOSITION_P (decl) ? !DECL_DECOMP_BASE (decl) |
| : (DECL_NAME (decl) && !DECL_ARTIFICIAL (decl))) |
| && type != error_mark_node |
| && (!CLASS_TYPE_P (type) |
| || !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) |
| || lookup_attribute ("warn_unused", |
| TYPE_ATTRIBUTES (TREE_TYPE (decl))))) |
| { |
| if (! TREE_USED (decl)) |
| { |
| if (!DECL_NAME (decl) && DECL_DECOMPOSITION_P (decl)) |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_variable, |
| "unused structured binding declaration"); |
| else |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_variable, "unused variable %qD", decl); |
| } |
| else if (DECL_CONTEXT (decl) == current_function_decl |
| // For -Wunused-but-set-variable leave references alone. |
| && !TYPE_REF_P (TREE_TYPE (decl)) |
| && errorcount == unused_but_set_errorcount) |
| { |
| if (!DECL_NAME (decl) && DECL_DECOMPOSITION_P (decl)) |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_but_set_variable, "structured " |
| "binding declaration set but not used"); |
| else |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_but_set_variable, |
| "variable %qD set but not used", decl); |
| unused_but_set_errorcount = errorcount; |
| } |
| } |
| } |
| |
| /* Remove declarations for all the DECLs in this level. */ |
| for (link = decls; link; link = TREE_CHAIN (link)) |
| { |
| tree name; |
| if (TREE_CODE (link) == TREE_LIST) |
| { |
| decl = TREE_VALUE (link); |
| name = TREE_PURPOSE (link); |
| gcc_checking_assert (name); |
| } |
| else |
| { |
| decl = link; |
| name = DECL_NAME (decl); |
| } |
| |
| /* Remove the binding. */ |
| if (TREE_CODE (decl) == LABEL_DECL) |
| pop_local_label (name, decl); |
| else |
| pop_local_binding (name, decl); |
| } |
| |
| /* Restore the IDENTIFIER_TYPE_VALUEs. */ |
| for (link = current_binding_level->type_shadowed; |
| link; link = TREE_CHAIN (link)) |
| SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link)); |
| |
| /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs |
| list if a `using' declaration put them there. The debugging |
| back ends won't understand OVERLOAD, so we remove them here. |
| Because the BLOCK_VARS are (temporarily) shared with |
| CURRENT_BINDING_LEVEL->NAMES we must do this fixup after we have |
| popped all the bindings. Also remove undeduced 'auto' decls, |
| which LTO doesn't understand, and can't have been used by anything. */ |
| if (block) |
| { |
| tree* d; |
| |
| for (d = &BLOCK_VARS (block); *d; ) |
| { |
| if (TREE_CODE (*d) == TREE_LIST |
| || (!processing_template_decl |
| && undeduced_auto_decl (*d))) |
| *d = TREE_CHAIN (*d); |
| else |
| d = &DECL_CHAIN (*d); |
| } |
| } |
| |
| /* If the level being exited is the top level of a function, |
| check over all the labels. */ |
| if (functionbody) |
| { |
| if (block) |
| { |
| /* 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); |
| } |
| else |
| pop_labels (subblocks); |
| } |
| |
| kind = current_binding_level->kind; |
| if (kind == sk_cleanup) |
| { |
| tree stmt; |
| |
| /* If this is a temporary binding created for a cleanup, then we'll |
| have pushed a statement list level. Pop that, create a new |
| BIND_EXPR for the block, and insert it into the stream. */ |
| stmt = pop_stmt_list (current_binding_level->statement_list); |
| stmt = c_build_bind_expr (input_location, block, stmt); |
| add_stmt (stmt); |
| } |
| |
| leave_scope (); |
| if (functionbody) |
| { |
| /* The current function is being defined, so its DECL_INITIAL |
| should be error_mark_node. */ |
| gcc_assert (DECL_INITIAL (current_function_decl) == error_mark_node); |
| DECL_INITIAL (current_function_decl) = block ? block : subblocks; |
| if (subblocks) |
| { |
| if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) |
| { |
| if (BLOCK_SUBBLOCKS (subblocks)) |
| BLOCK_OUTER_CURLY_BRACE_P (BLOCK_SUBBLOCKS (subblocks)) = 1; |
| } |
| else |
| BLOCK_OUTER_CURLY_BRACE_P (subblocks) = 1; |
| } |
| } |
| else if (block) |
| current_binding_level->blocks |
| = block_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 |
| = block_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; |
| |
| /* All temporary bindings created for cleanups are popped silently. */ |
| if (kind == sk_cleanup) |
| goto restart; |
| |
| return block; |
| } |
| |
| /* Call wrapup_globals_declarations for the globals in NAMESPACE. */ |
| /* Diagnose odr-used extern inline variables without definitions |
| in the current TU. */ |
| |
| int |
| wrapup_namespace_globals () |
| { |
| if (vec<tree, va_gc> *statics = static_decls) |
| { |
| for (tree decl : *statics) |
| { |
| if (warn_unused_function |
| && TREE_CODE (decl) == FUNCTION_DECL |
| && DECL_INITIAL (decl) == 0 |
| && DECL_EXTERNAL (decl) |
| && !TREE_PUBLIC (decl) |
| && !DECL_ARTIFICIAL (decl) |
| && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl) |
| && !warning_suppressed_p (decl, OPT_Wunused_function)) |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_function, |
| "%qF declared %<static%> but never defined", decl); |
| |
| if (VAR_P (decl) |
| && DECL_EXTERNAL (decl) |
| && DECL_INLINE_VAR_P (decl) |
| && DECL_ODR_USED (decl)) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "odr-used inline variable %qD is not defined", decl); |
| } |
| |
| /* Clear out the list, so we don't rescan next time. */ |
| static_decls = NULL; |
| |
| /* Write out any globals that need to be output. */ |
| return wrapup_global_declarations (statics->address (), |
| statics->length ()); |
| } |
| return 0; |
| } |
| |
| /* 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 (input_location, 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; |
| TYPE_STUB_DECL (type) = decl; |
| |
| return decl; |
| } |
| |
| /* Function-scope local entities that need discriminators. Each entry |
| is a {decl,name} pair. VAR_DECLs for anon unions get their name |
| smashed, so we cannot rely on DECL_NAME. */ |
| |
| static GTY((deletable)) vec<tree, va_gc> *local_entities; |
| |
| /* Determine the mangling discriminator of local DECL. There are |
| generally very few of these in any particular function. */ |
| |
| void |
| determine_local_discriminator (tree decl) |
| { |
| auto_cond_timevar tv (TV_NAME_LOOKUP); |
| retrofit_lang_decl (decl); |
| tree ctx = DECL_CONTEXT (decl); |
| tree name = (TREE_CODE (decl) == TYPE_DECL |
| && TYPE_UNNAMED_P (TREE_TYPE (decl)) |
| ? NULL_TREE : DECL_NAME (decl)); |
| size_t nelts = vec_safe_length (local_entities); |
| for (size_t i = 0; i < nelts; i += 2) |
| { |
| tree *pair = &(*local_entities)[i]; |
| tree d = pair[0]; |
| tree n = pair[1]; |
| gcc_checking_assert (d != decl); |
| if (name == n |
| && TREE_CODE (decl) == TREE_CODE (d) |
| && ctx == DECL_CONTEXT (d)) |
| { |
| tree disc = integer_one_node; |
| if (DECL_DISCRIMINATOR (d)) |
| disc = build_int_cst (TREE_TYPE (disc), |
| TREE_INT_CST_LOW (DECL_DISCRIMINATOR (d)) + 1); |
| DECL_DISCRIMINATOR (decl) = disc; |
| /* Replace the saved decl. */ |
| pair[0] = decl; |
| decl = NULL_TREE; |
| break; |
| } |
| } |
| |
| if (decl) |
| { |
| vec_safe_reserve (local_entities, 2); |
| local_entities->quick_push (decl); |
| local_entities->quick_push (name); |
| } |
| } |
| |
| |
| |
| /* Returns true if functions FN1 and FN2 have equivalent trailing |
| requires clauses. */ |
| |
| static bool |
| function_requirements_equivalent_p (tree newfn, tree oldfn) |
| { |
| /* In the concepts TS, the combined constraints are compared. */ |
| if (cxx_dialect < cxx20 |
| && (DECL_TEMPLATE_SPECIALIZATION (newfn) |
| <= DECL_TEMPLATE_SPECIALIZATION (oldfn))) |
| { |
| tree ci1 = get_constraints (oldfn); |
| tree ci2 = get_constraints (newfn); |
| tree req1 = ci1 ? CI_ASSOCIATED_CONSTRAINTS (ci1) : NULL_TREE; |
| tree req2 = ci2 ? CI_ASSOCIATED_CONSTRAINTS (ci2) : NULL_TREE; |
| return cp_tree_equal (req1, req2); |
| } |
| |
| /* Compare only trailing requirements. */ |
| tree reqs1 = get_trailing_function_requirements (newfn); |
| tree reqs2 = get_trailing_function_requirements (oldfn); |
| if ((reqs1 != NULL_TREE) != (reqs2 != NULL_TREE)) |
| return false; |
| |
| /* Substitution is needed when friends are involved. */ |
| reqs1 = maybe_substitute_reqs_for (reqs1, newfn); |
| reqs2 = maybe_substitute_reqs_for (reqs2, oldfn); |
| |
| return cp_tree_equal (reqs1, reqs2); |
| } |
| |
| /* 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, bool record_versions /* = true */) |
| { |
| 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; |
| |
| gcc_assert (DECL_P (newdecl)); |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| /* Specializations of different templates are different functions |
| even if they have the same type. */ |
| tree t1 = (DECL_USE_TEMPLATE (newdecl) |
| ? DECL_TI_TEMPLATE (newdecl) |
| : NULL_TREE); |
| tree t2 = (DECL_USE_TEMPLATE (olddecl) |
| ? DECL_TI_TEMPLATE (olddecl) |
| : NULL_TREE); |
| if (t1 != t2) |
| return 0; |
| |
| if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl) |
| && ! (DECL_EXTERN_C_P (newdecl) |
| && DECL_EXTERN_C_P (olddecl))) |
| return 0; |
| |
| /* A new declaration doesn't match a built-in one unless it |
| is also extern "C". */ |
| if (DECL_IS_UNDECLARED_BUILTIN (olddecl) |
| && DECL_EXTERN_C_P (olddecl) && !DECL_EXTERN_C_P (newdecl)) |
| return 0; |
| |
| tree f1 = TREE_TYPE (newdecl); |
| tree f2 = TREE_TYPE (olddecl); |
| if (TREE_CODE (f1) != TREE_CODE (f2)) |
| return 0; |
| |
| /* A declaration with deduced return type should use its pre-deduction |
| type for declaration matching. */ |
| tree r2 = fndecl_declared_return_type (olddecl); |
| tree r1 = fndecl_declared_return_type (newdecl); |
| |
| tree p1 = TYPE_ARG_TYPES (f1); |
| tree p2 = TYPE_ARG_TYPES (f2); |
| |
| if (same_type_p (r1, r2)) |
| { |
| if (!prototype_p (f2) && DECL_EXTERN_C_P (olddecl) |
| && fndecl_built_in_p (olddecl)) |
| { |
| types_match = self_promoting_args_p (p1); |
| if (p1 == void_list_node) |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl); |
| } |
| else |
| types_match = |
| compparms (p1, p2) |
| && type_memfn_rqual (f1) == type_memfn_rqual (f2) |
| && (TYPE_ATTRIBUTES (TREE_TYPE (newdecl)) == NULL_TREE |
| || comp_type_attributes (TREE_TYPE (newdecl), |
| TREE_TYPE (olddecl)) != 0); |
| } |
| else |
| types_match = 0; |
| |
| /* Two function declarations match if either has a requires-clause |
| then both have a requires-clause and their constraints-expressions |
| are equivalent. */ |
| if (types_match && flag_concepts) |
| types_match = function_requirements_equivalent_p (newdecl, olddecl); |
| |
| /* The decls dont match if they correspond to two different versions |
| of the same function. Disallow extern "C" functions to be |
| versions for now. */ |
| if (types_match |
| && !DECL_EXTERN_C_P (newdecl) |
| && !DECL_EXTERN_C_P (olddecl) |
| && targetm.target_option.function_versions (newdecl, olddecl)) |
| { |
| if (record_versions) |
| maybe_version_functions (newdecl, olddecl, |
| (!DECL_FUNCTION_VERSIONED (newdecl) |
| || !DECL_FUNCTION_VERSIONED (olddecl))); |
| return 0; |
| } |
| } |
| else if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| if (!template_heads_equivalent_p (newdecl, olddecl)) |
| return 0; |
| |
| tree oldres = DECL_TEMPLATE_RESULT (olddecl); |
| tree newres = DECL_TEMPLATE_RESULT (newdecl); |
| |
| if (TREE_CODE (newres) != TREE_CODE (oldres)) |
| return 0; |
| |
| /* Two template types match if they are the same. Otherwise, compare |
| the underlying declarations. */ |
| if (TREE_CODE (newres) == TYPE_DECL) |
| types_match = same_type_p (TREE_TYPE (newres), TREE_TYPE (oldres)); |
| else |
| types_match = decls_match (newres, oldres); |
| } |
| else |
| { |
| /* Need to check scope for variable declaration (VAR_DECL). |
| For typedef (TYPE_DECL), scope is ignored. */ |
| if (VAR_P (newdecl) |
| && CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl) |
| /* [dcl.link] |
| Two declarations for an object with C language linkage |
| with the same name (ignoring the namespace that qualify |
| it) that appear in different namespace scopes refer to |
| the same object. */ |
| && !(DECL_EXTERN_C_P (olddecl) && DECL_EXTERN_C_P (newdecl))) |
| return 0; |
| |
| 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; |
| } |
| |
| /* Mark DECL as versioned if it isn't already. */ |
| |
| static void |
| maybe_mark_function_versioned (tree decl) |
| { |
| if (!DECL_FUNCTION_VERSIONED (decl)) |
| { |
| DECL_FUNCTION_VERSIONED (decl) = 1; |
| /* If DECL_ASSEMBLER_NAME has already been set, re-mangle |
| to include the version marker. */ |
| if (DECL_ASSEMBLER_NAME_SET_P (decl)) |
| mangle_decl (decl); |
| } |
| } |
| |
| /* NEWDECL and OLDDECL have identical signatures. If they are |
| different versions adjust them and return true. |
| If RECORD is set to true, record function versions. */ |
| |
| bool |
| maybe_version_functions (tree newdecl, tree olddecl, bool record) |
| { |
| if (!targetm.target_option.function_versions (newdecl, olddecl)) |
| return false; |
| |
| maybe_mark_function_versioned (olddecl); |
| if (DECL_LOCAL_DECL_P (olddecl)) |
| { |
| olddecl = DECL_LOCAL_DECL_ALIAS (olddecl); |
| maybe_mark_function_versioned (olddecl); |
| } |
| |
| maybe_mark_function_versioned (newdecl); |
| if (DECL_LOCAL_DECL_P (newdecl)) |
| { |
| /* Unfortunately, we can get here before pushdecl naturally calls |
| push_local_extern_decl_alias, so we need to call it directly. */ |
| if (!DECL_LOCAL_DECL_ALIAS (newdecl)) |
| push_local_extern_decl_alias (newdecl); |
| newdecl = DECL_LOCAL_DECL_ALIAS (newdecl); |
| maybe_mark_function_versioned (newdecl); |
| } |
| |
| if (record) |
| cgraph_node::record_function_versions (olddecl, newdecl); |
| |
| return true; |
| } |
| |
| /* 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) |
| { |
| 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 |
| 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; |
| |
| auto_diagnostic_group d; |
| if (permerror (DECL_SOURCE_LOCATION (newdecl), |
| "%qD was declared %<extern%> and later %<static%>", newdecl)) |
| inform (DECL_SOURCE_LOCATION (olddecl), |
| "previous declaration of %qD", olddecl); |
| } |
| |
| /* NEW_DECL is a redeclaration of OLD_DECL; both are functions or |
| function templates. If their exception specifications do not |
| match, issue a diagnostic. */ |
| |
| static void |
| check_redeclaration_exception_specification (tree new_decl, |
| tree old_decl) |
| { |
| tree new_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (new_decl)); |
| tree old_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl)); |
| |
| /* Two default specs are equivalent, don't force evaluation. */ |
| if (UNEVALUATED_NOEXCEPT_SPEC_P (new_exceptions) |
| && UNEVALUATED_NOEXCEPT_SPEC_P (old_exceptions)) |
| return; |
| |
| if (!type_dependent_expression_p (old_decl)) |
| { |
| maybe_instantiate_noexcept (new_decl); |
| maybe_instantiate_noexcept (old_decl); |
| } |
| new_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (new_decl)); |
| old_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl)); |
| |
| /* [except.spec] |
| |
| If any declaration of a function has an exception-specification, |
| all declarations, including the definition and an explicit |
| specialization, of that function shall have an |
| exception-specification with the same set of type-ids. */ |
| if (!DECL_IS_UNDECLARED_BUILTIN (old_decl) |
| && !DECL_IS_UNDECLARED_BUILTIN (new_decl) |
| && !comp_except_specs (new_exceptions, old_exceptions, ce_normal)) |
| { |
| const char *const msg |
| = G_("declaration of %qF has a different exception specifier"); |
| bool complained = true; |
| location_t new_loc = DECL_SOURCE_LOCATION (new_decl); |
| auto_diagnostic_group d; |
| if (DECL_IN_SYSTEM_HEADER (old_decl)) |
| complained = pedwarn (new_loc, OPT_Wsystem_headers, msg, new_decl); |
| else if (!flag_exceptions) |
| /* We used to silently permit mismatched eh specs with |
| -fno-exceptions, so make them a pedwarn now. */ |
| complained = pedwarn (new_loc, OPT_Wpedantic, msg, new_decl); |
| else |
| error_at (new_loc, msg, new_decl); |
| if (complained) |
| inform (DECL_SOURCE_LOCATION (old_decl), |
| "from previous declaration %qF", old_decl); |
| } |
| } |
| |
| /* Return true if OLD_DECL and NEW_DECL agree on constexprness. |
| Otherwise issue diagnostics. */ |
| |
| static bool |
| validate_constexpr_redeclaration (tree old_decl, tree new_decl) |
| { |
| old_decl = STRIP_TEMPLATE (old_decl); |
| new_decl = STRIP_TEMPLATE (new_decl); |
| if (!VAR_OR_FUNCTION_DECL_P (old_decl) |
| || !VAR_OR_FUNCTION_DECL_P (new_decl)) |
| return true; |
| if (DECL_DECLARED_CONSTEXPR_P (old_decl) |
| == DECL_DECLARED_CONSTEXPR_P (new_decl)) |
| { |
| if (TREE_CODE (old_decl) != FUNCTION_DECL) |
| return true; |
| if (DECL_IMMEDIATE_FUNCTION_P (old_decl) |
| == DECL_IMMEDIATE_FUNCTION_P (new_decl)) |
| return true; |
| } |
| if (TREE_CODE (old_decl) == FUNCTION_DECL) |
| { |
| /* With -fimplicit-constexpr, ignore changes in the constexpr |
| keyword. */ |
| if (flag_implicit_constexpr |
| && (DECL_IMMEDIATE_FUNCTION_P (new_decl) |
| == DECL_IMMEDIATE_FUNCTION_P (old_decl))) |
| return true; |
| if (fndecl_built_in_p (old_decl)) |
| { |
| /* Hide a built-in declaration. */ |
| DECL_DECLARED_CONSTEXPR_P (old_decl) |
| = DECL_DECLARED_CONSTEXPR_P (new_decl); |
| if (DECL_IMMEDIATE_FUNCTION_P (new_decl)) |
| SET_DECL_IMMEDIATE_FUNCTION_P (old_decl); |
| return true; |
| } |
| /* 7.1.5 [dcl.constexpr] |
| Note: An explicit specialization can differ from the template |
| declaration with respect to the constexpr specifier. */ |
| if (! DECL_TEMPLATE_SPECIALIZATION (old_decl) |
| && DECL_TEMPLATE_SPECIALIZATION (new_decl)) |
| return true; |
| |
| const char *kind = "constexpr"; |
| if (DECL_IMMEDIATE_FUNCTION_P (old_decl) |
| || DECL_IMMEDIATE_FUNCTION_P (new_decl)) |
| kind = "consteval"; |
| error_at (DECL_SOURCE_LOCATION (new_decl), |
| "redeclaration %qD differs in %qs " |
| "from previous declaration", new_decl, |
| kind); |
| inform (DECL_SOURCE_LOCATION (old_decl), |
| "previous declaration %qD", old_decl); |
| return false; |
| } |
| return true; |
| } |
| |
| // If OLDDECL and NEWDECL are concept declarations with the same type |
| // (i.e., and template parameters), but different requirements, |
| // emit diagnostics and return true. Otherwise, return false. |
| static inline bool |
| check_concept_refinement (tree olddecl, tree newdecl) |
| { |
| if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl)) |
| return false; |
| |
| tree d1 = DECL_TEMPLATE_RESULT (olddecl); |
| tree d2 = DECL_TEMPLATE_RESULT (newdecl); |
| if (TREE_CODE (d1) != TREE_CODE (d2)) |
| return false; |
| |
| tree t1 = TREE_TYPE (d1); |
| tree t2 = TREE_TYPE (d2); |
| if (TREE_CODE (d1) == FUNCTION_DECL) |
| { |
| if (compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)) |
| && comp_template_parms (DECL_TEMPLATE_PARMS (olddecl), |
| DECL_TEMPLATE_PARMS (newdecl)) |
| && !equivalently_constrained (olddecl, newdecl)) |
| { |
| error ("cannot specialize concept %q#D", olddecl); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /* DECL is a redeclaration of a function or function template. If |
| it does have default arguments issue a diagnostic. Note: this |
| function is used to enforce the requirements in C++11 8.3.6 about |
| no default arguments in redeclarations. */ |
| |
| static void |
| check_redeclaration_no_default_args (tree decl) |
| { |
| gcc_assert (DECL_DECLARES_FUNCTION_P (decl)); |
| |
| for (tree t = FUNCTION_FIRST_USER_PARMTYPE (decl); |
| t && t != void_list_node; t = TREE_CHAIN (t)) |
| if (TREE_PURPOSE (t)) |
| { |
| permerror (DECL_SOURCE_LOCATION (decl), |
| "redeclaration of %q#D may not have default " |
| "arguments", decl); |
| return; |
| } |
| } |
| |
| /* NEWDECL is a redeclaration of a function or function template OLDDECL, |
| in any case represented as FUNCTION_DECLs (the DECL_TEMPLATE_RESULTs of |
| the TEMPLATE_DECLs in case of function templates). This function is used |
| to enforce the final part of C++17 11.3.6/4, about a single declaration: |
| "If a friend declaration specifies a default argument expression, that |
| declaration shall be a definition and shall be the only declaration of |
| the function or function template in the translation unit." */ |
| |
| static void |
| check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl) |
| { |
| if (!DECL_UNIQUE_FRIEND_P (olddecl) && !DECL_UNIQUE_FRIEND_P (newdecl)) |
| return; |
| |
| for (tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl), |
| t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl); |
| t1 && t1 != void_list_node; |
| t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) |
| if ((DECL_UNIQUE_FRIEND_P (olddecl) && TREE_PURPOSE (t1)) |
| || (DECL_UNIQUE_FRIEND_P (newdecl) && TREE_PURPOSE (t2))) |
| { |
| auto_diagnostic_group d; |
| if (permerror (DECL_SOURCE_LOCATION (newdecl), |
| "friend declaration of %q#D specifies default " |
| "arguments and isn%'t the only declaration", newdecl)) |
| inform (DECL_SOURCE_LOCATION (olddecl), |
| "previous declaration of %q#D", olddecl); |
| return; |
| } |
| } |
| |
| /* Merge tree bits that correspond to attributes noreturn, nothrow, |
| const, malloc, and pure from NEWDECL with those of OLDDECL. */ |
| |
| static void |
| merge_attribute_bits (tree newdecl, tree olddecl) |
| { |
| TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); |
| TREE_THIS_VOLATILE (olddecl) |= TREE_THIS_VOLATILE (newdecl); |
| TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl); |
| TREE_NOTHROW (olddecl) |= TREE_NOTHROW (newdecl); |
| TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); |
| TREE_READONLY (olddecl) |= TREE_READONLY (newdecl); |
| DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); |
| DECL_IS_MALLOC (olddecl) |= DECL_IS_MALLOC (newdecl); |
| DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl); |
| DECL_PURE_P (olddecl) |= DECL_PURE_P (newdecl); |
| DECL_UNINLINABLE (newdecl) |= DECL_UNINLINABLE (olddecl); |
| DECL_UNINLINABLE (olddecl) |= DECL_UNINLINABLE (newdecl); |
| } |
| |
| #define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn) \ |
| && lookup_attribute ("gnu_inline", \ |
| DECL_ATTRIBUTES (fn))) |
| |
| /* A subroutine of duplicate_decls. Emits a diagnostic when newdecl |
| ambiguates olddecl. Returns true if an error occurs. */ |
| |
| static bool |
| duplicate_function_template_decls (tree newdecl, tree olddecl) |
| { |
| |
| tree newres = DECL_TEMPLATE_RESULT (newdecl); |
| tree oldres = DECL_TEMPLATE_RESULT (olddecl); |
| /* Function template declarations can be differentiated by parameter |
| and return type. */ |
| if (compparms (TYPE_ARG_TYPES (TREE_TYPE (oldres)), |
| TYPE_ARG_TYPES (TREE_TYPE (newres))) |
| && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)), |
| TREE_TYPE (TREE_TYPE (olddecl)))) |
| { |
| /* ... and also by their template-heads and requires-clauses. */ |
| if (template_heads_equivalent_p (newdecl, olddecl) |
| && function_requirements_equivalent_p (newres, oldres)) |
| { |
| error ("ambiguating new declaration %q+#D", newdecl); |
| inform (DECL_SOURCE_LOCATION (olddecl), |
| "old declaration %q#D", olddecl); |
| return true; |
| } |
| |
| /* FIXME: The types are the same but the are differences |
| in either the template heads or function requirements. |
| We should be able to diagnose a set of common errors |
| stemming from these declarations. For example: |
| |
| template<typename T> requires C void f(...); |
| template<typename T> void f(...) requires C; |
| |
| These are functionally equivalent but not equivalent. */ |
| } |
| |
| return false; |
| } |
| |
| /* OLD_PARMS is the innermost set of template parameters for some template |
| declaration, and NEW_PARMS is the corresponding set of template parameters |
| for a redeclaration of that template. Merge the default arguments within |
| these two sets of parameters. CLASS_P is true iff the template in |
| question is a class template. */ |
| |
| bool |
| merge_default_template_args (tree new_parms, tree old_parms, bool class_p) |
| { |
| gcc_checking_assert (TREE_VEC_LENGTH (new_parms) |
| == TREE_VEC_LENGTH (old_parms)); |
| for (int i = 0; i < TREE_VEC_LENGTH (new_parms); i++) |
| { |
| tree new_parm = TREE_VALUE (TREE_VEC_ELT (new_parms, i)); |
| tree old_parm = TREE_VALUE (TREE_VEC_ELT (old_parms, i)); |
| tree& new_default = TREE_PURPOSE (TREE_VEC_ELT (new_parms, i)); |
| tree& old_default = TREE_PURPOSE (TREE_VEC_ELT (old_parms, i)); |
| if (new_default != NULL_TREE && old_default != NULL_TREE) |
| { |
| auto_diagnostic_group d; |
| error ("redefinition of default argument for %q+#D", new_parm); |
| inform (DECL_SOURCE_LOCATION (old_parm), |
| "original definition appeared here"); |
| return false; |
| } |
| else if (new_default != NULL_TREE) |
| /* Update the previous template parameters (which are the ones |
| that will really count) with the new default value. */ |
| old_default = new_default; |
| else if (class_p && old_default != NULL_TREE) |
| /* Update the new parameters, too; they'll be used as the |
| parameters for any members. */ |
| new_default = old_default; |
| } |
| return true; |
| } |
| |
| /* 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. |
| |
| HIDING is true if the new decl is being hidden. WAS_HIDDEN is true |
| if the old decl was hidden. |
| |
| Hidden decls can be anticipated builtins, injected friends, or |
| (coming soon) injected from a local-extern decl. */ |
| |
| tree |
| duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) |
| { |
| unsigned olddecl_uid = DECL_UID (olddecl); |
| int types_match = 0; |
| int new_defines_function = 0; |
| tree new_template_info; |
| location_t olddecl_loc = DECL_SOURCE_LOCATION (olddecl); |
| location_t newdecl_loc = DECL_SOURCE_LOCATION (newdecl); |
| |
| 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) |
| return error_mark_node; |
| |
| /* Check for redeclaration and other discrepancies. */ |
| if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_IS_UNDECLARED_BUILTIN (olddecl)) |
| { |
| if (TREE_CODE (newdecl) != FUNCTION_DECL) |
| { |
| /* Avoid warnings redeclaring built-ins which have not been |
| explicitly declared. */ |
| if (was_hidden) |
| { |
| if (TREE_PUBLIC (newdecl) |
| && CP_DECL_CONTEXT (newdecl) == global_namespace) |
| warning_at (newdecl_loc, |
| OPT_Wbuiltin_declaration_mismatch, |
| "built-in function %qD declared as non-function", |
| newdecl); |
| 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)) |
| { |
| warning_at (newdecl_loc, |
| OPT_Wshadow, |
| fndecl_built_in_p (olddecl) |
| ? G_("shadowing built-in function %q#D") |
| : G_("shadowing library function %q#D"), 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 (! fndecl_built_in_p (olddecl)) |
| warning_at (newdecl_loc, 0, |
| "library function %q#D redeclared as non-function %q#D", |
| olddecl, newdecl); |
| else |
| error_at (newdecl_loc, |
| "declaration of %q#D conflicts with built-in " |
| "declaration %q#D", newdecl, olddecl); |
| return NULL_TREE; |
| } |
| else if (!types_match) |
| { |
| /* Avoid warnings redeclaring built-ins which have not been |
| explicitly declared. */ |
| if (was_hidden) |
| { |
| tree t1, t2; |
| |
| /* A new declaration doesn't match a built-in one unless it |
| is also extern "C". */ |
| gcc_assert (DECL_IS_UNDECLARED_BUILTIN (olddecl)); |
| gcc_assert (DECL_EXTERN_C_P (olddecl)); |
| if (!DECL_EXTERN_C_P (newdecl)) |
| return NULL_TREE; |
| |
| for (t1 = TYPE_ARG_TYPES (TREE_TYPE (newdecl)), |
| t2 = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); |
| t1 || t2; |
| t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) |
| { |
| if (!t1 || !t2) |
| break; |
| /* FILE, tm types are not known at the time |
| we create the builtins. */ |
| for (unsigned i = 0; |
| i < sizeof (builtin_structptr_types) |
| / sizeof (builtin_structptr_type); |
| ++i) |
| if (TREE_VALUE (t2) == builtin_structptr_types[i].node) |
| { |
| tree t = TREE_VALUE (t1); |
| |
| if (TYPE_PTR_P (t) |
| && TYPE_IDENTIFIER (TREE_TYPE (t)) |
| == get_identifier (builtin_structptr_types[i].str) |
| && compparms (TREE_CHAIN (t1), TREE_CHAIN (t2))) |
| { |
| tree oldargs = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); |
| |
| TYPE_ARG_TYPES (TREE_TYPE (olddecl)) |
| = TYPE_ARG_TYPES (TREE_TYPE (newdecl)); |
| types_match = decls_match (newdecl, olddecl); |
| if (types_match) |
| return duplicate_decls (newdecl, olddecl, |
| hiding, was_hidden); |
| TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs; |
| } |
| goto next_arg; |
| } |
| |
| if (! same_type_p (TREE_VALUE (t1), TREE_VALUE (t2))) |
| break; |
| next_arg:; |
| } |
| |
| warning_at (newdecl_loc, |
| OPT_Wbuiltin_declaration_mismatch, |
| "declaration of %q#D conflicts with built-in " |
| "declaration %q#D", newdecl, olddecl); |
| } |
| 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)))) |
| { |
| /* Don't really override olddecl for __* prefixed builtins |
| except for __[^b]*_chk, the compiler might be using those |
| explicitly. */ |
| if (fndecl_built_in_p (olddecl)) |
| { |
| tree id = DECL_NAME (olddecl); |
| const char *name = IDENTIFIER_POINTER (id); |
| size_t len; |
| |
| if (name[0] == '_' |
| && name[1] == '_' |
| && (startswith (name + 2, "builtin_") |
| || (len = strlen (name)) <= strlen ("___chk") |
| || memcmp (name + len - strlen ("_chk"), |
| "_chk", strlen ("_chk") + 1) != 0)) |
| { |
| if (DECL_INITIAL (newdecl)) |
| { |
| error_at (newdecl_loc, |
| "definition of %q#D ambiguates built-in " |
| "declaration %q#D", newdecl, olddecl); |
| return error_mark_node; |
| } |
| auto_diagnostic_group d; |
| if (permerror (newdecl_loc, |
| "new declaration %q#D ambiguates built-in" |
| " declaration %q#D", newdecl, olddecl) |
| && flag_permissive) |
| inform (newdecl_loc, |
| "ignoring the %q#D declaration", newdecl); |
| return flag_permissive ? olddecl : error_mark_node; |
| } |
| } |
| |
| /* A near match; override the builtin. */ |
| |
| if (TREE_PUBLIC (newdecl)) |
| warning_at (newdecl_loc, |
| OPT_Wbuiltin_declaration_mismatch, |
| "new declaration %q#D ambiguates built-in " |
| "declaration %q#D", newdecl, olddecl); |
| else |
| warning (OPT_Wshadow, |
| fndecl_built_in_p (olddecl) |
| ? G_("shadowing built-in function %q#D") |
| : G_("shadowing library function %q#D"), olddecl); |
| } |
| else |
| /* Discard the old built-in function. */ |
| return NULL_TREE; |
| |
| /* Replace the old RTL to avoid problems with inlining. */ |
| COPY_DECL_RTL (newdecl, olddecl); |
| } |
| else |
| { |
| /* Even if the types match, prefer the new declarations type |
| for built-ins which have not been explicitly declared, |
| for exception lists, etc... */ |
| 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; |
| } |
| |
| /* If a function is explicitly declared "throw ()", propagate that to |
| the corresponding builtin. */ |
| if (DECL_BUILT_IN_CLASS (olddecl) == BUILT_IN_NORMAL |
| && was_hidden |
| && TREE_NOTHROW (newdecl) |
| && !TREE_NOTHROW (olddecl)) |
| { |
| enum built_in_function fncode = DECL_FUNCTION_CODE (olddecl); |
| tree tmpdecl = builtin_decl_explicit (fncode); |
| if (tmpdecl && tmpdecl != olddecl && types_match) |
| TREE_NOTHROW (tmpdecl) = 1; |
| } |
| |
| /* 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)); |
| COPY_DECL_RTL (newdecl, olddecl); |
| } |
| } |
| else if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) |
| { |
| /* C++ Standard, 3.3, clause 4: |
| "[Note: a namespace name or a class template name must be unique |
| in its declarative region (7.3.2, clause 14). ]" */ |
| if (TREE_CODE (olddecl) == NAMESPACE_DECL |
| || TREE_CODE (newdecl) == NAMESPACE_DECL) |
| /* Namespace conflicts with not namespace. */; |
| else if (DECL_TYPE_TEMPLATE_P (olddecl) |
| || DECL_TYPE_TEMPLATE_P (newdecl)) |
| /* Class template conflicts. */; |
| else if ((TREE_CODE (olddecl) == TEMPLATE_DECL |
| && DECL_TEMPLATE_RESULT (olddecl) |
| && TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == VAR_DECL) |
| || (TREE_CODE (newdecl) == TEMPLATE_DECL |
| && DECL_TEMPLATE_RESULT (newdecl) |
| && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == VAR_DECL)) |
| /* Variable template conflicts. */; |
| else if (concept_definition_p (olddecl) |
| || concept_definition_p (newdecl)) |
| /* Concept conflicts. */; |
| else if ((TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_FUNCTION_TEMPLATE_P (olddecl)) |
| || (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_FUNCTION_TEMPLATE_P (newdecl))) |
| { |
| /* One is a function and the other is a template |
| function. */ |
| if (!UDLIT_OPER_P (DECL_NAME (newdecl))) |
| return NULL_TREE; |
| |
| /* There can only be one! */ |
| if (TREE_CODE (newdecl) == TEMPLATE_DECL |
| && check_raw_literal_operator (olddecl)) |
| error_at (newdecl_loc, |
| "literal operator %q#D conflicts with" |
| " raw literal operator", newdecl); |
| else if (check_raw_literal_operator (newdecl)) |
| error_at (newdecl_loc, |
| "raw literal operator %q#D conflicts with" |
| " literal operator template", newdecl); |
| else |
| return NULL_TREE; |
| |
| inform (olddecl_loc, "previous declaration %q#D", olddecl); |
| return error_mark_node; |
| } |
| else if ((VAR_P (olddecl) && DECL_DECOMPOSITION_P (olddecl)) |
| || (VAR_P (newdecl) && DECL_DECOMPOSITION_P (newdecl))) |
| /* A structured binding must be unique in its declarative region. */; |
| else if (DECL_IMPLICIT_TYPEDEF_P (olddecl) |
| || DECL_IMPLICIT_TYPEDEF_P (newdecl)) |
| /* One is an implicit typedef, that's ok. */ |
| return NULL_TREE; |
| |
| error ("%q#D redeclared as different kind of entity", newdecl); |
| inform (olddecl_loc, "previous declaration %q#D", olddecl); |
| |
| return error_mark_node; |
| } |
| 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) |
| { |
| tree oldres = DECL_TEMPLATE_RESULT (olddecl); |
| tree newres = DECL_TEMPLATE_RESULT (newdecl); |
| |
| /* 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 (oldres) == TYPE_DECL |
| || TREE_CODE (newres) == TYPE_DECL) |
| { |
| error_at (newdecl_loc, |
| "conflicting declaration of template %q#D", newdecl); |
| inform (olddecl_loc, |
| "previous declaration %q#D", olddecl); |
| return error_mark_node; |
| } |
| |
| else if (TREE_CODE (oldres) == FUNCTION_DECL |
| && TREE_CODE (newres) == FUNCTION_DECL) |
| { |
| if (duplicate_function_template_decls (newdecl, olddecl)) |
| return error_mark_node; |
| return NULL_TREE; |
| } |
| else if (check_concept_refinement (olddecl, newdecl)) |
| return error_mark_node; |
| return NULL_TREE; |
| } |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl)) |
| { |
| error_at (newdecl_loc, |
| "conflicting declaration of C function %q#D", |
| newdecl); |
| inform (olddecl_loc, |
| "previous declaration %q#D", olddecl); |
| return error_mark_node; |
| } |
| /* For function versions, params and types match, but they |
| are not ambiguous. */ |
| else if ((!DECL_FUNCTION_VERSIONED (newdecl) |
| && !DECL_FUNCTION_VERSIONED (olddecl)) |
| // The functions have the same parameter types. |
| && compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), |
| TYPE_ARG_TYPES (TREE_TYPE (olddecl))) |
| // And the same constraints. |
| && equivalently_constrained (newdecl, olddecl)) |
| { |
| error_at (newdecl_loc, |
| "ambiguating new declaration of %q#D", newdecl); |
| inform (olddecl_loc, |
| "old declaration %q#D", olddecl); |
| return error_mark_node; |
| } |
| else |
| return NULL_TREE; |
| } |
| else |
| { |
| error_at (newdecl_loc, "conflicting declaration %q#D", newdecl); |
| inform (olddecl_loc, |
| "previous declaration as %q#D", olddecl); |
| return error_mark_node; |
| } |
| } |
| else if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_OMP_DECLARE_REDUCTION_P (newdecl)) |
| { |
| /* OMP UDRs are never duplicates. */ |
| gcc_assert (DECL_OMP_DECLARE_REDUCTION_P (olddecl)); |
| error_at (newdecl_loc, |
| "redeclaration of %<pragma omp declare reduction%>"); |
| inform (olddecl_loc, |
| "previous %<pragma omp declare reduction%> declaration"); |
| return error_mark_node; |
| } |
| 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; |
| |
| /* Leave it to update_binding to merge or report error. */ |
| return NULL_TREE; |
| } |
| else |
| { |
| const char *errmsg = redeclaration_error_message (newdecl, olddecl); |
| if (errmsg) |
| { |
| auto_diagnostic_group d; |
| error_at (newdecl_loc, errmsg, newdecl); |
| if (DECL_NAME (olddecl) != NULL_TREE) |
| inform (olddecl_loc, |
| (DECL_INITIAL (olddecl) && namespace_bindings_p ()) |
| ? G_("%q#D previously defined here") |
| : G_("%q#D previously declared here"), olddecl); |
| return error_mark_node; |
| } |
| else if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_INITIAL (olddecl) != NULL_TREE |
| && !prototype_p (TREE_TYPE (olddecl)) |
| && prototype_p (TREE_TYPE (newdecl))) |
| { |
| /* Prototype decl follows defn w/o prototype. */ |
| auto_diagnostic_group d; |
| if (warning_at (newdecl_loc, 0, |
| "prototype specified for %q#D", newdecl)) |
| inform (olddecl_loc, |
| "previous non-prototype definition here"); |
| } |
| else if (VAR_OR_FUNCTION_DECL_P (olddecl) |
| && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl)) |
| { |
| /* [dcl.link] |
| If two declarations of the same function or object |
| specify different linkage-specifications ..., the program |
| is ill-formed.... Except for functions with C++ linkage, |
| a function declaration without a linkage specification |
| shall not precede the first linkage specification for |
| that function. A function can be declared without a |
| linkage specification after an explicit linkage |
| specification has been seen; the linkage explicitly |
| specified in the earlier declaration is not affected by |
| such a function declaration. |
| |
| DR 563 raises the question why the restrictions on |
| functions should not also apply to objects. Older |
| versions of G++ silently ignore the linkage-specification |
| for this example: |
| |
| namespace N { |
| extern int i; |
| extern "C" int i; |
| } |
| |
| which is clearly wrong. Therefore, we now treat objects |
| like functions. */ |
| if (current_lang_depth () == 0) |
| { |
| /* There is no explicit linkage-specification, so we use |
| the linkage from the previous declaration. */ |
| retrofit_lang_decl (newdecl); |
| SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); |
| } |
| else |
| { |
| auto_diagnostic_group d; |
| error_at (newdecl_loc, |
| "conflicting declaration of %q#D with %qL linkage", |
| newdecl, DECL_LANGUAGE (newdecl)); |
| inform (olddecl_loc, |
| "previous declaration with %qL linkage", |
| DECL_LANGUAGE (olddecl)); |
| } |
| } |
| |
| if (DECL_LANG_SPECIFIC (olddecl) && DECL_USE_TEMPLATE (olddecl)) |
| ; |
| else if (TREE_CODE (olddecl) == FUNCTION_DECL) |
| { |
| /* Note: free functions, as TEMPLATE_DECLs, are handled below. */ |
| if (DECL_FUNCTION_MEMBER_P (olddecl) |
| && (/* grokfndecl passes member function templates too |
| as FUNCTION_DECLs. */ |
| DECL_TEMPLATE_INFO (olddecl) |
| /* C++11 8.3.6/6. |
| Default arguments for a member function of a class |
| template shall be specified on the initial declaration |
| of the member function within the class template. */ |
| || CLASSTYPE_TEMPLATE_INFO (CP_DECL_CONTEXT (olddecl)))) |
| { |
| check_redeclaration_no_default_args (newdecl); |
| |
| if (DECL_TEMPLATE_INFO (olddecl) |
| && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (olddecl))) |
| { |
| tree new_parms = DECL_TEMPLATE_INFO (newdecl) |
| ? DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (newdecl)) |
| : INNERMOST_TEMPLATE_PARMS (current_template_parms); |
| tree old_parms |
| = DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (olddecl)); |
| merge_default_template_args (new_parms, old_parms, |
| /*class_p=*/false); |
| } |
| } |
| else |
| { |
| tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl); |
| tree t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl); |
| int i = 1; |
| |
| for (; t1 && t1 != void_list_node; |
| t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2), i++) |
| if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2)) |
| { |
| if (simple_cst_equal (TREE_PURPOSE (t1), |
| TREE_PURPOSE (t2)) == 1) |
| { |
| auto_diagnostic_group d; |
| if (permerror (newdecl_loc, |
| "default argument given for parameter " |
| "%d of %q#D", i, newdecl)) |
| inform (olddecl_loc, |
| "previous specification in %q#D here", |
| olddecl); |
| } |
| else |
| { |
| auto_diagnostic_group d; |
| error_at (newdecl_loc, |
| "default argument given for parameter %d " |
| "of %q#D", i, newdecl); |
| inform (olddecl_loc, |
| "previous specification in %q#D here", |
| olddecl); |
| } |
| } |
| |
| /* C++17 11.3.6/4: "If a friend declaration specifies a default |
| argument expression, that declaration... shall be the only |
| declaration of the function or function template in the |
| translation unit." */ |
| check_no_redeclaration_friend_default_args (olddecl, newdecl); |
| } |
| } |
| } |
| |
| /* 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 (DECL_TEMPLATE_PARM_P (olddecl) != DECL_TEMPLATE_PARM_P (newdecl)) |
| return NULL_TREE; |
| |
| if (!validate_constexpr_redeclaration (olddecl, newdecl)) |
| return error_mark_node; |
| |
| if (modules_p () |
| && TREE_CODE (CP_DECL_CONTEXT (olddecl)) == NAMESPACE_DECL |
| && TREE_CODE (olddecl) != NAMESPACE_DECL |
| && !hiding) |
| { |
| if (DECL_ARTIFICIAL (olddecl)) |
| { |
| if (!(global_purview_p () || not_module_p ())) |
| error ("declaration %qD conflicts with builtin", newdecl); |
| else |
| DECL_MODULE_EXPORT_P (olddecl) = DECL_MODULE_EXPORT_P (newdecl); |
| } |
| else |
| { |
| if (!module_may_redeclare (olddecl)) |
| { |
| error ("declaration %qD conflicts with import", newdecl); |
| inform (olddecl_loc, "import declared %q#D here", olddecl); |
| |
| return error_mark_node; |
| } |
| |
| if (DECL_MODULE_EXPORT_P (newdecl) |
| && !DECL_MODULE_EXPORT_P (olddecl)) |
| { |
| error ("conflicting exporting declaration %qD", newdecl); |
| inform (olddecl_loc, "previous declaration %q#D here", olddecl); |
| } |
| } |
| } |
| |
| /* We have committed to returning OLDDECL at this point. */ |
| |
| /* If new decl is `static' and an `extern' was seen previously, |
| warn about it. */ |
| warn_extern_redeclared_static (newdecl, olddecl); |
| |
| /* True to merge attributes between the declarations, false to |
| set OLDDECL's attributes to those of NEWDECL (for template |
| explicit specializations that specify their own attributes |
| independent of those specified for the primary template). */ |
| const bool merge_attr = (TREE_CODE (newdecl) != FUNCTION_DECL |
| || !DECL_TEMPLATE_SPECIALIZATION (newdecl) |
| || DECL_TEMPLATE_SPECIALIZATION (olddecl)); |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (merge_attr) |
| { |
| if (diagnose_mismatched_attributes (olddecl, newdecl)) |
| inform (olddecl_loc, DECL_INITIAL (olddecl) |
| ? G_("previous definition of %qD here") |
| : G_("previous declaration of %qD here"), olddecl); |
| |
| /* [dcl.attr.noreturn]: The first declaration of a function shall |
| specify the noreturn attribute if any declaration of that function |
| specifies the noreturn attribute. */ |
| tree a; |
| if (TREE_THIS_VOLATILE (newdecl) |
| && !TREE_THIS_VOLATILE (olddecl) |
| /* This applies to [[noreturn]] only, not its GNU variants. */ |
| && (a = lookup_attribute ("noreturn", DECL_ATTRIBUTES (newdecl))) |
| && cxx11_attribute_p (a) |
| && get_attribute_namespace (a) == NULL_TREE) |
| { |
| error_at (newdecl_loc, "function %qD declared %<[[noreturn]]%> " |
| "but its first declaration was not", newdecl); |
| inform (olddecl_loc, "previous declaration of %qD", olddecl); |
| } |
| } |
| |
| /* 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_INVALID_OVERRIDER_P (newdecl) |= DECL_INVALID_OVERRIDER_P (olddecl); |
| DECL_FINAL_P (newdecl) |= DECL_FINAL_P (olddecl); |
| DECL_OVERRIDE_P (newdecl) |= DECL_OVERRIDE_P (olddecl); |
| DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl); |
| DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (newdecl) |
| |= DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (olddecl); |
| if (DECL_OVERLOADED_OPERATOR_P (olddecl)) |
| DECL_OVERLOADED_OPERATOR_CODE_RAW (newdecl) |
| = DECL_OVERLOADED_OPERATOR_CODE_RAW (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 if at least one is/was hidden. */ |
| && !(hiding || was_hidden) |
| /* Don't warn about declaration followed by specialization. */ |
| && (! DECL_TEMPLATE_SPECIALIZATION (newdecl) |
| || DECL_TEMPLATE_SPECIALIZATION (olddecl))) |
| { |
| auto_diagnostic_group d; |
| if (warning_at (newdecl_loc, |
| OPT_Wredundant_decls, |
| "redundant redeclaration of %qD in same scope", |
| newdecl)) |
| inform (olddecl_loc, |
| "previous declaration of %qD", olddecl); |
| } |
| |
| /* [dcl.fct.def.delete] A deleted definition of a function shall be the |
| first declaration of the function or, for an explicit specialization |
| of a function template, the first declaration of that |
| specialization. */ |
| if (!(DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && DECL_TEMPLATE_SPECIALIZATION (newdecl))) |
| { |
| if (DECL_DELETED_FN (newdecl)) |
| { |
| auto_diagnostic_group d; |
| if (pedwarn (newdecl_loc, 0, "deleted definition of %qD " |
| "is not first declaration", newdecl)) |
| inform (olddecl_loc, |
| "previous declaration of %qD", olddecl); |
| } |
| DECL_DELETED_FN (newdecl) |= DECL_DELETED_FN (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. */ |
| if (merge_attr) |
| DECL_ATTRIBUTES (newdecl) |
| = (*targetm.merge_decl_attributes) (olddecl, newdecl); |
| else |
| DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl); |
| |
| if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| tree old_result = DECL_TEMPLATE_RESULT (olddecl); |
| tree new_result = DECL_TEMPLATE_RESULT (newdecl); |
| TREE_TYPE (olddecl) = TREE_TYPE (old_result); |
| |
| /* The new decl should not already have gathered any |
| specializations. */ |
| gcc_assert (!DECL_TEMPLATE_SPECIALIZATIONS (newdecl)); |
| |
| DECL_ATTRIBUTES (old_result) |
| = (*targetm.merge_decl_attributes) (old_result, new_result); |
| |
| if (DECL_FUNCTION_TEMPLATE_P (newdecl)) |
| { |
| if (DECL_SOURCE_LOCATION (newdecl) |
| != DECL_SOURCE_LOCATION (olddecl)) |
| { |
| /* Per C++11 8.3.6/4, default arguments cannot be added in |
| later declarations of a function template. */ |
| check_redeclaration_no_default_args (newdecl); |
| /* C++17 11.3.6/4: "If a friend declaration specifies a default |
| argument expression, that declaration... shall be the only |
| declaration of the function or function template in the |
| translation unit." */ |
| check_no_redeclaration_friend_default_args |
| (old_result, new_result); |
| |
| tree new_parms = DECL_INNERMOST_TEMPLATE_PARMS (newdecl); |
| tree old_parms = DECL_INNERMOST_TEMPLATE_PARMS (olddecl); |
| merge_default_template_args (new_parms, old_parms, |
| /*class_p=*/false); |
| } |
| if (!DECL_UNIQUE_FRIEND_P (old_result)) |
| DECL_UNIQUE_FRIEND_P (new_result) = false; |
| |
| check_default_args (newdecl); |
| |
| if (GNU_INLINE_P (old_result) != GNU_INLINE_P (new_result) |
| && DECL_INITIAL (new_result)) |
| { |
| if (DECL_INITIAL (old_result)) |
| DECL_UNINLINABLE (old_result) = 1; |
| else |
| DECL_UNINLINABLE (old_result) = DECL_UNINLINABLE (new_result); |
| DECL_EXTERNAL (old_result) = DECL_EXTERNAL (new_result); |
| DECL_NOT_REALLY_EXTERN (old_result) |
| = DECL_NOT_REALLY_EXTERN (new_result); |
| DECL_INTERFACE_KNOWN (old_result) |
| = DECL_INTERFACE_KNOWN (new_result); |
| DECL_DECLARED_INLINE_P (old_result) |
| = DECL_DECLARED_INLINE_P (new_result); |
| DECL_DISREGARD_INLINE_LIMITS (old_result) |
| |= DECL_DISREGARD_INLINE_LIMITS (new_result); |
| |
| } |
| else |
| { |
| DECL_DECLARED_INLINE_P (old_result) |
| |= DECL_DECLARED_INLINE_P (new_result); |
| DECL_DISREGARD_INLINE_LIMITS (old_result) |
| |= DECL_DISREGARD_INLINE_LIMITS (new_result); |
| check_redeclaration_exception_specification (newdecl, olddecl); |
| |
| merge_attribute_bits (new_result, old_result); |
| } |
| } |
| |
| /* If the new declaration is a definition, update the file and |
| line information on the declaration, and also make |
| the old declaration the same definition. */ |
| if (DECL_INITIAL (new_result) != NULL_TREE) |
| { |
| DECL_SOURCE_LOCATION (olddecl) |
| = DECL_SOURCE_LOCATION (old_result) |
| = DECL_SOURCE_LOCATION (newdecl); |
| DECL_INITIAL (old_result) = DECL_INITIAL (new_result); |
| if (DECL_FUNCTION_TEMPLATE_P (newdecl)) |
| { |
| tree parm; |
| DECL_ARGUMENTS (old_result) |
| = DECL_ARGUMENTS (new_result); |
| for (parm = DECL_ARGUMENTS (old_result); parm; |
| parm = DECL_CHAIN (parm)) |
| DECL_CONTEXT (parm) = old_result; |
| |
| if (tree fc = DECL_FRIEND_CONTEXT (new_result)) |
| SET_DECL_FRIEND_CONTEXT (old_result, fc); |
| } |
| } |
| |
| return olddecl; |
| } |
| |
| if (types_match) |
| { |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| check_redeclaration_exception_specification (newdecl, olddecl); |
| |
| /* Automatically handles default parameters. */ |
| tree oldtype = TREE_TYPE (olddecl); |
| tree newtype; |
| |
| /* For typedefs use the old type, as the new type's DECL_NAME points |
| at newdecl, which will be ggc_freed. */ |
| if (TREE_CODE (newdecl) == TYPE_DECL) |
| { |
| /* But NEWTYPE might have an attribute, honor that. */ |
| tree tem = TREE_TYPE (newdecl); |
| newtype = oldtype; |
| |
| if (TYPE_USER_ALIGN (tem)) |
| { |
| if (TYPE_ALIGN (tem) > TYPE_ALIGN (newtype)) |
| SET_TYPE_ALIGN (newtype, TYPE_ALIGN (tem)); |
| TYPE_USER_ALIGN (newtype) = true; |
| } |
| |
| /* And remove the new type from the variants list. */ |
| if (TYPE_NAME (TREE_TYPE (newdecl)) == newdecl) |
| { |
| tree remove = TREE_TYPE (newdecl); |
| if (TYPE_MAIN_VARIANT (remove) == remove) |
| { |
| gcc_assert (TYPE_NEXT_VARIANT (remove) == NULL_TREE); |
| /* If remove is the main variant, no need to remove that |
| from the list. One of the DECL_ORIGINAL_TYPE |
| variants, e.g. created for aligned attribute, might still |
| refer to the newdecl TYPE_DECL though, so remove that one |
| in that case. */ |
| if (tree orig = DECL_ORIGINAL_TYPE (newdecl)) |
| if (orig != remove) |
| for (tree t = TYPE_MAIN_VARIANT (orig); t; |
| t = TYPE_MAIN_VARIANT (t)) |
| if (TYPE_NAME (TYPE_NEXT_VARIANT (t)) == newdecl) |
| { |
| TYPE_NEXT_VARIANT (t) |
| = TYPE_NEXT_VARIANT (TYPE_NEXT_VARIANT (t)); |
| break; |
| } |
| } |
| else |
| for (tree t = TYPE_MAIN_VARIANT (remove); ; |
| t = TYPE_NEXT_VARIANT (t)) |
| if (TYPE_NEXT_VARIANT (t) == remove) |
| { |
| TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (remove); |
| break; |
| } |
| } |
| } |
| else if (merge_attr) |
| newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); |
| else |
| newtype = TREE_TYPE (newdecl); |
| |
| if (VAR_P (newdecl)) |
| { |
| DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl); |
| /* For already initialized vars, TREE_READONLY could have been |
| cleared in cp_finish_decl, because the var needs runtime |
| initialization or destruction. Make sure not to set |
| TREE_READONLY on it again. */ |
| if (DECL_INITIALIZED_P (olddecl) |
| && !DECL_EXTERNAL (olddecl) |
| && !TREE_READONLY (olddecl)) |
| TREE_READONLY (newdecl) = 0; |
| DECL_INITIALIZED_P (newdecl) |= DECL_INITIALIZED_P (olddecl); |
| DECL_NONTRIVIALLY_INITIALIZED_P (newdecl) |
| |= DECL_NONTRIVIALLY_INITIALIZED_P (olddecl); |
| if (DECL_DEPENDENT_INIT_P (olddecl)) |
| SET_DECL_DEPENDENT_INIT_P (newdecl, true); |
| DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl) |
| |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl); |
| DECL_DECLARED_CONSTEXPR_P (newdecl) |
| |= DECL_DECLARED_CONSTEXPR_P (olddecl); |
| DECL_DECLARED_CONSTINIT_P (newdecl) |
| |= DECL_DECLARED_CONSTINIT_P (olddecl); |
| |
| /* Merge the threadprivate attribute from OLDDECL into NEWDECL. */ |
| if (DECL_LANG_SPECIFIC (olddecl) |
| && CP_DECL_THREADPRIVATE_P (olddecl)) |
| { |
| /* Allocate a LANG_SPECIFIC structure for NEWDECL, if needed. */ |
| retrofit_lang_decl (newdecl); |
| CP_DECL_THREADPRIVATE_P (newdecl) = 1; |
| } |
| } |
| |
| /* An explicit specialization of a function template or of a member |
| function of a class template can be declared transaction_safe |
| independently of whether the corresponding template entity is declared |
| transaction_safe. */ |
| if (flag_tm && TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && DECL_TEMPLATE_SPECIALIZATION (newdecl) |
| && tx_safe_fn_type_p (newtype) |
| && !tx_safe_fn_type_p (TREE_TYPE (newdecl))) |
| newtype = tx_unsafe_fn_variant (newtype); |
| |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype; |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| check_default_args (newdecl); |
| |
| /* 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 ((VAR_P (newdecl) |
| || 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 deprecatedness. */ |
| if (TREE_DEPRECATED (newdecl)) |
| TREE_DEPRECATED (olddecl) = 1; |
| |
| /* Merge unavailability. */ |
| if (TREE_UNAVAILABLE (newdecl)) |
| TREE_UNAVAILABLE (olddecl) = 1; |
| |
| /* Preserve function specific target and optimization options */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (DECL_FUNCTION_SPECIFIC_TARGET (olddecl) |
| && !DECL_FUNCTION_SPECIFIC_TARGET (newdecl)) |
| DECL_FUNCTION_SPECIFIC_TARGET (newdecl) |
| = DECL_FUNCTION_SPECIFIC_TARGET (olddecl); |
| |
| if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl) |
| && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl)) |
| DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl) |
| = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl); |
| |
| if (!DECL_UNIQUE_FRIEND_P (olddecl)) |
| DECL_UNIQUE_FRIEND_P (newdecl) = false; |
| } |
| else |
| { |
| /* Merge the const type qualifier. */ |
| if (TREE_READONLY (newdecl)) |
| TREE_READONLY (olddecl) = 1; |
| /* Merge the volatile type qualifier. */ |
| 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 (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl); |
| DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (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); |
| if (DECL_IS_OPERATOR_NEW_P (olddecl)) |
| DECL_SET_IS_OPERATOR_NEW (newdecl, true); |
| DECL_LOOPING_CONST_OR_PURE_P (newdecl) |
| |= DECL_LOOPING_CONST_OR_PURE_P (olddecl); |
| DECL_IS_REPLACEABLE_OPERATOR (newdecl) |
| |= DECL_IS_REPLACEABLE_OPERATOR (olddecl); |
| |
| if (merge_attr) |
| merge_attribute_bits (newdecl, olddecl); |
| else |
| { |
| /* Merge the noreturn bit. */ |
| TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); |
| TREE_READONLY (olddecl) = TREE_READONLY (newdecl); |
| TREE_NOTHROW (olddecl) = TREE_NOTHROW (newdecl); |
| DECL_IS_MALLOC (olddecl) = DECL_IS_MALLOC (newdecl); |
| DECL_PURE_P (olddecl) = DECL_PURE_P (newdecl); |
| } |
| /* Keep the old RTL. */ |
| COPY_DECL_RTL (olddecl, newdecl); |
| } |
| else if (VAR_P (newdecl) |
| && (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_NOTHROW (olddecl) = TREE_NOTHROW (newdecl); |
| TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl); |
| } |
| |
| /* Merge the storage class information. */ |
| merge_weak (newdecl, 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_COMDAT (olddecl)) |
| DECL_COMDAT (newdecl) = 0; |
| |
| if (VAR_OR_FUNCTION_DECL_P (newdecl) && DECL_LOCAL_DECL_P (newdecl)) |
| { |
| if (!DECL_LOCAL_DECL_P (olddecl)) |
| /* This can happen if olddecl was brought in from the |
| enclosing namespace via a using-decl. The new decl is |
| then not a block-scope extern at all. */ |
| DECL_LOCAL_DECL_P (newdecl) = false; |
| else |
| { |
| retrofit_lang_decl (newdecl); |
| tree alias = DECL_LOCAL_DECL_ALIAS (newdecl) |
| = DECL_LOCAL_DECL_ALIAS (olddecl); |
| DECL_ATTRIBUTES (alias) |
| = (*targetm.merge_decl_attributes) (alias, newdecl); |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| merge_attribute_bits (newdecl, alias); |
| } |
| } |
| |
| new_template_info = NULL_TREE; |
| if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl)) |
| { |
| bool new_redefines_gnu_inline = false; |
| |
| if (new_defines_function |
| && ((DECL_INTERFACE_KNOWN (olddecl) |
| && TREE_CODE (olddecl) == FUNCTION_DECL) |
| || (TREE_CODE (olddecl) == TEMPLATE_DECL |
| && (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) |
| == FUNCTION_DECL)))) |
| new_redefines_gnu_inline = GNU_INLINE_P (STRIP_TEMPLATE (olddecl)); |
| |
| if (!new_redefines_gnu_inline) |
| { |
| DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl); |
| DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl); |
| DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl); |
| } |
| |
| if (TREE_CODE (newdecl) != TYPE_DECL) |
| { |
| DECL_TEMPLATE_INSTANTIATED (newdecl) |
| |= DECL_TEMPLATE_INSTANTIATED (olddecl); |
| DECL_ODR_USED (newdecl) |= DECL_ODR_USED (olddecl); |
| |
| /* If the OLDDECL is an instantiation and/or specialization, |
| then the NEWDECL must be too. But, it may not yet be marked |
| as such if the caller has created NEWDECL, but has not yet |
| figured out that it is a redeclaration. */ |
| if (!DECL_USE_TEMPLATE (newdecl)) |
| DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl); |
| |
| if (!DECL_TEMPLATE_SPECIALIZATION (newdecl)) |
| DECL_INITIALIZED_IN_CLASS_P (newdecl) |
| |= DECL_INITIALIZED_IN_CLASS_P (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); |
| |
| if (LANG_DECL_HAS_MIN (newdecl)) |
| { |
| DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl); |
| if (DECL_TEMPLATE_INFO (newdecl)) |
| { |
| new_template_info = DECL_TEMPLATE_INFO (newdecl); |
| if (DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && DECL_TEMPLATE_SPECIALIZATION (newdecl)) |
| /* Remember the presence of explicit specialization args. */ |
| TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (olddecl)) |
| = TINFO_USED_TEMPLATE_ID (new_template_info); |
| } |
| DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); |
| } |
| |
| if (DECL_DECLARES_FUNCTION_P (newdecl)) |
| { |
| /* Only functions have these fields. */ |
| DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl); |
| 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)) |
| SET_DECL_THUNKS (newdecl, DECL_THUNKS (olddecl)); |
| else if (tree fc = DECL_FRIEND_CONTEXT (newdecl)) |
| SET_DECL_FRIEND_CONTEXT (olddecl, fc); |
| } |
| else if (VAR_P (newdecl)) |
| { |
| /* Only variables have this field. */ |
| if (VAR_HAD_UNKNOWN_BOUND (olddecl)) |
| SET_VAR_HAD_UNKNOWN_BOUND (newdecl); |
| } |
| } |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| tree parm; |
| |
| /* Merge parameter attributes. */ |
| tree oldarg, newarg; |
| for (oldarg = DECL_ARGUMENTS(olddecl), newarg = DECL_ARGUMENTS(newdecl); |
| oldarg && newarg; |
| oldarg = DECL_CHAIN(oldarg), newarg = DECL_CHAIN(newarg)) |
| { |
| DECL_ATTRIBUTES (newarg) |
| = (*targetm.merge_decl_attributes) (oldarg, newarg); |
| DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg); |
| } |
| |
| 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. */ |
| gcc_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl)); |
| |
| if (DECL_ODR_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 %qD after first use", |
| olddecl); |
| |
| SET_DECL_TEMPLATE_SPECIALIZATION (olddecl); |
| DECL_COMDAT (newdecl) = (TREE_PUBLIC (newdecl) |
| && DECL_DECLARED_INLINE_P (newdecl)); |
| |
| /* Don't propagate visibility from the template to the |
| specialization here. We'll do that in determine_visibility if |
| appropriate. */ |
| DECL_VISIBILITY_SPECIFIED (olddecl) = 0; |
| |
| /* [temp.expl.spec/14] We don't inline explicit specialization |
| just because the primary template says so. */ |
| gcc_assert (!merge_attr); |
| |
| DECL_DECLARED_INLINE_P (olddecl) |
| = DECL_DECLARED_INLINE_P (newdecl); |
| |
| DECL_DISREGARD_INLINE_LIMITS (olddecl) |
| = DECL_DISREGARD_INLINE_LIMITS (newdecl); |
| |
| DECL_UNINLINABLE (olddecl) = DECL_UNINLINABLE (newdecl); |
| } |
| else if (new_defines_function && DECL_INITIAL (olddecl)) |
| { |
| /* Never inline re-defined extern inline functions. |
| FIXME: this could be better handled by keeping both |
| function as separate declarations. */ |
| DECL_UNINLINABLE (newdecl) = 1; |
| } |
| else |
| { |
| if (DECL_PENDING_INLINE_P (olddecl)) |
| { |
| DECL_PENDING_INLINE_P (newdecl) = 1; |
| DECL_PENDING_INLINE_INFO (newdecl) |
| = DECL_PENDING_INLINE_INFO (olddecl); |
| } |
| else if (DECL_PENDING_INLINE_P (newdecl)) |
| ; |
| else if (DECL_SAVED_AUTO_RETURN_TYPE (newdecl) == NULL) |
| DECL_SAVED_AUTO_RETURN_TYPE (newdecl) |
| = DECL_SAVED_AUTO_RETURN_TYPE (olddecl); |
| |
| DECL_DECLARED_INLINE_P (newdecl) |= DECL_DECLARED_INLINE_P (olddecl); |
| |
| DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl) |
| = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)); |
| |
| DECL_DISREGARD_INLINE_LIMITS (newdecl) |
| = DECL_DISREGARD_INLINE_LIMITS (olddecl) |
| = (DECL_DISREGARD_INLINE_LIMITS (newdecl) |
| || DECL_DISREGARD_INLINE_LIMITS (olddecl)); |
| } |
| |
| /* Preserve abstractness on cloned [cd]tors. */ |
| DECL_ABSTRACT_P (newdecl) = DECL_ABSTRACT_P (olddecl); |
| |
| /* Update newdecl's parms to point at olddecl. */ |
| for (parm = DECL_ARGUMENTS (newdecl); parm; |
| parm = DECL_CHAIN (parm)) |
| DECL_CONTEXT (parm) = olddecl; |
| |
| if (! types_match) |
| { |
| SET_DECL_LANGUAGE (olddecl, DECL_LANGUAGE (newdecl)); |
| COPY_DECL_ASSEMBLER_NAME (newdecl, olddecl); |
| COPY_DECL_RTL (newdecl, olddecl); |
| } |
| 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 redeclaring a builtin function, it stays built in |
| if newdecl is a gnu_inline definition, or if newdecl is just |
| a declaration. */ |
| if (fndecl_built_in_p (olddecl) |
| && (new_defines_function ? GNU_INLINE_P (newdecl) : types_match)) |
| { |
| copy_decl_built_in_function (newdecl, olddecl); |
| /* If we're keeping the built-in definition, keep the rtl, |
| regardless of declaration matches. */ |
| COPY_DECL_RTL (olddecl, newdecl); |
| if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL) |
| { |
| enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl); |
| if (builtin_decl_explicit_p (fncode)) |
| { |
| /* A compatible prototype of these builtin functions |
| is seen, assume the runtime implements it with |
| the expected semantics. */ |
| switch (fncode) |
| { |
| case BUILT_IN_STPCPY: |
| set_builtin_decl_implicit_p (fncode, true); |
| break; |
| default: |
| set_builtin_decl_declared_p (fncode, true); |
| break; |
| } |
| } |
| |
| copy_attributes_to_builtin (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) |
| { |
| DECL_RESULT (newdecl) = DECL_RESULT (olddecl); |
| /* Don't clear out the arguments if we're just redeclaring 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); |
| |
| /* Warn about conflicting visibility specifications. */ |
| if (DECL_VISIBILITY_SPECIFIED (olddecl) |
| && DECL_VISIBILITY_SPECIFIED (newdecl) |
| && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) |
| { |
| auto_diagnostic_group d; |
| if (warning_at (newdecl_loc, OPT_Wattributes, |
| "%qD: visibility attribute ignored because it " |
| "conflicts with previous declaration", newdecl)) |
| inform (olddecl_loc, |
| "previous declaration of %qD", olddecl); |
| } |
| /* Choose the declaration which specified visibility. */ |
| if (DECL_VISIBILITY_SPECIFIED (olddecl)) |
| { |
| DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); |
| DECL_VISIBILITY_SPECIFIED (newdecl) = 1; |
| } |
| /* Init priority used to be merged from newdecl to olddecl by the memcpy, |
| so keep this behavior. */ |
| if (VAR_P (newdecl) && DECL_HAS_INIT_PRIORITY_P (newdecl)) |
| { |
| SET_DECL_INIT_PRIORITY (olddecl, DECL_INIT_PRIORITY (newdecl)); |
| DECL_HAS_INIT_PRIORITY_P (olddecl) = 1; |
| } |
| /* Likewise for DECL_ALIGN, DECL_USER_ALIGN and DECL_PACKED. */ |
| if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) |
| { |
| SET_DECL_ALIGN (newdecl, DECL_ALIGN (olddecl)); |
| DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); |
| } |
| else if (DECL_ALIGN (olddecl) == DECL_ALIGN (newdecl) |
| && DECL_USER_ALIGN (olddecl) != DECL_USER_ALIGN (newdecl)) |
| DECL_USER_ALIGN (newdecl) = 1; |
| |
| DECL_USER_ALIGN (olddecl) = DECL_USER_ALIGN (newdecl); |
| if (DECL_WARN_IF_NOT_ALIGN (olddecl) |
| > DECL_WARN_IF_NOT_ALIGN (newdecl)) |
| SET_DECL_WARN_IF_NOT_ALIGN (newdecl, |
| DECL_WARN_IF_NOT_ALIGN (olddecl)); |
| if (TREE_CODE (newdecl) == FIELD_DECL) |
| DECL_PACKED (olddecl) = DECL_PACKED (newdecl); |
| |
| /* The DECL_LANG_SPECIFIC information in OLDDECL will be replaced |
| with that from NEWDECL below. */ |
| if (DECL_LANG_SPECIFIC (olddecl)) |
| { |
| gcc_checking_assert (DECL_LANG_SPECIFIC (olddecl) |
| != DECL_LANG_SPECIFIC (newdecl)); |
| ggc_free (DECL_LANG_SPECIFIC (olddecl)); |
| } |
| |
| /* Merge the USED information. */ |
| if (TREE_USED (olddecl)) |
| TREE_USED (newdecl) = 1; |
| else if (TREE_USED (newdecl)) |
| TREE_USED (olddecl) = 1; |
| |
| if (VAR_P (newdecl)) |
| { |
| if (DECL_READ_P (olddecl)) |
| DECL_READ_P (newdecl) = 1; |
| else if (DECL_READ_P (newdecl)) |
| DECL_READ_P (olddecl) = 1; |
| } |
| |
| if (DECL_PRESERVE_P (olddecl)) |
| DECL_PRESERVE_P (newdecl) = 1; |
| else if (DECL_PRESERVE_P (newdecl)) |
| DECL_PRESERVE_P (olddecl) = 1; |
| |
| /* Merge the DECL_FUNCTION_VERSIONED information. newdecl will be copied |
| to olddecl and deleted. */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_FUNCTION_VERSIONED (olddecl)) |
| { |
| /* Set the flag for newdecl so that it gets copied to olddecl. */ |
| DECL_FUNCTION_VERSIONED (newdecl) = 1; |
| /* newdecl will be purged after copying to olddecl and is no longer |
| a version. */ |
| cgraph_node::delete_function_version_by_decl (newdecl); |
| } |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| int function_size; |
| struct symtab_node *snode = symtab_node::get (olddecl); |
| |
| function_size = sizeof (struct tree_decl_common); |
| |
| memcpy ((char *) olddecl + sizeof (struct tree_common), |
| (char *) newdecl + sizeof (struct tree_common), |
| function_size - sizeof (struct tree_common)); |
| |
| memcpy ((char *) olddecl + sizeof (struct tree_decl_common), |
| (char *) newdecl + sizeof (struct tree_decl_common), |
| sizeof (struct tree_function_decl) - sizeof (struct tree_decl_common)); |
| |
| /* Preserve symtab node mapping. */ |
| olddecl->decl_with_vis.symtab_node = snode; |
| |
| if (new_template_info) |
| /* 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, |
| new_template_info, |
| olddecl); |
| } |
| else |
| { |
| size_t size = tree_code_size (TREE_CODE (newdecl)); |
| |
| memcpy ((char *) olddecl + sizeof (struct tree_common), |
| (char *) newdecl + sizeof (struct tree_common), |
| sizeof (struct tree_decl_common) - sizeof (struct tree_common)); |
| |
| switch (TREE_CODE (newdecl)) |
| { |
| case LABEL_DECL: |
| case VAR_DECL: |
| case RESULT_DECL: |
| case PARM_DECL: |
| case FIELD_DECL: |
| case TYPE_DECL: |
| case CONST_DECL: |
| { |
| struct symtab_node *snode = NULL; |
| |
| if (VAR_P (newdecl) |
| && (TREE_STATIC (olddecl) || TREE_PUBLIC (olddecl) |
| || DECL_EXTERNAL (olddecl))) |
| snode = symtab_node::get (olddecl); |
| memcpy ((char *) olddecl + sizeof (struct tree_decl_common), |
| (char *) newdecl + sizeof (struct tree_decl_common), |
| size - sizeof (struct tree_decl_common) |
| + TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *)); |
| if (VAR_P (newdecl)) |
| olddecl->decl_with_vis.symtab_node = snode; |
| } |
| break; |
| default: |
| memcpy ((char *) olddecl + sizeof (struct tree_decl_common), |
| (char *) newdecl + sizeof (struct tree_decl_common), |
| sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common) |
| + TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *)); |
| break; |
| } |
| } |
| |
| if (VAR_OR_FUNCTION_DECL_P (newdecl)) |
| { |
| if (DECL_EXTERNAL (olddecl) |
| || TREE_PUBLIC (olddecl) |
| || TREE_STATIC (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) |
| set_decl_section_name (olddecl, newdecl); |
| |
| if (DECL_ONE_ONLY (newdecl)) |
| { |
| struct symtab_node *oldsym, *newsym; |
| if (TREE_CODE (olddecl) == FUNCTION_DECL) |
| oldsym = cgraph_node::get_create (olddecl); |
| else |
| oldsym = varpool_node::get_create (olddecl); |
| newsym = symtab_node::get (newdecl); |
| oldsym->set_comdat_group (newsym->get_comdat_group ()); |
| } |
| } |
| |
| if (VAR_P (newdecl) |
| && CP_DECL_THREAD_LOCAL_P (newdecl)) |
| { |
| CP_DECL_THREAD_LOCAL_P (olddecl) = true; |
| if (!processing_template_decl) |
| set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl)); |
| } |
| } |
| |
| DECL_UID (olddecl) = olddecl_uid; |
| |
| /* 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 |
| || (VAR_P (olddecl) |
| && TREE_STATIC (olddecl)))) |
| make_decl_rtl (olddecl); |
| |
| /* The NEWDECL will no longer be needed. Because every out-of-class |
| declaration of a member results in a call to duplicate_decls, |
| freeing these nodes represents in a significant savings. |
| |
| Before releasing the node, be sore to remove function from symbol |
| table that might have been inserted there to record comdat group. |
| Be sure to however do not free DECL_STRUCT_FUNCTION because this |
| structure is shared in between newdecl and oldecl. */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| DECL_STRUCT_FUNCTION (newdecl) = NULL; |
| if (VAR_OR_FUNCTION_DECL_P (newdecl)) |
| { |
| struct symtab_node *snode = symtab_node::get (newdecl); |
| if (snode) |
| snode->remove (); |
| } |
| |
| if (TREE_CODE (olddecl) == FUNCTION_DECL) |
| { |
| tree clone; |
| FOR_EACH_CLONE (clone, olddecl) |
| { |
| DECL_ATTRIBUTES (clone) = DECL_ATTRIBUTES (olddecl); |
| DECL_PRESERVE_P (clone) |= DECL_PRESERVE_P (olddecl); |
| } |
| } |
| |
| /* Remove the associated constraints for newdecl, if any, before |
| reclaiming memory. */ |
| if (flag_concepts) |
| remove_constraints (newdecl); |
| |
| ggc_free (newdecl); |
| |
| return olddecl; |
| } |
| |
| /* 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 NULL; |
| else |
| return G_("redefinition of %q#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) |
| && DECL_INITIAL (olddecl) == NULL_TREE) |
| return NULL; |
| |
| /* 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) |
| && ! decls_match (olddecl, newdecl)) |
| return G_("%qD 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_defined_p (olddecl) |
| && decl_defined_p (newdecl)) |
| { |
| if (DECL_NAME (olddecl) == NULL_TREE) |
| return G_("%q#D not declared in class"); |
| else if (!GNU_INLINE_P (olddecl) |
| || GNU_INLINE_P (newdecl)) |
| return G_("redefinition of %q#D"); |
| } |
| |
| if (DECL_DECLARED_INLINE_P (olddecl) && DECL_DECLARED_INLINE_P (newdecl |