From: Richard Smith Date: Tue, 10 Mar 2015 01:41:22 +0000 (+0000) Subject: [modules] Don't clobber a destructor's operator delete when adding another one; X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fd6e857ed0f5ab95e16b98b9696880dd39f1e3bb;p=clang [modules] Don't clobber a destructor's operator delete when adding another one; move the operator delete updating into a separate update record so we can cope with updating another module's destructor's operator delete. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@231735 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index 48eb629277..27fdeac6b1 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 ed6e2dc752..a5b44f4e80 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(getFirstDecl())->OperatorDelete = OD; - } + void setOperatorDelete(FunctionDecl *OD); const FunctionDecl *getOperatorDelete() const { return cast(getFirstDecl())->OperatorDelete; } diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 0d7a9c8821..175ee7a3b3 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 87a063438b..82fb2a6950 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(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 3c4fed1d18..0d69f570be 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 88cdbcfe17..09e0a40f1c 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 5aeb3d1e51..2a01d853c7 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(Record, Idx); + if (auto *OperatorDelete = ReadDeclAs(Record, Idx)) { + auto *Canon = cast(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(FD)) std::tie(CD->CtorInitializers, CD->NumCtorInitializers) = Reader.ReadCXXCtorInitializers(ModuleFile, Record, Idx); - if (auto *DD = dyn_cast(FD)) - // FIXME: Check consistency. - DD->setOperatorDelete(Reader.ReadDeclAs(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(ModuleFile, Record, Idx); + auto *First = cast(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 f92848ad21..2e8e590eb5 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(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 723f4caea8..ee0d21999b 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 0000000000..023606eb35 --- /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 0000000000..75958564cc --- /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 0000000000..61578a1865 --- /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 0000000000..ead67ec334 --- /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"