/// containing an object.
bool HasObjectMember : 1;
+ /// \brief Whether the field declarations of this record have been loaded
+ /// from external storage. To avoid unnecessary deserialization of
+ /// methods/nested types we allow deserialization of just the fields
+ /// when needed.
+ mutable bool LoadedFieldsFromExternalStorage : 1;
+ friend void DeclContext::LoadLexicalDeclsFromExternalStorage() const;
+
protected:
RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
// data members, functions, constructors, destructors, etc.
typedef specific_decl_iterator<FieldDecl> field_iterator;
- field_iterator field_begin() const {
- return field_iterator(decls_begin());
- }
+ field_iterator field_begin() const;
+
field_iterator field_end() const {
- return field_iterator(decls_end());
+ return field_iterator(decl_iterator());
}
// field_empty - Whether there are any fields (non-static data
static bool classofKind(Kind K) {
return K >= firstRecord && K <= lastRecord;
}
+
+private:
+ /// \brief Deserialize just the fields.
+ void LoadFieldsFromExternalStorage() const;
};
class FileScopeAsmDecl : public Decl {
/// dependent context).
mutable StoredDeclsMap *LookupPtr;
+protected:
/// FirstDecl - The first declaration stored within this declaration
/// context.
mutable Decl *FirstDecl;
friend class ExternalASTSource;
-protected:
+ /// \brief Build up a chain of declarations.
+ ///
+ /// \returns the first/last pair of declarations.
+ static std::pair<Decl *, Decl *>
+ BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls);
+
DeclContext(Decl::Kind K)
: DeclKind(K), ExternalLexicalStorage(false),
ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+#include "clang/AST/DeclBase.h"
#include <cassert>
#include <vector>
virtual void MaterializeVisibleDecls(const DeclContext *DC) = 0;
/// \brief Finds all declarations lexically contained within the given
- /// DeclContext.
+ /// DeclContext, after applying an optional filter predicate.
+ ///
+ /// \param isKindWeWant a predicate function that returns true if the passed
+ /// declaration kind is one we are looking for. If NULL, all declarations
+ /// are returned.
///
/// \return true if an error occurred
virtual bool FindExternalLexicalDecls(const DeclContext *DC,
- llvm::SmallVectorImpl<Decl*> &Result) = 0;
+ bool (*isKindWeWant)(Decl::Kind),
+ llvm::SmallVectorImpl<Decl*> &Result) = 0;
+
+ /// \brief Finds all declarations lexically contained within the given
+ /// DeclContext.
+ ///
+ /// \return true if an error occurred
+ bool FindExternalLexicalDecls(const DeclContext *DC,
+ llvm::SmallVectorImpl<Decl*> &Result) {
+ return FindExternalLexicalDecls(DC, 0, Result);
+ }
+
+ template <typename DeclTy>
+ bool FindExternalLexicalDeclsBy(const DeclContext *DC,
+ llvm::SmallVectorImpl<Decl*> &Result) {
+ return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
+ }
/// \brief Notify ExternalASTSource that we started deserialization of
/// a decl or type so until FinishedDeserializing is called there may be
/// reserved for the translation unit declaration.
typedef uint32_t DeclID;
+ /// \brief a Decl::Kind/DeclID pair.
+ typedef std::pair<uint32_t, DeclID> KindDeclIDPair;
+
/// \brief An ID number that refers to a type in an AST file.
///
/// The ID of a type is partitioned into two parts: the lower
/// \brief Information about the contents of a DeclContext.
struct DeclContextInfo {
void *NameLookupTableData; // a ASTDeclContextNameLookupTable.
- const serialization::DeclID *LexicalDecls;
+ const serialization::KindDeclIDPair *LexicalDecls;
unsigned NumLexicalDecls;
};
// In a full chain, there could be multiple updates to every decl context,
/// \returns true if there was an error while reading the
/// declarations for this declaration context.
virtual bool FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
llvm::SmallVectorImpl<Decl*> &Decls);
/// \brief Notify ASTReader that we started deserialization of
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
HasObjectMember = false;
+ LoadedFieldsFromExternalStorage = false;
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
}
cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName();
}
+RecordDecl::field_iterator RecordDecl::field_begin() const {
+ if (hasExternalLexicalStorage() && !LoadedFieldsFromExternalStorage)
+ LoadFieldsFromExternalStorage();
+
+ return field_iterator(decl_iterator(FirstDecl));
+}
+
/// completeDefinition - Notes that the definition of this type is now
/// complete.
void RecordDecl::completeDefinition() {
return D;
}
+void RecordDecl::LoadFieldsFromExternalStorage() const {
+ ExternalASTSource *Source = getASTContext().getExternalSource();
+ assert(hasExternalLexicalStorage() && Source && "No external storage?");
+
+ // Notify that we have a RecordDecl doing some initialization.
+ ExternalASTSource::Deserializing TheFields(Source);
+
+ llvm::SmallVector<Decl*, 64> Decls;
+ if (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls))
+ return;
+
+#ifndef NDEBUG
+ // Check that all decls we got were FieldDecls.
+ for (unsigned i=0, e=Decls.size(); i != e; ++i)
+ assert(isa<FieldDecl>(Decls[i]));
+#endif
+
+ LoadedFieldsFromExternalStorage = true;
+
+ if (Decls.empty())
+ return;
+
+ llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls);
+}
+
//===----------------------------------------------------------------------===//
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
}
}
+std::pair<Decl *, Decl *>
+DeclContext::BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls) {
+ // Build up a chain of declarations via the Decl::NextDeclInContext field.
+ Decl *FirstNewDecl = 0;
+ Decl *PrevDecl = 0;
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+ Decl *D = Decls[I];
+ if (PrevDecl)
+ PrevDecl->NextDeclInContext = D;
+ else
+ FirstNewDecl = D;
+
+ PrevDecl = D;
+ }
+
+ return std::make_pair(FirstNewDecl, PrevDecl);
+}
+
/// \brief Load the declarations within this lexical storage from an
/// external source.
void
if (Decls.empty())
return;
- // Resolve all of the declaration IDs into declarations, building up
- // a chain of declarations via the Decl::NextDeclInContext field.
- Decl *FirstNewDecl = 0;
- Decl *PrevDecl = 0;
- for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
- Decl *D = Decls[I];
- if (PrevDecl)
- PrevDecl->NextDeclInContext = D;
- else
- FirstNewDecl = D;
-
- PrevDecl = D;
- }
+ // We may have already loaded just the fields of this record, in which case
+ // don't add the decls, just replace the FirstDecl/LastDecl chain.
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(this))
+ if (RD->LoadedFieldsFromExternalStorage) {
+ llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls);
+ return;
+ }
// Splice the newly-read declarations into the beginning of the list
// of declarations.
- PrevDecl->NextDeclInContext = FirstDecl;
- FirstDecl = FirstNewDecl;
+ Decl *ExternalFirst, *ExternalLast;
+ llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls);
+ ExternalLast->NextDeclInContext = FirstDecl;
+ FirstDecl = ExternalFirst;
if (!LastDecl)
- LastDecl = PrevDecl;
+ LastDecl = ExternalLast;
}
DeclContext::lookup_result
return true;
}
- Info.LexicalDecls = reinterpret_cast<const DeclID*>(Blob);
- Info.NumLexicalDecls = BlobLen / sizeof(DeclID);
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob);
+ Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair);
} else {
Info.LexicalDecls = 0;
Info.NumLexicalDecls = 0;
case TU_UPDATE_LEXICAL: {
DeclContextInfo Info = {
/* No visible information */ 0,
- reinterpret_cast<const DeclID *>(BlobStart),
- BlobLen / sizeof(DeclID)
+ reinterpret_cast<const KindDeclIDPair *>(BlobStart),
+ BlobLen / sizeof(KindDeclIDPair)
};
DeclContextOffsets[Context ? Context->getTranslationUnitDecl() : 0]
.push_back(Info);
}
bool ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
llvm::SmallVectorImpl<Decl*> &Decls) {
assert(DC->hasExternalLexicalStorage() &&
"DeclContext has no lexical decls in storage");
continue;
// Load all of the declaration IDs
- for (const DeclID *ID = I->LexicalDecls, *IDE = ID + I->NumLexicalDecls;
- ID != IDE; ++ID) {
- Decl *D = GetDecl(*ID);
+ for (const KindDeclIDPair *ID = I->LexicalDecls,
+ *IDE = ID + I->NumLexicalDecls; ID != IDE; ++ID) {
+ if (isKindWeWant && !isKindWeWant((Decl::Kind)ID->first))
+ continue;
+
+ Decl *D = GetDecl(ID->second);
assert(D && "Null decl in lexical decls");
Decls.push_back(D);
}
uint64_t Offset = Stream.GetCurrentBitNo();
RecordData Record;
Record.push_back(DECL_CONTEXT_LEXICAL);
- llvm::SmallVector<DeclID, 64> Decls;
+ llvm::SmallVector<KindDeclIDPair, 64> Decls;
for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
D != DEnd; ++D)
- Decls.push_back(GetDeclRef(*D));
+ Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D)));
++NumLexicalDeclContexts;
Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record,
- reinterpret_cast<char*>(Decls.data()), Decls.size() * sizeof(DeclID));
+ reinterpret_cast<char*>(Decls.data()),
+ Decls.size() * sizeof(KindDeclIDPair));
return Offset;
}
// We don't start with the translation unit, but with its decls that
// don't come from the chained PCH.
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
- llvm::SmallVector<DeclID, 64> NewGlobalDecls;
+ llvm::SmallVector<KindDeclIDPair, 64> NewGlobalDecls;
for (DeclContext::decl_iterator I = TU->noload_decls_begin(),
E = TU->noload_decls_end();
I != E; ++I) {
if ((*I)->getPCHLevel() == 0)
- NewGlobalDecls.push_back(GetDeclRef(*I));
+ NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I)));
else if ((*I)->isChangedSinceDeserialization())
(void)GetDeclRef(*I); // Make sure it's written, but don't record it.
}
Record.push_back(TU_UPDATE_LEXICAL);
Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record,
reinterpret_cast<const char*>(NewGlobalDecls.data()),
- NewGlobalDecls.size() * sizeof(DeclID));
+ NewGlobalDecls.size() * sizeof(KindDeclIDPair));
// And in C++, a visible updates block for the TU.
if (Context.getLangOptions().CPlusPlus) {
Abv = new llvm::BitCodeAbbrev();
--- /dev/null
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -include-pch %t -emit-llvm-only %s
+
+#ifndef HEADER
+#define HEADER
+// Header.
+
+struct S1 {
+ void S1_method(); // This should not be deserialized.
+};
+
+
+#else
+// Using the header.
+
+void test(S1*) {
+}
+
+#endif