PR c++/59480, DR 136
authorPaolo Carlini <paolo.carlini@oracle.com>
Tue, 7 Aug 2018 16:40:18 +0000 (16:40 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Tue, 7 Aug 2018 16:40:18 +0000 (16:40 +0000)
/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

13 files changed:
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/other/friend10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/friend11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/friend12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/friend13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/friend14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/friend15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/friend8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/friend9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/defarg4.C
gcc/testsuite/g++.dg/parse/defarg8.C

index 159fc37454f4a754a07be56f29586a95564126ff..0d4377c2d6aeb1f4d8054ea33ae16bcaadac26ce 100644 (file)
@@ -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
index cf216a1a960c22a8c5d628f66c6a5a298604668c..0efb42e0f20b008ce4b9ca78265708767f9c8a0e 100644 (file)
@@ -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);
index 868f4215ef0c10f0b0af11a9a1d133240084dd03..a607ed60e30d3283cbaf41d11f961c8e2e73e5e7 100644 (file)
@@ -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 (file)
index 0000000..c162395
--- /dev/null
@@ -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 (file)
index 0000000..b82b39d
--- /dev/null
@@ -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 (file)
index 0000000..b78ce4b
--- /dev/null
@@ -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 (file)
index 0000000..6cdb322
--- /dev/null
@@ -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 (file)
index 0000000..0f955a0
--- /dev/null
@@ -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 (file)
index 0000000..7f31811
--- /dev/null
@@ -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 (file)
index 0000000..6b5df88
--- /dev/null
@@ -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 (file)
index 0000000..16b4f57
--- /dev/null
@@ -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>;
index 151f6c5f668b071d5981d497335782ff89088df5..ad8a1ed6c65c65a5b87f3e06a5dba5eea05f2e95 100644 (file)
@@ -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>
index 1f1f078aa16dbe05286dfda7c13b802b504d5c14..33100069eadf94c30455a714413a81f71b40790c 100644 (file)
@@ -1,3 +1,5 @@
+// { dg-options "-fpermissive -w" }
+
 struct A {
   static void g(int);
 };