aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog12
-rw-r--r--gcc/cp/class.c10
-rw-r--r--gcc/cp/decl.c67
-rw-r--r--gcc/testsuite/ChangeLog22
-rw-r--r--gcc/testsuite/g++.dg/ext/uow-3.C4
-rw-r--r--gcc/testsuite/g++.dg/ext/uow-4.C4
-rw-r--r--gcc/testsuite/g++.dg/lookup/name-clash11.C20
-rw-r--r--gcc/testsuite/g++.dg/lookup/name-clash7.C4
-rw-r--r--gcc/testsuite/g++.dg/lookup/redecl1.C4
-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/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
-rw-r--r--gcc/testsuite/g++.dg/warn/changes-meaning.C4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.jason/scoping8.C4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.law/nest1.C4
19 files changed, 174 insertions, 32 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7161565..e9574f3 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 3d155a5..4300c5c 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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);
}
}
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 3c1e2ef..5239ffd 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7fc2a42..b9b8922 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/ext/uow-3.C b/gcc/testsuite/g++.dg/ext/uow-3.C
index a2c2240..9378c62 100644
--- a/gcc/testsuite/g++.dg/ext/uow-3.C
+++ b/gcc/testsuite/g++.dg/ext/uow-3.C
@@ -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" } */
};
diff --git a/gcc/testsuite/g++.dg/ext/uow-4.C b/gcc/testsuite/g++.dg/ext/uow-4.C
index 21ed04a..73a3a6f 100644
--- a/gcc/testsuite/g++.dg/ext/uow-4.C
+++ b/gcc/testsuite/g++.dg/ext/uow-4.C
@@ -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" } */
};
}
diff --git a/gcc/testsuite/g++.dg/lookup/name-clash11.C b/gcc/testsuite/g++.dg/lookup/name-clash11.C
index 28ce4c9..bc63645 100644
--- a/gcc/testsuite/g++.dg/lookup/name-clash11.C
+++ b/gcc/testsuite/g++.dg/lookup/name-clash11.C
@@ -13,11 +13,11 @@
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); }
diff --git a/gcc/testsuite/g++.dg/lookup/name-clash7.C b/gcc/testsuite/g++.dg/lookup/name-clash7.C
index 5c0690a..cc27181 100644
--- a/gcc/testsuite/g++.dg/lookup/name-clash7.C
+++ b/gcc/testsuite/g++.dg/lookup/name-clash7.C
@@ -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" }
};
diff --git a/gcc/testsuite/g++.dg/lookup/redecl1.C b/gcc/testsuite/g++.dg/lookup/redecl1.C
index 436316c..b105be2 100644
--- a/gcc/testsuite/g++.dg/lookup/redecl1.C
+++ b/gcc/testsuite/g++.dg/lookup/redecl1.C
@@ -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
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/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);
};
diff --git a/gcc/testsuite/g++.dg/warn/changes-meaning.C b/gcc/testsuite/g++.dg/warn/changes-meaning.C
index fdbddf8..0b9fc4c 100644
--- a/gcc/testsuite/g++.dg/warn/changes-meaning.C
+++ b/gcc/testsuite/g++.dg/warn/changes-meaning.C
@@ -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\\>" } */
};
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/scoping8.C b/gcc/testsuite/g++.old-deja/g++.jason/scoping8.C
index bb31735..fe3b336 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/scoping8.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/scoping8.C
@@ -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" }
};
diff --git a/gcc/testsuite/g++.old-deja/g++.law/nest1.C b/gcc/testsuite/g++.old-deja/g++.law/nest1.C
index 7b2cae5..68ad6ae 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/nest1.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/nest1.C
@@ -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;
};