PR c++/78489 - wrong SFINAE behavior.
authorJason Merrill <jason@redhat.com>
Fri, 23 Mar 2018 22:03:51 +0000 (18:03 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 23 Mar 2018 22:03:51 +0000 (18:03 -0400)
PR c++/84489
* pt.c (type_unification_real): Don't defer substitution failure.

From-SVN: r258824

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/fntmpdefarg4a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/sfinae60.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/sfinae61.C [new file with mode: 0644]

index 52af546409097d9cd2e1f1a8b190e1239f6c0d9f..09cc7dac812444a907413f628aba8de3903ed3f2 100644 (file)
@@ -1,3 +1,10 @@
+2018-03-23  Jason Merrill  <jason@redhat.com>
+
+       PR c++/78489 - wrong SFINAE behavior.
+
+       PR c++/84489
+       * pt.c (type_unification_real): Don't defer substitution failure.
+
 2018-03-23  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/85015
index ef531b6d795c96f7c3fcd60db642d0287d7170f0..9cf03f45e24e50055912d0807b1b9e1976fbb950 100644 (file)
@@ -19995,41 +19995,49 @@ type_unification_real (tree tparms,
          if (targ || tparm == error_mark_node)
            continue;
          tree parm = TREE_VALUE (tparm);
-
-         tsubst_flags_t fcomplain = complain;
-         if (saw_undeduced == 1)
-           {
-             /* When saw_undeduced == 1, substitution into parm and arg might
-                fail or not replace all template parameters, and that's
-                fine.  */
-             fcomplain = tf_none;
-             if (TREE_CODE (parm) == PARM_DECL
-                 && uses_template_parms (TREE_TYPE (parm)))
-               continue;
-           }
-
          tree arg = TREE_PURPOSE (tparm);
          reopen_deferring_access_checks (*checks);
          location_t save_loc = input_location;
          if (DECL_P (parm))
            input_location = DECL_SOURCE_LOCATION (parm);
-
          if (saw_undeduced == 1)
            ++processing_template_decl;
-         arg = tsubst_template_arg (arg, full_targs, fcomplain, NULL_TREE);
-         if (saw_undeduced == 1)
-           --processing_template_decl;
 
-         if (arg != error_mark_node && !uses_template_parms (arg))
-           arg = convert_template_argument (parm, arg, full_targs, complain,
-                                            i, NULL_TREE);
-         else if (saw_undeduced == 1)
-           arg = NULL_TREE;
+         if (saw_undeduced == 1
+             && TREE_CODE (parm) == PARM_DECL
+             && uses_template_parms (TREE_TYPE (parm)))
+           {
+             /* The type of this non-type parameter depends on undeduced
+                parameters.  Don't try to use its default argument yet,
+                but do check whether the arguments we already have cause
+                substitution failure, so that that happens before we try
+                later default arguments (78489).  */
+             tree type = tsubst (TREE_TYPE (parm), full_targs, complain,
+                                 NULL_TREE);
+             if (type == error_mark_node)
+               arg = error_mark_node;
+             else
+               arg = NULL_TREE;
+           }
          else
-           arg = error_mark_node;
+           {
+             arg = tsubst_template_arg (arg, full_targs, complain, NULL_TREE);
+
+             if (!uses_template_parms (arg))
+               arg = convert_template_argument (parm, arg, full_targs,
+                                                complain, i, NULL_TREE);
+             else if (saw_undeduced == 1)
+               arg = NULL_TREE;
+             else
+               arg = error_mark_node;
+           }
+
+         if (saw_undeduced == 1)
+           --processing_template_decl;
          input_location = save_loc;
          *checks = get_deferred_access_checks ();
          pop_deferring_access_checks ();
+
          if (arg == error_mark_node)
            return 1;
          else if (arg)
diff --git a/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg4a.C b/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg4a.C
new file mode 100644 (file)
index 0000000..023d9af
--- /dev/null
@@ -0,0 +1,6 @@
+// PR c++/55724
+// { dg-do compile { target c++11 } }
+
+template<int N> struct S {};
+template<typename T = int, T N = 42> void f(S<N>) {}
+int main() { S<1> s; f(s); }
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae60.C b/gcc/testsuite/g++.dg/cpp0x/sfinae60.C
new file mode 100644 (file)
index 0000000..cfb4dc0
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/78489
+// { dg-do compile { target c++11 } }
+
+template <bool P, class T = void> struct enable_if { using type = T; };
+template <class T> struct enable_if<false, T> {};
+
+template <class Dummy> struct use_type { using type = int; };
+
+template <bool Pred>
+struct get_type {
+    static_assert(Pred, "");
+    using type = int;
+};
+
+template <bool Val,
+              class      = typename enable_if<Val>::type, // Evaluation/Substitution should end here
+              class ValT = typename get_type<Val>::type,  // This should not be instantiated
+              typename use_type<ValT>::type = 0           // This NTTP causes ValT to be required
+            >
+constexpr bool test(int) { return false; }
+
+template <bool>
+constexpr bool test(long) { return true; }
+
+static_assert(test<false>(0), ""); // should call test(long)
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae61.C b/gcc/testsuite/g++.dg/cpp0x/sfinae61.C
new file mode 100644 (file)
index 0000000..9e71453
--- /dev/null
@@ -0,0 +1,21 @@
+// PR c++/78489
+// { dg-do compile { target c++11 } }
+
+template <bool Pred, class T> struct enable_if { typedef T type; };
+template <class T> struct enable_if<false, T> {};
+
+template <int Idx> struct blows_up { static_assert(Idx != Idx, ""); };
+
+template <int Idx,
+           // substitution should fail here
+          typename enable_if<Idx != Idx, int>::type = 0,
+          // GCC evaluates this statement
+          class = typename blows_up<Idx>::type 
+>
+void Foo() {}
+
+// Check the constructor in as SFINAE context
+template <int I> constexpr auto test(int) -> decltype((Foo<I>(), true)) { return true; }
+template <int>   constexpr bool test(long) { return false; }
+
+static_assert(!test<3>(0), ""); // Blows up