Commit 0cf4820d by Nathan Sidwell Committed by Nathan Sidwell

[PR C++/59930] template friend classes & default args

https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01055.html
	PR c++/59930
	* decl.c (xref_tag_1): Correct comments about template friends and
	default args.
	* friend.c (make_friend_class): Move comments concerning
	self-friendliness to code dealing with such.
	* pt.c (check_default_tmpl_args): Deal with template friend
	classes too.
	(push_template_decl_real): Check default args for non-function
	template friends.

	PR c++/59930
	* g++.dg/cpp0x/temp_default4.C: Adjust diagnostic.
	* g++.old-deja/g++.pt/friend23.C: Likewise.
	* g++.old-deja/g++.pt/friend24.C: Delete.

From-SVN: r255698
parent e7425c18
2017-12-15 Nathan Sidwell <nathan@acm.org>
PR c++/59930
* decl.c (xref_tag_1): Correct comments about template friends and
default args.
* friend.c (make_friend_class): Move comments concerning
self-friendliness to code dealing with such.
* pt.c (check_default_tmpl_args): Deal with template friend
classes too.
(push_template_decl_real): Check default args for non-function
template friends.
2017-12-14 Bernd Edlinger <bernd.edlinger@hotmail.de>
* decl2.c (start_static_storage_duration_function): Avoid warning.
......
......@@ -13538,37 +13538,28 @@ xref_tag_1 (enum tag_types tag_code, tree name,
processing a (member) template declaration of a template
class, we must be very careful; consider:
template <class X>
struct S1
template <class X> struct S1
template <class U>
struct S2
{ template <class V>
friend struct S1; };
template <class U> struct S2
{
template <class V> friend struct S1;
};
Here, the S2::S1 declaration should not be confused with the
outer declaration. In particular, the inner version should
have a template parameter of level 2, not level 1. This
would be particularly important if the member declaration
were instead:
template <class V = U> friend struct S1;
have a template parameter of level 2, not level 1.
say, when we should tsubst into `U' when instantiating
S2. On the other hand, when presented with:
On the other hand, when presented with:
template <class T>
struct S1 {
template <class U>
struct S2 {};
template <class U>
friend struct S2;
template <class T> struct S1
{
template <class U> struct S2 {};
template <class U> friend struct S2;
};
we must find the inner binding eventually. We
accomplish this by making sure that the new type we
create to represent this declaration has the right
TYPE_CONTEXT. */
the friend must find S1::S2 eventually. We accomplish this
by making sure that the new type we create to represent this
declaration has the right TYPE_CONTEXT. */
context = TYPE_CONTEXT (t);
t = NULL_TREE;
}
......@@ -13622,9 +13613,10 @@ xref_tag_1 (enum tag_types tag_code, tree name,
return error_mark_node;
}
/* Make injected friend class visible. */
if (scope != ts_within_enclosing_non_class && TYPE_HIDDEN_P (t))
{
/* This is no longer an invisible friend. Make it
visible. */
tree decl = TYPE_NAME (t);
DECL_ANTICIPATED (decl) = false;
......
......@@ -283,21 +283,18 @@ make_friend_class (tree type, tree friend_type, bool complain)
return;
if (friend_depth)
/* If the TYPE is a template then it makes sense for it to be
friends with itself; this means that each instantiation is
friends with all other instantiations. */
{
/* [temp.friend] Friend declarations shall not declare partial
specializations. */
if (CLASS_TYPE_P (friend_type)
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type)
&& uses_template_parms (friend_type))
{
/* [temp.friend]
Friend declarations shall not declare partial
specializations. */
error ("partial specialization %qT declared %<friend%>",
friend_type);
return;
}
if (TYPE_TEMPLATE_INFO (friend_type)
&& !PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (friend_type)))
{
......@@ -311,7 +308,11 @@ make_friend_class (tree type, tree friend_type, bool complain)
return;
}
}
else if (same_type_p (type, friend_type))
/* It makes sense for a template class to be friends with itself,
that means the instantiations can be friendly. Other cases are
not so meaningful. */
if (!friend_depth && same_type_p (type, friend_type))
{
if (complain)
warning (0, "class %qT is implicitly friends with itself",
......
......@@ -4980,9 +4980,10 @@ fixed_parameter_pack_p (tree parm)
a primary template. IS_PARTIAL is true if DECL is a partial
specialization.
IS_FRIEND_DECL is nonzero if DECL is a friend function template
declaration (but not a definition); 1 indicates a declaration, 2
indicates a redeclaration. When IS_FRIEND_DECL=2, no errors are
IS_FRIEND_DECL is nonzero if DECL is either a non-defining friend
function template declaration or a friend class template
declaration. In the function case, 1 indicates a declaration, 2
indicates a redeclaration. When IS_FRIEND_DECL=2, no errors are
emitted for extraneous default arguments.
Returns TRUE if there were no errors found, FALSE otherwise. */
......@@ -5130,7 +5131,7 @@ check_default_tmpl_args (tree decl, tree parms, bool is_primary,
msg = G_("default template arguments may not be used in function template "
"friend re-declaration");
else if (is_friend_decl)
msg = G_("default template arguments may not be used in function template "
msg = G_("default template arguments may not be used in template "
"friend declarations");
else if (TREE_CODE (decl) == FUNCTION_DECL && (cxx_dialect == cxx98))
msg = G_("default template arguments may not be used in function templates "
......@@ -5277,7 +5278,7 @@ push_template_decl_real (tree decl, bool is_friend)
is_friend = true;
if (is_friend)
/* For a friend, we want the context of the friend function, not
/* For a friend, we want the context of the friend, not
the type of which it is a friend. */
ctx = CP_DECL_CONTEXT (decl);
else if (CP_DECL_CONTEXT (decl)
......@@ -5380,9 +5381,12 @@ push_template_decl_real (tree decl, bool is_friend)
}
/* Check to see that the rules regarding the use of default
arguments are not being violated. */
check_default_tmpl_args (decl, current_template_parms,
is_primary, is_partial, /*is_friend_decl=*/0);
arguments are not being violated. We check args for a friend
functions when we know whether it's a definition, introducing
declaration or re-declaration. */
if (!is_friend || TREE_CODE (decl) != FUNCTION_DECL)
check_default_tmpl_args (decl, current_template_parms,
is_primary, is_partial, is_friend);
/* Ensure that there are no parameter packs in the type of this
declaration that have not been expanded. */
......
2017-12-14 Nathan Sidwell <nathan@acm.org>
PR c++/59930
* g++.dg/cpp0x/temp_default4.C: Adjust diagnostic.
* g++.old-deja/g++.pt/friend23.C: Likewise.
* g++.old-deja/g++.pt/friend24.C: Delete.
2017-12-15 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/83269
......
// { dg-do compile { target c++11 } }
class X {
template<typename T = int> friend void f(X) { }
template<typename T = int> friend void f(X) { } // OK
template<typename T> friend void g(X); // { dg-message "previously declared here" }
template<typename T = int> friend void h(X); // { dg-error "function template friend" }
template<typename T = int> friend void h(X); // { dg-error "template friend" }
};
template<typename T = int> void g(X) // { dg-error "default template argument" }
......
// { dg-do assemble }
// PR 59930 (part) templated class friend declarations cannot have
// default args.
template <class T = int> // { dg-message "note: original definition" }
template <class T>
struct S
{
template <class U = int>
friend class S; // { dg-error "redefinition of default argument" }
template <class U = int> friend class R; // { dg-error "template friend" }
template <class U = int> friend class S; // { dg-error "template friend" }
};
template struct S<int>;
// { dg-do assemble }
template <class T>
struct S
{
template <class U = T>
friend class S;
void f(T);
};
template struct S<int>;
void g()
{
S<> s;
s.f(3);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment