https://gcc.gnu.org/g:f28f4ddcfd59015cc926e215dd53ad447f6bc10f
commit r16-7191-gf28f4ddcfd59015cc926e215dd53ad447f6bc10f Author: Marek Polacek <[email protected]> Date: Wed Jan 28 17:05:46 2026 -0500 c++/reflection: check TYPE_BEING_DEFINED in define_aggregate As discussed in <https://gcc.gnu.org/pipermail/gcc-patches/2026-January/705756.html>, we should check TYPE_BEING_DEFINED along with COMPLETE_TYPE_P in eval_define_aggregate. It seems that with this check added, we don't need this code anymore: if (c == type) { auto_diagnostic_group d; error_at (loc, "%<define_aggregate%> evaluated from " "%<consteval%> block enclosed by %qT being " "defined", type); //... } so I'm removing that in this patch. gcc/cp/ChangeLog: * reflect.cc (eval_define_aggregate): Also give an error when TYPE_BEING_DEFINED is true for the first argument. Remove code that did the same. gcc/testsuite/ChangeLog: * g++.dg/reflect/define_aggregate3.C: Adjust expected diagnostic. * g++.dg/reflect/p2996-21.C: Likewise. Reviewed-by: Jakub Jelinek <[email protected]> Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/reflect.cc | 26 +++++++++++------------- gcc/testsuite/g++.dg/reflect/define_aggregate3.C | 16 +++++++-------- gcc/testsuite/g++.dg/reflect/p2996-21.C | 4 ++-- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index 3654f8814fb5..56f36e917e95 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -5897,6 +5897,14 @@ eval_define_aggregate (location_t loc, const constexpr_ctx *ctx, *non_constant_p = true; return call; } + if (TYPE_BEING_DEFINED (type)) + { + if (!cxx_constexpr_quiet_p (ctx)) + error_at (loc, "first %<define_aggregate%> argument is a reflection " + "of a class type %qT being defined", type); + *non_constant_p = true; + return call; + } hash_set<tree> nameset; for (int i = 0; i < TREE_VEC_LENGTH (rvec); ++i) { @@ -5953,21 +5961,11 @@ eval_define_aggregate (location_t loc, const constexpr_ctx *ctx, tree cscope = NULL_TREE, tscope = NULL_TREE; for (tree c = TYPE_CONTEXT (CP_DECL_CONTEXT (consteval_block)); c; c = get_containing_scope (c)) - { - if (c == type) - { - auto_diagnostic_group d; - error_at (loc, "%<define_aggregate%> evaluated from " - "%<consteval%> block enclosed by %qT being " - "defined", type); - inform (DECL_SOURCE_LOCATION (consteval_block), - "%<consteval%> block defined here"); - return get_reflection_raw (loc, orig_type); - } - if (cscope == NULL_TREE - && (TYPE_P (c) || TREE_CODE (c) == FUNCTION_DECL)) + if (TYPE_P (c) || TREE_CODE (c) == FUNCTION_DECL) + { cscope = c; - } + break; + } for (tree c = TYPE_CONTEXT (type); c; c = get_containing_scope (c)) { if (c == consteval_block) diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate3.C b/gcc/testsuite/g++.dg/reflect/define_aggregate3.C index db04a80bbe3b..5951f7cf5b3a 100644 --- a/gcc/testsuite/g++.dg/reflect/define_aggregate3.C +++ b/gcc/testsuite/g++.dg/reflect/define_aggregate3.C @@ -15,8 +15,8 @@ consteval bool foo () { return define_aggregate (^^S2, {}) == ^^S2; } const bool a = foo (); // { dg-error "call to consteval function 'foo\\\(\\\)' is not a constant expression" } struct S3 { - consteval { // { dg-message "'consteval' block defined here" } - define_aggregate (^^S3, {}); // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S3' being defined" } + consteval { + define_aggregate (^^S3, {}); // { dg-error "first 'define_aggregate' argument is a reflection of a class type .S3. being defined" } } }; @@ -33,26 +33,26 @@ consteval { template <typename T> struct S5 { - consteval { // { dg-message "'consteval' block defined here" } - define_aggregate (^^S5 <T>, {}); // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S5<int>' being defined" } + consteval { + define_aggregate (^^S5 <T>, {}); // { dg-error "first 'define_aggregate' argument is a reflection of a class type .S5<int>. being defined" } } }; S5 <int> s5; -consteval bool bar (info x) { return define_aggregate (x, {}) == x; } // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S6' being defined" } +consteval bool bar (info x) { return define_aggregate (x, {}) == x; } // { dg-error "first 'define_aggregate' argument is a reflection of a class type .S6. being defined" } struct S6 { - consteval { // { dg-message "'consteval' block defined here" } + consteval { bar (^^S6); } }; -consteval bool baz (info x) { return define_aggregate (x, {}) == x; } // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S7<char>' being defined" } +consteval bool baz (info x) { return define_aggregate (x, {}) == x; } // { dg-error "first 'define_aggregate' argument is a reflection of a class type .S7<char>. being defined" } template <typename T> struct S7 { - consteval { // { dg-message "'consteval' block defined here" } + consteval { baz (^^S7 <T>); } }; diff --git a/gcc/testsuite/g++.dg/reflect/p2996-21.C b/gcc/testsuite/g++.dg/reflect/p2996-21.C index 8a9f7895d591..478be47585ec 100644 --- a/gcc/testsuite/g++.dg/reflect/p2996-21.C +++ b/gcc/testsuite/g++.dg/reflect/p2996-21.C @@ -7,9 +7,9 @@ using namespace std::meta; struct S0 { - consteval { // { dg-message "'consteval' block defined here" } + consteval { std::meta::define_aggregate(^^S0, {}); // error: scope associated with S0 encloses the consteval block - } // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S0' being defined" "" { target *-*-* } .-1 } + } // { dg-error "first 'define_aggregate' argument is a reflection of a class type .S0. being defined" "" { target *-*-* } .-1 } }; struct S1;
