From d9ba5a48cdddf332d3ccb6806c0c9ea03dcea099 Mon Sep 17 00:00:00 2001 From: Richard Smith <richard-llvm@metafoo.co.uk> Date: Wed, 24 Aug 2016 21:25:37 +0000 Subject: [PATCH] PR29097: add an update record when we instantiate the default member initializer of an imported field. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@279667 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTMutationListener.h | 4 ++++ include/clang/Serialization/ASTWriter.h | 1 + lib/Frontend/MultiplexConsumer.cpp | 6 ++++++ lib/Sema/SemaTemplateInstantiate.cpp | 4 ++++ lib/Serialization/ASTCommon.h | 1 + lib/Serialization/ASTReaderDecl.cpp | 17 ++++++++++++++++ lib/Serialization/ASTWriter.cpp | 14 +++++++++++++ test/PCH/cxx1y-default-initializer.cpp | 27 +++++++++++++++++++------ 8 files changed, 68 insertions(+), 6 deletions(-) diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index e2d184d654e..a8eff1a2fcb 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -22,6 +22,7 @@ namespace clang { class CXXRecordDecl; class Decl; class DeclContext; + class FieldDecl; class FunctionDecl; class FunctionTemplateDecl; class Module; @@ -93,6 +94,9 @@ public: /// \brief A default argument was instantiated. virtual void DefaultArgumentInstantiated(const ParmVarDecl *D) {} + /// \brief A default member initializer was instantiated. + virtual void DefaultMemberInitializerInstantiated(const FieldDecl *D) {} + /// \brief A new objc category class was added for an interface. virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) {} diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index ca0cee0574c..b07b36cc1e3 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -674,6 +674,7 @@ private: void CompletedImplicitDefinition(const FunctionDecl *D) override; void StaticDataMemberInstantiated(const VarDecl *D) override; void DefaultArgumentInstantiated(const ParmVarDecl *D) override; + void DefaultMemberInitializerInstantiated(const FieldDecl *D) override; void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) override; diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp index 17cdaee4be0..8ef6df5e740 100644 --- a/lib/Frontend/MultiplexConsumer.cpp +++ b/lib/Frontend/MultiplexConsumer.cpp @@ -120,6 +120,7 @@ public: void CompletedImplicitDefinition(const FunctionDecl *D) override; void StaticDataMemberInstantiated(const VarDecl *D) override; void DefaultArgumentInstantiated(const ParmVarDecl *D) override; + void DefaultMemberInitializerInstantiated(const FieldDecl *D) override; void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) override; void FunctionDefinitionInstantiated(const FunctionDecl *D) override; @@ -201,6 +202,11 @@ void MultiplexASTMutationListener::DefaultArgumentInstantiated( for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DefaultArgumentInstantiated(D); } +void MultiplexASTMutationListener::DefaultMemberInitializerInstantiated( + const FieldDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->DefaultMemberInitializerInstantiated(D); +} void MultiplexASTMutationListener::AddedObjCCategoryToInterface( const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) { diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 7e02586e217..4749962d045 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/Basic/LangOptions.h" @@ -2215,6 +2216,9 @@ bool Sema::InstantiateInClassInitializer( ActOnFinishCXXInClassMemberInitializer( Instantiation, Init ? Init->getLocStart() : SourceLocation(), Init); + if (auto *L = getASTMutationListener()) + L->DefaultMemberInitializerInstantiated(Instantiation); + // Exit the scope of this instantiation. SavedContext.pop(); diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h index 641165e4178..cbc5f04738b 100644 --- a/lib/Serialization/ASTCommon.h +++ b/lib/Serialization/ASTCommon.h @@ -30,6 +30,7 @@ enum DeclUpdateKind { UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, UPD_CXX_INSTANTIATED_CLASS_DEFINITION, UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT, + UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER, UPD_CXX_RESOLVED_DTOR_DELETE, UPD_CXX_RESOLVED_EXCEPTION_SPEC, UPD_CXX_DEDUCED_RETURN_TYPE, diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 209f95a5859..04231cd8e0b 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -3796,6 +3796,23 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, break; } + case UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER: { + auto FD = cast<FieldDecl>(D); + auto DefaultInit = Reader.ReadExpr(F); + + // Only apply the update if the field still has an uninstantiated + // default member initializer. + if (FD->hasInClassInitializer() && !FD->getInClassInitializer()) { + if (DefaultInit) + FD->setInClassInitializer(DefaultInit); + else + // Instantiation failed. We can get here if we serialized an AST for + // an invalid program. + FD->removeInClassInitializer(); + } + break; + } + case UPD_CXX_ADDED_FUNCTION_DEFINITION: { FunctionDecl *FD = cast<FunctionDecl>(D); if (Reader.PendingBodies[FD]) { diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 42e5b35f6d7..72b2bf6d168 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4702,6 +4702,11 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { cast<ParmVarDecl>(Update.getDecl())->getDefaultArg())); break; + case UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER: + Record.AddStmt( + cast<FieldDecl>(Update.getDecl())->getInClassInitializer()); + break; + case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: { auto *RD = cast<CXXRecordDecl>(D); UpdatedDeclContexts.insert(RD->getPrimaryContext()); @@ -5815,6 +5820,15 @@ void ASTWriter::DefaultArgumentInstantiated(const ParmVarDecl *D) { DeclUpdate(UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT, D)); } +void ASTWriter::DefaultMemberInitializerInstantiated(const FieldDecl *D) { + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back( + DeclUpdate(UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER, D)); +} + void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) { if (Chain && Chain->isProcessingUpdateRecords()) return; diff --git a/test/PCH/cxx1y-default-initializer.cpp b/test/PCH/cxx1y-default-initializer.cpp index 1f8d9a5d08d..c9593a56d2e 100644 --- a/test/PCH/cxx1y-default-initializer.cpp +++ b/test/PCH/cxx1y-default-initializer.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -pedantic -std=c++1y %s -o %t -// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch %s -o %t -// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t -verify %s +// RUN: %clang_cc1 -pedantic -std=c++1y -include %s -include %s -verify %s +// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch -o %t.1 %s +// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.1 -emit-pch -o %t.2 %s +// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.2 -verify %s -#ifndef HEADER_INCLUDED - -#define HEADER_INCLUDED +#ifndef HEADER_1 +#define HEADER_1 struct A { int x; @@ -19,6 +19,20 @@ struct B { constexpr B(int k) : z1(k) {} }; +template<typename T> struct C { + constexpr C() {} + T c = T(); + struct U {}; +}; +// Instantiate C<int> but not the default initializer. +C<int>::U ciu; + +#elif !defined(HEADER_2) +#define HEADER_2 + +// Instantiate the default initializer now, should create an update record. +C<int> ci; + #else static_assert(A{}.z == 3, ""); @@ -27,5 +41,6 @@ static_assert(A{.y = 5}.z == 5, ""); // expected-warning {{C99}} static_assert(A{3, .y = 1}.z == 4, ""); // expected-warning {{C99}} static_assert(make<int>().z == 3, ""); static_assert(make<int>(12).z == 15, ""); +static_assert(C<int>().c == 0, ""); #endif -- GitLab