We segfault upon the following invalid code === cut here === template <int> struct S { friend void foo (int a = []{}()); }; void foo (int a) {} int main () { S<0> t; foo (); } === cut here ===
The problem is that we end up with a LAMBDA_EXPR callee in set_flags_from_callee, and dereference its NULL_TREE TREE_TYPE (TREE_TYPE ( )). This patch simply sets the default argument to error_mark_node for friend functions that do not meet the requirement in C++17 11.3.6/4. Successfully tested on x86_64-pc-linux-gnu. PR c++/118319 gcc/cp/ChangeLog: * decl.cc (grokfndecl): Inspect all friend function parameters, and set them to error_mark_node if invalid. gcc/testsuite/ChangeLog: * g++.dg/parse/defarg18.C: New test. --- gcc/cp/decl.cc | 13 +++++--- gcc/testsuite/g++.dg/parse/defarg18.C | 48 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/defarg18.C diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 503ecd9387e..b2761c23d3e 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -11134,14 +11134,19 @@ grokfndecl (tree ctype, expression, that declaration shall be a definition..." */ if (friendp && !funcdef_flag) { + bool has_permerrored = false; for (tree t = FUNCTION_FIRST_USER_PARMTYPE (decl); t && t != void_list_node; t = TREE_CHAIN (t)) if (TREE_PURPOSE (t)) { - permerror (DECL_SOURCE_LOCATION (decl), - "friend declaration of %qD specifies default " - "arguments and isn%'t a definition", decl); - break; + if (!has_permerrored) + { + has_permerrored = true; + permerror (DECL_SOURCE_LOCATION (decl), + "friend declaration of %qD specifies default " + "arguments and isn%'t a definition", decl); + } + TREE_PURPOSE (t) = error_mark_node; } } diff --git a/gcc/testsuite/g++.dg/parse/defarg18.C b/gcc/testsuite/g++.dg/parse/defarg18.C new file mode 100644 index 00000000000..a087d45bf34 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/defarg18.C @@ -0,0 +1,48 @@ +// PR c++/118319 +// { dg-do "compile" { target c++11 } } + +// Template case, that used to crash. + +template <int> +struct S { + friend void foo1 (int a = []{}()); // { dg-error "specifies default|only declaration" } + friend void foo3 (int a, // { dg-error "specifies default|only declaration" } + int b = []{}(), + int c = []{}()); +}; + +void foo1 (int a) {} +void foo3 (int a, int b, int c) {} + +void hello (){ + S<0> t; + foo1 (); + foo3 (1, 2); +} + + +// Template case, that already worked. + +template <int> +struct T { + friend void bar (int a = []{}()); // { dg-error "specifies default|only declaration" } +}; + +void hallo (){ + T<0> t; + bar (); // { dg-error "not declared" } +} + + +// Non template case, that already worked. + +struct NoTemplate { + friend void baz (int a = []{}()); // { dg-error "specifies default" } +}; + +void baz (int a) {} // { dg-error "only declaration" } + +void ola (){ + NoTemplate t; + baz (); +} -- 2.44.0