]> granicus.if.org Git - clang/commitdiff
Allow classes to befriend implicitly-declared members. Fixes PR6207 for
authorJohn McCall <rjmccall@apple.com>
Tue, 13 Apr 2010 07:45:41 +0000 (07:45 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 13 Apr 2010 07:45:41 +0000 (07:45 +0000)
members of non-templated classes.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101122 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/CXX/class.access/class.friend/p1.cpp
test/SemaCXX/implicit-member-functions.cpp

index 005311f075bf97b67c7d49fa8a4ba053b7cb5a76..675cc36346d2b68f0ea18f9f84984e726a7b5220 100644 (file)
@@ -1058,10 +1058,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
     }
 
     const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
-    const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+    CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(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;
         }
       }
index b1aa2e879a9f651a2202d9b4e4a3d9d83e662a77..46ed857a9e4f32de4cdb738f897d21651c95f3ea 100644 (file)
@@ -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, 
index 88cbe4f4cddecda36b8eaec1825a80b47ae2ca71..991f611cdd8ddf83f48c99e189295d8822fea578 100644 (file)
@@ -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&);
+  };
+}
index 2112188ae6784755012e2e03044a6dc90247118d..79cc3679f4981bf44b1805412fbb3d1f5f1ad904 100644 (file)
@@ -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