mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-18 04:40:25 +08:00
re PR c++/13495 (Friendship to class nested within a template is broken)
PR c++/13495 * decl.c (make_unbound_class_template): Add PARM_LIST parameter. * cp-tree.h (make_unbound_class_template): Adjust prototype. * parser.c (cp_parser_lookup_name): Adjust call to make_unbound_class_template. (cp_parser_single_declaration): Handle member class of class template as template friend parsing correctly. * friend.c (is_friend): Call is_specialization_of_friend for template friend class. (make_friend_class): Handle member class of class template as template friend. * pt.c (is_specialization_of_friend): Likewise. (instantiate_class_template): Likewise. (tsubst): Adjust call to make_unbound_class_template. * g++.dg/template/memfriend9.C: New test. * g++.dg/template/memfriend10.C: Likewise. * g++.dg/template/memfriend11.C: Likewise. * g++.dg/template/memfriend12.C: Likewise. * g++.dg/template/memfriend13.C: Likewise. * g++.dg/template/memfriend14.C: Likewise. * g++.dg/template/memfriend15.C: Likewise. * g++.dg/template/memfriend16.C: Likewise. * g++.dg/template/memfriend17.C: Likewise. * g++.old-deja/g++.pt/friend44.C: Remove bogus error. From-SVN: r89335
This commit is contained in:
parent
23517e6b4e
commit
b939a02360
gcc
cp
testsuite
ChangeLog
g++.dg/template
memfriend10.Cmemfriend11.Cmemfriend12.Cmemfriend13.Cmemfriend14.Cmemfriend15.Cmemfriend16.Cmemfriend17.Cmemfriend9.C
g++.old-deja/g++.pt
@ -1,3 +1,20 @@
|
||||
2004-10-20 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
PR c++/13495
|
||||
* decl.c (make_unbound_class_template): Add PARM_LIST parameter.
|
||||
* cp-tree.h (make_unbound_class_template): Adjust prototype.
|
||||
* parser.c (cp_parser_lookup_name): Adjust call to
|
||||
make_unbound_class_template.
|
||||
(cp_parser_single_declaration): Handle member class of class
|
||||
template as template friend parsing correctly.
|
||||
* friend.c (is_friend): Call is_specialization_of_friend for
|
||||
template friend class.
|
||||
(make_friend_class): Handle member class of class template as
|
||||
template friend.
|
||||
* pt.c (is_specialization_of_friend): Likewise.
|
||||
(instantiate_class_template): Likewise.
|
||||
(tsubst): Adjust call to make_unbound_class_template.
|
||||
|
||||
2004-10-20 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
* typeck.c (composite_pointer_type): Add comment about DR 195
|
||||
|
@ -3689,7 +3689,7 @@ extern tree define_label (location_t, tree);
|
||||
extern void check_goto (tree);
|
||||
extern void define_case_label (void);
|
||||
extern tree make_typename_type (tree, tree, tsubst_flags_t);
|
||||
extern tree make_unbound_class_template (tree, tree, tsubst_flags_t);
|
||||
extern tree make_unbound_class_template (tree, tree, tree, tsubst_flags_t);
|
||||
extern tree check_for_out_of_scope_variable (tree);
|
||||
extern tree build_library_fn (tree, tree);
|
||||
extern tree build_library_fn_ptr (const char *, tree);
|
||||
|
@ -2730,14 +2730,18 @@ make_typename_type (tree context, tree name, tsubst_flags_t complain)
|
||||
return build_typename_type (context, name, fullname);
|
||||
}
|
||||
|
||||
/* Resolve `CONTEXT::template NAME'. Returns an appropriate type,
|
||||
unless an error occurs, in which case error_mark_node is returned.
|
||||
If we locate a TYPE_DECL, we return that, rather than the _TYPE it
|
||||
corresponds to. If COMPLAIN zero, don't complain about any errors
|
||||
that occur. */
|
||||
/* Resolve `CONTEXT::template NAME'. Returns a TEMPLATE_DECL if the name
|
||||
can be resolved or an UNBOUND_CLASS_TEMPLATE, unless an error occurs,
|
||||
in which case error_mark_node is returned.
|
||||
|
||||
If PARM_LIST is non-NULL, also make sure that the template parameter
|
||||
list of TEMPLATE_DECL matches.
|
||||
|
||||
If COMPLAIN zero, don't complain about any errors that occur. */
|
||||
|
||||
tree
|
||||
make_unbound_class_template (tree context, tree name, tsubst_flags_t complain)
|
||||
make_unbound_class_template (tree context, tree name, tree parm_list,
|
||||
tsubst_flags_t complain)
|
||||
{
|
||||
tree t;
|
||||
tree d;
|
||||
@ -2763,6 +2767,17 @@ make_unbound_class_template (tree context, tree name, tsubst_flags_t complain)
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
if (parm_list
|
||||
&& !comp_template_parms (DECL_TEMPLATE_PARMS (tmpl), parm_list))
|
||||
{
|
||||
if (complain & tf_error)
|
||||
{
|
||||
error ("template parameters do not match template");
|
||||
cp_error_at ("%qD declared here", tmpl);
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
if (complain & tf_error)
|
||||
perform_or_defer_access_check (TYPE_BINFO (context), tmpl);
|
||||
|
||||
@ -2780,6 +2795,7 @@ make_unbound_class_template (tree context, tree name, tsubst_flags_t complain)
|
||||
TYPE_STUB_DECL (TREE_TYPE (d)) = d;
|
||||
DECL_CONTEXT (d) = FROB_CONTEXT (context);
|
||||
DECL_ARTIFICIAL (d) = 1;
|
||||
DECL_TEMPLATE_PARMS (d) = parm_list;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
113
gcc/cp/friend.c
113
gcc/cp/friend.c
@ -92,7 +92,7 @@ is_friend (tree type, tree supplicant)
|
||||
tree t = TREE_VALUE (list);
|
||||
|
||||
if (TREE_CODE (t) == TEMPLATE_DECL ?
|
||||
is_specialization_of (TYPE_MAIN_DECL (supplicant), t) :
|
||||
is_specialization_of_friend (TYPE_MAIN_DECL (supplicant), t) :
|
||||
same_type_p (supplicant, t))
|
||||
return 1;
|
||||
}
|
||||
@ -197,7 +197,31 @@ void
|
||||
make_friend_class (tree type, tree friend_type, bool complain)
|
||||
{
|
||||
tree classes;
|
||||
int is_template_friend;
|
||||
|
||||
/* 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,
|
||||
defined inside the `if' block for TYPENAME_TYPE case, 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 class C<V>::D;
|
||||
};
|
||||
};
|
||||
|
||||
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').
|
||||
|
||||
The friend is a template friend iff FRIEND_DEPTH is nonzero. */
|
||||
|
||||
int class_template_depth = template_class_depth (type);
|
||||
int friend_depth = processing_template_decl - class_template_depth;
|
||||
|
||||
if (! IS_AGGR_TYPE (friend_type))
|
||||
{
|
||||
@ -205,7 +229,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
|
||||
return;
|
||||
}
|
||||
|
||||
if (processing_template_decl > template_class_depth (type))
|
||||
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. */
|
||||
@ -221,8 +245,6 @@ make_friend_class (tree type, tree friend_type, bool complain)
|
||||
friend_type);
|
||||
return;
|
||||
}
|
||||
|
||||
is_template_friend = 1;
|
||||
}
|
||||
else if (same_type_p (type, friend_type))
|
||||
{
|
||||
@ -231,8 +253,6 @@ make_friend_class (tree type, tree friend_type, bool complain)
|
||||
type);
|
||||
return;
|
||||
}
|
||||
else
|
||||
is_template_friend = 0;
|
||||
|
||||
/* [temp.friend]
|
||||
|
||||
@ -240,13 +260,75 @@ make_friend_class (tree type, tree friend_type, bool complain)
|
||||
class template, a specialization of a function template or
|
||||
class template, or an ordinary (nontemplate) function or
|
||||
class. */
|
||||
if (!is_template_friend)
|
||||
if (!friend_depth)
|
||||
;/* ok */
|
||||
else if (TREE_CODE (friend_type) == TYPENAME_TYPE)
|
||||
{
|
||||
/* template <class T> friend typename S<T>::X; */
|
||||
error ("typename type %q#T declared %<friend%>", friend_type);
|
||||
return;
|
||||
if (TREE_CODE (TYPENAME_TYPE_FULLNAME (friend_type))
|
||||
== TEMPLATE_ID_EXPR)
|
||||
{
|
||||
/* template <class U> friend class T::X<U>; */
|
||||
/* [temp.friend]
|
||||
Friend declarations shall not declare partial
|
||||
specializations. */
|
||||
error ("partial specialization %qT declared %<friend%>",
|
||||
friend_type);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We will figure this out later. */
|
||||
bool template_member_p = false;
|
||||
|
||||
tree ctype = TYPE_CONTEXT (friend_type);
|
||||
tree name = TYPE_IDENTIFIER (friend_type);
|
||||
tree decl;
|
||||
|
||||
if (!uses_template_parms_level (ctype, class_template_depth
|
||||
+ friend_depth))
|
||||
template_member_p = true;
|
||||
|
||||
if (class_template_depth)
|
||||
{
|
||||
/* We rely on tsubst_friend_class to check the
|
||||
validity of the declaration later. */
|
||||
if (template_member_p)
|
||||
friend_type
|
||||
= make_unbound_class_template (ctype,
|
||||
name,
|
||||
current_template_parms,
|
||||
tf_error);
|
||||
else
|
||||
friend_type
|
||||
= make_typename_type (ctype, name, tf_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
decl = lookup_member (ctype, name, 0, true);
|
||||
if (!decl)
|
||||
{
|
||||
error ("%qT is not a member of %qT", name, ctype);
|
||||
return;
|
||||
}
|
||||
if (template_member_p && !DECL_CLASS_TEMPLATE_P (decl))
|
||||
{
|
||||
error ("%qT is not a member class template of %qT",
|
||||
name, ctype);
|
||||
cp_error_at ("%qD declared here", decl);
|
||||
return;
|
||||
}
|
||||
if (!template_member_p && (TREE_CODE (decl) != TYPE_DECL
|
||||
|| !CLASS_TYPE_P (TREE_TYPE (decl))))
|
||||
{
|
||||
error ("%qT is not a nested class of %qT",
|
||||
name, ctype);
|
||||
cp_error_at ("%qD declared here", decl);
|
||||
return;
|
||||
}
|
||||
|
||||
friend_type = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
|
||||
{
|
||||
@ -260,10 +342,13 @@ make_friend_class (tree type, tree friend_type, bool complain)
|
||||
error ("%q#T is not a template", friend_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_template_friend)
|
||||
else
|
||||
/* template <class T> friend class A; where A is a template */
|
||||
friend_type = CLASSTYPE_TI_TEMPLATE (friend_type);
|
||||
|
||||
if (friend_type == error_mark_node)
|
||||
return;
|
||||
|
||||
/* See if it is already a friend. */
|
||||
for (classes = CLASSTYPE_FRIEND_CLASSES (type);
|
||||
classes;
|
||||
@ -297,7 +382,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
|
||||
|
||||
CLASSTYPE_FRIEND_CLASSES (type)
|
||||
= tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
|
||||
if (is_template_friend)
|
||||
if (TREE_CODE (friend_type) == TEMPLATE_DECL)
|
||||
friend_type = TREE_TYPE (friend_type);
|
||||
if (!uses_template_parms (type))
|
||||
CLASSTYPE_BEFRIENDING_CLASSES (friend_type)
|
||||
|
@ -14158,7 +14158,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
|
||||
/*complain=*/1));
|
||||
else if (is_template)
|
||||
decl = make_unbound_class_template (parser->scope,
|
||||
name,
|
||||
name, NULL_TREE,
|
||||
/*complain=*/1);
|
||||
else
|
||||
decl = build_nt (SCOPE_REF, parser->scope, name);
|
||||
@ -14847,6 +14847,21 @@ cp_parser_single_declaration (cp_parser* parser,
|
||||
if (cp_parser_declares_only_class_p (parser))
|
||||
{
|
||||
decl = shadow_tag (&decl_specifiers);
|
||||
|
||||
/* In this case:
|
||||
|
||||
struct C {
|
||||
friend template <typename T> struct A<T>::B;
|
||||
};
|
||||
|
||||
A<T>::B will be represented by a TYPENAME_TYPE, and
|
||||
therefore not recognized by shadow_tag. */
|
||||
if (friend_p && *friend_p
|
||||
&& !decl
|
||||
&& decl_specifiers.type
|
||||
&& TYPE_P (decl_specifiers.type))
|
||||
decl = decl_specifiers.type;
|
||||
|
||||
if (decl && decl != error_mark_node)
|
||||
decl = TYPE_NAME (decl);
|
||||
else
|
||||
|
122
gcc/cp/pt.c
122
gcc/cp/pt.c
@ -939,7 +939,8 @@ is_specialization_of_friend (tree decl, tree friend)
|
||||
bool need_template = true;
|
||||
int template_depth;
|
||||
|
||||
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
|
||||
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
|
||||
|| TREE_CODE (decl) == TYPE_DECL);
|
||||
|
||||
/* For [temp.friend/6] when FRIEND is an ordinary member function
|
||||
of a template class, we want to check if DECL is a specialization
|
||||
@ -948,16 +949,20 @@ is_specialization_of_friend (tree decl, tree friend)
|
||||
&& DECL_TEMPLATE_INFO (friend)
|
||||
&& !DECL_USE_TEMPLATE (friend))
|
||||
{
|
||||
/* We want a TEMPLATE_DECL for `is_specialization_of'. */
|
||||
friend = DECL_TI_TEMPLATE (friend);
|
||||
need_template = false;
|
||||
}
|
||||
else if (TREE_CODE (friend) == TEMPLATE_DECL
|
||||
&& !PRIMARY_TEMPLATE_P (friend))
|
||||
need_template = false;
|
||||
|
||||
/* There is nothing to do if this is not a template friend. */
|
||||
if (TREE_CODE (friend) != TEMPLATE_DECL)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (is_specialization_of (decl, friend))
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
/* [temp.friend/6]
|
||||
A member of a class template may be declared to be a friend of a
|
||||
@ -986,17 +991,25 @@ is_specialization_of_friend (tree decl, tree friend)
|
||||
CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (friend))))
|
||||
{
|
||||
/* Next, we check the members themselves. In order to handle
|
||||
a few tricky cases like
|
||||
a few tricky cases, such as when FRIEND's are
|
||||
|
||||
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. */
|
||||
and DECL's are
|
||||
|
||||
void A<int>::g(int);
|
||||
template <int> void A<int>::h();
|
||||
|
||||
we need to figure out ARGS, the template arguments from
|
||||
the context of DECL. This is required for template substitution
|
||||
of `T' in the function parameter of `g' and template parameter
|
||||
of `h' in the above examples. Here ARGS corresponds to `int'. */
|
||||
|
||||
tree context = DECL_CONTEXT (decl);
|
||||
tree args = NULL_TREE;
|
||||
int current_depth = 0;
|
||||
|
||||
while (current_depth < template_depth)
|
||||
{
|
||||
if (CLASSTYPE_TEMPLATE_INFO (context))
|
||||
@ -1023,7 +1036,7 @@ is_specialization_of_friend (tree decl, tree friend)
|
||||
is_template = DECL_TEMPLATE_INFO (decl)
|
||||
&& PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl));
|
||||
if (need_template ^ is_template)
|
||||
return 0;
|
||||
return false;
|
||||
else if (is_template)
|
||||
{
|
||||
/* If both are templates, check template parameter list. */
|
||||
@ -1033,7 +1046,7 @@ is_specialization_of_friend (tree decl, tree friend)
|
||||
if (!comp_template_parms
|
||||
(DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl)),
|
||||
friend_parms))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
decl_type = TREE_TYPE (DECL_TI_TEMPLATE (decl));
|
||||
}
|
||||
@ -1043,11 +1056,11 @@ is_specialization_of_friend (tree decl, tree friend)
|
||||
friend_type = tsubst_function_type (TREE_TYPE (friend), args,
|
||||
tf_none, NULL_TREE);
|
||||
if (friend_type == error_mark_node)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
/* Check if return types match. */
|
||||
if (!same_type_p (TREE_TYPE (decl_type), TREE_TYPE (friend_type)))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
/* Check if function parameter types match, ignoring the
|
||||
`this' parameter. */
|
||||
@ -1057,11 +1070,46 @@ is_specialization_of_friend (tree decl, tree 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 compparms (decl_args_type, friend_args_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* DECL is a TYPE_DECL */
|
||||
bool is_template;
|
||||
tree decl_type = TREE_TYPE (decl);
|
||||
|
||||
/* Make sure that both DECL and FRIEND are templates or
|
||||
non-templates. */
|
||||
is_template
|
||||
= CLASSTYPE_TEMPLATE_INFO (decl_type)
|
||||
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (decl_type));
|
||||
|
||||
if (need_template ^ is_template)
|
||||
return false;
|
||||
else if (is_template)
|
||||
{
|
||||
tree friend_parms;
|
||||
/* If both are templates, check the name of the two
|
||||
TEMPLATE_DECL's first because is_friend didn't. */
|
||||
if (DECL_NAME (CLASSTYPE_TI_TEMPLATE (decl_type))
|
||||
!= DECL_NAME (friend))
|
||||
return false;
|
||||
|
||||
/* Now check template parameter list. */
|
||||
friend_parms
|
||||
= tsubst_template_parms (DECL_TEMPLATE_PARMS (friend),
|
||||
args, tf_none);
|
||||
return comp_template_parms
|
||||
(DECL_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (decl_type)),
|
||||
friend_parms);
|
||||
}
|
||||
else
|
||||
return (DECL_NAME (decl)
|
||||
== DECL_NAME (friend));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Register the specialization SPEC as a specialization of TMPL with
|
||||
@ -5691,15 +5739,37 @@ instantiate_class_template (tree type)
|
||||
/* Build new CLASSTYPE_FRIEND_CLASSES. */
|
||||
|
||||
tree friend_type = t;
|
||||
tree new_friend_type;
|
||||
bool adjust_processing_template_decl = false;
|
||||
|
||||
if (TREE_CODE (friend_type) == TEMPLATE_DECL)
|
||||
new_friend_type = tsubst_friend_class (friend_type, args);
|
||||
{
|
||||
friend_type = tsubst_friend_class (friend_type, args);
|
||||
adjust_processing_template_decl = true;
|
||||
}
|
||||
else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE)
|
||||
{
|
||||
friend_type = tsubst (friend_type, args,
|
||||
tf_error | tf_warning, NULL_TREE);
|
||||
if (TREE_CODE (friend_type) == TEMPLATE_DECL)
|
||||
friend_type = TREE_TYPE (friend_type);
|
||||
adjust_processing_template_decl = true;
|
||||
}
|
||||
else if (TREE_CODE (friend_type) == TYPENAME_TYPE)
|
||||
{
|
||||
friend_type = tsubst (friend_type, args,
|
||||
tf_error | tf_warning, NULL_TREE);
|
||||
/* Bump processing_template_decl for correct
|
||||
dependent_type_p calculation. */
|
||||
++processing_template_decl;
|
||||
if (dependent_type_p (friend_type))
|
||||
adjust_processing_template_decl = true;
|
||||
--processing_template_decl;
|
||||
}
|
||||
else if (uses_template_parms (friend_type))
|
||||
new_friend_type = tsubst (friend_type, args,
|
||||
tf_error | tf_warning, NULL_TREE);
|
||||
friend_type = tsubst (friend_type, args,
|
||||
tf_error | tf_warning, NULL_TREE);
|
||||
else if (CLASSTYPE_USE_TEMPLATE (friend_type))
|
||||
new_friend_type = friend_type;
|
||||
friend_type = friend_type;
|
||||
else
|
||||
{
|
||||
tree ns = decl_namespace_context (TYPE_MAIN_DECL (friend_type));
|
||||
@ -5707,12 +5777,12 @@ instantiate_class_template (tree type)
|
||||
/* The call to xref_tag_from_type does injection for friend
|
||||
classes. */
|
||||
push_nested_namespace (ns);
|
||||
new_friend_type =
|
||||
friend_type =
|
||||
xref_tag_from_type (friend_type, NULL_TREE, 1);
|
||||
pop_nested_namespace (ns);
|
||||
}
|
||||
|
||||
if (TREE_CODE (friend_type) == TEMPLATE_DECL)
|
||||
if (adjust_processing_template_decl)
|
||||
/* Trick make_friend_class into realizing that the friend
|
||||
we're adding is a template, not an ordinary class. It's
|
||||
important that we use make_friend_class since it will
|
||||
@ -5720,11 +5790,10 @@ instantiate_class_template (tree type)
|
||||
information. */
|
||||
++processing_template_decl;
|
||||
|
||||
if (new_friend_type != error_mark_node)
|
||||
make_friend_class (type, new_friend_type,
|
||||
/*complain=*/false);
|
||||
if (friend_type != error_mark_node)
|
||||
make_friend_class (type, friend_type, /*complain=*/false);
|
||||
|
||||
if (TREE_CODE (friend_type) == TEMPLATE_DECL)
|
||||
if (adjust_processing_template_decl)
|
||||
--processing_template_decl;
|
||||
}
|
||||
else
|
||||
@ -7283,11 +7352,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
|
||||
in_decl, /*entering_scope=*/1);
|
||||
tree name = TYPE_IDENTIFIER (t);
|
||||
tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t));
|
||||
|
||||
if (ctx == error_mark_node || name == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
return make_unbound_class_template (ctx, name, complain);
|
||||
if (parm_list)
|
||||
parm_list = tsubst_template_parms (parm_list, args, complain);
|
||||
return make_unbound_class_template (ctx, name, parm_list, complain);
|
||||
}
|
||||
|
||||
case INDIRECT_REF:
|
||||
|
@ -1,3 +1,17 @@
|
||||
2004-10-20 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
PR c++/13495
|
||||
* g++.dg/template/memfriend9.C: New test.
|
||||
* g++.dg/template/memfriend10.C: Likewise.
|
||||
* g++.dg/template/memfriend11.C: Likewise.
|
||||
* g++.dg/template/memfriend12.C: Likewise.
|
||||
* g++.dg/template/memfriend13.C: Likewise.
|
||||
* g++.dg/template/memfriend14.C: Likewise.
|
||||
* g++.dg/template/memfriend15.C: Likewise.
|
||||
* g++.dg/template/memfriend16.C: Likewise.
|
||||
* g++.dg/template/memfriend17.C: Likewise.
|
||||
* g++.old-deja/g++.pt/friend44.C: Remove bogus error.
|
||||
|
||||
2004-10-20 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
* g++.dg/conversion/dr195.C: New.
|
||||
|
71
gcc/testsuite/g++.dg/template/memfriend10.C
Normal file
71
gcc/testsuite/g++.dg/template/memfriend10.C
Normal file
@ -0,0 +1,71 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Nested class template of class template as friend
|
||||
|
||||
template <class T> struct A
|
||||
{
|
||||
template <class U> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
class C {
|
||||
int i;
|
||||
template <class T> template <class U> friend struct A<T>::B;
|
||||
};
|
||||
|
||||
template <class T> struct A<T*>
|
||||
{
|
||||
template <class U> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct A<char>
|
||||
{
|
||||
template <class U> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template <class T> template <class U> void A<T>::B<U>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <class T> template <class U> void A<T*>::B<U>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <class U> void A<char>::B<U>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <> void A<char>::B<int>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int>::B<int> b1;
|
||||
b1.f();
|
||||
A<int *>::B<int> b2;
|
||||
b2.f();
|
||||
A<char>::B<char> b3;
|
||||
b3.f();
|
||||
A<char>::B<int> b4;
|
||||
b4.f();
|
||||
}
|
73
gcc/testsuite/g++.dg/template/memfriend11.C
Normal file
73
gcc/testsuite/g++.dg/template/memfriend11.C
Normal file
@ -0,0 +1,73 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Nest class template of class template as friend
|
||||
|
||||
template<class T> struct A
|
||||
{
|
||||
template <T t> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
class C {
|
||||
int i;
|
||||
template<class T> template <T t> friend struct A<T>::B;
|
||||
};
|
||||
|
||||
template<class T> struct A<T*>
|
||||
{
|
||||
template <T* t> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template<> struct A<char>
|
||||
{
|
||||
template <char t> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template<class T> template <T t> void A<T>::B<t>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template<class T> template <T* t> void A<T*>::B<t>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <char t> void A<char>::B<t>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <> void A<char>::B<'b'>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int d2 = 0;
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int>::B<0> b1;
|
||||
b1.f();
|
||||
A<int *>::B<&d2> b2;
|
||||
b2.f();
|
||||
A<char>::B<'a'> b3;
|
||||
b3.f();
|
||||
A<char>::B<'b'> b4;
|
||||
b4.f();
|
||||
}
|
63
gcc/testsuite/g++.dg/template/memfriend12.C
Normal file
63
gcc/testsuite/g++.dg/template/memfriend12.C
Normal file
@ -0,0 +1,63 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Nested class of class template as friend
|
||||
|
||||
template<class T> struct A
|
||||
{
|
||||
struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template <class U> class C {
|
||||
int i;
|
||||
template<class T> friend struct A<T>::B;
|
||||
};
|
||||
|
||||
template<class T> struct A<T*>
|
||||
{
|
||||
struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template<> struct A<char>
|
||||
{
|
||||
struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template<class T> void A<T>::B::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template<class T> void A<T*>::B::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
void A<char>::B::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int>::B b1;
|
||||
b1.f();
|
||||
A<int *>::B b2;
|
||||
b2.f();
|
||||
A<char>::B b3;
|
||||
b3.f();
|
||||
}
|
71
gcc/testsuite/g++.dg/template/memfriend13.C
Normal file
71
gcc/testsuite/g++.dg/template/memfriend13.C
Normal file
@ -0,0 +1,71 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Nested class template of class template as friend
|
||||
|
||||
template <class T> struct A
|
||||
{
|
||||
template <class U> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template <class V> class C {
|
||||
int i;
|
||||
template <class T> template <class U> friend struct A<T>::B;
|
||||
};
|
||||
|
||||
template <class T> struct A<T*>
|
||||
{
|
||||
template <class U> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct A<char>
|
||||
{
|
||||
template <class U> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template <class T> template <class U> void A<T>::B<U>::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <class T> template <class U> void A<T*>::B<U>::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <class U> void A<char>::B<U>::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <> void A<char>::B<int>::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int>::B<int> b1;
|
||||
b1.f();
|
||||
A<int *>::B<int> b2;
|
||||
b2.f();
|
||||
A<char>::B<char> b3;
|
||||
b3.f();
|
||||
A<char>::B<int> b4;
|
||||
b4.f();
|
||||
}
|
73
gcc/testsuite/g++.dg/template/memfriend14.C
Normal file
73
gcc/testsuite/g++.dg/template/memfriend14.C
Normal file
@ -0,0 +1,73 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Nest class template of class template as friend
|
||||
|
||||
template<class T> struct A
|
||||
{
|
||||
template <T t> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template <class U> class C {
|
||||
int i;
|
||||
template<class T> template <T t> friend struct A<T>::B;
|
||||
};
|
||||
|
||||
template<class T> struct A<T*>
|
||||
{
|
||||
template <T* t> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template<> struct A<char>
|
||||
{
|
||||
template <char t> struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template<class T> template <T t> void A<T>::B<t>::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template<class T> template <T* t> void A<T*>::B<t>::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <char t> void A<char>::B<t>::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template <> void A<char>::B<'b'>::f()
|
||||
{
|
||||
C<int> c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int d2 = 0;
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int>::B<0> b1;
|
||||
b1.f();
|
||||
A<int *>::B<&d2> b2;
|
||||
b2.f();
|
||||
A<char>::B<'a'> b3;
|
||||
b3.f();
|
||||
A<char>::B<'b'> b4;
|
||||
b4.f();
|
||||
}
|
34
gcc/testsuite/g++.dg/template/memfriend15.C
Normal file
34
gcc/testsuite/g++.dg/template/memfriend15.C
Normal file
@ -0,0 +1,34 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Nested class of class template as friend
|
||||
|
||||
template<class T> struct A
|
||||
{
|
||||
struct B1
|
||||
{
|
||||
};
|
||||
struct B2
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
class C {
|
||||
int i; // { dg-error "private" }
|
||||
template<class T> friend struct A<T>::B1;
|
||||
};
|
||||
|
||||
template<class T> void A<T>::B2::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int>::B2 b1;
|
||||
b1.f(); // { dg-error "instantiated" }
|
||||
}
|
34
gcc/testsuite/g++.dg/template/memfriend16.C
Normal file
34
gcc/testsuite/g++.dg/template/memfriend16.C
Normal file
@ -0,0 +1,34 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Nested class of class template as friend
|
||||
|
||||
template<class T> struct A
|
||||
{
|
||||
template <class U> struct B1
|
||||
{
|
||||
};
|
||||
template <class U> struct B2
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
class C {
|
||||
int i; // { dg-error "private" }
|
||||
template<class T> template <class U> friend struct A<T>::B1;
|
||||
};
|
||||
|
||||
template<class T> template <class U> void A<T>::B2<U>::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0; // { dg-error "context" }
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int>::B2<int> b1;
|
||||
b1.f(); // { dg-error "instantiated" }
|
||||
}
|
46
gcc/testsuite/g++.dg/template/memfriend17.C
Normal file
46
gcc/testsuite/g++.dg/template/memfriend17.C
Normal file
@ -0,0 +1,46 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Origin: Giovanni Bajo <giovannibajo@libero.it>
|
||||
|
||||
// PR c++/13495: Nested class as template friend.
|
||||
|
||||
template<typename T>
|
||||
class A{
|
||||
public:
|
||||
class B
|
||||
{
|
||||
void func1(void);
|
||||
void func2(void);
|
||||
};
|
||||
};
|
||||
|
||||
template<typename Q>
|
||||
class F1
|
||||
{
|
||||
friend class A<Q>::B;
|
||||
enum { foo = 0 }; // { dg-error "private" }
|
||||
};
|
||||
|
||||
template<typename Q>
|
||||
class F2
|
||||
{
|
||||
template<typename T>
|
||||
friend class A<T>::B;
|
||||
enum { foo = 0 };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void A<T>::B::func1(void)
|
||||
{
|
||||
(void)F1<T>::foo;
|
||||
(void)F2<T>::foo;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void A<T>::B::func2(void)
|
||||
{
|
||||
(void)F1<T*>::foo; // { dg-error "context" }
|
||||
(void)F2<T*>::foo;
|
||||
}
|
||||
|
||||
template class A<int>; // { dg-error "instantiated" }
|
63
gcc/testsuite/g++.dg/template/memfriend9.C
Normal file
63
gcc/testsuite/g++.dg/template/memfriend9.C
Normal file
@ -0,0 +1,63 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2004 Free Software Foundation
|
||||
// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
|
||||
|
||||
// Nested class of class template as friend
|
||||
|
||||
template<class T> struct A
|
||||
{
|
||||
struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
class C {
|
||||
int i;
|
||||
template<class T> friend struct A<T>::B;
|
||||
};
|
||||
|
||||
template<class T> struct A<T*>
|
||||
{
|
||||
struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template<> struct A<char>
|
||||
{
|
||||
struct B
|
||||
{
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
template<class T> void A<T>::B::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
template<class T> void A<T*>::B::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
void A<char>::B::f()
|
||||
{
|
||||
C c;
|
||||
c.i = 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A<int>::B b1;
|
||||
b1.f();
|
||||
A<int *>::B b2;
|
||||
b2.f();
|
||||
A<char>::B b3;
|
||||
b3.f();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// { dg-do run }
|
||||
// { dg-do compile }
|
||||
// Test that template friends referring to class template members are
|
||||
// respected.
|
||||
|
||||
@ -15,7 +15,7 @@ class B
|
||||
{
|
||||
template <class T> friend int A<T>::f (T);
|
||||
template <class T> friend struct A<T>::AI;
|
||||
int a; // { dg-bogus "" "" { xfail *-*-* } }
|
||||
int a;
|
||||
public:
|
||||
B(): a(0) { }
|
||||
};
|
||||
@ -29,7 +29,7 @@ template <class T> int A<T>::f (T)
|
||||
template <class T> int A<T>::AI::f (T)
|
||||
{
|
||||
B b;
|
||||
return b.a; // { dg-bogus "" "" { xfail *-*-* } }
|
||||
return b.a;
|
||||
}
|
||||
|
||||
int main ()
|
||||
|
Loading…
x
Reference in New Issue
Block a user