On Wed, Jan 28, 2026 at 05:10:18PM -0500, Marek Polacek wrote:
> 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");

I wonder if this message shouldn't mention the type like the diagnostics
that is obsoleted by this.
While in cases like S3 it is obvious, sometimes the define_aggregate might
be in a consteval call with completely different locus and figuring out
what is the type being defined might be harder.

> +      *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

        Jakub

Reply via email to