Commit 636ecb78 by Jason Merrill Committed by Jason Merrill

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

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
parent f942ef18
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> 2019-01-31 Jakub Jelinek <jakub@redhat.com>
PR libstdc++/88170 PR libstdc++/88170
......
...@@ -453,6 +453,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; ...@@ -453,6 +453,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
DECLTYPE_FOR_REF_CAPTURE (in DECLTYPE_TYPE) DECLTYPE_FOR_REF_CAPTURE (in DECLTYPE_TYPE)
CONSTRUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR) CONSTRUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR)
OVL_NESTED_P (in OVERLOAD) OVL_NESTED_P (in OVERLOAD)
LAMBDA_EXPR_INSTANTIATED (in LAMBDA_EXPR)
4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
CALL_EXPR, or FIELD_DECL). CALL_EXPR, or FIELD_DECL).
...@@ -1334,6 +1335,10 @@ enum cp_lambda_default_capture_mode_type { ...@@ -1334,6 +1335,10 @@ enum cp_lambda_default_capture_mode_type {
#define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \ #define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \
TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (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 /* True if this TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST is for an explicit
capture. */ capture. */
#define LAMBDA_CAPTURE_EXPLICIT_P(NODE) \ #define LAMBDA_CAPTURE_EXPLICIT_P(NODE) \
......
...@@ -13298,6 +13298,19 @@ lambda_fn_in_template_p (tree fn) ...@@ -13298,6 +13298,19 @@ lambda_fn_in_template_p (tree fn)
return CLASSTYPE_TEMPLATE_INFO (closure) != NULL_TREE; 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 /* We're instantiating a variable from template function TCTX. Return the
corresponding current enclosing scope. This gets complicated because lambda corresponding current enclosing scope. This gets complicated because lambda
functions in templates are regenerated rather than instantiated, but generic functions in templates are regenerated rather than instantiated, but generic
...@@ -13317,13 +13330,19 @@ enclosing_instantiation_of (tree otctx) ...@@ -13317,13 +13330,19 @@ enclosing_instantiation_of (tree otctx)
{ {
tree ofn = fn; tree ofn = fn;
int flambda_count = 0; 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)) fn = decl_function_context (fn))
++flambda_count; ++flambda_count;
if ((fn && DECL_TEMPLATE_INFO (fn)) if ((fn && DECL_TEMPLATE_INFO (fn))
? most_general_template (fn) != most_general_template (tctx) ? most_general_template (fn) != most_general_template (tctx)
: fn != tctx) : fn != tctx)
continue; 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) gcc_assert (DECL_NAME (ofn) == DECL_NAME (otctx)
|| DECL_CONV_FN_P (ofn)); || DECL_CONV_FN_P (ofn));
return ofn; return ofn;
...@@ -17870,6 +17889,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -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 (r)
= LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t); = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t); LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
LAMBDA_EXPR_INSTANTIATED (r) = true;
if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE) if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE)
/* A lambda in a default argument outside a class gets no /* A lambda in a default argument outside a class gets no
......
// 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;
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment