From: Kriang Lerdsuwanakij Date: Mon, 14 Mar 2005 14:51:25 +0000 (+0000) Subject: re PR c++/4403 (incorrect class becomes a friend in template) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5a24482e72fb06ef2e93050cdb056002f99bb226;p=gcc.git re PR c++/4403 (incorrect class becomes a friend in template) PR c++/4403 PR c++/9783, DR433 * name-lookup.c (pushtag): Skip template parameter scope when scope is ts_global. Don't push tag into template parameter scope. * pt.c (instantiate_class_template): Reorder friend class template substitution to handle non-dependent friend class that hasn't been previously declared. * g++.dg/template/friend34.C: New test. * g++.dg/template/friend35.C: Likewise. * g++.old-deja/g++.pt/inherit2.C: Remove XFAIL's. From-SVN: r96432 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e2a7de3b1b5..0ac2a84379c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2005-03-14 Kriang Lerdsuwanakij + + PR c++/4403 + PR c++/9783, DR433 + * name-lookup.c (pushtag): Skip template parameter scope when + scope is ts_global. Don't push tag into template parameter + scope. + * pt.c (instantiate_class_template): Reorder friend class + template substitution to handle non-dependent friend class + that hasn't been previously declared. + 2005-03-14 Kriang Lerdsuwanakij Friend class name lookup 5/n diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 4a5429cd29d..fda7d345b1f 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -4571,10 +4571,19 @@ maybe_process_template_type_declaration (tree type, int is_friend, return decl; } -/* Push a tag name NAME for struct/class/union/enum type TYPE. - Normally put it into the inner-most non-sk_cleanup scope, - but if GLOBALIZE is true, put it in the inner-most non-class scope. - The latter is needed for implicit declarations. +/* Push a tag name NAME for struct/class/union/enum type TYPE. In case + that the NAME is a class template, the tag is processed but not pushed. + + The pushed scope depend on the SCOPE parameter: + - When SCOPE is TS_CURRENT, put it into the inner-most non-sk_cleanup + scope. + - When SCOPE is TS_GLOBAL, put it in the inner-most non-class and + non-template-parameter scope. This case is needed for forward + declarations. + - When SCOPE is TS_WITHIN_ENCLOSING_NON_CLASS, this is similar to + TS_GLOBAL case except that names within template-parameter scopes + are not pushed at all. + Returns TYPE upon success and ERROR_MARK_NODE otherwise. */ tree @@ -4590,10 +4599,9 @@ pushtag (tree name, tree type, tag_scope scope) /* Neither are the scopes used to hold template parameters for an explicit specialization. For an ordinary template declaration, these scopes are not scopes from the point of - view of the language -- but we need a place to stash - things that will go in the containing namespace when the - template is instantiated. */ - || (b->kind == sk_template_parms && b->explicit_spec_p) + view of the language. */ + || (b->kind == sk_template_parms + && (b->explicit_spec_p || scope == ts_global)) || (b->kind == sk_class && (scope != ts_current /* We may be defining a new type in the initializer @@ -4666,7 +4674,7 @@ pushtag (tree name, tree type, tag_scope scope) else pushdecl_class_level (d); } - else + else if (b->kind != sk_template_parms) d = pushdecl_with_scope (d, b); if (d == error_mark_node) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1147f7984e2..51d32b32a37 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5781,11 +5781,13 @@ instantiate_class_template (tree type) if (TREE_CODE (friend_type) == TEMPLATE_DECL) { + /* template friend class C; */ friend_type = tsubst_friend_class (friend_type, args); adjust_processing_template_decl = true; } else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE) { + /* template friend class C::D; */ friend_type = tsubst (friend_type, args, tf_error | tf_warning, NULL_TREE); if (TREE_CODE (friend_type) == TEMPLATE_DECL) @@ -5794,6 +5796,15 @@ instantiate_class_template (tree type) } else if (TREE_CODE (friend_type) == TYPENAME_TYPE) { + /* This could be either + + friend class T::C; + + when dependent_type_p is false or + + template friend class T::C; + + otherwise. */ friend_type = tsubst (friend_type, args, tf_error | tf_warning, NULL_TREE); /* Bump processing_template_decl for correct @@ -5803,13 +5814,14 @@ instantiate_class_template (tree type) adjust_processing_template_decl = true; --processing_template_decl; } - else if (uses_template_parms (friend_type)) - friend_type = tsubst (friend_type, args, - tf_error | tf_warning, NULL_TREE); - else if (CLASSTYPE_USE_TEMPLATE (friend_type)) - friend_type = friend_type; - else + else if (!CLASSTYPE_USE_TEMPLATE (friend_type) + && hidden_name_p (TYPE_NAME (friend_type))) { + /* friend class C; + + where C hasn't been declared yet. Let's lookup name + from namespace scope directly, bypassing any name that + come from dependent base class. */ tree ns = decl_namespace_context (TYPE_MAIN_DECL (friend_type)); /* The call to xref_tag_from_type does injection for friend @@ -5817,9 +5829,22 @@ instantiate_class_template (tree type) push_nested_namespace (ns); friend_type = xref_tag_from_type (friend_type, NULL_TREE, - /*tag_scope=*/ts_global); + /*tag_scope=*/ts_current); pop_nested_namespace (ns); } + else if (uses_template_parms (friend_type)) + /* friend class C; */ + friend_type = tsubst (friend_type, args, + tf_error | tf_warning, NULL_TREE); + /* Otherwise it's + + friend class C; + + where C is already declared or + + friend class C; + + We don't have to do anything in these cases. */ if (adjust_processing_template_decl) /* Trick make_friend_class into realizing that the friend diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 993b95b8ee9..841c7330a6c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2005-03-14 Kriang Lerdsuwanakij + + PR c++/4403 + PR c++/9783, DR433 + * g++.dg/template/friend34.C: New test. + * g++.dg/template/friend35.C: Likewise. + * g++.old-deja/g++.pt/inherit2.C: Remove XFAIL's. + 2005-03-14 Kriang Lerdsuwanakij Friend class name lookup 5/n diff --git a/gcc/testsuite/g++.dg/template/friend34.C b/gcc/testsuite/g++.dg/template/friend34.C new file mode 100644 index 00000000000..555cf358a7d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend34.C @@ -0,0 +1,16 @@ +// { dg-do compile } + +// Origin: mleone@pixar.com +// Wolfgang Bangerth + +// PR c++/9783: Forward declaration of class in template. + +template +struct C { + void foo (struct X *); +}; + +struct X {}; + +template +void C::foo(struct X *) {} diff --git a/gcc/testsuite/g++.dg/template/friend35.C b/gcc/testsuite/g++.dg/template/friend35.C new file mode 100644 index 00000000000..b150ccdab89 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend35.C @@ -0,0 +1,28 @@ +// { dg-do compile } + +// Origin: Giovanni Bajo + +// PR c++/4403: Incorrect friend class chosen during instantiation. + +template +struct A +{ + struct F; +}; + +template +struct B : A +{ + friend struct F; +private: + int priv; +}; + +struct F +{ + void func(void) + { + B b; + b.priv = 0; + } +}; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/inherit2.C b/gcc/testsuite/g++.old-deja/g++.pt/inherit2.C index 2ae56727370..136050d455a 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/inherit2.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/inherit2.C @@ -24,8 +24,8 @@ template class B static T value_AC; }; template T B::valueA_AA; -template T B::valueA_AC;// { dg-error "" "" { xfail *-*-* } } private - -template T B::value_AC; // { dg-bogus "" "" { xfail *-*-* } } - +template T B::valueA_AC;// { dg-error "" "" } private - +template T B::value_AC; // { dg-bogus "" "" } - // this one is a friend template struct A::AA @@ -41,7 +41,7 @@ template struct A::AC { T M () { - return B::valueA_AC; // { dg-error "" "" { xfail *-*-* } } within this context - + return B::valueA_AC; // { dg-error "" "" } within this context - } }; @@ -50,7 +50,7 @@ struct AC { int M () { - return B::value_AC; // { dg-bogus "" "" { xfail *-*-* } } - + return B::value_AC; // { dg-bogus "" "" } - } };