aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorSimon Martin <simon@nasilyan.com>2025-02-05 20:35:34 +0100
committerSimon Martin <simon@nasilyan.com>2025-02-05 20:36:23 +0100
commit198f4df07d6a1db9c8ef39536da56c1b596c57a8 (patch)
treeca75673d6c520a07b9a82261a696fbe3c5850f5b /gcc
parent98545441308c2ae4d535f14b108ad6551fd927d5 (diff)
downloadgcc-198f4df07d6a1db9c8ef39536da56c1b596c57a8.zip
gcc-198f4df07d6a1db9c8ef39536da56c1b596c57a8.tar.gz
gcc-198f4df07d6a1db9c8ef39536da56c1b596c57a8.tar.bz2
c++: Reject default arguments for template class friend functions [PR118319]
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/decl.cc22
-rw-r--r--gcc/testsuite/g++.dg/parse/defarg18.C48
-rw-r--r--gcc/testsuite/g++.dg/parse/defarg18a.C33
3 files changed, 99 insertions, 4 deletions
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index b7af33b..4238314 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -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
index 0000000..62c8f15
--- /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|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
index 0000000..9157a4d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg18a.C
@@ -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 ();
+}