Commit 6498dea6 by Paolo Carlini Committed by Paolo Carlini

re PR c++/59480 (Missing error diagnostic: friend declaration specifying a…

re PR c++/59480 (Missing error diagnostic: friend declaration specifying a default argument must be a definition)

/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
parent 0559979c
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> 2018-07-18 Richard Biener <rguenther@suse.de>
PR debug/86523 PR debug/86523
......
...@@ -8285,10 +8285,12 @@ note_name_declared_in_class (tree name, tree decl) ...@@ -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 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 in its context and when re-evaluated in the completed scope of
S. */ S. */
permerror (input_location, "declaration of %q#D", decl); if (permerror (DECL_SOURCE_LOCATION (decl),
permerror (location_of ((tree) n->value), "declaration of %q#D changes meaning of %qD",
"changes meaning of %qD from %q#D", decl, OVL_NAME (decl)))
OVL_NAME (decl), (tree) n->value); inform (location_of ((tree) n->value),
"%qD declared here as %q#D",
OVL_NAME (decl), (tree) n->value);
} }
} }
......
...@@ -1280,6 +1280,39 @@ check_redeclaration_no_default_args (tree decl) ...@@ -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, /* Merge tree bits that correspond to attributes noreturn, nothrow,
const, malloc, and pure from NEWDECL with those of OLDDECL. */ const, malloc, and pure from NEWDECL with those of OLDDECL. */
...@@ -1876,6 +1909,12 @@ next_arg:; ...@@ -1876,6 +1909,12 @@ next_arg:;
olddecl); 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:; ...@@ -2008,11 +2047,18 @@ next_arg:;
if (DECL_FUNCTION_TEMPLATE_P (newdecl)) 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) if (DECL_SOURCE_LOCATION (newdecl)
!= DECL_SOURCE_LOCATION (olddecl)) != 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); check_default_args (newdecl);
...@@ -8763,6 +8809,21 @@ grokfndecl (tree ctype, ...@@ -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 this decl has namespace scope, set that up. */
if (in_namespace) if (in_namespace)
set_decl_namespace (decl, in_namespace, friendp); set_decl_namespace (decl, in_namespace, friendp);
......
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> 2018-07-18 Richard Biener <rguenther@suse.de>
PR debug/86523 PR debug/86523
......
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-Wall" } */ /* { dg-options "-Wall" } */
typedef int UOW; /* { dg-error "" } */ typedef int UOW; /* { dg-message "declared here" } */
struct ABC { struct ABC {
UOW UOW; /* { dg-error "" } */ UOW UOW; /* { dg-error "changes meaning" } */
}; };
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
extern "C" { extern "C" {
typedef int UOW; /* { dg-error "" } */ typedef int UOW; /* { dg-message "declared here" } */
struct ABC { struct ABC {
UOW UOW; /* { dg-error "" } */ UOW UOW; /* { dg-error "changes meaning" } */
}; };
} }
......
...@@ -13,11 +13,11 @@ ...@@ -13,11 +13,11 @@
void test_bitset () void test_bitset ()
{ {
int x; // { dg-warning "changes meaning" } int x; // { dg-message "declared here" }
{ {
struct S { struct S {
int x: sizeof x; // { dg-warning "declaration" } int x: sizeof x; // { dg-warning "changes meaning" }
}; };
} }
} }
...@@ -25,11 +25,11 @@ void test_bitset () ...@@ -25,11 +25,11 @@ void test_bitset ()
void test_enum () void test_enum ()
{ {
// Also exercise (not covered by c++/69023): // Also exercise (not covered by c++/69023):
int y; // { dg-warning "changes meaning" } int y; // { dg-message "declared here" }
{ {
struct S { struct S {
enum E { 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. // Verify the enumerator has the correct value.
...@@ -40,7 +40,7 @@ void test_enum () ...@@ -40,7 +40,7 @@ void test_enum ()
void test_alignas () void test_alignas ()
{ {
enum { A = 16 }; // { dg-warning "changes meaning" } enum { A = 16 }; // { dg-message "declared here" }
{ {
struct S { struct S {
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
...@@ -48,7 +48,7 @@ void test_alignas () ...@@ -48,7 +48,7 @@ void test_alignas ()
#else #else
__attribute__ ((aligned (A))) __attribute__ ((aligned (A)))
#endif #endif
int A; // { dg-warning "declaration" } int A; // { dg-warning "changes meaning" }
// Verify the member has the correct alignment. // Verify the member has the correct alignment.
void test () { ASSERT (__alignof__ (this->A) == 16); } void test () { ASSERT (__alignof__ (this->A) == 16); }
...@@ -58,10 +58,10 @@ void test_alignas () ...@@ -58,10 +58,10 @@ void test_alignas ()
void test_array () void test_array ()
{ {
enum { A = 16 }; // { dg-warning "changes meaning" } enum { A = 16 }; // { dg-message "declared here" }
{ {
struct S { struct S {
int A [A]; // { dg-warning "declaration" } int A [A]; // { dg-warning "changes meaning" }
// Verify the member has the correct alignment. // Verify the member has the correct alignment.
void test () { ASSERT (sizeof (this->A) == 16 * sizeof (int)); } void test () { ASSERT (sizeof (this->A) == 16 * sizeof (int)); }
...@@ -71,10 +71,10 @@ void test_array () ...@@ -71,10 +71,10 @@ void test_array ()
void test_vector () void test_vector ()
{ {
enum { A = 16 }; // { dg-warning "changes meaning" } enum { A = 16 }; // { dg-message "declared here" }
{ {
struct S { 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. // Verify the member has the correct size.
void test () { ASSERT (sizeof (this->A) == 16); } void test () { ASSERT (sizeof (this->A) == 16); }
......
// PR c++/28513 // PR c++/28513
class foo { // { dg-error "changes meaning" } class foo { // { dg-message "declared here" }
public: public:
typedef int bar; typedef int bar;
}; };
class baz { class baz {
public: public:
foo::bar foo; // { dg-error "declaration" } foo::bar foo; // { dg-error "changes meaning" }
}; };
// PR c++/14668 // PR c++/14668
class A {}; // { dg-error "" } class A {}; // { dg-message "declared here" }
class B { class B {
static A *A; // { dg-error "" } static A *A; // { dg-error "changes meaning" }
}; };
A *B::A = 0; A *B::A = 0;
// 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" }
// 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" }
};
// 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>;
// 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" }
};
// 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>;
// { dg-do compile } // { dg-options "-fpermissive -w" }
// Copyright (C) 2003 Free Software Foundation, Inc. // Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 3 Jul 2003 <nathan@codesourcery.com> // Contributed by Nathan Sidwell 3 Jul 2003 <nathan@codesourcery.com>
......
// { dg-options "-fpermissive -w" }
struct A { struct A {
static void g(int); static void g(int);
}; };
......
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-fpermissive" } */ /* { 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> template <class _Tp>
class counted_ptr class counted_ptr
{ {
public: public:
auto_ptr<_Tp> auto_ptr(); /* { dg-warning "" } */ auto_ptr<_Tp> auto_ptr(); /* { dg-warning "17:declaration of .auto_ptr\\<_Tp\\>" } */
}; };
// { dg-do assemble } // { dg-do assemble }
// Bug: g++ allows two different meanings of a name in the same scope. // 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 { struct A {
A (foo); A (foo);
int foo (); // { dg-error "" } foo already used in scope int foo (); // { dg-error "changes meaning" }
}; };
...@@ -6,10 +6,10 @@ ...@@ -6,10 +6,10 @@
// Subject: Local type names bug in g++ 2.3.3 // Subject: Local type names bug in g++ 2.3.3
// Message-ID: <1992Dec30.203807.17504@murdoch.acc.Virginia.EDU> // 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 { struct Y {
T a; T a;
typedef long T; // error. See ARM p189-191 for details// { dg-error "" } typedef long T; // { dg-error "changes meaning" }
T b; T b;
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment