On Sat, Feb 21, 2026 at 03:31:24PM +0900, Jason Merrill wrote: > On 2/20/26 2:49 AM, Marek Polacek wrote: > > dg.exp=reflect/* passed on x86_64-linux so far. Ok for trunk? > > > > -- >8 -- > > As discussed in > > <https://gcc.gnu.org/pipermail/gcc-patches/2026-January/705756.html>, > > we shouldn't walk BIND_EXPR_VARS in check_out_of_consteval_use_r, but > > BIND_EXPR_BODY should still be walked. > > > > The IF_STMT is there so that we don't emit bogus errors in "if consteval" > > branches, as tested in expr12.C. > > > > gcc/cp/ChangeLog: > > > > * reflect.cc (check_out_of_consteval_use_r): Walk BIND_EXPR_BODY. > > For IF_STMT_CONSTEVAL_P, only walk the ELSE_CLAUSE. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/reflect/expr11.C: Adjust dg-error. > > * g++.dg/reflect/expr12.C: Adjust test. > > --- > > gcc/cp/reflect.cc | 24 ++++++++++++++++++++++-- > > gcc/testsuite/g++.dg/reflect/expr11.C | 2 +- > > gcc/testsuite/g++.dg/reflect/expr12.C | 18 ++++++++++++++++++ > > 3 files changed, 41 insertions(+), 3 deletions(-) > > > > diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc > > index 46355251bcd..0e9118129be 100644 > > --- a/gcc/cp/reflect.cc > > +++ b/gcc/cp/reflect.cc > > @@ -8108,8 +8108,6 @@ check_out_of_consteval_use_r (tree *tp, int > > *walk_subtrees, void *pset) > > /* Don't walk INIT_EXPRs, because we'd emit bogus errors about > > member initializers. */ > > || TREE_CODE (t) == INIT_EXPR > > - /* Don't walk BIND_EXPR_VARS. */ > > - || TREE_CODE (t) == BIND_EXPR > > /* And don't recurse on DECL_EXPRs. */ > > || TREE_CODE (t) == DECL_EXPR) > > { > > @@ -8139,6 +8137,28 @@ check_out_of_consteval_use_r (tree *tp, int > > *walk_subtrees, void *pset) > > return ret; > > } > > + if (TREE_CODE (t) == BIND_EXPR) > > + { > > + if (tree r = cp_walk_tree (&BIND_EXPR_BODY (t), > > + check_out_of_consteval_use_r, pset, > > + static_cast<hash_set<tree> *>(pset))) > > + return r; > > + /* Don't walk BIND_EXPR_VARS. */ > > + *walk_subtrees = false; > > + return NULL_TREE; > > + } > > + > > + if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t)) > > + { > > + if (tree r = cp_walk_tree (&ELSE_CLAUSE (t), > > + check_out_of_consteval_use_r, pset, > > + static_cast<hash_set<tree> *>(pset))) > > + return r; > > + /* Don't walk the consteval branch. */ > > + *walk_subtrees = false; > > + return NULL_TREE; > > + } > > + > > /* Now check the type to see if we are dealing with a consteval-only > > expression. */ > > if (!consteval_only_p (t)) > > diff --git a/gcc/testsuite/g++.dg/reflect/expr11.C > > b/gcc/testsuite/g++.dg/reflect/expr11.C > > index 20af4bc07ae..9691ceb07c7 100644 > > --- a/gcc/testsuite/g++.dg/reflect/expr11.C > > +++ b/gcc/testsuite/g++.dg/reflect/expr11.C > > @@ -15,7 +15,7 @@ f () > > constexpr auto cr = ^^int; > > } > > if constexpr (auto r = ^^int; // { dg-error "consteval-only variable > > .r." } > > - r == ^^int); // { dg-error "the value of .r. is not usable" > > } > > + r == ^^int); // { dg-error "consteval-only expressions|the > > value of .r. is not usable" } > > This change seems wrong, since the condition of an "if constexpr" is > manifestly constant-evaluated.
Ah, of course. So I have to handle even IF_STMT_CONSTEXPR_P specially. Note that this walks even the discarded statement. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? -- >8 -- As discussed in <https://gcc.gnu.org/pipermail/gcc-patches/2026-January/705756.html>, we shouldn't walk BIND_EXPR_VARS in check_out_of_consteval_use_r, but BIND_EXPR_BODY should still be walked. The IF_STMT is there so that we don't emit bogus errors in "if consteval" branches, as tested in expr12.C. gcc/cp/ChangeLog: * reflect.cc (check_out_of_consteval_use_r): Walk BIND_EXPR_BODY. For IF_STMT_CONSTEVAL_P, only walk the ELSE_CLAUSE. For IF_STMT_CONSTEXPR_P, only walk the THEN_ and ELSE_CLAUSE. gcc/testsuite/ChangeLog: * g++.dg/reflect/expr11.C: Test more if constexpr. * g++.dg/reflect/expr12.C: Adjust test. --- gcc/cp/reflect.cc | 42 +++++++++++++++++++++++++-- gcc/testsuite/g++.dg/reflect/expr11.C | 17 +++++++++++ gcc/testsuite/g++.dg/reflect/expr12.C | 18 ++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index 522b7c06a29..2a62ea7217f 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -8112,8 +8112,6 @@ check_out_of_consteval_use_r (tree *tp, int *walk_subtrees, void *pset) /* Don't walk INIT_EXPRs, because we'd emit bogus errors about member initializers. */ || TREE_CODE (t) == INIT_EXPR - /* Don't walk BIND_EXPR_VARS. */ - || TREE_CODE (t) == BIND_EXPR /* And don't recurse on DECL_EXPRs. */ || TREE_CODE (t) == DECL_EXPR) { @@ -8143,6 +8141,46 @@ check_out_of_consteval_use_r (tree *tp, int *walk_subtrees, void *pset) return ret; } + if (TREE_CODE (t) == BIND_EXPR) + { + if (tree r = cp_walk_tree (&BIND_EXPR_BODY (t), + check_out_of_consteval_use_r, pset, + static_cast<hash_set<tree> *>(pset))) + return r; + /* Don't walk BIND_EXPR_VARS. */ + *walk_subtrees = false; + return NULL_TREE; + } + + if (TREE_CODE (t) == IF_STMT) + { + if (IF_STMT_CONSTEVAL_P (t)) + { + if (tree r = cp_walk_tree (&ELSE_CLAUSE (t), + check_out_of_consteval_use_r, pset, + static_cast<hash_set<tree> *>(pset))) + return r; + /* Don't walk the consteval branch. */ + *walk_subtrees = false; + return NULL_TREE; + } + else if (IF_STMT_CONSTEXPR_P (t)) + { + if (tree r = cp_walk_tree (&THEN_CLAUSE (t), + check_out_of_consteval_use_r, pset, + static_cast<hash_set<tree> *>(pset))) + return r; + if (tree r = cp_walk_tree (&ELSE_CLAUSE (t), + check_out_of_consteval_use_r, pset, + static_cast<hash_set<tree> *>(pset))) + return r; + /* Don't walk the condition -- it's a manifestly constant-evaluated + context. */ + *walk_subtrees = false; + return NULL_TREE; + } + } + /* Now check the type to see if we are dealing with a consteval-only expression. */ if (!consteval_only_p (t)) diff --git a/gcc/testsuite/g++.dg/reflect/expr11.C b/gcc/testsuite/g++.dg/reflect/expr11.C index 20af4bc07ae..44d66947d9d 100644 --- a/gcc/testsuite/g++.dg/reflect/expr11.C +++ b/gcc/testsuite/g++.dg/reflect/expr11.C @@ -29,4 +29,21 @@ f () while (^^char != ^^char); do {} while (^^char != ^^char); } + + if constexpr (true) + { + auto r = ^^int; // { dg-error "consteval-only variable .r." } + } + else + { + auto r = ^^int; // { dg-error "consteval-only variable .r." } + } + if constexpr (false) + { + auto r = ^^int; // { dg-error "consteval-only variable .r." } + } + else + { + auto r = ^^int; // { dg-error "consteval-only variable .r." } + } } diff --git a/gcc/testsuite/g++.dg/reflect/expr12.C b/gcc/testsuite/g++.dg/reflect/expr12.C index a59a60f03a3..34aed536429 100644 --- a/gcc/testsuite/g++.dg/reflect/expr12.C +++ b/gcc/testsuite/g++.dg/reflect/expr12.C @@ -20,11 +20,29 @@ f () if not consteval { ^^void; // { dg-error "consteval-only expressions" } + } + if not consteval + { q; // { dg-error "consteval-only expressions" } + } + if not consteval + { auto r = ^^int; // { dg-error "consteval-only variable" } + } + if not consteval + { if (q != ^^char); // { dg-error "consteval-only expressions" } + } + if not consteval + { if (^^char == ^^char); // { dg-error "consteval-only expressions" } + } + if not consteval + { while (^^char != ^^char); // { dg-error "consteval-only expressions" } + } + if not consteval + { do {} while (^^char != ^^char); // { dg-error "consteval-only expressions" } } } base-commit: ad5905160560d1abecfb90e10bcafbf19361649a -- 2.53.0
