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