CodeGen may see out-of-line declarations of the various special member
functions when they are explicitly declared, e.g., via a function
template specialization or explicit template instantiation
declaration. Don't try to synthesize bodies for the special member
functions in this case; rather, check whether we have an implicit
declaration and, if so, synthesize the appropriate function
body. Fixes PR5084.

llvm-svn: 83212
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 72009da..f9e54b7 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -239,28 +239,37 @@
     if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD))
       EmitDtorEpilogue(DD, GD.getDtorType());
     FinishFunction(S->getRBracLoc());
-  }
-  else
+  } else if (FD->isImplicit()) {
+    const CXXRecordDecl *ClassDecl =
+      cast<CXXRecordDecl>(FD->getDeclContext());
+    (void) ClassDecl;
     if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
-      const CXXRecordDecl *ClassDecl =
-        cast<CXXRecordDecl>(CD->getDeclContext());
-      (void) ClassDecl;
+      // FIXME: For C++0x, we want to look for implicit *definitions* of
+      // these special member functions, rather than implicit *declarations*.
       if (CD->isCopyConstructor(getContext())) {
         assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
-               "bogus constructor is being synthesize");
+               "Cannot synthesize a non-implicit copy constructor");
         SynthesizeCXXCopyConstructor(CD, GD.getCtorType(), Fn, Args);
-      }
-      else {
+      } else if (CD->isDefaultConstructor()) {
         assert(!ClassDecl->hasUserDeclaredConstructor() &&
-               "bogus constructor is being synthesize");
+               "Cannot synthesize a non-implicit default constructor.");
         SynthesizeDefaultConstructor(CD, GD.getCtorType(), Fn, Args);
+      } else {
+        assert(false && "Implicit constructor cannot be synthesized");
       }
-    }
-  else if (const CXXDestructorDecl *CD = dyn_cast<CXXDestructorDecl>(FD))
-    SynthesizeDefaultDestructor(CD, GD.getDtorType(), Fn, Args);
-  else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
-    if (MD->isCopyAssignment())
+    } else if (const CXXDestructorDecl *CD = dyn_cast<CXXDestructorDecl>(FD)) {
+      assert(!ClassDecl->hasUserDeclaredDestructor() &&
+             "Cannot synthesize a non-implicit destructor");
+      SynthesizeDefaultDestructor(CD, GD.getDtorType(), Fn, Args);
+    } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+      assert(MD->isCopyAssignment() && 
+             !ClassDecl->hasUserDeclaredCopyAssignment() &&
+             "Cannot synthesize a method that is not an implicit-defined "
+             "copy constructor");
       SynthesizeCXXCopyAssignment(MD, Fn, Args);
+    } else {
+      assert(false && "Cannot synthesize unknown implicit function");
+    }
   }
 
   // Destroy the 'this' declaration.