diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-07-02 20:37:36 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-07-02 20:37:36 +0000 |
commit | 4923aa25eb39d64106a5817c02d560a3aecf8b2c (patch) | |
tree | 1004c47e2ddba9fe789603ab6bcf3f8cb04796e6 /lib/Sema | |
parent | d0b982ca5cf685af08d5015e8c2dfae3ecab1a0b (diff) |
Lazily declare the implicitly-declared destructor in a C++ class.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107510 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-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 |
4 files changed, 74 insertions, 6 deletions
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()) { |