diff options
author | Jason Merrill <jason@redhat.com> | 2018-03-23 18:03:51 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2018-03-23 18:03:51 -0400 |
commit | 86771dcbc33d34860313f5a123ecec172e59453d (patch) | |
tree | 4120c8efa3ca8166e60808383eab03b86f9ac498 | |
parent | 532c7a45847f3401e26fa2f07e52613891c80718 (diff) | |
download | gcc-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/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/pt.c | 54 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/fntmpdefarg4a.C | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/sfinae60.C | 25 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/sfinae61.C | 21 |
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 |