diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 884f09c3b44..a115317a03c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2019-01-30 Jason Merrill + + 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 PR libstdc++/88170 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 f92fa1a1813..9aa3c75d2d7 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 struct b { static constexpr int c = a; }; +class d; +template struct e { typedef d f; }; +template using h = typename e::f; +template constexpr bool i = b::c; +class d { +public: + using j = float; +}; +template void k(); +int main() { k(); } +template l m; +template void n(r o) { + [](int) {}(o(m)); +} +template void k() { + n([](auto inputs) { + auto p(inputs); + using s = h; + s q; + if constexpr (i) + [&] { return q; }(); + return 42; + }); +}