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 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);
          //...
        }

but I'm not 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.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/define_aggregate3.C: Adjust expected diagnostic.
        * g++.dg/reflect/p2996-21.C: Likewise.
---
 gcc/cp/reflect.cc                                |  8 ++++++++
 gcc/testsuite/g++.dg/reflect/define_aggregate3.C | 16 ++++++++--------
 gcc/testsuite/g++.dg/reflect/p2996-21.C          |  4 ++--
 3 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index bdeec2f0f38..4845e648fdf 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -5896,6 +5896,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 being defined");
+      *non_constant_p = true;
+      return call;
+    }
   hash_set<tree> nameset;
   for (int i = 0; i < TREE_VEC_LENGTH (rvec); ++i)
     {
diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate3.C 
b/gcc/testsuite/g++.dg/reflect/define_aggregate3.C
index db04a80bbe3..382194ff727 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 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 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 
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 
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 8a9f7895d59..46d235afb01 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 being defined" "" { 
target *-*-* } .-1 }
 };
 
 struct S1;

base-commit: a1adc5aa30caae043cbd45dbbf9a738bebba34cc
-- 
2.52.0

Reply via email to