diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-02-28 01:01:56 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-02-28 01:01:56 +0000 |
commit | 91c18de7556f9524c62f655ccdda94adf3848092 (patch) | |
tree | 2ce3a4ad6be2f320764a5d4d27d23e728132224c /clang/lib | |
parent | f986d68b363a961a8bde29fcab649d46aaf23445 (diff) | |
download | bcm5719-llvm-91c18de7556f9524c62f655ccdda94adf3848092.tar.gz bcm5719-llvm-91c18de7556f9524c62f655ccdda94adf3848092.zip |
Rework our handling of key functions. We used to track a complete list of all
dynamic classes in the translation unit and check whether each one's key
function is defined when we got to the end of the TU (and when we got to the
end of each module). This is really terrible for modules performance, since it
causes unnecessary deserialization of every dynamic class in every compilation.
We now use a much simpler (and, in a modules build, vastly more efficient)
system: when we see an out-of-line definition of a virtual function, we check
whether that function was in fact its class's key function. (If so, we need to
emit the vtable.)
llvm-svn: 230830
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/MultiplexExternalSemaSource.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 50 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 8 |
6 files changed, 29 insertions, 71 deletions
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 449ddf43114..a0315777675 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -236,12 +236,6 @@ void MultiplexExternalSemaSource::ReadExtVectorDecls( Sources[i]->ReadExtVectorDecls(Decls); } -void MultiplexExternalSemaSource::ReadDynamicClasses( - SmallVectorImpl<CXXRecordDecl*> &Decls) { - for(size_t i = 0; i < Sources.size(); ++i) - Sources[i]->ReadDynamicClasses(Decls); -} - void MultiplexExternalSemaSource::ReadUnusedLocalTypedefNameCandidates( llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) { for(size_t i = 0; i < Sources.size(); ++i) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 5170c244bbf..a851ce14556 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -621,22 +621,6 @@ void Sema::ActOnEndOfTranslationUnit() { if (TUKind != TU_Prefix) { DiagnoseUseOfUnimplementedSelectors(); - // If any dynamic classes have their key function defined within - // this translation unit, then those vtables are considered "used" and must - // be emitted. - for (DynamicClassesType::iterator I = DynamicClasses.begin(ExternalSource), - E = DynamicClasses.end(); - I != E; ++I) { - assert(!(*I)->isDependentType() && - "Should not see dependent types here!"); - if (const CXXMethodDecl *KeyFunction = - Context.getCurrentKeyFunction(*I)) { - const FunctionDecl *Definition = nullptr; - if (KeyFunction->hasBody(Definition)) - MarkVTableUsed(Definition->getLocation(), *I, true); - } - } - // If DefinedUsedVTables ends up marking any virtual member functions it // might lead to more pending template instantiations, which we then need // to instantiate. @@ -668,6 +652,8 @@ void Sema::ActOnEndOfTranslationUnit() { // All delayed member exception specs should be checked or we end up accepting // incompatible declarations. + // FIXME: This is wrong for TUKind == TU_Prefix. In that case, we need to + // write out the lists to the AST file (if any). assert(DelayedDefaultedMemberExceptionSpecs.empty()); assert(DelayedExceptionSpecChecks.empty()); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e2547739f43..eb5b7154936 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8011,28 +8011,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // This needs to happen first so that 'inline' propagates. NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl)); - if (isa<CXXMethodDecl>(NewFD)) { - // A valid redeclaration of a C++ method must be out-of-line, - // but (unfortunately) it's not necessarily a definition - // because of templates, which means that the previous - // declaration is not necessarily from the class definition. - - // For just setting the access, that doesn't matter. - CXXMethodDecl *oldMethod = cast<CXXMethodDecl>(OldDecl); - NewFD->setAccess(oldMethod->getAccess()); - - // Update the key-function state if necessary for this ABI. - if (NewFD->isInlined() && - !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { - // setNonKeyFunction needs to work with the original - // declaration from the class definition, and isVirtual() is - // just faster in that case, so map back to that now. - oldMethod = cast<CXXMethodDecl>(oldMethod->getFirstDecl()); - if (oldMethod->isVirtual()) { - Context.setNonKeyFunction(oldMethod); - } - } - } + if (isa<CXXMethodDecl>(NewFD)) + NewFD->setAccess(OldDecl->getAccess()); } } @@ -10559,7 +10539,31 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, !FD->isDependentContext()) computeNRVO(Body, getCurFunction()); } - + + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { + const CXXMethodDecl *KeyFunction; + if (MD->isOutOfLine() && (MD = MD->getCanonicalDecl()) && + MD->isVirtual() && + (KeyFunction = Context.getCurrentKeyFunction(MD->getParent())) && + MD == KeyFunction->getCanonicalDecl()) { + // Update the key-function state if necessary for this ABI. + if (FD->isInlined() && + !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { + Context.setNonKeyFunction(MD); + + // If the newly-chosen key function is already defined, then we + // need to mark the vtable as used retroactively. + KeyFunction = Context.getCurrentKeyFunction(MD->getParent()); + const FunctionDecl *Definition; + if (KeyFunction && KeyFunction->isDefined(Definition)) + MarkVTableUsed(Definition->getLocation(), MD->getParent(), true); + } else { + // We just defined they key function; mark the vtable as used. + MarkVTableUsed(FD->getLocation(), MD->getParent(), true); + } + } + } + assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c41dc3309a5..c78f214fbca 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4875,9 +4875,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } - if (Record->isDynamicClass() && !Record->isDependentType()) - DynamicClasses.push_back(Record); - if (Record->getIdentifier()) { // C++ [class.mem]p13: // If T is the name of a class, then each of the following shall have a diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 9d9885b7930..78c44d17887 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3099,11 +3099,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } break; - case DYNAMIC_CLASSES: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - DynamicClasses.push_back(getGlobalDeclID(F, Record[I])); - break; - case PENDING_IMPLICIT_INSTANTIATIONS: if (PendingInstantiations.size() % 2 != 0) { Error("Invalid existing PendingInstantiations"); @@ -7312,16 +7307,6 @@ void ASTReader::ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) { ExtVectorDecls.clear(); } -void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) { - for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { - CXXRecordDecl *D - = dyn_cast_or_null<CXXRecordDecl>(GetDecl(DynamicClasses[I])); - if (D) - Decls.push_back(D); - } - DynamicClasses.clear(); -} - void ASTReader::ReadUnusedLocalTypedefNameCandidates( llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) { for (unsigned I = 0, N = UnusedLocalTypedefNameCandidates.size(); I != N; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index c70935c0c7d..e04c46ed982 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4344,10 +4344,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, for (const TypedefNameDecl *TD : SemaRef.UnusedLocalTypedefNameCandidates) AddDeclRef(TD, UnusedLocalTypedefNameCandidates); - // Build a record containing all of dynamic classes declarations. - RecordData DynamicClasses; - AddLazyVectorDecls(*this, SemaRef.DynamicClasses, DynamicClasses); - // Build a record containing all of pending implicit instantiations. RecordData PendingInstantiations; for (std::deque<Sema::PendingImplicitInstantiation>::iterator @@ -4628,10 +4624,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, if (!VTableUses.empty()) Stream.EmitRecord(VTABLE_USES, VTableUses); - // Write the record containing dynamic classes declarations. - if (!DynamicClasses.empty()) - Stream.EmitRecord(DYNAMIC_CLASSES, DynamicClasses); - // Write the record containing potentially unused local typedefs. if (!UnusedLocalTypedefNameCandidates.empty()) Stream.EmitRecord(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES, |