Hi,

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

> 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.
Ping.

Thanks! Simon
>>
>>      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