On Thu, Jan 29, 2026 at 06:44:24PM +0800, Jason Merrill wrote:
> On 1/29/26 4:32 PM, Jakub Jelinek wrote:
> > 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.
>
> Why not?
Done now.
> > > 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.
>
> Please.
Sure.
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);
//...
}
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.
---
gcc/cp/reflect.cc | 26 ++++++++-----------
.../g++.dg/reflect/define_aggregate3.C | 16 ++++++------
gcc/testsuite/g++.dg/reflect/p2996-21.C | 4 +--
3 files changed, 21 insertions(+), 25 deletions(-)
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 78990ce414d..2902f755ab1 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,9 @@ 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))
- cscope = c;
- }
+ if (cscope == NULL_TREE
+ && (TYPE_P (c) || TREE_CODE (c) == FUNCTION_DECL))
+ cscope = c;
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 db04a80bbe3..5951f7cf5b3 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 8a9f7895d59..478be47585e 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;
base-commit: 41f293e72c253301f71fefc5a5e1040cb468e4ed
--
2.52.0