{
tree eq = implicitly_declare_fn (sfk_comparison, t, false, space,
NULL_TREE);
- if (DECL_FRIEND_P (space))
+ bool is_friend = DECL_CONTEXT (space) != t;
+ if (is_friend)
do_friend (NULL_TREE, DECL_NAME (eq), eq,
NULL_TREE, NO_SPECIAL, true);
else
DECL_CHAIN (eq) = TYPE_FIELDS (t);
TYPE_FIELDS (t) = eq;
}
- maybe_add_class_template_decl_list (t, eq, DECL_FRIEND_P (space));
+ maybe_add_class_template_decl_list (t, eq, is_friend);
}
while (*access_decls)
void
remove_constraints (tree t)
{
- gcc_assert (DECL_P (t));
+ gcc_checking_assert (DECL_P (t));
if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t);
{
if (reqs == NULL_TREE)
return NULL_TREE;
+
tree decl = CONST_CAST_TREE (decl_);
tree result = STRIP_TEMPLATE (decl);
- if (DECL_FRIEND_P (result))
+
+ if (DECL_UNIQUE_FRIEND_P (result))
{
- tree tmpl = decl == result ? DECL_TI_TEMPLATE (result) : decl;
+ tree tmpl = decl;
+ if (TREE_CODE (decl) != TEMPLATE_DECL)
+ tmpl = DECL_TI_TEMPLATE (result);
+
tree gargs = generic_targs_for (tmpl);
processing_template_decl_sentinel s;
if (uses_template_parms (gargs))
thunked to function decl. */
tree befriending_classes;
- /* For a non-virtual FUNCTION_DECL, this is
- DECL_FRIEND_CONTEXT. For a virtual FUNCTION_DECL for which
+ /* For a virtual FUNCTION_DECL for which
DECL_THIS_THUNK_P does not hold, this is DECL_THUNKS. Both
this pointer and result pointer adjusting thunks are
chained here. This pointer thunks to return pointer thunks
- will be chained on the return pointer thunk. */
+ will be chained on the return pointer thunk.
+ For a DECL_CONSTUCTOR_P FUNCTION_DECL, this is the base from
+ whence we inherit. Otherwise, it is the class in which a
+ (namespace-scope) friend is defined (if any). */
tree context;
union lang_decl_u5
(DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL)) \
->u.base.odr_used)
-/* Nonzero for DECL means that this decl is just a friend declaration,
- and should not be added to the list of members for this class. */
-#define DECL_FRIEND_P(NODE) \
- (DECL_LANG_SPECIFIC (TYPE_FUNCTION_OR_TEMPLATE_DECL_CHECK (NODE)) \
+/* Nonzero for FUNCTION_DECL means that this is a friend that is
+ either not pushed into a namespace/looked up in a class (because it
+ is a dependent type, in an uninstantiated template), or it has
+ /only/ been subject to hidden friend injection from one or more
+ befriending classes. Once another decl matches, the flag is
+ cleared. There are requirements on its default parms. */
+#define DECL_UNIQUE_FRIEND_P(NODE) \
+ (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE)) \
->u.base.friend_or_tls)
/* Nonzero if the thread-local variable was declared with __thread as
the DECL_FRIEND_CONTEXT for `f' will be `S'. */
#define DECL_FRIEND_CONTEXT(NODE) \
- ((DECL_DECLARES_FUNCTION_P (NODE) \
- && DECL_FRIEND_P (NODE) && !DECL_FUNCTION_MEMBER_P (NODE)) \
+ ((DECL_DECLARES_FUNCTION_P (NODE) && !DECL_VIRTUAL_P (NODE) \
+ && !DECL_CONSTRUCTOR_P (NODE)) \
? LANG_DECL_FN_CHECK (NODE)->context \
: NULL_TREE)
the function or function template in the translation unit." */
static void
-check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl,
- bool olddecl_hidden_p)
+check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl)
{
- if (!olddecl_hidden_p && !DECL_FRIEND_P (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 ((olddecl_hidden_p && TREE_PURPOSE (t1))
- || (DECL_FRIEND_P (newdecl) && TREE_PURPOSE (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),
duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
{
unsigned olddecl_uid = DECL_UID (olddecl);
- int olddecl_friend = 0, types_match = 0;
- int olddecl_hidden_friend = 0;
+ int types_match = 0;
int new_defines_function = 0;
tree new_template_info;
location_t olddecl_loc = DECL_SOURCE_LOCATION (olddecl);
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, was_hidden);
+ check_no_redeclaration_friend_default_args (olddecl, newdecl);
}
}
}
else
DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
- if (DECL_DECLARES_FUNCTION_P (olddecl))
- {
- olddecl_friend = DECL_FRIEND_P (STRIP_TEMPLATE (olddecl));
- olddecl_hidden_friend = olddecl_friend && was_hidden;
- }
-
if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
tree old_result = DECL_TEMPLATE_RESULT (olddecl);
declaration of the function or function template in the
translation unit." */
check_no_redeclaration_friend_default_args
- (old_result, new_result, olddecl_hidden_friend);
+ (old_result, new_result);
}
+ if (!DECL_UNIQUE_FRIEND_P (old_result))
+ DECL_UNIQUE_FRIEND_P (new_result) = false;
check_default_args (newdecl);
&& !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
{
}
DECL_UID (olddecl) = olddecl_uid;
- if (olddecl_friend)
- DECL_FRIEND_P (olddecl) = true;
/* NEWDECL contains the merged attribute lists.
Update OLDDECL to be the same. */
definition and shall be the only declaration of the
function template in the translation unit. */
if ((cxx_dialect != cxx98)
- && TREE_CODE (ot) == FUNCTION_DECL && DECL_FRIEND_P (ot)
+ && TREE_CODE (ot) == FUNCTION_DECL && DECL_UNIQUE_FRIEND_P (ot)
&& !check_default_tmpl_args (nt, DECL_TEMPLATE_PARMS (newdecl),
/*is_primary=*/true,
/*is_partial=*/false,
return NULL;
}
else if (VAR_P (newdecl)
- && CP_DECL_THREAD_LOCAL_P (newdecl) != CP_DECL_THREAD_LOCAL_P (olddecl)
+ && (CP_DECL_THREAD_LOCAL_P (newdecl)
+ != CP_DECL_THREAD_LOCAL_P (olddecl))
&& (! DECL_LANG_SPECIFIC (olddecl)
|| ! CP_DECL_THREADPRIVATE_P (olddecl)
|| CP_DECL_THREAD_LOCAL_P (newdecl)))
start_preparsed_function (tree decl1, tree attrs, int flags)
{
tree ctype = NULL_TREE;
- tree fntype;
- tree restype;
- int doing_friend = 0;
- cp_binding_level *bl;
- tree current_function_parms;
- struct c_fileinfo *finfo
- = get_fileinfo (LOCATION_FILE (DECL_SOURCE_LOCATION (decl1)));
- bool honor_interface;
+ bool doing_friend = false;
/* Sanity check. */
gcc_assert (VOID_TYPE_P (TREE_VALUE (void_list_node)));
gcc_assert (TREE_CHAIN (void_list_node) == NULL_TREE);
- fntype = TREE_TYPE (decl1);
+ tree fntype = TREE_TYPE (decl1);
if (TREE_CODE (fntype) == METHOD_TYPE)
ctype = TYPE_METHOD_BASETYPE (fntype);
-
- /* ISO C++ 11.4/5. A friend function defined in a class is in
- the (lexical) scope of the class in which it is defined. */
- if (!ctype && DECL_FRIEND_P (decl1))
+ else
{
ctype = DECL_FRIEND_CONTEXT (decl1);
- /* CTYPE could be null here if we're dealing with a template;
- for example, `inline friend float foo()' inside a template
- will have no CTYPE set. */
- if (ctype && TREE_CODE (ctype) != RECORD_TYPE)
- ctype = NULL_TREE;
- else
- doing_friend = 1;
+ if (ctype)
+ doing_friend = true;
}
if (DECL_DECLARED_INLINE_P (decl1)
by push_nested_class.) */
if (processing_template_decl)
{
- tree newdecl1 = push_template_decl (decl1, DECL_FRIEND_P (decl1));
+ tree newdecl1 = push_template_decl (decl1, doing_friend);
if (newdecl1 == error_mark_node)
{
if (ctype || DECL_STATIC_FUNCTION_P (decl1))
check_function_type (decl1, DECL_ARGUMENTS (decl1));
/* Build the return declaration for the function. */
- restype = TREE_TYPE (fntype);
+ tree restype = TREE_TYPE (fntype);
if (DECL_RESULT (decl1) == NULL_TREE)
{
/* Save the parm names or decls from this function's declarator
where store_parm_decls will find them. */
- current_function_parms = DECL_ARGUMENTS (decl1);
+ tree current_function_parms = DECL_ARGUMENTS (decl1);
/* Let the user know we're compiling this function. */
announce_function (decl1);
even when processing a template; this is how we get
CFUN set up, and our per-function variables initialized.
FIXME factor out the non-RTL stuff. */
- bl = current_binding_level;
+ cp_binding_level *bl = current_binding_level;
allocate_struct_function (decl1, processing_template_decl);
/* Initialize the language data structures. Whenever we start
}
}
- honor_interface = (!DECL_TEMPLATE_INSTANTIATION (decl1)
- /* Implicitly-defined methods (like the
- destructor for a class in which no destructor
- is explicitly declared) must not be defined
- until their definition is needed. So, we
- ignore interface specifications for
- compiler-generated functions. */
- && !DECL_ARTIFICIAL (decl1));
+ bool honor_interface = (!DECL_TEMPLATE_INSTANTIATION (decl1)
+ /* Implicitly-defined methods (like the
+ destructor for a class in which no destructor
+ is explicitly declared) must not be defined
+ until their definition is needed. So, we
+ ignore interface specifications for
+ compiler-generated functions. */
+ && !DECL_ARTIFICIAL (decl1));
+ struct c_fileinfo *finfo
+ = get_fileinfo (LOCATION_FILE (DECL_SOURCE_LOCATION (decl1)));
if (processing_template_decl)
/* Don't mess with interface flags. */;
/* We process method specializations in finish_struct_1. */
if (processing_template_decl && !DECL_TEMPLATE_SPECIALIZATION (fndecl))
{
- fndecl = push_template_decl (fndecl, DECL_FRIEND_P (fndecl));
+ /* Avoid calling decl_spec_seq... until we have to. */
+ bool friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend);
+ fndecl = push_template_decl (fndecl, friendp);
if (fndecl == error_mark_node)
return fndecl;
}
- if (! DECL_FRIEND_P (fndecl))
+ if (DECL_CHAIN (fndecl) && !decl_spec_seq_has_spec_p (declspecs, ds_friend))
{
- if (DECL_CHAIN (fndecl))
- {
- fndecl = copy_node (fndecl);
- TREE_CHAIN (fndecl) = NULL_TREE;
- }
+ fndecl = copy_node (fndecl);
+ TREE_CHAIN (fndecl) = NULL_TREE;
}
cp_finish_decl (fndecl, NULL_TREE, false, NULL_TREE, 0);
asmspec_tree, flags);
/* Pass friends back this way. */
- if (DECL_FRIEND_P (value))
+ if (DECL_UNIQUE_FRIEND_P (value))
return void_type_node;
DECL_IN_AGGR_P (value) = 1;
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
gcc_assert (!ctype || MAYBE_CLASS_TYPE_P (ctype));
- /* Every decl that gets here is a friend of something. */
- DECL_FRIEND_P (decl) = 1;
+ /* Friend functions are unique, until proved otherwise. */
+ DECL_UNIQUE_FRIEND_P (decl) = 1;
if (DECL_OVERRIDE_P (decl) || DECL_FINAL_P (decl))
error ("friend declaration %qD may not have virt-specifiers",
error ("member %qD declared as friend before type %qT defined",
decl, ctype);
}
- /* A global friend.
- @@ or possibly a friend from a base class ?!? */
- else if (TREE_CODE (decl) == FUNCTION_DECL)
+ else
{
+ /* Namespace-scope friend function. */
int is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
- /* Friends must all go through the overload machinery,
- even though they may not technically be overloaded.
-
- Note that because classes all wind up being top-level
- in their scope, their friend wind up in top-level scope as well. */
if (funcdef_flag)
SET_DECL_FRIEND_CONTEXT (decl, current_class_type);
add_friend (current_class_type,
is_friend_template ? DECL_TI_TEMPLATE (decl) : decl,
/*complain=*/true);
- DECL_FRIEND_P (decl) = 1;
}
return decl;
typedef struct C {} C;
correctly. */
- tree found = NULL_TREE;
- bool reveal = false;
if (tree type = iter->type)
{
if (qualify_lookup (type, LOOK_want::TYPE)
|| LOCAL_BINDING_P (iter)
|| DECL_CONTEXT (type) == iter->scope->this_entity))
{
- found = type;
if (how != TAG_how::HIDDEN_FRIEND)
- reveal = HIDDEN_TYPE_BINDING_P (iter);
+ /* It is no longer a hidden binding. */
+ HIDDEN_TYPE_BINDING_P (iter) = false;
+
+ return type;
}
}
else
&& (how != TAG_how::CURRENT_ONLY
|| !INHERITED_VALUE_BINDING_P (iter)))
{
- found = iter->value;
- if (how != TAG_how::HIDDEN_FRIEND)
- reveal = !iter->type && HIDDEN_TYPE_BINDING_P (iter);
- }
- }
-
- if (found)
- {
- if (reveal)
- {
- /* It is no longer a hidden binding. */
- HIDDEN_TYPE_BINDING_P (iter) = false;
-
- /* Unanticipate the decl itself. */
- DECL_FRIEND_P (found) = false;
+ if (how != TAG_how::HIDDEN_FRIEND && !iter->type)
+ /* It is no longer a hidden binding. */
+ HIDDEN_TYPE_BINDING_P (iter) = false;
- gcc_checking_assert (TREE_CODE (found) != TEMPLATE_DECL);
-
- if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (found)))
- {
- tree tmpl = TI_TEMPLATE (ti);
- DECL_FRIEND_P (tmpl) = false;
- }
+ return iter->value;
}
-
- return found;
}
}
if (tree *slot = find_namespace_slot (ns, name))
{
/* If this is the kind of thing we're looking for, we're done. */
- tree found = NULL_TREE;
- bool reveal = false;
-
if (tree type = MAYBE_STAT_TYPE (*slot))
{
- found = type;
if (how != TAG_how::HIDDEN_FRIEND)
- {
- reveal = STAT_TYPE_HIDDEN_P (*slot);
- STAT_TYPE_HIDDEN_P (*slot) = false;
- }
+ /* No longer hidden. */
+ STAT_TYPE_HIDDEN_P (*slot) = false;
+
+ return type;
}
else if (tree decl = MAYBE_STAT_DECL (*slot))
{
if (qualify_lookup (decl, LOOK_want::TYPE))
{
- found = decl;
-
- if (how != TAG_how::HIDDEN_FRIEND && STAT_HACK_P (*slot))
+ if (how != TAG_how::HIDDEN_FRIEND && STAT_HACK_P (*slot)
+ && STAT_DECL_HIDDEN_P (*slot))
{
- reveal = STAT_DECL_HIDDEN_P (*slot);
- if (reveal)
- {
- if (STAT_TYPE (*slot))
- STAT_DECL_HIDDEN_P (*slot) = false;
- else
- /* There is no type, just remove the stat
- hack. */
- *slot = decl;
- }
+ if (STAT_TYPE (*slot))
+ STAT_DECL_HIDDEN_P (*slot) = false;
+ else
+ /* There is no type, just remove the stat
+ hack. */
+ *slot = decl;
}
- }
- }
- if (found)
- {
- if (reveal)
- {
- /* Reveal the previously hidden thing. */
- DECL_FRIEND_P (found) = false;
-
- if (TREE_CODE (found) == TEMPLATE_DECL)
- {
- tree res = DECL_TEMPLATE_RESULT (found);
- if (DECL_LANG_SPECIFIC (res))
- DECL_FRIEND_P (res) = false;
- }
- else if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (found)))
- {
- tree tmpl = TI_TEMPLATE (ti);
- DECL_FRIEND_P (tmpl) = false;
- }
+ return decl;
}
-
- return found;
}
}
tdef = create_implicit_typedef (name, type);
DECL_CONTEXT (tdef) = FROB_CONTEXT (context);
- bool is_friend = how == TAG_how::HIDDEN_FRIEND;
- if (is_friend)
- {
- // FIXME: can go away
- /* This is a friend. Make this TYPE_DECL node hidden from
- ordinary name lookup. Its corresponding TEMPLATE_DECL
- will be marked in push_template_decl. */
- retrofit_lang_decl (tdef);
- DECL_FRIEND_P (tdef) = 1;
- }
-
- decl = maybe_process_template_type_declaration (type, is_friend, b);
+ decl = maybe_process_template_type_declaration
+ (type, how == TAG_how::HIDDEN_FRIEND, b);
if (decl == error_mark_node)
return decl;
not have template information. The optimized lookup relies
on having ARGS be the template arguments for both the class
and the function template. */
- && !DECL_FRIEND_P (DECL_TEMPLATE_RESULT (tmpl)));
+ && !DECL_UNIQUE_FRIEND_P (DECL_TEMPLATE_RESULT (tmpl)));
}
/* Make sure ARGS doesn't use any inappropriate typedefs; we should have
/* No surprising friend functions. */
gcc_checking_assert (is_friend
|| !(TREE_CODE (decl) == FUNCTION_DECL
- && DECL_FRIEND_P (decl)));
+ && DECL_UNIQUE_FRIEND_P (decl)));
if (is_friend)
/* For a friend, we want the context of the friend, not
if (!ctx
&& !(is_friend && template_class_depth (current_class_type) > 0))
{
- /* Hide template friend classes that haven't been declared yet. */
- if (is_friend && TREE_CODE (decl) == TYPE_DECL)
- DECL_FRIEND_P (tmpl) = 1;
-
tmpl = pushdecl_namespace_level (tmpl, /*hiding=*/is_friend);
if (tmpl == error_mark_node)
return error_mark_node;
if (!lambda_fntype)
set_constraints (r, ci);
- if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
+ if (DECL_FRIEND_CONTEXT (t))
SET_DECL_FRIEND_CONTEXT (r,
tsubst (DECL_FRIEND_CONTEXT (t),
args, complain, in_decl));
&& !(DECL_CLASS_SCOPE_P (expression)
&& dependent_type_p (DECL_CONTEXT (expression)))
&& !(DECL_LANG_SPECIFIC (expression)
- && DECL_FRIEND_P (expression)
+ && DECL_UNIQUE_FRIEND_P (expression)
&& (!DECL_FRIEND_CONTEXT (expression)
|| dependent_type_p (DECL_FRIEND_CONTEXT (expression))))
&& !DECL_LOCAL_DECL_P (expression))
make_friend_class (type, TREE_TYPE (decl), true);
else
{
- DECL_FRIEND_P (decl) = true;
+ DECL_UNIQUE_FRIEND_P (decl) = true;
add_friend (type, decl, true);
}