Lazily declare the implicitly-declared destructor in a C++ class.

llvm-svn: 107510
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 1cd7d73..9ec790b 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -2282,6 +2282,10 @@
   void DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
                                     CXXMethodDecl *MethodDecl);
 
+  /// \brief Force the declaration of any implicitly-declared members of this
+  /// class.
+  void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class);
+  
   /// MaybeBindToTemporary - If the passed in expression has a record type with
   /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
   /// it simply returns the passed in expression.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c1d670c..d090e32 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -3676,7 +3676,7 @@
       CXXRecordDecl *Record = Destructor->getParent();
       QualType ClassType = Context.getTypeDeclType(Record);
       
-      // FIXME: Shouldn't we be able to perform thisc heck even when the class
+      // FIXME: Shouldn't we be able to perform this check even when the class
       // type is dependent? Both gcc and edg can handle that.
       if (!ClassType->isDependentType()) {
         DeclarationName Name
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 7ba34a5..3299999 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2662,8 +2662,16 @@
   if (!ClassDecl->hasUserDeclaredCopyAssignment())
     DeclareImplicitCopyAssignment(ClassDecl);
 
-  if (!ClassDecl->hasUserDeclaredDestructor())
-    DeclareImplicitDestructor(ClassDecl);
+  if (!ClassDecl->hasUserDeclaredDestructor()) {
+    ++ASTContext::NumImplicitDestructors;
+    
+    // If we have a dynamic class, then the destructor may be virtual, so we 
+    // have to declare the destructor immediately. This ensures that, e.g., it
+    // shows up in the right place in the vtable and that we diagnose problems
+    // with the implicit exception specification.
+    if (ClassDecl->isDynamicClass())
+      DeclareImplicitDestructor(ClassDecl);
+  }
 }
 
 void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
@@ -4274,6 +4282,7 @@
                     LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
   }
   
+  // Create the actual destructor declaration.
   QualType Ty = Context.getFunctionType(Context.VoidTy,
                                         0, 0, false, 0,
                                         ExceptSpec.hasExceptionSpecification(),
@@ -4294,15 +4303,21 @@
   Destructor->setAccess(AS_public);
   Destructor->setImplicit();
   Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
+  
+  // Note that we have declared this destructor.
+  ClassDecl->setDeclaredDestructor(true);
+  ++ASTContext::NumImplicitDestructorsDeclared;
+  
+  // Introduce this destructor into its scope.
   if (Scope *S = getScopeForContext(ClassDecl))
-    PushOnScopeChains(Destructor, S, true);
-  else
-    ClassDecl->addDecl(Destructor);
+    PushOnScopeChains(Destructor, S, false);
+  ClassDecl->addDecl(Destructor);
   
   // This could be uniqued if it ever proves significant.
   Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
   
   AddOverriddenMethods(ClassDecl, Destructor);
+  
   return Destructor;
 }
 
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 72c7593..fc5c8e8 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -447,11 +447,52 @@
   return false;
 }
 
+/// \brief Determine whether we can declare a special member function within
+/// the class at this point.
+static bool CanDeclareSpecialMemberFunction(ASTContext &Context,
+                                            const CXXRecordDecl *Class) {
+  // We need to have a definition for the class.
+  if (!Class->getDefinition() || Class->isDependentContext())
+    return false;
+  
+  // We can't be in the middle of defining the class.
+  if (const RecordType *RecordTy
+                        = Context.getTypeDeclType(Class)->getAs<RecordType>())
+    return !RecordTy->isBeingDefined();
+    
+  return false;
+}
+
+void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
+  // If the destructor has not yet been declared, do so now.
+  if (CanDeclareSpecialMemberFunction(Context, Class) &&
+      !Class->hasDeclaredDestructor())
+    DeclareImplicitDestructor(Class);  
+}
+
+
 // Adds all qualifying matches for a name within a decl context to the
 // given lookup result.  Returns true if any matches were found.
 static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
   bool Found = false;
 
+  // Lazily declare C++ special member functions.
+  if (S.getLangOptions().CPlusPlus) {
+    switch (R.getLookupName().getNameKind()) {
+    case DeclarationName::CXXDestructorName:
+      if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
+        if (Record->getDefinition() && !Record->hasDeclaredDestructor() &&
+            CanDeclareSpecialMemberFunction(S.Context, Record))
+          S.DeclareImplicitDestructor(const_cast<CXXRecordDecl *>(Record));
+        
+      break;
+        
+    default:
+      break;      
+    }
+  }
+  
+  // Perform lookup into this declaration context.
   DeclContext::lookup_const_iterator I, E;
   for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
     NamedDecl *D = *I;
@@ -1904,6 +1945,11 @@
 ///
 /// \returns The destructor for this class.
 CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
+  // If the destructor has not yet been declared, do so now.
+  if (CanDeclareSpecialMemberFunction(Context, Class) &&
+      !Class->hasDeclaredDestructor())
+    DeclareImplicitDestructor(Class);
+
   return Class->getDestructor();
 }
 
@@ -2205,6 +2251,9 @@
   if (Visited.visitedContext(Ctx->getPrimaryContext()))
     return;
   
+  if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
+    Result.getSema().ForceDeclarationOfImplicitMembers(Class);
+
   // Enumerate all of the results in this context.
   for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; 
        CurCtx = CurCtx->getNextContext()) {