PR c++/88752 - ICE with lambda and constexpr if.
authorJason Merrill <jason@redhat.com>
Thu, 31 Jan 2019 15:03:21 +0000 (10:03 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 31 Jan 2019 15:03:21 +0000 (10:03 -0500)
In this testcase, we look for an instantiation of the outer lambda from
within the inner lambda.  enclosing_instantiation_of didn't handle this
properly, as it assumed that any references would be from the same lambda
nesting depth.  Fixed thus.

* cp-tree.h (LAMBDA_EXPR_INSTANTIATED): New.
* pt.c (tsubst_lambda_expr): Set it.
(instantiated_lambda_fn_p): Check it.
(enclosing_instantiation_of): Use it.

From-SVN: r268424

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1z/constexpr-if26.C [new file with mode: 0644]

index 884f09c3b440d14ec81d597955acdeea0c7a6d46..a115317a03cb161c8d6dcbf896310f73108bcbcd 100644 (file)
@@ -1,3 +1,11 @@
+2019-01-30  Jason Merrill  <jason@redhat.com>
+
+       PR c++/88752 - ICE with lambda and constexpr if.
+       * cp-tree.h (LAMBDA_EXPR_INSTANTIATED): New.
+       * pt.c (tsubst_lambda_expr): Set it.
+       (instantiated_lambda_fn_p): Check it.
+       (enclosing_instantiation_of): Use it.
+
 2019-01-31  Jakub Jelinek  <jakub@redhat.com>
 
        PR libstdc++/88170
index 77e1425b4357b7c7ab720c5b233ce381d98dd74a..dada3a6aa4105f4f9c828de0add3ab94252a5a2f 100644 (file)
@@ -453,6 +453,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       DECLTYPE_FOR_REF_CAPTURE (in DECLTYPE_TYPE)
       CONSTRUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR)
       OVL_NESTED_P (in OVERLOAD)
+      LAMBDA_EXPR_INSTANTIATED (in LAMBDA_EXPR)
    4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
       TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
          CALL_EXPR, or FIELD_DECL).
@@ -1334,6 +1335,10 @@ enum cp_lambda_default_capture_mode_type {
 #define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \
   TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE))
 
+/* True iff this LAMBDA_EXPR was generated in tsubst_lambda_expr.  */
+#define LAMBDA_EXPR_INSTANTIATED(NODE) \
+  TREE_LANG_FLAG_3 (LAMBDA_EXPR_CHECK (NODE))
+
 /* True if this TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST is for an explicit
    capture.  */
 #define LAMBDA_CAPTURE_EXPLICIT_P(NODE) \
index f92fa1a181340782cd05c8e767baac8b77f85786..9aa3c75d2d74a5860445c2c6cb7a6aba2cdf5e9d 100644 (file)
@@ -13298,6 +13298,19 @@ lambda_fn_in_template_p (tree fn)
   return CLASSTYPE_TEMPLATE_INFO (closure) != NULL_TREE;
 }
 
+/* True if FN is the substitution (via tsubst_lambda_expr) of a function for
+   which the above is true.  */
+
+bool
+instantiated_lambda_fn_p (tree fn)
+{
+  if (!fn || !LAMBDA_FUNCTION_P (fn))
+    return false;
+  tree closure = DECL_CONTEXT (fn);
+  tree lam = CLASSTYPE_LAMBDA_EXPR (closure);
+  return LAMBDA_EXPR_INSTANTIATED (lam);
+}
+
 /* We're instantiating a variable from template function TCTX.  Return the
    corresponding current enclosing scope.  This gets complicated because lambda
    functions in templates are regenerated rather than instantiated, but generic
@@ -13317,13 +13330,19 @@ enclosing_instantiation_of (tree otctx)
     {
       tree ofn = fn;
       int flambda_count = 0;
-      for (; flambda_count < lambda_count && fn && LAMBDA_FUNCTION_P (fn);
+      for (; fn && instantiated_lambda_fn_p (fn);
           fn = decl_function_context (fn))
        ++flambda_count;
       if ((fn && DECL_TEMPLATE_INFO (fn))
          ? most_general_template (fn) != most_general_template (tctx)
          : fn != tctx)
        continue;
+      if (flambda_count != lambda_count)
+       {
+         gcc_assert (flambda_count > lambda_count);
+         for (; flambda_count > lambda_count; --flambda_count)
+           ofn = decl_function_context (ofn);
+       }
       gcc_assert (DECL_NAME (ofn) == DECL_NAME (otctx)
                  || DECL_CONV_FN_P (ofn));
       return ofn;
@@ -17870,6 +17889,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
     = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
   LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
+  LAMBDA_EXPR_INSTANTIATED (r) = true;
 
   if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE)
     /* A lambda in a default argument outside a class gets no
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if26.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if26.C
new file mode 100644 (file)
index 0000000..e85dcdc
--- /dev/null
@@ -0,0 +1,28 @@
+// PR c++/88752
+// { dg-do compile { target c++17 } }
+
+template <int a> struct b { static constexpr int c = a; };
+class d;
+template <typename> struct e { typedef d f; };
+template <typename g> using h = typename e<g>::f;
+template <typename> constexpr bool i = b<true>::c;
+class d {
+public:
+  using j = float;
+};
+template <typename> void k();
+int main() { k<d>(); }
+template <class l> l m;
+template <class, class r> void n(r o) {
+  [](int) {}(o(m<d>));
+}
+template <typename> void k() {
+  n<int>([](auto inputs) {
+    auto p(inputs);
+    using s = h<decltype(p)>;
+    s q;
+    if constexpr (i<typename s::j>)
+      [&] { return q; }();
+    return 42;
+  });
+}