On 03/17/2013 04:33 PM, Jason Merrill wrote:
On 03/16/2013 03:38 PM, Jason Merrill wrote:
In SFINAE context, we need to instantiate a class so that we can tell
whether or not is abstract.  Doing this in non-SFINAE context caused
problems, so I've made it conditional.

But it still causes problems, such as PR 56642.  So I've reverted the
complete_type change for now.

This patch fixes 56642 properly; forcing the type to be complete can cause a function decl instantiation to cause its own instantiation again, so we need to deal with that.

Tested x86_64-pc-linux-gnu, applying to trunk.


commit f6585cdd1828608c4052ac06b80c89ce86da120f
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Mar 18 00:25:34 2013 -0400

    	PR c++/17232
    	PR c++/56642
    	* pt.c (tsubst_decl): Check return value of register_specialization.
    	* typeck2.c (abstract_virtuals_error_sfinae): Re-apply complete_type
    	change.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4274479..531d860 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10285,7 +10285,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    DECL_TEMPLATE_INFO (r)
 	      = build_template_info (gen_tmpl, argvec);
 	    SET_DECL_IMPLICIT_INSTANTIATION (r);
-	    register_specialization (r, gen_tmpl, argvec, false, hash);
+
+	    tree new_r
+	      = register_specialization (r, gen_tmpl, argvec, false, hash);
+	    if (new_r != r)
+	      /* We instantiated this while substituting into
+		 the type earlier (template/friend54.C).  */
+	      RETURN (new_r);
 
 	    /* We're not supposed to instantiate default arguments
 	       until they are called, for a template.  But, for a
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 24b5593..3bac67c 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -265,6 +265,10 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
     return 0;
   type = TYPE_MAIN_VARIANT (type);
 
+  /* In SFINAE context, force instantiation.  */
+  if (!(complain & tf_error))
+    complete_type (type);
+
   /* If the type is incomplete, we register it within a hash table,
      so that we can check again once it is completed. This makes sense
      only for objects for which we have a declaration or at least a
diff --git a/gcc/testsuite/g++.dg/template/abstract-dr337.C b/gcc/testsuite/g++.dg/template/abstract-dr337.C
index 4f66c1c..6905262 100644
--- a/gcc/testsuite/g++.dg/template/abstract-dr337.C
+++ b/gcc/testsuite/g++.dg/template/abstract-dr337.C
@@ -6,8 +6,8 @@ class A {
 };
 
 template<typename T>
-void g(T (*a)[1]) {}		// { dg-error "abstract" "" { xfail *-*-* } }
+void g(T (*a)[1]) {}		// { dg-error "abstract" "" }
 
 int main() {
-  g<A<int> >(0);  // { dg-error "no matching function" "" { xfail *-*-* } }
+  g<A<int> >(0);  // { dg-error "no matching function" }
 }
diff --git a/gcc/testsuite/g++.dg/template/friend54.C b/gcc/testsuite/g++.dg/template/friend54.C
new file mode 100644
index 0000000..ead7a72
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend54.C
@@ -0,0 +1,18 @@
+// PR c++/56642
+
+template <class T> struct A;
+
+template <class T>
+A<T> f(T*) { return A<T>(); }
+
+template <class T>
+struct A
+{
+  friend A f<T>(T*);
+};
+
+int main()
+{
+  int *p = 0;
+  f(p);
+}

Reply via email to