[cfe-commits] r107510 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/DeclCXX.h lib/AST/ASTContext.cpp lib/AST/DeclCXX.cpp lib/Frontend/PCHReaderDecl.cpp lib/Frontend/PCHWriterDecl.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaLookup.cpp

Douglas Gregor dgregor at apple.com
Fri Jul 2 13:37:36 PDT 2010


Author: dgregor
Date: Fri Jul  2 15:37:36 2010
New Revision: 107510

URL: http://llvm.org/viewvc/llvm-project?rev=107510&view=rev
Log:
Lazily declare the implicitly-declared destructor in a C++ class.

Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Frontend/PCHReaderDecl.cpp
    cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Fri Jul  2 15:37:36 2010
@@ -1322,6 +1322,17 @@
   /// \brief Data Pointer data that will be provided to the callback function
   /// when it is called.
   void AddDeallocation(void (*Callback)(void*), void *Data);
+
+  //===--------------------------------------------------------------------===//
+  //                    Statistics
+  //===--------------------------------------------------------------------===//
+
+  /// \brief The number of implicitly-declared destructors.
+  static unsigned NumImplicitDestructors;
+  
+  /// \brief The number of implicitly-declared destructors for which 
+  /// declarations were built.
+  static unsigned NumImplicitDestructorsDeclared;
   
 private:
   ASTContext(const ASTContext&); // DO NOT IMPLEMENT

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Jul  2 15:37:36 2010
@@ -319,6 +319,9 @@
     /// already computed and are available.
     bool ComputedVisibleConversions : 1;
   
+    /// \brief Whether we have already declared a destructor within the class.
+    bool DeclaredDestructor : 1;
+    
     /// Bases - Base classes of this class.
     /// FIXME: This is wasted space for a union.
     CXXBaseSpecifier *Bases;
@@ -600,8 +603,21 @@
   /// fully defined, a destructor will be implicitly declared.
   void setUserDeclaredDestructor(bool UCD) {
     data().UserDeclaredDestructor = UCD;
+    if (UCD)
+      data().DeclaredDestructor = true;
   }
 
+  /// \brief Determine whether this class has had its destructor declared,
+  /// either via the user or via an implicit declaration.
+  ///
+  /// This value is used for lazy creation of destructors.
+  bool hasDeclaredDestructor() const { return data().DeclaredDestructor; }
+  
+  /// \brief Note whether this class has already had its destructor declared.
+  void setDeclaredDestructor(bool DD) {
+    data().DeclaredDestructor = DD;
+  }
+  
   /// getConversions - Retrieve the overload set containing all of the
   /// conversion functions in this class.
   UnresolvedSetImpl *getConversionFunctions() {

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Fri Jul  2 15:37:36 2010
@@ -31,6 +31,9 @@
 
 using namespace clang;
 
+unsigned ASTContext::NumImplicitDestructors;
+unsigned ASTContext::NumImplicitDestructorsDeclared;
+
 enum FloatingRank {
   FloatRank, DoubleRank, LongDoubleRank
 };
@@ -253,6 +256,10 @@
 
   fprintf(stderr, "Total bytes = %d\n", int(TotalBytes));
 
+  // Implicit special member functions.
+  fprintf(stderr, "  %u/%u implicit destructors created\n",
+          NumImplicitDestructorsDeclared, NumImplicitDestructors);
+  
   if (ExternalSource.get()) {
     fprintf(stderr, "\n");
     ExternalSource->PrintStats();

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Jul  2 15:37:36 2010
@@ -32,6 +32,7 @@
     Abstract(false), HasTrivialConstructor(true),
     HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
     HasTrivialDestructor(true), ComputedVisibleConversions(false),
+    DeclaredDestructor(false),
     Bases(0), NumBases(0), VBases(0), NumVBases(0),
     Definition(D), FirstFriend(0) {
 }

Modified: cfe/trunk/lib/Frontend/PCHReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderDecl.cpp?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderDecl.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderDecl.cpp Fri Jul  2 15:37:36 2010
@@ -668,6 +668,7 @@
       Data.HasTrivialCopyAssignment = Record[Idx++];
       Data.HasTrivialDestructor = Record[Idx++];
       Data.ComputedVisibleConversions = Record[Idx++];
+      Data.DeclaredDestructor = Record[Idx++];
 
       // setBases() is unsuitable since it may try to iterate the bases of an
       // unitialized base.

Modified: cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterDecl.cpp?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterDecl.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterDecl.cpp Fri Jul  2 15:37:36 2010
@@ -664,6 +664,7 @@
       Record.push_back(Data.HasTrivialCopyAssignment);
       Record.push_back(Data.HasTrivialDestructor);
       Record.push_back(Data.ComputedVisibleConversions);
+      Record.push_back(Data.DeclaredDestructor);
 
       Record.push_back(D->getNumBases());
       for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Jul  2 15:37:36 2010
@@ -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.

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jul  2 15:37:36 2010
@@ -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

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Jul  2 15:37:36 2010
@@ -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;
 }
 

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=107510&r1=107509&r2=107510&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Fri Jul  2 15:37:36 2010
@@ -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()) {





More information about the cfe-commits mailing list