On Tue, 12 May 2026, Marek Polacek wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16.2?
> 
> -- >8 --
> This bug report shows that we generate a bogus "has incomplete type"
> error for Element::mData in type12.C with -freflection: consteval_only_p
> attempts to complete Array when finishing mData, but mData uses Element
> which is currently being defined, so we can't complete it yet.  We could
> fix this bogus error by checking can_complete_type_without_circularity
> before calling complete_type in consteval_only_p, but I'm no longer so
> sure that we must call complete_type at all.

Yeah, it doesn't make much sense for consteval_only_p to only try to
complete the outermost type but not any nested types it recurses into.

>  This patch removes that
> call.  One consequence of that is that we don't produce the "outside
> a constant-evaluated context" error for C::mData (only when mData is
> defined outside the class as with A::mData above).  This behavior
> matches clang++ though so I'm not too worried about it.
> 
> type13.C shows that even without the complete_type we can still get
> to consteval_only_p_walker::walk with a member with erroneous type
> which currently crashes.
> 
>       PR c++/125280
> 
> gcc/cp/ChangeLog:
> 
>       * reflect.cc (consteval_only_p): Don't complete_type.
>       (consteval_only_p_walker::walk): Return false for
>       error_operand_p.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/reflect/init19.C: New test.
>       * g++.dg/reflect/type12.C: New test.
>       * g++.dg/reflect/type13.C: New test.
> ---
>  gcc/cp/reflect.cc                     | 10 +++-------
>  gcc/testsuite/g++.dg/reflect/init19.C | 12 ++++++++++++
>  gcc/testsuite/g++.dg/reflect/type12.C | 28 +++++++++++++++++++++++++++
>  gcc/testsuite/g++.dg/reflect/type13.C | 13 +++++++++++++
>  4 files changed, 56 insertions(+), 7 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/reflect/init19.C
>  create mode 100644 gcc/testsuite/g++.dg/reflect/type12.C
>  create mode 100644 gcc/testsuite/g++.dg/reflect/type13.C
> 
> diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
> index c30ba1582af..abe919f8b48 100644
> --- a/gcc/cp/reflect.cc
> +++ b/gcc/cp/reflect.cc
> @@ -8623,13 +8623,6 @@ consteval_only_p (tree t)
>    if (dependent_type_p (t))
>      return false;
>  
> -  /* We need the complete type otherwise we'd have no fields for class
> -     templates and thus come up with zilch for things like
> -       template<typename T>
> -       struct X : T { };
> -     which could be consteval-only, depending on T.  */
> -  t = complete_type (t);
> -
>    consteval_only_p_walker walker;
>    return walker.walk (t).is_true ();
>  }
> @@ -8641,6 +8634,9 @@ consteval_only_p (tree t)
>  tristate
>  consteval_only_p_walker::walk (tree t)
>  {
> +  if (error_operand_p (t))
> +    return false;

To me error_operand_p is intended for use on expressions with possibly
erroneous type, rather than on a type directly.  So I have a slight
preference of just checking == error_mark_node if that works.  OK
either way though.

> +
>    t = TYPE_MAIN_VARIANT (t);
>  
>    if (REFLECTION_TYPE_P (t))
> diff --git a/gcc/testsuite/g++.dg/reflect/init19.C 
> b/gcc/testsuite/g++.dg/reflect/init19.C
> new file mode 100644
> index 00000000000..bfebe4cf2d7
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/reflect/init19.C
> @@ -0,0 +1,12 @@
> +// PR c++/125280
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +
> +struct C { decltype(^^::) i; };
> +struct N { int i; };
> +
> +template<typename T>
> +struct X : T { };
> +
> +auto a = X<C>{}; // { dg-error "outside a constant-evaluated context" }
> +auto b = X<N>{};
> diff --git a/gcc/testsuite/g++.dg/reflect/type12.C 
> b/gcc/testsuite/g++.dg/reflect/type12.C
> new file mode 100644
> index 00000000000..c066f27fb69
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/reflect/type12.C
> @@ -0,0 +1,28 @@
> +// PR c++/125280
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +
> +template <class T, int N>
> +struct Array {
> +  T mElements[N];
> +};
> +
> +struct Element {
> +  static const Array<Element, 9> mData;
> +};
> +const Array<Element, 9> Element::mData;
> +
> +struct CE { decltype(^^::) i; };
> +
> +struct A {
> +  static const Array<CE, 10> mData;
> +};
> +const Array<CE, 10> A::mData{}; // { dg-error "outside a constant-evaluated 
> context" }
> +
> +struct B {
> +  static constexpr Array<CE, 11> mData{};
> +};
> +
> +struct C {
> +  static const Array<CE, 12> mData;
> +};
> diff --git a/gcc/testsuite/g++.dg/reflect/type13.C 
> b/gcc/testsuite/g++.dg/reflect/type13.C
> new file mode 100644
> index 00000000000..22d26852ec9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/reflect/type13.C
> @@ -0,0 +1,13 @@
> +// PR c++/125280
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +
> +template <class T, int N>
> +struct Array {
> +  T mElements[N]; // { dg-error "incomplete type" }
> +};
> +
> +struct Element {
> +  static const Array<Element, 10> mData{}; // { dg-error "initialization of 
> static data member" }
> +};
> +const Array<Element, 10> Element::mData;
> 
> base-commit: db3bb1099797354bb3a9ea4fd833380305304db1
> -- 
> 2.54.0
> 
> 

Reply via email to