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
PR c++/1016
* cp-tree.h (pushtag): Adjust declaration.
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
/* 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
else
pushdecl_class_level (d);
}
- else
+ else if (b->kind != sk_template_parms)
d = pushdecl_with_scope (d, b);
if (d == error_mark_node)
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)
}
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
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
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
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
PR c++/1016
* g++.dg/lookup/hidden-class1.C: New test.
--- /dev/null
+// { 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 *) {}
--- /dev/null
+// { 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;
+ }
+};
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
{
T M ()
{
- return B<T>::valueA_AC; // { dg-error "" "" { xfail *-*-* } } within this context -
+ return B<T>::valueA_AC; // { dg-error "" "" } within this context -
}
};
{
int M ()
{
- return B<int>::value_AC; // { dg-bogus "" "" { xfail *-*-* } } -
+ return B<int>::value_AC; // { dg-bogus "" "" } -
}
};