[modules] Deserialize CXXCtorInitializer list for a constructor lazily.

Previously we'd deserialize the list of mem-initializers for a constructor when
we deserialized the declaration of the constructor. That could trigger a
significant amount of unnecessary work (pulling in all base classes
recursively, for a start) and was causing problems for the modules buildbot due
to cyclic deserializations. We now deserialize these on demand.

This creates a certain amount of duplication with the handling of
CXXBaseSpecifiers; I'll look into reducing that next.

llvm-svn: 233052
This commit is contained in:
Richard Smith 2015-03-24 06:36:48 +00:00
parent 20f3da11e8
commit c2bb81860b
18 changed files with 362 additions and 140 deletions

View File

@ -2149,7 +2149,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
/// \name Support for base and member initializers.
/// \{
/// \brief The arguments used to initialize the base or member.
CXXCtorInitializer **CtorInitializers;
LazyCXXCtorInitializersPtr CtorInitializers;
unsigned NumCtorInitializers;
/// \}
@ -2188,7 +2188,7 @@ public:
typedef CXXCtorInitializer **init_iterator;
/// \brief Iterates through the member/base initializer list.
typedef CXXCtorInitializer * const * init_const_iterator;
typedef CXXCtorInitializer *const *init_const_iterator;
typedef llvm::iterator_range<init_iterator> init_range;
typedef llvm::iterator_range<init_const_iterator> init_const_range;
@ -2199,17 +2199,20 @@ public:
}
/// \brief Retrieve an iterator to the first initializer.
init_iterator init_begin() { return CtorInitializers; }
init_iterator init_begin() {
const auto *ConstThis = this;
return const_cast<init_iterator>(ConstThis->init_begin());
}
/// \brief Retrieve an iterator to the first initializer.
init_const_iterator init_begin() const { return CtorInitializers; }
init_const_iterator init_begin() const;
/// \brief Retrieve an iterator past the last initializer.
init_iterator init_end() {
return CtorInitializers + NumCtorInitializers;
return init_begin() + NumCtorInitializers;
}
/// \brief Retrieve an iterator past the last initializer.
init_const_iterator init_end() const {
return CtorInitializers + NumCtorInitializers;
return init_begin() + NumCtorInitializers;
}
typedef std::reverse_iterator<init_iterator> init_reverse_iterator;
@ -2240,14 +2243,14 @@ public:
NumCtorInitializers = numCtorInitializers;
}
void setCtorInitializers(CXXCtorInitializer ** initializers) {
CtorInitializers = initializers;
void setCtorInitializers(CXXCtorInitializer **Initializers) {
CtorInitializers = Initializers;
}
/// \brief Determine whether this constructor is a delegating constructor.
bool isDelegatingConstructor() const {
return (getNumCtorInitializers() == 1) &&
CtorInitializers[0]->isDelegatingInitializer();
init_begin()[0]->isDelegatingInitializer();
}
/// \brief When this constructor delegates to another, retrieve the target.

View File

@ -2002,8 +2002,8 @@ class ObjCImplementationDecl : public ObjCImplDecl {
SourceLocation IvarRBraceLoc;
/// Support for ivar initialization.
/// IvarInitializers - The arguments used to initialize the ivars
CXXCtorInitializer **IvarInitializers;
/// \brief The arguments used to initialize the ivars
LazyCXXCtorInitializersPtr IvarInitializers;
unsigned NumIvarInitializers;
/// Do the ivars of this class require initialization other than
@ -2052,17 +2052,20 @@ public:
}
/// init_begin() - Retrieve an iterator to the first initializer.
init_iterator init_begin() { return IvarInitializers; }
init_iterator init_begin() {
const auto *ConstThis = this;
return const_cast<init_iterator>(ConstThis->init_begin());
}
/// begin() - Retrieve an iterator to the first initializer.
init_const_iterator init_begin() const { return IvarInitializers; }
init_const_iterator init_begin() const;
/// init_end() - Retrieve an iterator past the last initializer.
init_iterator init_end() {
return IvarInitializers + NumIvarInitializers;
return init_begin() + NumIvarInitializers;
}
/// end() - Retrieve an iterator past the last initializer.
init_const_iterator init_end() const {
return IvarInitializers + NumIvarInitializers;
return init_begin() + NumIvarInitializers;
}
/// getNumArgs - Number of ivars which must be initialized.
unsigned getNumIvarInitializers() const {

View File

@ -22,6 +22,7 @@ namespace clang {
class ASTConsumer;
class CXXBaseSpecifier;
class CXXCtorInitializer;
class DeclarationName;
class ExternalSemaSource; // layering violation required for downcasting
class FieldDecl;
@ -121,6 +122,12 @@ public:
/// The default implementation of this method is a no-op.
virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
/// \brief Resolve the offset of a set of C++ constructor initializers in
/// the decl stream into an array of initializers.
///
/// The default implementation of this method is a no-op.
virtual CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset);
/// \brief Resolve the offset of a set of C++ base specifiers in the decl
/// stream into an array of specifiers.
///
@ -553,8 +560,13 @@ typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>
typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>
LazyDeclPtr;
/// \brief A lazy pointer to a set of CXXCtorInitializers.
typedef LazyOffsetPtr<CXXCtorInitializer *, uint64_t,
&ExternalASTSource::GetExternalCXXCtorInitializers>
LazyCXXCtorInitializersPtr;
/// \brief A lazy pointer to a set of CXXBaseSpecifiers.
typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
&ExternalASTSource::GetExternalCXXBaseSpecifiers>
LazyCXXBaseSpecifiersPtr;

View File

@ -86,10 +86,14 @@ public:
/// stream into an array of specifiers.
CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override;
/// \brief Resolve a handle to a list of ctor initializers into the list of
/// initializers themselves.
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
/// \brief Find all declarations with the given name in the
/// given context.
bool
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override;
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;
/// \brief Ensures that the table of all visible declarations inside this
/// context is up to date.

View File

@ -149,7 +149,11 @@ namespace clang {
/// \brief An ID number that refers to a set of CXXBaseSpecifiers in an
/// AST file.
typedef uint32_t CXXBaseSpecifiersID;
/// \brief An ID number that refers to a list of CXXCtorInitializers in an
/// AST file.
typedef uint32_t CXXCtorInitializersID;
/// \brief An ID number that refers to an entity in the detailed
/// preprocessing record.
typedef uint32_t PreprocessedEntityID;
@ -555,6 +559,10 @@ namespace clang {
/// \brief Record code for potentially unused local typedef names.
UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES = 52,
/// \brief Record code for the table of offsets to CXXCtorInitializers
/// lists.
CXX_CTOR_INITIALIZERS_OFFSETS = 53,
};
/// \brief Record types used within a source manager block.
@ -1074,6 +1082,8 @@ namespace clang {
DECL_STATIC_ASSERT,
/// \brief A record containing CXXBaseSpecifiers.
DECL_CXX_BASE_SPECIFIERS,
/// \brief A record containing CXXCtorInitializers.
DECL_CXX_CTOR_INITIALIZERS,
/// \brief A IndirectFieldDecl record.
DECL_INDIRECTFIELD,
/// \brief A NonTypeTemplateParmDecl record that stores an expanded

View File

@ -943,9 +943,6 @@ private:
/// passing decls to consumer.
bool PassingDeclsToConsumer;
/// Number of CXX base specifiers currently loaded
unsigned NumCXXBaseSpecifiersLoaded;
/// \brief The set of identifiers that were read while the AST reader was
/// (recursively) loading declarations.
///
@ -1583,11 +1580,6 @@ public:
return Result;
}
/// \brief Returns the number of C++ base specifiers found in the chain.
unsigned getTotalNumCXXBaseSpecifiers() const {
return NumCXXBaseSpecifiersLoaded;
}
/// \brief Reads a TemplateArgumentLocInfo appropriate for the
/// given TemplateArgument kind.
TemplateArgumentLocInfo
@ -1993,10 +1985,18 @@ public:
const RecordData &Record,unsigned &Idx);
/// \brief Read a CXXCtorInitializer array.
std::pair<CXXCtorInitializer **, unsigned>
CXXCtorInitializer **
ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
unsigned &Idx);
/// \brief Read a CXXCtorInitializers ID from the given record and
/// return its global bit offset.
uint64_t ReadCXXCtorInitializersRef(ModuleFile &M, const RecordData &Record,
unsigned &Idx);
/// \brief Read the contents of a CXXCtorInitializer array.
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
/// \brief Read a source location from raw form.
SourceLocation ReadSourceLocation(ModuleFile &ModuleFile, unsigned Raw) const {
SourceLocation Loc = SourceLocation::getFromRawEncoding(Raw);

View File

@ -415,7 +415,7 @@ private:
unsigned NumVisibleDeclContexts;
/// \brief The offset of each CXXBaseSpecifier set within the AST.
SmallVector<uint32_t, 4> CXXBaseSpecifiersOffsets;
SmallVector<uint32_t, 16> CXXBaseSpecifiersOffsets;
/// \brief The first ID number we can use for our own base specifiers.
serialization::CXXBaseSpecifiersID FirstCXXBaseSpecifiersID;
@ -443,6 +443,33 @@ private:
/// in the order they should be written.
SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite;
/// \brief The offset of each CXXCtorInitializer list within the AST.
SmallVector<uint32_t, 16> CXXCtorInitializersOffsets;
/// \brief The first ID number we can use for our own ctor initializers.
serialization::CXXCtorInitializersID FirstCXXCtorInitializersID;
/// \brief The ctor initializers ID that will be assigned to the next new
/// list of C++ ctor initializers.
serialization::CXXCtorInitializersID NextCXXCtorInitializersID;
/// \brief A set of C++ ctor initializers that is queued to be written
/// into the AST file.
struct QueuedCXXCtorInitializers {
QueuedCXXCtorInitializers() : ID() {}
QueuedCXXCtorInitializers(serialization::CXXCtorInitializersID ID,
ArrayRef<CXXCtorInitializer*> Inits)
: ID(ID), Inits(Inits) {}
serialization::CXXCtorInitializersID ID;
ArrayRef<CXXCtorInitializer*> Inits;
};
/// \brief Queue of C++ ctor initializers to be written to the AST file,
/// in the order they should be written.
SmallVector<QueuedCXXCtorInitializers, 2> CXXCtorInitializersToWrite;
/// \brief A mapping from each known submodule to its ID number, which will
/// be a positive integer.
llvm::DenseMap<Module *, unsigned> SubmoduleIDs;
@ -471,6 +498,7 @@ private:
void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
bool isModule);
void WriteCXXBaseSpecifiersOffsets();
void WriteCXXCtorInitializersOffsets();
unsigned TypeExtQualAbbrev;
unsigned TypeFunctionProtoAbbrev;
@ -675,6 +703,11 @@ public:
void AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
RecordDataImpl &Record);
/// \brief Emit the ID for a CXXCtorInitializer array and register the array
/// for later serialization.
void AddCXXCtorInitializersRef(ArrayRef<CXXCtorInitializer *> Inits,
RecordDataImpl &Record);
/// \brief Emit a CXXCtorInitializer array.
void AddCXXCtorInitializers(
const CXXCtorInitializer * const *CtorInitializers,
@ -747,6 +780,18 @@ public:
/// via \c AddCXXBaseSpecifiersRef().
void FlushCXXBaseSpecifiers();
/// \brief Flush all of the C++ constructor initializer lists that have been
/// added via \c AddCXXCtorInitializersRef().
void FlushCXXCtorInitializers();
/// \brief Flush all pending records that are tacked onto the end of
/// decl and decl update records.
void FlushPendingAfterDecl() {
FlushStmts();
FlushCXXBaseSpecifiers();
FlushCXXCtorInitializers();
}
/// \brief Record an ID for the given switch-case statement.
unsigned RecordSwitchCaseID(SwitchCase *S);

View File

@ -404,6 +404,13 @@ public:
/// indexed by the C++ base specifier set ID (-1).
const uint32_t *CXXBaseSpecifiersOffsets;
/// \brief The number of C++ ctor initializer lists in this AST file.
unsigned LocalNumCXXCtorInitializers;
/// \brief Offset of each C++ ctor initializer list within the bitstream,
/// indexed by the C++ ctor initializer list ID minus 1.
const uint32_t *CXXCtorInitializersOffsets;
typedef llvm::DenseMap<const DeclContext *, DeclContextInfo>
DeclContextInfosMap;

View File

@ -1739,6 +1739,10 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
isImplicitlyDeclared, isConstexpr);
}
CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
return CtorInitializers.get(getASTContext().getExternalSource());
}
CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const {
assert(isDelegatingConstructor() && "Not a delegating constructor!");
Expr *E = (*init_begin())->getInit()->IgnoreImplicit();

View File

@ -1820,6 +1820,11 @@ void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
}
}
ObjCImplementationDecl::init_const_iterator
ObjCImplementationDecl::init_begin() const {
return IvarInitializers.get(getASTContext().getExternalSource());
}
raw_ostream &clang::operator<<(raw_ostream &OS,
const ObjCImplementationDecl &ID) {
OS << ID.getName();

View File

@ -66,6 +66,11 @@ Stmt *ExternalASTSource::GetExternalDeclStmt(uint64_t Offset) {
return nullptr;
}
CXXCtorInitializer **
ExternalASTSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
return nullptr;
}
CXXBaseSpecifier *
ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return nullptr;

View File

@ -43,6 +43,7 @@ protected:
Selector GetExternalSelector(uint32_t ID) override;
uint32_t GetNumExternalSelectors() override;
Stmt *GetExternalDeclStmt(uint64_t Offset) override;
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override;
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;
@ -232,6 +233,10 @@ CXXBaseSpecifier *
ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
}
CXXCtorInitializer **
ChainedIncludesSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
return getFinalReader().GetExternalCXXCtorInitializers(Offset);
}
bool
ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {

View File

@ -86,6 +86,14 @@ CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers(
return nullptr;
}
CXXCtorInitializer **
MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
for (auto *S : Sources)
if (auto *R = S->GetExternalCXXCtorInitializers(Offset))
return R;
return nullptr;
}
bool MultiplexExternalSemaSource::
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
bool AnyDeclsFound = false;

View File

@ -3204,16 +3204,26 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
case OBJC_CATEGORIES:
F.ObjCCategories.swap(Record);
break;
case CXX_BASE_SPECIFIER_OFFSETS: {
if (F.LocalNumCXXBaseSpecifiers != 0) {
Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
return Failure;
}
F.LocalNumCXXBaseSpecifiers = Record[0];
F.CXXBaseSpecifiersOffsets = (const uint32_t *)Blob.data();
NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers;
break;
}
case CXX_CTOR_INITIALIZERS_OFFSETS: {
if (F.LocalNumCXXCtorInitializers != 0) {
Error("duplicate CXX_CTOR_INITIALIZERS_OFFSETS record in AST file");
return Failure;
}
F.LocalNumCXXCtorInitializers = Record[0];
F.CXXCtorInitializersOffsets = (const uint32_t *)Blob.data();
break;
}
@ -6187,6 +6197,38 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
}
}
uint64_t ASTReader::ReadCXXCtorInitializersRef(ModuleFile &M,
const RecordData &Record,
unsigned &Idx) {
if (Idx >= Record.size() || Record[Idx] > M.LocalNumCXXCtorInitializers) {
Error("malformed AST file: missing C++ ctor initializers");
return 0;
}
unsigned LocalID = Record[Idx++];
return getGlobalBitOffset(M, M.CXXCtorInitializersOffsets[LocalID - 1]);
}
CXXCtorInitializer **
ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) {
RecordLocation Loc = getLocalBitOffset(Offset);
BitstreamCursor &Cursor = Loc.F->DeclsCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(Loc.Offset);
ReadingKindTracker ReadingKind(Read_Decl, *this);
RecordData Record;
unsigned Code = Cursor.ReadCode();
unsigned RecCode = Cursor.readRecord(Code, Record);
if (RecCode != DECL_CXX_CTOR_INITIALIZERS) {
Error("malformed AST file: missing C++ ctor initializers");
return nullptr;
}
unsigned Idx = 0;
return ReadCXXCtorInitializers(*Loc.F, Record, Idx);
}
uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M,
const RecordData &Record,
unsigned &Idx) {
@ -7918,92 +7960,89 @@ ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
return Result;
}
std::pair<CXXCtorInitializer **, unsigned>
CXXCtorInitializer **
ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
CXXCtorInitializer **CtorInitializers = nullptr;
unsigned NumInitializers = Record[Idx++];
if (NumInitializers) {
CtorInitializers
= new (Context) CXXCtorInitializer*[NumInitializers];
for (unsigned i=0; i != NumInitializers; ++i) {
TypeSourceInfo *TInfo = nullptr;
bool IsBaseVirtual = false;
FieldDecl *Member = nullptr;
IndirectFieldDecl *IndirectMember = nullptr;
assert(NumInitializers && "wrote ctor initializers but have no inits");
auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers];
for (unsigned i = 0; i != NumInitializers; ++i) {
TypeSourceInfo *TInfo = nullptr;
bool IsBaseVirtual = false;
FieldDecl *Member = nullptr;
IndirectFieldDecl *IndirectMember = nullptr;
CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
switch (Type) {
case CTOR_INITIALIZER_BASE:
TInfo = GetTypeSourceInfo(F, Record, Idx);
IsBaseVirtual = Record[Idx++];
break;
case CTOR_INITIALIZER_DELEGATING:
TInfo = GetTypeSourceInfo(F, Record, Idx);
break;
CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
switch (Type) {
case CTOR_INITIALIZER_BASE:
TInfo = GetTypeSourceInfo(F, Record, Idx);
IsBaseVirtual = Record[Idx++];
break;
case CTOR_INITIALIZER_MEMBER:
Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
break;
case CTOR_INITIALIZER_DELEGATING:
TInfo = GetTypeSourceInfo(F, Record, Idx);
break;
case CTOR_INITIALIZER_INDIRECT_MEMBER:
IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
break;
}
case CTOR_INITIALIZER_MEMBER:
Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
break;
SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
Expr *Init = ReadExpr(F);
SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
bool IsWritten = Record[Idx++];
unsigned SourceOrderOrNumArrayIndices;
SmallVector<VarDecl *, 8> Indices;
if (IsWritten) {
SourceOrderOrNumArrayIndices = Record[Idx++];
} else {
SourceOrderOrNumArrayIndices = Record[Idx++];
Indices.reserve(SourceOrderOrNumArrayIndices);
for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
}
CXXCtorInitializer *BOMInit;
if (Type == CTOR_INITIALIZER_BASE) {
BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual,
LParenLoc, Init, RParenLoc,
MemberOrEllipsisLoc);
} else if (Type == CTOR_INITIALIZER_DELEGATING) {
BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc,
Init, RParenLoc);
} else if (IsWritten) {
if (Member)
BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc,
LParenLoc, Init, RParenLoc);
else
BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
MemberOrEllipsisLoc, LParenLoc,
Init, RParenLoc);
} else {
if (IndirectMember) {
assert(Indices.empty() && "Indirect field improperly initialized");
BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
MemberOrEllipsisLoc, LParenLoc,
Init, RParenLoc);
} else {
BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc,
LParenLoc, Init, RParenLoc,
Indices.data(), Indices.size());
}
}
if (IsWritten)
BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices);
CtorInitializers[i] = BOMInit;
case CTOR_INITIALIZER_INDIRECT_MEMBER:
IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
break;
}
SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
Expr *Init = ReadExpr(F);
SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
bool IsWritten = Record[Idx++];
unsigned SourceOrderOrNumArrayIndices;
SmallVector<VarDecl *, 8> Indices;
if (IsWritten) {
SourceOrderOrNumArrayIndices = Record[Idx++];
} else {
SourceOrderOrNumArrayIndices = Record[Idx++];
Indices.reserve(SourceOrderOrNumArrayIndices);
for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
}
CXXCtorInitializer *BOMInit;
if (Type == CTOR_INITIALIZER_BASE) {
BOMInit = new (Context)
CXXCtorInitializer(Context, TInfo, IsBaseVirtual, LParenLoc, Init,
RParenLoc, MemberOrEllipsisLoc);
} else if (Type == CTOR_INITIALIZER_DELEGATING) {
BOMInit = new (Context)
CXXCtorInitializer(Context, TInfo, LParenLoc, Init, RParenLoc);
} else if (IsWritten) {
if (Member)
BOMInit = new (Context) CXXCtorInitializer(
Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc);
else
BOMInit = new (Context)
CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
LParenLoc, Init, RParenLoc);
} else {
if (IndirectMember) {
assert(Indices.empty() && "Indirect field improperly initialized");
BOMInit = new (Context)
CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
LParenLoc, Init, RParenLoc);
} else {
BOMInit = CXXCtorInitializer::Create(
Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc,
Indices.data(), Indices.size());
}
}
if (IsWritten)
BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices);
CtorInitializers[i] = BOMInit;
}
return std::make_pair(CtorInitializers, NumInitializers);
return CtorInitializers;
}
NestedNameSpecifier *
@ -8680,8 +8719,7 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot,
NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
PassingDeclsToConsumer(false), NumCXXBaseSpecifiersLoaded(0),
ReadingKind(Read_None) {
PassingDeclsToConsumer(false), ReadingKind(Read_None) {
SourceMgr.setExternalSLocEntrySource(this);
}

View File

@ -405,6 +405,12 @@ void ASTDeclReader::Visit(Decl *D) {
// module).
// FIXME: Can we diagnose ODR violations somehow?
if (Record[Idx++]) {
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
CD->NumCtorInitializers = Record[Idx++];
if (CD->NumCtorInitializers)
CD->CtorInitializers =
Reader.ReadCXXCtorInitializersRef(F, Record, Idx);
}
Reader.PendingBodies[FD] = GetCurrentCursorOffset();
HasPendingBody = true;
}
@ -992,8 +998,9 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
D->setHasNonZeroConstructors(Record[Idx++]);
D->setHasDestructors(Record[Idx++]);
std::tie(D->IvarInitializers, D->NumIvarInitializers) =
Reader.ReadCXXCtorInitializers(F, Record, Idx);
D->NumIvarInitializers = Record[Idx++];
if (D->NumIvarInitializers)
D->IvarInitializers = Reader.ReadCXXCtorInitializersRef(F, Record, Idx);
}
@ -1623,9 +1630,6 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
if (D->isCanonicalDecl())
D->setInheritedConstructor(CD);
D->IsExplicitSpecified = Record[Idx++];
// FIXME: We should defer loading this until we need the constructor's body.
std::tie(D->CtorInitializers, D->NumCtorInitializers) =
Reader.ReadCXXCtorInitializers(F, Record, Idx);
}
void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
@ -3146,6 +3150,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_CXX_BASE_SPECIFIERS:
Error("attempt to read a C++ base-specifier record as a declaration");
return nullptr;
case DECL_CXX_CTOR_INITIALIZERS:
Error("attempt to read a C++ ctor initializer record as a declaration");
return nullptr;
case DECL_IMPORT:
// Note: last entry of the ImportDecl record is the number of stored source
// locations.
@ -3649,9 +3656,12 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
});
}
FD->setInnerLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
std::tie(CD->CtorInitializers, CD->NumCtorInitializers) =
Reader.ReadCXXCtorInitializers(ModuleFile, Record, Idx);
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
CD->NumCtorInitializers = Record[Idx++];
if (CD->NumCtorInitializers)
CD->CtorInitializers =
Reader.ReadCXXCtorInitializersRef(F, Record, Idx);
}
// Store the offset of the body so we can lazily load it later.
Reader.PendingBodies[FD] = GetCurrentCursorOffset();
HasPendingBody = true;

View File

@ -2694,6 +2694,29 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record);
}
void ASTWriter::WriteCXXCtorInitializersOffsets() {
if (CXXCtorInitializersOffsets.empty())
return;
RecordData Record;
// Create a blob abbreviation for the C++ ctor initializer offsets.
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(CXX_CTOR_INITIALIZERS_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned CtorInitializersOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
// Write the base specifier offsets table.
Record.clear();
Record.push_back(CXX_CTOR_INITIALIZERS_OFFSETS);
Record.push_back(CXXCtorInitializersOffsets.size());
Stream.EmitRecordWithBlob(CtorInitializersOffsetAbbrev, Record,
data(CXXCtorInitializersOffsets));
}
void ASTWriter::WriteCXXBaseSpecifiersOffsets() {
if (CXXBaseSpecifiersOffsets.empty())
return;
@ -4154,7 +4177,8 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0),
NumLexicalDeclContexts(0), NumVisibleDeclContexts(0),
NextCXXBaseSpecifiersID(1), TypeExtQualAbbrev(0),
NextCXXBaseSpecifiersID(1), NextCXXCtorInitializersID(1),
TypeExtQualAbbrev(0),
TypeFunctionProtoAbbrev(0), DeclParmVarAbbrev(0),
DeclContextLexicalAbbrev(0), DeclContextVisibleLookupAbbrev(0),
UpdateVisibleAbbrev(0), DeclRecordAbbrev(0), DeclTypedefAbbrev(0),
@ -4559,6 +4583,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
if (!DeclUpdatesOffsetsRecord.empty())
Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord);
WriteCXXBaseSpecifiersOffsets();
WriteCXXCtorInitializersOffsets();
WriteFileDeclIDsMap();
WriteSourceManagerBlock(Context.getSourceManager(), PP);
@ -4818,11 +4843,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
Stream.EmitRecord(DECL_UPDATES, Record);
// Flush any statements that were written as part of this update record.
FlushStmts();
// Flush C++ base specifiers, if there are any.
FlushCXXBaseSpecifiers();
FlushPendingAfterDecl();
}
}
@ -4934,8 +4955,16 @@ void ASTWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordDataImpl &Record
AddDeclRef(Temp->getDestructor(), Record);
}
void ASTWriter::AddCXXCtorInitializersRef(ArrayRef<CXXCtorInitializer *> Inits,
RecordDataImpl &Record) {
assert(!Inits.empty() && "Empty ctor initializer sets are not recorded");
CXXCtorInitializersToWrite.push_back(
QueuedCXXCtorInitializers(NextCXXCtorInitializersID, Inits));
Record.push_back(NextCXXCtorInitializersID++);
}
void ASTWriter::AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases,
CXXBaseSpecifier const *BasesEnd,
CXXBaseSpecifier const *BasesEnd,
RecordDataImpl &Record) {
assert(Bases != BasesEnd && "Empty base-specifier sets are not recorded");
CXXBaseSpecifiersToWrite.push_back(
@ -5496,7 +5525,8 @@ void ASTWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
void ASTWriter::FlushCXXBaseSpecifiers() {
RecordData Record;
for (unsigned I = 0, N = CXXBaseSpecifiersToWrite.size(); I != N; ++I) {
unsigned N = CXXBaseSpecifiersToWrite.size();
for (unsigned I = 0; I != N; ++I) {
Record.clear();
// Record the offset of this base-specifier set.
@ -5520,6 +5550,8 @@ void ASTWriter::FlushCXXBaseSpecifiers() {
FlushStmts();
}
assert(N == CXXBaseSpecifiersToWrite.size() &&
"added more base specifiers while writing base specifiers");
CXXBaseSpecifiersToWrite.clear();
}
@ -5561,6 +5593,35 @@ void ASTWriter::AddCXXCtorInitializers(
}
}
void ASTWriter::FlushCXXCtorInitializers() {
RecordData Record;
unsigned N = CXXCtorInitializersToWrite.size();
for (auto &Init : CXXCtorInitializersToWrite) {
Record.clear();
// Record the offset of this mem-initializer list.
unsigned Index = Init.ID - 1;
if (Index == CXXCtorInitializersOffsets.size())
CXXCtorInitializersOffsets.push_back(Stream.GetCurrentBitNo());
else {
if (Index > CXXCtorInitializersOffsets.size())
CXXCtorInitializersOffsets.resize(Index + 1);
CXXCtorInitializersOffsets[Index] = Stream.GetCurrentBitNo();
}
AddCXXCtorInitializers(Init.Inits.data(), Init.Inits.size(), Record);
Stream.EmitRecord(serialization::DECL_CXX_CTOR_INITIALIZERS, Record);
// Flush any expressions that were written as part of the initializers.
FlushStmts();
}
assert(N == CXXCtorInitializersToWrite.size() &&
"added more ctor initializers while writing ctor initializers");
CXXCtorInitializersToWrite.clear();
}
void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record) {
auto &Data = D->data();
Record.push_back(Data.IsLambda);

View File

@ -133,9 +133,12 @@ namespace clang {
void AddFunctionDefinition(const FunctionDecl *FD) {
assert(FD->doesThisDeclarationHaveABody());
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
Writer.AddCXXCtorInitializers(CD->CtorInitializers,
CD->NumCtorInitializers, Record);
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
Record.push_back(CD->NumCtorInitializers);
if (CD->NumCtorInitializers)
Writer.AddCXXCtorInitializersRef(
llvm::makeArrayRef(CD->init_begin(), CD->init_end()), Record);
}
Writer.AddStmt(FD->getBody());
}
@ -209,7 +212,7 @@ void ASTDeclWriter::Visit(Decl *D) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Record.push_back(FD->doesThisDeclarationHaveABody());
if (FD->doesThisDeclarationHaveABody())
Writer.AddStmt(FD->getBody());
AddFunctionDefinition(FD);
}
}
@ -711,8 +714,10 @@ void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
Record.push_back(D->hasNonZeroConstructors());
Record.push_back(D->hasDestructors());
Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers,
Record);
Record.push_back(D->NumIvarInitializers);
if (D->NumIvarInitializers)
Writer.AddCXXCtorInitializersRef(
llvm::makeArrayRef(D->init_begin(), D->init_end()), Record);
Code = serialization::DECL_OBJC_IMPLEMENTATION;
}
@ -1120,8 +1125,6 @@ void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
Writer.AddDeclRef(D->getInheritedConstructor(), Record);
Record.push_back(D->IsExplicitSpecified);
Writer.AddCXXCtorInitializers(D->CtorInitializers, D->NumCtorInitializers,
Record);
Code = serialization::DECL_CXX_CONSTRUCTOR;
}
@ -2066,12 +2069,10 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
D->getDeclKindName() + "'");
Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
// Flush any expressions that were written as part of this declaration.
FlushStmts();
// Flush C++ base specifiers, if there are any.
FlushCXXBaseSpecifiers();
// Flush any expressions, base specifiers, and ctor initializers that
// were written as part of this declaration.
FlushPendingAfterDecl();
// Note declarations that should be deserialized eagerly so that we can add
// them to a record in the AST file later.
if (isRequiredDecl(D, Context))

View File

@ -38,6 +38,7 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
SelectorLookupTableData(nullptr), SelectorLookupTable(nullptr),
LocalNumDecls(0), DeclOffsets(nullptr), BaseDeclID(0),
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(nullptr),
LocalNumCXXCtorInitializers(0), CXXCtorInitializersOffsets(nullptr),
FileSortedDecls(nullptr), NumFileSortedDecls(0),
RedeclarationsMap(nullptr), LocalNumRedeclarationsInMap(0),
ObjCCategoriesMap(nullptr), LocalNumObjCCategoriesInMap(0),