commit ffb9b449d208ef324c092df35460d9e0b34eacfd
Author: Jason Merrill <jason@redhat.com>
Date: Mon May 23 16:02:45 2011 -0400
PR c++/48884
* class.c (pushclass): Accept NULL argument.
(popclass): Deal with popping null class.
* pt.c (push_access_scope, pop_access_scope): Use them rather than
push_to_top_level/pop_from_top_level.
(push_deduction_access_scope, pop_defarg_context): New.
(fn_type_unification): Use them.
* name-lookup.c (lookup_name_real_1): Check current_class_type.
@@ -6082,6 +6082,9 @@ restore_class_cache (void)
So that we may avoid calls to lookup_name, we cache the _TYPE
nodes of local TYPE_DECLs in the TREE_TYPE field of the name.
+ For use by push_access_scope, we allow TYPE to be null to temporarily
+ push out of class scope. This does not actually change binding levels.
+
For multiple inheritance, we perform a two-pass depth-first search
of the type lattice. */
@@ -6090,8 +6093,6 @@ pushclass (tree type)
{
class_stack_node_t csn;
- type = TYPE_MAIN_VARIANT (type);
-
/* Make sure there is enough room for the new entry on the stack. */
if (current_class_depth + 1 >= current_class_stack_size)
{
@@ -6110,6 +6111,15 @@ pushclass (tree type)
csn->hidden = 0;
current_class_depth++;
+ if (type == NULL_TREE)
+ {
+ current_class_name = current_class_type = NULL_TREE;
+ csn->hidden = true;
+ return;
+ }
+
+ type = TYPE_MAIN_VARIANT (type);
+
/* Now set up the new type. */
current_class_name = TYPE_NAME (type);
if (TREE_CODE (current_class_name) == TYPE_DECL)
@@ -6154,7 +6164,11 @@ invalidate_class_lookup_cache (void)
void
popclass (void)
{
- poplevel_class ();
+ if (current_class_type)
+ poplevel_class ();
+ else
+ gcc_assert (current_class_depth
+ && current_class_stack[current_class_depth - 1].hidden);
current_class_depth--;
current_class_name = current_class_stack[current_class_depth].name;
@@ -4469,7 +4469,7 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p,
/* Conversion operators are handled specially because ordinary
unqualified name lookup will not find template conversion
operators. */
- if (IDENTIFIER_TYPENAME_P (name))
+ if (IDENTIFIER_TYPENAME_P (name) && current_class_type)
{
struct cp_binding_level *level;
@@ -212,7 +212,7 @@ push_access_scope (tree t)
else if (DECL_CLASS_SCOPE_P (t))
push_nested_class (DECL_CONTEXT (t));
else
- push_to_top_level ();
+ pushclass (NULL_TREE);
if (TREE_CODE (t) == FUNCTION_DECL)
{
@@ -237,7 +237,7 @@ pop_access_scope (tree t)
if (DECL_FRIEND_CONTEXT (t) || DECL_CLASS_SCOPE_P (t))
pop_nested_class ();
else
- pop_from_top_level ();
+ popclass ();
}
/* Do any processing required when DECL (a member template
@@ -13820,6 +13820,30 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain)
return ret;
}
+/* We're going to do deduction substitution on the type of TMPL, a function
+ template. In C++11 mode, push into that access scope. In C++03 mode,
+ disable access checking. */
+
+static void
+push_deduction_access_scope (tree tmpl)
+{
+ if (cxx_dialect >= cxx0x)
+ push_access_scope (DECL_TEMPLATE_RESULT (tmpl));
+ else
+ push_deferring_access_checks (dk_no_check);
+}
+
+/* And pop back out. */
+
+static void
+pop_deduction_access_scope (tree tmpl)
+{
+ if (cxx_dialect >= cxx0x)
+ pop_access_scope (DECL_TEMPLATE_RESULT (tmpl));
+ else
+ pop_deferring_access_checks ();
+}
+
/* The FN is a TEMPLATE_DECL for a function. ARGS is an array with
NARGS elements of the arguments that are being used when calling
it. TARGS is a vector into which the deduced template arguments
@@ -13958,7 +13982,9 @@ fn_type_unification (tree fn,
incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
processing_template_decl += incomplete;
+ push_deduction_access_scope (fn);
fntype = deduction_tsubst_fntype (fn, converted_args);
+ pop_deduction_access_scope (fn);
processing_template_decl -= incomplete;
if (fntype == error_mark_node)
@@ -14029,7 +14055,10 @@ fn_type_unification (tree fn,
substitution results in an invalid type, as described above,
type deduction fails. */
{
- tree substed = deduction_tsubst_fntype (fn, targs);
+ tree substed;
+ push_deduction_access_scope (fn);
+ substed = deduction_tsubst_fntype (fn, targs);
+ pop_deduction_access_scope (fn);
if (substed == error_mark_node)
return 1;
new file mode 100644
@@ -0,0 +1,23 @@
+// PR c++/48884
+
+class X
+{
+ static const int I = 42;
+ friend struct Y;
+};
+
+template <int I> struct A { };
+
+struct Y
+{
+ template <typename T>
+ static A<T::I> f(T t)
+ {
+ return A<T::I>();
+ }
+};
+
+int main()
+{
+ Y::f(X());
+}
new file mode 100644
@@ -0,0 +1,15 @@
+template <int I> struct B { };
+
+template <class T>
+B<T::I> f();
+
+class A
+{
+ static const int I = 42;
+ template <class T> friend B<T::I> f();
+};
+
+int main()
+{
+ f<A>();
+}