diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index f44acfd62b5..830ede56af8 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7246,6 +7246,7 @@ finish_struct (tree t, tree attributes)
     error ("trying to finish struct, but kicked out due to previous parse errors");
 
   if (processing_template_decl && at_function_scope_p ()
+      && TYPE_CONTEXT (t) == current_function_decl
       /* Lambdas are defined by the LAMBDA_EXPR.  */
       && !LAMBDA_TYPE_P (t))
     add_stmt (build_min (TAG_DEFN, t));
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index d178f15a4da..c25df2fbc0e 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -479,9 +479,31 @@ static GTY(()) tree max_id;
    an array of runtime length.  */
 
 static tree
-vla_capture_type (tree array_type)
+vla_capture_type (tree array_type, tree lambda)
 {
-  tree type = xref_tag (record_type, make_anon_name (), ts_current, false);
+  tree closure = LAMBDA_EXPR_CLOSURE (lambda);
+  tree type = make_class_type (RECORD_TYPE);
+  cp_binding_level *slev = current_binding_level;
+  if (closure)
+    {
+      /* If we're already inside the lambda body, force the capture type out
+	 into the enclosing context, so we don't crash trying to instantiate
+	 the capture field in tsubst_lambda_expr.  We won't have a TAG_DEFN
+	 from finish_struct in the enclosing context, which we work around in
+	 tsubst_lambda_expr.  */
+      TYPE_CONTEXT (type) = TYPE_CONTEXT (closure);
+      cp_binding_level *b = current_binding_level;
+      for (;; b = b->level_chain)
+	if (b->this_entity == closure)
+	  {
+	    while (b->this_entity == closure)
+	      b = b->level_chain;
+	    break;
+	  }
+      current_binding_level = b;
+    }
+  type = pushtag (make_anon_name (), type, ts_current);
+  current_binding_level = slev;
   xref_basetypes (type, NULL_TREE);
   type = begin_class_definition (type);
   if (!ptr_id)
@@ -541,7 +563,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
       initializer = build_constructor_va (init_list_type_node, 2,
 					  NULL_TREE, build_address (elt),
 					  NULL_TREE, array_type_nelts (type));
-      type = vla_capture_type (type);
+      type = vla_capture_type (type, lambda);
     }
   else if (!dependent_type_p (type)
 	   && variably_modified_type_p (type, NULL_TREE))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d678e278078..673ea8e2258 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17989,6 +17989,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       if (PACK_EXPANSION_P (ofield))
 	ofield = PACK_EXPANSION_PATTERN (ofield);
       tree field = tsubst_decl (ofield, args, complain);
+      if (DECL_VLA_CAPTURE_P (ofield))
+	/* The type of a VLA capture might not have a TAG_DEFN in the enclosing
+	   context, so complete it here.  */
+	complete_type (TREE_TYPE (field));
 
       if (DECL_PACK_P (ofield) && !DECL_NORMAL_CAPTURE_P (ofield))
 	{
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index da814bdd655..d1a378acd98 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3469,10 +3469,12 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
 	= decl_function_context (containing_function);
     }
 
-  /* In a lambda within a template, wait until instantiation
-     time to implicitly capture a dependent type.  */
+  /* In a lambda within a template, wait until instantiation time to implicitly
+     capture a parameter pack.  We want to wait because we don't know if we're
+     capturing the whole pack or a single element, and it's OK to wait because
+     find_parameter_packs_r walks into the lambda body.  */
   if (context == containing_function
-      && dependent_type_p (TREE_TYPE (decl)))
+      && DECL_PACK_P (decl))
     return decl;
 
   if (lambda_expr && VAR_P (decl)
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C
new file mode 100644
index 00000000000..a1a6e0b78f6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C
@@ -0,0 +1,22 @@
+// PR c++/86969
+// { dg-do compile { target c++17 } }
+
+auto compose = [](auto... fs) {
+    if constexpr (sizeof...(fs) == 0) {
+        return [](auto x) { return x; };
+    } else {
+        auto fn = [](auto self, auto f, auto... fs) {
+            if constexpr (sizeof...(fs) == 0) return f;
+            else return [=](auto x) { 
+                return f(self(self, fs...)(x));
+            };
+        };
+        return fn(fn, fs...);
+    }
+};
+
+static_assert(compose(
+        [](auto x) { return x * 3; },
+        [](auto x) { return x + 1; },
+        [](auto x) { return x / 2; }
+    )(6) == 12);
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a2d16e15b4a..e4d876b4c0b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+2019-02-27  Jason Merrill  <jason@redhat.com>
+
+	PR c++/86969 - ICE with constexpr if and recursive generic lambdas.
+	* semantics.c (process_outer_var_ref): Do capture dependent vars.
+	* class.c (finish_struct): Only add TAG_DEFN if T is in
+	current_function_decl.
+	* lambda.c (vla_capture_type): Force the capture type out into the
+	lambda's enclosing function.
+	(add_capture): Pass in the lambda.
+	* pt.c (tsubst_lambda_expr): complete_type a VLA capture type.
+
 2019-02-27  Marek Polacek  <polacek@redhat.com>
 
 	PR c++/89511 - ICE with using-declaration and unscoped enumerator.
