From: John McCall Date: Tue, 13 Apr 2010 07:45:41 +0000 (+0000) Subject: Allow classes to befriend implicitly-declared members. Fixes PR6207 for X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3d04336baf091b16e9d8f85b48b82dafd2695874;p=clang Allow classes to befriend implicitly-declared members. Fixes PR6207 for members of non-templated classes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101122 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 005311f075..675cc36346 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1058,10 +1058,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { } const CXXMethodDecl* OldMethod = dyn_cast(Old); - const CXXMethodDecl* NewMethod = dyn_cast(New); + CXXMethodDecl* NewMethod = dyn_cast(New); if (OldMethod && NewMethod) { - if (!NewMethod->getFriendObjectKind() && - NewMethod->getLexicalDeclContext()->isRecord()) { + // Preserve triviality. + NewMethod->setTrivial(OldMethod->isTrivial()); + + bool isFriend = NewMethod->getFriendObjectKind(); + + if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) { // -- Member function declarations with the same name and the // same parameter types cannot be overloaded if any of them // is a static member function declaration. @@ -1087,14 +1091,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Diag(New->getLocation(), NewDiag); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); - } else { - if (OldMethod->isImplicit()) { + + // Complain if this is an explicit declaration of a special + // member that was initially declared implicitly. + // + // As an exception, it's okay to befriend such methods in order + // to permit the implicit constructor/destructor/operator calls. + } else if (OldMethod->isImplicit()) { + if (isFriend) { + NewMethod->setImplicit(); + } else { Diag(NewMethod->getLocation(), diag::err_definition_of_implicitly_declared_member) - << New << getSpecialMember(Context, OldMethod); - - Diag(OldMethod->getLocation(), - diag::note_previous_implicit_declaration); + << New << getSpecialMember(Context, OldMethod); return true; } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b1aa2e879a..46ed857a9e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2682,8 +2682,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { } } - // Notify the class that we've added a constructor. - ClassDecl->addedConstructor(Context, Constructor); + // Notify the class that we've added a constructor. In principle we + // don't need to do this for out-of-line declarations; in practice + // we only instantiate the most recent declaration of a method, so + // we have to call this for everything but friends. + if (!Constructor->getFriendObjectKind()) + ClassDecl->addedConstructor(Context, Constructor); } /// CheckDestructor - Checks a fully-formed destructor for well-formedness, diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp index 88cbe4f4cd..991f611cdd 100644 --- a/test/CXX/class.access/class.friend/p1.cpp +++ b/test/CXX/class.access/class.friend/p1.cpp @@ -211,3 +211,14 @@ namespace test5 { }; } } + +// PR6207 +namespace test6 { + struct A {}; + + struct B { + friend A::A(); + friend A::~A(); + friend A &A::operator=(const A&); + }; +} diff --git a/test/SemaCXX/implicit-member-functions.cpp b/test/SemaCXX/implicit-member-functions.cpp index 2112188ae6..79cc3679f4 100644 --- a/test/SemaCXX/implicit-member-functions.cpp +++ b/test/SemaCXX/implicit-member-functions.cpp @@ -1,15 +1,15 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -struct A { }; // expected-note {{previous implicit declaration is here}} +struct A { }; A::A() { } // expected-error {{definition of implicitly declared constructor}} -struct B { }; // expected-note {{previous implicit declaration is here}} +struct B { }; B::B(const B&) { } // expected-error {{definition of implicitly declared copy constructor}} -struct C { }; // expected-note {{previous implicit declaration is here}} +struct C { }; C& C::operator=(const C&) { return *this; } // expected-error {{definition of implicitly declared copy assignment operator}} -struct D { }; // expected-note {{previous implicit declaration is here}} +struct D { }; D::~D() { } // expected-error {{definition of implicitly declared destructor}} // Make sure that the special member functions are introduced for