From 86771dcbc33d34860313f5a123ecec172e59453d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 23 Mar 2018 18:03:51 -0400 Subject: [PATCH] PR c++/78489 - wrong SFINAE behavior. PR c++/84489 * pt.c (type_unification_real): Don't defer substitution failure. From-SVN: r258824 --- gcc/cp/ChangeLog | 7 +++ gcc/cp/pt.c | 54 +++++++++++++--------- gcc/testsuite/g++.dg/cpp0x/fntmpdefarg4a.C | 6 +++ gcc/testsuite/g++.dg/cpp0x/sfinae60.C | 25 ++++++++++ gcc/testsuite/g++.dg/cpp0x/sfinae61.C | 21 +++++++++ 5 files changed, 90 insertions(+), 23 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/fntmpdefarg4a.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/sfinae60.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/sfinae61.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 52af5464090..09cc7dac812 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2018-03-23 Jason Merrill + + PR c++/78489 - wrong SFINAE behavior. + + PR c++/84489 + * pt.c (type_unification_real): Don't defer substitution failure. + 2018-03-23 Jakub Jelinek PR c++/85015 diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ef531b6d795..9cf03f45e24 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 00000000000..023d9afdf70 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg4a.C @@ -0,0 +1,6 @@ +// PR c++/55724 +// { dg-do compile { target c++11 } } + +template struct S {}; +template void f(S) {} +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 00000000000..cfb4dc0b9a7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae60.C @@ -0,0 +1,25 @@ +// PR c++/78489 +// { dg-do compile { target c++11 } } + +template struct enable_if { using type = T; }; +template struct enable_if {}; + +template struct use_type { using type = int; }; + +template +struct get_type { + static_assert(Pred, ""); + using type = int; +}; + +template ::type, // Evaluation/Substitution should end here + class ValT = typename get_type::type, // This should not be instantiated + typename use_type::type = 0 // This NTTP causes ValT to be required + > +constexpr bool test(int) { return false; } + +template +constexpr bool test(long) { return true; } + +static_assert(test(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 00000000000..9e7145305e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae61.C @@ -0,0 +1,21 @@ +// PR c++/78489 +// { dg-do compile { target c++11 } } + +template struct enable_if { typedef T type; }; +template struct enable_if {}; + +template struct blows_up { static_assert(Idx != Idx, ""); }; + +template ::type = 0, + // GCC evaluates this statement + class = typename blows_up::type +> +void Foo() {} + +// Check the constructor in as SFINAE context +template constexpr auto test(int) -> decltype((Foo(), true)) { return true; } +template constexpr bool test(long) { return false; } + +static_assert(!test<3>(0), ""); // Blows up -- 2.30.2