diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 11 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 16 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 7 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 25 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 49 |
10 files changed, 111 insertions, 6 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index b3545e8192..f109d48159 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1322,6 +1322,17 @@ public: /// \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 diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index d8ad02a41b..f67faa86ec 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -319,6 +319,9 @@ class CXXRecordDecl : public RecordDecl { /// 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 @@ public: /// 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() { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ca83964b3e..40342b36ba 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -31,6 +31,9 @@ using namespace clang; +unsigned ASTContext::NumImplicitDestructors; +unsigned ASTContext::NumImplicitDestructorsDeclared; + enum FloatingRank { FloatRank, DoubleRank, LongDoubleRank }; @@ -253,6 +256,10 @@ void ASTContext::PrintStats() const { 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(); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index a77c1c8ed5..05e3680ea9 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -32,6 +32,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) 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) { } diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 9bc7099079..08ab9a26f6 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -668,6 +668,7 @@ void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { 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. diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 936ca5e818..d865e7c1b2 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -664,6 +664,7 @@ void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { 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(), diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 1cd7d739d2..9ec790bcdc 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2282,6 +2282,10 @@ public: 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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c1d670c0fd..d090e322f1 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3676,7 +3676,7 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, 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/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 7ba34a5fea..3299999536 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2662,8 +2662,16 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { 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 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { 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 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { 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/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 72c7593e2f..fc5c8e868d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -447,11 +447,52 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { 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 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, /// /// \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 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, 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()) { |