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.
This commit is contained in:
parent
9854544130
commit
198f4df07d
3 changed files with 99 additions and 4 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
48
gcc/testsuite/g++.dg/parse/defarg18.C
Normal file
48
gcc/testsuite/g++.dg/parse/defarg18.C
Normal file
|
@ -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" }
|
||||
}
|
33
gcc/testsuite/g++.dg/parse/defarg18a.C
Normal file
33
gcc/testsuite/g++.dg/parse/defarg18a.C
Normal file
|
@ -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 ();
|
||||
}
|
Loading…
Add table
Reference in a new issue