Commit 5a24482e by Kriang Lerdsuwanakij Committed by Kriang Lerdsuwanakij

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
parent 18410793
2005-03-14 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net> 2005-03-14 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
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 <lerdsuwa@users.sourceforge.net>
Friend class name lookup 5/n Friend class name lookup 5/n
PR c++/1016 PR c++/1016
* cp-tree.h (pushtag): Adjust declaration. * cp-tree.h (pushtag): Adjust declaration.
......
...@@ -4571,10 +4571,19 @@ maybe_process_template_type_declaration (tree type, int is_friend, ...@@ -4571,10 +4571,19 @@ maybe_process_template_type_declaration (tree type, int is_friend,
return decl; return decl;
} }
/* Push a tag name NAME for struct/class/union/enum type TYPE. /* Push a tag name NAME for struct/class/union/enum type TYPE. In case
Normally put it into the inner-most non-sk_cleanup scope, that the NAME is a class template, the tag is processed but not pushed.
but if GLOBALIZE is true, put it in the inner-most non-class scope.
The latter is needed for implicit declarations. 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. */ Returns TYPE upon success and ERROR_MARK_NODE otherwise. */
tree tree
...@@ -4590,10 +4599,9 @@ pushtag (tree name, tree type, tag_scope scope) ...@@ -4590,10 +4599,9 @@ pushtag (tree name, tree type, tag_scope scope)
/* Neither are the scopes used to hold template parameters /* Neither are the scopes used to hold template parameters
for an explicit specialization. For an ordinary template for an explicit specialization. For an ordinary template
declaration, these scopes are not scopes from the point of declaration, these scopes are not scopes from the point of
view of the language -- but we need a place to stash view of the language. */
things that will go in the containing namespace when the || (b->kind == sk_template_parms
template is instantiated. */ && (b->explicit_spec_p || scope == ts_global))
|| (b->kind == sk_template_parms && b->explicit_spec_p)
|| (b->kind == sk_class || (b->kind == sk_class
&& (scope != ts_current && (scope != ts_current
/* We may be defining a new type in the initializer /* We may be defining a new type in the initializer
...@@ -4666,7 +4674,7 @@ pushtag (tree name, tree type, tag_scope scope) ...@@ -4666,7 +4674,7 @@ pushtag (tree name, tree type, tag_scope scope)
else else
pushdecl_class_level (d); pushdecl_class_level (d);
} }
else else if (b->kind != sk_template_parms)
d = pushdecl_with_scope (d, b); d = pushdecl_with_scope (d, b);
if (d == error_mark_node) if (d == error_mark_node)
......
...@@ -5781,11 +5781,13 @@ instantiate_class_template (tree type) ...@@ -5781,11 +5781,13 @@ instantiate_class_template (tree type)
if (TREE_CODE (friend_type) == TEMPLATE_DECL) if (TREE_CODE (friend_type) == TEMPLATE_DECL)
{ {
/* template <class T> friend class C; */
friend_type = tsubst_friend_class (friend_type, args); friend_type = tsubst_friend_class (friend_type, args);
adjust_processing_template_decl = true; adjust_processing_template_decl = true;
} }
else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE) else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE)
{ {
/* template <class T> friend class C::D; */
friend_type = tsubst (friend_type, args, friend_type = tsubst (friend_type, args,
tf_error | tf_warning, NULL_TREE); tf_error | tf_warning, NULL_TREE);
if (TREE_CODE (friend_type) == TEMPLATE_DECL) if (TREE_CODE (friend_type) == TEMPLATE_DECL)
...@@ -5794,6 +5796,15 @@ instantiate_class_template (tree type) ...@@ -5794,6 +5796,15 @@ instantiate_class_template (tree type)
} }
else if (TREE_CODE (friend_type) == TYPENAME_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 <class U> friend class T::C;
otherwise. */
friend_type = tsubst (friend_type, args, friend_type = tsubst (friend_type, args,
tf_error | tf_warning, NULL_TREE); tf_error | tf_warning, NULL_TREE);
/* Bump processing_template_decl for correct /* Bump processing_template_decl for correct
...@@ -5803,13 +5814,14 @@ instantiate_class_template (tree type) ...@@ -5803,13 +5814,14 @@ instantiate_class_template (tree type)
adjust_processing_template_decl = true; adjust_processing_template_decl = true;
--processing_template_decl; --processing_template_decl;
} }
else if (uses_template_parms (friend_type)) else if (!CLASSTYPE_USE_TEMPLATE (friend_type)
friend_type = tsubst (friend_type, args, && hidden_name_p (TYPE_NAME (friend_type)))
tf_error | tf_warning, NULL_TREE);
else if (CLASSTYPE_USE_TEMPLATE (friend_type))
friend_type = friend_type;
else
{ {
/* 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)); tree ns = decl_namespace_context (TYPE_MAIN_DECL (friend_type));
/* The call to xref_tag_from_type does injection for friend /* The call to xref_tag_from_type does injection for friend
...@@ -5817,9 +5829,22 @@ instantiate_class_template (tree type) ...@@ -5817,9 +5829,22 @@ instantiate_class_template (tree type)
push_nested_namespace (ns); push_nested_namespace (ns);
friend_type = friend_type =
xref_tag_from_type (friend_type, NULL_TREE, xref_tag_from_type (friend_type, NULL_TREE,
/*tag_scope=*/ts_global); /*tag_scope=*/ts_current);
pop_nested_namespace (ns); pop_nested_namespace (ns);
} }
else if (uses_template_parms (friend_type))
/* friend class C<T>; */
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<int>;
We don't have to do anything in these cases. */
if (adjust_processing_template_decl) if (adjust_processing_template_decl)
/* Trick make_friend_class into realizing that the friend /* Trick make_friend_class into realizing that the friend
......
2005-03-14 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net> 2005-03-14 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
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 <lerdsuwa@users.sourceforge.net>
Friend class name lookup 5/n Friend class name lookup 5/n
PR c++/1016 PR c++/1016
* g++.dg/lookup/hidden-class1.C: New test. * g++.dg/lookup/hidden-class1.C: New test.
......
// { dg-do compile }
// Origin: mleone@pixar.com
// Wolfgang Bangerth <bangerth@ticam.utexas.edu>
// PR c++/9783: Forward declaration of class in template.
template <typename T>
struct C {
void foo (struct X *);
};
struct X {};
template <typename T>
void C<T>::foo(struct X *) {}
// { dg-do compile }
// Origin: Giovanni Bajo <giovannibajo@libero.it>
// PR c++/4403: Incorrect friend class chosen during instantiation.
template <typename T>
struct A
{
struct F;
};
template <typename T>
struct B : A<T>
{
friend struct F;
private:
int priv;
};
struct F
{
void func(void)
{
B<int> b;
b.priv = 0;
}
};
...@@ -24,8 +24,8 @@ template <class T> class B ...@@ -24,8 +24,8 @@ template <class T> class B
static T value_AC; static T value_AC;
}; };
template <typename T> T B<T>::valueA_AA; template <typename T> T B<T>::valueA_AA;
template <typename T> T B<T>::valueA_AC;// { dg-error "" "" { xfail *-*-* } } private - template <typename T> T B<T>::valueA_AC;// { dg-error "" "" } private -
template <typename T> T B<T>::value_AC; // { dg-bogus "" "" { xfail *-*-* } } - template <typename T> T B<T>::value_AC; // { dg-bogus "" "" } -
// this one is a friend // this one is a friend
template <class T> struct A<T>::AA template <class T> struct A<T>::AA
...@@ -41,7 +41,7 @@ template <class T> struct A<T>::AC ...@@ -41,7 +41,7 @@ template <class T> struct A<T>::AC
{ {
T M () T M ()
{ {
return B<T>::valueA_AC; // { dg-error "" "" { xfail *-*-* } } within this context - return B<T>::valueA_AC; // { dg-error "" "" } within this context -
} }
}; };
...@@ -50,7 +50,7 @@ struct AC ...@@ -50,7 +50,7 @@ struct AC
{ {
int M () int M ()
{ {
return B<int>::value_AC; // { dg-bogus "" "" { xfail *-*-* } } - return B<int>::value_AC; // { dg-bogus "" "" } -
} }
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment