From: Paolo Carlini Date: Tue, 7 Aug 2018 16:40:18 +0000 (+0000) Subject: PR c++/59480, DR 136 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6429b8e0f1ecb9fe2993a66623df1936b0886bfa;p=gcc.git PR c++/59480, DR 136 /cp 2018-08-07 Paolo Carlini PR c++/59480, DR 136 * decl.c (check_no_redeclaration_friend_default_args): New. (duplicate_decls): Use the latter; also check that a friend declaration specifying default arguments is a definition. /testsuite 2018-08-07 Paolo Carlini PR c++/59480, DR 136 * g++.dg/other/friend8.C: New. * g++.dg/other/friend9.C: Likewise. * g++.dg/other/friend10.C: Likewise. * g++.dg/other/friend11.C: Likewise. * g++.dg/other/friend12.C: Likewise. * g++.dg/other/friend13.C: Likewise. * g++.dg/other/friend14.C: Likewise. * g++.dg/other/friend15.C: Likewise. * g++.dg/parse/defarg4.C: Compile with -fpermissive -w. * g++.dg/parse/defarg8.C: Likewise. From-SVN: r263361 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 159fc37454f..0d4377c2d6a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2018-08-07 Paolo Carlini + + PR c++/59480, DR 136 + * decl.c (check_no_redeclaration_friend_default_args): New. + (duplicate_decls): Use the latter; also check that a friend + declaration specifying default arguments is a definition. + 2018-08-07 Ville Voutilainen PR c++/79133 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index cf216a1a960..0efb42e0f20 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1280,6 +1280,38 @@ check_redeclaration_no_default_args (tree decl) } } +/* NEWDECL is a redeclaration of a function or function template OLDDECL, + in any case represented as FUNCTION_DECLs (the DECL_TEMPLATE_RESULTs of + the TEMPLATE_DECLs in case of function templates). This function is used + to enforce the final part of C++17 11.3.6/4, about a single declaration: + "If a friend declaration specifies a default argument expression, that + declaration shall be a definition and shall be the only declaration of + the function or function template in the translation unit." */ + +static void +check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl, + bool olddecl_hidden_friend_p) +{ + if (!olddecl_hidden_friend_p && !DECL_FRIEND_P (newdecl)) + return; + + tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl); + tree t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl); + + for (; t1 && t1 != void_list_node; + t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) + if ((olddecl_hidden_friend_p && TREE_PURPOSE (t1)) + || (DECL_FRIEND_P (newdecl) && TREE_PURPOSE (t2))) + { + if (permerror (DECL_SOURCE_LOCATION (newdecl), + "friend declaration of %q#D specifies default " + "arguments and isn't the only declaration", newdecl)) + inform (DECL_SOURCE_LOCATION (olddecl), + "previous declaration of %q#D", olddecl); + return; + } +} + /* Merge tree bits that correspond to attributes noreturn, nothrow, const, malloc, and pure from NEWDECL with those of OLDDECL. */ @@ -1318,6 +1350,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) { unsigned olddecl_uid = DECL_UID (olddecl); int olddecl_friend = 0, types_match = 0, hidden_friend = 0; + int olddecl_hidden_friend = 0; int new_defines_function = 0; tree new_template_info; location_t olddecl_loc = DECL_SOURCE_LOCATION (olddecl); @@ -1876,6 +1909,13 @@ next_arg:; olddecl); } } + + /* C++17 11.3.6/4: "If a friend declaration specifies a default + argument expression, that declaration... shall be the only + declaration of the function or function template in the + translation unit." */ + check_no_redeclaration_friend_default_args + (olddecl, newdecl, DECL_HIDDEN_FRIEND_P (olddecl)); } } } @@ -1982,6 +2022,7 @@ next_arg:; if (DECL_DECLARES_FUNCTION_P (olddecl) && DECL_DECLARES_FUNCTION_P (newdecl)) { olddecl_friend = DECL_FRIEND_P (olddecl); + olddecl_hidden_friend = DECL_HIDDEN_FRIEND_P (olddecl); hidden_friend = (DECL_ANTICIPATED (olddecl) && DECL_HIDDEN_FRIEND_P (olddecl) && newdecl_is_friend); @@ -1994,10 +2035,8 @@ next_arg:; if (TREE_CODE (newdecl) == TEMPLATE_DECL) { - tree old_result; - tree new_result; - old_result = DECL_TEMPLATE_RESULT (olddecl); - new_result = DECL_TEMPLATE_RESULT (newdecl); + tree old_result = DECL_TEMPLATE_RESULT (olddecl); + tree new_result = DECL_TEMPLATE_RESULT (newdecl); TREE_TYPE (olddecl) = TREE_TYPE (old_result); DECL_TEMPLATE_SPECIALIZATIONS (olddecl) = chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl), @@ -2008,11 +2047,19 @@ next_arg:; if (DECL_FUNCTION_TEMPLATE_P (newdecl)) { - /* Per C++11 8.3.6/4, default arguments cannot be added in later - declarations of a function template. */ if (DECL_SOURCE_LOCATION (newdecl) != DECL_SOURCE_LOCATION (olddecl)) - check_redeclaration_no_default_args (newdecl); + { + /* Per C++11 8.3.6/4, default arguments cannot be added in + later declarations of a function template. */ + check_redeclaration_no_default_args (newdecl); + /* C++17 11.3.6/4: "If a friend declaration specifies a default + argument expression, that declaration... shall be the only + declaration of the function or function template in the + translation unit." */ + check_no_redeclaration_friend_default_args + (old_result, new_result, olddecl_hidden_friend); + } check_default_args (newdecl); @@ -8780,6 +8827,21 @@ grokfndecl (tree ctype, } } + /* C++17 11.3.6/4: "If a friend declaration specifies a default argument + expression, that declaration shall be a definition..." */ + if (friendp && !funcdef_flag) + { + 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 this decl has namespace scope, set that up. */ if (in_namespace) set_decl_namespace (decl, in_namespace, friendp); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 868f4215ef0..a607ed60e30 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,17 @@ +2018-08-07 Paolo Carlini + + PR c++/59480, DR 136 + * g++.dg/other/friend8.C: New. + * g++.dg/other/friend9.C: Likewise. + * g++.dg/other/friend10.C: Likewise. + * g++.dg/other/friend11.C: Likewise. + * g++.dg/other/friend12.C: Likewise. + * g++.dg/other/friend13.C: Likewise. + * g++.dg/other/friend14.C: Likewise. + * g++.dg/other/friend15.C: Likewise. + * g++.dg/parse/defarg4.C: Compile with -fpermissive -w. + * g++.dg/parse/defarg8.C: Likewise. + 2018-08-07 Martin Liska PR middle-end/83023 diff --git a/gcc/testsuite/g++.dg/other/friend10.C b/gcc/testsuite/g++.dg/other/friend10.C new file mode 100644 index 00000000000..c162395210b --- /dev/null +++ b/gcc/testsuite/g++.dg/other/friend10.C @@ -0,0 +1,9 @@ +// PR c++/59480 + +class test { + friend int foo(bool = true) { return 1; } // { dg-message "14:previous" } + template friend int bar(bool = true) { return 1; } // { dg-message "33:previous" } +}; + +int foo(bool); // { dg-error "5:friend declaration" } +template int bar(bool); // { dg-error "24:friend declaration" } diff --git a/gcc/testsuite/g++.dg/other/friend11.C b/gcc/testsuite/g++.dg/other/friend11.C new file mode 100644 index 00000000000..b82b39ddbe3 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/friend11.C @@ -0,0 +1,8 @@ +// PR c++/59480 + +class test { + friend int foo(bool = true) { return 1; } // { dg-message "14:previous" } + friend int foo(bool); // { dg-error "14:friend declaration" } + template friend int bar(bool = true) { return 1; } // { dg-message "33:previous" } + template friend int bar(bool); // { dg-error "33:friend declaration" } +}; diff --git a/gcc/testsuite/g++.dg/other/friend12.C b/gcc/testsuite/g++.dg/other/friend12.C new file mode 100644 index 00000000000..b78ce4b078c --- /dev/null +++ b/gcc/testsuite/g++.dg/other/friend12.C @@ -0,0 +1,11 @@ +// PR c++/59480 + +template +class test { + friend int foo(bool = true) { return 1; } // { dg-message "14:previous" } + friend int foo(bool); // { dg-error "14:friend declaration" } + template friend int bar(bool = true) { return 1; } // { dg-message "33:previous" } + template friend int bar(bool); // { dg-error "33:friend declaration" } +}; + +template class test; diff --git a/gcc/testsuite/g++.dg/other/friend13.C b/gcc/testsuite/g++.dg/other/friend13.C new file mode 100644 index 00000000000..6cdb322f1df --- /dev/null +++ b/gcc/testsuite/g++.dg/other/friend13.C @@ -0,0 +1,6 @@ +// PR c++/59480 + +void f(int, int, int=0); // { dg-message "6:previous" } +class C { + friend void f(int, int=0, int) {} // { dg-error "15:friend declaration" } +}; diff --git a/gcc/testsuite/g++.dg/other/friend14.C b/gcc/testsuite/g++.dg/other/friend14.C new file mode 100644 index 00000000000..0f955a09b5f --- /dev/null +++ b/gcc/testsuite/g++.dg/other/friend14.C @@ -0,0 +1,14 @@ +// PR c++/59480 + +class Matrix; + +Matrix rot90 (const Matrix& a, int k = 1); +template Matrix rot90_ (const Matrix& a, int k = 1); + +class Matrix { + friend Matrix rot90 (const Matrix&, int); + template friend Matrix rot90_ (const Matrix&, int); +}; + +Matrix rot90 (const Matrix& a, int k) { return Matrix(); } +template Matrix rot90_ (const Matrix& a, int k) { return Matrix(); } diff --git a/gcc/testsuite/g++.dg/other/friend15.C b/gcc/testsuite/g++.dg/other/friend15.C new file mode 100644 index 00000000000..7f3181122e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/friend15.C @@ -0,0 +1,14 @@ +// PR c++/59480 + +class Matrix; + +void rot90 (const Matrix& a, int k = 1) { } +template void rot90_ (const Matrix& a, int k = 1) { } + +class Matrix { + friend void rot90 (const Matrix&, int); + template friend void rot90_ (const Matrix&, int); +}; + +void rot90 (const Matrix& a, int k); +template void rot90_ (const Matrix& a, int k); diff --git a/gcc/testsuite/g++.dg/other/friend8.C b/gcc/testsuite/g++.dg/other/friend8.C new file mode 100644 index 00000000000..6b5df88d6a4 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/friend8.C @@ -0,0 +1,6 @@ +// PR c++/59480 + +class test { + friend int foo(bool = true); // { dg-error "14:friend declaration" } + template friend int bar(bool = true); // { dg-error "33:friend declaration" } +}; diff --git a/gcc/testsuite/g++.dg/other/friend9.C b/gcc/testsuite/g++.dg/other/friend9.C new file mode 100644 index 00000000000..16b4f57335d --- /dev/null +++ b/gcc/testsuite/g++.dg/other/friend9.C @@ -0,0 +1,9 @@ +// PR c++/59480 + +template +class test { + friend int foo(bool = true); // { dg-error "14:friend declaration" } + template friend int bar(bool = true); // { dg-error "33:friend declaration" } +}; + +template class test; diff --git a/gcc/testsuite/g++.dg/parse/defarg4.C b/gcc/testsuite/g++.dg/parse/defarg4.C index 151f6c5f668..ad8a1ed6c65 100644 --- a/gcc/testsuite/g++.dg/parse/defarg4.C +++ b/gcc/testsuite/g++.dg/parse/defarg4.C @@ -1,4 +1,4 @@ -// { dg-do compile } +// { dg-options "-fpermissive -w" } // Copyright (C) 2003 Free Software Foundation, Inc. // Contributed by Nathan Sidwell 3 Jul 2003 diff --git a/gcc/testsuite/g++.dg/parse/defarg8.C b/gcc/testsuite/g++.dg/parse/defarg8.C index 1f1f078aa16..33100069ead 100644 --- a/gcc/testsuite/g++.dg/parse/defarg8.C +++ b/gcc/testsuite/g++.dg/parse/defarg8.C @@ -1,3 +1,5 @@ +// { dg-options "-fpermissive -w" } + struct A { static void g(int); };