+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.
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;
}
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;
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)))
{
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",
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. */
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 "
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)
}
/* 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>;
+++ /dev/null
-// { 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);
-}