/// it is created.
enum PredefinedDeclIDs {
/// \brief The NULL declaration.
- PREDEF_DECL_NULL_ID = 0
+ PREDEF_DECL_NULL_ID = 0,
+
+ /// \brief The translation unit.
+ PREDEF_DECL_TRANSLATION_UNIT_ID = 1
};
/// \brief The number of declaration IDs that are predefined.
///
/// For more information about predefined declarations, see the
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
- const unsigned int NUM_PREDEF_DECL_IDS = 1;
+ const unsigned int NUM_PREDEF_DECL_IDS = 2;
/// \brief Record codes for each kind of declaration.
///
/// constant describes a record for a specific declaration class
/// in the AST.
enum DeclCode {
- /// \brief A TranslationUnitDecl record.
- DECL_TRANSLATION_UNIT = 50,
/// \brief A TypedefDecl record.
- DECL_TYPEDEF,
+ DECL_TYPEDEF = 51,
/// \brief A TypeAliasDecl record.
DECL_TYPEALIAS,
/// \brief An EnumDecl record.
void LoadedDecl(unsigned Index, Decl *D);
Decl *ReadDeclRecord(serialization::DeclID ID);
RecordLocation DeclCursorForID(serialization::DeclID ID);
+ void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
RecordLocation getLocalBitOffset(uint64_t GlobalOffset);
uint64_t getGlobalBitOffset(Module &M, uint32_t LocalOffset);
TypeSourceInfo *GetTypeSourceInfo(Module &F,
const RecordData &Record, unsigned &Idx);
- /// \brief Resolve and return the translation unit declaration.
- TranslationUnitDecl *GetTranslationUnitDecl();
-
/// \brief Resolve a type ID into a type, potentially building a new
/// type.
QualType GetType(serialization::TypeID ID);
if (F.LocalNumDecls > 0) {
// Introduce the global -> local mapping for declarations within this
// module.
- GlobalDeclMap.insert(std::make_pair(getTotalNumDecls() + 1, &F));
+ GlobalDeclMap.insert(
+ std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F));
// Introduce the local -> global mapping for declarations within this
// module.
reinterpret_cast<const KindDeclIDPair *>(BlobStart),
static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair))
};
- DeclContextOffsets[Context ? Context->getTranslationUnitDecl() : 0]
- .push_back(Info);
+
+ DeclContext *TU = Context ? Context->getTranslationUnitDecl() : 0;
+ DeclContextOffsets[TU].push_back(Info);
+ if (TU)
+ TU->setHasExternalLexicalStorage(true);
+
break;
}
(const unsigned char *)BlobStart,
ASTDeclContextNameLookupTrait(*this, F));
// FIXME: Complete hack to check for the TU
- if (ID == (*(ModuleMgr.end() - 1))->BaseDeclID + 1 && Context) { // Is it the TU?
+ if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID && Context) { // Is it the TU?
DeclContextInfo Info = {
&F, Table, /* No lexical information */ 0, 0
};
- DeclContextOffsets[Context->getTranslationUnitDecl()].push_back(Info);
+
+ DeclContext *TU = Context->getTranslationUnitDecl();
+ DeclContextOffsets[TU].push_back(Info);
+ TU->setHasExternalVisibleStorage(true);
} else
PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F));
break;
// If we have an update block for the TU waiting, we have to add it before
// deserializing the decl.
+ TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
DeclContextOffsetsMap::iterator DCU = DeclContextOffsets.find(0);
if (DCU != DeclContextOffsets.end()) {
// Insertion could invalidate map, so grab vector.
DeclContextInfos T;
T.swap(DCU->second);
DeclContextOffsets.erase(DCU);
- DeclContextOffsets[Ctx.getTranslationUnitDecl()].swap(T);
+ DeclContextOffsets[TU].swap(T);
}
+
+ // If there's a listener, notify them that we "read" the translation unit.
+ if (DeserializationListener)
+ DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID, TU);
- // Load the translation unit declaration
- GetTranslationUnitDecl();
+ // Make sure we load the declaration update records for the translation unit,
+ // if there are any.
+ loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID, TU);
+
+ // Note that the translation unit has external lexical and visible storage.
+ TU->setHasExternalLexicalStorage(true);
+ TU->setHasExternalVisibleStorage(true);
// FIXME: Find a better way to deal with collisions between these
// built-in types. Right now, we just ignore the problem.
return Bases;
}
-TranslationUnitDecl *ASTReader::GetTranslationUnitDecl() {
- // FIXME: This routine might not even make sense when we're loading multiple
- // unrelated AST files, since we'll have to merge the translation units
- // somehow.
- unsigned TranslationUnitID = (*(ModuleMgr.end() - 1))->BaseDeclID + 1;
- if (!DeclsLoaded[TranslationUnitID - 1]) {
- ReadDeclRecord(TranslationUnitID);
- if (DeserializationListener)
- DeserializationListener->DeclRead(TranslationUnitID,
- DeclsLoaded[TranslationUnitID - 1]);
- }
-
- return cast<TranslationUnitDecl>(DeclsLoaded[TranslationUnitID - 1]);
-}
-
serialization::DeclID
ASTReader::getGlobalDeclID(Module &F, unsigned LocalID) const {
if (LocalID < NUM_PREDEF_DECL_IDS)
Decl *ASTReader::GetDecl(DeclID ID) {
if (ID < NUM_PREDEF_DECL_IDS) {
switch ((PredefinedDeclIDs)ID) {
- case serialization::PREDEF_DECL_NULL_ID:
+ case PREDEF_DECL_NULL_ID:
return 0;
+
+ case PREDEF_DECL_TRANSLATION_UNIT_ID:
+ assert(Context && "No context available?");
+ return Context->getTranslationUnitDecl();
}
return 0;
}
- if (ID > DeclsLoaded.size()) {
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+
+ if (Index > DeclsLoaded.size()) {
Error("declaration ID out-of-range for AST file");
return 0;
}
-
- unsigned Index = ID - NUM_PREDEF_DECL_IDS;
- if (!DeclsLoaded[Index]) {
+
+if (!DeclsLoaded[Index]) {
ReadDeclRecord(ID);
if (DeserializationListener)
DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
llvm::errs() << " Base preprocessed entity ID: " << BasePreprocessedEntityID
<< '\n'
- << "Number of preprocessed entities: "
+ << " Number of preprocessed entities: "
<< NumPreallocatedPreprocessingEntities << '\n';
dumpLocalRemap("Preprocessed entity ID local -> global map",
PreprocessedEntityRemap);
}
void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
- VisitDecl(TU);
- TU->setAnonymousNamespace(ReadDeclAs<NamespaceDecl>(Record, Idx));
+ llvm_unreachable("Translation units are not serialized");
}
void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) {
/// \brief Read the declaration at the given offset from the AST file.
Decl *ASTReader::ReadDeclRecord(DeclID ID) {
- unsigned Index = ID - 1;
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
RecordLocation Loc = DeclCursorForID(ID);
llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
// Keep track of where we are in the stream, then jump back there
case DECL_CONTEXT_VISIBLE:
assert(false && "Record cannot be de-serialized with ReadDeclRecord");
break;
- case DECL_TRANSLATION_UNIT:
- assert(Index == Loc.F->BaseDeclID &&
- "Translation unit must be at first index in file");
- D = Context->getTranslationUnitDecl();
- break;
case DECL_TYPEDEF:
D = TypedefDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
0, 0);
}
assert(Idx == Record.size());
+ // Load any relevant update records.
+ loadDeclUpdateRecords(ID, D);
+
+ // If we have deserialized a declaration that has a definition the
+ // AST consumer might need to know about, queue it.
+ // We don't pass it to the consumer immediately because we may be in recursive
+ // loading, and some declarations may still be initializing.
+ if (isConsumerInterestedIn(D))
+ InterestingDecls.push_back(D);
+
+ return D;
+}
+
+void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
// The declaration may have been modified by files later in the chain.
// If this is the case, read the record containing the updates from each file
// and pass it to ASTDeclReader to make the modifications.
if (UpdI != DeclUpdateOffsets.end()) {
FileOffsetsTy &UpdateOffsets = UpdI->second;
for (FileOffsetsTy::iterator
- I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) {
+ I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) {
Module *F = I->first;
uint64_t Offset = I->second;
llvm::BitstreamCursor &Cursor = F->DeclsCursor;
unsigned RecCode = Cursor.ReadRecord(Code, Record);
(void)RecCode;
assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
+
+ unsigned Idx = 0;
+ ASTDeclReader Reader(*this, *F, Cursor, ID, Record, Idx);
Reader.UpdateDecl(D, *F, Record);
}
}
-
- // If we have deserialized a declaration that has a definition the
- // AST consumer might need to know about, queue it.
- // We don't pass it to the consumer immediately because we may be in recursive
- // loading, and some declarations may still be initializing.
- if (isConsumerInterestedIn(D))
- InterestingDecls.push_back(D);
-
- return D;
}
+
void ASTDeclReader::UpdateDecl(Decl *D, Module &Module,
const RecordData &Record) {
unsigned Idx = 0;
RECORD(TYPE_PACK_EXPANSION);
RECORD(TYPE_ATTRIBUTED);
RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
- RECORD(DECL_TRANSLATION_UNIT);
RECORD(DECL_TYPEDEF);
RECORD(DECL_ENUM);
RECORD(DECL_RECORD);
ASTContext &Context = SemaRef.Context;
Preprocessor &PP = SemaRef.PP;
- // The translation unit is the first declaration we'll emit.
- DeclIDs[Context.getTranslationUnitDecl()] = 1;
- ++NextDeclID;
- DeclTypesToEmit.push(Context.getTranslationUnitDecl());
+ // Set up predefined declaration IDs.
+ DeclIDs[Context.getTranslationUnitDecl()] = PREDEF_DECL_TRANSLATION_UNIT_ID;
// Make sure that we emit IdentifierInfos (and any attached
// declarations) for builtins.
AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes);
SpecialTypes.push_back(Context.isInt128Installed());
+ // 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();
+ 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(std::make_pair((*I)->getKind(), GetDeclRef(*I)));
+ else if ((*I)->isChangedSinceDeserialization())
+ (void)GetDeclRef(*I); // Make sure it's written, but don't record it.
+ }
+ // We also need to write a lexical updates block for the TU.
+ llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
+ Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
+ unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(Abv);
+ Record.clear();
+ Record.push_back(TU_UPDATE_LEXICAL);
+ Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record,
+ data(NewGlobalDecls));
+
+ // And a visible updates block for the DeclContexts.
+ Abv = new llvm::BitCodeAbbrev();
+ Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 32));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
+ UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv);
+ WriteDeclContextVisibleUpdate(TU);
+
+ // If the translation unit has an anonymous namespace, write it as an
+ // update block.
+ if (NamespaceDecl *NS = TU->getAnonymousNamespace()) {
+ ASTWriter::UpdateRecord &Record = DeclUpdates[TU];
+ Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE);
+ AddDeclRef(NS, Record);
+ }
+
// Keep writing types and declarations until all types and
// declarations have been written.
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
if (!KnownNamespaces.empty())
Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
+ WriteDeclUpdatesBlocks();
+
// Some simple statistics
Record.clear();
Record.push_back(NumStatements);
ASTContext &Context = SemaRef.Context;
Preprocessor &PP = SemaRef.PP;
+ // Set up predefined declaration IDs.
+ DeclIDs[Context.getTranslationUnitDecl()] = PREDEF_DECL_TRANSLATION_UNIT_ID;
+
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
WriteMetadata(Context, isysroot, "");
}
void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
- VisitDecl(D);
- Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
- Code = serialization::DECL_TRANSLATION_UNIT;
+ llvm_unreachable("Translation units aren't directly serialized");
}
void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) {
// anonymous namespace.
Decl *Parent = cast<Decl>(
D->getParent()->getRedeclContext()->getPrimaryContext());
- if (Parent->getPCHLevel() > 0) {
+ if (Parent->getPCHLevel() > 0 || isa<TranslationUnitDecl>(Parent)) {
ASTWriter::UpdateRecord &Record = Writer.DeclUpdates[Parent];
Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE);
Writer.AddDeclRef(D, Record);
if (clang_isDeclaration(Cursor.kind)) {
Decl *D = getCursorDecl(Cursor);
assert(D && "Invalid declaration cursor");
- if (D->getPCHLevel() > MaxPCHLevel)
+ if (D->getPCHLevel() > MaxPCHLevel && !isa<TranslationUnitDecl>(D))
return false;
if (D->isImplicit())