public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH for c++/84489, dependent default template argument
@ 2018-02-27 17:26 Jason Merrill
  2018-03-23 22:14 ` Jason Merrill
  0 siblings, 1 reply; 2+ messages in thread
From: Jason Merrill @ 2018-02-27 17:26 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 431 bytes --]

The logic in type_unification_real for handling template parms that
depend on earlier template parms is a bit complicated.  It already
recognizes when the type of the parm depends on something not
available yet, and it dealt with the case where substituting partial
args left some template parm uses behind, but it didn't handle the
case where substituting partial args just failed.

Tested x86_64-pc-linux-gnu, applying to trunk.

[-- Attachment #2: 84489.diff --]
[-- Type: text/plain, Size: 2074 bytes --]

commit dade5ae09222e696b2aaa05d730e2414b3568bd4
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Feb 26 23:38:10 2018 -0500

            PR c++/84489 - dependent default template argument
    
            * pt.c (type_unification_real): Handle early substitution failure.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 40c897aadc9..2a64fa6d9ad 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -19831,21 +19831,28 @@ type_unification_real (tree tparms,
 	    continue;
 	  tree parm = TREE_VALUE (tparm);
 
-	  if (TREE_CODE (parm) == PARM_DECL
-	      && uses_template_parms (TREE_TYPE (parm))
-	      && saw_undeduced < 2)
-	    continue;
+	  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);
-	  arg = tsubst_template_arg (arg, full_targs, complain, NULL_TREE);
-	  if (!uses_template_parms (arg))
+	  arg = tsubst_template_arg (arg, full_targs, fcomplain, NULL_TREE);
+	  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 < 2)
+	  else if (saw_undeduced == 1)
 	    arg = NULL_TREE;
 	  else
 	    arg = error_mark_node;
diff --git a/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg7.C b/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg7.C
new file mode 100644
index 00000000000..636bf1afd88
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg7.C
@@ -0,0 +1,10 @@
+// PR c++/84489
+// { dg-do compile { target c++11 } }
+
+template <class T = int, T N = T(), bool B = (N >> 1)>
+T f1() {return 0;}
+
+int main()
+{
+  f1(); // Bug here
+}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: C++ PATCH for c++/84489, dependent default template argument
  2018-02-27 17:26 C++ PATCH for c++/84489, dependent default template argument Jason Merrill
@ 2018-03-23 22:14 ` Jason Merrill
  0 siblings, 0 replies; 2+ messages in thread
From: Jason Merrill @ 2018-03-23 22:14 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 992 bytes --]

On Tue, Feb 27, 2018 at 12:26 PM, Jason Merrill <jason@redhat.com> wrote:
> The logic in type_unification_real for handling template parms that
> depend on earlier template parms is a bit complicated.  It already
> recognizes when the type of the parm depends on something not
> available yet, and it dealt with the case where substituting partial
> args left some template parm uses behind, but it didn't handle the
> case where substituting partial args just failed.

And that was still wrong, leading to the regression on the later
testcase in 78489.  When substitution fails, that still needs to cause
deduction to fail immediately.  The important part of the 84489 patch
was setting processing_template_decl so unresolved template parms
don't cause substitution failure.

And to handle the first testcase in 78489, we also need to substitute
into the type of non-type parameters even if we aren't going to use
their default arguments yet.

Tested x86_64-pc-linux-gnu, applying to trunk.

[-- Attachment #2: 78489.diff --]
[-- Type: text/x-patch, Size: 5126 bytes --]

commit 02864b90c69f3af56054a627e834dd66a0aa0c80
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Mar 23 11:15:05 2018 -0400

            PR c++/78489 - wrong SFINAE behavior.
    
            PR c++/84489
            * pt.c (type_unification_real): Don't defer substitution failure.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 5293c2b5491..8af29cef8d3 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -19996,41 +19996,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
+	      && 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 = 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;
-
-	  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;
-	  else
-	    arg = error_mark_node;
 	  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<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 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 <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 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 <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

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-03-23 22:04 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-27 17:26 C++ PATCH for c++/84489, dependent default template argument Jason Merrill
2018-03-23 22:14 ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).