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? Jakub
2019-10-02 Jakub Jelinek <ja...@redhat.com> * constexpr.c (cxx_eval_store_expression): Formatting fix. Handle const_object_being_modified with array type. --- gcc/cp/constexpr.c.jj 2019-09-27 20:33:37.600208356 +0200 +++ gcc/cp/constexpr.c 2019-09-27 20:38:38.203710246 +0200 @@ -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)) fail = true; else {
2019-10-02 Jakub Jelinek <ja...@redhat.com> * constexpr.c (cxx_eval_constant_expression) <case CLEANUP_STMT>: If not skipping upon entry to body, run cleanup with the same *jump_target as it started to run the cleanup even if the body returns, breaks or continues. (potential_constant_expression_1): Allow CLEANUP_STMT. * g++.dg/ext/constexpr-attr-cleanup1.C: New test. --- gcc/cp/constexpr.c.jj 2019-10-02 13:15:21.822352849 +0200 +++ gcc/cp/constexpr.c 2019-10-02 13:15:53.527879667 +0200 @@ -4907,14 +4907,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. */ + cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, non_constant_p, overflow_p, - jump_target); - if (!CLEANUP_EH_ONLY (t) && !*non_constant_p) - /* Also evaluate the cleanup. */ - cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, - non_constant_p, overflow_p, - jump_target); + jump_target ? &initial_jump_target + : NULL); + } break; /* These differ from cxx_eval_unary_expression in that this doesn't @@ -6983,6 +6990,12 @@ potential_constant_expression_1 (tree t, return true; case CLEANUP_STMT: + if (!RECUR (CLEANUP_BODY (t), any)) + return false; + if (!CLEANUP_EH_ONLY (t) && !RECUR (CLEANUP_EXPR (t), any)) + return false; + return true; + case EMPTY_CLASS_EXPR: case PREDICT_EXPR: return false; --- gcc/testsuite/g++.dg/ext/constexpr-attr-cleanup1.C.jj 2019-10-02 13:32:11.973282291 +0200 +++ gcc/testsuite/g++.dg/ext/constexpr-attr-cleanup1.C 2019-10-02 13:32:56.192624120 +0200 @@ -0,0 +1,30 @@ +// { dg-do compile { target c++2a } } + +constexpr void +cleanup (int *x) +{ + if (x) + asm (""); // { dg-error "inline assembly is not a constant expression" } +} // { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 } + +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 (); // { dg-message "in 'constexpr' expansion of" } +constexpr auto y = bar ();