Hi,

On 20 Dec 2024, at 20:37, Simon Martin wrote:

> We currently fail due to "infinite recursion" on the following invalid
> code with -std=c++20 and above
>
> === cut here ===
> template <class T> struct S { struct U { const S s; } u; };
> S t{2};
> === cut here ===
>
> The problem is that reshape_init_class for S calls reshape_init_r for
> its field S::u, that calls reshape_init_class for S::U, that calls
> reshape_init_r for field S::U::s that calls reshape_init_class for its
> type S, etc.
>
> This patch fixes the issue by erroring out in reshape_init_class if we
> detect that we're about to call reshape_init_r for a type that's part 
> of
> our "TYPE_CONTEXT chain".
>
> An alternative was to change the check in grokdeclarator that rejects
> fields with an incomplete type to check for the field type's
> TYPE_BEING_DECLARED (which sounds like the right thing to do), however
> erroring for the definition of U::s breaks a bunch of existing test
> cases, and it would also make us diverge from clang and MSVC (but 
> behave
> like EDG) - see https://godbolt.org/z/hT8d1GWa3. It feels to me like 
> we
> don't want that (I'm happy to revisit if people think it's OK).
>
> Successfully tested on x86_64-pc-linux-gnu.
>
>       PR c++/118078
>
> gcc/cp/ChangeLog:
>
>       * decl.cc (reshape_init_class): Don't trigger infinite recursion
>       for invalid "recursive types".
>
> gcc/testsuite/ChangeLog:
>
>       * g++.dg/cpp1z/class-deduction118.C: New test.
>       * g++.dg/cpp2a/class-deduction-aggr16.C: New test.
>
> ---
>  gcc/cp/decl.cc                                | 21 
> ++++++++++++++++---
>  .../g++.dg/cpp1z/class-deduction118.C         |  8 +++++++
>  .../g++.dg/cpp2a/class-deduction-aggr16.C     |  7 +++++++
>  3 files changed, 33 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction118.C
>  create mode 100644 
> gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr16.C
>
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 42e83f880f9..ea55ea4c0e5 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -7315,9 +7315,24 @@ reshape_init_class (tree type, reshape_iter *d, 
> bool first_initializer_p,
>         d->cur++;
>       }
>        else
> -     field_init = reshape_init_r (TREE_TYPE (field), d,
> -                                  /*first_initializer_p=*/NULL_TREE,
> -                                  complain);
> +     {
> +       /* Make sure that we won't be calling ourselves recursively, which
> +          could happen with "recursive template types" (PR c++/118078).  
> */
> +       tree ctx = TYPE_CONTEXT (type);
> +       while (ctx && CLASS_TYPE_P (ctx))
> +         {
> +           if (ctx == TYPE_MAIN_VARIANT (TREE_TYPE (field))) {
Of course this should be same_type_p (cxx, TYPE_MAIN_VARIANT (TREE_TYPE 
(field)))...

I’m running an extra round of testing with this. Ok assuming the 
testing comes back green?

> +               if (complain & tf_error)
> +                 error ("field %qD has incomplete type %qT", field,
> +                        TREE_TYPE (field));
> +               return error_mark_node;
> +           }
> +           ctx = TYPE_CONTEXT (ctx);
> +         }
> +       field_init = reshape_init_r (TREE_TYPE (field), d,
> +                                    /*first_initializer_p=*/NULL_TREE,
> +                                    complain);
> +     }
>
>        if (field_init == error_mark_node)
>       return error_mark_node;
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction118.C 
> b/gcc/testsuite/g++.dg/cpp1z/class-deduction118.C
> new file mode 100644
> index 00000000000..b14d62df793
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction118.C
> @@ -0,0 +1,8 @@
> +// PR c++/118078
> +// { dg-do "compile" { target c++11 } }
> +
> +template <class T>
> +struct S { struct U { const S s; } u; };
> +S t{2};   // { dg-error "invalid use of template-name 'S' without an 
> argument list" "" { target c++14_down } }
> +       // { dg-error "class template argument deduction failed" "" { 
> target c++17 } .-1 }
> +       // { dg-error "no matching function for call to 'S\\\(int\\\)'" "" 
> { target c++17 } .-2 }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr16.C 
> b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr16.C
> new file mode 100644
> index 00000000000..feab11927c1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr16.C
> @@ -0,0 +1,7 @@
> +// PR c++/118078
> +// { dg-do "compile" { target c++20 } }
> +
> +template <class T>
> +struct S { const struct U { struct V { volatile S s; } v; } u; };
> +S t{2};   // { dg-error "class template argument deduction failed" }
> +       // { dg-error "no matching function for call to 'S\\\(int\\\)'" "" 
> { target *-*-* } .-1 }
> -- 
> 2.44.0

Reply via email to