aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2018-03-23 18:03:51 -0400
committerJason Merrill <jason@gcc.gnu.org>2018-03-23 18:03:51 -0400
commit86771dcbc33d34860313f5a123ecec172e59453d (patch)
tree4120c8efa3ca8166e60808383eab03b86f9ac498
parent532c7a45847f3401e26fa2f07e52613891c80718 (diff)
downloadgcc-86771dcbc33d34860313f5a123ecec172e59453d.zip
gcc-86771dcbc33d34860313f5a123ecec172e59453d.tar.gz
gcc-86771dcbc33d34860313f5a123ecec172e59453d.tar.bz2
PR c++/78489 - wrong SFINAE behavior.
PR c++/84489 * pt.c (type_unification_real): Don't defer substitution failure. From-SVN: r258824
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/pt.c54
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/fntmpdefarg4a.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/sfinae60.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/sfinae61.C21
5 files changed, 90 insertions, 23 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 52af546..09cc7da 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ef531b6..9cf03f4 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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
index 0000000..023d9af
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg4a.C
@@ -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
index 0000000..cfb4dc0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae60.C
@@ -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
index 0000000..9e71453
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae61.C
@@ -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