]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/59480 (Missing error diagnostic: friend declaration specifying a default...
authorPaolo Carlini <paolo.carlini@oracle.com>
Wed, 18 Jul 2018 10:27:12 +0000 (10:27 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Wed, 18 Jul 2018 10:27:12 +0000 (10:27 +0000)
/cp
2018-07-18  Paolo Carlini  <paolo.carlini@oracle.com>

* class.c (note_name_declared_in_class): Prefer permerror + inform
to a pair of permerrors; use DECL_SOURCE_LOCATION.

/testsuite
2018-07-18  Paolo Carlini  <paolo.carlini@oracle.com>

* g++.dg/ext/uow-3.C: Adjust.
* g++.dg/ext/uow-4.C: Likewise.
* g++.dg/lookup/name-clash11.C: Likewise.
* g++.dg/lookup/name-clash7.C: Likewise.
* g++.dg/lookup/redecl1.C: Likewise.
* g++.dg/warn/changes-meaning.C: Likewise.
* g++.old-deja/g++.jason/scoping8.C: Likewise.
* g++.old-deja/g++.law/nest1.C: Likewise.

/cp
2019-07-18  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
2019-07-18  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/parse/defarg4.C: Compile with -fpermissive -w.
* g++.dg/parse/defarg8.C: Likewise.

From-SVN: r262851

19 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/uow-3.C
gcc/testsuite/g++.dg/ext/uow-4.C
gcc/testsuite/g++.dg/lookup/name-clash11.C
gcc/testsuite/g++.dg/lookup/name-clash7.C
gcc/testsuite/g++.dg/lookup/redecl1.C
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/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
gcc/testsuite/g++.dg/warn/changes-meaning.C
gcc/testsuite/g++.old-deja/g++.jason/scoping8.C
gcc/testsuite/g++.old-deja/g++.law/nest1.C

index 7161565280a6abbaa0b68bace5568143205d93e8..e9574f3e9035b22fe3aad32bbb76b8a229fc1549 100644 (file)
@@ -1,3 +1,15 @@
+2019-07-18  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-07-18  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       * class.c (note_name_declared_in_class): Prefer permerror + inform
+       to a pair of permerrors; use DECL_SOURCE_LOCATION.
+
 2018-07-18  Richard Biener  <rguenther@suse.de>
 
        PR debug/86523
index 3d155a55500f6e1cd046b5e4d1460cd6bf638c1f..4300c5cacf39025a4e090c0c974eeda3bb51eb37 100644 (file)
@@ -8285,10 +8285,12 @@ note_name_declared_in_class (tree name, tree decl)
         A name N used in a class S shall refer to the same declaration
         in its context and when re-evaluated in the completed scope of
         S.  */
-      permerror (input_location, "declaration of %q#D", decl);
-      permerror (location_of ((tree) n->value),
-                "changes meaning of %qD from %q#D",
-                OVL_NAME (decl), (tree) n->value);
+      if (permerror (DECL_SOURCE_LOCATION (decl),
+                    "declaration of %q#D changes meaning of %qD",
+                    decl, OVL_NAME (decl)))
+       inform (location_of ((tree) n->value),
+               "%qD declared here as %q#D",
+               OVL_NAME (decl), (tree) n->value);
     }
 }
 
index 3c1e2ef36984129e2fa2d561908bbe3113f7d6e5..5239ffd5a076d30210e3a25373ca3c10bad47da3 100644 (file)
@@ -1280,6 +1280,39 @@ check_redeclaration_no_default_args (tree decl)
       }
 }
 
+/* NEWDECL is a redeclaration of a function or function template OLDDECL.
+   If either the declaration or the redeclaration is a friend declaration
+   and specifies default arguments issue a diagnostic.   Note: this is to
+   enforce 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."  */
+
+static void
+check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl)
+{
+  bool olddecl_friend_p = DECL_FRIEND_P (STRIP_TEMPLATE (olddecl));
+  bool newdecl_friend_p = DECL_FRIEND_P (STRIP_TEMPLATE (newdecl));
+
+  if (!olddecl_friend_p && !newdecl_friend_p)
+    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_friend_p && TREE_PURPOSE (t1))
+       || (newdecl_friend_p && 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.  */
 
@@ -1876,6 +1909,12 @@ 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);
            }
        }
     }
@@ -2008,11 +2047,18 @@ 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 (olddecl, newdecl);
+           }
 
          check_default_args (newdecl);
 
@@ -8763,6 +8809,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 7fc2a42fbcef33a59bcaf8af0ffd30c620d85aa0..b9b89224fc24af511e32b6eb9e8aef9ce057779a 100644 (file)
@@ -1,3 +1,25 @@
+2019-07-18  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/parse/defarg4.C: Compile with -fpermissive -w.
+       * g++.dg/parse/defarg8.C: Likewise.
+
+2018-07-18  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       * g++.dg/ext/uow-3.C: Adjust.
+       * g++.dg/ext/uow-4.C: Likewise.
+       * g++.dg/lookup/name-clash11.C: Likewise.
+       * g++.dg/lookup/name-clash7.C: Likewise.
+       * g++.dg/lookup/redecl1.C: Likewise.
+       * g++.dg/warn/changes-meaning.C: Likewise.
+       * g++.old-deja/g++.jason/scoping8.C: Likewise.
+       * g++.old-deja/g++.law/nest1.C: Likewise.
+
 2018-07-18  Richard Biener  <rguenther@suse.de>
 
        PR debug/86523
index a2c2240214bf0414e39c29ea56ff755f8e3e9de5..9378c62564a9e1f98cd77b6f677feeec2d04c541 100644 (file)
@@ -1,8 +1,8 @@
 /* { dg-do compile } */
 /* { dg-options "-Wall" } */
 
-typedef int UOW;  /* { dg-error "" } */
+typedef int UOW;  /* { dg-message "declared here" } */
 struct ABC {
-  UOW UOW; /* { dg-error "" } */
+  UOW UOW; /* { dg-error "changes meaning" } */
 };
 
index 21ed04a88ea578a2b9008d0309a78a11855a6063..73a3a6fa11c61f6372f56cca7e9675688f2f727e 100644 (file)
@@ -3,9 +3,9 @@
 
 extern "C" {
 
-typedef int UOW;  /* { dg-error "" } */
+typedef int UOW;  /* { dg-message "declared here" } */
 struct ABC {
-  UOW UOW; /* { dg-error "" } */
+  UOW UOW; /* { dg-error "changes meaning" } */
 };
 
 }
index 28ce4c937c5365ec2e2b996a151948c5e7755ee0..bc63645e8d3948b77c1b89e461ac90bb66281873 100644 (file)
 
 void test_bitset ()
 {
-  int x;                        // { dg-warning "changes meaning" }
+  int x;                        // { dg-message "declared here" }
 
   {
     struct S {
-      int x: sizeof x;          // { dg-warning "declaration" }
+      int x: sizeof x;          // { dg-warning "changes meaning" }
     };
   }
 }
@@ -25,11 +25,11 @@ void test_bitset ()
 void test_enum ()
 {
   // Also exercise (not covered by c++/69023):
-  int y;                        // { dg-warning "changes meaning" }
+  int y;                        // { dg-message "declared here" }
   {
     struct S {
       enum E {
-        y = sizeof y            // { dg-warning "declaration" }
+        y = sizeof y            // { dg-warning "9:declaration of .y. changes meaning" }
       };
 
       // Verify the enumerator has the correct value.
@@ -40,7 +40,7 @@ void test_enum ()
 
 void test_alignas ()
 {
-  enum { A = 16 };              // { dg-warning "changes meaning" }
+  enum { A = 16 };              // { dg-message "declared here" }
   {
     struct S {
 #if __cplusplus >= 201103L
@@ -48,7 +48,7 @@ void test_alignas ()
 #else
       __attribute__ ((aligned (A)))
 #endif
-      int A;                    // { dg-warning "declaration" }
+      int A;                    // { dg-warning "changes meaning" }
 
       // Verify the member has the correct alignment.
       void test () { ASSERT (__alignof__ (this->A) == 16); }
@@ -58,10 +58,10 @@ void test_alignas ()
 
 void test_array ()
 {
-  enum { A = 16 };              // { dg-warning "changes meaning" }
+  enum { A = 16 };              // { dg-message "declared here" }
   {
     struct S {
-      int A [A];                // { dg-warning "declaration" }
+      int A [A];                // { dg-warning "changes meaning" }
 
       // Verify the member has the correct alignment.
       void test () { ASSERT (sizeof (this->A) == 16 * sizeof (int)); }
@@ -71,10 +71,10 @@ void test_array ()
 
 void test_vector ()
 {
-  enum { A = 16 };              // { dg-warning "changes meaning" }
+  enum { A = 16 };              // { dg-message "declared here" }
   {
     struct S {
-      int A __attribute__ ((vector_size (A))); // { dg-warning "declaration" }
+      int A __attribute__ ((vector_size (A))); // { dg-warning "changes meaning" }
 
       // Verify the member has the correct size.
       void test () { ASSERT (sizeof (this->A) == 16); }
index 5c0690aa8505bb4946051fd669d4a4874d0d9511..cc27181744d96ac85331401246e22965a5f3e9ac 100644 (file)
@@ -1,11 +1,11 @@
 // PR c++/28513
 
-class foo {                    // { dg-error "changes meaning" }
+class foo {                    // { dg-message "declared here" }
 public:
   typedef int bar;
 };
 
 class baz {
 public:
-  foo::bar foo;                        // { dg-error "declaration" }
+  foo::bar foo;                        // { dg-error "changes meaning" }
 };
index 436316ca07011427a9f4b286b6c25e3bec13b7fa..b105be25e759a32379397f553baacfae8fb7c478 100644 (file)
@@ -1,7 +1,7 @@
 // PR c++/14668
 
-class A {}; // { dg-error "" }
+class A {}; // { dg-message "declared here" }
 class B { 
-  static A *A; // { dg-error "" }
+  static A *A; // { dg-error "changes meaning" }
 }; 
 A *B::A = 0;
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/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);
 };
index fdbddf820914d0a892d5285cb1a8acc946e8ceef..0b9fc4cbe8ed41521cb3e0861652a28351ae7334 100644 (file)
@@ -1,11 +1,11 @@
 /* { dg-do compile } */
 /* { dg-options "-fpermissive" } */
 
-template <class _Tp> class auto_ptr {};  /* { dg-warning "changes meaning" } */
+template <class _Tp> class auto_ptr {};  /* { dg-message "declared here" } */
 template <class _Tp>
 class counted_ptr
 {
 public:
-  auto_ptr<_Tp> auto_ptr(); /* { dg-warning "" } */
+  auto_ptr<_Tp> auto_ptr(); /* { dg-warning "17:declaration of .auto_ptr\\<_Tp\\>" } */
 };
 
index bb31735f228d14f149e6e83d726df9df09ec55f4..fe3b33646014dbd6c3f14fe3a4e328f1edee87cf 100644 (file)
@@ -1,8 +1,8 @@
 // { dg-do assemble  }
 // Bug: g++ allows two different meanings of a name in the same scope.
 
-typedef int foo;               // { dg-error "" } 
+typedef int foo;               // { dg-message "declared here" }
 struct A {
   A (foo);
-  int foo ();                  // { dg-error "" } foo already used in scope
+  int foo ();                  // { dg-error "changes meaning" }
 };
index 7b2cae55b4b3759a55a8e65bdca6db10fa2fb768..68ad6ae987a0097e324bceaebf3fc45de68f5d48 100644 (file)
@@ -6,10 +6,10 @@
 // Subject:  Local type names bug in g++ 2.3.3
 // Message-ID: <1992Dec30.203807.17504@murdoch.acc.Virginia.EDU>
 
-typedef char* T; // { dg-error "" } previous declaration
+typedef char* T; // { dg-message "declared here" }
 
 struct Y {
     T a;
-    typedef long T; // error. See ARM p189-191 for details// { dg-error "" } 
+    typedef long T; // { dg-error "changes meaning" } 
     T b;
 };