From: Richard Smith <richard-llvm@metafoo.co.uk> Date: Thu, 7 Aug 2014 18:53:08 +0000 (+0000) Subject: [modules] When emitting an update record containing the body of a destructor, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ab7091d2d905e5d9de77169a4778264b74922d80;p=clang [modules] When emitting an update record containing the body of a destructor, also emit the updated 'operator delete' looked up for that destructor. Switch from UpdateDecl to an actual update record when this happens due to implicitly defining a special member function and unify this code path and the one for instantiating a function definition. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@215132 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h index c766974926..6090a13439 100644 --- a/lib/Serialization/ASTCommon.h +++ b/lib/Serialization/ASTCommon.h @@ -25,8 +25,8 @@ enum DeclUpdateKind { UPD_CXX_ADDED_IMPLICIT_MEMBER, UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, + UPD_CXX_ADDED_FUNCTION_DEFINITION, UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, - UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION, UPD_CXX_INSTANTIATED_CLASS_DEFINITION, UPD_CXX_RESOLVED_EXCEPTION_SPEC, UPD_CXX_DEDUCED_RETURN_TYPE, diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 441427cc56..078e9c86f2 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -3273,7 +3273,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, Reader.ReadSourceLocation(ModuleFile, Record, Idx)); break; - case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION: { + case UPD_CXX_ADDED_FUNCTION_DEFINITION: { FunctionDecl *FD = cast<FunctionDecl>(D); if (Reader.PendingBodies[FD]) { // FIXME: Maybe check for ODR violations. @@ -3296,6 +3296,10 @@ 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; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 8de1fca05f..baed95ebf8 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4629,17 +4629,17 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { Record.push_back(GetDeclRef(Update.getDecl())); break; - case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: - AddSourceLocation(Update.getLoc(), Record); - break; - - case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION: + case UPD_CXX_ADDED_FUNCTION_DEFINITION: // An updated body is emitted last, so that the reader doesn't need // to skip over the lazy body to reach statements for other records. Record.pop_back(); HasUpdatedBody = true; break; + case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: + AddSourceLocation(Update.getLoc(), Record); + break; + case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: { auto *RD = cast<CXXRecordDecl>(D); AddUpdatedDeclContext(RD->getPrimaryContext()); @@ -4709,10 +4709,12 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { if (HasUpdatedBody) { const FunctionDecl *Def = cast<FunctionDecl>(D); - Record.push_back(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION); + Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION); 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)); @@ -5704,9 +5706,8 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { if (!D->isFromASTFile()) return; // Declaration not imported from PCH. - // Implicit decl from a PCH was defined. - // FIXME: Should implicit definition be a separate FunctionDecl? - RewriteDecl(D); + // Implicit function decl from a PCH was defined. + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { @@ -5714,10 +5715,8 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { if (!D->isFromASTFile()) return; - // Since the actual instantiation is delayed, this really means that we need - // to update the instantiation location. DeclUpdates[D].push_back( - DeclUpdate(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION)); + DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { diff --git a/test/Modules/Inputs/cxx-irgen-left.h b/test/Modules/Inputs/cxx-irgen-left.h index fb36b218a4..31ae805c9a 100644 --- a/test/Modules/Inputs/cxx-irgen-left.h +++ b/test/Modules/Inputs/cxx-irgen-left.h @@ -18,3 +18,9 @@ namespace ImplicitSpecialMembers { C c2(c); D d2(d); } } + +namespace OperatorDeleteLookup { + // Trigger definition of A::~A() and lookup of operator delete. + // Likewise for B<int>::~B(). + inline void f() { A a; B<int> b; } +} diff --git a/test/Modules/Inputs/cxx-irgen-top.h b/test/Modules/Inputs/cxx-irgen-top.h index 0ab586f7ae..43c0b18c77 100644 --- a/test/Modules/Inputs/cxx-irgen-top.h +++ b/test/Modules/Inputs/cxx-irgen-top.h @@ -32,3 +32,9 @@ namespace ImplicitSpecialMembers { D(int); }; } + +namespace OperatorDeleteLookup { + struct A { void operator delete(void*); virtual ~A() = default; }; + template<typename T> struct B { void operator delete(void*); virtual ~B() {} typedef int t; }; + typedef B<int>::t b_int_instantated; +} diff --git a/test/Modules/cxx-irgen.cpp b/test/Modules/cxx-irgen.cpp index 9fb38cedac..7bb1287162 100644 --- a/test/Modules/cxx-irgen.cpp +++ b/test/Modules/cxx-irgen.cpp @@ -18,6 +18,9 @@ int b = h(); // CHECK-DAG: define linkonce_odr {{signext i32|i32}} @_Z3minIiET_S0_S0_(i32 int c = min(1, 2); +// CHECK-LABEL: define {{.*}} @_ZN20OperatorDeleteLookup1AD0Ev( +// CHECK: call void @_ZN20OperatorDeleteLookup1AdlEPv( + namespace ImplicitSpecialMembers { // CHECK-LABEL: define {{.*}} @_ZN22ImplicitSpecialMembers1DC2EOS0_( // CHECK: call {{.*}} @_ZN22ImplicitSpecialMembers1AC1ERKS0_( @@ -45,6 +48,12 @@ namespace ImplicitSpecialMembers { D d3(static_cast<D&&>(d1)); } +namespace OperatorDeleteLookup { + // Trigger emission of B's vtable and deleting dtor. + // This requires us to know what operator delete was selected. + void g() { f(); } +} + // CHECK: define available_externally {{signext i32|i32}} @_ZN1SIiE1fEv({{.*}} #[[ALWAYS_INLINE]] align // CHECK: attributes #[[ALWAYS_INLINE]] = {{.*}} alwaysinline