On 2/4/25 11:25 AM, Simon Martin wrote:
Hi Jason,

On 4 Feb 2025, at 1:11, Jason Merrill wrote:

On 1/31/25 11:12 AM, Simon Martin wrote:
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.

That's fine, it's common to be stricter in templates.
Ok, cool. The attached updated patch does this, and has been
successfully tested on x86_64-pc-linux-gnu. OK for trunk?

+           if (!has_permerrored)
+             {
+               has_permerrored = true;
+               permerror (DECL_SOURCE_LOCATION (decl),

This still needs to be a hard error in a template; you probably want to use emit_diagnostic to allow the diagnostic category to be different.

+                          "friend declaration of %qD specifies default "
+                          "arguments and isn%'t a definition", decl);
+             }
+           if (processing_template_decl)
+             TREE_PURPOSE (t) = error_mark_node;


Reply via email to