blob: 242429d9ef4a2a95ce1b6a368fd1833cb5062f2e [file] [log] [blame]
/* Process declarations and variables for -*- C++ -*- compiler.
Copyright (C) 1988-2021 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"
/* 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;
bool subtime = timevar_cond_start (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;
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
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)
{
bool subtime = timevar_cond_start (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);
}
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
}
/* 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)
&& 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)
{
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;
}
/* 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);
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);
}
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;
}
}
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);
DECL_LOCAL_DECL_ALIAS (newdecl) = DECL_LOCAL_DECL_ALIAS (olddecl);
}
}
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 (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;