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
This commit is contained in:
Jason Merrill 2019-01-31 10:03:21 -05:00 committed by Jason Merrill
parent f942ef18b8
commit 636ecb78a3
4 changed files with 62 additions and 1 deletions

View 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

View 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) \

View 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

View File

@ -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;
});
}