From e9fa2f6ded6a0d7aeb43a0818930d73704626cc7 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 1 Feb 2019 00:30:46 +0000 Subject: [PATCH] PR c++/88983 - ICE with switch in constexpr function. * constexpr.c (cxx_eval_switch_expr): Use SWITCH_COND and SWITCH_BODY. (cxx_eval_constant_expression) : Don't look for the label in the else branch if we found it in the then branch. * g++.dg/cpp1y/constexpr-88983.C: New test. From-SVN: r268438 --- gcc/cp/ChangeLog | 5 ++ gcc/cp/constexpr.c | 19 +++++- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.dg/cpp1y/constexpr-88983.C | 71 ++++++++++++++++++++ 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-88983.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a48b14c2091..2a2aba3ad44 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -6,6 +6,11 @@ * decl.c (reshape_init_r): Don't reshape a digested initializer. Return the initializer for COMPOUND_LITERAL_P. + PR c++/88983 - ICE with switch in constexpr function. + * constexpr.c (cxx_eval_switch_expr): Use SWITCH_COND and SWITCH_BODY. + (cxx_eval_constant_expression) : Don't look for the + label in the else branch if we found it in the then branch. + 2019-01-30 Jason Merrill PR c++/88752 - ICE with lambda and constexpr if. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 19eb44fc0c0..923763faa0a 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4140,13 +4140,13 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { - tree cond = TREE_OPERAND (t, 0); + tree cond = SWITCH_COND (t); cond = cxx_eval_constant_expression (ctx, cond, false, non_constant_p, overflow_p); VERIFY_CONSTANT (cond); *jump_target = cond; - tree body = TREE_OPERAND (t, 1); + tree body = SWITCH_BODY (t); constexpr_ctx new_ctx = *ctx; constexpr_switch_state css = css_default_not_seen; new_ctx.css_state = &css; @@ -4681,6 +4681,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case COND_EXPR: if (jump_target && *jump_target) { + tree orig_jump = *jump_target; /* When jumping to a label, the label might be either in the then or else blocks, so process then block first in skipping mode first, and if we are still in the skipping mode at its end, @@ -4688,7 +4689,19 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), lval, non_constant_p, overflow_p, jump_target); - if (*jump_target) + /* It's possible that we found the label in the then block. But + it could have been followed by another jumping statement, e.g. + say we're looking for case 1: + if (cond) + { + // skipped statements + case 1:; // clears up *jump_target + return 1; // and sets it to a RETURN_EXPR + } + else { ... } + in which case we need not go looking to the else block. + (goto is not allowed in a constexpr function.) */ + if (*jump_target == orig_jump) r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2), lval, non_constant_p, overflow_p, jump_target); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ec3b597339f..989f4c5acec 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-01-31 Marek Polacek + + PR c++/88983 - ICE with switch in constexpr function. + * g++.dg/cpp1y/constexpr-88983.C: New test. + 2019-01-31 Thomas Koenig PR fortran/88669 diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-88983.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-88983.C new file mode 100644 index 00000000000..9d70601d427 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-88983.C @@ -0,0 +1,71 @@ +// PR c++/88983 +// { dg-do compile { target c++14 } } + +constexpr int +fn1 (int ay) +{ + switch (ay) + { + if (1) + { + case 1: + return 1; + } + else + { + default:; + } + } + + return 0; +} + +constexpr int +fn2 (int ay) +{ + switch (ay) + { + if (1) + { + case 1: + break; + } + else + { + default:; + } + } + + return 0; +} + +constexpr int +fn3 (int ay) +{ + int i = 0; + while (i++ < 100) + { + if (i == 1) + return 1; + switch (ay) + { + if (1) + { + case 1: + continue; + } + else + { + default:; + return -1; + } + } + return -1; + } + + return -1; +} + +static_assert (fn1 (1) == 1, ""); +static_assert (fn2 (1) == 0, ""); +static_assert (fn3 (1) == 1, ""); -- 2.30.2