On 2/25/26 7:00 AM, Marek Polacek wrote:
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?
OK.
-- >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