Message ID | 20200412134833.2053141-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: Infinite diagnostic loop with decltype([]{}) [PR94521] | expand |
On 4/12/20 9:48 AM, Patrick Palka wrote: > We are hitting a recursive loop when printing the signature of a function > containing a decltype([]{}) type. The loop is > > dump_function_decl -> dump_substitution > -> dump_template_bindings > -> dump_type > -> dump_aggr_type > -> dump_scope -> dump_function_decl > > and we loop because dump_template_bindings wants to print the resolved type of > decltype([]{}) (i.e. just a lambda type), so it calls dump_aggr_type, which > wants to print the function scope of the lambda type. But the function scope of > the lambda type is the function which we're in the middle of printing. > > This patch breaks the loop by passing TFF_NO_FUNCTION_ARGUMENTS to > dump_function_decl from dump_scope, so that we avoid recursing into > dump_substitution and ultimately looping. > > This also means we no longer print a "[with ...]" clause when printing a > function template scope, and we instead just print its template argument list in > a more natural way, e.g. instead of > foo(int, char) [with T=bool]::x > we would now print > foo<bool>::x > which seems like an improvement on its own. Hmm. That no longer distinguishes between multiple template overloads of foo, but I suppose we should always print the full function as part of the same diagnostic, so having a terser form here is OK. > The full signature of the function 'spam' in the below testcase is now > void spam(decltype (<lambda>)*) [with T = int; decltype (<lambda>) = spam<int>::<lambda()>] > > Successfully bootstrapped and regtested on x86_64-pc-linux-gnu, does this look > OK to commit? OK. > gcc/cp/ChangeLog: > > PR c++/94521 > * error.c (dump_scope): Pass TFF_NO_FUNCTION_ARGUMENTS to > dump_function_decl when printing a function template instantiation as a > scope. > > gcc/testsuite/ChangeLog: > > PR c++/94521 > * g++.dg/cpp2a/lambda-uneval12.C: New test. > --- > gcc/cp/error.c | 2 ++ > gcc/testsuite/g++.dg/cpp2a/lambda-uneval12.C | 13 +++++++++++++ > 2 files changed, 15 insertions(+) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-uneval12.C > > diff --git a/gcc/cp/error.c b/gcc/cp/error.c > index 61d1218dc90..98c163db572 100644 > --- a/gcc/cp/error.c > +++ b/gcc/cp/error.c > @@ -211,6 +211,8 @@ dump_scope (cxx_pretty_printer *pp, tree scope, int flags) > } > else if ((flags & TFF_SCOPE) && TREE_CODE (scope) == FUNCTION_DECL) > { > + if (DECL_USE_TEMPLATE (scope)) > + f |= TFF_NO_FUNCTION_ARGUMENTS; > dump_function_decl (pp, scope, f); > pp_cxx_colon_colon (pp); > } > diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval12.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval12.C > new file mode 100644 > index 00000000000..24d2e701e44 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval12.C > @@ -0,0 +1,13 @@ > +// PR c++/94521 > +// { dg-do compile { target c++2a } } > + > +template <typename T> > +void spam(decltype([]{}) *s) > +{ > + static_assert(__is_same(int, decltype(s))); // { dg-error "static assertion failed" } > +} > + > +void foo() > +{ > + spam<int>(nullptr); > +} >
diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 61d1218dc90..98c163db572 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -211,6 +211,8 @@ dump_scope (cxx_pretty_printer *pp, tree scope, int flags) } else if ((flags & TFF_SCOPE) && TREE_CODE (scope) == FUNCTION_DECL) { + if (DECL_USE_TEMPLATE (scope)) + f |= TFF_NO_FUNCTION_ARGUMENTS; dump_function_decl (pp, scope, f); pp_cxx_colon_colon (pp); } diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval12.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval12.C new file mode 100644 index 00000000000..24d2e701e44 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval12.C @@ -0,0 +1,13 @@ +// PR c++/94521 +// { dg-do compile { target c++2a } } + +template <typename T> +void spam(decltype([]{}) *s) +{ + static_assert(__is_same(int, decltype(s))); // { dg-error "static assertion failed" } +} + +void foo() +{ + spam<int>(nullptr); +}