From f6a144f5991c6b29622a31fdab86adede0648d12 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Tue, 25 Jun 2013 23:09:30 +0000 Subject: [PATCH] Implement DR136 Friend declarations that specify a default argument must be a definition and the only declaration in the translation unit. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184889 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 4 ++ lib/Sema/SemaDeclCXX.cpp | 34 +++++++++++++++++ test/CXX/drs/dr1xx.cpp | 38 +++++++++++++------ .../2004-11-27-FriendDefaultArgCrash.cpp | 2 +- test/SemaCXX/friend.cpp | 2 +- www/cxx_dr_status.html | 2 +- 6 files changed, 67 insertions(+), 15 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 05f71d5b91..5428550e85 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4270,6 +4270,10 @@ def err_member_def_undefined_record : Error< "out-of-line definition of %0 from class %1 without definition">; def err_member_def_does_not_match : Error< "out-of-line definition of %0 does not match any declaration in %1">; +def err_friend_decl_with_def_arg_must_be_def : Error< + "friend declaration specifying a default argument must be a definition">; +def err_friend_decl_with_def_arg_redeclared : Error< + "friend declaration specifying a default argument must be the only declaration">; def err_friend_decl_does_not_match : Error< "friend declaration of %0 does not match any declaration in %1">; def err_member_def_does_not_match_suggest : Error< diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index caf7affd0c..4e5e307be6 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -404,6 +404,17 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { } } +static bool functionDeclHasDefaultArgument(const FunctionDecl *FD) { + for (unsigned NumParams = FD->getNumParams(); NumParams > 0; --NumParams) { + const ParmVarDecl *PVD = FD->getParamDecl(NumParams-1); + if (!PVD->hasDefaultArg()) + return false; + if (!PVD->hasInheritedDefaultArg()) + return true; + } + return false; +} + /// MergeCXXFunctionDecl - Merge two declarations of the same C++ /// function, once we already know that they have the same /// type. Subroutine of MergeFunctionDecl. Returns true if there was an @@ -578,6 +589,17 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Invalid = true; } + // C++11 [dcl.fct.default]p4: 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. + if (Old->getFriendObjectKind() == Decl::FOK_Undeclared && + functionDeclHasDefaultArgument(Old)) { + Diag(New->getLocation(), diag::err_friend_decl_with_def_arg_redeclared); + Diag(Old->getLocation(), diag::note_previous_declaration); + Invalid = true; + } + if (CheckEquivalentExceptionSpec(Old, New)) Invalid = true; @@ -11377,6 +11399,18 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, else FD = cast(ND); + // C++11 [dcl.fct.default]p4: 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. + if (functionDeclHasDefaultArgument(FD)) { + if (FunctionDecl *OldFD = FD->getPreviousDecl()) { + Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_redeclared); + Diag(OldFD->getLocation(), diag::note_previous_declaration); + } else if (!D.isFunctionDefinition()) + Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_must_be_def); + } + // Mark templated-scope function declarations as unsupported. if (FD->getNumTemplateParameterLists()) FrD->setUnsupportedFriend(true); diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp index 7d5b36d922..88ae6ba0e4 100644 --- a/test/CXX/drs/dr1xx.cpp +++ b/test/CXX/drs/dr1xx.cpp @@ -357,25 +357,39 @@ namespace dr135 { // dr135: yes }; } -namespace dr136 { // dr136: no - void f(int, int, int = 0); - void g(int, int, int); +namespace dr136 { // dr136: 3.4 + void f(int, int, int = 0); // expected-note {{previous declaration is here}} + void g(int, int, int); // expected-note {{previous declaration is here}} struct A { - // FIXME: These declarations of f, g, and h are invalid. - friend void f(int, int = 0, int); - friend void g(int, int, int = 0); - friend void h(int, int, int = 0); - friend void i(int, int, int = 0) {} + friend void f(int, int = 0, int); // expected-error {{friend declaration specifying a default argument must be the only declaration}} + friend void g(int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}} + friend void h(int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be a definition}} + friend void i(int, int, int = 0) {} // expected-note {{previous declaration is here}} friend void j(int, int, int = 0) {} operator int(); }; - // FIXME: This declaration of i is invalid. - void i(int, int, int); + void i(int, int, int); // expected-error {{friend declaration specifying a default argument must be the only declaration}} void q() { j(A(), A()); // ok, has default argument } - // FIXME: Also test extern "C" friends and default arguments from other - // namespaces? + extern "C" void k(int, int, int, int); // expected-note {{previous declaration is here}} + namespace NSA { + struct A { + friend void dr136::k(int, int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}} \ + // expected-note {{previous declaration is here}} + }; + } + namespace NSB { + struct A { + friend void dr136::k(int, int, int = 0, int); // expected-error {{friend declaration specifying a default argument must be the only declaration}} + }; + } + struct B { + void f(int); // expected-note {{previous declaration is here}} + }; + struct C { + friend void B::f(int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}} + }; } namespace dr137 { // dr137: yes diff --git a/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp b/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp index 3bfecd54b7..c478e7dcae 100644 --- a/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp +++ b/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp @@ -4,6 +4,6 @@ namespace nm { struct str { - friend int foo(int arg = 0); + friend void foo(int arg = 0) {}; }; } diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp index 3da27e0f33..5daadf0e72 100644 --- a/test/SemaCXX/friend.cpp +++ b/test/SemaCXX/friend.cpp @@ -44,7 +44,7 @@ namespace test2 { // PR5134 namespace test3 { class Foo { - friend const int getInt(int inInt = 0); + friend const int getInt(int inInt = 0) {} }; } diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index dd8c7d233f..6ffc0e7500 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -854,7 +854,7 @@ 136 CD1 Default arguments and friend declarations - No + SVN 137 -- 2.40.0