PR c++/71747 - ICE with self-referential partial spec
authorJason Merrill <jason@redhat.com>
Wed, 27 Jul 2016 14:31:30 +0000 (10:31 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 27 Jul 2016 14:31:30 +0000 (10:31 -0400)
* pt.c (get_partial_spec_bindings): Replace tparms and spec_args
parameters with spec_tmpl.  Call push_tinst_level.
(most_specialized_partial_spec): Adjust.
(more_specialized_partial_spec): Adjust.

From-SVN: r238785

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/initlist-template2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/pr55843.C

index 0e3e826d6aceb888896f4f2dbc44b030e80764e7..99c7c28d0a11e90f0f9d167e66e17d3342633a83 100644 (file)
@@ -1,3 +1,11 @@
+2016-07-27  Jason Merrill  <jason@redhat.com>
+
+       PR c++/71747
+       * pt.c (get_partial_spec_bindings): Replace tparms and spec_args
+       parameters with spec_tmpl.  Call push_tinst_level.
+       (most_specialized_partial_spec): Adjust.
+       (more_specialized_partial_spec): Adjust.
+
 2016-07-25  Jason Merrill  <jason@redhat.com>
 
        PR c++/65970
index 97d50001b146b211b9f287312571eb8f557c3650..a23a05aff35ed591fa168b17940bb119502dee8c 100644 (file)
@@ -140,7 +140,7 @@ static int unify (tree, tree, tree, tree, int, bool);
 static void add_pending_template (tree);
 static tree reopen_tinst_level (struct tinst_level *);
 static tree tsubst_initializer_list (tree, tree);
-static tree get_partial_spec_bindings (tree, tree, tree, tree);
+static tree get_partial_spec_bindings (tree, tree, tree);
 static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
                                   bool, bool);
 static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t,
@@ -20689,8 +20689,6 @@ more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2)
 
   tree tmpl1 = TREE_VALUE (pat1);
   tree tmpl2 = TREE_VALUE (pat2);
-  tree parms1 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl1);
-  tree parms2 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl2);
   tree specargs1 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl1)));
   tree specargs2 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl2)));
 
@@ -20699,14 +20697,14 @@ more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2)
      types in the arguments, and we need our dependency check functions
      to behave correctly.  */
   ++processing_template_decl;
-  targs = get_partial_spec_bindings (tmpl, parms1, specargs1, specargs2);
+  targs = get_partial_spec_bindings (tmpl, tmpl1, specargs2);
   if (targs)
     {
       --winner;
       any_deductions = true;
     }
 
-  targs = get_partial_spec_bindings (tmpl, parms2, specargs2, specargs1);
+  targs = get_partial_spec_bindings (tmpl, tmpl2, specargs1);
   if (targs)
     {
       ++winner;
@@ -20790,23 +20788,23 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
 }
 
 /* Return the innermost template arguments that, when applied to a partial
-   specialization of TMPL whose innermost template parameters are
-   TPARMS, and whose specialization arguments are SPEC_ARGS, yield the
-   ARGS.
+   specialization SPEC_TMPL of TMPL, yield the ARGS.
 
    For example, suppose we have:
 
      template <class T, class U> struct S {};
      template <class T> struct S<T*, int> {};
 
-   Then, suppose we want to get `S<double*, int>'.  The TPARMS will be
-   {T}, the SPEC_ARGS will be {T*, int} and the ARGS will be {double*,
-   int}.  The resulting vector will be {double}, indicating that `T'
-   is bound to `double'.  */
+   Then, suppose we want to get `S<double*, int>'.  SPEC_TMPL will be the
+   partial specialization and the ARGS will be {double*, int}.  The resulting
+   vector will be {double}, indicating that `T' is bound to `double'.  */
 
 static tree
-get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
+get_partial_spec_bindings (tree tmpl, tree spec_tmpl, tree args)
 {
+  tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
+  tree spec_args
+    = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (spec_tmpl)));
   int i, ntparms = TREE_VEC_LENGTH (tparms);
   tree deduced_args;
   tree innermost_deduced_args;
@@ -20832,6 +20830,13 @@ get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
     if (! TREE_VEC_ELT (innermost_deduced_args, i))
       return NULL_TREE;
 
+  tree tinst = build_tree_list (spec_tmpl, deduced_args);
+  if (!push_tinst_level (tinst))
+    {
+      excessive_deduction_depth = true;
+      return NULL_TREE;
+    }
+
   /* Verify that nondeduced template arguments agree with the type
      obtained from argument deduction.
 
@@ -20848,6 +20853,9 @@ get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
   spec_args = coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
                                     spec_args, tmpl,
                                     tf_none, false, false);
+
+  pop_tinst_level ();
+
   if (spec_args == error_mark_node
       /* We only need to check the innermost arguments; the other
         arguments will always agree.  */
@@ -21057,44 +21065,21 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain)
 
   for (t = DECL_TEMPLATE_SPECIALIZATIONS (main_tmpl); t; t = TREE_CHAIN (t))
     {
-      tree partial_spec_args;
       tree spec_args;
       tree spec_tmpl = TREE_VALUE (t);
 
-      partial_spec_args = TREE_PURPOSE (t);
-
-      ++processing_template_decl;
-
       if (outer_args)
        {
-         /* Discard the outer levels of args, and then substitute in the
-            template args from the enclosing class.  */
-         partial_spec_args = INNERMOST_TEMPLATE_ARGS (partial_spec_args);
-         partial_spec_args = tsubst_template_args
-           (partial_spec_args, outer_args, tf_none, NULL_TREE);
-
-         /* And the same for the partial specialization TEMPLATE_DECL.  */
+         /* Substitute in the template args from the enclosing class.  */
+         ++processing_template_decl;
          spec_tmpl = tsubst (spec_tmpl, outer_args, tf_none, NULL_TREE);
+         --processing_template_decl;
        }
 
-      partial_spec_args =
-         coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
-                                partial_spec_args,
-                                tmpl, tf_none,
-                                /*require_all_args=*/true,
-                                /*use_default_args=*/true);
-
-      --processing_template_decl;
-
-      if (partial_spec_args == error_mark_node)
-       return error_mark_node;
       if (spec_tmpl == error_mark_node)
        return error_mark_node;
 
-      tree parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
-      spec_args = get_partial_spec_bindings (tmpl, parms,
-                                     partial_spec_args,
-                                     args);
+      spec_args = get_partial_spec_bindings (tmpl, spec_tmpl, args);
       if (spec_args)
        {
          if (outer_args)
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-template2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-template2.C
new file mode 100644 (file)
index 0000000..40e3075
--- /dev/null
@@ -0,0 +1,23 @@
+// PR c++/71747
+// { dg-do compile { target c++11 } }
+// { dg-options -ftemplate-depth=20 }
+
+template < bool > struct A
+{
+  typedef int type; 
+  constexpr bool operator() () const 
+  { 
+    return true; 
+  }
+}; 
+
+template < bool, typename = int > struct F; 
+template < bool X > 
+// should be: struct F < X, typename A < A < X > {} () >::type > 
+struct F < X, typename A < F < X > {} () >::type > // { dg-error "" }
+{
+};
+
+F < true > f;
+
+// { dg-prune-output "compilation terminated" }
index e1691d5a5b058f9e8961df46fe602ae22711806a..467dd827218ece1c30500e07c4e8cfae1ba0fce5 100644 (file)
@@ -7,11 +7,11 @@ template<bool b> struct if_c {
 };
 template< typename T > struct has_type {
   struct gcc_3_2_wknd {
-    template< typename U > static yes_tag test( type_wrapper<U> const volatile*
+    template< typename U > static yes_tag test( type_wrapper<U> const volatile* // { dg-message "required" }
 , type_wrapper<typename U::type>* = 0 );
   };
   typedef type_wrapper<T> t_;
-  static const bool value = sizeof(gcc_3_2_wknd::test(static_cast<t_*>(0))) ==
+  static const bool value = sizeof(gcc_3_2_wknd::test(static_cast<t_*>(0))) == // { dg-message "required" }
 sizeof(yes_tag);
 };
 template <class K, class T, class=void> struct Get_type {
@@ -19,9 +19,10 @@ template <class K, class T, class=void> struct Get_type {
 struct FT_tag {};
 struct RT_tag {};
 template <class K> struct Get_type<K, RT_tag, typename if_c<
-!has_type<Get_type<K, FT_tag> >::value >::type> { };
+!has_type<Get_type<K, FT_tag> >::value >::type> { }; // { dg-message "required" }
 template <class K> struct Get_type<K, FT_tag, typename if_c<
-!has_type<Get_type<K, RT_tag> >::value >::type> { };  // { dg-error "depth" }
+!has_type<Get_type<K, RT_tag> >::value >::type> { };  // { dg-message "required" }
 typedef Get_type<int, FT_tag>::type P;
 
+// { dg-prune-output "-ftemplate-depth" }
 // { dg-prune-output "compilation terminated" }