diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index 48eb6292772c2f078af719794b8d988d70129a56..27fdeac6b1f07dbc758761191f4f8764fe5c5a6a 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -16,9 +16,10 @@ #include "clang/Basic/SourceLocation.h" namespace clang { - class CXXRecordDecl; class ClassTemplateDecl; class ClassTemplateSpecializationDecl; + class CXXDestructorDecl; + class CXXRecordDecl; class Decl; class DeclContext; class FunctionDecl; @@ -72,6 +73,10 @@ public: /// \brief A function's return type has been deduced. virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType); + /// \brief A virtual destructor's operator delete has been resolved. + virtual void ResolvedOperatorDelete(const CXXDestructorDecl *DD, + const FunctionDecl *Delete) {} + /// \brief An implicit member got a definition. virtual void CompletedImplicitDefinition(const FunctionDecl *D) {} diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index ed6e2dc752f88642748f758850669d110b3b9330..a5b44f4e80abb02f0f0a4092ab75b066dc0a2fc2 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -2372,9 +2372,7 @@ public: bool isImplicitlyDeclared); static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID); - void setOperatorDelete(FunctionDecl *OD) { - cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete = OD; - } + void setOperatorDelete(FunctionDecl *OD); const FunctionDecl *getOperatorDelete() const { return cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete; } diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 0d7a9c8821c9e2c1104e05d6cc380068b80e40d3..175ee7a3b39775b2bad1c37bc582d2224e5c0dd3 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -806,6 +806,8 @@ public: const FunctionDecl *D) override; void ResolvedExceptionSpec(const FunctionDecl *FD) override; void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override; + void ResolvedOperatorDelete(const CXXDestructorDecl *DD, + const FunctionDecl *Delete) override; void CompletedImplicitDefinition(const FunctionDecl *D) override; void StaticDataMemberInstantiated(const VarDecl *D) override; void FunctionDefinitionInstantiated(const FunctionDecl *D) override; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 87a063438bc61b5b1e8fdbe50b8512854a0ac1a6..82fb2a6950a65b5b87a9e0f68ecfe53004d9367a 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1886,6 +1886,15 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, isInline, isImplicitlyDeclared); } +void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD) { + auto *First = cast<CXXDestructorDecl>(getFirstDecl()); + if (OD && !First->OperatorDelete) { + First->OperatorDelete = OD; + if (auto *L = getASTMutationListener()) + L->ResolvedOperatorDelete(First, OD); + } +} + void CXXConversionDecl::anchor() { } CXXConversionDecl * diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp index 3c4fed1d18e31d858a5bb4ce7d8b7f5bc4a5bd47..0d69f570be53cb0e9e87a70ac71f06a79df1a99f 100644 --- a/lib/Frontend/MultiplexConsumer.cpp +++ b/lib/Frontend/MultiplexConsumer.cpp @@ -99,6 +99,8 @@ public: void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D) override; void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override; + void ResolvedOperatorDelete(const CXXDestructorDecl *DD, + const FunctionDecl *Delete) override; void CompletedImplicitDefinition(const FunctionDecl *D) override; void StaticDataMemberInstantiated(const VarDecl *D) override; void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, @@ -154,6 +156,11 @@ void MultiplexASTMutationListener::DeducedReturnType(const FunctionDecl *FD, for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeducedReturnType(FD, ReturnType); } +void MultiplexASTMutationListener::ResolvedOperatorDelete( + const CXXDestructorDecl *DD, const FunctionDecl *Delete) { + for (auto *L : Listeners) + L->ResolvedOperatorDelete(DD, Delete); +} void MultiplexASTMutationListener::CompletedImplicitDefinition( const FunctionDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h index 88cdbcfe179ebbc0df711a740a717696141a68d2..09e0a40f1c97dffa9be4749ba68f046d70c8ea3b 100644 --- a/lib/Serialization/ASTCommon.h +++ b/lib/Serialization/ASTCommon.h @@ -29,6 +29,7 @@ enum DeclUpdateKind { UPD_CXX_ADDED_FUNCTION_DEFINITION, UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, UPD_CXX_INSTANTIATED_CLASS_DEFINITION, + UPD_CXX_RESOLVED_DTOR_DELETE, UPD_CXX_RESOLVED_EXCEPTION_SPEC, UPD_CXX_DEDUCED_RETURN_TYPE, UPD_DECL_MARKED_USED, diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 5aeb3d1e51739f37dd197bc61e8a7172945696f8..2a01d853c7c4bdf16ed9cf05f9cc75e390a1c34d 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1620,7 +1620,12 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { VisitCXXMethodDecl(D); - D->OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx); + if (auto *OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx)) { + auto *Canon = cast<CXXDestructorDecl>(D->getCanonicalDecl()); + // FIXME: Check consistency if we have an old and new operator delete. + if (!Canon->OperatorDelete) + Canon->OperatorDelete = OperatorDelete; + } } void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { @@ -3621,10 +3626,6 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) std::tie(CD->CtorInitializers, CD->NumCtorInitializers) = Reader.ReadCXXCtorInitializers(ModuleFile, Record, Idx); - if (auto *DD = dyn_cast<CXXDestructorDecl>(FD)) - // FIXME: Check consistency. - DD->setOperatorDelete(Reader.ReadDeclAs<FunctionDecl>(ModuleFile, - Record, Idx)); // Store the offset of the body so we can lazily load it later. Reader.PendingBodies[FD] = GetCurrentCursorOffset(); HasPendingBody = true; @@ -3691,6 +3692,17 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, break; } + case UPD_CXX_RESOLVED_DTOR_DELETE: { + // Set the 'operator delete' directly to avoid emitting another update + // record. + auto *Del = Reader.ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx); + auto *First = cast<CXXDestructorDecl>(D->getCanonicalDecl()); + // FIXME: Check consistency if we have an old and new operator delete. + if (!First->OperatorDelete) + First->OperatorDelete = Del; + break; + } + case UPD_CXX_RESOLVED_EXCEPTION_SPEC: { // FIXME: This doesn't send the right notifications if there are // ASTMutationListeners other than an ASTWriter. diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index f92848ad21f8618eaadb6086a5df1acdde07ab48..2e8e590eb53466c5d6be87e951fbea16a26f962a 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4761,6 +4761,10 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { break; } + case UPD_CXX_RESOLVED_DTOR_DELETE: + AddDeclRef(Update.getDecl(), Record); + break; + case UPD_CXX_RESOLVED_EXCEPTION_SPEC: addExceptionSpec( *this, @@ -4792,8 +4796,6 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { Record.push_back(Def->isInlined()); AddSourceLocation(Def->getInnerLocStart(), Record); AddFunctionDefinition(Def, Record); - if (auto *DD = dyn_cast<CXXDestructorDecl>(Def)) - Record.push_back(GetDeclRef(DD->getOperatorDelete())); } OffsetsRecord.push_back(GetDeclRef(D)); @@ -5810,6 +5812,22 @@ void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) { DeclUpdates[FD].push_back(DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType)); } +void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD, + const FunctionDecl *Delete) { + assert(!WritingAST && "Already writing the AST!"); + assert(Delete && "Not given an operator delete"); + for (auto *D : DD->redecls()) { + if (D->isFromASTFile()) { + // We added an operator delete that some imported destructor didn't + // know about. Add an update record to let importers of us and that + // declaration know about it. + DeclUpdates[DD].push_back( + DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete)); + return; + } + } +} + void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 723f4caea802f5f27a8b13564a298fa458161c19..ee0d21999b37e35b48e67ba99f6d95cd98dcdf87 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -1129,7 +1129,7 @@ void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { VisitCXXMethodDecl(D); - Writer.AddDeclRef(D->OperatorDelete, Record); + Writer.AddDeclRef(D->getOperatorDelete(), Record); Code = serialization::DECL_CXX_DESTRUCTOR; } diff --git a/test/Modules/Inputs/cxx-dtor/a.h b/test/Modules/Inputs/cxx-dtor/a.h new file mode 100644 index 0000000000000000000000000000000000000000..023606eb35a728f5d43f7d1097b9c378e99f9645 --- /dev/null +++ b/test/Modules/Inputs/cxx-dtor/a.h @@ -0,0 +1 @@ +struct X { X(); virtual ~X(); }; diff --git a/test/Modules/Inputs/cxx-dtor/b.h b/test/Modules/Inputs/cxx-dtor/b.h new file mode 100644 index 0000000000000000000000000000000000000000..75958564cc9cc290fb41b07a65d831f4666d2a86 --- /dev/null +++ b/test/Modules/Inputs/cxx-dtor/b.h @@ -0,0 +1,3 @@ +struct X { X(); virtual ~X(); }; +inline X::~X() {} +#include "a.h" diff --git a/test/Modules/Inputs/cxx-dtor/module.modulemap b/test/Modules/Inputs/cxx-dtor/module.modulemap new file mode 100644 index 0000000000000000000000000000000000000000..61578a1865aa520c006d15cf7c174092b914dec7 --- /dev/null +++ b/test/Modules/Inputs/cxx-dtor/module.modulemap @@ -0,0 +1,2 @@ +module a { header "a.h" export * } +module b { header "b.h" export * } diff --git a/test/Modules/cxx-dtor.cpp b/test/Modules/cxx-dtor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ead67ec334e70db2ba0ea123b933e17f2d393662 --- /dev/null +++ b/test/Modules/cxx-dtor.cpp @@ -0,0 +1,3 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 -fmodules-cache-path=%t -I %S/Inputs/cxx-dtor -emit-llvm-only %s +#include "b.h"