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
This commit is contained in:
Kriang Lerdsuwanakij 2005-03-14 14:51:25 +00:00 committed by Kriang Lerdsuwanakij
parent 184107932d
commit 5a24482e72
7 changed files with 116 additions and 20 deletions

View File

@ -1,3 +1,14 @@
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

View File

@ -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)

View File

@ -5781,11 +5781,13 @@ instantiate_class_template (tree type)
if (TREE_CODE (friend_type) == TEMPLATE_DECL)
{
/* template <class T> 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 <class T> 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 <class U> 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<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)
/* Trick make_friend_class into realizing that the friend

View File

@ -1,3 +1,11 @@
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

View File

@ -0,0 +1,16 @@
// { 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 *) {}

View File

@ -0,0 +1,28 @@
// { 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;
}
};

View File

@ -24,8 +24,8 @@ template <class T> class B
static T value_AC;
};
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>::value_AC; // { dg-bogus "" "" { xfail *-*-* } } -
template <typename T> T B<T>::valueA_AC;// { dg-error "" "" } private -
template <typename T> T B<T>::value_AC; // { dg-bogus "" "" } -
// this one is a friend
template <class T> struct A<T>::AA
@ -41,7 +41,7 @@ template <class T> struct A<T>::AC
{
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
{
int M ()
{
return B<int>::value_AC; // { dg-bogus "" "" { xfail *-*-* } } -
return B<int>::value_AC; // { dg-bogus "" "" } -
}
};