The problem here was that when looking for unexpanded packs, we looked
into IF_STMT_EXTRA_ARGS of a constexpr if, which includes the bindings
for function parameter packs, but not in a way that uses them.  So we
shouldn't look there for unexpanded packs.

Trying to write a smaller testcase revealed another bug, whereby
collecting the bindings for captured variables wasn't respecting
unevaluated context.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit c63bbedf903c28225d9cc273c14d3023e6074fa5
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Jul 13 23:22:26 2018 +1000

            PR c++/86480 - nested variadic lambda and constexpr if.
    
            * pt.c (find_parameter_packs_r) [IF_STMT]: Don't walk into
            IF_STMT_EXTRA_ARGS.
            * tree.c (cp_walk_subtrees) [DECLTYPE_TYPE]: Set
            cp_unevaluated_operand.
            [ALIGNOF_EXPR] [SIZEOF_EXPR] [NOEXCEPT_EXPR]: Likewise.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7e858a19d76..2b885793d3f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3865,6 +3865,17 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
 	return NULL_TREE;
       }
 
+    case IF_STMT:
+      cp_walk_tree (&IF_COND (t), &find_parameter_packs_r,
+		    ppd, ppd->visited);
+      cp_walk_tree (&THEN_CLAUSE (t), &find_parameter_packs_r,
+		    ppd, ppd->visited);
+      cp_walk_tree (&ELSE_CLAUSE (t), &find_parameter_packs_r,
+		    ppd, ppd->visited);
+      /* Don't walk into IF_STMT_EXTRA_ARGS.  */
+      *walk_subtrees = 0;
+      return NULL_TREE;
+
     default:
       return NULL_TREE;
     }
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index b1333f55e39..7e2a77bf67b 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -4865,7 +4865,19 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
       break;
 
     case DECLTYPE_TYPE:
-      WALK_SUBTREE (DECLTYPE_TYPE_EXPR (*tp));
+      ++cp_unevaluated_operand;
+      /* We can't use WALK_SUBTREE here because of the goto.  */
+      result = cp_walk_tree (&DECLTYPE_TYPE_EXPR (*tp), func, data, pset);
+      --cp_unevaluated_operand;
+      *walk_subtrees_p = 0;
+      break;
+
+    case ALIGNOF_EXPR:
+    case SIZEOF_EXPR:
+    case NOEXCEPT_EXPR:
+      ++cp_unevaluated_operand;
+      result = cp_walk_tree (&TREE_OPERAND (*tp, 0), func, data, pset);
+      --cp_unevaluated_operand;
       *walk_subtrees_p = 0;
       break;
  
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if24.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if24.C
new file mode 100644
index 00000000000..cbdb38d95c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if24.C
@@ -0,0 +1,21 @@
+// PR c++/86480
+// { dg-additional-options -std=c++17 }
+
+template <class...> constexpr bool val = true;
+
+template <class... T>
+void f()
+{
+  [](auto... p)
+    {
+      []{
+	if constexpr (val<T..., decltype(p)...>) { return true; }
+	return false;
+      }();
+    }(42);
+}
+
+int main()
+{
+  f<int>();
+}

Reply via email to