re PR c++/5369 (template member friend declaration not honored)
PR c++/5369 * friend.c (is_friend): Handle member function of a class template as template friend. (do_friend): Likewise. * decl2.c (check_classfn): Add template_header_p parameter. * decl.c (start_decl): Adjust check_classfn call. (grokfndecl): Likewise. * pt.c (is_specialization_of_friend): New function. (uses_template_parms_level): Likewise. (push_template_decl_real): Use uses_template_parms_level. (tsubst_friend_function): Adjust check_classfn call. * cp-tree.h (check_classfn): Adjust declaration. (uses_template_parms_level): Add declaration. (is_specialization_of_friend): Likewise. * g++.dg/template/memfriend1.C: New test. * g++.dg/template/memfriend2.C: Likewise. * g++.dg/template/memfriend3.C: Likewise. * g++.dg/template/memfriend4.C: Likewise. * g++.dg/template/memfriend5.C: Likewise. * g++.dg/template/memfriend6.C: Likewise. * g++.dg/template/memfriend7.C: Likewise. * g++.dg/template/memfriend8.C: Likewise. * g++.old-deja/g++.pt/friend44.C: Remove a bogus error. From-SVN: r73833
This commit is contained in:
parent
646118866e
commit
d43f603d85
|
@ -1,3 +1,20 @@
|
|||
2003-11-22 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
PR c++/5369
|
||||
* friend.c (is_friend): Handle member function of a class
|
||||
template as template friend.
|
||||
(do_friend): Likewise.
|
||||
* decl2.c (check_classfn): Add template_header_p parameter.
|
||||
* decl.c (start_decl): Adjust check_classfn call.
|
||||
(grokfndecl): Likewise.
|
||||
* pt.c (is_specialization_of_friend): New function.
|
||||
(uses_template_parms_level): Likewise.
|
||||
(push_template_decl_real): Use uses_template_parms_level.
|
||||
(tsubst_friend_function): Adjust check_classfn call.
|
||||
* cp-tree.h (check_classfn): Adjust declaration.
|
||||
(uses_template_parms_level): Add declaration.
|
||||
(is_specialization_of_friend): Likewise.
|
||||
|
||||
2003-11-21 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
PR c++/12515
|
||||
|
|
|
@ -3718,7 +3718,7 @@ extern void maybe_make_one_only (tree);
|
|||
extern void grokclassfn (tree, tree, enum overload_flags, tree);
|
||||
extern tree grok_array_decl (tree, tree);
|
||||
extern tree delete_sanity (tree, tree, int, int);
|
||||
extern tree check_classfn (tree, tree);
|
||||
extern tree check_classfn (tree, tree, bool);
|
||||
extern void check_member_template (tree);
|
||||
extern tree grokfield (tree, tree, tree, tree, tree);
|
||||
extern tree grokbitfield (tree, tree, tree);
|
||||
|
@ -3877,6 +3877,7 @@ extern void redeclare_class_template (tree, tree);
|
|||
extern tree lookup_template_class (tree, tree, tree, tree, int, tsubst_flags_t);
|
||||
extern tree lookup_template_function (tree, tree);
|
||||
extern int uses_template_parms (tree);
|
||||
extern int uses_template_parms_level (tree, int);
|
||||
extern tree instantiate_class_template (tree);
|
||||
extern tree instantiate_template (tree, tree, tsubst_flags_t);
|
||||
extern int fn_type_unification (tree, tree, tree, tree, tree, unification_kind_t, int);
|
||||
|
@ -3894,6 +3895,7 @@ extern int is_member_template (tree);
|
|||
extern int comp_template_parms (tree, tree);
|
||||
extern int template_class_depth (tree);
|
||||
extern int is_specialization_of (tree, tree);
|
||||
extern bool is_specialization_of_friend (tree, tree);
|
||||
extern int comp_template_args (tree, tree);
|
||||
extern void maybe_process_partial_specialization (tree);
|
||||
extern void maybe_check_template_type (tree);
|
||||
|
|
|
@ -3756,7 +3756,9 @@ start_decl (tree declarator,
|
|||
}
|
||||
else
|
||||
{
|
||||
tree field = check_classfn (context, decl);
|
||||
tree field = check_classfn (context, decl,
|
||||
processing_template_decl
|
||||
> template_class_depth (context));
|
||||
if (field && duplicate_decls (decl, field))
|
||||
decl = field;
|
||||
}
|
||||
|
@ -5661,7 +5663,9 @@ grokfndecl (tree ctype,
|
|||
{
|
||||
tree old_decl;
|
||||
|
||||
old_decl = check_classfn (ctype, decl);
|
||||
old_decl = check_classfn (ctype, decl,
|
||||
processing_template_decl
|
||||
> template_class_depth (ctype));
|
||||
|
||||
if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
|
||||
/* Because grokfndecl is always supposed to return a
|
||||
|
|
|
@ -643,10 +643,12 @@ check_java_method (tree method)
|
|||
|
||||
/* Sanity check: report error if this function FUNCTION is not
|
||||
really a member of the class (CTYPE) it is supposed to belong to.
|
||||
CNAME is the same here as it is for grokclassfn above. */
|
||||
CNAME is the same here as it is for grokclassfn above.
|
||||
TEMPLATE_HEADER_P is true when this declaration comes with a
|
||||
template header. */
|
||||
|
||||
tree
|
||||
check_classfn (tree ctype, tree function)
|
||||
check_classfn (tree ctype, tree function, bool template_header_p)
|
||||
{
|
||||
int ix;
|
||||
int is_template;
|
||||
|
@ -669,7 +671,7 @@ check_classfn (tree ctype, tree function)
|
|||
|
||||
/* OK, is this a definition of a member template? */
|
||||
is_template = (TREE_CODE (function) == TEMPLATE_DECL
|
||||
|| (processing_template_decl - template_class_depth (ctype)));
|
||||
|| template_header_p);
|
||||
|
||||
ix = lookup_fnfields_1 (complete_type (ctype),
|
||||
DECL_CONSTRUCTOR_P (function) ? ctor_identifier :
|
||||
|
|
|
@ -60,25 +60,15 @@ is_friend (tree type, tree supplicant)
|
|||
tree friends = FRIEND_DECLS (list);
|
||||
for (; friends ; friends = TREE_CHAIN (friends))
|
||||
{
|
||||
if (TREE_VALUE (friends) == NULL_TREE)
|
||||
tree friend = TREE_VALUE (friends);
|
||||
|
||||
if (friend == NULL_TREE)
|
||||
continue;
|
||||
|
||||
if (supplicant == TREE_VALUE (friends))
|
||||
if (supplicant == friend)
|
||||
return 1;
|
||||
|
||||
/* Temporarily, we are more lenient to deal with
|
||||
nested friend functions, for which there can be
|
||||
more than one FUNCTION_DECL, despite being the
|
||||
same function. When that's fixed, this bit can
|
||||
go. */
|
||||
if (DECL_FUNCTION_MEMBER_P (supplicant)
|
||||
&& same_type_p (TREE_TYPE (supplicant),
|
||||
TREE_TYPE (TREE_VALUE (friends))))
|
||||
return 1;
|
||||
|
||||
if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL
|
||||
&& is_specialization_of (supplicant,
|
||||
TREE_VALUE (friends)))
|
||||
if (is_specialization_of_friend (supplicant, friend))
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
@ -338,8 +328,6 @@ do_friend (tree ctype, tree declarator, tree decl, tree parmdecls,
|
|||
tree attrlist, enum overload_flags flags, tree quals,
|
||||
int funcdef_flag)
|
||||
{
|
||||
int is_friend_template = 0;
|
||||
|
||||
/* Every decl that gets here is a friend of something. */
|
||||
DECL_FRIEND_P (decl) = 1;
|
||||
|
||||
|
@ -353,39 +341,70 @@ do_friend (tree ctype, tree declarator, tree decl, tree parmdecls,
|
|||
if (TREE_CODE (decl) != FUNCTION_DECL)
|
||||
abort ();
|
||||
|
||||
is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
|
||||
|
||||
if (ctype)
|
||||
{
|
||||
/* CLASS_TEMPLATE_DEPTH counts the number of template headers for
|
||||
the enclosing class. FRIEND_DEPTH counts the number of template
|
||||
headers used for this friend declaration. TEMPLATE_MEMBER_P is
|
||||
true if a template header in FRIEND_DEPTH is intended for
|
||||
DECLARATOR. For example, the code
|
||||
|
||||
template <class T> struct A {
|
||||
template <class U> struct B {
|
||||
template <class V> template <class W>
|
||||
friend void C<V>::f(W);
|
||||
};
|
||||
};
|
||||
|
||||
will eventually give the following results
|
||||
|
||||
1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U').
|
||||
2. FRIEND_DEPTH equals 2 (for `V' and `W').
|
||||
3. TEMPLATE_MEMBER_P is true (for `W'). */
|
||||
|
||||
int class_template_depth = template_class_depth (current_class_type);
|
||||
int friend_depth = processing_template_decl - class_template_depth;
|
||||
/* We will figure this out later. */
|
||||
bool template_member_p = false;
|
||||
|
||||
tree cname = TYPE_NAME (ctype);
|
||||
if (TREE_CODE (cname) == TYPE_DECL)
|
||||
cname = DECL_NAME (cname);
|
||||
|
||||
/* A method friend. */
|
||||
if (flags == NO_SPECIAL && ctype && declarator == cname)
|
||||
if (flags == NO_SPECIAL && declarator == cname)
|
||||
DECL_CONSTRUCTOR_P (decl) = 1;
|
||||
|
||||
/* This will set up DECL_ARGUMENTS for us. */
|
||||
grokclassfn (ctype, decl, flags, quals);
|
||||
|
||||
if (is_friend_template)
|
||||
decl = DECL_TI_TEMPLATE (push_template_decl (decl));
|
||||
else if (DECL_TEMPLATE_INFO (decl))
|
||||
;
|
||||
else if (template_class_depth (current_class_type))
|
||||
decl = push_template_decl_real (decl, /*is_friend=*/1);
|
||||
if (friend_depth)
|
||||
{
|
||||
if (!uses_template_parms_level (ctype, class_template_depth
|
||||
+ friend_depth))
|
||||
template_member_p = true;
|
||||
}
|
||||
|
||||
/* We can't do lookup in a type that involves template
|
||||
parameters. Instead, we rely on tsubst_friend_function
|
||||
to check the validity of the declaration later. */
|
||||
if (processing_template_decl)
|
||||
add_friend (current_class_type, decl, /*complain=*/true);
|
||||
/* A nested class may declare a member of an enclosing class
|
||||
to be a friend, so we do lookup here even if CTYPE is in
|
||||
the process of being defined. */
|
||||
else if (COMPLETE_TYPE_P (ctype) || TYPE_BEING_DEFINED (ctype))
|
||||
if (class_template_depth
|
||||
|| COMPLETE_TYPE_P (ctype)
|
||||
|| TYPE_BEING_DEFINED (ctype))
|
||||
{
|
||||
decl = check_classfn (ctype, decl);
|
||||
if (DECL_TEMPLATE_INFO (decl))
|
||||
/* DECL is a template specialization. No need to
|
||||
build a new TEMPLATE_DECL. */
|
||||
;
|
||||
else if (class_template_depth)
|
||||
/* We rely on tsubst_friend_function to check the
|
||||
validity of the declaration later. */
|
||||
decl = push_template_decl_real (decl, /*is_friend=*/1);
|
||||
else
|
||||
decl = check_classfn (ctype, decl, template_member_p);
|
||||
|
||||
if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
|
||||
decl = DECL_TI_TEMPLATE (decl);
|
||||
|
||||
if (decl)
|
||||
add_friend (current_class_type, decl, /*complain=*/true);
|
||||
|
@ -398,6 +417,8 @@ do_friend (tree ctype, tree declarator, tree decl, tree parmdecls,
|
|||
@@ or possibly a friend from a base class ?!? */
|
||||
else if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||
{
|
||||
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.
|
||||
|
||||
|
|
152
gcc/cp/pt.c
152
gcc/cp/pt.c
|
@ -876,6 +876,140 @@ is_specialization_of (tree decl, tree tmpl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Returns nonzero iff DECL is a specialization of friend declaration
|
||||
FRIEND according to [temp.friend]. */
|
||||
|
||||
bool
|
||||
is_specialization_of_friend (tree decl, tree friend)
|
||||
{
|
||||
bool need_template = true;
|
||||
int template_depth;
|
||||
|
||||
my_friendly_assert (TREE_CODE (decl) == FUNCTION_DECL, 0);
|
||||
|
||||
/* For [temp.friend/6] when FRIEND is an ordinary member function
|
||||
of a template class, we want to check if DECL is a specialization
|
||||
if this. */
|
||||
if (TREE_CODE (friend) == FUNCTION_DECL
|
||||
&& DECL_TEMPLATE_INFO (friend)
|
||||
&& !DECL_USE_TEMPLATE (friend))
|
||||
{
|
||||
friend = DECL_TI_TEMPLATE (friend);
|
||||
need_template = false;
|
||||
}
|
||||
|
||||
/* There is nothing to do if this is not a template friend. */
|
||||
if (TREE_CODE (friend) != TEMPLATE_DECL)
|
||||
return 0;
|
||||
|
||||
if (is_specialization_of (decl, friend))
|
||||
return 1;
|
||||
|
||||
/* [temp.friend/6]
|
||||
A member of a class template may be declared to be a friend of a
|
||||
non-template class. In this case, the corresponding member of
|
||||
every specialization of the class template is a friend of the
|
||||
class granting friendship.
|
||||
|
||||
For example, given a template friend declaration
|
||||
|
||||
template <class T> friend void A<T>::f();
|
||||
|
||||
the member function below is considered a friend
|
||||
|
||||
template <> struct A<int> {
|
||||
void f();
|
||||
};
|
||||
|
||||
For this type of template friend, TEMPLATE_DEPTH below will be
|
||||
non-zero. To determine if DECL is a friend of FRIEND, we first
|
||||
check if the enclosing class is a specialization of another. */
|
||||
|
||||
template_depth = template_class_depth (DECL_CONTEXT (friend));
|
||||
if (template_depth
|
||||
&& DECL_CLASS_SCOPE_P (decl)
|
||||
&& is_specialization_of (TYPE_NAME (DECL_CONTEXT (decl)),
|
||||
CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (friend))))
|
||||
{
|
||||
/* Next, we check the members themselves. In order to handle
|
||||
a few tricky cases like
|
||||
|
||||
template <class T> friend void A<T>::g(T t);
|
||||
template <class T> template <T t> friend void A<T>::h();
|
||||
|
||||
we need to figure out what ARGS is (corresponding to `T' in above
|
||||
examples) from DECL for later processing. */
|
||||
|
||||
tree context = DECL_CONTEXT (decl);
|
||||
tree args = NULL_TREE;
|
||||
int current_depth = 0;
|
||||
while (current_depth < template_depth)
|
||||
{
|
||||
if (CLASSTYPE_TEMPLATE_INFO (context))
|
||||
{
|
||||
if (current_depth == 0)
|
||||
args = TYPE_TI_ARGS (context);
|
||||
else
|
||||
args = add_to_template_args (TYPE_TI_ARGS (context), args);
|
||||
current_depth++;
|
||||
}
|
||||
context = TYPE_CONTEXT (context);
|
||||
}
|
||||
|
||||
if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||
{
|
||||
bool is_template;
|
||||
tree friend_type;
|
||||
tree decl_type;
|
||||
tree friend_args_type;
|
||||
tree decl_args_type;
|
||||
|
||||
/* Make sure that both DECL and FRIEND are templates or
|
||||
non-templates. */
|
||||
is_template = DECL_TEMPLATE_INFO (decl)
|
||||
&& PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl));
|
||||
if (need_template ^ is_template)
|
||||
return 0;
|
||||
else if (is_template)
|
||||
{
|
||||
/* If both are templates, check template paramter list. */
|
||||
tree friend_parms
|
||||
= tsubst_template_parms (DECL_TEMPLATE_PARMS (friend),
|
||||
args, tf_none);
|
||||
if (!comp_template_parms
|
||||
(DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl)),
|
||||
friend_parms))
|
||||
return 0;
|
||||
|
||||
decl_type = TREE_TYPE (DECL_TI_TEMPLATE (decl));
|
||||
}
|
||||
else
|
||||
decl_type = TREE_TYPE (decl);
|
||||
|
||||
friend_type = tsubst_function_type (TREE_TYPE (friend), args,
|
||||
tf_none, NULL_TREE);
|
||||
if (friend_type == error_mark_node)
|
||||
return 0;
|
||||
|
||||
/* Check if return types match. */
|
||||
if (!same_type_p (TREE_TYPE (decl_type), TREE_TYPE (friend_type)))
|
||||
return 0;
|
||||
|
||||
/* Check if function parameter types match, ignoring the
|
||||
`this' parameter. */
|
||||
friend_args_type = TYPE_ARG_TYPES (friend_type);
|
||||
decl_args_type = TYPE_ARG_TYPES (decl_type);
|
||||
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (friend))
|
||||
friend_args_type = TREE_CHAIN (friend_args_type);
|
||||
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
|
||||
decl_args_type = TREE_CHAIN (decl_args_type);
|
||||
if (compparms (decl_args_type, friend_args_type))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register the specialization SPEC as a specialization of TMPL with
|
||||
the indicated ARGS. Returns SPEC, or an equivalent prior
|
||||
declaration, if available. */
|
||||
|
@ -2861,10 +2995,8 @@ push_template_decl_real (tree decl, int is_friend)
|
|||
/* It is a conversion operator. See if the type converted to
|
||||
depends on innermost template operands. */
|
||||
|
||||
if (for_each_template_parm (TREE_TYPE (TREE_TYPE (tmpl)),
|
||||
template_parm_this_level_p,
|
||||
&depth,
|
||||
NULL))
|
||||
if (uses_template_parms_level (TREE_TYPE (TREE_TYPE (tmpl)),
|
||||
depth))
|
||||
DECL_TEMPLATE_CONV_FN_P (tmpl) = 1;
|
||||
}
|
||||
}
|
||||
|
@ -4602,12 +4734,22 @@ for_each_template_parm (tree t, tree_fn_t fn, void* data, htab_t visited)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Returns true if T depends on any template parameter. */
|
||||
|
||||
int
|
||||
uses_template_parms (tree t)
|
||||
{
|
||||
return for_each_template_parm (t, 0, 0, NULL);
|
||||
}
|
||||
|
||||
/* Returns true if T depends on any template parameter with level LEVEL. */
|
||||
|
||||
int
|
||||
uses_template_parms_level (tree t, int level)
|
||||
{
|
||||
return for_each_template_parm (t, template_parm_this_level_p, &level, NULL);
|
||||
}
|
||||
|
||||
static int tinst_depth;
|
||||
extern int max_tinst_depth;
|
||||
#ifdef GATHER_STATISTICS
|
||||
|
@ -4917,7 +5059,7 @@ tsubst_friend_function (tree decl, tree args)
|
|||
/* Check to see that the declaration is really present, and,
|
||||
possibly obtain an improved declaration. */
|
||||
tree fn = check_classfn (DECL_CONTEXT (new_friend),
|
||||
new_friend);
|
||||
new_friend, false);
|
||||
|
||||
if (fn)
|
||||
new_friend = fn;
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
2003-11-22 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
PR c++/5369
|
||||
* g++.dg/template/memfriend1.C: New test.
|
||||
* g++.dg/template/memfriend2.C: Likewise.
|
||||
* g++.dg/template/memfriend3.C: Likewise.
|
||||
* g++.dg/template/memfriend4.C: Likewise.
|
||||
* g++.dg/template/memfriend5.C: Likewise.
|
||||
* g++.dg/template/memfriend6.C: Likewise.
|
||||
* g++.dg/template/memfriend7.C: Likewise.
|
||||
* g++.dg/template/memfriend8.C: Likewise.
|
||||
* g++.old-deja/g++.pt/friend44.C: Remove a bogus error.
|
||||
|
||||
2003-11-21 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
PR c++/12515
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2003 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Member function of class template as friend
|
||||
|
||||
template<class T> struct A
|
||||
{
|
||||
void f();
|
||||
};
|
||||
|
||||
class C {
|
||||
int i;
|
||||
template<class T> friend void A<T>::f();
|
||||
};
|
||||
|
||||
template<class T> struct A<T*>
|
||||
{
|
||||
void f();
|
||||
};
|
||||
|
||||
template<> struct A<char>
|
||||
{
|
||||
void f();
|
||||
};
|
||||
|
||||
template<class T> void A<T>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template<class T> void A<T*>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
void A<char>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int> a1;
|
||||
a1.f();
|
||||
A<int *> a2;
|
||||
a2.f();
|
||||
A<char> a3;
|
||||
a3.f();
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2003 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Member function template of class template as friend
|
||||
|
||||
template <class T> struct A
|
||||
{
|
||||
template <class U> void f();
|
||||
};
|
||||
|
||||
class C {
|
||||
int i;
|
||||
template <class T> template <class U> friend void A<T>::f();
|
||||
};
|
||||
|
||||
template <class T> struct A<T*>
|
||||
{
|
||||
template <class U> void f();
|
||||
};
|
||||
|
||||
template <> struct A<char>
|
||||
{
|
||||
template <class U> void f();
|
||||
};
|
||||
|
||||
template <class T> template <class U> void A<T>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <class T> template <class U> void A<T*>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <class U> void A<char>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <> void A<char>::f<int>()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int> a1;
|
||||
a1.f<char>();
|
||||
A<int *> a2;
|
||||
a2.f<char>();
|
||||
A<char> a3;
|
||||
a3.f<char>();
|
||||
a3.f<int>();
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2003 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Member function of class template as friend
|
||||
|
||||
template<class T> struct A
|
||||
{
|
||||
void f(T);
|
||||
};
|
||||
|
||||
class C {
|
||||
int i;
|
||||
template<class T> friend void A<T>::f(T);
|
||||
};
|
||||
|
||||
template<class T> struct A<T*>
|
||||
{
|
||||
void f(T*);
|
||||
};
|
||||
|
||||
template<> struct A<char>
|
||||
{
|
||||
void f(char);
|
||||
};
|
||||
|
||||
template<class T> void A<T>::f(T)
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template<class T> void A<T*>::f(T*)
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
void A<char>::f(char)
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int> a1;
|
||||
a1.f(0);
|
||||
A<int *> a2;
|
||||
int *p = 0;
|
||||
a2.f(p);
|
||||
A<char> a3;
|
||||
a3.f('a');
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2003 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Member function of class template as friend
|
||||
|
||||
template<class T> struct A
|
||||
{
|
||||
template <T t> void f();
|
||||
};
|
||||
|
||||
class C {
|
||||
int i;
|
||||
template<class T> template <T t> friend void A<T>::f();
|
||||
};
|
||||
|
||||
template<class T> struct A<T*>
|
||||
{
|
||||
template <T* t> void f();
|
||||
};
|
||||
|
||||
template<> struct A<char>
|
||||
{
|
||||
template <char t> void f();
|
||||
};
|
||||
|
||||
template<class T> template <T t> void A<T>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template<class T> template <T* t> void A<T*>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <char t> void A<char>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <> void A<char>::f<'b'>()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int d2 = 0;
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int> a1;
|
||||
a1.f<0>();
|
||||
A<int *> a2;
|
||||
a2.f<&d2>();
|
||||
A<char> a3;
|
||||
a3.f<'a'>();
|
||||
a3.f<'b'>();
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2003 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Member template function of member class template as friend
|
||||
|
||||
template <class T> struct A {
|
||||
template <class U> struct B {
|
||||
template <class V> void f(V);
|
||||
};
|
||||
};
|
||||
|
||||
class X {
|
||||
int i;
|
||||
template <class T> template <class U> template <class V>
|
||||
friend void A<T>::B<U>::f(V);
|
||||
};
|
||||
|
||||
template <class T> template <class U> template <class V>
|
||||
void A<T>::B<U>::f(V)
|
||||
{
|
||||
X x;
|
||||
x.i = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<char>::B<char> a1;
|
||||
a1.f(0);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2003 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Member function of class template as friend
|
||||
// Erroneous case: mismatch during declaration
|
||||
|
||||
template <class T> struct A {
|
||||
template <class U> void f(U); // { dg-error "candidate" }
|
||||
void g(); // { dg-error "candidate" }
|
||||
void h(); // { dg-error "candidate" }
|
||||
void i(int); // { dg-error "candidate" }
|
||||
};
|
||||
|
||||
class C {
|
||||
int ii;
|
||||
template <class U> friend void A<U>::f(U); // { dg-error "not match" }
|
||||
template <class U> template <class V>
|
||||
friend void A<U>::g(); // { dg-error "not match" }
|
||||
template <class U> friend int A<U>::h(); // { dg-error "not match" }
|
||||
template <class U> friend void A<U>::i(char); // { dg-error "not match" }
|
||||
};
|
|
@ -0,0 +1,133 @@
|
|||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2003 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Member function of class template as friend
|
||||
// Erroneous case: mismatch during specialization
|
||||
|
||||
template <class T> struct A {
|
||||
template <class U> void f(U);
|
||||
void g();
|
||||
void h();
|
||||
void i(int);
|
||||
template <T t> void j();
|
||||
};
|
||||
|
||||
class C {
|
||||
int ii; // { dg-error "private" }
|
||||
template <class U> template <class V>
|
||||
friend void A<U>::f(V);
|
||||
template <class U> friend void A<U>::g();
|
||||
template <class U> friend void A<U>::h();
|
||||
template <class U> friend void A<U>::i(int);
|
||||
template <class U> template <U t>
|
||||
friend void A<U>::j();
|
||||
};
|
||||
|
||||
template <class T> struct A<T*> {
|
||||
void f(int);
|
||||
template <class U> void g();
|
||||
int h();
|
||||
void i(char);
|
||||
template <int> void j();
|
||||
};
|
||||
|
||||
template <class T> void A<T*>::f(int)
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
template <class T> template <class U> void A<T*>::g()
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
template <class T> int A<T*>::h()
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
template <class T> void A<T*>::i(char)
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
template <class T> template <int> void A<T*>::j()
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
template <> struct A<char> {
|
||||
void f(int);
|
||||
template <class U> void g();
|
||||
int h();
|
||||
void i(char);
|
||||
template <int> void j();
|
||||
};
|
||||
|
||||
void A<char>::f(int)
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
template <class U> void A<char>::g()
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
template <> void A<char>::g<int>()
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
int A<char>::h()
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
void A<char>::i(char)
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
template <int> void A<char>::j()
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
template <> void A<char>::j<0>()
|
||||
{
|
||||
C c;
|
||||
c.ii = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int *> a1;
|
||||
a1.f(0); // { dg-error "instantiated" }
|
||||
a1.g<char>(); // { dg-error "instantiated" }
|
||||
a1.g<int>(); // { dg-error "instantiated" }
|
||||
a1.h(); // { dg-error "instantiated" }
|
||||
a1.i('a'); // { dg-error "instantiated" }
|
||||
a1.j<1>(); // { dg-error "instantiated" }
|
||||
A<char> a2;
|
||||
a2.f(0);
|
||||
a2.g<char>(); // { dg-error "instantiated" }
|
||||
a2.g<int>();
|
||||
a2.h();
|
||||
a2.i('a');
|
||||
a2.j<1>(); // { dg-error "instantiated" }
|
||||
a2.j<0>();
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// { dg-do compile }
|
||||
|
||||
// Origin: Martin Sebor <sebor@roguewave.com>
|
||||
|
||||
// PR c++/5369: Member function of class template as friend
|
||||
|
||||
template <class T>
|
||||
struct S
|
||||
{
|
||||
int foo () {
|
||||
return S<int>::bar ();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <class U>
|
||||
friend int S<U>::foo ();
|
||||
|
||||
static int bar () { return 0; }
|
||||
};
|
||||
|
||||
int main ()
|
||||
{
|
||||
S<char>().foo ();
|
||||
}
|
|
@ -23,7 +23,7 @@ public:
|
|||
template <class T> int A<T>::f (T)
|
||||
{
|
||||
B b;
|
||||
return b.a; // { dg-bogus "" "" { xfail *-*-* } }
|
||||
return b.a;
|
||||
}
|
||||
|
||||
template <class T> int A<T>::AI::f (T)
|
||||
|
|
Loading…
Reference in New Issue