diff options
author | Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net> | 2004-10-20 16:20:50 +0000 |
---|---|---|
committer | Kriang Lerdsuwanakij <lerdsuwa@gcc.gnu.org> | 2004-10-20 16:20:50 +0000 |
commit | b939a02360cf41893436921e319c4283f2d6edb5 (patch) | |
tree | 36d5919ab016d6c55b8dee09fb15a76c348df75e | |
parent | 23517e6b4ea01d0af35984f8473a235a29ff93c7 (diff) | |
download | gcc-b939a02360cf41893436921e319c4283f2d6edb5.tar.gz |
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
-rw-r--r-- | gcc/cp/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 2 | ||||
-rw-r--r-- | gcc/cp/decl.c | 28 | ||||
-rw-r--r-- | gcc/cp/friend.c | 113 | ||||
-rw-r--r-- | gcc/cp/parser.c | 17 | ||||
-rw-r--r-- | gcc/cp/pt.c | 122 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/memfriend10.C | 71 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/memfriend11.C | 73 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/memfriend12.C | 63 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/memfriend13.C | 71 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/memfriend14.C | 73 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/memfriend15.C | 34 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/memfriend16.C | 34 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/memfriend17.C | 46 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/memfriend9.C | 63 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/friend44.C | 6 |
17 files changed, 797 insertions, 50 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6dc5345e282..a90cc61f575 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6534170392e..0f75fce3812 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 00844fdbd0b..21ffb519e82 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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; } diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index 6ab9d731ca5..2d177a084f3 100644 --- a/gcc/cp/friend.c +++ b/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) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index df3cb6526de..fc947a5936f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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 diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 18e3c0a057d..1ced2389f90 100644 --- a/gcc/cp/pt.c +++ b/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: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 04c73cd9989..f072df9f7b6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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. diff --git a/gcc/testsuite/g++.dg/template/memfriend10.C b/gcc/testsuite/g++.dg/template/memfriend10.C new file mode 100644 index 00000000000..4fe760af2eb --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend10.C @@ -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(); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend11.C b/gcc/testsuite/g++.dg/template/memfriend11.C new file mode 100644 index 00000000000..d06a936d59b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend11.C @@ -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(); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend12.C b/gcc/testsuite/g++.dg/template/memfriend12.C new file mode 100644 index 00000000000..77f8214003d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend12.C @@ -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(); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend13.C b/gcc/testsuite/g++.dg/template/memfriend13.C new file mode 100644 index 00000000000..7faed22a217 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend13.C @@ -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(); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend14.C b/gcc/testsuite/g++.dg/template/memfriend14.C new file mode 100644 index 00000000000..86d2d3f0e26 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend14.C @@ -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(); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend15.C b/gcc/testsuite/g++.dg/template/memfriend15.C new file mode 100644 index 00000000000..08db7aef655 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend15.C @@ -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" } +} diff --git a/gcc/testsuite/g++.dg/template/memfriend16.C b/gcc/testsuite/g++.dg/template/memfriend16.C new file mode 100644 index 00000000000..a4eeafd79fe --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend16.C @@ -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" } +} diff --git a/gcc/testsuite/g++.dg/template/memfriend17.C b/gcc/testsuite/g++.dg/template/memfriend17.C new file mode 100644 index 00000000000..fd26bc0171e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend17.C @@ -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" } diff --git a/gcc/testsuite/g++.dg/template/memfriend9.C b/gcc/testsuite/g++.dg/template/memfriend9.C new file mode 100644 index 00000000000..9c926013b06 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend9.C @@ -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(); +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend44.C b/gcc/testsuite/g++.old-deja/g++.pt/friend44.C index 1f791729061..1d2c1d1f9b6 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/friend44.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/friend44.C @@ -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 () |