]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Reject default arguments for template class friend functions [PR118319]
authorSimon Martin <simon@nasilyan.com>
Wed, 5 Feb 2025 19:35:34 +0000 (20:35 +0100)
committerSimon Martin <simon@nasilyan.com>
Wed, 5 Feb 2025 19:36:23 +0000 (20:36 +0100)
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 sets the default argument to error_mark_node and gives a hard
error for template class friend functions that do not meet the
requirement in C++17 11.3.6/4 (the change is restricted to templates per
discussion with Jason).

PR c++/118319

gcc/cp/ChangeLog:

* decl.cc (grokfndecl): Inspect all friend function parameters.
If it's not valid for them to have a default value and we're
processing a template, set the default value to error_mark_node
and give a hard error.

gcc/testsuite/ChangeLog:

* g++.dg/parse/defarg18.C: New test.
* g++.dg/parse/defarg18a.C: New test.

gcc/cp/decl.cc
gcc/testsuite/g++.dg/parse/defarg18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/defarg18a.C [new file with mode: 0644]

index b7af33b3231771543be8728ac3ce78a95d67d830..4238314558b1aaba1afbe71957dd139800066249 100644 (file)
@@ -11213,14 +11213,28 @@ grokfndecl (tree ctype,
      expression, that declaration shall be a definition..."  */
   if (friendp && !funcdef_flag)
     {
+      bool has_errored = 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;
+           diagnostic_t diag_kind = DK_PERMERROR;
+           /* For templates, mark the default argument as erroneous and give a
+              hard error.  */
+           if (processing_template_decl)
+             {
+               diag_kind = DK_ERROR;
+               TREE_PURPOSE (t) = error_mark_node;
+             }
+           if (!has_errored)
+             {
+               has_errored = true;
+               emit_diagnostic (diag_kind,
+                                DECL_SOURCE_LOCATION (decl),
+                                /*diagnostic_option_id=*/0,
+                                "friend declaration of %qD specifies default "
+                                "arguments and isn%'t a definition", decl);
+             }
          }
     }
 
diff --git a/gcc/testsuite/g++.dg/parse/defarg18.C b/gcc/testsuite/g++.dg/parse/defarg18.C
new file mode 100644 (file)
index 0000000..62c8f15
--- /dev/null
@@ -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|could not convert" }
+};
+
+void baz (int a) {} // { dg-error "only declaration" }
+
+void ola (){
+  NoTemplate t;
+  baz (); // { dg-error "void value not ignored" }
+}
diff --git a/gcc/testsuite/g++.dg/parse/defarg18a.C b/gcc/testsuite/g++.dg/parse/defarg18a.C
new file mode 100644 (file)
index 0000000..9157a4d
--- /dev/null
@@ -0,0 +1,33 @@
+// PR c++/118319 - With -fpermissive
+// { dg-do "compile" { target c++11 } }
+// { dg-additional-options "-fpermissive" }
+
+// Template case, that used to crash.
+// Check that we error-out even with -fpermissive.
+
+template <int>
+struct S { // { dg-error "instantiating erroneous template" }
+  friend void foo1 (int a = []{}());  // { dg-warning "specifies default|only declaration" }
+};
+
+void foo1 (int a) {}
+
+void hello (){
+  S<0> t;
+  foo1 ();
+}
+
+
+// Non template case, that already worked.
+// Check that errors are demoted to warnings.
+
+struct NoTemplate {
+  friend void baz (int a = 1); // { dg-warning "specifies default" }
+};
+
+void baz (int a) {} // { dg-warning "only declaration" }
+
+void ola (){
+  NoTemplate t;
+  baz ();
+}