On 10/2/19 7:36 AM, Jakub Jelinek wrote:
Hi!
Thanks for the review, let me start with the unrelated bugfixes then and
deal with the rest later.
On Tue, Oct 01, 2019 at 05:56:00PM -0400, Jason Merrill wrote:
@@ -3905,7 +4033,7 @@ cxx_eval_store_expression (const constex
bool no_zero_init = true;
releasing_vec ctors;
- while (!refs->is_empty())
+ while (!refs->is_empty ())
{
if (*valp == NULL_TREE)
{
@@ -4046,7 +4174,9 @@ cxx_eval_store_expression (const constex
if (const_object_being_modified)
{
bool fail = false;
- if (!CLASS_TYPE_P (TREE_TYPE (const_object_being_modified)))
+ tree const_objtype
+ = strip_array_types (TREE_TYPE (const_object_being_modified));
+ if (!CLASS_TYPE_P (const_objtype))
This looks like an unrelated bugfix; you might commit it (and the others)
separately if that's convenient.
@@ -4907,14 +5043,21 @@ cxx_eval_constant_expression (const cons
break;
case CLEANUP_STMT:
- r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval,
+ {
+ tree initial_jump_target = jump_target ? *jump_target : NULL_TREE;
+ r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (!CLEANUP_EH_ONLY (t) && !*non_constant_p)
+ /* Also evaluate the cleanup. If we weren't skipping at the
+ start of the CLEANUP_BODY, change jump_target temporarily
+ to &initial_jump_target, so that even a return or break or
+ continue in the body doesn't skip the cleanup. */
This also looks like an unrelated bugfix.
Both are only partially related, I think they can go in separately, but at
least for the first one I haven't managed to come up with a testcase where
it would matter and nothing in e.g. check-c++-all comes there with ARRAY_TYPE,
is it ok for trunk without a testcase (first attached patch)?
As for the second bugfix, I think it should be accompanied with the
potential_constant_expression_1 change, and there I've actually managed to
come up with a testcase where it matters, though it is using a GCC extension
(generally, CLEANUP_STMTs won't appear in constexpr functions that often
because of the requirement that variables in them have literal type and
literal types have trivial destructors, so really no cleanups in that case).
The testcase where it makes a difference is:
constexpr void
cleanup (int *x)
{
if (x)
asm ("");
}
constexpr void
cleanup2 (int *x)
{
}
constexpr bool
foo ()
{
int a __attribute__((cleanup (cleanup))) = 1;
return true;
}
constexpr bool
bar ()
{
int a __attribute__((cleanup (cleanup2))) = 1;
return true;
}
constexpr auto x = foo ();
constexpr auto y = bar ();
With vanilla trunk, one gets a weird message:
test.C:27:24: error: ‘constexpr bool foo()’ called in a constant expression
27 | constexpr auto x = foo ();
| ~~~~^~
test.C:28:24: error: ‘constexpr bool bar()’ called in a constant expression
28 | constexpr auto y = bar ();
| ~~~~^~
That is because we call potential_constant_expression_1 on the foo (or
bar) body, see CLEANUP_STMT in there and punt. With just the
potential_constant_expression_1 change to handle CLEANUP_STMT, we actually
accept it, which is wrong.
Finally, with the whole patch attached below, we reject foo () call and
accept bar ():
test.C:27:24: in ‘constexpr’ expansion of ‘foo()’
test.C:27:25: in ‘constexpr’ expansion of ‘cleanup((& a))’
test.C:5:5: error: inline assembly is not a constant expression
5 | asm ("");
| ^~~
test.C:5:5: note: only unevaluated inline assembly is allowed in a ‘constexpr’
function in C++2a
Is the testcase ok in the second patch? Are those patches ok for trunk?
OK, thanks.
Jason