diff mbox series

[C++] PR c++/88752 - ICE with lambda and constexpr if.

Message ID 20190131150245.9476-1-jason@redhat.com
State New
Headers show
Series [C++] PR c++/88752 - ICE with lambda and constexpr if. | expand

Commit Message

Jason Merrill Jan. 31, 2019, 3:02 p.m. UTC
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.

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

	* 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.
---
 gcc/cp/cp-tree.h                            |  5 ++++
 gcc/cp/pt.c                                 | 22 +++++++++++++++-
 gcc/testsuite/g++.dg/cpp1z/constexpr-if26.C | 28 +++++++++++++++++++++
 gcc/cp/ChangeLog                            |  8 ++++++
 4 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if26.C


base-commit: a657d4f2881460abe1d3e7186c4abfa32da45e0e
diff mbox series

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 77e1425b435..dada3a6aa41 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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) \
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index cb06a570d48..f100f62f9a1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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
index 00000000000..e85dcdc7f77
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if26.C
@@ -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;
+  });
+}
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index af4d9c2635e..507103791e7 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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-29  Jason Merrill  <jason@redhat.com>
 
 	PR c++/86943 - wrong code converting lambda to function pointer.