Hi Jason, On 31 Jan 2025, at 16:29, Jason Merrill wrote:
> On 1/31/25 9:52 AM, Simon Martin wrote: >> Hi Jason, >> >> On 9 Jan 2025, at 22:55, Jason Merrill wrote: >> >>> On 1/9/25 8:25 AM, Simon Martin wrote: >>>> 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; >>> >>> If we're going to unconditionally change TREE_PURPOSE, then >>> permerror >>> needs to strengthen to error. But I'd think we could leave the >>> current state in a non-template class, only changing the template >>> case. >> Thanks. It’s true that setting the argument to error_mark_node is >> contradictory with the fact that we accept the code with >> -fpermissive, >> even if only under processing_template_decl, so I checked if >> there’s >> not a better way of approaching this PR. >> >> After a bit of investigation, I think that the real problem is that >> duplicate_decls tries to merge the two declarations, even though they >> don’t meet the constraint about friend functions and default >> arguments. > > I disagree; in this testcase the friend is the (lexically) first > declaration, the problem is that it's a non-defining friend (in a > template) that specifies default args, as addressed by your first > patch. Fair. > I still think my earlier comments are the way forward here: leave the > non-template case alone (permerror, don't change TREE_PURPOSE), in a > template give a hard error and change to error_mark_node. Thanks, understood. The reason I looked for another “solution” is that it felt strange to be permissive in non-templates and stricter in templates. For example, if we do so, we’ll regress the case I added in defarg19.C in -fpermissive (also available at https://godbolt.org/z/YT3dexGjM). I’m probably splitting hair, and I’m happy to go ahead with your suggestion if you think it’s fine. Otherwise I’ll see if I find some better fix. Simon