diff options
author | Simon Martin <simon@nasilyan.com> | 2025-02-05 20:35:34 +0100 |
---|---|---|
committer | Simon Martin <simon@nasilyan.com> | 2025-02-05 20:36:23 +0100 |
commit | 198f4df07d6a1db9c8ef39536da56c1b596c57a8 (patch) | |
tree | ca75673d6c520a07b9a82261a696fbe3c5850f5b /gcc | |
parent | 98545441308c2ae4d535f14b108ad6551fd927d5 (diff) | |
download | gcc-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.cc | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/parse/defarg18.C | 48 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/parse/defarg18a.C | 33 |
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 (); +} |