c++: Fix friend attributes [PR51344]
51344 was a problem with calling save_template_attributes twice for the same friend function: once from do_friend and once from grokmethod. The 2012 patch for the bug avoided creating an infinite loop when this happens, but it's better to avoid the duplication in the first place. This also restores the dependent attributes to the beginning of the attribute list, as originally intended. And then apply_late_template_attributes can avoid copying the non-dependent attributes. gcc/cp/ChangeLog: PR c++/51344 * decl2.c (grokfield): Call cplus_decl_attributes for friend. (save_template_attributes): Use chainon. * friend.c (do_friend): Remove attrlist parm. * cp-tree.h (do_friend): Adjust. * class.c (add_implicitly_declared_members): Adjust. * decl.c (grokdeclarator): Adjust. * pt.c (apply_late_template_attributes): Optimize.
This commit is contained in:
parent
58a92b789a
commit
a0fdff3cf3
@ -3314,7 +3314,7 @@ add_implicitly_declared_members (tree t, tree* access_decls,
|
||||
bool is_friend = DECL_CONTEXT (space) != t;
|
||||
if (is_friend)
|
||||
do_friend (NULL_TREE, DECL_NAME (eq), eq,
|
||||
NULL_TREE, NO_SPECIAL, true);
|
||||
NO_SPECIAL, true);
|
||||
else
|
||||
{
|
||||
add_method (t, eq, false);
|
||||
|
@ -6848,7 +6848,7 @@ extern void mark_exp_read (tree);
|
||||
extern int is_friend (tree, tree);
|
||||
extern void make_friend_class (tree, tree, bool);
|
||||
extern void add_friend (tree, tree, bool);
|
||||
extern tree do_friend (tree, tree, tree, tree,
|
||||
extern tree do_friend (tree, tree, tree,
|
||||
enum overload_flags, bool);
|
||||
|
||||
extern void set_global_friend (tree);
|
||||
|
@ -13758,8 +13758,7 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
}
|
||||
|
||||
decl = do_friend (ctype, unqualified_id, decl,
|
||||
*attrlist, flags,
|
||||
funcdef_flag);
|
||||
flags, funcdef_flag);
|
||||
return decl;
|
||||
}
|
||||
else
|
||||
|
@ -974,7 +974,11 @@ grokfield (const cp_declarator *declarator,
|
||||
if ((TREE_CODE (value) == FUNCTION_DECL
|
||||
|| TREE_CODE (value) == TEMPLATE_DECL)
|
||||
&& DECL_CONTEXT (value) != current_class_type)
|
||||
return value;
|
||||
{
|
||||
if (attrlist)
|
||||
cplus_decl_attributes (&value, attrlist, 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Need to set this before push_template_decl. */
|
||||
if (VAR_P (value))
|
||||
@ -1278,9 +1282,9 @@ save_template_attributes (tree *attr_p, tree *decl_p, int flags)
|
||||
|
||||
tree old_attrs = *q;
|
||||
|
||||
/* Merge the late attributes at the beginning with the attribute
|
||||
/* Place the late attributes at the beginning of the attribute
|
||||
list. */
|
||||
late_attrs = merge_attributes (late_attrs, *q);
|
||||
late_attrs = chainon (late_attrs, *q);
|
||||
if (*q != late_attrs
|
||||
&& !DECL_P (*decl_p)
|
||||
&& !(flags & ATTR_FLAG_TYPE_IN_PLACE))
|
||||
|
@ -475,7 +475,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
|
||||
|
||||
tree
|
||||
do_friend (tree ctype, tree declarator, tree decl,
|
||||
tree attrlist, enum overload_flags flags,
|
||||
enum overload_flags flags,
|
||||
bool funcdef_flag)
|
||||
{
|
||||
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
|
||||
@ -488,13 +488,6 @@ do_friend (tree ctype, tree declarator, tree decl,
|
||||
error ("friend declaration %qD may not have virt-specifiers",
|
||||
decl);
|
||||
|
||||
/* Unfortunately, we have to handle attributes here. Normally we would
|
||||
handle them in start_decl_1, but since this is a friend decl start_decl_1
|
||||
never gets to see it. */
|
||||
|
||||
/* Set attributes here so if duplicate decl, will have proper attributes. */
|
||||
cplus_decl_attributes (&decl, attrlist, 0);
|
||||
|
||||
if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
|
||||
{
|
||||
declarator = TREE_OPERAND (declarator, 0);
|
||||
|
51
gcc/cp/pt.c
51
gcc/cp/pt.c
@ -11659,7 +11659,6 @@ static bool
|
||||
apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags,
|
||||
tree args, tsubst_flags_t complain, tree in_decl)
|
||||
{
|
||||
tree last_dep = NULL_TREE;
|
||||
tree t;
|
||||
tree *p;
|
||||
|
||||
@ -11685,39 +11684,35 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags,
|
||||
p = &TREE_CHAIN (*p);
|
||||
}
|
||||
|
||||
/* save_template_attributes puts the dependent attributes at the beginning of
|
||||
the list; find the non-dependent ones. */
|
||||
for (t = attributes; t; t = TREE_CHAIN (t))
|
||||
if (ATTR_IS_DEPENDENT (t))
|
||||
{
|
||||
last_dep = t;
|
||||
attributes = copy_list (attributes);
|
||||
break;
|
||||
}
|
||||
if (!ATTR_IS_DEPENDENT (t))
|
||||
break;
|
||||
tree nondep = t;
|
||||
|
||||
*p = attributes;
|
||||
if (last_dep)
|
||||
/* Apply any non-dependent attributes. */
|
||||
*p = nondep;
|
||||
|
||||
/* And then any dependent ones. */
|
||||
tree late_attrs = NULL_TREE;
|
||||
tree *q = &late_attrs;
|
||||
for (t = attributes; t != nondep; t = TREE_CHAIN (t))
|
||||
{
|
||||
tree late_attrs = NULL_TREE;
|
||||
tree *q = &late_attrs;
|
||||
|
||||
for (; *p; )
|
||||
*q = tsubst_attribute (t, decl_p, args, complain, in_decl);
|
||||
if (*q == error_mark_node)
|
||||
return false;
|
||||
if (*q == t)
|
||||
{
|
||||
t = *p;
|
||||
if (ATTR_IS_DEPENDENT (t))
|
||||
{
|
||||
*q = tsubst_attribute (t, decl_p, args, complain, in_decl);
|
||||
if (*q == error_mark_node)
|
||||
return false;
|
||||
*p = TREE_CHAIN (t);
|
||||
TREE_CHAIN (t) = NULL_TREE;
|
||||
while (*q)
|
||||
q = &TREE_CHAIN (*q);
|
||||
}
|
||||
else
|
||||
p = &TREE_CHAIN (t);
|
||||
*q = copy_node (t);
|
||||
TREE_CHAIN (*q) = NULL_TREE;
|
||||
}
|
||||
|
||||
cplus_decl_attributes (decl_p, late_attrs, attr_flags);
|
||||
while (*q)
|
||||
q = &TREE_CHAIN (*q);
|
||||
}
|
||||
|
||||
cplus_decl_attributes (decl_p, late_attrs, attr_flags);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user