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> 2019-01-31 Jakub Jelinek <jakub@redhat.com>
PR libstdc++/88170 PR libstdc++/88170

View File

@ -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 {
#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) \

View File

@ -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)
{ {
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)
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

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