PR 59930 concerns some problems with templated friend classes (of
templates). In rying to clean up our handling, I discovered we were
accepting default args of such things. This is ill formed
[temp.param]/12 'A default template-argument shall not be specified in a
friend class template declaration.'
This patch addresses that problem by extending check_default_tmpl_args
to deal with such friends.
We'll still have to deal with:
template <typename T> class X {
template <typename U, T> friend class Y;
};
which is probably just as involved. But at least this removes one
source of confusion.
nathan
--
Nathan Sidwell
2017-12-14 Nathan Sidwell <nat...@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): Adjust for template friend classes.
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.
Index: cp/decl.c
===================================================================
--- cp/decl.c (revision 255634)
+++ cp/decl.c (working copy)
@@ -13538,37 +13538,28 @@ xref_tag_1 (enum tag_types tag_code, tre
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;
-
- say, when we should tsubst into `U' when instantiating
- S2. On the other hand, when presented with:
-
- template <class T>
- struct S1 {
- template <class U>
- struct S2 {};
- template <class U>
- friend struct S2;
+ have a template parameter of level 2, not level 1.
+
+ On the other hand, when presented with:
+
+ 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, tre
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;
Index: cp/friend.c
===================================================================
--- cp/friend.c (revision 255634)
+++ cp/friend.c (working copy)
@@ -283,21 +283,18 @@ make_friend_class (tree type, tree frien
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 frien
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",
Index: cp/pt.c
===================================================================
--- cp/pt.c (revision 255634)
+++ cp/pt.c (working copy)
@@ -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
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 = 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
}
/* Check to see that the rules regarding the use of default
- arguments are not being violated. */
+ arguments are not being violated. We recheck args for a
+ friend function when we know whether it's a definition,
+ introducing declaration or re-declaration. */
check_default_tmpl_args (decl, current_template_parms,
- is_primary, is_partial, /*is_friend_decl=*/0);
+ is_primary, is_partial,
+ is_friend && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl)));
/* Ensure that there are no parameter packs in the type of this
declaration that have not been expanded. */
Index: testsuite/g++.dg/cpp0x/temp_default4.C
===================================================================
--- testsuite/g++.dg/cpp0x/temp_default4.C (revision 255634)
+++ testsuite/g++.dg/cpp0x/temp_default4.C (working copy)
@@ -1,9 +1,9 @@
// { 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" }
Index: testsuite/g++.old-deja/g++.pt/friend23.C
===================================================================
--- testsuite/g++.old-deja/g++.pt/friend23.C (revision 255634)
+++ testsuite/g++.old-deja/g++.pt/friend23.C (working copy)
@@ -1,10 +1,9 @@
-// { 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>;
Index: testsuite/g++.old-deja/g++.pt/friend24.C
===================================================================
--- testsuite/g++.old-deja/g++.pt/friend24.C (revision 255634)
+++ testsuite/g++.old-deja/g++.pt/friend24.C (working copy)
@@ -1,18 +0,0 @@
-// { 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);
-}