aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Carlini <paolo.carlini@oracle.com>2018-08-07 16:40:18 +0000
committerPaolo Carlini <paolo@gcc.gnu.org>2018-08-07 16:40:18 +0000
commit6429b8e0f1ecb9fe2993a66623df1936b0886bfa (patch)
tree5c9ad3b129b647e5d47ffff789bad9149febb9d9
parent1d1b732865a2dd3a97b8a8e605d7c5906ab0df0e (diff)
downloadgcc-6429b8e0f1ecb9fe2993a66623df1936b0886bfa.zip
gcc-6429b8e0f1ecb9fe2993a66623df1936b0886bfa.tar.gz
gcc-6429b8e0f1ecb9fe2993a66623df1936b0886bfa.tar.bz2
PR c++/59480, DR 136
/cp 2018-08-07 Paolo Carlini <paolo.carlini@oracle.com> 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 <paolo.carlini@oracle.com> 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
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/decl.c76
-rw-r--r--gcc/testsuite/ChangeLog14
-rw-r--r--gcc/testsuite/g++.dg/other/friend10.C9
-rw-r--r--gcc/testsuite/g++.dg/other/friend11.C8
-rw-r--r--gcc/testsuite/g++.dg/other/friend12.C11
-rw-r--r--gcc/testsuite/g++.dg/other/friend13.C6
-rw-r--r--gcc/testsuite/g++.dg/other/friend14.C14
-rw-r--r--gcc/testsuite/g++.dg/other/friend15.C14
-rw-r--r--gcc/testsuite/g++.dg/other/friend8.C6
-rw-r--r--gcc/testsuite/g++.dg/other/friend9.C9
-rw-r--r--gcc/testsuite/g++.dg/parse/defarg4.C2
-rw-r--r--gcc/testsuite/g++.dg/parse/defarg8.C2
13 files changed, 170 insertions, 8 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 159fc37..0d4377c 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,10 @@
+2018-08-07 Paolo Carlini <paolo.carlini@oracle.com>
+
+ 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 <ville.voutilainen@gmail.com>
PR c++/79133
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index cf216a1..0efb42e 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 868f421..a607ed6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,17 @@
+2018-08-07 Paolo Carlini <paolo.carlini@oracle.com>
+
+ 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 <mliska@suse.cz>
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 0000000..c162395
--- /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<typename> friend int bar(bool = true) { return 1; } // { dg-message "33:previous" }
+};
+
+int foo(bool); // { dg-error "5:friend declaration" }
+template<typename> 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 0000000..b82b39d
--- /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<typename> friend int bar(bool = true) { return 1; } // { dg-message "33:previous" }
+ template<typename> 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 0000000..b78ce4b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/friend12.C
@@ -0,0 +1,11 @@
+// PR c++/59480
+
+template<typename>
+class test {
+ friend int foo(bool = true) { return 1; } // { dg-message "14:previous" }
+ friend int foo(bool); // { dg-error "14:friend declaration" }
+ template<typename> friend int bar(bool = true) { return 1; } // { dg-message "33:previous" }
+ template<typename> friend int bar(bool); // { dg-error "33:friend declaration" }
+};
+
+template class test<bool>;
diff --git a/gcc/testsuite/g++.dg/other/friend13.C b/gcc/testsuite/g++.dg/other/friend13.C
new file mode 100644
index 0000000..6cdb322
--- /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 0000000..0f955a0
--- /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<typename> Matrix rot90_ (const Matrix& a, int k = 1);
+
+class Matrix {
+ friend Matrix rot90 (const Matrix&, int);
+ template<typename> friend Matrix rot90_ (const Matrix&, int);
+};
+
+Matrix rot90 (const Matrix& a, int k) { return Matrix(); }
+template<typename> 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 0000000..7f31811
--- /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<typename> void rot90_ (const Matrix& a, int k = 1) { }
+
+class Matrix {
+ friend void rot90 (const Matrix&, int);
+ template<typename> friend void rot90_ (const Matrix&, int);
+};
+
+void rot90 (const Matrix& a, int k);
+template<typename> 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 0000000..6b5df88
--- /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<typename> 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 0000000..16b4f57
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/friend9.C
@@ -0,0 +1,9 @@
+// PR c++/59480
+
+template<typename>
+class test {
+ friend int foo(bool = true); // { dg-error "14:friend declaration" }
+ template<typename> friend int bar(bool = true); // { dg-error "33:friend declaration" }
+};
+
+template class test<bool>;
diff --git a/gcc/testsuite/g++.dg/parse/defarg4.C b/gcc/testsuite/g++.dg/parse/defarg4.C
index 151f6c5..ad8a1ed 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 <nathan@codesourcery.com>
diff --git a/gcc/testsuite/g++.dg/parse/defarg8.C b/gcc/testsuite/g++.dg/parse/defarg8.C
index 1f1f078..3310006 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);
};