https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124012
--- Comment #7 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Jakub Jelinek <[email protected]>: https://gcc.gnu.org/g:c7c02eeae17ee3440a00ee232e3684ed06c76e30 commit r16-7502-gc7c02eeae17ee3440a00ee232e3684ed06c76e30 Author: Jakub Jelinek <[email protected]> Date: Fri Feb 13 16:11:07 2026 +0100 c++: Fix up consteval-only diagnostics with structured bindings [PR124012] We ICE on the following testcase, because a constexpr structured binding with consteval-only initializer of the whole struct but not for this exact structured binding is used in a context where it is not constant evaluated and folded into a constant. The problem is that check_out_of_consteval_use during walking didn't walk DECL_VALUE_EXPR of vars it sees being used. So we haven't noticed invalid consteval-only use, the consteval-only base of the structured binding isn't gimplified but the structured binding referencing that in its DECL_VALUE_EXPR is and so we ICE during gimplification. In order to fix that, I had to move the lambda into a separate function (similarly to why consteval_only_type_r is not a lambda) so that it can recurse with that. That isn't the only problem though. DECL_VALUE_EXPR in this case is just COMPONENT_REF with the underlying VAR_DECL (which is consteval-only). But walker had: if (VAR_P (t) && (DECL_DECLARED_CONSTEXPR_P (t) || DECL_DECLARED_CONSTINIT_P (t))) /* This is fine, don't bother checking the type. */ return NULL_TREE; and so wouldn't report anything even after the fix. The reason why it works correctly in the constexpr auto a = A {}; foo (a.a); // { dg-error "consteval-only expressions are only allowed in a constant-evaluated context" } case is that in that case (no DECL_VALUE_EXPR) there is COMPONENT_REF of VIEW_CONVERT_EXPR of the VAR_DECL (i.e. location wrapper) and so we diagnose it on the location wrapper. That is just weird, we really shouldn't depend on location wrappers being there for correct behavior (rather than just for better locations). That if is there because cp_finish_decl calls check_out_of_consteval_use on the whole VAR_DECL and in that case we want to avoid diagnosing anything if it is constexpr/constinit var. Maybe we just shouldn't call check_out_of_consteval_use at all, though this patch moves that check to an early out in that function rather than during the walk (similarly to early out for expr == NULL_TREE which also happens occassionally). If we see a constexpr/constinit VAR_DECL which is consteval-only nested somewhere deep inside of other expressions, we should diagnose that. On Wed, Feb 11, 2026 at 08:58:26PM +0900, Jason Merrill wrote: > I'd drop constinit, that doesn't seem to qualify under > [basic.types.general]/12.1. You're right. Seems constinit was still in P2996R9 but P2996R10 has removed it except for one occurrence in the revision history (that is ok, but surprisingly the P2996R10 change that removed it is not mentioned). So, this patch additionally stops special casing constinit for consteval-only checks anywhere, only constexpr is significant. There is an unresolved part of the PR, if there is constexpr auto a = A {}; int b = a.a; then we don't reject that (similarly after the patch with constexpr structured binding). The problem in that case is that we try to constant evaluate initializers of vars (and a few other spots) and if they fold to constants (like in this case to 0) even when it is not manifestly constant-evaluated, we just replace it with the constant and so don't see there was a consteval-only use that should have been reported. Of course, if it is something manifestly constant-evaluated and folds into constant, it shouldn't be rejected. So I wonder if we don't need to call check_out_of_consteval_use in further spots... 2026-02-13 Jakub Jelinek <[email protected]> PR c++/124012 * reflect.cc (check_out_of_consteval_use_r): New function. (check_out_of_consteval_use): Use it instead of lambda. Don't ignore constexpr/constinit vars in the walker and walk DECL_VALUE_EXPR of vars which have it. Ignore expr equal to constexpr VAR_DECL. In diagnostics only complain about missing constexpr on VAR_DECLs without that flag and never suggest constinit. Remove constinit traces from function comment. * g++.dg/reflect/pr124012.C: New test. * g++.dg/reflect/init1.C (r): Change constinit to constexpr. (p): Change constinit to constexpr const. * g++.dg/reflect/init6.C: Expect diagnostics for constinit consteval-only vars. * g++.dg/reflect/init7.C: Likewise. * g++.dg/reflect/init10.C: Likewise. * g++.dg/reflect/diag3.C: Likewise. Don't expect suggestion to add constinit.
