re PR c++/89785 (Incorrect "not a constant expression" error with switch statement that returns)
PR c++/89785 * constexpr.c (struct check_for_return_continue_data): New type. (check_for_return_continue): New function. (potential_constant_expression_1) <case SWITCH_STMT>: Walk SWITCH_STMT_BODY to find RETURN_EXPRs or CONTINUE_STMTs not nested in loop bodies and set *jump_target to that if found. * g++.dg/cpp1y/constexpr-89785-1.C: New test. * g++.dg/cpp1y/constexpr-89785-2.C: New test. From-SVN: r269995
This commit is contained in:
parent
12b9247b19
commit
c7a53bdbb1
|
@ -1,3 +1,12 @@
|
|||
2019-03-28 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/89785
|
||||
* constexpr.c (struct check_for_return_continue_data): New type.
|
||||
(check_for_return_continue): New function.
|
||||
(potential_constant_expression_1) <case SWITCH_STMT>: Walk
|
||||
SWITCH_STMT_BODY to find RETURN_EXPRs or CONTINUE_STMTs not nested
|
||||
in loop bodies and set *jump_target to that if found.
|
||||
|
||||
2019-03-27 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/89831 - error with qualified-id in const member function.
|
||||
|
|
|
@ -5731,6 +5731,86 @@ check_automatic_or_tls (tree ref)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Data structure for passing data from potential_constant_expression_1
|
||||
to check_for_return_continue via cp_walk_tree. */
|
||||
struct check_for_return_continue_data {
|
||||
hash_set<tree> *pset;
|
||||
tree continue_stmt;
|
||||
};
|
||||
|
||||
/* Helper function for potential_constant_expression_1 SWITCH_STMT handling,
|
||||
called through cp_walk_tree. Return the first RETURN_EXPR found, or note
|
||||
the first CONTINUE_STMT if RETURN_EXPR is not found. */
|
||||
static tree
|
||||
check_for_return_continue (tree *tp, int *walk_subtrees, void *data)
|
||||
{
|
||||
tree t = *tp, s;
|
||||
check_for_return_continue_data *d = (check_for_return_continue_data *) data;
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case RETURN_EXPR:
|
||||
return t;
|
||||
|
||||
case CONTINUE_STMT:
|
||||
if (d->continue_stmt == NULL_TREE)
|
||||
d->continue_stmt = t;
|
||||
break;
|
||||
|
||||
#define RECUR(x) \
|
||||
if (tree r = cp_walk_tree (&x, check_for_return_continue, data, \
|
||||
d->pset)) \
|
||||
return r
|
||||
|
||||
/* For loops, walk subtrees manually, so that continue stmts found
|
||||
inside of the bodies of the loops are ignored. */
|
||||
case DO_STMT:
|
||||
*walk_subtrees = 0;
|
||||
RECUR (DO_COND (t));
|
||||
s = d->continue_stmt;
|
||||
RECUR (DO_BODY (t));
|
||||
d->continue_stmt = s;
|
||||
break;
|
||||
|
||||
case WHILE_STMT:
|
||||
*walk_subtrees = 0;
|
||||
RECUR (WHILE_COND (t));
|
||||
s = d->continue_stmt;
|
||||
RECUR (WHILE_BODY (t));
|
||||
d->continue_stmt = s;
|
||||
break;
|
||||
|
||||
case FOR_STMT:
|
||||
*walk_subtrees = 0;
|
||||
RECUR (FOR_INIT_STMT (t));
|
||||
RECUR (FOR_COND (t));
|
||||
RECUR (FOR_EXPR (t));
|
||||
s = d->continue_stmt;
|
||||
RECUR (FOR_BODY (t));
|
||||
d->continue_stmt = s;
|
||||
break;
|
||||
|
||||
case RANGE_FOR_STMT:
|
||||
*walk_subtrees = 0;
|
||||
RECUR (RANGE_FOR_EXPR (t));
|
||||
s = d->continue_stmt;
|
||||
RECUR (RANGE_FOR_BODY (t));
|
||||
d->continue_stmt = s;
|
||||
break;
|
||||
#undef RECUR
|
||||
|
||||
case STATEMENT_LIST:
|
||||
case CONSTRUCTOR:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!EXPR_P (t))
|
||||
*walk_subtrees = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Return true if T denotes a potentially constant expression. Issue
|
||||
diagnostic as appropriate under control of FLAGS. If WANT_RVAL is true,
|
||||
an lvalue-rvalue conversion is implied. If NOW is true, we want to
|
||||
|
@ -6196,7 +6276,24 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
|
|||
if (!RECUR (SWITCH_STMT_COND (t), rval))
|
||||
return false;
|
||||
/* FIXME we don't check SWITCH_STMT_BODY currently, because even
|
||||
unreachable labels would be checked. */
|
||||
unreachable labels would be checked and it is enough if there is
|
||||
a single switch cond value for which it is a valid constant
|
||||
expression. We need to check if there are any RETURN_EXPRs
|
||||
or CONTINUE_STMTs inside of the body though, as in that case
|
||||
we need to set *jump_target. */
|
||||
else
|
||||
{
|
||||
hash_set<tree> pset;
|
||||
check_for_return_continue_data data = { &pset, NULL_TREE };
|
||||
if (tree ret_expr
|
||||
= cp_walk_tree (&SWITCH_STMT_BODY (t), check_for_return_continue,
|
||||
&data, &pset))
|
||||
/* The switch might return. */
|
||||
*jump_target = ret_expr;
|
||||
else if (data.continue_stmt)
|
||||
/* The switch can't return, but might continue. */
|
||||
*jump_target = data.continue_stmt;
|
||||
}
|
||||
return true;
|
||||
|
||||
case STMT_EXPR:
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2019-03-28 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/89785
|
||||
* g++.dg/cpp1y/constexpr-89785-1.C: New test.
|
||||
* g++.dg/cpp1y/constexpr-89785-2.C: New test.
|
||||
|
||||
2019-03-27 Janus Weil <janus@gcc.gnu.org>
|
||||
|
||||
PR fortran/85537
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// PR c++/89785
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
constexpr int
|
||||
foo (int x)
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
throw -42;
|
||||
case 2:
|
||||
return 42;
|
||||
}
|
||||
throw 42;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
bar (int x)
|
||||
{
|
||||
do
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
throw 42;
|
||||
case 1:
|
||||
continue;
|
||||
}
|
||||
throw -42;
|
||||
}
|
||||
while (0);
|
||||
return x;
|
||||
}
|
||||
|
||||
static_assert (foo (2) == 42, "");
|
||||
static_assert (bar (1) == 1, "");
|
|
@ -0,0 +1,36 @@
|
|||
// PR c++/89785
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
constexpr int
|
||||
foo (int x)
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
}
|
||||
throw 42; // { dg-error "is not a constant expression" }
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
bar (int x)
|
||||
{
|
||||
do
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
throw 42;
|
||||
case 1:
|
||||
for (int i = 0; i < 10; i++)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
throw -42; // { dg-error "is not a constant expression" }
|
||||
}
|
||||
while (0);
|
||||
return x;
|
||||
}
|
Loading…
Reference in New Issue